Struts2 i18n(三)

来源:互联网 发布:简易平面图软件 编辑:程序博客网 时间:2024/06/11 08:04

下面略述com.opensymphony.xwork2.ActionSupport.getText()方法
public String getText(String aTextName)
说明:Gets a messages based on a message key,or null if no message is found
        Parameters:aTextName-the resource bundle key that is to be searched for
        得到一个基于key的消息,如果没有找到这个消息则返回null
        参数:aTextName是在资源包寻找到的所匹配的key
小结:该方法用来完成国际化,接收的参数即资源包中的key,返回资源包中的value
public String getText(String aTextName,List args)
说明:Gets a message based on a key using the supplied args,as defined in MessageFormat
        使用提供的一个被定义在MessageFormat中的参数args得到一个基于key的消息
小结:即此时资源包的key的值可以带参数,即{0}占位符,该参数由List类型的args提供
        换句话说,此时可以传递一些运行时的参数,使得消息的产生是动态的
        另外还有个与该方法功能相同的public String getText(String key,String[] args)
        只不过List参数的方法可接收Object参数,而数组参数的方法则只能接收String
        实际上Object类型的参数真正输出到页面时,也是调用toString()转换成字符串
public String getText(String aTextName,String defaultValue)
说明:Gets a message based on a key,if the message is not found,a supplied default value is returned
小结:即当在资源包中找不到key时,就会返回defaultValue


--------------------------------------------------------------------------------

Struts2里面国际化资源文件的三个存活范围
Struts2提供了更精细化的资源文件定义方式,可分全局的和局部的
而局部的国际化资源文件又分为两种情况,分别是:包级别和类级别
包级别资源文件自然要在相应包下建立,它的命名是固定的package_zh_CN.properties
若存在相同key,那么包级别中的提示信息要高于全局资源文件中的提示信息
这就好似Java一样,若定义了同名的成员变量和局部变量,那么成员变量将被覆盖掉
类级别资源文件同样要建立在相应包下,它的命名类似于LoginAction_zh_CN.properties
类级别的提示信息更加具体,因此类级别的提示信息要高于包级别资源文件的提示信息


--------------------------------------------------------------------------------

类级别和包级别在应用中的触发点
若要在表单中进行国际化信息的显示,则应去掉<s:form/>的theme="simple"属性
然后将姓名输入域改为<s:textfield name="username" key="username.xml.invalid"/>
访问页面时,会在姓名位置显示包级别提示信息,即package_zh_CN.properties中的
点击Submit时会在姓名位置显示类级别别提示信息,即RegisterAction_zh_CN.properties中的
点击Submit后,表单便与在struts.xml中设定的Action关联在一起,故显示类级别提示信息
所以当使用类级别国际化文件时,必须经过Action才能生效,才能按照预定的进行国际化
若未经Action而直接访问JSP页面,则无法显示类级别的国际化消息,这一点和Struts1.X是不一样的


--------------------------------------------------------------------------------

在国际化资源文件中嵌套OGNL表达式
国际化资源文件中的内容示例如下
login.text = 登录
login.title = %{getText("login.text")}页面
那么在页面中显示login.title国际化消息时,就会显示:登录页面


--------------------------------------------------------------------------------

页面中国际化的显示
<s:text name="key"/>会自动按照范围到资源文件中查找name所指定的key
然后输出Key所对应的Value,若Key不存在,则将name值原封不动的输出
并且它也是可以动态传递参数的,这时需要在该标签中嵌套<s:param/>标签
<s:label key=""/>在输出国际化信息时,会自动在国际化文本后面加上一个多余的冒号
通过查看页面源文件发现:使用<s:label/>输出的国际化信息位于HTML的<label/>标签内
                                  使用<s:text/>输出的国际化信息则是一些单纯的文本
<s:i18n name=""/>用来明确的指定所使用的临时的国际化资源文件
并且该临时资源文件默认与struts.xml处于同一目录下,亦可在name中指定其存放路径
它的name值用来指定所要读取的国际化资源文件,然后再嵌套<s:text/>标签就可以输出指定的key值了
在<s:param/>中显示国际化信息如在<s:param value="%{getText('login.tip')}"/>
在<s:param/>中接收Action属性如<s:param value="%{username}"/>
Struts2表单标签的key属性通常用来输出国际化信息,可以在key值中传一个OGNL表达式
而label属性中放的是字符串,所以也可以使用%{}输出国际化信息,如下所示
<s:property value="getText('key')"/>或者<s:textfield label="%{getText('key')}"/>
另外关于<s:radio/>标签的国际化显示,如下所示
<s:radio list="#{1:getText('i18n.sex.male') ,0:getText('i18n.sex.female')}" name="sex" value="1" key="i18n.sex"/>
这个时候就不用再写成%{getText('i18n.sex.male')}了,也就是说可以把%{}去掉了
由于<s:textfield label="%{getText('key')}"/>的label默认使用的是字符串,所以要加上%{}
而在<s:radio/>的list属性里面本身已经有{}符号了,说明它已经是一个OGNL表达式了
所以在<s:radio list=“#{}”/>中就没必要再使用%{}了


--------------------------------------------------------------------------------

