在Java/JSP中,通常使用.properties文件定义各语言的文本,里面可以用{0},{1},{2}表示待插入的变量值(之所以用数字,不用%s、%d等占位符,是因为不同语言的语序不同)。
用java.util.ResourceBundle类的ResourceBundle.getBundle方法读取.properties文件。
用java.text.MessageFormat类替换{0},{1},{2}等占位符。在字符串中,{和}字符本身用'{和'}表示(在前面加单引号),单引号本身用双单引号''表示。
用java.text.ChoiceFormat实现名词单复数的功能。中文没有名词的数的概念,但英语分单复数,阿拉伯语的名词还分为单数、双数和复数。
默认情况下,Java里面中文数字是有千分隔符的,但我们中国人的真实习惯是不显示千分隔符。需要在NumberFormat类里面用setGroupingUsed(false)关闭千分隔符的显示。
这几个类都是Java默认支持的类,不需要额外导入其他jar包。
第一节 在文本中替换变量占位符,并处理名词单复数
import java.text.ChoiceFormat;
import java.text.MessageFormat;
import java.text.NumberFormat;
import java.util.Locale;
public class Test {
public static void main(String[] args) {
test(getChineseMessage());
test(getEnglishMessage());
}
public static MessageFormat getChineseMessage() {
// 中文没有单复数
MessageFormat msgfmt = new MessageFormat("{1}有{0}个文件。");
NumberFormat nf = NumberFormat.getInstance(Locale.SIMPLIFIED_CHINESE);
nf.setGroupingUsed(false); // 显示数字时不显示千分隔符
msgfmt.setFormatByArgumentIndex(0, nf);
return msgfmt;
}
public static MessageFormat getEnglishMessage() {
// 英文有单复数之分
double[] pluralRule = {0, 1, ChoiceFormat.nextDouble(1)};
String[] choices = {"are no files", "is one file", "are {0} files"};
MessageFormat msgfmt = new MessageFormat("There {0} on {1}.");
ChoiceFormat cf = new ChoiceFormat(pluralRule, choices);
msgfmt.setFormatByArgumentIndex(0, cf);
return msgfmt;
}
public static void test(MessageFormat msgfmt) {
Object[] values = {1, "A"};
String str = msgfmt.format(values);
System.out.println(str);
values = new Object[] {1.01, "B"};
str = msgfmt.format(values);
System.out.println(str);
values[0] = 12345;
str = msgfmt.format(values);
System.out.println(str);
values[0] = 0;
str = msgfmt.format(values);
System.out.println(str);
values[0] = -1;
str = msgfmt.format(values);
System.out.println(str);
}
}
程序运行结果:
A有1个文件。
B有1.01个文件。
B有12345个文件。
B有0个文件。
B有-1个文件。
There is one file on A.
There are 1.01 files on B.
There are 12,345 files on B.
There are no files on B.
There are no files on B.
第二节 从.properties文件中读取多语言文本
新建两个.properties文件:haha_en_US.properties和haha_zh_CN.properties。
这两个文件要放到src文件夹里面。
haha_en_US.properties:
test.msg = There {0} on {1}.
test.msg.c00 = are no files
test.msg.c01 = is one file
test.msg.c02 = are {0} files
haha_zh_CN.properties:
请注意在.properties文件里面,所有的汉字都需要ISO-8859-1转义。
test.msg = {1}\u6709{0}\u4E2A\u6587\u4EF6\u3002
测试代码:
import java.text.ChoiceFormat;
import java.text.MessageFormat;
import java.text.NumberFormat;
import java.util.Locale;
import java.util.ResourceBundle;
public class Test2 {
public static void main(String[] args) {
// 定义参数
Object[] values = {12345678, "A"};
// 显示简体中文文本
ResourceBundle res = ResourceBundle.getBundle("haha", Locale.SIMPLIFIED_CHINESE);
String fmt = res.getString("test.msg");
MessageFormat mfmt = new MessageFormat(fmt);
NumberFormat nf = NumberFormat.getInstance(Locale.SIMPLIFIED_CHINESE);
nf.setGroupingUsed(false); // 显示数字时不显示千分隔符
mfmt.setFormatByArgumentIndex(0, nf);
String str = mfmt.format(values);
System.out.println(str);
// 显示英语(美国)文本
res = ResourceBundle.getBundle("haha", Locale.US);
fmt = res.getString("test.msg");
mfmt = new MessageFormat(fmt);
double[] pluralRule = {0, 1, ChoiceFormat.nextDouble(1)}; // 0、单数、复数判定方法
String[] fmtList0 = new String[3]; // 0、单数、复数对应的文本
fmtList0[0] = res.getString("test.msg.c00");
fmtList0[1] = res.getString("test.msg.c01");
fmtList0[2] = res.getString("test.msg.c02");
ChoiceFormat cf = new ChoiceFormat(pluralRule, fmtList0);
mfmt.setFormatByArgumentIndex(0, cf);
str = mfmt.format(values);
System.out.println(str);
}
}
程序运行结果:
A有12345678个文件。
There are 12,345,678 files on A.