Rogue Wave banner
Previous fileTop of DocumentContentsIndex pageNext file
Internationalization Module User's Guide
Rogue Wave web site:  Home Page  |  Main Documentation Page

10.4 Localized Resources

Resource bundles enable you to store and access locale-dependent data. This is an important component of internationalizing your application, because it separates your code from information that needs to be localized.

In the Internationalization Module, resource bundles are represented by RWUResourceBundle.

10.4.1 The Resource Hierarchy

Although the resource bundles for an application are placed in a single directory in the file system, they are organized into a logical hierarchy based upon the locales associated with the bundles. At the base of the hierarchy is the root resource bundle. You create the root resource bundle for your application when you develop it, with resource values expressed in accordance with your own locale. (See Section 10.4.2.)

When your application is localized for a particular locale--either by you or by a software translator at some time in the future--a new resource bundle is created that translates the values in the root resource bundle for the new locale.

In the logical resource hierarchy, immediately below the root resource bundle are language-specific bundles; for example, de, en, and ja bundles. Below the language-specific bundles are country-specific bundles; for example, de_DE and de_CH. Below the country-specific bundles are variant-specific bundles; for example, de_DE_PREEURO. A sample resource hierarchy is illustrated in Figure 1.

Figure 1: Sample resource bundle hierarchy

Not every bundle needs a resource value for each localizable aspect of the application. A fallback mechanism (see Section 10.4.5 and Section 10.4.6) ensures that a child resource bundle need only contain the resources whose values differ from its ancestor bundles.

10.4.2 Defining Resource Bundles

Resource bundles contain one or more resources. They are created as text files using the simple syntax described below, then compiled into an efficient, binary form (see Section 10.4.3). Resource text may be in any recognized encoding; it is converted to Unicode when you compile the text file.

Resources may be simple or complex. Simple resources hold a single value. Complex resources hold one or more simple or complex resources. Simple resources are specified in the text resource files using the following syntax:

A simple resource can be of type string, integer, integer vector, or binary:

Complex resources can be arranged as a table or as an array:

Note that tables and arrays may themselves contain other tables and arrays, not just simple resources. As with all resources held by arrays, a table held within an array must not be named.

Because tables and arrays can be disambiguated from each other solely on the basis of their syntactic form, you may omit the type information from complex resources. For example, this resource is unambiguously an array:

Resource bundles are themselves tables, named after the locale they are associated with. For example, this is a simple root resource bundle:

To define the root resource bundle for your application, gather all the application data that may need to be translated or localized, express it in the resource syntax described above, and save it in a text file called root.txt.

The resources in the root bundle can be localized, as necessary, to particular locales. For example, this might be a localization of the resources above to the es locale, saved in a text file called es.txt:

Note that the Version resource is not localized. If that resource is sought in the es resource bundle, the fallback mechanism ensures it is found in the root resource bundle.

10.4.3 Compiling Resource Bundles

Resource definitions in a text file are compiled into a compact, binary form using the supplied genrb utility, located in:

The genrb reads text files (see Section 10.4.2), and outputs .res binary resource bundle files. For example:

creates the resource bundle en_US.res. The complete syntax for genrb is:

where files is a list of text files. Some of the more useful options are:

For a complete list of options, type genrb -h.

When you compile a resource bundle, any string data is converted from the text encoding to a Unicode format. However, to simplify the lookup process, keys are not converted to a Unicode representation, but are used exactly as encoded in the text file. Although you may use any single-byte character set for RWUResourceBundle keys, for maximum portability, it is best to limit the characters used for keys to the basic source character set described in Section 2.6. This set corresponds to the printable ASCII or Latin-1 character set.

Note that binary data, as well as keyed data, are compiled into a platform-specific form. As a result, table data may not be found on a platform where the character encoding (ASCII or EBCDIC, for instance) used for the keys is different than that where compiled. For similar reasons, binary data may be wrong if compiled on a big-endian machine and read on a little-endian machine, or vice versa.

10.4.4 Packaging Resource Bundles

If you have many resource (.res) files, you can package them into a single combined file using the supplied pkgdata utility, located in the same directory as the genrb utility. This tool accepts a list of resource files, and creates a combined file with a .dat extension. For a complete list of options, type pkgdata -h.

10.4.5 Retrieving a Resource Bundle

In the Internationalization Module, when an application needs localized data, it constructs an RWUResourceBundle, then queries the instance for the needed resources. The constructors for RWUResourceBundle accept the name of a directory containing .res or .dat files, and the name of a locale. For example:

