|
If you've developed global software, you know that one of the great commandments of internationalization is to separate text, labels, messages, and other locale-sensitive objects from the core source code. This helps to maintain a single source code base for all language versions of your product. It also facilitates translations because all localizable resources are identified and isolated. Depending on the operating system (OS) and programming language environments, developers can use a variety of mechanisms to identify and separate culturally sensitive or locale-dependent objects from their source code. Windows programmers have their resource (RC) files and resource-only dynamic link libraries (DLLs). Macintosh developers have their resource forks and similar concepts. Of course, Java developers have a method too--the resource bundle. This article explores the types, structure, creation, and usage of Java resource bundles. You'll learn how to use these files to create a localizable program. Resource Bundles
The most obvious type of localizable object is a text string, but resource
bundles can store any Java object. Whatever you choose to store, you'll
put it into some form of
To create a concrete class you must subclass What's in a Name?
For each language translation of your product, you create a new version
of your initial resource bundle. For example, if you create
Using the above example, the French version of the resources should
be named
Appending the locale name to the base name of the bundle effectively
links the bundle's usage to a specific locale. When you ask for the bundle
using
Actually,
The
So, use a concrete example this time. Suppose the default locale determined
from the operating system is en_US (U.S. English). However, you may want
to load
The search would end, of course, as soon as any bundle is found along
the way. If no bundle is found, Accessing Objects
All public final Object getObject(String key)
The
ResourceBundle res =
ResourceBundle.getBundle("MyResource");
String labelOK =
(String) res.getObject("OK_TEXT");
Casting the returned object is easy, but ResourceBundle provides a few convenience methods for returning common object types. Some examples follow: public final String getString(String key) public final String[] getStringArray(String key) These methods are convenient, but they don't do anything complex. If they save you some of the time or trouble necessary to cast the returned value, try them. The same code above becomes:
ResourceBundle res =
ResourceBundle.getBundle("MyResource");
String labelOK = res.getString("OK_TEXT");
Inheritance
Bundles can share the same <key, value> pairs if the bundles share the
same base name. For example, imagine you have created
The Figure 1 ResourceBundle Inheritance
ListResourceBundle
The
You can create your own
ListResourceBundle allows you to store any class of object. Notice the definition of CANCEL_BUTTON above. CANCEL_BUTTON is an AWT Button object that gets instantiated inside the resource bundle itself. Although value objects can be any type, keys are always a String object in both ListResourceBundle and PropertyResourceBundles.
ListResourceBundles are classes, so you store them in a PropertyResourceBundleA PropertyResourceBundle is definitely the easiest bundle to implement. It is nothing more than a text file. A PropertyResourceBundle can have multiple lines, and each line is either a comment, blank line, or a <key>=<value> entry. Property bundles should follow the same naming conventions as those used by a ListResourceBundle. However, the differences are that property bundles are not compiled and that they have a properties extension. So, the bundle below could be named MyResource.properties. The following example illustrates the structure and contents of the above resource bundle implemented as a property file:
Unfortunately, property files of this type have a limitation on the objects that can be stored. You are limited to storing String <value> entries. However, this limitation is tolerable, especially since there is a workaround. You can create an object instance if you know its class name. Imagine that you need to create an AddressPanel object as indicated in the above property file. The following code shows how to handle both the "Cancel" button and the panel.
Other Resource Bundles
You can create additional resource bundle types yourself by subclassing
the
Inprise, Inc. provides a good example of a new ResourceBundle type in
their JBuilder product. JBuilder is an integrated development environment
(IDE) for Java, and it includes a new class named
So, just how much better is performance? The results are surprising. Inprise's international software development team for JBuilder helped evaluate the performance differences among these three classes:
Table 1 ResourceBundle Performance
Compiling Non-ASCII BundlesJava uses Unicode as its internal character set. However, most operating system, editors, and other tools still use regional code pages to represent text. In most cases, this means that you will create your *.java files in a regional encoding, not Unicode. Of course, the Java compiler must compensate for the difference by converting your native code page into Unicode. Several character converters are included in the JDK. You can see a partial list in Table 2.
The Java compiler automatically assumes that your resource files are
written in the default code page of your operating system. So, if you're
using a U.S. English version of Solaris, the compiler will probably
assume your character set is ISO 8859-1. Although 8859-1 supports many
languages, it doesn't represent everything. So, if you need to compile
a Cyrillic language bundle, you would get incorrect results. Fortunately,
the compiler allows a command line directive that specifies the character
set of the source file. Using the appropriate converter, you can direct
the compiler to accurately convert the *.java source into Unicode. The
following example shows the command line you would use to compile a Japanese
resource bundle that's written in Shift JIS, a popular Japanese encoding:
Table 2 Partial List of Supported Languages and Converters
Sun Microsystems continually updates its list of supported character sets. If you need one that's not already supported, chances are that it's in progress. Of course, it wouldn't hurt to submit a request at the JDC Bug Database either. You'll need to understand another caveat regarding property bundles; you must create them in ASCII, or use Unicode escape codes to represent Unicode characters. Since you don't compile a property file to byte codes, there is no way to tell the Java1 Virtual Machine (JVM) which character set to use. So you must explicitly stick with ASCII or use the escape sequences. You can represent a Unicode character in any Java file using \uXXXX, where XXXX is the hexidecimal representation of the character. If you don't know the hexidecimal value for a character, just use the native2ascii tool provided in the JDK. This tool will convert a file written in your native encoding to one that represents non-ASCII characters as Unicode escape sequences. A partial listing of the %JDK_HOME%\lib\font.properties.ja file provides an example of these escape sequences:
Graceful DegradationJava searches for bundles by first looking for the fully qualified bundle name including a complete locale. If it can't find that file, it repeatedly chops off or replaces pieces of the locale identifier. The search algorithm is useful, since it provides graceful degradation when the requested bundle cannot be found. ConclusionResource bundles are a great way to isolate translatable text or localizable objects from your core source code. They're both easy to create and easy to use. Moreover, many of the good integrated development environments are including resource-bundle creation and management tools. Make sure you use resource bundles in your next application. Better yet, explore ways to incorporate them into your existing applications. They will definitely make localizing your product easier.
_______ John O'Conner teaches software internationalization topics and consults for global development projects. He also enjoys speaking Japanese, playing softball, and spending time with his family. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
| ||||||||||||