Struts应用的国际化

Struts应用的国际化
1.1 本地化与国际化的概念
       国际化(简称I18N)指的是在软件设计阶段,就应该使软件具有支持多种语言和地区的功能。

       本地化意味着针对不同语言的客户,开发出不同的软件版本;国际化意味着同一个软件可以面向使用各种不同语言的客户。


如果一个应用支持国际化,它应该具备以下特征:

l         当应用需要支持一种新的语言时,无需修改应用程序代码。

l         文本、消息和图片从源程序代码中抽取出来,存储在外部。

l         应该根据用户的语言和地理位置,对与特定文化相关数据,如日期、时间和货币,进行正确的格式化。

l         支持非标准的字符集。

l         可以方便快捷地对应用作出调整,使它适应新的语言和地区。

    I18N是Internationalization的简称,因为该单词的首字母I与尾字母N中间隔着18个字符,由此得名。
 

1.2 Web应用的中文本地化
       无论是对Web应用的本地化还是国际化,都会涉及字符编码转换问题。Web应用的各种可能的输入和输出流如图,当数据流的源与目的地使用不同的字符编码时,就需要对字符编码进行正确的转换。


1.2.1 处理HTTP请求数据编码
       默认情况下,IE浏览器发送请求时采用”ISO-8859-1”字符编码,如果Web应用程序要正确地读取用户发送的中文数据,则需要进行编码转换。

       两种方法:

l         在处理请求前,先设置HttpServletRequest对象的字符编码:

 request.setCharacterEncoding(“gb2312”);
 

l         对用户输入的请求数据进行编码转换:

 String clientData = request.getParameter(“clientData”);

 if ( clientData != null )

    clientData = new String( clientData.getBytes(“ISO-8859-1”), ”GB2312” );
 

1.2.2 处理数据库数据编码
 Connection con = DbUtil.connectToDb();

 PreparedStatement pstmt = null;

 ResultSet rs = null;

 pStmt = con.prepareStatement(“select FILED1 from MYTABLE”);

 rs = pStmt.executeQuery();

 while ( rs.next() ) {

   String field1 = rs.getString(“FILED1”);

   String field1_ch = new String(field1.getBytes(“ISO-8859-1”), “GB2312” );

   //process data
 }
 

如果数据库系统字符编码使用的”ISO-8859-1”的话,那么需要如上的操作转换为GB2312。

 

1.2.3 处理XML配置文件编码
       如果在XML文件中包含中文,可以将XML文件的字符编码设为”GB2312”,这样,当Java程序加载和解析XML文件时无需再进行编码转换:

 <?xml version=’1.0’ encoding=”GB2312” ?>
 

1.2.4 处理响应结果的编码
       可以通过以下方式来设置响应结果的编码:

l         在Servlet中

 response.setContentType(“text/html;charset=GB2312”);

l         在JSP中

         <%@ page contentType=”text/html;charset=GB2312” %>

l         在HTML中

        <head>

          <META HTTP-EQUIV=”Content-Type” CONTENT=”text/html;charset=GB2312”>

        </head>

1.3 Java对I18N的支持
       Java在其核心库中提供了支持I18N的类和接口。

1.3.1 Locale类
       java.util.Locale类是最重要的Java I18N类。

       Locale类的实例代表一种特定的语言和地区。如果Java类库中的某个类在运行时需要根据Locale对象来调整其功能,那么称这个类是本地敏感的(Locale-Sensitive)。例如,java.text.DateFormat类就是本地敏感的,因为它需要依照特定的Locale对象来对日期进行相应的格式化。

       创建Locale对象时,需要明确地指定其语言和国家代码:

  Locale usLocale = new Locale(“en”, “US”);  //美国的

  Locale chLocale = new Locale(“ch”, “CH”);  //中国的
 

       第一个参数是语言代码,由两个小写字母组成,遵从ISO-639规范,可以从http://www.unicode.org/unicode/onlinedat/languages.html中获得完整的语言代码列表。

       第二个参数是国家代码,由两个大写字母组成,遵从ISO-3166规范,可以从http://www.unicode.org/unicode/onlinedat/countries.html中获得完整的国家代码列表。

       Locale类提供了几个静态常量,代表一些常用的Locale实例,如日本,可以使用:

              Locale locale1 = Locale.JAPAN

            Locale locale2 = new Locale(“ja”, “JP”);

1.      Web容器中Locale对象的来源
Java虚拟机在启动时会查询操作系统,为运行环境设置默认的Locale,Java程序可以调用java.util.Locale类的静态方法getLocale()来获得默认的Locale。

                 Locale defaultLocale = Locale.getDefautl(); 


2.      在Web应用中访问Locale对象
对于Web应用程序,通常不必创建自己的Locale实例,因为Web容器会负责创建所需的Locale实例。在应用程序中,可以调用HttpServletRequest对象的以下两个方法,来取得包含Web客户的Locale信息的Locale实例:

public java.util.Locale getLocale();

public java.util.Enumeration getLocales();
 

这两个方法都会访问HTTP请求中的Accept-Language头信息,getLocale()方法返回客户优先使用的Locale,而getLocales()方法返回一个Enumeration集合对象,它包含了按优先级降序排列的所有Locale对象。如果客户没有配置任何Locale,getLocale()方法会返回默认的Locale。

大多数浏览器允许用户配置Locale,如IE,在Internet选项的语言中,可以进行配置:


3.      在Struts应用中访问Locale对象
由于Web服务器并不和客户浏览器保持长期的连接,因此每个发送到Web容器的HTTP请求中都包含了Locale信息,Struts配置文件的<controller>元素的Locale属性指定是否把Locale对象保存在session范围内,默认是true。在处理每一个用户请求时,RequestProcessor类都会调用它的processLocale()方法:

protected void processLocale(HttpServletRequest request,

                            HttpServletResponse response)  {

//Are we configured to select the Locale automatically?
if ( !moduleConfig.getControllerConfig().getLocale() )  {

  return;
}

 
//Has a Locale already been selected?
HttpSession session = request.getSession();

if ( session.getAttribute(Globals.LOCALE_KEY) != null )  {

  return;
}

 
//Use the Locale returned by the servlet container(if any)
Locale locale = request.getLocale();

if ( locale != null )  {

  session.setAttribute(Globals.LOCALE_KEY, locale);
}

}
 

尽管每次发送的HTTP请求都包含Locale信息,processLocale()方法把Locale对象存储在session范围内,需要满足两个条件:

l         Struts配置文件的<controller>元素的locale属性为true

l         在session范围内Locale对象不存在

       在Struts应用中可以很方便地读取Locale信息,在Action类中,可以调用Struts Action基类中定义的getLocale()方法。return RequestUtils.getUserLocale(request, null);
  public static Locale getUserLocale(HttpServletRequest request, String Locale)  {

Locale userLocale = null;

HttpSession session = request.getSession(false);

 
if ( locale == null )  {

  locale = Globals.LOCALE_KEY;

}

 
//Only check session if sessions are enabled
if ( session != null )  {

  userLocale = (Locale)session.getAttribute(locale);

}

 
if ( userLocale == null )  {

  //Returns Locale based on Accept-Language header or the server default
  userLocale = request.getLocale();

}

 
return userLocale;

  }
 

 
       getUserLocale()方法先通过HttpServletRequest参数获得HttpSession对象,然后再通过HttpSession对象来读取Locale对象,如果存在HttpSession对象并且其中存储了Locale对象,就返回该Locale对象,否则就直接调用HttpServletRequest的getLocale()方法获取Locale对象,并返回。

1.3.2 ResourceBundle类
       java.util.ResourceBundle类提供存放和管理与Locale相关的资源的功能。这些资源包括文本域或按钮的Label、状态信息、图片名、错误信息和网页标题等。

       Struts框架没有直接使用Java语言提供的ResourceBundle类,而是提供了:

l         org.apache.struts.util.MessageResource
l         org.apache.struts.util.PropertyMessageResource
1.3.3 MessageFormat类和复合消息
       Java的ResourceBundle类和Struts的MessageResource类都允许使用静态和动态的文本。静态的就是在ResourceBundle中添加固定的信息:

       error.requriedfield.name=The Name field is requried to save.

error.requriedfield.phone=The Phone field is requried to save.

但是如果表单有100个域,就需要写100个,就使得我们的ResourceBundle很庞大并且难于维护,这就可以使用动态方式:

error.requriedfield=The {0} field is requried to save.

lable.phone=Phone

lable.name=Name

       以此类推,还可以使用{1}、{2}来表示,在运行时,MessageFormat类的format()方法可以把参数{0}替换成真正的动态文本内容。

import java.util.ResourceBundle;

import java.util.Locale;

import java.text.MessageFormat;

 
public class FormatExample  {

  public static void main(String[] args)  {

//Load the resource bundle
ResourceBundle bundle = ResourceBundle.getBundle(“ApplicationResources”);

//Get the message template
String requriedFieldMessage = bundle.getString(“error.requriedfield”);

//Create a String array of size one to hold the arguments
String[] messageArgs = new String[1];

//Get the “Name” field from the bundle and load it in as an argument
messageArgs[0] = bundle.getString(“lable.name”);

//Format the message using the message and the arguments
String formattedNameMessage =

           MessageFormat.format(requriedFieldMessage, messageArgs);

System.out.println(formattedNameMessage);

//Get the “Phone” field from the bundle and load it in as an argument
messageArgs[0] = bundel.getString(“lable.phone”);

//Format
String formattedPhoneMessage =

           MessageFormat.format(requriedFieldMessage, messageArgs);

System.out.println(formattedPhoneMessage);

  }

}
 

