Tuesday, November 9, 2010

Internationalization in Java

Internationalization means developing your application in such a way so that people from different countries who speak different languages can still use your program. For example, a French user, when presented with a "Yes/No" dialog, should instead be shown a "Oui/Non" dialog. The term "internationalization" is often abbreviated to "i18n". The "18" represents the eighteen letters between the first and last letters of the word.

Java provides a very nice way of doing this. It involves putting all of the text that your application uses into .properties files, which reside somewhere on the classpath. Each translation has its own .properties file and is named according to the language and (optionally) the country. For example, a German properties file would look like "messages_de.properties" ("de" being the standard, two-letter abbreviation for "German"). A British English properties file would look like "messages_en_UK.properties".

The properties files are organized in a hierarchy. This means that when searching for a particular string, the language/country file is looked for first (messages_en_UK.properties) followed by the language file (messages_en.properties) followed by the default file (messages.properties). One benefit to this is that if two translations are mostly the same (like US and UK translations), the parent file can contain most of the text, while the child files can define the differences. This helps to reduce duplication. It also allows for "fall-back" translations. For example, if there is no American English file, then it will use the English file.

To access these files in the Java code, the ResourceBundle class is used like so:

ResourceBundle messages = ResourceBundle.getBundle("com/example/messages");

In this example, the .properties files are located in the "com.example" package and have names that begin with "message". It finds the property with a name of "hello.world" and prints its value to the console.

To determine which language to use, the Java application looks at the default Locale, which is automatically set in every Java program. ResourceBundle uses the default Locale to determine which properties file to use. For example, a French user using your application will automatically be shown the French translation because his or her default locale is set to France. No extra work needs to be done by the application.

Additionally, you can add arguments to your property values. This allows you to customize a message at runtime.  For example, the following property contains two arguments:

hello.someone=Hello, {0}!  I'm {1} to see you!

To populate the arguments, you must use the MessageFormat class like so:

ResourceBundle messages = ResourceBundle.getBundle("com/example/messages");
String hello = messages.getString("hello.someone");
System.out.println(MessageFormat.format(hello, "Joe", "happy"));

The above code would print "Hello, Joe! I'm happy to see you!" to the console.


electronic seal said...

Internationalization is really very important when you expect your application to be used in multiple countries or when you are targeting multiple countries as your future market of some product. Java is really very powerful to easily enable you to achieve this

Michael Angstadt said...

It certainly is. It makes it easy to translate your application--all you have to do is send a single .properties file to a translator. You don't have to do any work in terms of putting together a list of text that needs translating.