JAVA国际化.docx
- 文档编号:3268546
- 上传时间:2022-11-21
- 格式:DOCX
- 页数:31
- 大小:42KB
JAVA国际化.docx
《JAVA国际化.docx》由会员分享,可在线阅读,更多相关《JAVA国际化.docx(31页珍藏版)》请在冰豆网上搜索。
JAVA国际化
1.1本教程是关于什么的?
本教程向您介绍了Java编程语言对多语言和多国环境的支持。
教程从对国际化原理和概念的一般性讨论开始,然后对Java国际化支持的特定领域做了一个概述。
最后几节针对任何国际化Java应用程序的基本领域(Unicode与Java字符;语言环境与资源束以及格式化日期、数字和货币)提供了更具实践性的讨论,包括主要讨论领域的示例程序,以及一个将它们连接在一起的最终的较完整应用程序。
一旦读完本教程,您将对国际化的元素及Java平台提供支持的领域有一个牢固的理解。
您也应该能够编写使用资源束并且能够格式化并解析日期、数字和货币的应用程序。
1.2本教程适合我吗?
如果您是一名中级Java程序员,对I/O和Swing有所了解并且对构建国际化Java应用程序感兴趣,那么Java国际化基础知识非常适合于您。
然而,从初级到高级的所有开发人员也能够从中收集有用的信息和复习材料。
特别是,每一位Java程序员都应该理解Unicode支持和Java字符与char数据类型节中讨论的内容。
虽然对所有的示例代码做了解释,但是重点集中在同国际化有密切关系的领域,而不是一般的Java编程。
以前对国际化的任何了解对学习本教程都是十分有帮助的,但是这里并不假定任何特殊的背景知识。
作者注:
虽然我有一些德语和俄语的基础,但是示例中的单词和短语主要是因特网字典研究的结果。
我希望,对于任何差劲或不恰当的用词,您会觉得可笑而不是生气。
如有任何改正、语言或其它方面的问题,请毫无拘束地和我联系。
请参阅参考资料以获取根据这里给出的材料展开的教程、文章和其它参考资料清单。
1.3代码样本与安装需求
Item5:
虽然撰写本教程时已经可以获得JDK1.4的一个评估版,但JDK1.3还是应用最广泛的版本。
明确地讲,这些示例是使用在WindowsNT4.0,ServicePack6a上运行的J2SEv1.3.1_02进行测试的。
在1.4中,只有几个同国际化有关的新项,在适当的节中会提到这些变更或增加项。
您当然应该有任何JDK/JRE的国际化版本。
注:
代码示例只是用来促进对基础知识的理解,并没有为生产使用而进行过优化。
本教程中使用的示例的类和源代码在参考资料中可以作为可下载的JAR文件获得。
在附录A:
完整的代码清单中还列出了单独的源文件。
1.4关于作者
有关本教程内容的技术问题,请同作者联系。
JoeSamShirah是conceptGO的负责人和开发人员,该公司提供远程咨询和软件开发服务以及产品,专长是JDBC、I18N、AS/400、RPG、金融、库存以及后勤方面。
JoeSam于1998年JavaOne上获得Java社区奖,他也是JavaDeveloperConnection上的JDBC2.0Fundamentals短期课程的作者。
他是developerWorks“Javafilter”论坛的主持人,还是jGuru的JDBC、国际化和Java400FAQ的管理人员。
JoeSam拥有经济学工商管理学士学位以及国际管理硕士学位。
可以通过joesam@和JoeSam联系。
2.1国际化
同计算机编程有关的国际化是设计和编写应用程序以便可以在全球或多国环境中使用的过程。
国际化程序能够支持不同的语言以及不同格式的日期、时间、货币和其它值,而无须软件修改。
这通常涉及“软编码”或将文本组件同程序代码分离并且可能涉及可插入代码模块。
从业者通常将国际化(internationalization)简写为I18N。
原因是internationalization一词开始的I和最后的N之间有18个字母。
试着多说、多写“internationalization”一词几次,您就会欣赏这个较短版本的价值。
此外,您可能会看到“I18N'ed”作为“国际化的(internationalized)”的缩写形式。
虽然这在语法上不准确,在技术上也不正确,但是“I18N'ed”很有用,您将在包括本教程在内的文献里经常看到它。
关系数据库管理系统和操作系统可能也对国际化的某些方面提供基本支持,通常使用术语“本地语言支持(NationalLanguageSupport)”或NLS来表示。
2.2本地化
本地化是设计和编写能够处理特定区域、国家或地区、语言、文化、企业或政治环境的应用程序的过程。
从某种意义上说,为特定地区编写的所有应用程序都本地化了,虽然这些应用程序大多数只支持一种语言环境。
然而,真正的本地化通常是由访问语言环境、位置、政治或其它特定组件和模块的核心代码,以及将文本翻译成适合于用户的版本来实现的。
适当国际化的程序使本地化更为便利,并为本地化提供了基础。
与将“internationalization”缩写成“I18N”相同的原因和逻辑,本地化(localization)通常缩写为L10N。
可以将处理多个国家或地区(比如说美国、加拿大、墨西哥和巴西)的税收或会计软件包国际化,使得无需对每个国家或地区重复定制显示、报表生成和其它程序。
然后本地化该软件包以处理适合于特定国家或地区甚至可能是州或省的不同会计和报表生成过程。
2.3I18N存在的理由(I18Nraisond'etre)
这一页的标题本身就为国际化提供了一个理由:
没有接触过“I18N”或不懂法语(raisond'etre的大致意思是“存在的理由”)的人将搞不清这一节是关于什么的。
有时,缺乏知识是一个优点,这可以由人造钻石的成功来证明。
然而,如果软件不能被人理解,那么不论开发人员多么陶醉于自己的智慧,它也是无用的。
不便或惹人生气的软件用处也不大,不适于销售。
最开始时使用ASCII。
直至今日,大多数编译器仍要求ASCII输入。
随着计算机的发展,需要额外的语言支持已为人们所公认,通常包含ASCII和本地语言的特定于国家或地区的字符集也随操作系统一起提供。
即便如此,一般也只支持一种“其它”语言,大多数开发人员都根据他们自己的国家和当地文化来设计程序。
由于历史和实际的原因,因特网和Web上的应用程序,通常遵循相同的模式。
虽然重点通常在英语语言上,但是很容易找到各种单语言应用程序和网站。
另外一个考虑是经济上的;在您的国家之外存在着巨大的市场。
随着那些以前贫穷的国家或地区GNP的增长,对计算机的广泛接受以及上网人口的增加,市场正在改变。
根据GlobalReach的全球因特网统计信息(GlobalInternetStatistics)页面提供的信息,到2001年12月,大约45%的因特网人口讲英语。
接下来是日语,大约占9%,紧随其后的顺序是中文、德语、西班牙语、韩国语、意大利语、法语以及其它语言。
假定计算机访问跟踪类似的比例是合理的。
虽然从2001年到2005年在线人口预期会翻一翻(在线商业预计从大约1万亿美元增长到6万亿美元),但整体讲英语的比例预期会持续下降到39%左右。
其它关注国际化问题的理由可能更接近于自身的利益:
您的公司可能在其它国家或地区开设办事处,或者从位于另外一个国家或地区的潜在客户收到一个投标请求(RequestForProposal(RFP))。
3.1国际化和Java编程语言
和大多数使用其它语言的程序员不同,Java程序员是大量构建在JDK中提供I18N支持的标准代码的受益者。
大部分代码最初来自IBM的Taligent子公司(自从合并进IBM以后),代表了许多人年的工作成果,比大多数公司独自在其产品中提供的代码要切实可行得多。
这些代码及其远见并不总是完美的;例如,请看一下java.util.Date类中许多弃用的(deprecated)方法。
我们中的许多人可能记得太平洋标准时间(PacificStandardTime)显然也是Java世界时间(JavaWorldTime)。
然而,即使在“错误的旧时代”,其它语言也没有能与这种内置的功能匹敌的东西,即便有,也很少。
这一节的页面简要地讨论了Java平台支持的一般国际化领域。
3.2Unicode支持
Java语言字符集是Unicode,而且相应地,原始char数据类型的长度是两个字节(16位),以容纳Unicode值。
由于大家熟悉的String由char组成,因此String也是基于Unicode的。
Unicode本身是这样定义的:
值0到127匹配标准ASCII,0到255匹配ISO8859-1(Latin-1)标准。
由于这一起始值的一致性,不使用I18N功能或不需要面对I18N问题的程序员可以编写他们的Java程序而无需理解或知道Unicode。
然而,考虑到Windows的普遍使用,该平台的程序员应该知道标准ISO8859-1和WindowsLatin-1(cp1252)之间的差异。
16位char长度允许0到65535之间的值。
提供了Unicode转义以在本地平台不支持实际字符时仍然允许输入。
其格式是“\u”后跟0000到FFFF的四个十六进制数字。
例如,下面两行代码是等价的:
charc1='a';
charc2='\u0061';
JDK/JRE的1.3版本支持Unicode2.1;1.4版本支持Unicode3.0。
更多关于Unicode和称为UniBook的Unicode显示程序的信息,请参阅参考资料中到UnicodeConsortium的链接。
3.3字符集转换和流输入/输出
上一页提到过Java字符集是Unicode,但并不是所有平台都支持Unicode。
那么,这个戏法是怎么完成的呢?
答案是:
所有支持字符的输入和输出流?
即java.io.Reader和java.io.Writer层次结构?
自动调用在平台的本地编码和Unicode之间执行转换的隐藏代码层。
请注意,本地编码是假设的。
如果数据不是缺省编码的,您将不得不自己转换数据。
幸运的是,java.io.InputStreamReader、java.io.OutputStreamWriter和java.lang.String类具有允许使用受支持的编码的转换规范的方法。
您可以在JDK文档(可以从参考资料访问)的Internationalization节中的SupportedEncodings下面找到它们。
请注意,JDK1.4现在对泰国语和印地语提供支持。
有趣的是,Java对数字的大尾数格式提供保证,而对于char数据类型却不支持这一保证。
缺省格式同平台有关。
例如,在NT4.0上,系统特性“sun.io.unicode.encoding”被设置成“UnicodeLittle”。
如果因为某种原因您想自己指定该格式,那么您可以根据文档来选择UnicodeBig、UnicodeBigUnmarked、UnicodeLittle、UnicodeLittleUnmarked、UTF8或UTF-16。
3.4字符分类与Character类
除了以标准方式为多种语言定义字符之外,Unicode也为每个字符定义了几个特性。
这些特性标识诸如一般类别、双向性、大写、小写以及该字符是数字还是控制字符等事情。
在可以从UnicodeConsortium网站上获得的UnicodeData文件中定义了这些特性。
JavaCharacter类提供获取这些特性的方法。
虽然特定实例是不变的,但是许多方法是静态的,允许实时访问字符的特性。
该类有用性的一个示例来自一个典型的ASCII编程算法:
许多程序员利用了这样一个事实,如果字符值在0x41和0x5A之间,那么它是大写字母(A-Z)。
加上0x20,您就得到小写字母(a-z)。
遗憾的是,如果处理的语言包含有超出ASCII范围的字符时,该算法会失效。
解决方案是使用Character.isUpperCase()和Character.toLowerCase(),它们在任何情况下都起作用。
另外一个示例是Character.isDigit(),它也用于表示ASCII‘0’到‘9’以外的数字的字符。
3.5语言环境
在Java语言中,语言环境(locale)仅仅是一个标识符,而不是一组本地化的属性。
java.util.Locale类的一个实例表示一个特定的地理政治区域,使用表示语言、区域以及国家或地区的参数创建。
每个与语言环境相关的类都维护着它自己的一组本地化属性,并且确定如何对含有Locale参数的方法请求做出响应。
按照以前的陈述,很明显,没有关于程序员可能怎样对含有Locale参数的方法请求做出响应的约束。
然而,在Sun的参考Java2平台和其它一致实现中,有一组一致的受支持的本地化实现。
更多信息,请参阅JDK文档(可以从参考资料访问)中的Internationalization一节中SupportedLocales。
应该注意,该文档将多种语言环境列为“也提供了,却未测试(alsoprovided,butnottested)”。
我个人看见这一“未测试”问题出现在JDK1.3.1中的Finnish(fi_FI)语言环境;买主自行当心。
3.6AWT/SwingName和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之前对它执行本地化,而无需设置特定的ComponentLocale。
3.7本地化的资源
java.util.ResourceBundle是一个为存储和定位由应用程序使用的资源提供机制的抽象类。
资源通常是本地化的String,但也可以是任何Java对象。
ResourceBundle以一种层次结构建立,它以一个具有基础名称的一般ResourceBundle开始,然后通过向另外的ResourceBundle的基础名添加语言和国家或地区标识(它们在JDK文档Internationalization一节的SupportedLocales中有定义,可以从参考资料访问这一节),使这种层次结构变得更为特定。
ResourceBundle的三大优点是:
●类装入器机制用于定位ResourceBundle,因此无需额外的I/O代码。
●ResourceBundle“知道”如何通过使用staticgetBundle(StringbaseName)或getBundle(StringbaseName,Localelocale)方法,按照从特定到一般的顺序,搜索层次结构以寻找适合于语言环境的实例。
●如果在特定实例中没有找到资源,那么将使用来自更一般实例的资源。
好消息/坏消息是:
ResourceBundle实例一旦被装入,将被以性能优化的名义进行高速缓存;这一高速缓存从不会被更新,并且没有操作该高速缓存的正式方法。
ResourceBundle有两个子类:
●ListResourceBundle,它是另一个抽象类,因此您必须提供自己的实现。
首先,您必须覆盖getContents(),它返回二维Object数组(Object[][])。
这种ResourceBundle可以返回任何类型的Object。
●PropertyResourceBundle,它是一个由java.util.Properties文件支持的具体类,它只能返回String。
您也可以提供您自己的定制子类。
在这种情况下,您必须覆盖并实现handleGetObject()和getKeys(Stringkey)。
ResourceBundle使用键/值对,并提供getString(Stringkey)和getObject(Stringkey)方法。
您也可以使用getKeys()来获得可用键的Enumeration。
3.8日历与时区支持
最初打算将java.util.Date用来处理日期与时间操作,但是内在的缺陷导致其只能以时间的形式表示具体时刻。
JDK1.1中引入了抽象类java.util.Calendar及其具体子类java.util.GregorianCalendar来处理java.util.Date的不足。
Calendar类具有获取所有日期与时间字段以及执行日期与时间运算的方法。
抽象java.util.TimeZone类及其具体子类java.util.SimpleTimeZone维护全球统一时间(UniversalCoordinatedTime(缩写为UTC,而不是您期待的UCT;由于历史原因这一缩写取自法语形式))的标准时及夏令时的偏差值。
此外,TimeZone也含有获取本机及本地化时区显示名称的方法。
3.9格式化与解析
数字、货币、日期、时间以及程序消息都受到文化及地区差异的影响,并且对于本地化需要大量的格式化与解析工作。
创建了抽象类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/JRE1.4,已经添加了java.util.Currency以使得可以独立于语言环境使用货币。
java.text.NumberFormat拥有处理货币和整数的新方法。
3.10与语言环境相关的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内的字符。
3.11输入法
实际上,以上所有讨论都涉及操作或显示数据。
然而,必须以某种方式输入数据。
对于最终用户,最常用的是键盘。
但是,如果键盘不支持某种语言输入所需的字符,您该怎么办呢?
输入法(Inputmethod)是允许数据输入的软件组件的一个技术术语。
Java平台既允许使用主机OS输入法也允许使用基于Java语言的输入法。
如果您需要实现输入法,您可以使用输入法框架(InputMethodFramework)。
您可以在JDK文档中Internationalization一节中的InputMethodFramework(可以从参考资料中访问该文档)中找到输入法客户机API(InputMethodClientAPI)及输入法引擎SPI(InputMethodEngineSPI)的规范、参考和教程。
4.1Java字符与char数据类型
Java程序员的一个最知名的抱怨是“我只看到程序输出是问号(或方块),我的数据是怎么被破坏的呢?
”通常,作为Java开发人员,您应该理解实际发生了什么以及这一表面问题后面的原因,而这种知识在处理国际化问题时尤为重要。
Java语言规范(JavaLanguageSpecification)将char定义为原始的、数值型和整型的类型。
此外,char是唯一的无符号(unsigned)数字类型,它允许一些有趣的(或讨厌的,这取决于您的观点)窍门。
char在另一方面也十分特殊,因为将它们送到诸如显示器或打印机的输出设备时,会将其值从字符映射或字体映射成字形。
然而,从根本上来说,char是数值类型,支持所有整数运算。
因此Unicode支持注释道:
可以使用字母或Unicode转义符设置char。
因为char是数值型,所以您也可以使用八进制、十进制或十六进制表示法甚至反转位来赋值。
假设出现上述情况并假定没有程序错误,上面问题的答案是:
字符映射或字体不支持该字符,显示问号或方块来
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- JAVA 国际化