我认为这是关于处理动态翻译的一个相当普遍的问题。
一般来说,我知道三种方法可以做到这一点。
- 应用程序中设置的每个标签或文本都必须为您在语言更改时发出的事件注册一个侦听器。在侦听器中,您将读取新的语言环境并从包中加载正确的字符串。
- 从窗口向下遍历组件层次结构并翻译途中找到的所有文本。
- 以编程方式设置其他语言环境,然后销毁并重新创建 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;
}
}