21
votes

I would like to be able to change the locale in my Swing application at runtime and have all the text elements on the screen update themselves with localized text from a ResourceBundle of the new locale.

Can this be done without customizing swing components or creating UIDelegates for all components that handle rendering localized text?

If no, then what is a good solution I can consider implementing?

5

5 Answers

13
votes
  1. You have a method that is used to change app locale (and probably persist the new value) and another one to get localized strings.

  2. Create an interface:

    interface LocaleChangeListener {
        void onLocaleChange();
    }
    

    Implement it by UI components that need to be able to change locale at runtime and set the new values in overrides onLocaleChange().

  3. Now, have a list of listeners that will be notified on locale change by the first method.

17
votes

use ResourceBundle.getBundle(BUNDLE_NAME).getString(key); to access the Strings.

when updating the Default Locale e.g. via Locale.setDefault(Locale.GERMAN); clear the Resourcebundle cache: ResourceBundle.clearCache();

the next call of ResourceBundle.getBundle(BUNDLE_NAME).getString(key); should the return the localized String of the chosen Locale.

3
votes

You may want to save the language preference out, and then require a restart of the app for changes to take effect.

Then, you should be able to use Locale.setDefault(Locale.<desired language>); on startup, prior to rendering the GUI. That should properly switch your locale, which will result in the desired .properties file(s) being loaded.

0
votes

What about, on changing locale, do a firePropertyChangeEvent("locale", "..."), then add propertyChangeListener() and register them, whereever labels and the like are to be updated?

-1
votes

There's two obvious approaches I see:

Instead of getting a String from the ResourceBundle, get some kind of event-source String holder. Document would be the very heavy solution, but anything that can handle replacing an immutable value will do. Instead of just setting the text on a label, say, have a method that also sets up a listener. Note, this quite a "heavy" solution.

Alternatively, have a central repository of listeners that are fired on a locale change, that each then go back and re-execute the relevant part of the set up code (don't duplicate). For common cases where you have, say, a JLabel using a resource string literally, then you can combine these all into one listener with a WeakHashMap<JLabel,String>. Sometimes it works out better to avoid lots of little listeners.