# 处理复合信息

复合信息可以包含几种类型的变量:日期、时间、字符串、数字、货币和百分比。要以与 Locale 无关的方式格式化复合信息,需要构造一个模式,将其应用于 MessageFormat 对象,并将此模式存储在 ResourceBundle 中。

下面通过一个示例程序来讲解如何使用,完整示例程序在最后贴出

# 1. 识别信息中的变量

假设要国际化以下信息

image-20200717112609464

上图显示了哪些是变量,并且数据类型是什么

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

将信息存储在 MessageBundle 中

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

为 en_US 翻译的信息文件 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
2
3
4

template 就是一个信息模式,如果将此模式与步骤 1 中显示的信息文本进行比较,将看到用 大括号括起来的参数 替换信息文本中的每个变量。

每个参数都以一个称为 参数号的数字开头,它与保存 参数值的对象数组中的元素的索引 相匹配。注意,在模式中,参数号没有任何特定的顺序。您可以将参数放在模式中的任何位置。惟一的要求是参数号在参数值数组中有一个匹配的元素。

下面解释下每个模式中的参数

Argument Description
{2,time,short} Date 对象的时间部分, short 表示使用 DateFormat.SHORT 来格式化时间
{2,date,long} Date 对象的日期部分,Date 日期和时间都使用相同的对象。在 Object 参数数组中,该 Date 对象元素索引为 2。
{1,number,integer} 一个 Number 对象,进一步使用 integer 来限定格式化
{0} ResourceBundle对应于planet关键。

# 3. 设置信息参数

为 template 构建参数数组,按照模式中的参数号进行构建

Object[] messageArguments = {
    messages.getString("planet"),
    new Integer(7),
    new Date()
};
1
2
3
4
5

# 4. 创建格式化程序

创建 MessageFormat 对象,设置 Locale 是因为该信息包含 Date 和 Number 对象,应该对 Locale 敏感的方式进行格式化

MessageFormat formatter = new MessageFormat("");
formatter.setLocale(currentLocale);
1
2

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

将信息模式传递给 MessageFormat ,进行格式化时,传递信息参数数组,返回一个格式化后的信息文本

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

# 完整程序示例

MessageBundle_zh_CN.properties

template = {2,date,long}{2,time,short} , \
    我们在{0}上发现有 {1,number,integer} 架宇宙飞船在飞行
planet = 火星
1
2
3

MessageBundle_en_US.properties 的内容在前面已经列出过了

import java.util.*;
import java.text.*;

public class MessageFormatDemo {

    static void displayMessage(Locale currentLocale) {

        System.out.println("currentLocale = " + currentLocale.toString());
        System.out.println();

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

        // 构建信息参数数组
        Object[] messageArguments = {
                messages.getString("planet"),
                new Integer(7),
                new Date()
        };

        MessageFormat formatter = new MessageFormat("");
        // 指定使用 Locale
        formatter.setLocale(currentLocale);

        // 给定信息中的复合信息模式(模板)
        formatter.applyPattern(messages.getString("template"));
        String output = formatter.format(messageArguments);

        System.out.println(output);

    }

    static public void main(String[] args) {
        displayMessage(new Locale("en", "US"));
        System.out.println();
        displayMessage(new Locale("zh", "CN"));
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

测试输出

currentLocale = en_US

At 11:58 AM on July 17, 2020, we detected 7 spaceships on the planet Mars.

currentLocale = zh_CN

2020年7月17日下午12:00 , 我们在火星上发现有 7 架宇宙飞船在飞行
1
2
3
4
5
6
7