Localizing Java Programs

Introduction

Though the terms are often used in different ways, and sometimes interchangeably, localization is the adaptation of a product to meet the requirements of a particular locale (including language and cultural differences) and internationalization is the design of a product that facilitates localization. Localization is often written as “l10n” and internationalization is often written as “i18n”.

The most common adaptations involve satisfying requirements involving the formatting of numbers, dates, times, addresses, and currencies, and the use of different terminology (often because of language differences) and symbology. This document is concerned with features of Java that facilitate localization.

Identifying a Locale

Java has a java.util.Locale class that encapsulates the identifying attributes of a locale. These attributes include a language (defined in ISO 639 ), a script or writing system (defined in ISO 15924 ), a country or region (defined in ISO 3166 ), and a variant (defined in IETF BCP47 ) like Canadian French or Swiss German.

When the Java Virtual Machine is started it determines the Locale of the processor it is running on. This information can be obtained from within a program using the java.util.Locale#getDefault() method.

Changing the Locale

The Java Virtual Machine can be provided with the information is should use to identify the Locale when it is started using the -Duser.country and -Duser.language options. For example, when executing an application named Test in the United States one could tell the JVM to use the Locale for Canadian French using the following virtual machine (VM) options:

-Duser.country=CA -Duser.language=fr

They can be passed to the VM from the command line when executing the java command. (Note: When using PowerShell, the arguments must be enclosed in double-quotes.) All IDEs also have a way of passing options to the VM (e.g., in Eclipse as part of the “VM arguments” in the“Arguments” tab of a “Run Configuration”; in jGRASP as “RUN Arguments”).

It is also possible to change the Locale inside of a program using the java.util.Locale#setDefault(java.util.Locale) method.

Localization of Terminology

Some people/companies approach the localization of terminology as a problem in machine translation but most use a simple mapping (and rely on human translators to do the hard work of translation). Java provides a java.util.ResourceBundle class for working which such mappings. To use it, one creates a file containing a mapping between keys (in the programmer’s language) and values (in the target language). Each key is, essentially, a String literal that appears in the user interface (e.g., “File”, “Open”, etc…). One mapping is created for each language, including the programmer’s language. The appropriate mapping is then loaded (based on the Locale) and is used everywhere a String literal would otherwise be used.

For example, one might create one file named Strings_en_US.properties in the calc.ui package containing the following:

Cancel = Cancel
File = File
Open = Open

and another named Strings_fr_FR.properties (in the same package) containing the following:

Cancel = Annuler
File = Fichier
Open = Ouvrir

Then, in the main class for the user interface one would load the mapping for the default Locale as follows:

 
public static final ResourceBundle STRINGS = 
  ResourceBundle.getBundle("calc.ui.Strings");

and use it as follows:

JButton cancelButton = new JButton(STRINGS.getString("Cancel"));
cancelButton.setActionCommand("Cancel");

Note that, one could use a Singleton rather than a visible static attribute however it is slightly inconvenient and it is unlikely that the additional flexibility it provides will be used (e.g., it is unlikely that one will need the ability to have more than one instance in the future). Note also that the static attribute need not have public visibility if it is only used in the same class or in the same package.

Formatting

Different locales have different formatting conventions involving numbers (e.g., what symbol to use between the one’s place and the one-tenth’s place, what symbol to use for groupings of places), dates (e.g., what order to use for the year, month and day), currencies (e.g., what currency symbol to use, whether the currency symbol appears before or after the amount), and other things.

Formatting Numbers

There are versions of the printf() method in the java.io.PrintStream class and and format() in the java.lang.String class that are a Locale object and use it to determine the appropriate formatting for numbers. The versions that are not passed a Locale simply call the versions that are, passing the default Locale. Hence, if one uses these methods one need not make any special accommodations to handle locales.

There is also a java.text.NumberFormat class that provides even more flexibility, though it is less convenient.

Formatting Currencies

The NumberFormat class has a static getCurrencyInstance() class that returns a NumberFormat object that will format currency information in a locale-specific way.

Formatting Dates and Times

The java.text.DateFormat class has a format() method that can be used to format dates in a variety of ways. It can be used to create SHORT, MEDIUM, LONG and FULL representations.

For More Information

More information is available from several sources on many topics, including: