Java教程是为JDK 8编写的。本页中描述的示例和实践未利用后续版本中引入的改进,并可能使用不再可用的技术。
请参阅Java语言更改以了解Java SE 9及后续版本中的更新语言功能摘要。
请参阅JDK发布说明以获取有关所有JDK版本的新功能、增强功能以及已删除或不推荐选项的信息。
如果消息中存在单数和复数形式的单词,那么单词可能会有所变化。使用ChoiceFormat类,您可以将数字映射到一个单词或短语,从而构建语法正确的消息。
在英语中,单词的复数和单数形式通常是不同的。当您构建涉及数量的消息时,这可能会导致问题。例如,如果您的消息报告了磁盘上的文件数量,则可能会出现以下变化:
X磁盘上没有文件。 X磁盘上有一个文件。 X磁盘上有2个文件。
解决此问题的最快方法是创建一个像这样的MessageFormat模式:
在{1}上有{0,number}个文件。
不幸的是,上述模式会导致错误的语法:
X磁盘上有1个文件。
如果您使用ChoiceFormat类,情况可能会好些。在本节中,您将通过查看一个名为ChoiceFormatDemo的示例程序来了解如何通过消息处理复数形式。该程序还使用了在前一节“处理复合消息”中讨论的MessageFormat类。
首先,识别消息中的变量:
接下来,使用参数替换消息中的变量,创建一个可以应用于MessageFormat对象的模式:
在{1}上{0}。
磁盘名称的参数,即{1},很容易处理。您只需将其视为MessageFormat模式中的任何其他String变量处理即可。此参数与参数值数组中索引为1的元素匹配。(参见第7步。)
处理参数{0}更为复杂,原因如下:
String。例如,数字1将映射到包含短语“有一个文件”的String。ChoiceFormat类允许您执行必要的映射。MessageFormat类允许您在短语中插入一个数字。因为消息文本需要进行翻译,所以将其放入一个ResourceBundle中:
ResourceBundle bundle = ResourceBundle.getBundle(
"ChoiceBundle", currentLocale);
示例程序使用属性文件作为ResourceBundle的后端。 ChoiceBundle_en_US.properties包含以下内容:
pattern = 在 {1} 上有 {0}。
noFiles = 没有文件
oneFile = 有一个文件
multipleFiles = 有 {2} 个文件
这个属性文件的内容显示了消息的构造和格式化方式。第一行包含了MessageFormat的模式。(参见步骤1。)其他行包含了将替换模式中的参数{0}的短语。 multipleFiles键对应的短语中包含参数{2},该参数将被一个数字替换。
这是法语版本的属性文件,ChoiceBundle_fr_FR.properties
pattern = Il y a {0} sur {1}.
noFiles = n'y a pas de fichiers
oneFile = y a un fichier
multipleFiles = y a {2} fichiers
在这一步中,实例化MessageFormat并设置其Locale:
MessageFormat messageForm = new MessageFormat("");
messageForm.setLocale(currentLocale);
ChoiceFormat对象允许您根据一个double数值选择一个特定的String。这些double数值的范围以及它们映射到的String对象在数组中指定:
double[] fileLimits = {0,1,2};
String [] fileStrings = {
bundle.getString("noFiles"),
bundle.getString("oneFile"),
bundle.getString("multipleFiles")
};
ChoiceFormat将double数组中的每个元素映射到具有相同索引的String数组中的元素。在示例代码中,0映射到调用bundle.getString("noFiles")返回的String。巧合的是,索引与fileLimits数组中的值相同。如果代码将fileLimits[0]设置为7,ChoiceFormat将把数字7映射到fileStrings[0]。
在实例化ChoiceFormat时,您需要指定double数组和String数组:
ChoiceFormat choiceForm = new ChoiceFormat(fileLimits, fileStrings);
记住在步骤1中构建的模式吗?现在是从ResourceBundle中检索模式并应用到MessageFormat对象的时候了:
String pattern = bundle.getString("pattern");
messageForm.applyPattern(pattern);
在这一步中,将在步骤4中创建的ChoiceFormat对象分配给MessageFormat对象:
Format[] formats = {choiceForm, null, NumberFormat.getInstance()};
messageForm.setFormats(formats);
setFormats方法将Format对象分配给消息模式中的参数。在调用setFormats方法之前,必须调用applyPattern方法。下表显示了Format数组的元素与消息模式中的参数的对应关系:
ChoiceFormatDemo程序的Format数组| 数组元素 | 模式参数 |
|---|---|
choiceForm |
{0} |
null |
{1} |
NumberFormat.getInstance() |
{2} |
在运行时,程序将变量分配给传递给MessageFormat对象的参数数组。数组中的元素与模式中的参数相对应。例如,messageArgument[1]对应模式参数{1},它是一个包含磁盘名称的String。在上一步中,程序将一个ChoiceFormat对象分配给模式参数{0}。因此,分配给messageArgument[0]的数字决定了ChoiceFormat对象选择哪个String。如果messageArgument[0]大于或等于2,则包含短语are {2} files的String将替换模式中的参数{0}。分配给messageArgument[2]的数字将替代模式参数{2}的位置。以下是尝试这样做的代码:
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);
}
将程序显示的消息与第2步中的ResourceBundle中的短语进行比较。注意,ChoiceFormat对象选择了正确的短语,而MessageFormat对象用于构造正确的消息。 ChoiceFormatDemo程序的输出如下所示:
currentLocale = en_US XDisk上没有文件。 XDisk上有一个文件。 XDisk上有2个文件。 XDisk上有3个文件。 currentLocale = fr_FR Il n'y a pas de fichiers sur XDisk. Il y a un fichier sur XDisk. Il y a 2 fichiers sur XDisk. Il y a 3 fichiers sur XDisk.