Changing locale at runtime in Swing
-
03-07-2019 - |
Question
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?
Solution
You have a method that is used to change app locale (and probably persist the new value) and another one to get localized strings.
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()
.Now, have a list of listeners that will be notified on locale change by the first method.
OTHER TIPS
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.
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.
What about, on changing locale, do a firePropertyChangeEvent("locale", "..."), then add propertyChangeListener() and register them, whereever labels and the like are to be updated?
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.