浅述Struts2国际化的实现过程
Struts2的I18nInterceptor拦截器会拦截所有的Action,它主要做的事情为
从客户端发送过来的请求参数中寻找是否存在名为request_locale的参数
若有,则将request_locale的value转化为locale保存起来
该locale是保存在以WW_TRANS_I18N_LOCALE所命名的session里面的
详见源码的第124行session.put(attributeName, locale)
其中attributeName即79行的protected String attributeName = DEFAULT_SESSION_ATTRIBUTE
和第75行的public static final String DEFAULT_SESSION_ATTRIBUTE = "WW_TRANS_I18N_LOCALE"
于是便可通过这种方式实现一个选择页面所显示的语言环境的功能
比如选择中文,那么就可以将request_locale设置为zh_CN
如果我们不做任何配置的话,客户端是不会发送request_locale参数的
它默认会用request的getLocale()方法得到默认locale,将其存放在session中
这样就使得以后客户的所有操作都是在同一个国际化的环境下执行
就不需要我们每一次都手工判断用户的国际化环境了


--------------------------------------------------------------------------------

接下来为大家展示示例代码

 

首先是struts.xml文件

view plaincopy to clipboardprint?
<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"  
"
http://struts.apache.org/dtds/struts-2.1.dtd"> 
 
<struts> 
    <constant name="struts.custom.i18n.resources" value="message"/> 
    <package name="struts2.1" extends="struts-default"> 
        <action name="internationalization" class="com.jadyer.action.InternationalizationAction"> 
            <result>loginSuccess.jsp</result> 
            <result name="input">internationalization.jsp</result> 
        </action> 
    </package> 
</struts> 
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
"
http://struts.apache.org/dtds/struts-2.1.dtd">

<struts>
 <constant name="struts.custom.i18n.resources" value="message"/>
 <package name="struts2.1" extends="struts-default">
  <action name="internationalization" class="com.jadyer.action.InternationalizationAction">
   <result>loginSuccess.jsp</result>
   <result name="input">internationalization.jsp</result>
  </action>
 </package>
</struts>

然后是web.xml文件

view plaincopy to clipboardprint?
<?xml version="1.0" encoding="UTF-8"?> 
<web-app version="2.5" xmlns="
http://java.sun.com/xml/ns/javaee
    xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance
    xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee   
   
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> 
    <filter> 
        <filter-name>struts2</filter-name> 
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> 
    </filter> 
    <filter-mapping> 
        <filter-name>struts2</filter-name> 
        <url-pattern> 
    @Override 
    public void validate() {  
        if (null == username || username.length() < 4 || username.length() > 10) {  
            this.addFieldError("username",this.getText("username.invalid", new String[]{username}));  
        
    

package com.jadyer.action;

import com.opensymphony.xwork2.ActionSupport;

@SuppressWarnings("serial")
public class InternationalizationAction extends ActionSupport {
 private String username;
 private String password;
 
 //关于username和password属性的getter和setter方法略
 
 @Override
 public String execute() throws Exception {
  if("admin".equals(this.getUsername().trim())&&"jadyer".equals(this.getPassword().trim())){
   return SUCCESS;
  }else{
   this.addFieldError("username", this.getText("username.password.error"));
   return INPUT;
  }
 }

 
 @Override
 public void validate() {
  if (null == username || username.length() < 4 || username.length() > 10) {
   this.addFieldError("username",this.getText("username.invalid", new String[]{username}));
  }
 }
}


用来测试<s:i18n>、<s:text>、<s:param>标签组合使用的temp_zh_CN_en_US.properties国际化资源文件

view plaincopy to clipboardprint?
hello = \u4F60\u597D\u3010{0}\u3011\u3002\u8FD9\u662F\u4F7F\u7528Struts2\u7684i18n\u6807\u7B7E\u5D4C\u5957text\u6807\u7B7E\u8F93\u51FA\u7684\u7ED3\u679C  
 
 
hello = Hello\u3010{0}\u3011\u3002This is used the Struts2 i18n with text tag to result 
hello = \u4F60\u597D\u3010{0}\u3011\u3002\u8FD9\u662F\u4F7F\u7528Struts2\u7684i18n\u6807\u7B7E\u5D4C\u5957text\u6807\u7B7E\u8F93\u51FA\u7684\u7ED3\u679C


hello = Hello\u3010{0}\u3011\u3002This is used the Struts2 i18n with text tag to result


最后是用到的全局的message_zh_CN.properties和message_en_US.properties国际化资源文件

view plaincopy to clipboardprint?
internationalization.jsp.CHINESE  = \u4E2D\u6587\u7248  
internationalization.jsp.ENGLISH  = \u82F1\u6587\u7248  
internationalization.jsp.passwrod = \u5BC6\u7801  
internationalization.jsp.username = \u7528\u6237  
username.invalid        = \u7528\u6237\u540D "{0}" \u586B\u5199\u4E0D\u6B63\u786E  
username.password.error = \u7528\u6237\u540D\u6216\u5BC6\u7801\u4E0D\u6B63\u786E  
 
 
internationalization.jsp.CHINESE  = Chinese  
internationalization.jsp.ENGLISH  = English  
internationalization.jsp.passwrod = password  
internationalization.jsp.username = username  
username.invalid        = username "{0}" invalid  
username.password.error = username or password error