How do I use locales and resource bundles to internationalize my application?
Author: Deron Eriksson
Description: This Java tutorial describes how to use locales and resource bundles to internationalize an application.
Tutorial created using: Windows XP || JDK 1.5.0_09 || Eclipse Web Tools Platform 2.0 (Eclipse 3.3.0)


This tutorial demonstrates how to use locales and resource bundles to internationalize a JavaSW application. We'll use a project with the following structure:

'testing' project

The ResourceBundle.getBundle() method allows us to get a set of properties from a .properties file by passing in the name of the bundle file (without its extension). We can also pass in a Locale object as a second parameter to get a resource bundle for a particular language in a particular country. In the project structure seen above, we have TestBundle.properties (default properties), TestBundle_en_US.properties (US English properties), and TestBundle_sv_SE.properties (Swedish properties). These bundles allow us to set our application to display different languages.

After getting a resource bundle, we can call getString() on the bundle with a property name to get the corresponding property value from the bundle.

To see some of the nuances involved with resource bundles and locales, I created the InternationalizationTest class.

InternationalizationTest.java

package test;

import java.util.Locale;
import java.util.ResourceBundle;

public class InternationalizationTest {

	public static void main(String[] args) throws Exception {

		ResourceBundle bundle1 = ResourceBundle.getBundle("TestBundle");
		displayValues(bundle1);

		Locale defaultLocale = Locale.getDefault();
		ResourceBundle bundle2 = ResourceBundle.getBundle("TestBundle", defaultLocale);
		displayValues(bundle2);

		Locale swedishLocale = new Locale("sv", "SE");
		ResourceBundle bundle3 = ResourceBundle.getBundle("TestBundle", swedishLocale);
		displayValues(bundle3);

		Locale nonexistentLocale = new Locale("xx", "XX");
		ResourceBundle bundle4 = ResourceBundle.getBundle("TestBundle", nonexistentLocale);
		displayValues(bundle4);

	}

	public static void displayValues(ResourceBundle bundle) {
		System.out.println("hello message:" + bundle.getString("my.hello"));
		System.out.println("goodbye message:" + bundle.getString("my.goodbye"));
		System.out.println("question message:" + bundle.getString("my.question"));
		System.out.println();
	}

}

InternationalizationTest gets four resource bundles and displays all the property values for each bundle. The first bundle is obtained by calling ResourceBundle.getBundle() with no locale specified. Next, we get the default locale and get the second bundle by including the default locale in the call to getBundle(). Next, we create a Swedish/Sweden locale and get the third bundle by calling getBundle() with the Swedish locale. Last of all, we create a locale with a language and a country that don't exist, and then call getBundle() with this locale.

The various properties files are shown here:

TestBundle.properties

my.hello=Hello (default)
my.goodbye=Bye (default)
my.question=Do you speak English? (default)

TestBundle_en_US.properties

my.hello=Hello
my.goodbye=Bye
my.question=Do you speak English?

TestBundle_sv_SE.properties

my.hello=Hejsan
my.goodbye=Hejd?
my.question=Pratar du engelska?

Executing InternationalizationTest on my machine generates the following results:

hello message:Hello
goodbye message:Bye
question message:Do you speak English?

hello message:Hello
goodbye message:Bye
question message:Do you speak English?

hello message:Hejsan
goodbye message:Hejdå
question message:Pratar du engelska?

hello message:Hello
goodbye message:Bye
question message:Do you speak English?

Notice that the #1, #2, and #4 bundles all use TestBundle_en_US.properties and the #3 bundle uses the TestBundle_sv_SE.properties. None of the bundles used TestBundle.properties. Even the bundle obtained with the nonexistent locale used TestBundle_en_US.properties.

Let's try changing the name of TestBundle_en_US.properties to NO_TestBundle_en_US.properties and re-run the InternationalizationTest class and see what happens.

changing name of TestBundle_en_US.properties to NO_TestBundle_en_US.properties

The execution of InternationalizationTest after this modification to the project is shown below.

hello message:Hello (default)
goodbye message:Bye (default)
question message:Do you speak English? (default)

hello message:Hello (default)
goodbye message:Bye (default)
question message:Do you speak English? (default)

hello message:Hejsan
goodbye message:Hejdå
question message:Pratar du engelska?

hello message:Hello (default)
goodbye message:Bye (default)
question message:Do you speak English? (default)

Now, the #1, #2, and #4 bundles use the TestBundle.properties since the TestBundle_en_US.properties file, which matches my default locale, can't be found. The #3 bundle returns Swedish results, as expected.