IT虾米网

struts2:国际化

itxm 2018年06月22日 编程语言 1405 0

国际化是指应用程序运行时,可根据客户端请求来自的国家/地区、语言的不同而显示不同的界面。

Java语言内核基于Unicode2.1,提供了对不同国家和不同语言文字的内部支持。

国际化的英文单词是Internationlization,因为单词过长,简称I18n。

国际化的基本步骤

1. 修改struts.xml文件,以加载全局资源文件

2. 创建不同语言的资源文件

  2.1 首先,生成中文过渡文件:message_zh_CN_org.properties

  2.2 其次,使用native2ascii.exe命令来生成message_zh_CN.properties文件

  2.3 生成英文message_en_US.properties

3. JSP页面的国际化(register_i18n.jsp)

  3.1 使用s:text标签

  3.2 在页面表单中的各个输入标签中加入key属性

  3.3 使用getText()表达式

4. 生成Action类(RegisterI18nAction.java)

5. 国际化验证文件(RegisterI18nAction-validation.xml)

6. 修改struts.xml文件,加入action配置

7. 测试

附录

一:国际化资源文件加载优先顺序(Action类,调用getText("login")方法)

二:国际化资源文件加载优先顺序(JSP文件)

三:临时修改用户默认语言环境 

国际化的基本步骤

1. 修改struts.xml文件,以加载全局资源文件

    <constant name="struts.custom.i18n.resources" value="message"></constant> 
    <constant name="struts.i18n.encoding" value="UTF-8"></constant>

上述代码建议放在struts.xml文件的开头位置。全局资源文件名以“message_区域名.properties“格式命名。

2. 创建不同语言的资源文件

为了方便,中文的资源文件建议以message_zh_CN_org.properties命名(UTF-8文件格式),然后用native2ascii工具将它转换为message_zh_CN.properties文件供项目使用。

2.1 首先,生成中文过渡文件:message_zh_CN_org.properties

title=用户注册 
name=用户名 
username=真实姓名 
pass=密码 
repass=重输密码 
sex=性别 
province=省 
age=年龄 
birth=生日 
love=爱好 
mobile=手机 
email=电子邮件 
submit=提交 
male=男 
famale=女 
chongqing=重庆 
beijing=北京 
shanghai=上海 
tianjin=天津 
swim=游泳 
walk=散步 
playtabletennis=乒乓球 
reading=读书 
others=其它 
validate_name_null=请输入用户名 
validate_name_scope=用户名必须在6到18位之间 
validate_pass_null=请输入密码 
validate_pass_scope=密码必须在6到12位之间,且只能是字母或数字 
validate_repass_null=请输入重复密码 
validate_repass_scope=两次输入的密码必须一致 
validate_age_scope=年龄必须在 ${min} 和 ${max}之间 
validate_birth_scope=生日必须在 ${min} 和 ${max}之间 
validate_email_scope=电子邮件地址无效

以UTF-8格式保存此文件(如果是用UrltraEdit编辑,菜单:文件-》转换-》ASCII到UTF-8)。

2.2 其次,使用native2ascii.exe命令来生成message_zh_CN.properties文件

native2ascii -encodeing utf-8 message_zh_CN_org.properties message_zh_CN.properties

注意:

  • native2ascii.exe文件位于java\bin目录下;
  • message_zh_CN_org.properties文件必须是以UTF-8格式保存,这样上述参数“utf-8”才有意义。

最后生成文件如下:

