初识国际化和ResourceBundle
这个类主要用来解决国际化和本地化问题。国际化和本地化可不是两个概念,两者都是一起出现的。可以说,国际化的目的就是为了实现本地化,详细的介绍可以看本文的最后。比如对于“取消”,中文中我们使用“取消”来表示,而英文中我们使用“cancel”。若我们的程序是面向国际的(这也是软件发展的一个趋势),那么使用的人群必然是多语言环境的,实现国际化就非常有必要。而ResourceBundle可以帮助我们轻松完成这个任务:当程序需要一个特定于语言环境的资源时(如String),程序可以从适合当前用户语言环境的资源包(大多数情况下也就是.properties文件)中加载它。这样可以编写很大程度上独立于用户语言环境的程序代码,它将资源包中大部分(即便不是全部)特定于语言环境的信息隔离开来。
这使编写的程序可以:
- 轻松地本地化或翻译成不同的语言
- 一次处理多个语言环境
- 以后可以轻松进行修改,以便支持更多的语言环境
下面我们来模拟一个多语言的环境
定义四个资源文件:res_en_US.properties、res_zh_CN.properties、res_zh.properties、res.properties
res_en_US.properties:cancelKey=cancel
res_zh_CN.properties:cancelKey=\u53D6\u6D88(取消)
res_zh.properties:cancelKey=\u53D6\u6D88zh(取消zh)
res.properties:cancelKey=\u53D6\u6D88default(取消default)
命名规则按照:资源名+_语言_国别.properties,每个资源文件中定义了本地化的信息,那么系统如何取到对应的资源文件呢?
1. ResourceBundle bundle = ResourceBundle.getBundle("res", new Locale("zh", "CN"));
其中new Locale("zh", "CN");这个对象就告诉了程序你的本地化信息,就拿这个来说吧:程序首先会去classpath下寻找res_zh_CN.properties
若不存在,那么会去找res_zh.properties,若还是不存在,则会去寻找res.properties,要还是找不到的话,那么就该抛异常了:MissingResourceException
我们可以来写个测试程序验证一下:
1. package bundle.test;
2.
3. import java.util.Locale;
4. import java.util.ResourceBundle;
5.
6. public class BundleTest {
7.
8. public static void main(String args[]) {
9. ResourceBundle bundle = ResourceBundle.getBundle("res", new Locale("zh", "CN"));
10. String cancel = bundle.getString("cancelKey");
11. System.out.println(cancel);
12.
13. bundle = ResourceBundle.getBundle("res", Locale.US);
14. cancel = bundle.getString("cancelKey");
15. System.out.println(cancel);
16.
17. bundle = ResourceBundle.getBundle("res", Locale.getDefault());
18. cancel = bundle.getString("cancelKey");
19. System.out.println(cancel);
20.
21. bundle = ResourceBundle.getBundle("res", Locale.GERMAN);
22. cancel = bundle.getString("cancelKey");
23. System.out.println(cancel);
24. }
25. }
输出:
取消
cancel
取消
取消
这里前三个都在我们的预期范围之内,但是最后一个GERMAN,应该会去使用res.properties这个资源包吧?怎么使用了res_zh_CH.properties?
原来ResourceBundle为我们提供了一个fallback(也就是一个备用方案),这个备用方案就是根据当前系统的语言环境来得到的本地化信息。
所以若是找不到GERMAN的,之后就会去找CHINA了,所以找到了res_zh_CH.properties这个资源包
这点我也是看了源代码才明白的,下面就贴上一些关键的源代码:
1. ResourceBundle baseBundle = null;
2. for (Locale targetLocale = locale;
3. targetLocale != null;
4. targetLocale = control.getFallbackLocale(baseName, targetLocale)) {// 这里就是去拿备用方案的
5. // do something 我们暂时不关心
6. }
跟踪control.getFallbackLocale(baseName, targetLocale)看看备用方案到底是什么?
1. public Locale getFallbackLocale(String baseName, Locale locale) {
2. if (baseName == null) {
3. throw new NullPointerException();
4. }
5. Locale defaultLocale = Locale.getDefault();
6. return locale.equals(defaultLocale) ? null : defaultLocale;
7. }
当显式定义的本地化信息并不是当前系统的本地化信息时,若未能通过显式定义的找到资源包,那么就去转而通过当前系统的本地化信息去找了~
最后放一点小知识吧~
国际化(Internationalization)是设计一个适用于多种语言和地区的应用程序的过程。适用于多种语言和地区的含义是当使用不同语言及处于不同的地区的用户在使用这个应用程序时,应用程序必须使用他们能看懂的语言和符合他们文化习惯来显示信息。国际化有时候被简称为i18n,因为有18个字母在国际化的英文单词的字母i和n之间。
一个国际化的程序通常具有以下特征:
- 有一个附加的本地化数据(localized data)及拥有在全世界各个地区执行的能力。
- 文本的元素,比如状态信息或GUI截面的lables,不是直接写(hardcoded)在程序中,而是被存储在本地化的数据中,并且能被程序正确的动态的使用。
- 支持新的语言时,不需要修改程序,不需要重新编译。
- 文化差异的数据,比如日期和货币,必须根据拥护的语言和习惯显示不同的格式。
- 可以被迅速的本地化。
本地化(Localization)是指通过增加本地描述的构件(locale-specificcomponents )和文字翻译工作来使应用程序适应于不同的语言和地区的过程。本地化有时候被简称为l10n,应为有10个字母在本地化的英文单词的字母l和n之间。通常本地化最耗时的工作应该是文字翻译。本地化工作者们要根据地区的具体需求来为日期、数字和通货等数据建立新的格式。其他类型的数据,象声音,图象等,也需要根据具体需要来决定是否本地化。
下面是查到的第二个版本解释
java.util.ResourceBundle使用详解
一、认识国际化资源文件
这个类提供软件国际化的捷径。通过此类,可以使您所编写的程序可以:
轻松地本地化或翻译成不同的语言
一次处理多个语言环境
以后可以轻松地进行修改,支持更多的语言环境
说的简单点,这个类的作用就是读取资源属性文件(properties),然后根据.properties文件的名称信息(本地化信息),匹配当前系统的国别语言信息(也可以程序指定),然后获取相应的properties文件的内容。
使用这个类,要注意的一点是,这个properties文件的名字是有规范的:一般的命名规范是: 自定义名_语言代码_国别代码.properties,
如果是默认的,直接写为:自定义名.properties
比如:
myres_en_US.properties
myres_zh_CN.properties
myres.properties
当在中文操作系统下,如果myres_zh_CN.properties、myres.properties两个文件都存在,则优先会使用myres_zh_CN.properties,当myres_zh_CN.properties不存在时候,会使用默认的myres.properties。
没有提供语言和地区的资源文件是系统默认的资源文件。
资源文件都必须是ISO-8859-1编码,因此,对于所有非西方语系的处理,都必须先将之转换为JavaUnicode Escape格式。转换方法是通过JDK自带的工具native2ascii.
二、实例
定义三个资源文件,放到src的根目录下面(必须这样,或者你放到自己配置的calsspath下面。
myres.properties
aaa=good
bbb=thanks
myres_en_US.properties
aaa=good
bbb=thanks
myres_zh_CN.properties
aaa=\u597d
bbb=\u591a\u8c22
import java.util.Locale;
import java.util.ResourceBundle;
/**
* 国际化资源绑定测试
*
* @author leizhimin 2009-7-29 21:17:42
*/
public class TestResourceBundle {
public static void main(String[] args) {
Localelocale1 = new Locale("zh", "CN");
ResourceBundleresb1 = ResourceBundle.getBundle("myres", locale1);
System.out.println(resb1.getString("aaa"));
ResourceBundleresb2 = ResourceBundle.getBundle("myres", Locale.getDefault());
System.out.println(resb1.getString("aaa"));
Localelocale3 = new Locale("en", "US");
ResourceBundleresb3 = ResourceBundle.getBundle("myres", locale3);
System.out.println(resb3.getString("aaa"));
}
}
运行结果:
好
好
good
Process finished with exit code 0
如果使用默认的Locale,那么在英文操作系统上,会选择myres_en_US.properties或myres.properties资源文件。
三、认识Locale
Locale 对象表示了特定的地理、政治和文化地区。需要 Locale 来执行其任务的操作称为语言环境敏感的 操作,它使用 Locale 为用户量身定制信息。例如,显示一个数值就是语言环境敏感的操作,应该根据用户的国家、地区或文化的风俗/传统来格式化该数值。
使用此类中的构造方法来创建 Locale:
Locale(Stringlanguage)
Locale(String language, String country)
Locale(String language, String country, String variant)
创建完 Locale 后,就可以查询有关其自身的信息。使用 getCountry 可获取 ISO 国家代码,使用 getLanguage 则获取 ISO 语言代码。可用使用getDisplayCountry 来获取适合向用户显示的国家名。同样,可用使用getDisplayLanguage 来获取适合向用户显示的语言名。有趣的是,getDisplayXXX 方法本身是语言环境敏感的,它有两个版本:一个使用默认的语言环境作为参数,另一个则使用指定的语言环境作为参数。
语言参数是一个有效的 ISO 语言代码。这些代码是由 ISO-639 定义的小写两字母代码。在许多网站上都可以找到这些代码的完整列表,如:
http://www.loc.gov/standards/iso639-2/englangn.html。
国家参数是一个有效的 ISO 国家代码。这些代码是由 ISO-3166 定义的大写两字母代码。在许多网站上都可以找到这些代码的完整列表,如:
http://www.iso.ch/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html。
四、中文资源文件的转码 native2ascii
这个工具用法如下:
如果觉得麻烦,可以直接将中文粘贴到里面,回车就可以看到转码后的结果了。