Resource Bundles in Java

When localizing an application, you’ll probably have a dauntingly large number of message strings, button labels, and so on, that all need to be translated. To make this task feasible, you’ll want to define the message strings in an external location, usually called a resource. The person carrying out the translation can then simply edit the resource files without having to touch the source code of the program.

In Java, you can use property files to specify string resources, and you can implement classes for resources of other types.

1. Locating Resource Bundles

When localizing an application, you produce a set of resource bundles. Each bundle is a property file or a class that describes locale-specific items (such as messages, labels, and so on). For each bundle, you have to provide versions for all locales that you want to support.

You need to use a specific naming convention for these bundles. For example, resources specific to Germany go into a file baseNamedeDE, whereas those shared by all German-speaking countries go into baseNamede. In general, use

baseName_language_country

for all country-specific resources, and

baseName_language

for all language-specific resources. Finally, as a fallback, you can put defaults into a file without any suffix.

To load a bundle, use the command

ResourceBundte currentResources = ResourceBundle.getBundle(baseName, currentLocale);

The getBundle method attempts to load the bundle that matches the current locale by language and country. If it is not successful, the country and the language are dropped in turn. Then the same search is applied to the default locale, and, finally, the default bundle file is consulted. If even that attempt fails, the method throws a MissingResourceException.

That is, the getBundle method tries to load the following bundles:

baseName_currentLocaleLanguage_currentLocaleCountry

baseName_currentLocaleLanguage

baseName_currentLocaleLanguage_defaultLocaleCountry

baseName_defaultLocaleLanguage

baseName

Once the getBundle method has located a bundle (say, baseName_de_DE), it will still keep looking for baseName_de and baseName. If these bundles exist, they become the parents of the baseName _de_DE bundle in a resource hierarchy. Later, when looking up a resource, the parents are searched if a lookup was not successful in the current bundle. That is, if a particular resource was not found in baseName_de_DE, then the baseName_de and baseName will be queried as well.

This is clearly a very useful service—and one that would be tedious to program by hand. The resource bundle mechanism of the Java programming language automatically locates the items that are the best match for a given locale. It is easy to add more and more localizations to an existing program—all you have to do is create additional resource bundles.

2. Property Files

Internationalizing strings is quite straightforward. You place all your strings into a property file such as MyProgramStrings.properties. This is simply a text file with one key/value pair per line. A typical file would look like this:

computeButton=Rechnen

colorName=black

defaultPaperSize=210×297

Then you name your property files as described in the preceding section, for example:

MyProgramStrings.properties

MyProgramStrings_en.properties

MyProgramStrings_de_DE.properties

You can load the bundle simply as

ResourceBundle bundle = ResourceBundle.getBundle(“MyProgramStrings”, locale);

To look up a specific string, call

String computeButtonLabel = bundle.getString(“computeButton”);

3. Bundle Classes

To provide resources that are not strings, define classes that extend the ResourceBundle class. Use the standard naming convention to name your classes, for example

MyProgramResources.java

MyProgramResources_en.java

MyProgramResources_de_DE.java

Load the class with the same getBundle method that you use to load a property file:

ResourceBundle bundle = ResourceBundle.getBundle(“MyProgramResources”, locale);

Each resource bundle class implements a lookup table. You need to provide a key string for each setting you want to localize, and use that key string to retrieve the setting. For example,

var backgroundCotor = (Color) bundle.getObject(“backgroundColor”);

double)] paperSize = (double]]) bundle.getObject(“defaultPaperSize”);

The simplest way to implement resource bundle classes is to extend the ListResourceBundle class. The ListResourceBundle lets you place all your resources into an object array and then does the lookup for you. Follow this code outline:

public class baseName language country extends ListResourceBundle

{

private static final Object]]]] contents =

{

{ key 1, value2 },

{ key2, value2 },

}

public Object]]]] getContents() { return contents; }

}

For example,

public class ProgramResources_de extends ListResourceBundle

{

private static final Object]]]] contents =

{

{ “backgroundColor”, Color.black },

{ “defaultPaperSize”, new double]] { 210, 297 } }

}

public Object]]]] getContents() { return contents; }

}

public class ProgramResources_en_US extends ListResourceBundle

{

private static final Object]]]] contents =

{

{ “backgroundColor”, Color.blue },

{ “defaultPaperSize”, new double]] { 216, 279 } }

}

public Object]]]] getContents() { return contents; }

}

Alternatively, your resource bundle classes can extend the ResourceBundte class. Then you need to implement two methods, to enumerate all keys and to look up the value for a given key:

Enumeration<String> getKeys()

Object handteGetObject(String key)

The getObject method of the ResourceBundte class calls the handteGetObject method that you supply.

Source: Horstmann Cay S. (2019), Core Java. Volume II – Advanced Features, Pearson; 11th edition.

Leave a Reply

Your email address will not be published. Required fields are marked *