If no locale is given, or an empty or null locale is passed, the default locale is used. (See Section 10.3.3.)

The constructor may succeed, succeed through fallback, or fail, depending on whether an exact match to the requested locale is found, a fallback match is found, or no bundle at all is found; for instance, if the resource path does not exist.

The fallback mechanism works as follows:

  1. The library first looks for the exact named RWUResourceBundle.

  2. Failing that, the library looks for a parent locale along the named locale's branch in the resource hierarchy (see Section 10.4.1).

  3. If no parent locale is found, the library looks for the locale named by RWULocale::getDefault().

  4. Failing that, the library looks for a parent locale along the default locale's branch in the resource hierarchy.

  5. Failing that, the library attempts to open the RWUResourceBundle named root.

  6. Finally, if it can find no information for any of the above mentioned locales, the library throws an RWUException.

For example, suppose the RWUResourceBundles shown in Figure 2 are defined, and that the current default RWULocale is es_ES.

Figure 2: Sample resource bundle hierarchy

In this case, if you attempt to open the RWUResourceBundle named ja_JP, the library tries these bundle names in order:

  1. ja_JP -- the exact match

  2. ja -- the parent

  3. es_ES -- the default locale

  4. es -- the default parent: Success!

  5. if es been missing, root would have been tried next

Constructors throw an RWUException if no bundle is found, but otherwise succeed and cache an RWUStatusCode to indicate the level of success. The getStatus() method returns an RWUStatusCode indicating whether fallback occurred during the creation or retrieval of the resource bundle:

If fallback occurred, you can use method getLocale() to return the actual locale where the resource bundle was found, as opposed to the locale originally requested. Method getLocaleName() returns the name of the locale; it is a convenience synonym for getLocale().getName().

Note that it is normal to expect fallbacks. Some programs don't need to distinguish resources for all locales.

10.4.6 Accessing a Resource

In the Internationalization Module, resources within a resource bundle are themselves represented as RWUResourceBundles, so RWUResourceBundle instances nest recursively. The RWUResourceBundle instances created by the constructors are called "top-level" resource bundles. Top-level resource bundles are guaranteed to be of type table, containing one or more top-level resources associated with const char* keys.

You can access a top-level resource using the get() method. This method returns the requested resource as an RWUResourceBundle. For example:

When the top-level RWUResourceBundle is queried for a particular top-level resource, the query may succeed, succeed through fallback, or fail.

The fallback mechanism works as follows:

  1. The library first looks for the named resource in the currently open RWUResourceBundle.

  2. Failing that, the library looks for the named resource in a parent of the currently open RWUResourceBundle.

  3. Failing that, the library looks in the root resource bundle.

  4. Failing that, the library throws an RWUException.

For example, suppose that in the es resource bundle there is a table named menu containing entries for file, edit, and help. Suppose also that the root resource bundle has, in addition to the menu table, a string resource named currentVersion. If you attempt to access the menu table resource, the library returns the one in the es RWUResourceBundle. If you attempt to access the currentVersion string resource, the library returns the one in root.

Note that fallback occurs only for top-level resources. When you open a resource held within a top level array or table, the library looks only in the already open top-level RWUResourceBundle. If the requested datum is not there, an RWUException is thrown. For example, continuing from the example above, suppose you have opened the menu resource, and now are looking for the tools string within the menu table. Suppose furthermore this entry is available in the menu resource in the root resource bundle, but not in the menu resource in the es resource bundle. Your attempt does not fall back; it fails.

The lookup query throws RWUException if it fails, but otherwise returns an RWUResourceBundle holding a cached RWUStatusCode. The getStatus() method returns the status code:

The get() method returns the requested resource as an RWUResourceBundle. If you know the type of the resource, you can then access it using the appropriate method:

All getX() methods throw RWUException if the resource is not of the specified type. If you don't know the type of a resource held by an RWUResourceBundle, you can query it using the getType() method, which returns a value from the ResourceType enumeration: None, String, Int, IntVec, Binary, Table, or Array. For example:



Previous fileTop of DocumentContentsNo linkNext file

Copyright © Rogue Wave Software, Inc. All Rights Reserved.

The Rogue Wave name and logo, and SourcePro, are registered trademarks of Rogue Wave Software. All other trademarks are the property of their respective owners.
Provide feedback to Rogue Wave about its documentation.