服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

java平台i18n 支持概述


  一、国际化和 java 编程语言

和大多数使用其它语言的程序员不同,java 程序员是大量构建在 jdk 中提供 i18n 支持的标准代码的受益者。大部分代码最初来自 ibm 的 taligent 子公司(自从合并进 ibm 以后),代表了许多人年的工作成果,比大多数公司独自在其产品中提供的代码要切实可行得多。

这些代码及其远见并不总是完美的;例如,请看一下 java.util.date 类中许多弃用的(deprecated)方法。我们中的许多人可能记得太平洋标准时间(pacific standard time)显然也是 java 世界时间(java world time)。然而,即使在“错误的旧时代”,其它语言也没有能与这种内置的功能匹敌的东西,即便有,也很少。这一节的页面简要地讨论了 java 平台支持的一般国际化领域。


二、unicode 支持

java 语言字符集是 unicode,而且相应地,原始 char 数据类型的长度是两个字节(16 位),以容纳 unicode 值。由于大家熟悉的 string 由 char 组成,因此 string 也是基于 unicode 的。unicode 本身是这样定义的:值 0 到 127 匹配标准 ascii,0 到 255 匹配 iso 8859-1 (latin-1) 标准。由于这一起始值的一致性,不使用 i18n 功能或不需要面对 i18n 问题的程序员可以编写他们的 java 程序而无需理解或知道 unicode。然而,考虑到 windows 的普遍使用,该平台的程序员应该知道标准 iso 8859-1 和 windows latin-1 (cp1252) 之间的差异。

16 位 char 长度允许 0 到 65535 之间的值。提供了 unicode 转义以在本地平台不支持实际字符时仍然允许输入。其格式是“u”后跟 0000 到 ffff 的四个十六进制数字。例如,下面两行代码是等价的:


char c1 = ´a´;
char c2 = ´u0061´;


jdk/jre 的 1.3 版本支持 unicode 2.1;1.4 版本支持 unicode 3.0。更多关于 unicode 和称为 unibook 的 unicode 显示程序的信息,请参阅参考资料中到 unicode consortium 的链接。


三、字符集转换和流输入/输出

上一页提到过 java 字符集是 unicode,但并不是所有平台都支持 unicode。那么,这个戏法是怎么完成的呢?答案是:所有支持字符的输入和输出流 ? 即 java.io.reader 和 java.io.writer 层次结构 ? 自动调用在平台的本地编码和 unicode 之间执行转换的隐藏代码层。请注意,本地编码是假设的。如果数据不是缺省编码的,您将不得不自己转换数据。幸运的是,java.io.inputstreamreader、java.io.outputstreamwriter 和 java.lang.string 类具有允许使用受支持的编码的转换规范的方法。您可以在 jdk 文档(可以从参考资料访问)的 internationalization 节中的 supported encodings 下面找到它们。请注意,jdk 1.4 现在对泰国语和印地语提供支持。

有趣的是,java 对数字的大尾数格式提供保证,而对于 char 数据类型却不支持这一保证。缺省格式同平台有关。例如,在 nt 4.0 上,系统特性“sun.io.unicode.encoding”被设置成“unicodelittle”。如果因为某种原因您想自己指定该格式,那么您可以根据文档来选择 unicodebig、unicodebigunmarked、unicodelittle、unicodelittleunmarked、utf8 或 utf-16。


四、字符分类与 character 类

除了以标准方式为多种语言定义字符之外,unicode 也为每个字符定义了几个特性。这些特性标识诸如一般类别、双向性、大写、小写以及该字符是数字还是控制字符等事情。在可以从 unicode consortium 网站上获得的 unicodedata 文件中定义了这些特性。

java character 类提供获取这些特性的方法。虽然特定实例是不变的,但是许多方法是静态的,允许实时访问字符的特性。

