Handling Plurals
如果复数形式和单数形式都可能,则消息中的单词可能会有所不同。使用ChoiceFormat
类,您可以将数字 Map 到单词或短语,从而可以构造语法正确的消息。
在英语中,单词的复数形式和单数形式通常是不同的。当您构造引用数量的消息时,这可能会带来问题。例如,如果您的消息报告磁盘上的文件数,则可能有以下变化:
There are no files on XDisk.
There is one file on XDisk.
There are 2 files on XDisk.
解决此问题的最快方法是创建一个MessageFormat
Pattern,如下所示:
There are {0,number} file(s) on {1}.
不幸的是,上述 Pattern 导致语法错误:
There are 1 file(s) on XDisk.
如果您使用ChoiceFormat类,则可以做得更好。在本节中,您将通过逐步执行名为ChoiceFormatDemo的示例程序来学习如何处理消息中的复数形式。该程序还使用MessageFormat
类,在上一节处理复合消息中进行了讨论。
1.定义消息 Pattern
首先,确定消息中的变量:
接下来,将消息中的变量替换为参数,创建可应用于MessageFormat
对象的 Pattern:
There {0} on {1}.
磁盘名称的参数由{1}
表示,很容易处理。您只需要像MessageFormat
Pattern 中的任何其他String
变量一样对待它即可。此参数与参数值数组中索引 1 处的元素匹配。 (请参阅step 7。)
处理参数{0}
比较复杂,原因有两个:
-
该参数替换的短语随文件数量的不同而不同。要在运行时构造此短语,您需要将文件数 Map 到特定的
String
。例如,数字 1 将 Map 到包含短语is one file
的String
。ChoiceFormat
类允许您执行必要的 Map。 -
如果磁盘包含多个文件,则该短语包括一个整数。
MessageFormat
类可让您在短语中插入数字。
2.创建一个 ResourceBundle
因为必须翻译消息文本,所以将其用ResourceBundle
隔开:
ResourceBundle bundle = ResourceBundle.getBundle(
"ChoiceBundle", currentLocale);
该示例程序使用属性文件支持ResourceBundle
。 ChoiceBundle_en_US.properties包含以下几行:
pattern = There {0} on {1}.
noFiles = are no files
oneFile = is one file
multipleFiles = are {2} files
此属性文件的内容显示了如何构造和格式化消息。第一行包含MessageFormat
的 Pattern。 (请参见step 1。)其他各行包含将替换 Pattern 中参数{0}
的短语。 multipleFiles
键的短语包含参数{2}
,该参数将替换为数字。
这是属性文件ChoiceBundle_fr_FR.properties的法语版本
pattern = Il {0} sur {1}.
noFiles = n'y a pas de fichiers
oneFile = y a un fichier
multipleFiles = y a {2} fichiers
3.创建邮件格式化程序
在此步骤中,实例化MessageFormat
并设置其Locale
:
MessageFormat messageForm = new MessageFormat("");
messageForm.setLocale(currentLocale);
4.创建选择格式器
ChoiceFormat
对象使您可以根据double
数字选择特定的String
。数组中指定double
数字的范围以及它们所 Map 的String
对象:
double[] fileLimits = {0,1,2};
String [] fileStrings = {
bundle.getString("noFiles"),
bundle.getString("oneFile"),
bundle.getString("multipleFiles")
};
ChoiceFormat
将double
数组中的每个元素 Map 到String
数组中具有相同索引的元素。在示例代码中,0Map 到通过调用bundle.getString("noFiles")
返回的String
。碰巧的是,索引与fileLimits
数组中的值相同。如果代码已将fileLimits[0]
设置为 7,则ChoiceFormat
会将数字 7Map 到fileStrings[0]
。
您在实例化ChoiceFormat
时指定double
和String
数组:
ChoiceFormat choiceForm = new ChoiceFormat(fileLimits, fileStrings);
5.应用图案
还记得您在步骤 1 中构建的 Pattern 吗?现在是时候从ResourceBundle
检索 Pattern 并将其应用于MessageFormat
对象了:
String pattern = bundle.getString("pattern");
messageForm.applyPattern(pattern);
6.分配格式
在此步骤中,您将在步骤 4 中创建的ChoiceFormat
对象分配给MessageFormat
对象:
Format[] formats = {choiceForm, null, NumberFormat.getInstance()};
messageForm.setFormats(formats);
setFormats
方法将Format
对象分配给消息 Pattern 中的参数。在调用setFormats
方法之前,必须先调用applyPattern
方法。下表显示了Format
数组的元素如何与消息 Pattern 中的参数相对应:
ChoiceFormatDemo 程序的格式数组
Array Element | Pattern Argument |
---|---|
choiceForm | {0} |
null | {1} |
NumberFormat.getInstance() | {2} |
7.设置参数并设置消息格式
在运行时,程序将变量分配给传递给MessageFormat
对象的参数数组。数组中的元素对应于 Pattern 中的参数。例如,messageArgument[1]
Map 到 Pattern 参数{1}
,该参数是包含磁盘名称的String
。在上一步中,程序将ChoiceFormat
对象分配给 Pattern 的自变量{0}
。因此,分配给messageArgument[0]
的数字确定ChoiceFormat
对象选择哪个String
。如果messageArgument[0]
大于或等于 2,则包含短语are {2} files
的String
替换 Pattern 中的参数{0}
。分配给messageArgument[2]
的数字将替换 Pattern 参数{2}
。这是try此代码的代码:
Object[] messageArguments = {null, "XDisk", null};
for (int numFiles = 0; numFiles < 4; numFiles++) {
messageArguments[0] = new Integer(numFiles);
messageArguments[2] = new Integer(numFiles);
String result = messageForm.format(messageArguments);
System.out.println(result);
}
8.运行演示程序
将程序显示的消息与步骤 2 的ResourceBundle
中的短语进行比较。请注意,ChoiceFormat
对象选择了正确的短语,MessageFormat
对象用来构造正确的消息。 ChoiceFormatDemo
程序的输出如下:
currentLocale = en_US
There are no files on XDisk.
There is one file on XDisk.
There are 2 files on XDisk.
There are 3 files on XDisk.
currentLocale = fr_FR
Il n'y a pas des fichiers sur XDisk.
Il y a un fichier sur XDisk.
Il y a 2 fichiers sur XDisk.
Il y a 3 fichiers sur XDisk.