通常把包含可变数据的消息成为复合消息,复合消息允许在程序运行时把动态数据加入到消息文本中,这能够减少Resource Bundle中的静态消息数量,从而减少把静态消息文本翻译成其他Locale版本所花费的时间。

1.4 Struts框架对国际化的支持
       Struts框架对国际化的支持体现在能够输出和用户Locale相符合的文本和图片上。当Struts配置文件的<controller>元素的locale属性为true时,Struts框架把用户的Locale实例保存在session范围内,这样,Struts框架能自动根据这一Locale实例来从Resource Bundle中选择合适的资源文件。如图,当用户的Locale为英文时,Struts框架就会向用户返回来自于application_en.properties文件的文本内容;当用户的Locale为中文时,Struts框架就会向用户返回来自于application_ch.properties文件的内容。


1.4.1 创建Struts的Resource Bundle
       对于多应用模块的Struts应用,可以为每个子应用配置一个或多个Resource Bundle,饮用模块中的Action、ActionForm Bean、JSP页和客户化标签都可以访问这些Bundle。Struts配置文件中的每个<message-resources>元素定义一个Resource Bundle。当应用中包含多个Resource Bundle时,它们通过<message-resources>元素的key属性来区别。

  <message-resources parameter=”application” />

  <message-resources key=”IMAGE_RESOURCE_KEY” parameter=”imageresources” />
 

       Resource Bundle的持久化消息文本存储在资源文件中,其扩展名为”.properties”,默认资源文件应该取名为application.properties,如果应用程序需要支持中文用户,可以再创建一个包含中文消息的资源文件,文件名为:application_ch_CN.properties或application_ch.properties。

       当Struts框架处理Locale为中文的用户请求时,它会依次搜索如下资源文件:

l         application_ch_CN.properties

l         application_ch.properties

l         application.properties

       Struts框架在/WEB-INF/classes/目录下依次寻找这些资源文件。如果在配置Resource Bundle时还给定了包名,那么properties文件应该在classes/对应的包名目录下。

1.4.2 访问Resource Bundle
       Struts应用的每个Resource Bundle和org.apache.struts.util.MessageResources类(实际上是其子类PropertyMessageResources)的一个实例对应。MessageResources对象中存放了来自资源文件的文本。当应用初始化时,这些MessageResources实例被存储在ServletContext中(即application范围内),因此任何一个Web组件都可以访问它们。


Struts应用、子应用模块、ResourceBundle和资源文件之间存在以下关系:

l         一个Struts应用可以有多个子应用模块,必须有且只有一个默认子应用模块

l         一个子应用模块可以有多个Resource Bundle,必须有且只有一个默认Resource Bundle

l         一个Resource Bundle可以有多个资源文件,必须有且只有一个默认资源文件

在Struts应用中访问Resource Bundle的途径:

1.      通过编程来访问Resource Bundle
在Action基类中定义了getResources(request)方法,它可以返回默认的MessageResources对象,代表当前应用模块使用的默认Resource Bundle,如果要获得特定的MessageResources对象,可以调用Action基类的getResources(request, key)方法,key对应<message-resources>元素的key属性。

org.apache.struts.util.MessageResources的getMessage()方法有几种重载形式:

l         根据参数指定的Locale检索对应的资源文件,然后返回和参数key对应的消息文本:

  getMessage(java.util.Locale locale, java.lang.String key);

l         根据参数指定的Locale检索对应的资源文件,然后返回和参数key对应的消息文本,args参数用于替换复合消息文本中的参数:

  getMessage(java.util.Locale locale, java.lang.String key, java.lang.Object[] args);

l         根据默认的Locale检索对应的资源文件,然后返回和参数key对应的消息文本:

  getMessage(java.lang.String key);

2.      使用和Resource Bundle绑定的Struts组件
Struts框架中的许多内在组件和Resource Bundle是绑定在一起的,如:

l         ActionMessage类和<html:errors>标签
每个ActionMessage实例代表Resource Bundle中的一条消息。调用ActionMessage的构造方法时,需要传递消息key。一般在ActionForm Bean的validate()方法中:

      errors.add(“username”, new ActionMessage(“hello.no.username.error”);

对于复合消息,在创建ActionMessage对象时,调用带两个参数的构造方法:ActionMessage(java.lang.String key, java.lang.Object[] values),values用于替换复合消息中的参数。

在JSP页面中,使用<html:errors>标签,就能读取显示ActionErrors集合众所有的ActionMessage对象包含的消息文本。

l         Struts Bean标签库的<bean:message>标签

<bean:message>标签从应用的Resource Bundle中获取消息字符串。如:

     <head><title><bean:message key=”hello.jsp.title” /></title></head>

<bean:message>标签根据存储在session范围内的Locale实例,从默认的Resource Bundle中检索和Locale对应的资源文件,再从资源文件中读取和”hello.jsp.title”对应的消息字符串。<bean:message>标签还有一个属性bundle,它和<message-resources>元素的key属性对应,如果没有,将访问默认的Resource  Bundle。

l         在Validator验证框架中访问Resource Bundle

l         在声明型异常处理中访问Resource Bundle

1.5 对helloapp应用实现国际化
1.5.1 对JSP文件的文件、 图片和按钮进行国际化
(1)   设置字符串编码。

可以将所有的JSP页面的字符编码统一设为UTF-8:

  <%@ page contentType=”text/html;charset=UTF-8” language=”java” %>

(2)   对文本国际化。

在JSP文件中不应该直接包含本地化的消息文本,而应该通过<bean:message>标签从Resource Bundle中获得。

(3)   对按钮国际化

<html:submit property=”submit”>

<bean:message key=”hello.jsp.page.submit”/>

</html:submit>

(4)   对图片国际化

 <html:img pageKey=”hello.jsp.page.strutsimage” altKey=”hello.jsp.page.struts” />

1.5.2 创建临时中文资源文件
       因为中文资源文件还需要进行转换,所以创建一个临时的,下一步进行转换,命名为application_temp.properties。

1.5.3 对临时资源文件进行编码转换
       JDK提供了native2ascii命令,它能够实现字符编码转换。转换上一步的临时中文资源文件:native2ascii –encoding gb2312 application_temp.properties application_zh_CN.properties 

将会把temp中的中文转换成”/u7b2c/u4e00/u4e2a….”形式。需要验证,可能转换会错误。

1.5.4 创建英文资源文件
       和application.properties相同,只是文件名叫application_en.properties。

1.5.5 采用Servlet过滤器设置请求数据的字符编码
       调用HttpServletRequest的setCharacterEncoding(“UTF-8”)方法,能够把用户的请求数据的字符编码也设为UTF-8,这样,Wen应用的输入和输出都采用同一种字符编码,就无需在程序中进行编码转换了。


编写SetCharacterEncodingFilter.java类,并在web.xml中加入

<filter>

  <filter-name>Set Character Encoding</filter-name>

  <filter-class>SetCharacterEncodingFilter</filter-class>

</filter>

<filter-mapping>

  <filter-name>Set Character Encoding</filter-name>

  <url-pattern>/*</url-pattern>

</filter-mapping>
 

1.5.6 运行国际化的helloapp应用
       通过修改IE选项的语言信息,可以改变使用的Locale信息。

    在同一个会话中,Struts框架仅读取HTTP请求的Locale信息一次,然后就把Locale对象保存在session范围内,因此在同一个会话中,Locale对象保持不变,选用的资源文件也不会变化。
 

1.6 异常处理的国际化
1.7 小结
       与国际化密切相关的两个组件是Locale和Resource Bundle:

l         Locale:包含了用户的本地化信息,如语言和国家

l         Resource Bundle:包含了多个消息资源文件,每个消息资源文件存放和一种Locale相对应的本地化消息文本。

       Struts框架在初始化时,把Resource Bundle(即MessageResources对象)存储在application范围内,在响应用户请求时,把包含用户Locale信息的Locale实例存储在session范围内。Struts框架能自动根据这一Locale实例,从Resource Bundle中检索相应的资源文件,再从资源文件中读取本地化的消息文本。

       对Struts应用实现国际化应该遵循以下原则:

l         尽量不在Servlet中使用含非英文字符的常量字符串。

l         对于JSP文件,应该对page指令中的charset属性进行相应的设置。

l         不要在JSP文件中直接包含本地化的消息资源,而应该把消息资源存放在Resource Bundle的资源文件中。

l         不必在每个JSP或Servlet中设置HTTP请求的字符编码,可以在Servlet过滤器中设置:HttpServletRequest.setCharacterEncoding(String encoding);

l         尽量使用”UTF-8”作为HTTP请求和响应的字符编码,而不是”GBK”或”GB2312”
l         充分考虑底层数据库所使用的编码,它可能会给应用程序的移植带来麻烦。


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/yuanfen127/archive/2007/10/16/1826661.aspx

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值