您的位置:首页 > 编程语言 > Java开发

Java程序员从笨鸟到菜鸟之(六十六)细谈struts2(十二)struts2国际化底层大揭秘

2012-06-04 12:24 549 查看
Struts2的博客在前不久已经停止了,但是里面还有很多内容我们都还没接触到,所以现在我们在补充一下struts2的内容。这篇博客我们主要是一块来看一下struts2内对国际化的支持。在了解struts2对资源国际化支持之前,我们先来看一下JDK对国际化的支持,因为如果你看一下啊源码你可以发现,其实struts2中国际化的支持底层主要就是对JDK中提供的国际化的一个封装。

一:JDK对国际化的支持

所谓国际化,就是我们写的应用程序在不同的地域和支持不同语言的场合可以给用户一个用户所在地域的语言支持。也就是说我在中国你的应用程序就给我中国的提示,我在美国你就给我英语的提示。在看具体应用之前我们先来熟悉一下几个JDK中提供资源国际化的类:

1.Local类

Locale 对象表示了特定的地理、政治和文化地区。需要 Locale 来执行其任务的操作称为语言环境敏感的操作,它使用 Locale 为用户量身定制信息。例如,显示一个数值就是语言环境敏感的操作,应该根据用户的国家、地区或文化的风俗/传统来格式化该数值。

使用此类中的构造方法来创建 Locale:

Locale(String language)根据语言创建对象
Locale(String language, String country)根据语言和国家来创建对象
Locale(String language, String country, String variant)根据语言、国家/地区和变量构造一个语言环境。


语言参数是一个有效的 ISO 语言代码。这些代码是由 ISO-639 定义的小写两字母代码。在许多网站上都可以找到这些代码的完整列表,如:http://www.loc.gov/standards/iso639-2/englangn.html。 Locale 类提供了一些方便的国家常量,可用这些常量为常用的语言环境创建 Locale 对象。例如,下面的内容为美国创建了一个 Locale 对象:Locale.US。

创建完 Locale 后,就可以查询有关其自身的信息。使用 getCountry 可获取 ISO 国家/地区代码,使用 getLanguage 则获取 ISO 语言代码。可用使用 getDisplayCountry 来获取适合向用户显示的国家/地区名。同样,可用使用 getDisplayLanguage 来获取适合向用户显示的语言名。有趣的是,getDisplayXXX 方法本身是语言环境敏感的,它有两个版本:一个使用默认的语言环境作为参数,另一个则使用指定的语言环境作为参数。

2.ResourceBundle

资源包包含特定于语言环境的对象。当程序需要一个特定于语言环境的资源时(如 String),程序可以从适合当前用户语言环境的资源包中加载它。简单来说就是通过静态方法来获得程序外界的资源包。使用这种方式,可以编写很大程度上独立于用户语言环境的程序代码,它将资源包中大部分(即便不是全部)特定于语言环境的信息隔离开来。

这使编写的程序可以:

· 轻松地本地化或翻译成不同的语言

· 一次处理多个语言环境

· 以后可以轻松进行修改,以便支持更多的语言环境

当程序需要特定于语言环境的对象时,它使用getBundle方法加载 ResourceBundle 类:

ResourceBundle myResources =
      ResourceBundle.getBundle("MyResources", currentLocale);


这里我们有必要说一下这里的两个参数,第一个参数指定我们外部资源文件的文件名的头,为什么说是文件头呢,要想知道这个我们还得先说一些我们的资源文件的命名规则是:文件头_语言代号_国家代号.properties。这里的文件名是我们自己起的,语言代号和国家代号都是一些定义好的,我们直接去调用就OK了。当程序所要找的语言环境我们没有定义的话,他会默认的去找:文件头.properties,第二个参数是设置我们的地域信息。

资源包包含键/值对。键唯一地标识了包中特定于语言环境的对象。 看到这里相信大家都应该想到这里的资源用什么文件最合适了,对,就是properties文件比较合适,JDK中提供了很多重载的getBundle方法,具体的看下图:




得到ResourceBundle 对象之后,我们可以调用他的一些内置的getxx方法获得到其相应的信息




3.MessageFormat

在国际化中的资源配置文件中我们也经常会看到占位符的形式出现,JDK中之所以可以支持占位符,完全就是看MessageFormat这个类的支持。当然了,这个也只是这个类的其中一个功能。MessageFormat 提供了以与语言无关方式生成连接消息的方式。使用此方法构造向终端用户显示的消息。MessageFormat 获取一组对象,格式化这些对象,然后将格式化后的字符串插入到模式中的适当位置。