title=\u7528\u6237\u6ce8\u518c 
name=\u7528\u6237\u540d 
username=\u771f\u5b9e\u59d3\u540d 
pass=\u5bc6\u7801 
repass=\u91cd\u8f93\u5bc6\u7801 
sex=\u6027\u522b 
province=\u7701 
age=\u5e74\u9f84 
birth=\u751f\u65e5 
love=\u7231\u597d 
mobile=\u624b\u673a 
email=\u7535\u5b50\u90ae\u4ef6 
submit=\u63d0\u4ea4 
male=\u7537 
famale=\u5973 
chongqing=\u91cd\u5e86 
beijing=\u5317\u4eac 
shanghai=\u4e0a\u6d77 
tianjin=\u5929\u6d25 
swim=\u6e38\u6cf3 
walk=\u6563\u6b65 
playtabletennis=\u4e52\u4e53\u7403 
reading=\u8bfb\u4e66 
others=\u5176\u5b83 
validate_name_null=\u8bf7\u8f93\u5165\u7528\u6237\u540d 
validate_name_scope=\u7528\u6237\u540d\u5fc5\u987b\u57286\u523018\u4f4d\u4e4b\u95f4 
validate_pass_null=\u8bf7\u8f93\u5165\u5bc6\u7801 
validate_pass_scope=\u5bc6\u7801\u5fc5\u987b\u57286\u523012\u4f4d\u4e4b\u95f4\uff0c\u4e14\u53ea\u80fd\u662f\u5b57\u6bcd\u6216\u6570\u5b57 
validate_repass_null=\u8bf7\u8f93\u5165\u91cd\u590d\u5bc6\u7801 
validate_repass_scope=\u4e24\u6b21\u8f93\u5165\u7684\u5bc6\u7801\u5fc5\u987b\u4e00\u81f4 
validate_age_scope=\u5e74\u9f84\u5fc5\u987b\u5728 ${min} \u548c ${max}\u4e4b\u95f4 
validate_birth_scope=\u751f\u65e5\u5fc5\u987b\u5728 ${min} \u548c ${max}\u4e4b\u95f4 
validate_email_scope=\u7535\u5b50\u90ae\u4ef6\u5730\u5740\u65e0\u6548

2.3 生成英文message_en_US.properties

title=USER REGISTER 
name=member name 
username=real name 
pass=input password 
repass=confirm password 
sex=sex 
province=province 
age=age 
birth=birth 
love=love 
mobile=mobile 
email=email 
submit=submit 
male=male 
famale=famale 
chongqing=chongqing 
beijing=beijing 
shanghai=shanghai 
tianjin=tianjin 
swim=swim 
walk=walk 
playtabletennis=playtabletennis 
reading=reading 
others=others 
validate_name_null=please input member name 
validate_name_scope=member name must be between 6 and 18 
validate_pass_null=please input password 
validate_pass_scope=password must be between 6 and 12 and only used number or letter 
validate_repass_null=please input confirm password 
validate_repass_scope=two password must be same 
validate_age_scope=age must be between ${min}and ${max} 
validate_birth_scope=birthday must be between ${min}and ${max} 
validate_email_scope=email is invalid

3. JSP页面的国际化(register_i18n.jsp)

在页面中读取国际化信息有三种方式:

3.1 使用s:text标签

<s:text name="title"></s:text>

3.2 在页面表单中的各个输入标签中加入key属性

<s:textfield name="username" key="username"></s:textfield>

3.3 使用getText()表达式

<s:radio list="#{'1':getText('male'),'0':getText('famale')}" value="1" name="sex" key="sex"></s:radio>

下面是国际化后的代码:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> 
<%@ page isELIgnored="false"%> 
<%@ taglib uri="/struts-tags" prefix="s"%> 
<%@ taglib uri="/struts-dojo-tags" prefix="sx"%> 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html> 
<head> 
<sx:head extraLocales="utf-8"/> 
    <title><s:text name="title"></s:text></title> 
