문제

What would be the best practice for sharing localization object (in this case ResourceBundle, where I do save all translations) across many GUI objects in app? I have few ideas, but both have drawbacks:

1) passing ResourceBundle via each GUI class constructor, but then I need to save it inside every class (for later use) - means having the same code in each class over and over again

2) declare ResourceBundle as public static (but not final, because I may need to change it - e.g. language changed) in main GUI class (e.g. "public static ResourceBundle msg") , then later access it always via it (e.g. calling MainGuiClass.msg.getString("something")), but then it can also be modified/destroyed by any other GUI class in the same package...

Maybe there is some better practice to do the sharing?

Thanks.

도움이 되었습니까?

해결책

The global ResourceBundle Object can not be final but instead should be cached in a Map. Changing the language doesn't require to change this reference:

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;

public class UIBundle {
    private static final Map<Locale, ResourceBundle> allUIResources = new HashMap<Locale, ResourceBundle>();

    public static String getString(final String key) {
        return getString(key, Locale.getDefault());
    }

    public static String getString(final String key, final Locale locale) {
        ResourceBundle rb = allUIResources.get(locale);
        if (rb == null) {
            rb = ResourceBundle.getBundle("my-ui-resource", locale);
            allUIResources.put(locale, rb);
        }
        return rb.getString(key);
    }

}

With this code you can either access texts in specific languages/locales or just use the default locale. If you want to switch your locale, just set the default locale. Your UI needs to know about locale changes, so you may have to introduce some listener interface for all your UI components (PropertyChangeListener, PropertyChangeSupport) and not change the locale directly.

다른 팁

You could implement a caching factory, which returns the ResourceBundle based on the value of an input locale parameter. Upon the first call the ResourceBundle will be constructed and then cached in a static reference, which can subsequently be returned and reused in later calls to the factory.

If you are concerned about other classes doing things you do not want to an object, make it a protected/private field of a class which has the methods you want to be performed on it.

Globals are evil, but sometimes their convenience is greater than their evilness.

The class ResourceBundle implements already a cache, so there is no need to implement caching yourself. Your access class can be implemented as singleton. To switch the language I use a ThreadLocal for the locale:

public final class ThreadLocale extends ThreadLocal<Locale>
{
    public static final ThreadLocale theInstance = new ThreadLocale ();

    private ThreadLocale () 
    {
        super ();
    }

    protected Locale initialValue()
    {
        return Locale.getDefault ();
    }
}

In the method of the access class, which gets the text from the resource bundle I use the current thread locale:

public synchronized String getMessage (Object messageKey, Locale locale) throws MissingResourceException
{
    ResourceBundle resourceBundle = null;
    resourceBundle = ResourceBundle.getBundle (filename, ThreadLocale.theInstance.get ());
    return resourceBundle.getString (messageKey.toString ());
}

So you can set a locale for each thread and not globally.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top