注:MessageFormat 不同于其他 Format 类,因为 MessageFormat 对象是用其构造方法之一创建的(而不是使用 getInstance 样式的工厂方法创建的)。工厂方法不是必需的,因为 MessageFormat 本身不实现特定于语言环境的行为。特定于语言环境的行为是由所提供的模式和用于已插入参数的子格式来定义的。

MessageFormat 类提供了两个构造方法,下面我们来看一下:

MessageFormat(String pattern)

构造默认语言环境和指定模式的 MessageFormat。

MessageFormat(String pattern, Locale locale)

构造指定语言环境和模式的 MessageFormat。

在获取到资源信息之后在进行格式化设置的时候我们一般不去new出他的对象,而是用他的一个静态方法:format方法,我们来看一下他提供的一些重载方法:

,%20java.lang.StringBuffer,%20java.text.FieldPosition)]format(Object[] arguments, StringBuffer result, FieldPosition pos)

格式化一个对象数组,并将 MessageFormat 的模式添加到所提供的 StringBuffer,用格式化后的对象替换格式元素。

format(Object arguments, StringBuffer result, FieldPosition pos)

格式化一个对象数组,并将 MessageFormat 的模式添加到所提供的 StringBuffer,用格式化后的对象替换格式元素

format(String pattern, Object... arguments)

创建具有给定模式的 MessageFormat,即为带有占位符的值。并用它来格式化给定的参数。

好了,几个重要的类介绍完了以后,我相信大家对资源国际化一定有和一个深刻的了解了吧。下面我们就以一个简单的小实例来把这几个类的用法串起来:

Locale locale = Locale.US;
ResourceBundle bundle = ResourceBundle
.getBundle("caoshenghuan", locale);
String value = bundle.getString("hello");
String result = MessageFormat.format(value, new Object[] { "曹胜欢" });
System.out.println(result);


我们可以看到,代码很简单,就是获取外部资源文件的key为hello的资源值。下面我们看一下资源文件的写法:

caoshenghuan_en_US.properties:
hello=helloworld{0}


Struts2国际化是建立在Java国际化的基础上的,一样是通过提供不同国家/语言环境的消息资源,然后通过ResourceBundle

加载指定Locale对应的资源文件,再取得该资源文件中指定key对应的消息--整个过程与J***A程序的国家化完全相同,只是Struts2框架对J***A程序国际化进行了进一步封装,从而简化了应用程序的国际化。

Struts2需要国际化的部分

1.类型转换:

2.数据校验:

3.验证框架xml配置文件的国际化:RegisterAction-validation.xml文件<message key="username.xml.invalid"/>

4.JSP页面的国际化:<s:text name="addUser"/>

5.Action的国际化:利用ActionSupport类提供的getText()方法.

6.Struts2中加载全局资源文件

struts.xml

<constant name="struts.custom.i18n.resources" value="baseName"/>



struts.properties

struts.custom.i18n.resources=baseName

访问国际化消息

Struts2访问国际化消息主要有如下三种方式:

(1)JSP页面:<s:text name="key"/>

(2)Action类中:使用ActionSupport类的getText方法。

(3)表单元素的Label里:为表单元素指定一个key属性

输出带占位符的国际化消息

Struts2中提供了如下两种方式来填充消息字符串中的占位符

(1)JSP页面,在<s:text.../>标签中使用多个<s:param.../>标签来填充消息中的占位符。

(2)Action中,在调用getText方法时使用getText(String aTextName,List args)或getText(String key, String[] args)方法来填充占位符。

除此之外,Struts2还提供了对占位符的一种替代方式,这种方式允许在国际化消息资源文件中使用表达式,对于这种方式,则可避免在使用国际化消息时还需要为占位符传入参数值。如下在消息资源中使用表达式succTip=${username}, 欢迎, 您已经登录!

在上面的消息资源中,通过使用表达式,可以从ValueStack中取出该username属性值,自动填充到该消息资源中。

加载资源文件的方式

(1)加载全局资源文件: <constant name="struts.custom.i18n.resources" value="baseName"/>

(2)包范围资源文件 :为Struts2指定包范围资源文件的方法是,在包的根路径下建立多个文件名为package_language_country.properties的文件,一旦建立了这个系列的国际化资源文件,应用中处于该包下的所有Action都可以访问该资源文件。需要注意的是上面的包范围资源文件的baseName就是package,不是Action所在的包名。

