IBM : developerWorks 中国网站 : Java : 所有的文章
Java程序的国际化和本地化介绍
--软件工程师, CA有限公司研发中心
2001 年 5 月
本文尝试用一个简单的例子来演示在书写Java应用程序时候,怎样使之符合国际化标准,然后对其进行本地化有多么简单。
当一个软件产品需要在全球范围应用的时候,得考虑在不同的地域和语言环境下面的使用情况,最简单的要求就是UI上的信息上能用本地化语言来显示,当然一个优秀的全球化软件产品关于国际化和本地化的要求远远不止于此,本文只是涉及了国际化和本地化的关于界面显示语言的一小部分。Java语言内核基于Unicode2.1提供了对不同国家和不同语言文字的内部支持,由于先天的原因,Java对于国际化的支持远远要比C/C++来的优越。
在开始具体介绍之前,需要先介绍几个术语:
i18n: 就是internationalization, 国际化,由于首字母"i"和末尾字母"n"间有18个字符,所以简称i18n. internationalization指为了使应用程序能适应不同的语言和地区间的变化而不作系统性的变化所采取的设计措施。
l10n: 就是localization, 本地化,由于首字母"l"和末尾字母"n"间有10个字母,所以简称l10n. localization指为了使应用软件能够在某一特定语言环境或地区使用而加入本地特殊化部件和翻译后文本的过程。
locale: 简单来说是指语言和区域进行特殊组合的一个标志。
我们的例子,显示一个有一个按钮和一个菜单的Dialog窗,在不改动程序的前提下使应用程能够显示英文文字的或者中文文字的界面。注:因为仅仅作为演示用,我们的菜单栏也作为一个部件加入对话框,好象是一个Button一样,而不是通常意义上的菜单条。
通常我们的程序是这样的:
/**
* File name: i18nDemo.java
* Author ID: Jack, at http://bbs.whnet.edu.cn, Java discuss board.
* Description: Shows a Dialog with a "OK" button and "File"/"Exit" menu.
*/
import javax.swing.*;
import java.awt.*;
import java.util.*;
public class i18nDemo {
public static void main(String args[]) throws Exception{
JDialog dialog=new JDialog();
JButton btOK=new JButton();
JMenuBar menuBar=new JMenuBar();
JMenu menuFile=new JMenu();
JMenuItem menuExit=new JMenuItem();
btOK.setText("OK");
menuFile.setText("File");
menuExit.setText("Exit");
dialog.setTitle("i18n Demo");
menuBar.add(menuFile);
menuFile.add(menuExit);
dialog.getContentPane().setLayout(new FlowLayout());
dialog.getContentPane().add(btOK);
dialog.getContentPane().add(menuBar);
dialog.setSize(200,100);
dialog.setModal(true);
dialog.show();
System.exit(0);
}
}
我们通过修改程序来达到i18n的要求:将那些和界面显示有关系的资源单独提取出来到资源文件里面.Java里面的资源文件叫做ResourceBundle,它分成两种,一种是ListResourceBundle,另一种是PropertyResourceBundle,我们这里使用ListResourceBundle,关于PropertyREsourceBundle请参阅文后的推荐阅读。当一个程序需要一些Locale相关的资源,例如字符串资源的时候,它可以从resource bundle里面将需要的本地化资源装入。
需要注意的是:为了能够正确显示中文字符,程序里的部件需要选择指定字体,例如在显示中文的时候使用"MS Song",不然界面有中文字符的时候会出现没有意义的方框。
请看修改过的程序和资源文件。
/**
* File name: i18nDemo.java
* Author: Jack, at http://bbs.whnet.edu.cn, Java discuss board.
* Email: greatjava@sina.com
* Description: Shows a Dialog with a "OK" button and "File"/"Exit" menu.
* This program made some modifications to fit the requestion of i18n
*/
import javax.swing.*;
import java.awt.*;
import java.util.*;
public class i18nDemo {
public static void main(String args[]) throws Exception{
ResourceBundle res;
if (args.length<1) {
//use current locale at machine to get the resource bundle.
res = ResourceBundle.getBundle("Res");
}else {
res = ResourceBundle.getBundle("Res",new Locale(args[0], args[1]));
}
JDialog dialog=new JDialog();
JButton btOK=new JButton();
JMenuBar menuBar=new JMenuBar();
JMenu menuFile=new JMenu();
JMenuItem menuExit=new JMenuItem();
Font font = new Font(res.getString("FontName"),Font.PLAIN,12);
btOK.setText(res.getString("OKText"));
menuFile.setText(res.getString("FileMenuText"));
menuExit.setText(res.getString("FileExitMenuText"));
dialog.setTitle(res.getString("DialogTitle"));
btOK.setFont(font);
menuFile.setFont(font);
menuExit.setFont(font);
menuBar.add(menuFile);
menuFile.add(menuExit);
dialog.getContentPane().setLayout(new FlowLayout());
dialog.getContentPane().add(btOK);
dialog.getContentPane().add(menuBar);
dialog.setSize(200,100);
dialog.setModal(true);
dialog.show();
System.exit(0);
}
}
/**
* File name: Res_en_US.java
* Author: Jack, at http://bbs.whnet.edu.cn, Java discuss board.
* Email: greatjava@sina.com
* Description: Resource file for i18nDemo.java
*/
import java.util.*;
public class Res_en_US extends java.util.ListResourceBundle {
static final Object[][] contents = new String[][]{
{ "OKText", "OK" },
{ "FontName", "Dialoginput" },
{ "FileMenuText", "File"},
{ "FileExitMenuText", "Exit"},
{ "DialogTitle", "Demo Dialog" }};
public Object[][] getContents() {
return contents;
}
}
在运行前,我们再做一个包含中文资源的资源文件
/**
* File name: Res_zh_CN.java
* Author: Jack, at http://bbs.whnet.edu.cn, Java discuss board.
* Email: greatjava@sina.com
* Description: Resource file for i18nDemo.java
*/
import java.util.*;
public class Res_zh_CN extends java.util.ListResourceBundle {
static final Object[][] contents = new String[][]{
{ "OKText", "确定" },
{ "FontName", "MS Song" },
{ "FileMenuText", "文件"},
{ "FileExitMenuText", "退出"},
{ "DialogTitle", "演示对话框" }};
public Object[][] getContents() {
return contents;
}
}
先运行来看看结果:
//Run next command step by step
javac *.java
java i18nDemo
java i18nDemo zh CN
java i18nDemo en US
可以看到出现了中文界面和英文界面的对话框。
具体的看一下程序:
主程序i18nDemo.java,多了一个ResourceBundle对象,它包含了一个资源文件的信息。然后需要使用本地化资源的时候,都通过res.getString(KEY)来得到相应的Locale的值。通过命令行,我们传入关于语言和国家的代码,这样在生成ResourceBundle对象的时候,可以指向相应的资源文件。如果没有指定Locale,那么在生成ResourceBundle使用的Locale是当前机器上缺省的区域和语言。在我的机器上(English WindowsNT 4),打开Richwin中文平台的时候,缺省的locale是中国,关闭RichWin的时候,Locale是U.S..
资源文件Res_en_US.java里面包含了英文的界面资源,文件名里的"en"指英语语言,"US"指国家是美国。Res_zh_CN.java是中文的资源文件,”zh“说明语言是中文,"CN"说明国家是中国。关于语言和国家的完整对照表可以在参考资源里找到链接。
Res_xx_XX类是从ListResourceBundle继承而来,ListResourceBundle子类必须提供重载getContents方法和一个对象数组,数组里面包含了资源的Keys和相应的Values。例如键"OKText"的值在两个文件里面分别是"OK"和"确定"。
在通常情况下,应用程序安装完后一般不需要常常改变Locale,这样,在我们发布应用程序时候,在不同的区域中不用提供多个resource文件,只要将用到的资源文件替换成相应locale内容的文件就可以了。例如本例里,只要一个Res.java的资源文件,当在英语环境中,其内容用Res_en_US.java里面的资源替换,在中文环境下,替换成Res_zh_CN.java里面内容就可以了。
关于i18n和l10n的进一步讨论本文讨论的只是最简单的关于界面显示语言的国际化,在实际的应用过程中,情况要复杂的多,一些需要考虑的因素包括:提示信息,GUI组件上的标签,在线帮助,声音,颜色,图形,图标,日期,货币符号.....
除了这些,在一些过程中的具体处理也会不同,例如排序方法,输入处理等。更多的技术内容请参见后面的推荐参考资料里面。
参考资料
语言代码对照表
http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt
国家代码对照表
http://www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html
Sun 关于 Internationlization 在 JDK 里面的说明
http://java.sun.com/j2se/1.3/docs/guide/intl/intlTOC.doc.html
Sun 的关于国际化教程
http://java.sun.com/docs/books/tutorial/i18n/index.html
关于作者
邵荣,软件技术专家。对软件工程和软件技术尤其是Java技术有深入的研究。目前他是ca有限公司研发中心的软件工程师,同时主持bbs白云黄鹤的Java讨论组。可以通过youcenter@yahoo.com与他联系。