</head> 
<body> 
    <s:form action="register_i18n" method="post" theme="xhtml"> 
        <s:textfield name="name" key="name"></s:textfield> 
        <s:textfield name="username" key="username"></s:textfield> 
        <s:textfield name="pass" key="pass"></s:textfield> 
        <s:textfield name="repass" key="repass"></s:textfield> 
        <s:radio list="#{'1':getText('male'),'0':getText('famale')}" value="1" name="sex" key="sex"></s:radio> 
        <s:select name="province" list="#{'0':getText('chongqing'),'1':getText('beijing'),'2':getText('shanghai'),'3':getText('tianjin')}" key="province"></s:select> 
        <s:textfield name="age" key="age"></s:textfield> 
        <sx:datetimepicker name="birth" displayFormat="yyyy-MM-dd" key="birth" accesskey="false"></sx:datetimepicker> 
        <s:checkboxlist name="love" key="love" list="#{'0':getText('swim'),'1':getText('walk'),'2':getText('playtabletennis'),'3':getText('reading'),'4':getText('others')}"></s:checkboxlist> 
        <s:textfield name="mobile" key="mobile"></s:textfield> 
        <s:textfield name="email" key="email"></s:textfield> 
        <s:textfield name="request_locale" key="request_locale"></s:textfield> 
        <s:submit key="submit"></s:submit> 
    </s:form> 
</body> 
</html>

本演示采用了xhtml主题,在form标签中有“theme=xhtml“代码。

4. 生成Action类(RegisterI18nAction.java)

package com.clzhang.struts2.demo1; 
 
import java.util.*; 
import com.opensymphony.xwork2.ActionSupport; 
 
public class RegisterI18nAction extends ActionSupport { 
    public static final long serialVersionUID = 1; 
 
    private String name; 
    private String username; 
    private String pass; 
    private String repass; 
    private String sex; 
    private String province; 
    private Integer age; 
    private Date birth; 
    private String love; 
    private String mobile; 
    private String email; 
     
    public String getName() { 
        return name; 
    } 
    public void setName(String name) { 
        this.name = name; 
    } 
    public String getUsername() { 
        return username; 
    } 
    public void setUsername(String username) { 
        this.username = username; 
    } 
    public String getPass() { 
        return pass; 
    } 
    public void setPass(String pass) { 
        this.pass = pass; 
    } 
    public String getRepass() { 
        return repass; 
    } 
    public void setRepass(String repass) { 
        this.repass = repass; 
    } 
    public String getSex() { 
        return sex; 
    } 
    public void setSex(String sex) { 
        this.sex = sex; 
    } 
    public String getProvince() { 
        return province; 
    } 
    public void setProvince(String province) { 
        this.province = province; 
    } 
    public Integer getAge() { 
        return age; 
    } 
    public void setAge(Integer age) { 
        this.age = age; 
    } 
    public Date getBirth() { 
        return birth; 
    } 
    public void setBirth(Date birth) { 
        this.birth = birth; 
    } 
    public String getLove() { 
        return love; 
    } 
    public void setLove(String love) { 
        this.love = love; 
    } 
    public String getMobile() { 
        return mobile; 
    } 
    public void setMobile(String mobile) { 
        this.mobile = mobile; 
    } 
    public String getEmail() { 
        return email; 
    } 
    public void setEmail(String email) { 
        this.email = email; 
    } 
     
    @Override 
    public String execute() { 
        System.out.println(username + "|" + age + "|" + mobile + " register(i18n) finished!"); 
 
        return SUCCESS; 
    } 
}

其实这个Action类只有相关setter/getter而已,此演示我们并不需要它真正实现什么业务功能的。

5. 国际化验证文件(RegisterI18nAction-validation.xml)

<!DOCTYPE validators PUBLIC 
        "-//Apache Struts//XWork Validator 1.0.2//EN" 
        "http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd"> 
