
本文详解在 jdk 11 及更高版本中为 jfilechooser 实现可靠本地化的两种专业方案:全局 locale 设置的局限性分析,以及基于 uimanager.put() 的精准字符串覆盖策略,并提供完整可复用的瑞典语本地化代码与资源键查找方法。
在 JDK 11 及后续版本中,单纯通过 Locale.setDefault(new Locale("sv", "SE")) 已无法使 JFileChooser 自动切换为瑞典语界面——这并非 Bug,而是 Swing L&F(外观与感觉)实现机制演进的结果。自 JDK 9 起,模块化系统强化了资源加载隔离;而从 JDK 11 开始,部分平台专属 Look & Feel(如 Windows L&F)对 Locale 的依赖被显式弱化,转而更依赖 UIManager 中预注册的 UIDefaults 值。这意味着:语言本地化不再由“单一 Locale 全局驱动”,而是由 UIManager 维护的键值映射表(UIDefaults)动态控制。
✅ 推荐方案:使用 UIManager.put() 精准覆盖 UI 字符串
这是目前最稳定、跨 JDK 版本兼容性最佳的方式。所有 JFileChooser 界面文本均由 UIManager 提供的键(key)对应值(value)渲染,例如 "FileChooser.openButtonText" 控制“打开”按钮文字。这些键不来自 JFileChooser 类本身,而是由当前 L&F 对应的 LookAndFeel 实现类(如 WindowsLookAndFeel)在初始化时向 UIManager 注册的默认资源值。
你可以通过以下方式确认当前 L&F:
System.out.println("Current L&F: " + UIManager.getSystemLookAndFeelClassName());
// 输出示例:com.sun.java.swing.plaf.windows.WindowsLookAndFeel⚠️ 注意:UIManager.put() 必须在创建任何 Swing 组件之前调用(通常在 main() 开头或 SwingUtilities.invokeLater() 的首行),否则无效。
?? 完整瑞典语本地化示例(Windows L&F)
以下代码覆盖了 JFileChooser 在 Windows 平台下 Open / Save 对话框中全部关键文本(已验证适用于 JDK 11–21):
import javax.swing.*;
import java.awt.*;
import java.util.Locale;
public class SwedishFileChooser {
public static void setupSwedishLocale() {
// 关键:必须在 UIManager.setLookAndFeel() 或任何组件创建前执行
UIManager.put("FileChooser.openDialogTitleText", "Öppna");
UIManager.put("FileChooser.saveDialogTitleText", "Spara som");
UIManager.put("FileChooser.lookInLabelText", "Bläddra i:");
UIManager.put("FileChooser.saveInLabelText", "Spara i:"); // JDK 11+ 必须显式设置!
UIManager.put("FileChooser.fileNameLabelText", "Filnamn:");
UIManager.put("FileChooser.filesOfTypeLabelText", "Filtyper:");
UIManager.put("FileChooser.openButtonText", "Öppna");
UIManager.put("FileChooser.saveButtonText", "Spara");
UIManager.put("FileChooser.cancelButtonText", "Avbryt");
UIManager.put("FileChooser.acceptAllFileFilterText", "Alla filer");
UIManager.put("FileChooser.newFolderButtonText", "Ny mapp");
UIManager.put("FileChooser.upFolderToolTipText", "Gå upp en nivå");
UIManager.put("FileChooser.homeFolderToolTipText", "Hemkatalog");
UIManager.put("FileChooser.desktopFolderToolTipText", "Skrivbord");
UIManager.put("FileChooser.detailsViewButtonToolTipText", "Detaljvy");
UIManager.put("FileChooser.listViewButtonToolTipText", "Listvy");
UIManager.put("FileChooser.fileNameHeaderText", "Namn");
UIManager.put("FileChooser.fileSizeHeaderText", "Storlek");
UIManager.put("FileChooser.fileTypeHeaderText", "Typ");
UIManager.put("FileChooser.fileDateHeaderText", "Ändrad");
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
try {
// 可选:显式设置 Windows L&F(确保行为一致)
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
setupSwedishLocale(); // ← 核心本地化步骤
JFileChooser chooser = new JFileChooser();
int result = chooser.showOpenDialog(null);
if (result == JFileChooser.APPROVE_OPTION) {
System.out.println("Vald fil: " + chooser.getSelectedFile());
}
});
}
}? 如何查找所有可用的 UIManager 键?
官方未提供完整键列表,但可通过以下方式获取权威参考:
- 权威键清单:The Bad Programmer – Swing UIManager Keys(持续更新,覆盖主流 L&F)
- 源码级验证:查看 OpenJDK 中对应 L&F 的资源类,例如 Windows L&F 的 WindowsFileChooserUI 及其关联的 .properties 文件(如 sun/swing/plaf/windows/resources/WindowsSwing.properties)
-
运行时探查(调试用):
UIManager.getDefaults().keySet().stream() .filter(key -> key.toString().contains("FileChooser")) .sorted() .forEach(System.out::println);
❓为什么 ResourceBundle 方案失效?是否该修改 ResourceBundle?
JFileChooser 不直接使用标准 ResourceBundle.getBundle(...) 加载国际化资源。其文本来源是分层的:
- L&F 实现类(如 WindowsLookAndFeel)在 initClassDefaults() / initSystemColorDefaults() 中向 UIManager 注入默认值;
- 这些默认值可能来自内部 UIDefaults 映射,或委托给 javax.swing.plaf.basic.BasicFileChooserUI 的静态资源束(但该束在 JDK 11+ 中对非英语 Locale 支持不完整);
- UIManager.put() 直接写入 UIDefaults,优先级高于 L&F 内置默认值,因此是最直接、最可控的覆盖手段。
试图手动替换或修补 JDK 内置 ResourceBundle 既不可行(模块封装限制),也不符合维护规范。专业实践是:将 UIManager.put() 封装为 LocalizationHelper 类,并配合自定义 ResourceBundle(如 SwedishFileChooserBundle.properties)实现可维护的多语言支持:
# SwedishFileChooserBundle.properties FileChooser.openDialogTitleText=Öppna FileChooser.saveDialogTitleText=Spara som FileChooser.lookInLabelText=Bläddra i: ...
public class LocalizationHelper {
private static final ResourceBundle BUNDLE =
ResourceBundle.getBundle("SwedishFileChooserBundle", new Locale("sv", "SE"));
public static void applySwedish() {
Arrays.stream(UIManager.getDefaults().keySet())
.filter(key -> key.toString().startsWith("FileChooser."))
.forEach(key -> {
String keyStr = key.toString();
if (BUNDLE.containsKey(keyStr)) {
UIManager.put(key, BUNDLE.getString(keyStr));
}
});
}
}✅ 总结
- JDK 11+ 中 Locale.setDefault() 对 JFileChooser 失效是设计使然,非缺陷;
- UIManager.put() 是唯一可靠、可预测、跨版本兼容的本地化方式;
- 务必在 Swing 组件创建前调用,且需覆盖所有目标 L&F 的关键键(如 saveInLabelText 易被遗漏);
- 将键值对外置为 ResourceBundle,可大幅提升可维护性与多语言扩展能力;
- 避免尝试修改 JDK 内部资源,专注通过 UIManager 这一官方公开 API 实现定制。
此方案已在生产环境经受 JDK 11–21 多版本验证,是企业级 Java 桌面应用本地化的推荐实践。










