Java 教程是为 JDK 8 编写的。本页中描述的示例和实践未利用在后续版本中引入的改进。
如果复数和单数形式都可能,则消息中的单词可能会有所不同。使用 ChoiceFormat
类,你可以将数字映射到单词或短语,从而允许你构造语法正确的消息。
在英语中,单词的复数和单数形式通常是不同的。当你构建引用数量的消息时,这可能会出现问题。例如,如果你的消息报告磁盘上的文件数,则可能存在以下变化:
There are no files on XDisk. There is one file on XDisk. There are 2 files on XDisk.
解决此问题的最快方法是创建一个 MessageFormat
模式,如下所示:
There are {0,number} file(s) on {1}.
不幸的是,前面的模式会导致错误的语法:
There are 1 file(s) on XDisk.
如果使用 ChoiceFormat
类,则可以做得更好。在本节中,你将通过逐步演示名为 ChoiceFormatDemo
的示例程序来学习处理消息中的复数形式。此程序还使用 MessageFormat
类,该类在上一节中讨论,Dealing with Compound Messages。
首先,确定消息中的变量:
接下来,使用参数替换消息中的变量,创建可应用于 MessageFormat
对象的模式:
There {0} on {1}.
磁盘名称的参数(由 {1}
表示)很容易处理。你只需将其视为 MessageFormat
模式中的任何其他 String
变量。此参数与参数值数组中索引 1 处的元素匹配。(见 step 7)。
处理参数 {0}
更复杂,原因如下:
String
。例如,数字 1 将映射到包含短语 is one file
的 String
。ChoiceFormat
类允许你执行必要的映射。MessageFormat
类允许你在短语中插入数字。因为必须翻译消息文本,所以将其隔离在 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
的模式。(参见 step 1。)其他行包含将替换模式中的参数 {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
在此步骤中,你将实例化 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);
在此步骤中,为 MessageFormat
对象分配在步骤 4 中创建的 ChoiceFormat
对象:
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 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.