(3)Action范围资源文件:在Action类文件所在的路径建立多个文件名为ActionName_language_country.properties的文件。

(4)临时指定资源文件:<s:i18n.../>标签的name属性指定临时的国际化资源文件

对于在JSP中访问国际化消息,则简单的多,他们又可以分为两种形式:

(1)对于使用<s:i18n.../>标签作为父标签的<s:text.../>标签、表单标签的形式:

a、将从<s:i18n.../>标签指定的国际化资源文件中加载指定key对应的消息。

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

c、如果经过上面步骤一直找不到该key对应的消息,将直接输出该key的字符串值。

(2)如果<s:text.../>标签、表单标签没有使用<s:i18n.../>标签作为父标签:

直接加载struts.custom.i18n.resources常量指定baseName的系列资源文件。如果找不到该key对应的消息,将直接输出该key的字符串值。允许用户自行选择程序语言

Struts2国际化的运行机制

在Struts2中,可以通ActionContext.getContext().setLocale(Locale arg)设置用户的默认语言。为了简化设置用户默认语言环境,Struts2提供了一个名为i18n的拦截器(Interceptor),并且将其注册在默认的拦截器中(defaultStack)。 i18n拦截器在执行Action方法前,自动查找请求中一个名为request_locale的参数。如果该参数存在,拦截器就将其作为参数,转换成Locale对象,并将其设为用户默认的Locale(代表国家/语言环境)。除此之外,i18n拦截器还会将上面生成的Locale对象保存在用户Session的名为WW_TRANS_I18N_LOCALE的属性中。一旦用户Session中存在一个名为WW_TRANS_I18N_LOCALE的属性,则该属性指定的Locale将会作为浏览者的默认Locale。

<%@ page language="java" contentType="text/html; charset=GBK"%>
<%@taglib prefix="s" uri="/struts-tags"%>
<script. type="text/javascript">
function langSelecter_onChanged()
{
 document.getElementById("langForm").submit();
}
</script>
<%-- 设置SESSION_LOCALE为用户session中的WW_TRANS_I18N_LOCALE属性值 --%>
<s:set name="SESSION_LOCALE" value="#session['WW_TRANS_I18N_LOCALE']"/>
<%-- 使用lee.Locales创建locales实例 --%>
<s:bean id="locales" name="lee.Locales">
 <%-- 为locales实例传入current参数值,如果SESSION_LOCALE为空,则返回ValueStack中locale属性值(即用户浏览器设置的Locale) --%>
 <s:param name="current" value="#SESSION_LOCALE == null ? locale : #SESSION_LOCALE"/>
</s:bean>
<%-- 让用户选择语言的表单 --%>
<form. action="<s:url/>" id="langForm"
    style="background-color:#bbbbbb; padding-top: 4px; padding-bottom: 4px;">
    <s:text name="languag"/>
 <s:select label="Language" list="#locales.locales" listKey="value" listValue="key"
        value="#SESSION_LOCALE == null ? locale : #SESSION_LOCALE"
        name="request_locale" id="langSelecter"
        nchange="langSelecter_onChanged()" theme="simple"/>
</form>


在其他页面中包含该页面:

<s:include value="selectlanguage.jsp"/>
在struts.xml文件中增加Action通配符的配置:
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
        "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
 <constant name="struts.custom.i18n.resources" value="messageResource"/>
 <constant name="struts.i18n.encoding" value="GBK"/>
    <package name="lee" extends="struts-default">
  <!-- 使用通配符定义Action的name -->
  <action name="*">
   <!-- 将请求转发给/WEB-INF/jsp/路径下同名的JSP页面 -->
   <result>/WEB-INF/jsp/{1}.jsp</result>
  </action>
    </package>
</struts>



用户主动选择国际化应用介绍

首先配置struts,xml

<constant name="struts.custom.i18n.resources" value="messageResouce"></constant>

然后编写:messageResouce_zh_CN.properties和messageResouce_en_US.properties

具体代码示例:

stuNumber=StudentNumber

password=Password

login=login

loginInfo=Play login

语言选择的地方可以使用链接到action中,需向action传递request_locale=en_US或者request_locale=zh_CN参数就可以简单的实现语言的切换



页面代码如下:

<a href="languageAction?request_locale=en_US">en</a>

<a href="languageAction?request_locale=zh_CN">cn</a>

然后再action中直接返回即可,在返回的界面得到messageResouce_zh_CN的属性值,如下代码示例:

label="%{getText('stuNumber')}"

label="%{getText('password')}"
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