Java Swing国际化-如何在运行时更新语言

Java Swing国际化-如何在运行时更新语言,java,swing,internationalization,Java,Swing,Internationalization,我已经跟随国际化我的应用程序。标签中显示的字符串现在存储在由“Externalize Strings”向导创建的属性文件中(我使用了经典的eclipse消息文件) 在myinitialize方法中,我的所有标签都已初始化,其文本设置如下: JLabel lblLanguage = new JLabel(Messages.getString("App.lblLanguage.text")); //$NON-NLS-1$ public void localeChanged(Lang lang) {

我已经跟随国际化我的应用程序。标签中显示的字符串现在存储在由“Externalize Strings”向导创建的属性文件中(我使用了经典的eclipse消息文件)

在my
initialize
方法中,我的所有标签都已初始化,其文本设置如下:

JLabel lblLanguage = new JLabel(Messages.getString("App.lblLanguage.text")); //$NON-NLS-1$
public void localeChanged(Lang lang) { nameLabel.setText(lang.getText("label.name")); submitButton.setText(lang.getText("button.submit")); etc... // I think on some screens I needed this to fix some quirky JTable/JTabbedPane layout issues: this.revalidate(); } 我在类
App
中创建了一个枚举类型,其中包含GUI:

private enum Lang { German(Locale.GERMAN), English(Locale.ENGLISH);

    private Locale loc;
    Lang (Locale l) {
        loc = l;
    }

    Locale getLocale() {
        return loc;
    }
}
将使用一个组合框设置语言,该组合框使用枚举类型Lang来显示可用的语言:

    JComboBox cboLanguage = new JComboBox();
    cboLanguage.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            JComboBox cb = (JComboBox)e.getSource();
            Lang l = (Lang)cb.getSelectedItem();
            // TODO: update language
        }
    });
    cboLanguage.setModel(new DefaultComboBoxModel(Lang.values()));

我已经找到了许多其他的howto和教程,它们涵盖了swing应用程序的国际化,但没有一个涵盖如何更新所有标签(以及可能包含文本的其他控件)。这里有一个链接,如果链接没有死掉的话,可能会有帮助。
因为我对java中的GUI编程有点陌生,我现在真的不知道该做什么,下面是我的问题:

  • 如果设置了新语言,那么在运行时更改所有控件的语言的最佳方法是什么
  • 是否可以(建议)将所有控件声明为my App类的私有成员,让一个方法更新它们的文本属性(->一个
    updateLanguage
    方法可以做到这一点)

当我这样做时,我也找不到一种内置的方法

所以我创建了自己的
LocaleChangeListener
接口。所有UI屏幕/面板都实现了这一点,并在我的中央UI控制器类上注册为侦听器。然后,每当语言发生变化时,就会向他们每个人发出
localeChanged(lang)
调用。 不过,我将组件初始化保持为单独的-不需要再次执行所有这些操作

他们只是有这样的代码:

JLabel lblLanguage = new JLabel(Messages.getString("App.lblLanguage.text")); //$NON-NLS-1$
public void localeChanged(Lang lang) { nameLabel.setText(lang.getText("label.name")); submitButton.setText(lang.getText("button.submit")); etc... // I think on some screens I needed this to fix some quirky JTable/JTabbedPane layout issues: this.revalidate(); } public void localeChanged(Lang Lang){ namelab.setText(lang.getText(“label.name”); submitButton.setText(lang.getText(“button.submit”); 等 //我认为在一些屏幕上,我需要这个来解决一些奇怪的JTable/JTabbedPane布局问题: 这个。重新验证(); }
由于用户不会经常更改语言,因此重新启动几乎是不可接受的。这样做的好处是,布局旧语言的工件不会损坏文本

这需要应用程序的可保存状态

一个JLabel
新的JLabel(Messages.getString(“App.lblLanguage.text”)立即计算为本地化文本,并且可能会按照该文本的宽度进行布局。所以这不适合动态的语言变化

另一种方法是依靠名称属性或反射来填充所有文本值。或代码:

JLabel lblLanguage = new JLabel();
Nls.setText(lblLanguage, "App.lblLanguage");

一些Nls.setText在一组中对lbl语言进行弱引用。

核心摆动中没有任何东西可以缓解疼痛。如果您使用某种支持资源注入的应用程序框架,比如f.i.(更好)SwingApplicationFramework,您可能会很高兴

假设所有文本都像往常一样在属性文件中声明,下面的代码段就是这样做的:

public static class ToggleLocaleAction extends AbstractAction {

    private boolean isAlternative;
    private SingleFrameApplication app;

    public ToggleLocaleAction(SingleFrameApplication app) {
        super("Locale");
        this.app = app;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // just toggling as an example
        Locale.setDefault(isAlternative ? Locale.GERMAN : Locale.ENGLISH);
        isAlternative = !isAlternative;
        injectResources(app);
    }

    public void injectResources(SingleFrameApplication app) {
        app.getContext().getResourceMap().injectComponents(app.getMainFrame());
    }
}
刚刚注意到一些小故障:

  • 不更新框架标题(可能是因为这不是beans属性)
  • 不更新操作文本(可能需要强制某些上下文操作更新,不确定)

我通过扩展JLabel并覆盖getText来返回对语言选择的评估来解决这个问题

您还需要一些发布/订阅机制来“告诉”标签语言已更改

我用的是这个

当用户更改语言时,您将触发事件:

JComboBox cboLanguage = new JComboBox();
cboLanguage.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        JComboBox cb = (JComboBox)e.getSource();
        Lang l = (Lang)cb.getSelectedItem();
        // this is the event fire
        ChangeEvent event = getChangeEvent(l);
        EventBusHolder.get().post(event);
    }
});
要使用的标签组件:

public class MyLabel extends JLabel {

    private static final long serialVersionUID = 1L;

    public MyLabel (String key) {
        super(key);
        // register this in event bus
        EventBusHolder.get().register(this);
    }

    @Override
    public String getText() {
        return Messages.getString(super.getText());
    }

    @Subscribe 
    public void recordCustomerChange(ChangeEvent e) {
        revalidate();
    }

}
在实例化标签时,必须传递转换键:

JLabel lbl = new JLabel("App.lblLanguage.text");

更多关于

的使用示例在大多数Sting值的更改不合适之后,我使用了there relayout whole Container Overriding getText实际上听起来是个好主意,尽管已经很久了,我甚至记不起我在哪个项目中遇到了这个特殊问题^^^但有一件事:您的类被称为“MyLabel”但是你的构造器是StudioLabel…是的,我以为你会找到一个解决方案。我提出这个答案是因为它可以为其他人服务。谢谢你的留言,我更正了名字。