跳到主要内容

Java 国际化字符串

什么是国际化?

国际化(Internationalization,通常简称为i18n,因为在"i"和"n"之间有18个字母)是指设计软件时考虑到不同国家、地区的用户,使其能够适应不同的语言和地区而无需修改程序本身。对于全球性的应用程序,国际化是一个非常重要的考虑因素。

Java提供了完善的国际化支持,使开发人员能够轻松创建适用于不同语言和地区的应用程序。

为什么需要国际化?

国际化的重要性
  • 扩大用户群 - 支持多种语言可以帮助你的应用程序覆盖更多的用户
  • 提升用户体验 - 用户能够以自己熟悉的语言使用应用程序
  • 符合地区法规 - 某些国家可能要求软件提供当地语言版本

Java 国际化的核心组件

1. Locale类

Locale类表示特定的地理、政治或文化区域。创建Locale对象是进行国际化的第一步。

java
// 创建不同的Locale对象
Locale usLocale = new Locale("en", "US"); // 美国英语
Locale frLocale = new Locale("fr", "FR"); // 法国法语
Locale zhLocale = new Locale("zh", "CN"); // 中国中文

// 获取系统默认的Locale
Locale defaultLocale = Locale.getDefault();
System.out.println("系统默认的Locale: " + defaultLocale.getDisplayName());

// 获取所有可用的Locale
Locale[] availableLocales = Locale.getAvailableLocales();
System.out.println("可用的Locale数量: " + availableLocales.length);

2. ResourceBundle类

ResourceBundle是Java国际化的核心类,它管理特定于区域的资源,最常见的是用于管理不同语言的字符串。

创建属性文件

首先,我们需要为每种支持的语言创建属性文件:

  • messages_en_US.properties (美国英语)
greeting=Hello
farewell=Goodbye
inquiry=How are you?
  • messages_fr_FR.properties (法国法语)
greeting=Bonjour
farewell=Au revoir
inquiry=Comment allez-vous?
  • messages_zh_CN.properties (中国中文)
greeting=您好
farewell=再见
inquiry=您好吗?

使用ResourceBundle加载资源

java
import java.util.Locale;
import java.util.ResourceBundle;

public class I18nDemo {
public static void main(String[] args) {
// 创建不同的Locale对象
Locale usLocale = new Locale("en", "US");
Locale frLocale = new Locale("fr", "FR");
Locale zhLocale = new Locale("zh", "CN");

// 加载美国英语资源
ResourceBundle bundle = ResourceBundle.getBundle("messages", usLocale);
System.out.println("美国英语: " + bundle.getString("greeting"));

// 加载法国法语资源
bundle = ResourceBundle.getBundle("messages", frLocale);
System.out.println("法国法语: " + bundle.getString("greeting"));

// 加载中国中文资源
bundle = ResourceBundle.getBundle("messages", zhLocale);
System.out.println("中国中文: " + bundle.getString("greeting"));
}
}

输出结果:

美国英语: Hello
法国法语: Bonjour
中国中文: 您好

3. MessageFormat类

MessageFormat类帮助构建包含动态值的消息字符串。这对于构建复杂的国际化消息非常有用。

首先,让我们扩展我们的属性文件:

  • messages_en_US.properties
welcome=Welcome, {0}!
items=You have {0} {1} in your cart.
dateFormat=MM/dd/yyyy
  • messages_fr_FR.properties
welcome=Bienvenue, {0}!
items=Vous avez {0} {1} dans votre panier.
dateFormat=dd/MM/yyyy
  • messages_zh_CN.properties
welcome=欢迎,{0}!
items=您的购物车中有{0}件{1}。
dateFormat=yyyy年MM月dd日

现在我们可以使用MessageFormat来格式化这些消息:

