1. I18N处理
什么是I18N问题?
在英文中, 国际化(Internationalization)被缩写为I18N, 即只取首尾两个字母, 中间字母为18个。
问题在哪里?
一个简单的例子
public class EnglishHelloWorld {
/** * @param args */ public static void main(String[] args) { System.out.println("Hello World"); }
}
|
public class ChineseHelloWorld {
/** * @param args */ public static void main(String[] args) { System.out.println("世界,你好"); }
} |
上述两个例子中,如果要分别输出英文和中文文本,就需要写两个程序。利用国际化处理机制,可以只写一个程序。即我们需要将程序中硬编码的文本转移到外部的资源文件(.properties文件)中!针对每一种语言环境,我们需要编写一个资源文件。然后指定当前应用程序所使用的语言环境,JAVA中的国际化处理机制,将能够自动找到对应的资源文件,并将其中的文本内容读出来。
下面我们将硬编码的文本转移到资源文件中。我们需要三个资源文件:
一个缺省的资源文件,即如果不指定语言环境,默认使用的资源文件;
一个用于中文环境的资源文件,如果指定是中文环境,将使用此资源文件;
一个用于英文环境的资源文件,如果指定是英文环境,将使用此资源文件;
MessageResources.properties文件:
hello=Hello World! |
MessageResources_en.properties文件:
hello=Hello World! |
MessageResources_zh.properties文件:
hello=/u4e16/u754c/uff0c/u4f60/u597d |
特别注意上述MessageResources_zh.properties文件,因为JAVA要求.properties文件不允许包含非ASCII(请自行上网查阅ASCII字符包括哪些字符,主要是英文和一些常见的符号,而中文等字符不属于ASCII字符)字符,所以对于中文,需要将中文转换为UNICODE编码的字符,并用/u+UNICODE编码来表示中文。
native2ascii.exe程序(在JAVA安装目录下面的bin目录下),就是用来将中文的字符转换为/u+UNICODE编码的文本的工具。
我们可以编写一个MessageResources_zh.txt文件:
hello=世界,你好 |
然后,在命令行下,通过如下命令,将MessageResources_zh.txt文件转换为MessageResources_zh.properties文件:
native2ascii MessageResources_zh.txt MessageResources_zh.properties |
资源文件的命名规则:
资源名称_语言代码_国家/地区代码.properties
其中,国家/地区代码是可选的。如果要加上国家/地区代码,上述资源文件,可命名为:
MessageResources_zh_CN.properties
MessageResources_en_US.properties
语言代码是小写的字母,国家/地区代码是大写的字母。
补充:JAVA都能支持哪些语言代码和国家/地区代码?
public static void main(String[] args) { Locale[] locales = DateFormat.getAvailableLocales(); for(Locale locale:locales){ System.out.println("语言代码:"+locale.getLanguage()+",国家代码"+locale.getCountry()); } } |
其输出如下:
语言代码:ja,国家代码JP 语言代码:es,国家代码PE 语言代码:en,国家代码 语言代码:ja,国家代码JP 语言代码:es,国家代码PA ………………………………………(忽略其它输出) |
² 语言代码标准:http://ftp.ics.uci.edu/pub/ietf/http/related/iso639.txt
² 国家代码标准:http://userpage.chemie.fu-berlin.de/diverse/doc/ISO_3166.html
使用native2ascii工具的注意问题:
如果你的文本文件本身的编码与你的电脑的编码不一致,比如你的操作系统是GBK编码,而你的MessageResources_zh.txt文件的编码是UTF-8,则你在使用native2ascii工具时,需要指定你的文件编码,如下所示:
native2ascii –encoding UTF-8 MessageResources_zh.txt MessageResources_zh.properties |
准备好了资源文件之后,我们可以编写下面的代码来测试:
public class HelloWorld {
/** * @param args */ public static void main(String[] args) { ResourceBundle rb = ResourceBundle.getBundle("MessageResources",Locale.CHINA); String hello = rb.getString("hello"); System.out.println(hello); }
} |
public class HelloWorld {
/** * @param args */ public static void main(String[] args) { ResourceBundle rb = ResourceBundle.getBundle("MessageResources",Locale.US); String hello = rb.getString("hello"); System.out.println(hello); }
} |
Locale对象
Locale对象代表了一种语言环境和国家/地区。
比如,日期、货币等等都跟Locale有关。随着Locale的不同,日期货币的表现形式也不一样。
在struts2中支持i18n处理是非常灵活的,下面先从一个简单的例子开始:
Struts2对I18N问题支持的一个简单的例子
我们需要做三件事情:一是定义资源文件,二是编写Action,三是在JSP页面中用标签把国际化资源文本取出。
资源文件的定义:
在Action所在的包或其任意一个父包中定义package.properties和package_language_COUTRY.properties资源文件,比如:假设在cn.com.leadfar.struts2.actions下面有一个UserAction,那么你可以在cn.com.leadfar.struts2.actions这个包或其任意一个父包中定义package.properties文件,比如选择cn.com.leadfar包,在它下面定义了三个资源文件:
package.properties:
user.username=UserName user.password=Password user.age=Age |
package_zh_CN.properties:
user.username=/u7528/u6237/u540d user.password=/u5bc6/u7801 user.age=/u5e74/u9f84 |
上面这个文件,请用native2ascii.exe工具来转换
命令如下:native2ascii package_zh_CN.txt package_zh_CN.properties
user.username=用户名 user.password=密码 user.age=年龄 |
上面这个是package_zh_CN.txt文件的内容
package_en_US.properties:
user.username=UserName user.password=Password user.age=Age |
编写Action:
我们编写的Action需要继承ActionSupport,这个父类提供了I18N的支持!
比如:
package cn.com.leadfar.struts2.actions;
import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.ModelDriven;
public class UserAction extends ActionSupport implements ModelDriven{
private User user;
@Override public Object getModel() { if(user == null){ user = new User(); } return user; }
public String addInput(){ return "add_input"; }
public String add(){
new UserManager().addUser(user);
return "success"; }
public User getUser() { return user; }
public void setUser(User user) { this.user = user; }
}
|
在JSP中使用国际化资源文本:
<form action="test/user.action" method="post"> <input type="hidden" name="method:add"> <s:property value="getText('user.username')"/>:<input type="text" name="username"> <br/> <s:property value="getText('user.password')"/>:<input type="text" name="password"> <br/> <s:property value="getText('user.age')"/>:<input type="text" name="age"> <br/> <input type="submit" name="submit" value="添加用户"> </form> <br/> |
我们通过UserAction中的addInput方法,打开上述JSP文件,将能够正确显示其对应的文本信息。随着改变浏览器中的语言设置选项,你可以看到其文本也会随之变化!
全局资源文件的定义
你可以把全局资源文件放到类路径的根目录下,命名可以随意,比如,我们在类路径根目录下添加了下面三个资源文件:
MessageResources.properties
MessageResources_zh_CN.properties
MessageResources_en_US.properties
那么,只要在struts的配置文件中增加下面一行定义即可:
<constant name="struts.custom.i18n.resources" value="MessageResources"></constant> |
如何改变当前系统的语言环境?
在struts2中,是通过在http session中放置一个Locale类型的对象,来表示当前是什么样的语言环境。如果我们希望改变当前的语言环境,通常我们无需直接操作http session。Struts2在一个I18Ninterceptor中做了这些设置Locale的工作。我们只需要向服务器发起任意一个请求,只要这个请求中包含参数:request_locale即可,在I18Ninterceptor中,struts2将根据这个参数的值,来改变http session中的Locale对象。这个参数的取值类似于如下格式:
en_US
zh_CN
等等。
比如:我们只要发出类似下面的请求即可:
http://localhost:8080/test/user.action?request_locale=zh_CN
下面是一小段供参考的演示代码:
<s:url namespace="/test" action="user" method="addInput" var="lan_en"> <s:param name="request_locale" value="'en_US'"></s:param> </s:url> <s:url namespace="/test" action="user" method="addInput" var="lan_cn"> <s:param name="request_locale" value="'zh_CN'"></s:param> </s:url> <a href="<s:property value="#lan_en"/>">EN</a> <a href="<s:property value="#lan_cn"/>">CN</a> |