<validators> 
    <field name="name"> 
        <field-validator type="requiredstring"> 
            <param name="trim">true</param> 
            <message key="validate_name_null"></message> 
        </field-validator> 
         
        <field-validator type="stringlength">   
            <param name="minLength">6</param> 
            <param name="maxLength">18</param>   
            <message key="validate_name_scope"></message> 
        </field-validator> 
    </field> 
     
    <field name="pass"> 
        <field-validator type="requiredstring"> 
            <param name="trim">true</param> 
            <message key="validate_pass_null"></message> 
        </field-validator> 
         
        <field-validator type="regex">   
            <param name="expression"><![CDATA[\w{6,12}]]></param>   
            <message key="validate_pass_scope"></message>   
        </field-validator> 
    </field> 
 
    <field name="repass"> 
        <field-validator type="requiredstring"> 
            <param name="trim">true</param> 
            <message key="validate_repass_null"></message> 
        </field-validator> 
         
        <field-validator type="fieldexpression">   
            <param name="expression"><![CDATA[repass==pass]]></param>  <!--这里也可以用repass.equals(pass)//--> 
            <message key="validate_repass_scope"></message>   
        </field-validator> 
    </field> 
 
    <field name="age"> 
        <field-validator type="int">   
            <param name="min">1</param> 
            <param name="max">150</param>   
            <message key="validate_age_scope"></message>   
        </field-validator> 
    </field> 
 
    <field name="birth"> 
        <field-validator type="date">   
            <param name="min">1900-01-01</param> 
            <param name="max">2050-01-01</param>   
            <message key="validate_birth_scope"></message>   
        </field-validator> 
    </field> 
 
    <field name="email"> 
        <field-validator type="email"> 
            <message key="validate_email_scope"></message> 
        </field-validator> 
    </field> 
</validators>

对此文件有不明白的地方,可以参考本文前些章节,以及文章:struts2:数据校验,validation.xml格式验证

6. 修改struts.xml文件,加入action配置

加入如下内容:

        <action name="register_i18n" class="com.clzhang.struts2.demo1.RegisterI18nAction"> 
            <result name="success">/struts2/demo1/success.jsp</result> 
            <result name="input">/struts2/demo1/register_i18n.jsp</result> 
        </action>

7. 测试

打开IE,输入地址:http://127.0.0.1:8080/st/ssh/demo1/register_i18n.jsp

结果如下:

 

直接提交,结果如下:

 

改变本机语言为英文,测试结果为:

注意:修改本机语言的方法,参考附录:二:临时修改用户默认语言环境 

附录

一:国际化资源文件加载优先顺序(Action类,调用getText("login")方法)

a. 首先加载action同目录下且baseName为action类名的系列资源文件。

b. 如果在a中找不到指定key对应的消息,且action有父类,则加载父类同目录下baseName为父类名的系列资源文件。

c. 如果在b中找不到key对应的消息,且action有实现接口,则加载其实现的接口同目录下baseName为接口名的系列资源文件。

d. 如果在c中找不到key对应的消息,则查找当前包下baseName为包名的系列资源文件。

e. 如果在d中找不到key对应的消息,则沿着当次包上溯,直到最顶层包来查找baseName为包名的系列资源文件。

f. 如果e中找不到key对应的消息,则查找struts.custom.i18n.resources常量指定baseName的系列资源文件。

g. 经过上面的步骤还是找不到key对应的消息,将直接输出该key的字符串值;如果上面的任何一步找到对应的key的消息,系统停止搜索,直接输出该key。

二:国际化资源文件加载优先顺序(JSP文件)

如果<s:text.../>标签、表单标签没有使用<s:i18n.../>标签作为父标签,其加载顺序为:

直接加载struts.custom.i18n.resources常量指定baseName的全局范围国际化资源文件。如果找不到该key对应的value值,将直接输出该key的字符串值。 

三:临时修改用户默认语言环境

方式一:

在“控制面板”-》“区域和语言”中将机器语言环境设置成相应的国家即可。

方式二:

向action额外提交一个request_locale的参数,取值为语言值即可。比如:request_locale=en_US、request_locale=zh_CN等。对于本演示而言,可以直接在request_locale文本框中输入相关值即可,如:en_US/zh_CN等。

因为struts2提供了一个名为i18n的拦截器,将其默认注册在拦截器栈中。i18n拦截器在执行action方法之前,自动查找请求中名为request_locale的参数。如果该参数存在,拦截器就将其作为参数,转换为Locale对象,并将其设为用户默认的Locale(代表国家、语言环境)。

评论关闭
IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!