如何在Java Swing中运行时更改语言

17

我尝试在我的Swing应用程序中运行时更改语言环境(Locale)。

但是我无法弄清楚它应该如何工作,或者是否有一个最佳方案?

我只能想到两个选择:

  1. 重新启动应用程序,不是最好的用户体验。
  2. 创建一个本地化管理器,可以注册/注销组件,在更改时只需迭代所有组件并更改文本。

1和2都感觉很尴尬。

其他信息:

  • 目前方向不是目标。
  • 应用程序被混淆。

示例:

LocRes_en.properties:

    text1 = 英文文本

LocRes_ja.properties:

    text1 = 日文文本

ChangeLocale.java:

    import java.awt.EventQueue;
    import java.awt.FlowLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.Locale;
    import java.util.ResourceBundle;
import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel;
public class ChangeLocale {
private JFrame frame;
public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { ChangeLocale window = new ChangeLocale(); window.frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); }
public ChangeLocale() { initialize(); }
private void initialize() { frame = new JFrame(); frame.setBounds(100, 100, 450, 300); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); FlowLayout flowLayout = new FlowLayout(FlowLayout.CENTER, 5, 5); frame.getContentPane().setLayout(flowLayout);
JButton btnChangeLoc = new JButton("更改语言"); frame.getContentPane().add(btnChangeLoc);
final JLabel lblLabel1 = new JLabel("新标签"); frame.getContentPane().add(lblLabel1); Locale.setDefault(new Locale("en")); ResourceBundle r = ResourceBundle.getBundle("LocRes"); lblLabel1.setText(r.getString("text1"));
btnChangeLoc.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Locale.setDefault(new Locale("ja"));```html
ResourceBundle r = ResourceBundle.getBundle("LocRes");
// 手动遍历所有组件 :(
lblLabel1.setText(r.getString("text1"));
//
}
});
}
}
```

从来没有需要过,但是一定有一些关于将属性加载到HashMap或List中的示例。 - mKorbel
4个回答

7
我已经使用ResourceBundles和EventBus实现了这个功能。
当语言环境发生变化时,EventBus会触发一个localeChangedEvent事件。所有有本地化字符串的JFrame窗口都需要订阅此事件。它们还必须实现一个changeLocale()方法,在接收到事件时执行该方法。
在这个方法中,所有字符串将被更新为当前的语言环境。
public void changeLocale(ResourceBundle rb) {
    lblLabel1.setText(rb.getString("text1"));
    lblLabel2.setText(rb.getString("text2"));
    ...
}

4

定义一个带有支持语言的下拉框的GUI。添加一个ItemListener,当下拉框改变时,更新文本内容。

LanguageGUIClient.java:

import javax.swing.*;

public class LanguageGUIClient
{
    public static void main(String[] arguments) throws Exception
    {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

        SwingUtilities.invokeLater(() ->
        {
            LanguageGUI languageGUI = new LanguageGUI();
            languageGUI.setVisible(true);
        });
    }
}

LanguageGUI.java:

import javax.swing.*;
import java.util.Locale;
import java.util.ResourceBundle;

public class LanguageGUI extends JFrame
{
    public static ResourceBundle resourceBundle;

    private JPanel rootPanel;
    private JComboBox<Locale> languageComboBox;
    private JLabel languageLabel;

    public LanguageGUI()
    {
        configureFrameProperties();
    }

    private void configureFrameProperties()
    {
        add(rootPanel);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        languageComboBox.addItem(Locale.US);
        languageComboBox.addItem(Locale.GERMANY);
        languageComboBox.addItem(Locale.FRANCE);
        setTexts();
        languageComboBox.addItemListener(itemEvent -> setTexts());
        setSize(300, 100);
    }

    private void setTexts()
    {
        Locale locale = languageComboBox.getItemAt(languageComboBox.getSelectedIndex());
        resourceBundle = ResourceBundle.getBundle("Bundle", locale);
        setTitle(resourceBundle.getString("application.title"));
        languageLabel.setText(resourceBundle.getString("language") + ":");
        languageComboBox.setToolTipText(resourceBundle.getString("language.tooltip"));
    }
}

请注意,我正在使用IntelliJ的表单设计器,因此.form文件内容也是必要的。
LanguageGUI.form:
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="LanguageGUI">
  <grid id="27dc6" binding="rootPanel" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
    <margin top="0" left="0" bottom="0" right="0"/>
    <constraints>
      <xy x="20" y="20" width="500" height="400"/>
    </constraints>
    <properties/>
    <border type="none"/>
    <children>
      <component id="eb651" class="javax.swing.JComboBox" binding="languageComboBox">
        <constraints>
          <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
        </constraints>
        <properties>
          <toolTipText value=""/>
        </properties>
      </component>
      <vspacer id="977c1">
        <constraints>
          <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
        </constraints>
      </vspacer>
      <component id="e59f" class="javax.swing.JLabel" binding="languageLabel">
        <constraints>
          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
        </constraints>
        <properties>
          <text value=""/>
        </properties>
      </component>
    </children>
  </grid>
</form>

此外,您需要在资源目录中创建相应的资源包文件: 结果是一个带有组合框的GUI界面,允许您立即更改语言:

不要忘记将“资源”文件夹添加到构建路径中(Eclipse:右键单击项目 - 属性 - Java构建器路径 - 源 - 添加文件夹),否则会出现java.util.MissingResourceException: Can't find bundle for base name Bundle, locale en_US异常。 - Neph

4

2

我曾经做过类似的事情,虽然我的任务比较简单:这是一个系统托盘应用程序,所以我只需要更改菜单项的文本。

但是在你的情况下,我认为这是可行的。首先,在GUI层中避免硬编码字符串。创建一个更改语言环境的类,然后迭代所有可见的框架并进入所有面板和组件并更改它们上面的文本。我唯一可能预料到的问题是画布上的文本。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接