java
import java.text.MessageFormat;
import java.util.Locale;
import java.util.ResourceBundle;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MessageFormatDemo {
public static void main(String[] args) {
// 使用不同的Locale
Locale[] locales = {
new Locale("en", "US"),
new Locale("fr", "FR"),
new Locale("zh", "CN")
};

String username = "Alex";
int itemCount = 5;
String itemName = "book";
Date currentDate = new Date();

for (Locale locale : locales) {
// 加载对应语言的资源包
ResourceBundle bundle = ResourceBundle.getBundle("messages", locale);

// 格式化欢迎消息
String welcome = bundle.getString("welcome");
String formattedWelcome = MessageFormat.format(welcome, username);

// 格式化商品消息
String items = bundle.getString("items");
String formattedItems = MessageFormat.format(items, itemCount, itemName);

// 格式化日期
String datePattern = bundle.getString("dateFormat");
SimpleDateFormat dateFormat = new SimpleDateFormat(datePattern, locale);
String formattedDate = dateFormat.format(currentDate);

// 打印结果
System.out.println("语言: " + locale.getDisplayLanguage());
System.out.println(formattedWelcome);
System.out.println(formattedItems);
System.out.println("当前日期: " + formattedDate);
System.out.println("------------------------");
}
}
}

输出结果可能类似于:

语言: 英语
Welcome, Alex!
You have 5 book in your cart.
当前日期: 07/15/2023
------------------------
语言: 法语
Bienvenue, Alex!
Vous avez 5 book dans votre panier.
当前日期: 15/07/2023
------------------------
语言: 中文
欢迎,Alex!
您的购物车中有5件book。
当前日期: 2023年07月15日
------------------------

国际化日期、货币和数字

Java还提供了用于格式化日期、货币和数字的国际化支持。

日期格式化

java
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;

public class DateFormatDemo {
public static void main(String[] args) {
Date now = new Date();

Locale[] locales = {
Locale.US, // 美国
Locale.FRANCE, // 法国
Locale.CHINA, // 中国
Locale.JAPAN, // 日本
new Locale("ar", "SA") // 沙特阿拉伯
};

for (Locale locale : locales) {
// 获取不同格式的日期格式化器
DateFormat shortDF = DateFormat.getDateInstance(DateFormat.SHORT, locale);
DateFormat mediumDF = DateFormat.getDateInstance(DateFormat.MEDIUM, locale);
DateFormat longDF = DateFormat.getDateInstance(DateFormat.LONG, locale);

System.out.println("区域: " + locale.getDisplayName());
System.out.println("SHORT: " + shortDF.format(now));
System.out.println("MEDIUM: " + mediumDF.format(now));
System.out.println("LONG: " + longDF.format(now));
System.out.println("------------------------");
}
}
}

货币格式化

java
import java.text.NumberFormat;
import java.util.Locale;

public class CurrencyFormatDemo {
public static void main(String[] args) {
double amount = 12345.67;

Locale[] locales = {
Locale.US, // 美国
Locale.FRANCE, // 法国
Locale.CHINA, // 中国
Locale.JAPAN, // 日本
new Locale("ar", "SA") // 沙特阿拉伯
};

for (Locale locale : locales) {
NumberFormat formatter = NumberFormat.getCurrencyInstance(locale);
String currency = formatter.format(amount);

System.out.println("区域: " + locale.getDisplayName());
System.out.println("货币格式: " + currency);
System.out.println("------------------------");
}
}
}

数字格式化

java
import java.text.NumberFormat;
import java.util.Locale;

public class NumberFormatDemo {
public static void main(String[] args) {
double number = 123456.789;

Locale[] locales = {
Locale.US, // 美国
Locale.FRANCE, // 法国
Locale.CHINA, // 中国
Locale.JAPAN, // 日本
new Locale("ar", "SA") // 沙特阿拉伯
};

for (Locale locale : locales) {
NumberFormat formatter = NumberFormat.getNumberInstance(locale);
String formattedNumber = formatter.format(number);

System.out.println("区域: " + locale.getDisplayName());
System.out.println("数字格式: " + formattedNumber);
System.out.println("------------------------");
}
}
}

实际应用案例:多语言聊天应用

让我们看一个实际案例:构建一个支持多语言的简单聊天应用界面。

java
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Locale;
import java.util.ResourceBundle;

public class MultilingualChatApp extends JFrame {
private JTextArea chatArea;
private JTextField messageField;
private JButton sendButton;
private JComboBox<String> languageSelector;
private ResourceBundle bundle;
private Locale currentLocale;

// 支持的语言
private final String[] languages = {"English", "Français", "中文"};
private final Locale[] locales = {
new Locale("en", "US"),
new Locale("fr", "FR"),
new Locale("zh", "CN")
};

public MultilingualChatApp() {
// 默认使用英语
currentLocale = locales[0];
loadLanguageBundle();
initializeUI();
}

private void loadLanguageBundle() {
bundle = ResourceBundle.getBundle("chat", currentLocale);
}

private void initializeUI() {
setTitle(bundle.getString("title"));
setSize(400, 500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());

// 顶部语言选择器
JPanel topPanel = new JPanel();
topPanel.add(new JLabel(bundle.getString("language") + ": "));
languageSelector = new JComboBox<>(languages);
languageSelector.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int selectedIndex = languageSelector.getSelectedIndex();
currentLocale = locales[selectedIndex];
loadLanguageBundle();
updateUIText();
}
});
topPanel.add(languageSelector);
add(topPanel, BorderLayout.NORTH);

// 聊天区域
chatArea = new JTextArea();
chatArea.setEditable(false);
JScrollPane scrollPane = new JScrollPane(chatArea);
add(scrollPane, BorderLayout.CENTER);

// 底部消息输入区
JPanel bottomPanel = new JPanel(new BorderLayout());
messageField = new JTextField();
sendButton = new JButton(bundle.getString("send"));

sendButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String message = messageField.getText();
if (!message.isEmpty()) {
// 添加消息到聊天区域
chatArea.append(bundle.getString("you") + ": " + message + "\n");
// 模拟回复
chatArea.append(bundle.getString("bot") + ": " +
bundle.getString("reply") + "\n");
messageField.setText("");
}
}
});

bottomPanel.add(messageField, BorderLayout.CENTER);
bottomPanel.add(sendButton, BorderLayout.EAST);
add(bottomPanel, BorderLayout.SOUTH);
}

private void updateUIText() {
setTitle(bundle.getString("title"));
sendButton.setText(bundle.getString("send"));
// 可以根据需要更新其他UI元素
}

public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new MultilingualChatApp().setVisible(true);
}
});
}
}

对应的资源文件:

  • chat_en_US.properties
title=Chat Application
language=Language
send=Send
you=You
bot=Bot
reply=Thank you for your message!
  • chat_fr_FR.properties
title=Application de Chat
language=Langue
send=Envoyer
you=Vous
bot=Robot
reply=Merci pour votre message!
  • chat_zh_CN.properties
title=聊天应用
language=语言
send=发送
you=你
bot=机器人
reply=谢谢您的留言!

国际化的最佳实践

最佳实践
  1. 早做计划 - 从项目开始就考虑国际化,而不是之后添加
  2. 分离文本资源 - 将所有显示文本放在属性文件中,不要在代码中硬编码
  3. 注意文化差异 - 不同国家有不同的日期格式、数字格式和时区
  4. 考虑文本膨胀 - 翻译后的文本长度可能会比原文长,UI设计要考虑这一点
  5. 对齐方向 - 某些语言(如阿拉伯语)是从右向左读的
  6. 图片和图标 - 使用文化中立的图像,避免可能在某些文化中有负面含义的符号

总结

在Java中实现国际化非常简单直观,主要依靠以下几个核心组件:

  1. Locale类 - 表示特定的地理、政治或文化区域
  2. ResourceBundle类 - 管理特定于区域的资源,特别是字符串
  3. MessageFormat类 - 构建包含动态值的国际化消息
  4. 用于格式化的类 - DateFormat、NumberFormat等用于格式化日期、数字和货币

通过这些工具,Java开发人员可以创建出适应全球用户的应用程序,提供本地化的用户体验。

练习

  1. 创建一个简单的多语言计算器应用,支持英语、你的母语和另一种你选择的语言。
  2. 编写一个程序,显示不同国家的当前时间,并根据各国的格式进行显示。
  3. 实现一个国际化的登录表单,根据用户选择的语言显示不同语言的表单字段和错误消息。
  4. 扩展本文中的聊天应用,增加更多功能和支持的语言。

额外资源

通过掌握Java国际化,你的应用程序将能够无缝地适应全球不同地区和语言的用户,大大扩展你的受众范围!