ResourceBundle

From Jsorm

Revision as of 22:36, 7 April 2009 by Deitch (Talk | contribs)
(diff) ←Older revision | Current revision (diff) | Newer revision→ (diff)
Jump to: navigation, search

Contents

Overview

ResourceBundle is a class to retrieve internationalized strings, as managed by property files. This class is explicitly modeled after the similarly named Java class. This class uses the identical format files as the Java class, known as property files.

Once set up, you use calls to an instance of ResourceBundle to retrieve the value of a string, rather than putting the string directly in your code. This allows you to write code that works in any language, and uses configuration information to select the language on the fly.

Without ResourceBundle, your code to set a textfield to the value of "Hello" would look like this:

document.getElementById("myTextField").value = "Hello";

If you wanted to internationalize it, you have two choices:

  • Regenerate the page (or part of it) and handle internationalization via the server, having the string "Hello" by some server-generated variable.
  • Don't.

Neither of these alternatives is acceptable in a Web 2.0 era, where your users may speak many languages, and expect rapid and responsive Web applications.

With ResourceBundle, your code now looks as follows:

document.getElementById("myTextField").value = rb.get("Hello");

The variable rb in the above example represents a loaded ResourceBundle in a particular language and locale. "Hello" is the key used to look up its value in the language and locale. If rb was loaded with US English, the textfield will be set to "Hello". On the other hand, if rb was loaded with French, the textfield will be set to "Bonjour". The above happens without changing the code, and you can even have the end-user pick the language, if you so choose.

Usage

To use ResourceBundle, you prepare pre-defined values, like Bonjour and Hello in the above examples, in property files. These files are prepared and placed in an accessible location on your server. In your JavaScript code, you load the language- and locale-specific property files, and then look up the values you desire.

For our example, we will stick with the Hello example above. We have already stated that our key is "Hello" (without the quotes). The value in US English is "Hello" while in French it is "Bonjour".

In the following code, we will load two resource bundles, one with French and one with US English.

var french, english;
var cb1 = function(success, bundle, options) {
    if (success)
        french = bundle;
}
var cb2 = function(success, bundle, options) {
    if (success)
        english = bundle;
}
var config1 = {name: "myBundle", locale: "fr", callback: cb1};
var config2 = {name: "myBundle", locale: "en_US", callback: cb2};
JSORM.ResourceBundle.getBundle(config1);
JSORM.ResourceBundle.getBundle(config2);

Once the bundle is loaded, we can then get the value of the key.

var helloFrench = french.get("Hello");
var helloEnglish = english.get("Hello");

Because the property files are retrieved from the server asynchronously (via Ajax), ResourceBundle.getBundle() does not return the bundle. Rather, you pass a callback function as a member of the config parameter to getBundle(). The callback will be called when the load has succeeded or failed.

Note that the bundle to be loaded has two properties.

  • name: This is the name of the bundle. It can be anything, and will represent part of the actual property file name.
  • locale: This is the specific locale we want to load.

How these two parts go together is the subject of the next section.

Understanding Locales

Locales are a combination of language or language plus country. The language is always a two-character, lower-case string, as defined by the IANA Language Subtag Registry; the country is always a two-character, upper-case string, as defined by the ISO 3166 Country Code Registry. You may have only a language, or you may have a language plus country. If you have both, they are joined by the underscore '_' character.

The following are sample valid locales.

Locale Name Represents
en_US US English
fr_FR France French
en English

Naming Bundle Files

Property files are named based on a combination of the name of the bundle, followed by the locale, followed by the string ".properties" (without the quotes). The locale may be the language or both the language and the country, as above. The locale is always separated from the bundle name by an underscore '_'. Additionally, a file may have no locale at all, indicating it is a default to be used if no other is available. The following are sample valid locales for a bundle named "MyBundle":

File Name Locale
MyBundle_en_US.properties US English
MyBundle_fr_FR.properties France French
MyBundle_en.properties English
MyBundle.properties Default if no other one is found

Locating Property Files

Now that we understand how bundle files are named, we can describe how ResourceBundle searches for and locates its bundle files. The general rule of thumbs is:

fileName = basepath + path + bundleName + locale + '.properties';

Where:

  • basepath is the basepath as defined in the config parameter passed to ResourceBundle.getBundle() or, if undefined or null, then the default of ResourceBundle.basepath
  • path is the path as defined in the config parameter passed to ResourceBundle.getBundle() or, if undefined or null, then the default of ResourceBundle.path
  • bundleName is the name of the bundle as defined in the config parameter passed to ResourceBundle,getBundle()
  • locale is the name of the locale as defined in the config parameter passed to ResourceBundle.getBundle(), subject to the search order described below

When ResourceBundle.getBundle() attempts to search for a bundle file, it first compiles an ordered list of files to search for. The name of the file in each entry in the list always begins with the basepath+path+bundleName and always ends with '.properties'. The entries change based on locale. The first file in the list that is found is used as the closest match. The locale list is as follows.

  • full locale, e.g. fr_FR
  • language part of locale, e.g. fr
  • full locale of default, e.g. en_US
  • language part of default, e.g. en
  • no locale

ResourceBundle is careful not to retrieve the same file twice. Thus, if the full locale is the same as the default locale, only three files will be in the list: full locale, language part, and no locale. Similarly, if the passed locale only includes a language, only four files will be in the list: language part, full default, language part of default, and no locale.

The following table lists an example search pattern if we ask for a file named MyBundle and a locale of fr_CA (Canada French) with a default ResourceBundle.defaultLocale = 'en_US'.

MyBundle_fr_FR.properties
MyBundle_fr.properties
MyBundle_en_US.properties
MyBundle_en.properties
MyBundle.properties

Contents of Bundle Files

Bundle files, a.k.a. property files, follow the Java property file syntax and can be generated by many editors and IDEs. The contents of the file are text lines. Each line is either a key/value pair or a comment/blank line. Comment lines are any line that begins with a hash mark (#); blank lines are any line that has no characters other than whitespace. Comment lines and blank lines are ignore.

Key/value pairs are lines that begin with a word with alphanumeric characters [a-zA-z0-9] are followed by an equals sign (=) and then by any other characters. The part before the equals sign, ignoring leading and trailing whitespace, is the key; the part following the equals sign is the value.

The following are example property files in English and French for MyBundle, continuing our example from above.

# MyBundle_fr_FR.properties
Hello = Bonjour
Goodbye = Au revoir
# MyBundle_en_US.properties
Hello = Hello
Goodbye = Goodbye
# MyBundle_en_UK.properties
Hello = Hallo
Goodbye = Cheers
Personal tools