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.