Tell me more ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

(Already posted here: http://stackoverflow.com/q/11298080/1469540)

I thought about the best way to implement localisation with runtime in Swing. Currently I solve the problem like that:

JMenu menuData = new JMenu("Data");
    menuData.setName("mainframe.menu.data"); // property key
    localeChangedListener.add(menuData);

The LocaleChangedListener:

public class SwingLocaleChangedListener implements LocaleChangedListener {

private ArrayList<AbstractButton>   abstractButtons;

@Override
public void localeChanged(ResourceBundle rb) {
    logger.info("Locale changed to '" + rb.getLocale() + "'");
    for (AbstractButton b : abstractButtons) {
        b.setText(rb.getString(b.getName()));
        b.setComponentOrientation(ComponentOrientation.getOrientation(rb.getLocale())); //EDIT: Line added
    }

}

public boolean add(AbstractButton b) {
    initAbstractButtons();
    return abstractButtons.add(b);
}

private void initAbstractButtons() {
    if (abstractButtons == null) {
        this.abstractButtons = new ArrayList<AbstractButton>();
    }
}

}

And the registration of the Listener:

public class GuiBundleManager {

private String                  filePrefix  = "language.lang";
private ResourceBundle          rb         = null;
private LocaleChangedListener   listener    = null;

private static GuiBundleManager instance    = null;

private GuiBundleManager() { 
    setLocale(Locale.getDefault());
}

public String getString(String key) {
    return rb.getString(key);
}

public String[] getStringArray(String key) {
    return rb.getStringArray(key);
}

public Locale getLocale() {
    return rb.getLocale();
}

public void setLocale(Locale l) {
    rb = ResourceBundle.getBundle(filePrefix, l);
    if (listener != null) {
        listener.localeChanged(rb);
    }

}

public LocaleChangedListener getLocaleChangedListener() {
    return listener;
}

public void setLocaleChangedListener(LocaleChangedListener listener) {
    this.listener = listener;
    if (listener != null) {
        listener.localeChanged(rb);
    }
}

public static GuiBundleManager get() {
    if (instance == null) {
        instance = new GuiBundleManager();
    }
    return instance;
}
}

. . An other way I'm thinking of is using Component.setLocale() combined with an PropertyChangedListener:

public abstract class GUIComponentFactory {

public JLabel createLocalisedJLabel(final String key) {
    final JLabel label = new JLabel(GuiBundleManager.get().getString(key));
    label.addPropertyChangeListener("locale", new PropertyChangeListener() {

        @Override
        public void propertyChange(PropertyChangeEvent e) {
            label.setText(GuiBundleManager.get().getString(key));
            label.setComponentOrientation(ComponentOrientation.getOrientation(e.getNewValue())); //Edit: Line added
            for(Component c : getComponents()){
                c.setLocale(e.getNewValue());
            }
        }
    });
            return label;

}
.
.
.

}

Maybe you have a better solution

share|improve this question

2 Answers

Consider applyComponentOrientation(), which recursively "Sets the ComponentOrientation property of this component and all components contained within it." Examples may be found here.

share|improve this answer
Thanks, I edited the code – niccomatik Jul 2 '12 at 20:21
I think I'll implement the PropertyChangedListener structure. This way seems more flexible to me – niccomatik Jul 3 '12 at 18:39
Agree; it's included in every Component. Do you have any i18n plans? – trashgod Jul 3 '12 at 19:29
I have a method in GuiBundleManager that list all locates with existing properties File (and you can change at runtime) - is this what you mean? – niccomatik Jul 3 '12 at 19:40
Yes; skimmed right past it! :-) – trashgod Jul 3 '12 at 19:42

Whatever approach you finally decide upon: you don't have to handle the resourceBundles yourself. Instead, add them to the UIManager and query that for the localized values:

// edited: it's the defaults which take the bundle, my bad I didn't check core api
// SwingX has a UIManagerExt which takes it directly :-)
UIManager.getDefaults().addResourceBundle("com.xypackage.resources.MyBundle");
...
label.setText(UIManager.get(key, label.getLocale());

There used to be (didn't check if it's fixed) a bug which prevented this to work reliably in webstartables.

share|improve this answer
UIManager.addResourceBundle() does not exist in my Java version (1.7) |||| but UIManager.getDefaults().addResourceBundle(bundleName) does – niccomatik Jul 5 '12 at 10:59
And this is also a problem: public Object get(Object key, Locale l) { Object value = getFromHashtable( key ); return (value != null) ? value : getFromResourceBundle(key, l); } – niccomatik Jul 5 '12 at 11:13
this means that it only returns the message of the first .properties and ignores the given Locale – niccomatik Jul 5 '12 at 11:21
darn, you are right with your first comment (will edit). Don't understand your conclusion: the lookup will return the most fitting value for the given locale, falling down from the most specific to the base. – kleopatra Jul 5 '12 at 11:48
UIManager.get(key, Locale.GERMAN) and UIManager.get(key, Locale.ENGLISH) return the same value (the German one) – niccomatik Jul 5 '12 at 12:50
show 2 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.