实现 Java 企业级应用的多语言(国际化)支持
2009-12-20 00:00:00 来源:WEB开发网在完成本文所有内容的阅读和实践前,本文假定您已具备了 Java ResouceBundle、Java Locale和J2EE方面的知识,同时熟悉Eclipse IDE开发环境以及Eclipse插件的安装、配置和使用。
IGT开发背景
软件全球化支持,被公认为是电子商务市场成功的一个关键部分。实时请求方式的电子商务,在"提供英语或其它语言版本的问题解答"方面,面临了新的挑战。在过去几年中,为了符合 "IBM的全球化标准",无论是那些新开发的,抑或是那些以英文版用户为设计初衷的软件产品,都要求能够被全球化。为使运行在单机服务器或终端处理机上的软件,能够在多语言环境(例如互联网)中,进行正确的多语言数据处理,数据显示以及日志,软件开发者不得不耗费巨大的精力。那么,如何才能成功解决这种新的需求难题呢?
全球化开发过程中,我们找到了一个有效的解决方案,即使用一个功能增强的Eclipse插件来简化全球化开发工作。在Eclipse 3.0版本中,Eclipse已为使用者提供了一个名为"Externalize String"的插件(外部化字符串插件)。虽然此Externalize String插件已具备了"提取字符串,修改代码,以及自动创建属性文件"的功能。但是经此插件处理的软件,不能在复杂的Internet环境中分离地处理多语言的数据显示和日志记录, 所以不适用于多用户的B/S应用。
基于以上各因素,最终我们开发出了一个新的Eclipse插件来实现软件国际化的目标。与原先的"Externalize String"插件相比,功能增强后的全球化插件--IBM Globalization Tool(简称为IGT),不仅完善了Externalize String所具有的"抽取核心字符串,修改代码,以及自动创建属性文件"的功能,还为用户提供了一个具有 "处理客户端地域信息,响应不同用户请求,以及创建多语言日志"功能的中间层。IGT允许一个服务实例,通过用一个在全球化过程中自动创建的称之为"XX Resources"的集合类对象,使得应用程序软件能够根据客户端的实际位置信息来显示多语言数据。在这个被称为"XX Resources"集合类中,每个被称为"资源入口(Resource Entry)"类的对象,都对应地指向了某个存放在属性文件里的消息字符串。而这种 "资源入口(Resource Entry)" 对象,既可以被开发人员自行实现或者使用默认由工具生成的。 基于这种理念设计出的IGT,为我们提供了一个更为灵活和快捷的国际化J2EE 企业级应用程序的方式。
下载组件
需要下载并安装的组件列表
表 1. 在这篇文章中用到的组件及版本
Component | Version |
Eclipse IDE | 3.1/3.0 |
IGT | 1.0 |
Java SDK 1.4.1 | 1.4.2 |
Tomcat | 5.0.16 |
下载需要的组件你需要的,站点被列在了资源一节中。
安装IGT
您需要根据您Eclipse版本, 把IGT解压到Eclipse的plugin文件夹下,重新启动Eclipse就可以完成IGT的安装了。验证IGT的安装从Eclipse界面, 如下图所示。
(图1 Eclipse菜单栏和工具栏界面)
实例1, 使用IGT实现一个C/S应用的全球化支持
本文将首先通过一个简单的C/S应用的实例(实例1简称例1)向您介绍IGT的使用方法。
例1实现一个简单的C/S应用程序,客户机Client和服务器(Server)能够进行基于Socket方式的通信。程序模拟了位于不同地区的客户机,同时向服务器提出服务请求。服务器在接收到客户机的请求后进行相应的处理,并将结果返回给客户机,同时在服务器上按照指定语言显示日志信息。
例1中用MultipleClients类和SocketServer类分别实现客户机和服务器的功能。
MultipleClients类创建了5个分别来自Japan,US,France,German,China的客户机类的实例。它们同时向服务器提出logon,Add, Update,Remove, Rollback和Logoff 这5类不同的服务请求,同时接受服务器的返回信息,并将返回的信息显示在客户端。
new ClientThread( addr , port, "Locale.US", "Login/Add/Remove/Update/Logoff" ),模拟了一个位于US的客户机向服务器发出连续的 "Login/Add/Remove/Update/Logoff" 五种动作的请求。
SocketServer类主要实现的功能:1、服务器响应客户机请求。2、显示动作请求在服务端. 3, 返回相应动作结素消息给客户机。
在未使用IGT去实现程序的全球化支持时,客户端和服务端的运行结果如下:
客户端
Server response to client 0[client:US] : Login server succefully!
Server response to client 4[client:GERMAN] : Login server succefully!
Server response to client 4[client:GERMAN] : Perform action Add succefully!
Server response to client 4[client:GERMAN] : Perform action Rollback succefully!
Server response to client 4[client:GERMAN] : Perform action Remove succefully!
Server response to client 3[client:FRANCE] : Login server succefully!
Server response to client 2[client:JAPAN] : Login server succefully!
Server response to client 3[client:FRANCE] : Perform action Remove succefully!
Server response to client 0[client:US] : Perform action Add succefully!
Server response to client 1[client:CHINA] : Login server succefully!
Server response to client 4[client:GERMAN] : Perform action Logoff succefully!
….
服务端
Server Started the service......
US logged on.
CHINA logged on.
GERMAN logged on.
FRANCE logged on.
JAPAN logged on.
US perfom action Add.
GERMAN perfom action Add.
GERMAN perfom action Rollback.
GERMAN perfom action Remove.
…
从以上显示结果中,可以发现服务器的日志信息和反馈信息都是英语。对于非英语用户来说软件的易用性不好。
下面,我们将在Eclipse平台下使用IGT插件实现增加服务器端程序的多语言支持,不同语言的客户得到不同语言的反馈, 并以指定语言记录日志信息。
使用IGT实现C/S应用程序的多语言支持
首先,选择要进行全球化的程序文件。为使服务器能够"根据客户端的语言信息,对客户端提交的申请做出相应的语言处理,并将相应的语言显示结果返回客户端",所以我们只需要对服务器程序(SocketServer.java)中的处理信息字符串做全球化的处理,主要处理硬编码的字符串信息。然后,启动"IGT全球化向导"应用程序去完成硬编码字符串的抽取,以及生成必要的辅助类和资源文件。接下来,我们需要对服务端代码做简单的修改去设置语言参数。最后,为其他语言创建资源文件。
使用"IGT全球化向导"
本节将向您介绍使用"IGT向导"应用程序的具体步骤:
步骤1:在SocketServer.java的编辑窗口中,以下三个方式的任一种启动IGT全球化向导。
1. 点击上图的IGT菜单
2. 点击上图的IGT按钮图标
3. 单击右键,在活动菜单栏中找到"Globalization Tool…"菜单项。
步骤2:全球化字符串首页--资源配置窗口。
查看原图(大图)
在此窗口中,选择您资源入口类和资源装载类的存放路径和存放的包名。在这里, 我们将这两个类存放在IGT_CS中的nls包。默认使用源文件所在的包。点击"Next"进入下一步。
步骤3:全球化字符串操作窗口。
查看原图(大图)
Enter common prefix for generated MessageIDs (EntryNames): IGT将自动在输入内容添加后缀,为您自动生成相应的变量名。默认为源文件类名
Ignore :放弃对此字符串做全球化处理。
Restore:将全球化处理后的字符还原为原来字符。
String to globalize栏:IGT自动为您从源文件中抽取出来的所有字符串显示在此栏中。您可以从中选择要进行全球化处理的字符串。Substitution pattern:选择字符串替换的方式。IGT为您提供了 tologgingString()和toString()两种替换方式。这两种替换方式的区别在于:
toString():此方法用于处理那些将显示给客户机的字符串信息。
tologgingString():用于处理那些将写入服务器端日志的或标准输出的字符串信息。
context栏:显示正在进行处理的字符串信息在源代码文件中的位置和内容。
例1的字符串处理内容显示如下:(×号表示不做处理;√表示进行处理。)
查看原图(大图)
完成上述处理后,点击"Next",进入下一步。
步骤4:此窗口显示IGT创建过程中遇见的问题。不需做如何操作直接点击"Next",进入下一步。
步骤5:进入如下所示的窗口,此窗口为您显示IGT将执行的处理内容。
查看原图(大图)
从上图的窗口中您可以看到,IGT主要对以下两方面进行处理:
A. 用新创建的SocketServerResources文件中对应的静态资源入口类对象替换掉源文件中需要进行全球化处理的字符串内容。
B. 创建的新的资源文件、资源入口类、资源装载类等文件。
步骤6:点击"Finish",结束IGT全球化过程。
设置客户机和服务器的语言环境参数,创建资源文件
经过"IGT全球化向导"的全球化应用程序的6个步骤,您已完成了全球化应用程序的大部分工作。但是,因为在本例中C/S应用的socket 服务端还不能处理客户端语言信息,我们需要对源程序作一些简单的修改,设置客户机和服务器的语言环境,创建基于各种语言的资源文件。
首先,我们在程序中添加"设定客户机和服务器的语言环境信息"的代码。IGT通过在资源加载类(ResourceLoader)中提供的 setActiveLocale(Locale locale)和setLoggingLocale(Locale locale)接口分别实现了对客户端和服务器端语言环境的设置。我们需要在应用程序中调用以上两个接口。
在Server.java中添加以下3部分的代码,Ctrl + Shift + O 重新组织导入的类库。
1) 在SocketServer.java中添加setLocale方法(清单2前面部分注释掉的那段代码):
public static void setLocale(String str){
if(str.equals("Locale.US")){
ResourceLoader.setActiveLocale(Locale.US);
}else if(str.equals("Locale.CHINA")){
ResourceLoader.setActiveLocale(Locale.CHINA);
}else if(str.equals("Locale.JAPAN")){
ResourceLoader.setActiveLocale(Locale.JAPAN);
}else if(str.equals("Locale.FRANCE")){
ResourceLoader.setActiveLocale(Locale.FRANCE);
}else if(str.equals("Locale.GERMAN")){
ResourceLoader.setActiveLocale(Locale.GERMAN);
}
}
根据客户机传递过来的字符串值,判断其对应的语言环境值(Locale值),并对客户机的语言环境值(Locale值)进行设定。在你的实际应用中你可以选择其他的方式来通知服务端设置合适的语言,例如,通过增加RMI调用借口,或者把其封装在连接对象中。
2) 在performAction()方法体中的if (action.equals(ActionDef.LOGIN)) 语句的执行语句体前,添加这样的一条语句:"ResourceLoader.setActiveLocale(clientLocale); "。添加这条语句的目的在于:在客户机登录服务器时,获取客户机Locale信息,
if (action.equals(ActionDef.LOGIN)) {
setLocale(clientLocale);
//Bind client locale to entry object.
setLocale(clientLocale);
…
3) 在main()函数中,在接受客户机请求信息的处理代码前添加如下的一条语句:
ResourceLoader.setLoggingLocale(Locale.JAPAN);将服务器本地语言环境设置为JAPAN。
public static void main(String[] args) throws IOException {
ServerSocket s = new ServerSocket(PORT);
System.out.println("Server Started the service......");
//Set Server locale
ResourceLoader.setLoggingLocale(Locale.JAPAN);
…
}
创建对应5种语言版本的资源文件:
IGT会为您自动地创建一个和原程序文件名一致的默认属性文件,本例自动创建的默认属性文件是SocketServer.properties。您需要拷贝这个文件在同一目录下,并重命名为:
SocketServer_en_US.properrties
SocketServer_zh_CN.properties
SocketServer_ja_JP.properties
SocketServer_de.properties
SocketServer_fr_FR.properties
为了简化问题的实际操作步骤,我们只是在属性文件中的原字符串后面加上语言环境的简写名称(如zh_CN等)来标识在不同语言环境中显示的处理信息。
例如:SocketServer0=\ logged on ########[ja_JP].
在实际应用中,你应该替换为相应语言字符为Unicode编码。
例如:SocketServer0=\ 成功登录
提示: 您可以通过JDK中提供的native2ascii程序来进行Unicode编码的转化。
测试全球化后的程序的执行结果
完成以上的所有步骤后,您已经成功使用IGT实现了应用程序全球化。
再次运行服务器端和客户端程序,您可以看到的显示结果分别如下:
客户机获得的服务器返回结果。
Server response to client 3[client:FRANCE] : Login server
succefully!########[fr_FR]
Server response to client 3[client:FRANCE] : Perform action Remove
succefully!########[fr_FR]
Server response to client 1[client:CHINA] : Login server
succefully!########[zh_CN]
Server response to client 2[client:JAPAN] : Login server
succefully!########[ja_JP]
Server response to client 4[client:GERMAN] : Login server
succefully!########[de]
Server response to client 3[client:FRANCE] : Perform action Add
succefully!########[fr_FR]
Server response to client 0[client:US] : Login server succefully!
Server response to client 4[client:GERMAN] : Perform action Add
succefully!########[de]
Server response to client 2[client:JAPAN] : Perform action Rollback
succefully!########[ja_JP]
…
服务器显示的日志信息
Locale.FRANCE logged on ########[ja_JP].
Locale.CHINA logged on ########[ja_JP].
Locale.US logged on ########[ja_JP].
Locale.GERMAN logged on ########[ja_JP].
Locale.JAPAN logged on ########[ja_JP].
Locale.FRANCE perfom action Remove.########[ja_JP]
Locale.FRANCE perfom action Add.########[ja_JP]
Locale.JAPAN No action to perform.########[ja_JP]
Locale.GERMAN perfom action Add.########[ja_JP]
Locale.CHINA No action to perform.########[ja_JP]
Locale.JAPAN perfom action Rollback.########[ja_JP]
Locale.CHINA No action to perform.########[ja_JP]
Locale.US perfom action Add.########[ja_JP]
…
比较使用IGT前、后的程序执行结果,服务器程序不仅能为客户机反馈基于客户机语言版本的显示信息,还能以指定语言的记录日志信息。
实例2,使用IGT实现一个简单的B/S类型的应用的全球化支持
上节向您介绍了如何使用IGT全球化C/S类型的应用程序,本节将通过一个简单的B/S应用实例(实例2简称例2)为你演示使用IGT全球化B/S 应用程序的全部过程。你可以通过本页的下载链接去获得示例工程。并工程中WebContent 文件夹以/IGT_BS部署在Tomcat上。
例2演示了一个简单的web响应。网站服务器程序够根据访问网站的用户的语言环境,向用户返回对应其语言的消息,同时在服务器端,根据指定的语言记录下用户的活动日志信息。
1.welcome.html:一个简单的页面,用户可以选择登陆和购买三种商品。在单击Perform按钮后,简单的返回成功执行的消息。
2. StoreActionBean:一个简单Javabean用来执行业务逻辑针对用户请求,在这里仅仅返回反馈信息,并记录日志。
例如,[Logging Locale:zh_CN]Done to add chocolate!
3.StoreServlet 处理用户请求,调用后台的Javabean,组织响应信息。
例如,[Browser's locale is: zh_CN] Done to add chocolate!
测试
模拟使用语言为的用户登录网站,您可以通过修改浏览器的默认Language 通过 点击工具 > Internet 选项 > 常规 > 语言, 移动"德语"到顶部。登陆welcome.html,点击Perform按钮。
查看原图(大图)
查看原图(大图)
日志
[Logging Locale:zh_CN]Login Successfully!
从以上两个图中可以看出:后台的Javabean没有实现多语言支持
使用IGT全球化B/S类型的应用程序
首先,确定需要进行全球化处理的源程序文件。在这里我们只集中精力于业务逻辑层StoreActionBean.java。
其次,激活"IGT全球化向导"进行处理。
最后,创建和配置相应的资源属性文件以及设置服务器和客户的语言环境参数。
使用"IGT全球化向导"
确定好需要作全球化处理的源文件后,接着的就是使用IGT向导来完成全球化过程。具体的操作步骤,本文已在例1做了详细的介绍,例2中就不再作赘述了。
1. 选择IGT_BS工程的nls包作为输出路径,单击Next。
2. 全球化字符串操作窗口中,修改配置如下图。单击Next。
查看原图(大图)
即对那些返回浏览器的信息做toStrring()方式的处理,对服务器的日志信息做toLoggingString()的处理。
3. 单击Finish结束。
创建属性文件,设置浏览器和服务器的语言环境参数
完成IGT向导的相关操作后,接下来需要在进行全球化的源程序文件中,设置服务器Locale和浏览器的Locale,以及创建所需语言版本的资源属性文件。
I. 设置服务器和浏览器Locale。在StoreActionBean.java中取消以下两条语句的注释,分别完成服务器日志和浏览器的语言地域的设置, Ctrl + Shift + O 重新组织引用。
ResourceLoader.setLoggingLocale(_serverLocale);
ResourceLoader.setActiveLocale(_clientLocale);
II. 创建所需语言版本的属性文件(Property File):
创建对应5种语言版本的资源文件:
IGT会为您自动地创建一个和原程序文件名一致的默认属性文件,本例自动创建的默认属性文件是StoreActionBean.properties。您需要拷贝这个文件在同一目录下,并重命名为:
StoreActionBean_en_US.properrties
StoreActionBean_zh_CN.properties
StoreActionBean_ja_JP.properties
StoreActionBean_de.properties
StoreActionBean_fr_FR.properties
类似于例1,我们也只是在原字符串中添加了一些说明语言版本的文字。在实际应用中,你应该替换相应语言字符为Unicode编码。
测试:
经过以上步骤的处理,您已完成例2程序的全球化全过程。重新发布一下这个web应用,分别修该浏览器的语言设置为"德语","中文",登录 http://localhost:8080/IGT_BS/Welcome.html。单击Perform按钮,浏览器获得服务器的返回结果分别如下:
查看原图(大图)
查看原图(大图)
比较浏览器前后的显示结果,可以发现服务器返回给浏览器的消息是根据浏览器的语言设置自动选择的。同时从服务器显示的日志信息中,您可以发现服务器能不受浏览器语言环境的影响,根据自身语言环境正确地显示日志信息。
[Logging Locale:zh_CN]Done to add chocolate!####[zh_CN]####
[Logging Locale:zh_CN]Done to add chocolate!####[zh_CN]####
实例3,使用IGT实现一个简单的RMI类型的应用的全球化支持
在开始之前,你需要通过下载链接去获得实例工程IGT_RMI,并在命令行中执行以下名令生成RMI的存根,
{$IGT_RMI_Project_location}>rmic server.RMIObjectImpl
在这个工程中我们仅需要对RMIObjectImpl.java应用IGT, 你可以使用相似的步骤去完成全球化向导。简要设置如下。
查看原图(大图)
在完成全球化向导之后,添加如下行在RMIObjectImpl的构造方法中
ResourceLoader.setLoggingLocale(Locale.getDefault());
添加如下语句在setClientLocale()方法中。Ctrl + Shift + O 重新组织引用。
ResourceLoader.setActiveLocale(_clientLocale);
创建对应5种语言版本的资源文件并为其增加标示,
RMIObjectImpl_en_US.properrties
RMIObjectImpl_zh_CN.properties
RMIObjectImpl_ja_JP.properties
RMIObjectImpl_de.properties
RMIObjectImpl_fr_FR.properties
测试
在Eclipse 中启动RMIServer, 并运行RMIClient程序。执行结果如下
客户端反馈消息
Done to add ####[zh_CN]####1998
Done to remove ####[zh_CN]####9
Done to add ####[de]####1998
Done to remove ####[de]####9
服务端日志
RMIServer starts on //localhost/RMIServer
Client's locale is: ####[zh_CN]####zh_CN
Perform Add ####[zh_CN]####1998
Perform Remove ####[zh_CN]####9
Client's locale is: ####[zh_CN]####de
Perform Add ####[zh_CN]####1998
Perform Remove ####[zh_CN]####9
可以看出RMI应用已经成功的实现了全球化语言支持。
结束语
在本文中,我们已经介绍了如何通过IGT实现C/S, B/S, RMI企业级应用的多语言(国际化)支持。您可以感受到通过使用IGT,实现多种类型的Java企业级应用的国际化变的如此简单。另外IGT还提供了方便的增删改的功能,使得你的国际化支持的开发工作更加的简洁高效。如果你对IGT有更多的建议,你可以登陆论坛http://www.alphaworks.ibm.com/tech/igt/forum发表你的观点或联系我们。
本文示例源代码或素材下载
更多精彩
赞助商链接