0

我正在创建一个原型应用程序,它应该支持日语语言环境和英语语言环境。应该有 Menuitem 来选择日语或英语。因此,应用程序应该以日文或英文显示所有它的标签按钮文本。

我使用 Netbeans 国际化支持进行开发。如果我将 VM 参数作为 -Duser.language=ja -Duser.country=JP 传递,应用程序会在标签和按钮等上显示日语文本。

如果我将 VM 参数作为 -Duser.language=en -Duser.country=IN 传递,应用程序会在标签和按钮等上显示英文文本。

这很好用。但是如何使它动态化。这样就无需使用 VM 参数重新启动应用程序。

4

1 回答 1

0

我认为这是关于处理动态翻译的一个相当普遍的问题。

一般来说,我知道三种方法可以做到这一点。

  1. 应用程序中设置的每个标签或文本都必须为您在语言更改时发出的事件注册一个侦听器。在侦听器中,您将读取新的语言环境并从包中加载正确的字符串。
  2. 从窗口向下遍历组件层次结构并翻译途中找到的所有文本。
  3. 以编程方式设置其他语言环境,然后销毁并重新创建 GUI。

说起来可能很悲哀,但所有这些选项都需要对程序代码进行一般性且相当大的更改。

其中,我更喜欢 1. 我实际上已经编写了一些组件,例如 JLocalizedLabel,将标签作为 LocalizedString 的实例而不是 String 接收标签。有了这个,你甚至不需要事件监听器,重新绘制组件就足够了,更改就完成了。但是这种方式只适用于按钮或标签上的主要文本,而对于工具提示文本等,您仍然需要事件侦听器。

这就是它的样子(只是一个例子):

public class JLocalizedLabel extends JLabel
{
   /** The localized string to display. */
   protected LocalizedString              string;

    public JLocalizedLabel(LocalizedString string, Icon icon, int horizontalAlignment)
    {
        super(string.toString(), icon, horizontalAlignment);
        this.string = string;
    }

    @Override
    public String getText()
    {
        if (string == null)
            return "";
        return string.toString();
    }

    @Override
    public void setText(String text)
    {
    }

}

和 LocalizedString 类:

public class LocalizedString
{

    /** The key to search for in the resource bundle. */
    protected String                                 key;
    /** The cached text to display. */
    protected String                                 text;
    /** The name of the resource bundle to use. */
    protected String                                 bundleName;
    /** The cache of resource bundles for the active locale. */
    private static Hashtable<String, ResourceBundle> bundles = new Hashtable<String, ResourceBundle>();
    /** The cached application locale. */
    private static Locale                            locale  = /* get the current locale */

    static {
        //install the locale change listener
        ServiceLocator.get(ConfigurationManager.class).get()
                .addPropertyChangeListener("locale", new PropertyChangeListener() {
                    @Override
                    public void propertyChange(PropertyChangeEvent evt)
                    {
                        bundles.clear();
                        locale = (Locale) evt.getNewValue();
                    }
                });
    }

    /**
     * Create a localized string by reading <code>key</code> from a resource bundle with name <code>name</code>.
     * 
     * @param bundleName The name of the resource bundle (the bundle will be retrieved by calling
     *            <code>ResourceBundle.getBundle(bundleName, locale)</code>)
     * @param key The key to search for in the resource bundle.
     */
    public LocalizedString(String bundleName, String key)
    {
        this.key = key;
        this.bundleName = bundleName;
        updateText();
        installLocaleListener();
    }

    /**
     * The locale has changed, so reload the text from the bundle.
     */
    protected void updateText()
    {
        try {
            text = getBundle().getString(key);
        } catch (MissingResourceException e) {
            text = "";
        }
    }

    /**
     * @return The resource bundle associated with this localized string in the current locale.
     */
    protected ResourceBundle getBundle()
    {
        if (bundles.get(bundleName) == null) {
            bundles.put(bundleName, ResourceBundle.getBundle(bundleName, locale));
        }
        return bundles.get(bundleName);
    }

    /**
     * Return the currently active locale.
     * 
     * You can override this in child classes to reflect another locale. Then you should also override
     * {@link #installLocaleListener()}.
     * 
     * @return The currently active locale.
     */
    protected Locale getLocale()
    {
        return locale;
    }

    /**
     * Add a listener to the active configuration that will call {@link #updateText()} every time the locale has
     * changed.
     * 
     * You can override this in child classes to reflect another locale. Then you should also override
     * {@link #getLocale()} .
     */
    protected void installLocaleListener()
    {
        ServiceLocator.get(ConfigurationManager.class).get()
                .addPropertyChangeListener("locale", new PropertyChangeListener() {
                    @Override
                    public void propertyChange(PropertyChangeEvent evt)
                    {
                        updateText();
                    }
                });
    }

    @Override
    public String toString()
    {
        return text;
    }
}
于 2013-09-24T12:49:46.000 回答