Previous | Next | Trail Map | Writing Java Programs | Writing Global Programs


Loading Resource Bundles

The AroundTheWorld program four resource bundles, all loaded by the LinguaPanel class.
ResourceBundle labels = ResourceBundle.getResourceBundle("LabelsBundle",
                        locale, loader);
ResourceBundle paragraph = ResourceBundle.getResourceBundle("ParagraphBundle",
                        locale, loader);
ResourceBundle numbers = ResourceBundle.getResourceBundle("NumbersBundle",
                        locale, loader);
MediaBundle flagNSoundsBundle = (MediaBundle)ResourceBundle.getResourceBundle(
                        "FlagNSoundsBundle", locale, loader);
The first three resources bundles loaded by in this code segment, LabelsBundle, NumbersBundle, and FlagNSoundsBundle, are all subclasses of ListResourceBundle. ParagraphBundle is a PropertyResourceBundle. Let's first investigate loading the list resource bundles. We'll look at the properties bundle later.

The first argument to ResourceBundle.getResourceBundle is the bundle name. This argument must be the fully qualified name of the base resource bundle class. Thus, it must include the full package name as well as the classname: myPackage.MyResources. Each of AroundTheWorld's resource bundles live in the default package, so in this case, the classname is the fully qualified name for each bundle: LabelsBundle, NumbersBundle, and FlagNSoundsBundle.

Loading a resource bundle via getResourceBundle is a locale-sensitive operation. Thus, the second argument to getResourceBundle is a locale. getResourceBundle uses this locale object to identify which version of the resource bundle to load.

To find the correct, locale-specific, resource bundle, getResourceBundle builds variations of the bundle name until it finds the name of a class that can be loaded. The series of names looks like this:

bundleName + "_" + localeLanguage + "_" + localeCountry + "_" + localeVariant 
bundleName + "_" + localeLanguage + "_" + localeCountry 
bundleName + "_" + localeLanguage 
bundleName + "_" + defaultLanguage + "_" + defaultCountry + "_" + defaultVariant 
bundleName + "_" + defaultLanguage + "_" + defaultCountry 
bundleName + "_" + defaultLanguage 
bundleName
where localeLanguage, localeCountry and localeVariant are taken from the locale specified in the getResourceBundle call. defaultLanguage, defaultCountry and defaultVariant are taken from the default locale. As you can see, the resource bundle named bundleName is the bundle of last resort and contains the values to be used if a version of the bundle is not available for a specific locale. If no ResourceBundle subclass can be found, getResourceBundle throws a MissingResourceException.

Typically, a program provides a default bundle for each of its resource bundles. The default bundle contains the full set of key-value pairs in the bundle. Thus, people performing the localization on the bundle have all the information required.

Let's watch how LabelsBundle is loaded into AroundTheWorld. As you know, AroundTheWorld creates one LinguaPanel per supported locale. Thus, it creates three LinguaPanels, one each for Locale.US, Locale.FRANCE, and Locale.CANADA_FRENCH. Upon construction each locale-specific LinguaPanel loads a locale-specific version of LabelsBundle.

For example, when AroundTheWorld creates a LinguaPanel for Locale.US, getResourceBundle searches first for LabelsBundle_en_US. This search is in vain because there is no LabelsBundle_en_US class. Then getResourceBundle searches for LabelsBundle_en (again in vain), and finally it searches for and finds LabelsBundle. The LabelsBundle class is the default bundle and contains English versions of the strings appropriate for the US. Thus it was not necessary to provide another LabelsBundle specifically for the US.

The AroundTheWorld program defines another version of LabelsBundle, the French language version, of LabelsBundle--LabelsBundle_fr. Note that this bundle is for the French language--it is not for a specific French-speaking country. You'll see why in a moment.

LabelsBundle_fr is the same as LabelsBundle except that the values in LabelsBundle_fr have been translated into French. Note that the keys have not changed. The keys are used to look up values in the bundle. So, you must use the same keys for the same items in related ResourceBundles.

When AroundTheWorld creates a LinguaPanel for Locale.FRANCE, getResourceBundle searches first for LabelsBundle_fr_FR, which it doesn't find, then searches for, and finds, LabelsBundle_fr. Similarly, when looking for the French Canadian version of LabelsBundle, getResourceBundle searches first for LabelsBundle_fr_CA, which it doesn't find, then searches for, and finds, LabelsBundle_fr. Thus the locales for France and French Canada use the same LabelsBundle class: LabelsBundle_fr. This is the proper design for LabelsBundle because the appropriate translations for the labels contained in LabelsBundle are the same for both locales.


Try this: Figure out how the other two ListResourceBundles, NumbersBundle and FlagNSoundsBundle, are loaded.

If the bundle in question is a properties bundle, such as ParagraphBundle in the AroundTheWorld program, getResourceBundle creates a PropertyResourceBundle and initializes it with the information from a properties file. getResourceBundle derives the name of the properties file in the same manner as it derives resource bundle class names.

To recap: To find the correct, locale-specific, properties file when loading a PropertyResourceBundle, getResourceBundle builds variations of the bundle name until it finds the name of a properties file that can be loaded. As with classnames, the series of property filenames looks like this:

bundleName + "_" + localeLanguage + "_" + localeCountry + "_" + localeVariant 
bundleName + "_" + localeLanguage + "_" + localeCountry 
bundleName + "_" + localeLanguage 
bundleName + "_" + defaultLanguage + "_" + defaultCountry + "_" + defaultVariant 
bundleName + "_" + defaultLanguage + "_" + defaultCountry 
bundleName + "_" + defaultLanguage 
bundleName
The properties file has a .properties extension.

When AroundTheWorld creates the LinguaPanel for Locale.US, it searches first for ParagraphBundle_en_US.properties, which it doesn't find, then for ParagraphBundle_en.properties, which again it doesn't find, and then finally for ParagraphBundle.properties, which it does find. As with LabelsBundle, default data is contained in this resource bundle. Because the default contains the information for the United States, a specific US version of this bundle is not necessary.

The French ParagraphBundle properties file is called ParagraphBundle_fr.properties. Again, only the values (not the keys) are translated into another language. This properties file is loaded into the PropertyResourceBundle when AroundTheWorld creates the Locale.FRANCE LinguaPanel.

France and French Canada cannot share ParagraphBundles because the paragraph provides a description of the locale. The language that the paragraphs are written in is the same for each locale. However, the contents are different. Thus AroundTheWorld must provide a third file ParagraphBundle_fr_CA.properties which gets loaded when the program creates the Locale.CANADA_FRENCH LinguaPanel.


Previous | Next | Trail Map | Writing Java Programs | Writing Global Programs