Localization in Java

Localization, or internationalization, is important in most languages. What good is an application if it is restricted to your own country because you speak a far from widespread language? And as most languages, Java offers a mechanism to implement it quite easily. I will review here the basics, using Daily Tasks as an example.

The principle

How do you get to internationalize a program in Java? Basically, your program will call a key, and you have to provide a message for this key in each locale (language) you wish to have available in your application.

That is the main line of the theory. Let’s get our hands dirty!

Hands on

Defining your messages

To define your messages, you will use what looks like standard .properties files, called bundles. Each message will be associated to a key. You will have to define a default bundle (let’s call it Messages.properties), then one bundle for each language you want to be available in your application.

For instance, if you want to create an English bundle, it will be called Messages_en.properties. For a Great-Britain-specific version, you will call it Messages_en_GB.properties.

When looking for a message, Java will go to the closest looking locale, then go up and ultimately search them from the default bundle. Thus, with the previous bundles (default, en and en_GB), if you are using the locale en_US, Java will look for an exact match, but finding none, it will use en. If you are using fr, it will have to fall back to the default bundle.

If your message is not defined in the closest looking locale, Java will go a level up. In the end, it will look up the default bundle. If the message is not defined in the default locale, an exception will be thrown.

This is why in Daily Tasks, MessageBundle_en.properties is empty: I want it to show to know the English is an available locale, but all the English messages are stored in the default bundle.

One little trap you should probably be aware of: the bundle must be encoded with ISO-8859-1, not UTF-8. So now, you will have to define a message in your bundle. As easy as defining a property in a .properties file. Let us make a default English Messages.properties and a French Messages_fr.properties.

Calling your message in code

I made a utility class for handling the resources in my Daily Tasks application, but this is really easy actually.

You will have to use java.util.ResourceBundle and java.util.Locale.

First, you will need to define the locale you want to use (once again, you should read further if you want to know more about locales). Basically, it’s calling a simple constructor:

Let us imagine you have stored your bundles in the following package/directory org.keyboardplaying.example. To instantiate your bundle and retrieve your message, you would just need to do the following:

And you are good to go! You can now use this message anywhere in your application.

Going further

What is a Locale?

Basically, a locale is a language with a possible variant. It is written this way:

where:

Java has a list of valid locales, which changes with versions. If you need to know what are the locales available for you, here is a program snippet which can help you:

And here is the output for my current configuration (well I actually removed much of it, but you get one locale of each type, and it should suffice to give you a better idea of how it works on the whole):

Useless trivia

Do you know why internationalization is often shortened to i18n?

Well, it is quite a long word, and risks of misspelling are quite high. Both internationalization and i18n begin with an I and end with an N, but what is then the meaning of the 18? I would not have guessed, had not a colleague of mine explained to me: 18 is the length of the string nternationalizatio (that is, the number of characters between the beginning I and ending N. Shorter to write, no more spelling problems…

Published by

Cyrille Chopelet

Programming addict, UX philosopher, casual gamer, sci-fi enthusiast, hi-tech dilettante, ... Some people even call me a geek.

"Wit beyond measure is man's greatest treasure." − Rowena Ravenclaw