# 处理复合消息

> 原文： [https://docs.oracle.com/javase/tutorial/i18n/format/messageFormat.html](https://docs.oracle.com/javase/tutorial/i18n/format/messageFormat.html)

复合邮件可能包含多种变量：日期，时间，字符串，数字，货币和百分比。要以与语言环境无关的方式格式化复合邮件，可以构造应用于`MessageFormat`对象的模式，并将此模式存储在`ResourceBundle`中。

通过单步调试示例程序，本节演示了如何使复合邮件国际化。示例程序使用 [`MessageFormat`](https://docs.oracle.com/javase/8/docs/api/java/text/MessageFormat.html) 类。该程序的完整源代码位于名为 [`MessageFormatDemo.java`](examples/MessageFormatDemo.java) 的文件中。德语语言环境属性位于名为 [`MessageBundle_de_DE.properties`](examples/MessageBundle_de_DE.properties) 的文件中。

## 1.识别消息中的变量

假设您要国际化以下消息：

<center>![The following line of text: At 1:15 on April 13, 1998, we detected 7 spaceships on the planet Mars.  The variable data (1:15, April 13,1998, 7, and Mars) have been underlined.](img/e3ed737400f94a595293b94464e6df58.jpg)</center>

请注意，我们已经为变量数据加下划线，并确定了哪种对象将代表这些数据。

## 2.隔离 ResourceBundle 中的消息模式

将消息存储在名为`MessageBundle`的`ResourceBundle`中，如下所示：

```
ResourceBundle messages =
   ResourceBundle.getBundle("MessageBundle", currentLocale);

```

`ResourceBundle`由每个`Locale`的属性文件支持。由于`ResourceBundle`被称为`MessageBundle`，因此美国英语的属性文件被命名为`MessageBundle_en_US.properties`。该文件的内容如下：

```
template = At {2,time,short} on {2,date,long}, \
    we detected {1,number,integer} spaceships on \
    the planet {0}.
planet = Mars

```

属性文件的第一行包含消息模式。如果将此模式与步骤 1 中显示的消息文本进行比较，您将看到括在大括号中的参数替换消息文本中的每个变量。每个参数都以一个名为参数编号的数字开头，该数字与`Object`数组中保存参数值的元素的索引相匹配。请注意，在模式中，参数编号不是任何特定顺序。您可以将参数放在模式中的任何位置。唯一的要求是参数号在参数值数组中具有匹配元素。

下一步讨论参数值数组，但首先让我们看一下模式中的每个参数。下表提供了有关参数的一些详细信息：

<caption>Arguments for `template` in `MessageBundle_en_US.properties`</caption>
| 争论 | 描述 |
| --- | --- |
| `{2,time,short}` | `Date`对象的时间部分。 `short`样式指定`DateFormat.SHORT`格式样式。 |
| `{2,date,long}` | `Date`对象的日期部分。相同的`Date`对象用于日期和时间变量。在`Object`参数数组中，保存`Date`对象的元素的索引是 2.（这将在下一步中介绍。） |
| `{1,number,integer}` | 一个`Number`对象，进一步使用`integer`编号样式限定。 |
| `{0}` | `ResourceBundle`中与`planet`键对应的`String`。 |

有关参数语法的完整说明，请参阅 [`MessageFormat`](https://docs.oracle.com/javase/8/docs/api/java/text/MessageFormat.html) 类的 API 文档。

## 3.设置消息参数

以下代码行为模式中的每个参数赋值。 `messageArguments`数组中元素的索引与模式中的参数号匹配。例如，索引 1 处的`Integer`元素对应于模式中的`{1,number,integer}`参数。因为必须进行转换，所以元素 0 处的`String`对象将使用`getString`方法从`ResourceBundle`中获取。以下是定义消息参数数组的代码：

```
Object[] messageArguments = {
    messages.getString("planet"),
    new Integer(7),
    new Date()
};

```

## 4.创建格式化程序

接下来，创建一个`MessageFormat`对象。您设置`Locale`，因为该消息包含`Date`和`Number`对象，这些对象应以区域设置敏感的方式格式化。

```
MessageFormat formatter = new MessageFormat("");
formatter.setLocale(currentLocale);

```

## 5.使用模式和参数格式化消息

此步骤显示模式，消息参数和格式化程序如何一起工作。首先，使用`getString`方法从`ResourceBundle`中获取模式`String`。模式的关键是`template`。使用`applyPattern`方法将模式`String`传递给格式化程序。然后通过调用`format`方法使用消息参数数组格式化消息。 `format`方法返回的`String`已准备好显示。所有这一切都只需两行代码即可完成：

```
formatter.applyPattern(messages.getString("template"));
String output = formatter.format(messageArguments);

```

## 6.运行演示程序

演示程序打印英语和德语语言环境的翻译消息，并正确格式化日期和时间变量。请注意，英语和德语动词（“detected”和“entdeckt”）位于相对于变量的不同位置：

```
currentLocale = en_US
At 10:16 AM on July 31, 2009, we detected 7
spaceships on the planet Mars.
currentLocale = de_DE
Um 10:16 am 31\. Juli 2009 haben wir 7 Raumschiffe
auf dem Planeten Mars entdeckt.

```