该类有用性的一个示例来自一个典型的 ascii 编程算法:许多程序员利用了这样一个事实,如果字符值在 0x41 和 0x5a 之间,那么它是大写字母(a-z)。加上 0x20,您就得到小写字母(a-z)。遗憾的是,如果处理的语言包含有超出 ascii 范围的字符时,该算法会失效。 解决方案是使用 character.isuppercase() 和 character.tolowercase(),它们在任何情况下都起作用。另外一个示例是 character.isdigit(),它也用于表示 ascii‘0’到‘9’以外的数字的字符。


五、语言环境

在 java 语言中,语言环境(locale)仅仅是一个标识符,而不是一组本地化的属性。java.util.locale 类的一个实例表示一个特定的地理政治区域,使用表示语言、区域以及国家或地区的参数创建。每个与语言环境相关的类都维护着它自己的一组本地化属性,并且确定如何对含有 locale 参数的方法请求做出响应。

按照以前的陈述,很明显,没有关于程序员可能怎样对含有 locale 参数的方法请求做出响应的约束。然而,在 sun 的参考 java 2 平台和其它一致实现中,有一组一致的受支持的本地化实现。更多信息,请参阅 jdk 文档(可以从参考资料访问)中的 internationalization 一节中 supported locales。应该注意,该文档将多种语言环境列为“也提供了,却未测试(also provided, but not tested)”。我个人看见这一“未测试”问题出现在 jdk 1.3.1 中的 finnish (fi_fi) 语言环境;买主自行当心。


六、awt/swing name 和 locale 属性

java.awt.component 类包含 name 和 locale 属性的读方法和写方法。虽然文档也讨论了 component 的构造器及其使用 name 参数的子类,但我显然需要倍加小心,因为我以前从未找到它们。component 位于大多数 swing 类的层次结构中,它们也自动支持这些属性。

name 属性是一个您可以通过编程进行赋值的不可本地化的 string。这有助于国际化 ? 听起来可能有些奇怪,但是随着大多数数据根据语言环境改变时,name 提供了一个标识组件的设置锚点。当然,在一个给定的类里,为对象等同性测试对象引用可以达到相同的目的。虽然每种技术都有极好的理由,但我通常在 actionperformed() 方法中使用对象等同性测试,如同您在代码示例中看到的那样。文档声明:如果不通过编程设置 name,那么将赋予一个缺省值,但不给出值或模式。在我编写的代码中,如果在调用 component.setname("aname") 之前调用了 component.getname(),它将返回 null。当然,作为未在文档中记录的行为,结果可能不一致,并且可能会在将来发生改变。因此,当将使用 name 属性时,良好的编程实践要求将所有组件的 name 属性设置成标准值(也就是“取消设置”),然后适当地设置想要的组件。

locale 属性允许组件跟踪它自己的语言环境,即便是应用程序的其余部分正在使用不同的语言环境。在某些情况下,该项技术非常有用,虽然对于具有文本值的 component,可以在将文本发送给 component 之前对它执行本地化,而无需设置特定的 component locale。


七、本地化的资源

java.util.resourcebundle 是一个为存储和定位由应用程序使用的资源提供机制的抽象类。资源通常是本地化的 string,但也可以是任何 java 对象。resourcebundle 以一种层次结构建立,它以一个具有基础名称的一般 resourcebundle 开始,然后通过向另外的 resourcebundle 的基础名添加语言和国家或地区标识(它们在 jdk 文档 internationalization 一节的 supported locales 中有定义,可以从参考资料访问这一节),使这种层次结构变得更为特定。resourcebundle 的三大优点是:

类装入器机制用于定位 resourcebundle,因此无需额外的 i/o 代码。


resourcebundle“知道”如何通过使用 static getbundle(string basename) 或 getbundle(string basename, locale locale) 方法,按照从特定到一般的顺序,搜索层次结构以寻找适合于语言环境的实例。


如果在特定实例中没有找到资源,那么将使用来自更一般实例的资源。
好消息/坏消息是:resourcebundle 实例一旦被装入,将被以性能优化的名义进行高速缓存;这一高速缓存从不会被更新,并且没有操作该高速缓存的正式方法。

resourcebundle 有两个子类:

listresourcebundle,它是另一个抽象类,因此您必须提供自己的实现。首先,您必须覆盖 getcontents(),它返回二维 object 数组(object[][])。这种 resourcebundle 可以返回任何类型的 object。


