Quick Tip 24: Changing the Language on the fly
This quick tip is a response to a question I found on NetBeans Zone by Jean-Claude Dauphin, author of the J-ISIS project from UNESCO. Sometimes you want to change the language of an application at runtime. This is especially useful in support. Unfortunately it’s not as easy as it could be, especially if you want to change the parts you don’t control, like menu items from the platform. Here are a few tricks & hacks that might serve as a starting point:
Most menuitems in the platform use this pattern for the getName method:
public String getName() {
return NbBundle.getMessage(SaveAction.class, “Save”);
}
That’s great, because it will work out of the box, when you simply change the locale like this:
Locale locale = new Locale(language, country);
Locale.setDefault(locale);
So you should always use the same pattern in your own actions for the getName method. But as always some actions are special… E.g. the Save as action in the file menu. Here’s an ugly hack you can use for it, since it’s the only Abstract Action in the System category :
AbstractAction instance = Lookups.forPath(”Actions/System”).lookup(AbstractAction.class);
instance.putValue(Action.NAME, NbBundle.getMessage(DataObject.class, “CTL_SaveAsAction”));
I wouldn’t recommend to do it like that though ;-). Another trick you can use is get the menubar and do whatever you want with the menuitems:
Frame main = WindowManager.getDefault().getMainWindow();
assert main != null;
if (main instanceof JFrame) {
Component[] comps = ((JFrame) main).getJMenuBar().getComponents();
for (int i = 0; i < comps.length; i++) {
if (!(comps[i] instanceof JMenu)) {
continue;
}
String name = ((JMenu) comps[i]).getText();
((JMenu) comps[i]).setText( name );// do something here
}
}
You can then walk the menu recursively, access the menuitems and do something with them. the problem with menus themselves is, that they also don’t respond to the changing of the Locale. You can change them manually as in the process shown above, but there’s a simpler way, you can force a refresh:
FileSystem sfs = Repository.getDefault().getDefaultFileSystem();
FileObject menus = sfs.findResource(”Menu”);
try {
FileObject[] children = menus.getChildren();
for (int i = 0; i < children.length; i++) {
FileObject fileObject = children[i];
FileLock lock = null;
try {
lock = fileObject.lock();
String oldname= fileObject.getName();
fileObject.rename(lock, “file”+1, null);
fileObject.rename(lock, oldname, null);
} catch (FileAlreadyLockedException es) {
es.printStackTrace();
}
lock.releaseLock();
}
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}



Couldn’t you also find the Bundle.properties file where the strings are found and then override them in the application’s ‘branding’ folder?
Comment by Geertjan
— 10. April 2009 @ 19:53
This only helps to brand an application, it doesn’t help when trying to change language while the application is already running…
Comment by Toni
— 10. April 2009 @ 21:16
But when would one want to do that? If you suddenly turn into a French person after you started the application as a Japanese person?
Comment by Geertjan
— 10. April 2009 @ 21:41
For support. E.g. if someone has a problem with an application rendered in a language or character set you can’t read and you would like to support him. Then it’s very useful being able to change the language while the application is running, so you can take over and work with it. I had this request from customers who create localizations in many languages including chinese.
Comment by Toni
— 11. April 2009 @ 07:08
Ah, now I get it. I think we should consider including a session on localization in our NetBeans Platform Certified Trainings. We could talk about NbBundle, about the Internationalization wizard, about the ‘branding’ folder, about putting localized texts in separate modules, etc etc.
Comment by Geertjan
— 11. April 2009 @ 11:04
Localization is extremely important. I do have a presentation on this, which I could contribute…
Comment by Toni
— 11. April 2009 @ 18:26
Hi Toni,
Thank you very much for this tip. The presentation on localization would be a great contribution.
I have a problem for displaying Tamil Text in a JTextPane with a document derived from DefaultStyledDocument.
Arabic is well displayed but Tamil gives boxes. I suppose it is a font problem, would you
have any idea how yo solve this pb
JCD
Comment by Jean-Claude Dauphin
— 13. May 2009 @ 10:35
I found it is not necessary to force a refresh, you can do it like this:
Frame main = WindowManager.getDefault().getMainWindow();
assert main != null;
if (main instanceof JFrame) {
Component[] cs = ((JFrame)main).getJMenuBar().getComponents();
for (Component c : cs) {
Runnable menu = (Runnable)c;
menu.run();
}
}
but in this way, you should localizing like this:
—— layer.xml ——–
…
—– Bundle.properties ——-
Menu/XXX=english menutitle
…
—– Bundle_zh_CN.properties ——-
Menu/XXX=chinese menutitle
…
Comment by ren
— 4. December 2009 @ 07:16
Why my last post display incomplete? I repost the “layer.xml” as following.
—— layer.xml ——
///
///
///
///
///
Comment by ren
— 4. December 2009 @ 08:03
Oh, no. It’s fail again…
In fact, in layer.xml, you need to set the localizing attribute for the menu folder which you want to translate.
(attr name=”SystemFileSystem.localizingBundle” stringvalue=”org.yours.module.Bundle”)
Comment by ren
— 4. December 2009 @ 08:13