最近在做Kettle8.1的国际化工作,闲暇之余,就看了看Java的国际化处理,明白程序怎么样找到对应的国际化文件。

说到国际化,经常看到一个东西叫i18n,其实是internationalization的缩写(ps:以后起昵称什么的就可以仿照这个规则信手拈来,又专业又好记)。

Java中相关的有以下3个类:

  • ResourceBundle:国际化资源包。
  • Locale:表示了特定的地理、政治和文化地区。
  • MessageFormat:用以实现动态填充国际化文件的占位符。

问题一:基本使用

话不多说,直接上案例,java代码如下:

package com.szh;

import java.util.Locale;
import java.util.ResourceBundle;

public class TestI18n {
	public static void main(String[] args) throws Exception {
		Locale l1 = new Locale("zh", "CN");
		ResourceBundle rb1 = ResourceBundle.getBundle("test", l1);
		System.out.println(rb1.getString("str1"));

		ResourceBundle rb2 = ResourceBundle.getBundle("test", Locale.getDefault());
		System.out.println(rb2.getString("str1"));

		Locale l3 = new Locale("en", "US");
		ResourceBundle rb3 = ResourceBundle.getBundle("test", l3);
		System.out.println(rb3.getString("str1"));
	}
}

下面3个国际化文件目录如下:

java国际化英语 国际化 java_java国际化英语

test_zh_CN.properties

str1=\u4F60\u597D!!

test_en_US.properties

str1=Hello!!

test.properties(当在对应的语言环境的国际化文件中找不到key时,则去此文件中拿):

str1=\u4F60\u597D!

此时,可以看到test_zh_CN.properties和test.properties显示出来的是ASCII码,jdk提供了cmd命令native2ascii.exe,能够查看对应的ASCII码,如下所示:

C:\Users\szh>native2ascii
你好!
\u4f60\u597d!

运行结果1:

你好!!
你好!!
Hello!!

运行结果2(我的语言环境为中文,当test_zh_CN.properties中没有str1时,则会去打印test.properties中str1的值):

你好!
你好!
Hello!!

问题二:动态填充占位符

另外一个问题,经常见到需要动态填充国际化字符串文本的情况,即需要填充占位符。此时需要类MessageFormat登场了。

首先修改test_en_US.properties代码如下:

str1=Hello!!{0}, {2}, {1} and {3}

主程序如下(四个乱序的占位符,我们只传3个看看效果):

package com.szh;

import java.text.MessageFormat;
import java.util.Locale;
import java.util.ResourceBundle;

public class TestI18n {
	public static void main(String[] args) throws Exception {
		Locale l3 = new Locale("en", "US");
		ResourceBundle rb3 = ResourceBundle.getBundle("test", l3);
		String s1 = MessageFormat.format(rb3.getString("str1"), new Object[] { "aa", "bb", "cc" });
		String s2 = new MessageFormat(rb3.getString("str1")).format(new Object[] { "aa", "bb", "cc" });
		System.out.println(s1);
		System.out.println(s2);
	}
}

运行结果(依次按照占位符序号填充,第四个参数未传,则按照字符串原样打印):

Hello!!aa, cc, bb and {3}
Hello!!aa, cc, bb and {3}

问题三:如何找到任意位置的国际化文件

上面的例子均放在src根目录下,那么如何能够像Kettle中一样,拿到自定义位置的国际化文件呢?

首先,我们将test_zh_CN.properties复制一份到com.szh包下:

java国际化英语 国际化 java_占位符_02

test_zh_CN.properties:

str1=\u665A\u5B89

主程序如下:

package com.szh;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;

public class TestI18n {

	@SuppressWarnings("rawtypes")
	public static void main(String[] args) throws Exception {
		Class cls = TestI18n.class;
		// 将message_zh_CN.properties放到TestI18n.java同级
		System.out.println("自定义位置:\n" + cls.getResource("message_zh_CN.properties"));
		InputStream is = null;
		try {
			is = cls.getResourceAsStream("message_zh_CN.properties");
			// PropertyResourceBundle继承于ResourceBundle
			ResourceBundle rb = new PropertyResourceBundle(new InputStreamReader(is, "UTF-8"));
			String str = rb.getString("str1");
			System.out.println(str);
		} catch (Exception e) {
			throw e;
		} finally {
			try {
				is.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

运行结果:

自定义位置:
file:/E:/J2SE_workspace/TestI18n/bin/com/szh/message_zh_CN.properties
晚安

通过查看Kettle国际化部分的源码,其思想同上,即通过传入不同的class参数,来对应找到不同位置的国际化文件。

另附,Kettle8.1,Spoon设计器界面公共部分(除转换、作业组件自身)需要汉化的整理文档: