7-国际化

国际化的思路

Java 程序的国际化思路是将程序中的标签、提示等信息放在资源文件中,程序需要支持哪些国家、语言环境,就对应提供相应的资源文件。资源文件是 key-value 对,每个资源文件中的 key 是不变的,但 value 则随不同的国家、语言而改变。

Java程序的国际化主要通过如下三个类完成:

  • java.util.ResourceBundle:用于加载国家、语言资源包。
  • java.util.Locale:用于封装特定的国家/区域、语言环境。
  • java.text.MessageFormat:用于格式化带占位符的字符串。

资源文件的内容是很多的 key-value 对,其中 key 是程序使用的部分,而 value 则是程序界面的显式字符串。资源文件的命名可以有如下三种形式:

  • baseName_language_contry.properties
  • baseName_language.properties
  • baseName.properties

baseNaem 是资源文件的基本名,可以随意指定;而 language 和 country 都不可随意变化,必须是Java支持的语言和国家。

1
2
3
4
5
6
7
8
//返回Java所支持的全部国家和语言的数组
Local[] localList=Locale.getAvailableLocales();
//遍历数组的每个元素,依次获取所支持的国家和语言
for (int i=0;i<localeList.length;i++)
{
System.out.println(localeList[i].getDisplayCountry()+"="+localeList[i].getCountry()+" "+
localeList[i].getDisplayLanguage()+"="+localeList[i].getLanguage());
}

完成国际化的步骤

准备资源文件

为程序提供两个文件:
第一个文件:mess.properties,其内容为:

1
2
#资源文件的内容是 key-value 对
hello=你好!

第二个文件:mess_en_US.properties,该文件的内容为:

1
2
#资源文件的内容是 key-value 对
hello=Welcome!

对于包含非西欧字符的资源文件,Java提供了一个工具来处理该文件:native2ascii,这个工具可以在 %JAVA_HOME%/bin 路径下找到,使用该工具的语法格式如下:

1
native2ascii 资源文件 目的资源文件

在命令窗口输入如下命令:

1
native2ascii mess.properties mess_zh_CN.properties

上面的命令将生成一个 mess_zh_CN.properties 文件,该文件才是程序需要的资源文件,该文件里面是非西欧字符的 Unicode 编码方式。

进行国际化

1
2
3
4
5
6
7
8
//取得系统默认的国家/语言环境
Locale myLocale=Locale.getDefault(Locale.Category.FORMAT);

//关键:根据指定的国家/语言环境加载资源文件
ResourceBundle bundle=ResourceBundle.getBundle("mess",myLocale);

//打印从资源文件中取得的消息
System.out.println(bundle.getString("hello");

注意该代码:

1
2
//根据指定的国家/语言环境加载资源文件
ResourceBundle bundle=ResourceBundle.getBundle("mess",myLocale);

上面代码将会加载 baseNamemess 的系列资源之一,到底加载其中的哪个资源文件,则取决于 myLocale ;对于简体中文的 Locale ,则加载 mess_zh_CN.properties 文件。

使用 MessageFormat 处理包含占位符的字符串

前面程序输出的消息是一个简单信息,如果需要输出的消息中必须包含动态的内容,例如,这些内容必须是从程序中取得的:

1
你好,yeeku!今天是 2018-03-12 上午 10:24

上面的输出字符串中,yeeku 是用户的名字,必须动态改变,后面的时间也必须动态改变。在这种情况先,可以使用带占位符的消息。

例如,提供一个 myMess_en_US.properties 文件,该文件内容如下:

1
msg=Hello,{0}!Today is {1}.

提供一个 myMess.properties 文件,内容如下:

1
msg=你好,{0}! 今天是 {1}。

现在,程序需要为 {0} 和 {1} 两个占位符赋值,此时需要使用 MessageFormat 类,该类包含了一个静态方法:

  • format(String pattern,Object… values):返回后面的多个参数值填充前面的 patter 字符串,其中 pattern 是一个带占位符的字符串。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    //定义一个 Locale 变量
    Locale currentLocale = null;
    //如果运行程序指定了两个参数
    if(args.length == 2)
    {
    //使用运行程序的两个参数构造 Locale 实例
    currentLocale = new Locale(args[0],args[1]);
    }
    else
    {
    //否则直接使用系统默认的 Locale
    currentLocale = Locale.getDefault(Locale.Catefory.FORMAT);
    }
    //根据 Locale 加载语言资源
    ResourceBundle bundle = ResourceBundle.getBundle("myMess",currentLocal);
    //取得已加载的语言资源文件中的 msg 对应消息
    String msg = bundle.getString("msg");
    //使用 MessageFormat 为带占位符的字符串传入参数
    System.out.println(MessageFormat.format(msg,"yeeku",new Date());

使用类文件代替资源文件

除了使用属性文件作为资源文件外,Java也允许使用类文件代替资源文件,即将所以的 key-value 对存入 class 文件,而不是属性文件。

使用类文件来代替资源文件必须满足以下条件:

  • 该类的类名必须是 baseName_language_country,这与属性文件的命名方式相似。
  • 该类必须继承 ListResourceBundle,并重写 getContents() 方法,该方法返回 Object数组,该数组的每一项都是 key-value 对。
    以下是一个简体中文语言环境的资源文件,可以替代 Mess_zh_CN.properties。当系统同时存在资源文件、类文件时,以类文件为主。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Mess_zh_CN extends ListResourceBundle
{
//定义资源
private final Object myDate[][] =
{
{"msg"" {0},你好!今天的日期是 {1} "}
};

//重写 getContents() 方法
public Object[][] getContents()
{
//该方法返回资源的 key-value 对
return myDate;
}
}