Java程序的国际化主要通过三个类完成:
java.util.ResourceBundle:用于加载一个资源包。
java.util.Locale:对应一个特定的国家/区域、语言环境。
java.text.MessageFormat:用于消息格式化。
而资源文件的命名方式主要有三种:baseName_language_country.properties、baseName_language.properties和baseName.properties。
以下的程序可以得到Java所支持的语言和国家:
public static void main(String[] args){
Locale[] localeList = Locale.getAvailableLocales();
for (int i=0;i<localeList.length;i++){
System.out.println(localeList[i].getdisplayCountry() + "=" + localeList[i].getCountry() + " " + localeList[i].getDisplayLanguage() + "=" + localeList[i].getLanguage());
}
}
}
使用国际化的代码如:
public static void main(String[] args){
Locale myLocale = Locale.getDefault();
ResourceBundle bundle = ResourceBundle.getBundle("mess",myLocale);
System.out.println(bundler.getString("hello"));
}
}
如果在资源文件中,存在例如msg = Hello,{0}!Today is {1}.这样需要程序动态插入参数的文本,则需要使用MessageFormat类的format()方法。
除了使用资源文件,我们也可以使用类文件来代替资源文件。使用Java文件代替资源文件的Java文件必须满足:1。类名必须是baseName_language_country,这与属性文件的命名相似。2。该类必须继承ListResourceBundle,并重写getContents方法,该方法返回Object数组。该数组的每一个项都是key-value对。
//定义资源
private final Object myData[][] = {
{"msg","类文件消息:{0},您好!今天是{1}"}
};
@Override
public Object[][] getContents(){
return myData;
}
}
对于简体中文的Locale,ResourceBundler搜索资源的顺序是:
baseName_zh_CN.class;baseName_zh_CH.properties;baseName_zh.class;baseName_zh.properties;baseName.class;baseName.properties
Struts2访问国际化消息,主要有3种方式:1)JSP页面输出国际化消息,可以使用Struts2的<s:text.../>标签,该标签可以指定一个name属性,该属性就是资源文件中的key。2)在Action中,可以使用ActionSupport类的getText方法,该方法可以接受一个name参数,指定了国际化资源文件中的key。3)表单元素的Label,可以为表单标签指定一个key属性,这个key指定了国际化资源文件的key。
对于带占位符的国际化消息,在Action中,则需要使用getText(String key, String[] args)来处理,其中args就是参数列表;而在页面中,则需要为<s:text.../>标签指定<s:param.../>子标签。如:
< s:param >< s:property value ="username" ></ s:param >
</ s:text >
在Struts2中,还有一种更加简单的表达方式。我们可以在资源文件中写例如这样的表达式:failTip=${username},对不起,您不能登录!,通过使用表达式,可以从ValueStack中取出username属性值,自动填充到消息资源中。这在Action中很常用。
对于一个大型应用而言,国际化资源文件的管理也是一个非常浩大的工程。为了能更好的分而治之,Struts2允许针对不同的模块、不同Action来组织国家化资源文件。
为Strut2应用指定包范围资源文件的方法是:在包的跟路径下建立多个文件名为package_language_country.properties的文件,一旦建立了这个系列的国际化资源文件,应用中处于该包下的所有Action都可以访问该资源文件。
例如一个Action为codes\packageScope\src\lee\action\LoginAction.java,那么我们可以提供package_zh_CN.properties和package_en_US.properties两个文件放在codes\packageScope\src\lee目录下,那么这两个文件就能被lee包及lee包下所有子包内的Action所能访问。
同时,我们也可以为LoginAction单独指定一份国际化资源文件。即在codes\packageScope\src\lee\action目录下,分别建立LoginAction_zh_CN.properties和LoginAction_en_US.properties两个文件。
有时候,处于某种特殊的原因,我们需要临时指定资源文件,那么就需要使用<s:i18n.../>来充当<s:text.../>标签的父标签了。如:
< s:text name ="loginPage" />
</ s:i18n >
< s:i18n name ="tmp" >
< s:form action ="login" >
< s:textfield name ="username" key ="user" />
< s:textfield name ="password" key ="pass" />
< s:submit key ="login" />
</ s:form >
</ s:i18n >
加载资源文件的顺序:
- 优先加载系统中保存在ChildAction的类文件相同位置,且baseName为ChildAction的系列资源文件。
- 如果在1)中找不到key对应的消息,且ChildAction有父类ParentAction,则加载系统中保存在ParentAction的类文件相同位置,且baseName为ParentAction的系列资源文件。
- 如果2)中找不到key对应的消息,且ChildAction有实现接口IChildAction,则加载系统中保存在IChildAction的类文件相同位置,且baseName为IChildAction的系列资源文件。
- 如果3)中找不到key对应的消息,且ChildAction有实现接口ModelDriven(即使用模型驱动模式),则对于getModel()方法返回的model对象,重新执行1)步操作。
- 如果在4)中找不到key对应的消息,则查找当前包下baseName为package的系列资源文件。
- 如果在5)中找不到key对应的消息,则沿着当前包上溯,直到最顶层包来查找baseName为package的系列资源文件。
- 如果在6)中找不到key对应的消息,则查找struts.custom.i18n.resources常量指定baseName的系列资源文件。
- 如果经过上面步骤一直找不到key对应的消息,将直接输出该key的字符串值
对于在JSP中访问国际化消息,则简单很多,可以分为两种形式:
1)对于使用<s:i18n.../>标签作为父标签的<s:text.../>标签,将直接从<s:i18n.../>标签指定的国际化资源文件中加载指定key对应的消息,如果没有,则读取struts.custom.i18n.resources常量指定baseName的系列文件。如果还没有,直接输出key。
2)对于没有使用<s:i18n.../>标签作为父标签的<s:text.../>标签,则直接读取struts.custom.i18n.resources常量指定baseName的系列文件。如果没有,直接输出key。
Struts2中, 我们可以通过ActionContext.getContext().setLocale(Locale arg)设置用户的默认语言。同时在Struts2 的defaultStack拦截栈中,i18n拦截器也能设置默认语言。i18n在执行Action方法前,会自动查找一个名为request_locale的参数。如果这个参数存在,则拦截器会将其转换成Locale对象,并设为默认的Locale。同时,这个Locale对象会保存在Session的名为WW_TRANS_I18N_LOCALE的属性中。一旦用户的Session中有WW_TRANS_I18N_LOCALE属性,则属性指定的Locale将会作为浏览器的默认Locale。因此,用户也可利用此功能来开发自行选择语言的功能。