文档

Java™ 教程
隐藏目录
处理复数形式
路径:国际化
课程:格式化
章节:消息

处理复数

如果消息中存在单数和复数形式的单词,那么单词可能会有所变化。使用ChoiceFormat类,您可以将数字映射到一个单词或短语,从而构建语法正确的消息。

在英语中,单词的复数和单数形式通常是不同的。当您构建涉及数量的消息时,这可能会导致问题。例如,如果您的消息报告了磁盘上的文件数量,则可能会出现以下变化:

X磁盘上没有文件。
X磁盘上有一个文件。
X磁盘上有2个文件。

解决此问题的最快方法是创建一个像这样的MessageFormat模式:

在{1}上有{0,number}个文件。

不幸的是,上述模式会导致错误的语法:

X磁盘上有1个文件。

如果您使用ChoiceFormat类,情况可能会好些。在本节中,您将通过查看一个名为ChoiceFormatDemo的示例程序来了解如何通过消息处理复数形式。该程序还使用了在前一节“处理复合消息”中讨论的MessageFormat类。

1. 定义消息模式

首先,识别消息中的变量:

Three lines of text, with the variables in each line highlighted.

接下来,使用参数替换消息中的变量,创建一个可以应用于MessageFormat对象的模式:

在{1}上{0}。

磁盘名称的参数,即{1},很容易处理。您只需将其视为MessageFormat模式中的任何其他String变量处理即可。此参数与参数值数组中索引为1的元素匹配。(参见第7步。)

处理参数{0}更为复杂,原因如下:

2. 创建一个资源包

因为消息文本需要进行翻译,所以将其放入一个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

3. 创建消息格式化器

在这一步中,实例化MessageFormat并设置其Locale

MessageFormat messageForm = new MessageFormat("");
messageForm.setLocale(currentLocale);

4. 创建选择格式化器

ChoiceFormat对象允许您根据一个double数值选择一个特定的String。这些double数值的范围以及它们映射到的String对象在数组中指定:

double[] fileLimits = {0,1,2};
String [] fileStrings = {
    bundle.getString("noFiles"),
    bundle.getString("oneFile"),
    bundle.getString("multipleFiles")
};

ChoiceFormatdouble数组中的每个元素映射到具有相同索引的String数组中的元素。在示例代码中,0映射到调用bundle.getString("noFiles")返回的String。巧合的是,索引与fileLimits数组中的值相同。如果代码将fileLimits[0]设置为7,ChoiceFormat将把数字7映射到fileStrings[0]

在实例化ChoiceFormat时,您需要指定double数组和String数组:

ChoiceFormat choiceForm = new ChoiceFormat(fileLimits, fileStrings);

5. 应用模式

记住在步骤1中构建的模式吗?现在是从ResourceBundle中检索模式并应用到MessageFormat对象的时候了:

String pattern = bundle.getString("pattern");
messageForm.applyPattern(pattern);

6. 分配格式

在这一步中,将在步骤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}

7. 设置参数并格式化消息

在运行时,程序将变量分配给传递给MessageFormat对象的参数数组。数组中的元素与模式中的参数相对应。例如,messageArgument[1]对应模式参数{1},它是一个包含磁盘名称的String。在上一步中,程序将一个ChoiceFormat对象分配给模式参数{0}。因此,分配给messageArgument[0]的数字决定了ChoiceFormat对象选择哪个String。如果messageArgument[0]大于或等于2,则包含短语are {2} filesString将替换模式中的参数{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);
}

8. 运行示例程序

将程序显示的消息与第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.

上一页: 处理复合消息
下一页: 使用文本