1.1 什么是I18N问题?
在英文中, 国际化(Internationalization)被缩写为I18N, 即只取首尾两个字母, 中间字母为18个。
问题在哪里?
1.2 一个简单的例子
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
准备好了资源文件之后,我们可以编写下面的代码来测试:
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); }
} |
1.3 Locale对象
Locale对象代表了一种语言环境和国家/地区。
比如,日期、货币等等都跟Locale有关。随着Locale的不同,日期货币的表现形式也不一样。
1.4 Struts1对国际化的支持
l 页面字符串硬编码
l 异常消息的硬编码
l 提示信息的硬编码
1、需要在struts配置文件中指定资源属性文件的位置和名称,如
<message-resources parameter="MessageResources" />
关于message-resources 配置中parameter的值
parameter的值,可以指定资源文件的位置和名称
举例:
<message-resources parameter="MessageResources" />
表示在类路径根目录(WEB-INF/classes目录)下有MessageResources_XX_XX.properties文件(注意:国家代码可以省略,跟java中对资源属性文件的处理一样)
<message-resources parameter="resources.application"/>
表示在类路径根目录下,有一个resources目录,在这个resources目录中存放着所有的application_XX_XX.properties资源属性文件
2、在相应的位置放置相应的文件
MessageResources.properties
MessageResources_zh.properties
MessageResources_en.properties
3、即可运用下述方法,对页面字符串、异常消息、提示消息的硬编码换成国际化的表示方法了!
1.4.1 页面字符串硬编码的替换
用<bean:message key=”xxx”/>来替换
如何用程序切换网页显示的语言
struts利用在session中存放一个Locale对象来达到设置当前语言的目的
默认的情况下,struts根据网页向后台提交时所包含的语言编码信息来提供缺省的Locale对象,这就是我们为什么可以通过更改网页显示语言设置,就能显示不同的语言文字的原因。
struts在session中存放的这个Locale对象,取名为:Globals.LOCALE_KEY 的值,Globals是struts框架提供的一个对象
利用这个原理,我们可以用编程的方式来手工切换整个应用系统的语言。
举例说明
ChangeLanguageAction
String lan = request.getParameter("lan");
Locale locale = new Locale(lan);
request.getSession().setAttribute(Globals.LOCALE_KEY, locale);
ActionForward f = new ActionForward(); f.setPath(request.getHeader("referer")); f.setRedirect(true);
return f; |
1.4.2 异常消息和提示消息的硬编码
l 为什么需要消息处理?
n 比如登录成功的提示
n 比如创建失败的提示
n 等等……总之,程序总是要通过界面来跟用户交互,所以,在交互的过程中,就产生了众多的消息文本
l struts提供了专门的处理机制,来将这些消息文本国际化,避免消息文本的硬编码
l 消息处理,就是在Action和JSP之间传递的消息文本的处理(区别于JSP页面硬编码文本的消息,JSP页面硬编码文本可以使用<bean:message/>标签来处理)
l Struts交互消息,是通过ActionMessages等对象,以及相应的<html:messages/>和<html:errors/>标签来处理的
如何创建消息对象?
l ActionMessages与ActionMessage对象
n ActionMessages对象是ActionMessage对象的集合
n 一个ActionMessage对象,代表一个国际化消息文本(字符串)
l 如何创建ActionMessages对象?
n ActionMessages messages = new ActionMessages();
l 如何创建ActionMessage对象?
n ActionMessage msg = new ActionMessage(“key”);
n 其构造方法带的参数,就是一个在资源属性文件中的key,所以,它能表示一个国际化消息文本
l 如何将ActionMessage对象添加到ActionMessages对象中?
n messages.add(“message_id”,msg);
n 第一个参数(message_id)表示本ActionMessage对象在ActionMessages对象中区别于其它ActionMessage对象的标识符
如何将消息对象从Action中传递到下一个页面(JSP)?
l 首先我们要决定的是,我们要传递的消息是普通消息还是错误消息?
n 普通消息:即普通的消息文本
n 错误消息:即提示错误的消息文本
n 本质上,这两种消息没有什么区别,都是消息文本,但是如果一个页面同时需要显示普通的消息文本和错误消息文本的时候,就需要进行区分了,比如不同类型的消息文本可能要用不同的样式来显示
l 通过一句简单的代码,将ActionMessages对象保存到HttpServletRequest对象中
n 保存普通消息:this.saveMessages(request,messages);
n 保存错误消息:this.saveErrors(request,messages);
n 这就是调用父类(Action)所提供的方法saveMessages()/saveErrors()来保存消息对象
n 实际上,父类的saveMessages()方法,将消息对象保存在了request中,并命名为Globals.MESSAGE_KEY
n saveErrors()方法,将消息对象保存在了request中,并命名为Globals.ERROR_KEY
如何在JSP中使用消息对象?
l 使用<html:messages/>标签来显示消息
l <html:messages/>标签既可以显示普通消息,也可以显示错误消息
l <html:messages/>标签的重要属性:
n name – 消息对象的名称,如果我们调用saveMessages/saveErrors方法来传递消息,那么这个名字不需要标识(struts使用缺省的名称,即Globals.MESSAGE_KEY 或Globals.ERROR_KEY )
n id – (这是必需的属性)因为我们传递的是ActionMessages对象,而不是ActionMessage对象,ActionMessages对象相当于一个集合,我们需要在JSP上依次输出它所包含的消息,因此需要一个id标识一个变量来临时存放其每条消息(与<logic:iterate/>标签的id属性的意义是一样的)
n property – 我们传递的ActionMessages对象,包含了多条消息文本,如果我们只需要显示其中一条,则可以通过property属性来指定显示哪条消息
n message – 可以取值为true或false,如果取值为true,将显示普通消息,如果取值为false,将显示错误消息
<html:errors/>标签
l <html:errors/>标签只显示错误消息
l <html:errors/>标签与<html:messages/>标签类似,但无id属性
l <html:errors/>标签通过提供header/footer属性以及prefix/suffix属性来定制每条消息的显示格式
n header/footer – 定义整个错误消息显示之前(之后)要显示的内容,这些内容也是在资源属性文件中定义的一些key值,默认的情况下,它们的取值分别为:errors.header和errors.footer
n prefix/suffix – 定义每条错误消息显示之前(之后)要显示的内容,这些内容也是在资源属性文件中定义的一些key值,默认的情况下,它们的取值分别为:errors.prefix和errors.suffix
举例如下:
errors.header=<UL>
errors.prefix=<LI>
errors.suffix=</LI>
errors.footer=</UL>