views:

2806

answers:

3

What are the different ways of implementing multilingual support in Swing applications?

Are you using ResourceBundle with property file and implementing it in every frame? Does it work good for you? What if you use some kind of GUI editor? Is there any other way around?

At work we are using Matisse4MyEclipse and the code gets regenerated every time we save the screen, so simply using Externalize Strings won't work here. One way is to define it as custom property for each component, which is very annoying. Another way is to go over the multilanguage components and their properties again after matisse's generated code, which is a pain, too.

A: 

I don't know of any way besides ResourceBundle.

Why do you keep regenerating code? I would imagine that it would be fine once you got a page started, but after that it'd be largely unnecessary. Sounds like code generation is your real problem. It's not saving you anything.

Do you try to compose pages out of several Components? I can imagine a common header, footer, and menu that wouldn't have to change all the time. It could be a design issue.

Spring has very nice support for I18N. Maybe it can help you here.

duffymo
+1  A: 

This is how I implemented the internationalization :

  • give a name to every component which has an internationalized text
  • at runtime, take the container(frame, dialog, applet) ,iterate all the components and build an i18n key for every component using its name and all parent names.
  • for every component type(JTextField, JLable, etc) define some keys for every internationalize field(text, label, hint, etc).
  • take this i18n key and query your ResourceBundle, take the results and populate the component fields.

It works with generated code or with manual created code.

Edit: Here it is :

public void buildIds() {
    buildId(true);
    int count = getComponentCount();
    if (count == 0) {
        return;
    }
    for (int i = 0; i < count; i++) {
        Component component = getComponent(i);
        if (component instanceof AbstractComponent) {
            ((AbstractComponent) component).buildIds();
        }
    }
}

protected void buildId(boolean fireChange) {
    String prevId = this.id;
    String computedId;
    if (getName() == null) {
        computedId = ClassUtilities.shortClassName(getClass()).toLowerCase() + "_" + Long.toHexString(ID_GENERATOR.getAndIncrement());
    } else {
        java.util.List<Component> parents = null;
        Component parent = getParent();
        if (parent != null) {
            StringBuilder buider = new StringBuilder(80);
            parents = new ArrayList<Component>();
            while (parent != null) {
                if (parent.getName() != null) {
                    parents.add(parent);
                }
                parent = parent.getParent();
            }
            Collections.reverse(parents);
            if (parents.size() > 0) {
                for (Component component : parents) {
                    if (buider.length() > 0) {
                        buider.append('.');
                    }
                    buider.append(component.getName());
                }
                buider.append('.');
            }
            buider.append(name);
            computedId = buider.toString().toLowerCase();
        } else {
            computedId = name;
        }
    }
    this.id = computedId;
    if (fireChange && prevId != null && !prevId.equals(computedId)) {
        componentIdChanged(this, prevId);
    }
}
adrian.tarau
How do you assign name/key to every component?
Vitaly Polonetsky
adrian.tarau
Where do you store the info that userName key is bound to jTextfield1?
Vitaly Polonetsky
Well, in your case you don't/shouldn't store it. In my case is a little bit more complex because I use an abstraction of a UI model and by default this namespace is used to calculate a component id which is unique per application. Based on this id every component will query a I18n service to ask for internationalized text.If you just want to apply the same principle just iterate all components, create the id, query a ResourceBundle and discard the id since you don't need it.
adrian.tarau
We use abstraction level for UI components, too. How do you generate unique id for each component? Is it some kind of meaningless hash?
Vitaly Polonetsky
No, as I told you the id is generated based its name and all parents up to the root. Since I cannot post code as a comment I will post it as an answer.
adrian.tarau
+1  A: 
Rastislav Komara