java 的i18n 问题,即java 的internationalization 问题, 指的是如何使应用程序能够同时支持多种语言的问题。对我国这样的非英语国家而汉字又有多种编码方式的情况下具有现实意义。本文将对用java 编制i18n 程序的方法作一介绍。
一、实现目标
作为i18n 程序,不单是能够识别不同编码这么简单。它应能解决如下问题:
*能识别不同的编码方式,如gb 码、big5 码等;
*与编码有关的元素,如状态行、消息、按钮的caption 等应在程序之外存储。使新增一种语言时不用修改程序;
*根据不同的语言习惯动态调整与语言相关的元素,如数字、金额、日期等的显示。
二、解决方法
1.?不同地区码的识别
java 中用locale 类识别不同的地区码。创建locale 类的实例时指定了语言代码和地区代码。创建gb 中文和big5 中文资源的locale 类实例的语句分别如下:zhlocale=new locale("zh","cn");twlocale=new locale("tw","tw")。此构造函数第一个参数是iso -639 中定义的语言代码(http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt);第二个参数为iso -3166 中定义的国家代码(http://www.chemie. fu -berlin.de/diverse/doc/iso ?3166.html)。当用户选定了适用的语言后,应将此locale 设为默认值:locale.setdefault(new locale("zh","cn")).
2. 与语言相关的资源单独存放
java 提供了两种方法存放与语言相关的资源。一种是用文本文件;另一种是用listresourcebundle 资源类。下面分别阐述两者的不同之处。
*文本文件
使用文本文件存放资源的好处是简单易用。可以用任何文本编辑器编写此文件,而且当修改资源时无须重新编译程序。其格式是´ 键= 值´ 的列表。例子如下:
#the list in webtaxresource_zh_cn.properties
button1= 税金
button2= 税率
status1= 初始化中
其中以´ #´ 开头的行为注释行。对应每一种语言写一个这样的资源文件,但所有的资源文件都必须包含相同的键。
*listresourcebundle 资源类
虽然用文本文件存储资源非常容易,但它只能存储字符对象。而对于数字、自定义对象等它就无能为力了。因此java 提供了listresourcebundle 类。其缺点是每次对资源的修改都必须重新编译程序。此类的结构如下:
//file webtaxresource_zh_cn.java
import java.util. *;
public class webtaxresource_zh_cn extends
listresourcebundle {
static final object[][] contents = {
{"frametitle"," 工资、薪金所得适用"},
{"label_qizhengdian"," 起征点:"},
{"label_shuikuan"," 税款:"},
{"label_shourue"," 收入额:"},
{"checkbox_qiushouru"," 求收入"},
{"checkbox_qiushuie"," 求税额"},
{"lable1"," 简易税金计算器"},
{"button1"," 工资、薪金个人所得税计算"},
{"button_caculate"," 计算"},
};
public object[][] getcontents() {
return contents;
}
}
其中两维的object 数组存放的是键-值对。每对中的第一个元素是键。在各个资源类中所有键的数量和标识都必须完全一致。
3. 资源的获取
不同语言的资源存放的文件名都不相同,那如何从正确的文件取得我们需要的资源呢?留意到前面例子中properties 文件名和listresourcebundle 类名中下划线后的部分吗?没错,它们就是在创建locale 实例时指定的语言代码和地区代码!剩下的问题就是要解决下划线前面的基本类名部分了。它是由一个resourcebundle 类的实例来指定的:
resourcebundle
bundle=resourcebundle.getbundle("webtax ?
resource",currentlocale);
getbundle 的第一个参数指定了资源文件和资源类的基本类名;第二个参数是你所创建的locale 的实例,指定了当前程序所有资源默认的语言代码和地区代码。
可见,资源文件名或类名是由" 基本类名_ 语言代码_ 地区代码" 组成的。java 将先查找有无此名称的类,若没有则查找具有此名称的properties 文件。
匹配了正确的资源文件名或类名后,要获取某键对应的值就变得相当容易。例如,要创建标识为" 计算器" 的标签,只要调用以下语句:
label1=new label(bundle.getstring("label_ jisuanqi"), label.center);
getstring 方法的参数是资源文件中的键名。除了getstring 外,resourcebundle 类还提供了其他方法获取不同的对象,如getstringarray、getobject 等(因为在listresourcebundle 的实例中允许存在非字符对象)。
4. 转换非unicode 资源
在java 内部字符是用unicode 字符表示的。unicode 是一种16bit 的编码,支持大多数地区的语言。具体标准可到http://www.unicode.org/index.html 查询。因此,无论是用文本文件还是用资源类的方式存储资源,都应该将非unicode 字符转换为unicode 字符。java 为我们提供了转换的工具-native2ascii。将含有gb 编码的汉字的webtaxresource_zh.cn.properties 文件转换为只含unicode 字符的例子如下:
native2ascii -encoding gb2321 webtaxre
source_zh_cn.properties
.outputwebtaxresource_zh_cn.properties
到此为止,一个支持i18n 的程序就已初步完成了。
三、其他相关问题
正如实现目标中所讲到,支持i18n 的程序不但要识别不同的编码方式,还要根据不同的语言习惯动态调整与语言相关的元素,如数字、金额、日期等的显示。例如在法文中数值123456.78 表示为123 456,78;而在德文中应表示为123.456,78。除了数值和货币之外,不同语言有不同表示的元素还有日期、时间和文本消息。java 提供了numberformat、dateformat、messageformat 类根据不同的locale 实例动态改变这些元素的显示模式。下面的例子将根据不同的locale 实例改变数值123456.78 的显示方式。
double amount = new double (123456.78);
numberformat numberformatter;
string amountout;
numberformatter = numberformatgetnumber ?
instance(currentlocale);
amountout = numberformatter.format
(amount);
system.out.println(amountout +" " +
currentlocale.tostring());
当然,实现java 程序的i18n 还有很多问题要考虑,如不同语言的语法问题等。但在java 中,遇到问题多看看联机文档或其他相关的资料,一般都能得到满意的答案。 (中国计算机报 苏志成)
闽公网安备 35060202000074号