Tuesday, March 27, 2007

Going International

I find rather amusing that, despite English not being my first language, I never really bothered looking into how to write software (and, in particular GUI components) using anything else than (tortured) English.

Entirely by chance, yesterday I eventually looked into "Resource Bundles" that allow one to easily create an application in Java that will be, one would hope, easier to distribute in several languages.

Here's how it works.

The basis of all this are "resource bundles" - in practice, simple properties files that have a list of mnemonics (eg, "s1", "file_not_found", "ad2234", etc.) and the corresponding string as the value ("Please don't click here", "File not found", etc.)
Let's call this file `messages.properties`

So far, so good.
The real beauty comes into play, in the simplicity of using a different Locale (eg, Italian) for a particular distribution. To achieve that, one creates an identical file (called `messages_it.properties`) with the same keys, and their equivalent values in the destination language ("Per favore, non cliccare qui", "File non trovato", "Buonanotte ai suonatori", etc. etc.)

In the application code, the selection as to which one to load is delegated to

ResourceBundle.getBundle("bundles.messages", new Locale(lang));

where `lang` could be `null` (in which cause the user's default locale would be used) or it could be a String with values such as `it`, `en_US`, `de_CH` and so on.

Please note that the .properties files MUST be saved inside a package within the classpath (I prefer to use something along the lines of `bundles` (as in the example above) but anything would do, really.

(so calling ResourceBundle.getBundle("com.ibw.utils.complex.package.name.if.you.wish.messages", "ru"); would work just as well - just make sure you save the properties files in the appropriate folder - and, yes. please do consult a mental health professional).

Were this not simple enough, NetBeans (don't you just love the Sun folks and the NetBeans community in general? thanks for being here folks!) makes it even easier.

Just right-click on a project and choose "Create new package" (if a suitable one isn't there yet) and then right-click on the package and choose "New/Properties file..." choose whathever name takes your fancy (eg, `system_messages`) and bob's your uncle the default resource bundle is created and opened in the editor.

The default properties file will look something like (example taken from the Javadoc API, here):

s1=The disk \"{1}\" contains {0}.
s3=My disk
s4=no files
s5=one file
s6={0,number} files
s7=3 Mar 1996

Then, let's say you want to create the Italian version, it's simply a matter of right-clicking on the properties file and selecting "Add Locale," either choosing from the list a 'pre-cooked' language/country/variant or choosing freely from the drop-down lists.

You will, of course, have to supply the Italian version of the various messages, like in:

s1=Il disco \"{1}\" contiene {0}.
s3=Il mio disco
s4=nessun file
s5=un file
s6={0,number} files
s7=3 Marzo 1996

but then choosing which locale to use in your code will be as simple as:

public static void main(String[] args) {

String lang = null;
PropertyResourceBundle messages;
if (args.length > 0) {
lang = args[0];
messages = (PropertyResourceBundle)
("bundles.messages", new Locale(lang));
} else
messages = (PropertyResourceBundle)

String s1 = messages.getString("s1");

System.out.println("Given language: "+
(lang==null? "default":lang)+
"\tThe message is: "+s1);

Depending on how you run it (say, java MyApp it) the output will be in the chosen locale.

Now, say you want to use this in a practical GUI (Swing) app, you face the problem that the text label on, say, a button, is defined in the generated code and NetBeans won't let you edit it.

In fact, it is quite easy to use a Resource Bundle here, and in fact, it's actually easier than hand-crafting the code.

After creating a button the usual way in the Swing layout editor, look at the "Properties" pane (it is usually bottom right): there is a 'text' property (in bold) that you can customise (by typing directly in the edit control): if you instead click on the "..." button on the right, it will open a dialog window, where you can select from a drop-down list, "Resource Bundle".

At this stage it's just a matter of entering the fully qualified name of the bundle (bundles.messages) and choosing whichever key identifies the text you want to appear on the button (eg, `s3').

You will see in the "Replace string:" box (which you can't directly edit) the code that NetBeans will generate to replace the text in the button and, when deployed in a locale for which you have provided a bundle, it will use as the text the appropriate entry.

Piece of cake, uh?

No comments:

Post a Comment