propertyresourcebundle,它是一个由 java.util.properties 文件支持的具体类,它只能返回 string。
您也可以提供您自己的定制子类。在这种情况下,您必须覆盖并实现 handlegetobject() 和 getkeys(string key)。

resourcebundle 使用键/值对,并提供 getstring(string key) 和 getobject(string key) 方法。您也可以使用 getkeys() 来获得可用键的 enumeration。


八、日历与时区支持

最初打算将 java.util.date 用来处理日期与时间操作,但是内在的缺陷导致其只能以时间的形式表示具体时刻。jdk 1.1 中引入了抽象类 java.util.calendar 及其具体子类 java.util.gregoriancalendar 来处理 java.util.date 的不足。calendar 类具有获取所有日期与时间字段以及执行日期与时间运算的方法。

抽象 java.util.timezone 类及其具体子类 java.util.simpletimezone 维护全球统一时间(universal coordinated time(缩写为 utc,而不是您期待的 uct;由于历史原因这一缩写取自法语形式))的标准时及夏令时的偏差值。此外,timezone 也含有获取本机及本地化时区显示名称的方法。


九、格式化与解析

数字、货币、日期、时间以及程序消息都受到文化及地区差异的影响,并且对于本地化需要大量的格式化与解析工作。创建了抽象类 java.text.format 及其子类来处理这一 i18n 领域的问题。所有这些子类都有与语言环境相关的 format() 和 parse() 方法来以与语言环境相关的方式操作值。遇到非法值,parse() 方法将抛出 parseexception。具体子类 java.text.simpledateformat 和 java.text.decimalformat 允许模式及对实例的适当符号的访问。通常,抽象父类拥有返回适当本地化的对象的 getinstance() 和 getxxxinstance() 静态工厂方法。

下面是 java.text.format 的直接子类的列表:

抽象 java.text.dateformat 类及其具体子类 java.text.simpledateformat,由 java.text.dateformatsymbols 类支持,用于处理日期与时间值。


抽象 java.text.numberformat 类及其具体子类 java.text.choiceformat 和 java.text.decimalformat,由 java.text.decimalformatsymbols 类支持,用于处理数字、货币及百分数。


java.text.messageformat 允许“软编码的”位置及格式化要插入本地化的消息的值。
对于 jdk/jre 1.4,已经添加了 java.util.currency 以使得可以独立于语言环境使用货币。java.text.numberformat 拥有处理货币和整数的新方法。


十、与语言环境相关的 string 操作

作为开发人员,我们经常需要操作、搜索 string 以及对其排序。当涉及多种语言,这项工作的难度简直令人难以置信。java 平台提供下列类以供帮助:

抽象 java.text.collator 类及其具体子类 java.text.rulebasedcollator 允许对与语言环境相关的 string 进行比较。


java.text.collationelementiterator 类以给定的整理顺序遍历 string 的每个字符并返回其有序的优先级。


java.text.collationkey 类表示一个由特定 collator 管理的 string,它允许相对较快的排序比较。


java.text.breakiterator 类以与语言环境相关的方式实现了定位断行、断句、断词和断字符的位置的约定。


java.text.stingcharacteriterator 类对 unicode 字符提供双向遍历,用于搜索 string 内的字符。


十一、输入法

实际上,以上所有讨论都涉及操作或显示数据。然而,必须以某种方式输入数据。对于最终用户,最常用的是键盘。但是,如果键盘不支持某种语言输入所需的字符,您该怎么办呢?

输入法(input method)是允许数据输入的软件组件的一个技术术语。java 平台既允许使用主机 os 输入法也允许使用基于 java 语言的输入法。如果您需要实现输入法,您可以使用输入法框架(input method framework)。您可以在 jdk 文档中 internationalization 一节中的 input method framework(可以从参考资料中访问该文档)中找到输入法客户机 api(input method client api)及输入法引擎 spi(input method engine spi)的规范、参考和教程。

--摘自ibm 网站

扫描关注微信公众号