Internationalization Issues

From OpenDSA Active-eBook Project
Jump to: navigation, search

Contents

Internationalization Issues

Internationalization (usually contracted to I18N) addresses the need to provide a program in different languages - either regarding the user interface (i.e., the buttons, menu items etc.), the actual content being shown (i.e., text inside an animation), or both. This is usually "state of art" in modern applications - think of the different Office suites, browsers, operating systems, or simply your own mobile phone. The ability to switch the language at start-up or while the system is running is mainly achieved by cleanly separating the "ID of the element to be translated" and its actual translation in a given language (say, English).

The problem

If you are familiar with Hashing and Hash tables, the following will immediately sound familiar. In principle, wherever a language-specific element appears in the code - typically, as a String -, this is replaced by a reference to a "key" to the actual translation.

For example, to create a standard JButton, one would typically write code similar to the following, assuming all required elements have been imported:

JButton quitButton = new JButton("Quit");
quitButton.setMnemonic('q');
quitButton.setToolTipText("Exit the program");
quitButton.addActionListener(someListener);

However, this approach is bad when thinking about internationalization, since providing a (say) German version now requires us to modify the code (argh!). The relevant differences have been put in bold face:

JButton quitButton = new JButton("Beenden");
quitButton.setMnemonic('b');
quitButton.setToolTipText("Beendet das Programm");
quitButton.addActionListener(someListener);

As you can see, this means that several elements have to be changed: the English texts had to be replaced (predictably). We also have to change the "mnemonic" or keyboard short-cut to better fit the target language and translation. There is no "q" in the German Beenden, so Java would not visibly indicate this short-cut, making it either useless or "surprising": I was not aware that hitting ALT-q would end the program!!!. As you may have seen, you really should not want to "hard-wire" this into your code.

The standard solution

Instead, we separate the translation key from the translated contents, roughly as follows:

// assume that t is a "magic object" that provides a translation for entries for the target language
// e.g., in the most simplified case, a static instance or a HashSet
JButton quitButton = new JButton(t.getTranslationFor("quit"));
quitButton.setMnemonic(t.getTranslationFor("q").charAt(0));
quitButton.setToolTipText(t.getTranslationFor("quitMsg"));
quitButton.addActionListener(someListener);

The resources are then stored somewhere "in an appropriate place and an appropriate coding". For example, you might have a HashSet that contains the texts for German and another with the texts for English. t.getTranslationFor("x") would then look up the value (text) associated with the key (here, x), and use this for the encoding.

Java already provides support for most of this using the java.util.PropertyResourceBundle class and its brothers and sisters - or one can simply use a HashSet or similar data structure.

The improved solution

The above solution still contains a lot of hand-crafted code. For example, our button now consists of four lines of Java code, plus three resource entries (button label, mnemonic, and tool tip text). (In reality, those will usually be four entries, since the button may also display a graphical icon - and this may have to be replaced when the language is changed, as well.

This is achieved using the Translator package bundled with the Animal system. Here, the code looks as follows:

// assume that t is an instance of class translator.Translator, created for a given locale
// t.getGenerator() returns the GUI builder of the Translator
JButton quitButton = t.getGenerator().generateJButton("quit");
quitButton.addActionListener(someListener);

Associated with this is are the following resources, here for German:

quit.label=Beenden
quit.iconName=quit.gif
quit.mnemonic=b
quit.toolTipText=Beendet das Programm

And this is the English version, requiring absolutely no Java code change to work:

quit.label=Quit
quit.iconName=quit.gif
quit.mnemonic=q
quit.toolTipText=Ends the program

Why is the code so much shorter? Simply because the Translator package "knows" what a JButton is, and retrieves all relevant elements - the label, name of an optional icon, mnemonic, and tool tip text - from the resource. Thus, the end user has to type less code, and gets better functionality. (If you are wondering: you can also use placeholders, e.g. {0}, in translations to substitute elements at run-time, e.g. as in turning Hello, {0} {1} into Hello, Mr. Smith by calling something like t.translateMessage("hello", new String[]{"Mr.", "Smith"}) and using variables rather than hard-coded parameters).

Further Reading

The Translator "poster" gives a rough idea of how this works.

You can get a copy of the Internationalization library (for Java) from OpenAlgoViz.

Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox