Wizard API updated!
Tim Boudreau has released a new version of the Swing Wizard library (version 0.997) that fixes the WizardException bug reported in JavaWorld's recent Open Source Java Project profile. The article's examples have been reworked to test out the new, improved WizardException. Thanks, Tim, for this helpful fix!
Open Source Java Projects: The Wizard API

Newsletter sign-up

Sign up for our technology specific newsletters.

Enterprise Java
View all newsletters

Email Address:

Localize this!

Use resource bundles to make your applications multicultural

For you to better understand how we're going to internationalize our application's text, including button labels, label text, and error messages, we need to look closely at what went on last month. Here's what happened from the application's point of view:

  1. The application started with a piece of data, such as an instance of the Date class, stored in some locale-neutral form.

  2. The application created an instance of the proper formatter, such as DateFormat, from the java.text package.

  3. Behind the scenes, the application queried the runtime in order to determine the locale in which the application was running. This likely involved some interaction with the operating system.

  4. Based on the information it received, the application determined how to format the date for the locale, given that the locale was supported.

  5. The application then formatted the date and created a string.

  6. Finally, the application displayed the string.



Steps 3 through 5 were hidden from view. The DateFormat and the NumberFormat classes did the work behind the scenes. (If you'd like more detailed information, take a look at last month's column.) This month, let's take a closer look at step 4.

Because the programmers at Sun wrote the code for the DateFormat and the NumberFormat classes, they were responsible for deciding which locales to support and for providing the code to perform the appropriate data conversions for those particular locales. Because there are only so many variations on dates and numbers, they were able to build the necessary code for formatting data in the Number and Date classes, according to the appropriate locale, directly into the Java library.

That saved us a lot of work!

Unfortunately, such forward planning and implementation isn't quite so easy when it comes to text messages. The developers at Sun could not possibly anticipate all the different text messages used by each application (current and future) and provide the appropriate translations; they left that task to individual developers. It is, therefore, up to us to decide which locales we intend to support and provide translations of our messages for each. In short, the work for step 4 now falls squarely on our shoulders.

Locale

Before we can proceed, we really need to better understand the notion of a locale, and its associated Java class Locale.

A locale is a loose term for a specific geographical, political, or cultural region. It's best defined by example. The region of origin of a group of people can often be surmised by the language they speak. Therefore, as you might also guess, language is an important component of locale. So too is nationality. Even though Americans and the British share a common tongue, we each possess our own customs and cultural identity. Thus, each region is its own locale.

In the Java programming language, a locale is represented by an instance of class Locale. An instance of Locale can be created for any language and any country. The Locale class also provides several predefined values for common countries (US and CANADA, for example) and languages (ENGLISH and FRENCH for example).

Operations that can be localized (formatting a date, for example) usually take a Locale instance as an argument. If it is not specified, the argument defaults to the current locale.

Resource bundles

Now let's return to our problem.

To completely internationalize our application, we'll need to gather a collection of strings appropriate for a locale and use them in appropriate places throughout the application. In order to assist us, the Java class library provides resource bundles.

A resource bundle is a collection of all resources and information for a specific locale. It associates each resource with a key, and the key is the same for each particular resource across all locales. In addition, due to the way resource bundles are named (explained below), they provide an orderly, effective way of locating the correct resource bundle.

Let's take a look at a concrete example. Recall that last month's example had five buttons: previous, next, new, add, and delete.

The Record Manager buttons

Each button has a label that indicates its function. Obviously, the labels should be in the appropriate language for the current locale. Therefore, for each locale I plan to support, I create a resource bundle containing the labels of each button, appropriately translated. Each resource bundle has five key/value pairs. The keys are the same across all bundles, while the values change to suit the locale. A key can hold any string. It is usually something significant to the programmer ("btn1," "btnPrevious," or "previous").

Consider the button bundle for my locale (the United States of America). The following table shows the keys and values for this bundle.

Key Value


btnPrevious "previous"


btnNext "next"


btnNew "new"


btnAdd "add"


btnDelete "delete"


Bundles and bundles of fun

A set of bundles (all the bundles that hold labels for the buttons in our application, for example) all belong to a group. The group has a name, often referred to as the "bundle name." Likewise, each bundle in the group of bundles has a name. The names are constructed in a uniform fashion: the bundle name plus the language, the country (optional), and the variant (a variant is a subregion within a country -- it's optional as well). One bundle has the same name as the group itself. This is the default bundle, and is the one selected if no other bundle is more appropriate.

This naming scheme is not as difficult as it sounds, but I think an example will help. Assume we have a group of bundles that hold the labels of the buttons in our application. The bundle name of the group is something like "ButtonLabels." At the very least, there would be one bundle -- the one with the name "ButtonLabels." If there was a specific bundle holding labels for francophones (French speakers), it would be named "ButtonLabels_fr" (note the underscore). If there was a specific bundle holding labels for French speaking Canadians, it would be named "ButtonLabels_fr_CA". I'll explain what the two letter abbreviations mean and how they're used in a moment. Likewise, for those who speak Japanese, "ButtonLabels_JP". If there was a specific bundle holding labels for the English speakers of Great Britain, it would be named "ButtonLabels_en_GB".

1 | 2 | 3 | 4 |  Next >
Resources
  • The internationalization specification http://java.sun.com/products/JDK/1.1/intl/html/intlspecTOC.doc.html
  • The Locale class http://www.javasoft.com/products/jdk/1.1/docs/api/java.util.Locale.html
  • The ResourceBundle class http://www.javasoft.com/products/jdk/1.1/docs/api/java.util.ResourceBundle.html
  • The ListResourceBundle class http://www.javasoft.com/products/jdk/1.1/docs/api/java.util.ListResourceBundle.html
  • The PropertyResourceBunlde class http://www.javasoft.com/products/jdk/1.1/docs/api/java.util.PropertyResourceBundle.html
  • ISO-639 http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt
  • ISO-3166 http://www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html
  • Download this article and the complete source as a gzipped tar file /javaworld/jw-01-1998/howto/jw-01-howto.tar.gz
  • Download this article and the complete source as a zip file /javaworld/jw-01-1998/howto/jw-01-howto.zip
  • Previous How-To Java articles