國際化是軟件走向全球市場的必經之路。Java 憑藉 Unicode 內碼支持、完善的 java.util.Locale、java.text 格式化包以及 ResourceBundle 資源束機制,提供了業界領先的本地化基礎設施。本文通過一個完整的 Swing 應用示例,系統講解 Java UI 本地化的三大支柱、資源文件組織、編碼處理、事件監聽器本地化陷阱及最佳實踐。
java.text 套件)ResourceBundle)// 語言代碼 (ISO-639) + 可選國家代碼 (ISO-3166)
Locale zh_CN = new Locale("zh", "CN"); // 中國大陸簡體中文
Locale zh_TW = new Locale("zh", "TW"); // 台灣繁體中文
Locale en_US = new Locale("en", "US"); // 美國英語
Locale DEFAULT = Locale.getDefault(); // JVM 默認地區(受操作系統/啟動參數影響)
// 設置全局默認地區(慎用,影響整個 JVM)
Locale.setDefault(Locale.ENGLISH);
查找策略(按優先級遞減):
basename_language_country_variant
basename_language_country
basename_language
basename (默認資源文件)
→ 找不到拋出 MissingResourceException
兩種實現方式:
PropertyResourceBundle,鍵值對文本文件,最常用ListResourceBundle,編譯為 class,支持複雜對象、邏輯判斷Java 源文件默認 ISO-8859-1,Properties 文件必須為 ASCII。工具將本地編碼轉為 Unicode 轉義序列:
# 轉換前
Title=中國
red.label=紅色
# native2ascii 轉換後
Title=\u4e2d\u56fd
red.label=\u7ea2\u8272
# 命令
native2ascii -encoding UTF-8 src.properties target.properties
現代替代:IDE 自動處理、Maven/Gradle 插件、Java 9+ 支持 UTF-8 Properties 文件(JEP 226)。
src/ ├── Properties/ │ ├── Dorian.properties # 默認資源(中文) │ ├── Dorian_en_US.properties # 美國英語 │ └── Dorian_zh_CN.properties # 中國大陸(繼承默認可為空) ├── MyNative.java # 主程序入口 ├── MyNativeFrame.java # 主窗口 └── MyNativePanel.java # 面板組件
# Dorian.properties (默認/中文)
Title=\u4e2d\u56fd
red.label=\u7ea2\u8272
green.label=\u7eff\u8272
blue.label=\u84dd\u8272
# Dorian_en_US.properties (美國英語)
Title=America
red.label=Red
green.label=Green
blue.label=Blue
public class MyNativeFrame extends JFrame {
public MyNativeFrame() {
// 1. 獲取地區(默認或指定)
Locale locale = Locale.getDefault();
// 2. 加載資源束
ResourceBundle bundle = ResourceBundle.getBundle("Properties.Dorian", locale);
// 3. 使用資源設置 UI 文本
setTitle(bundle.getString("Title"));
panel.setCmdRed(bundle.getString("red.label"));
panel.setCmdBlue(bundle.getString("blue.label"));
panel.setCmdGreen(bundle.getString("green.label"));
}
}
class MyNativePanel extends JPanel {
// 關鍵:使用內部類作為監聽器,避免硬編碼 actionCommand
public MyNativePanel() {
cmdRed = new JButton();
cmdRed.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String s = e.getActionCommand(); // 獲取按鈕當前文本(已本地化)
txt.setBackground(Color.red);
txt.setText(s);
}
});
// ... 其他按鈕同理
}
// 設置按鈕文本的 setter
public void setCmdRed(String s) { cmdRed.setText(s); }
// ...
}
問題代碼:
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if (cmd.equals("Cancel")) { // 硬編碼英文!
doCancel();
}
}
本地化後按鈕文本變為「取消」,判斷失效。
| 方案 | 實現方式 | 優點 | 缺點 |
|---|---|---|---|
| 1. 內部類監聽器 | 每個組件獨立匿名類,不依賴 actionCommand 判斷邏輯 | 完全解耦、代碼內聚 | 類數量多、微增內存 |
| 2. 使用 name 屬性 | btn.setName("cancelBtn"),判斷 e.getSource().getName() | 文本與標識分離 | 需維護 name 常量 |
| 3. 客戶端屬性 | btn.putClientProperty("actionId", "CANCEL") | 類型安全、擴展性強 | API 稍顯繁瑣 |