最近在做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个国际化文件目录如下:
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包下:
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设计器界面公共部分(除转换、作业组件自身)需要汉化的整理文档: