Internationalization (i18n) package.

Overview

Internationalization package consist of two components:

  • Global resource manager class I18 maintains hierarchy of resource bundles and returns requested resource bundles to the client applications. Resource bundles contain various internationalized resource (strings, images, fonts) which client application can then retrieve. All resource bundle implementations inherit ResourceBundle class, that defines methods for retrieving different types of resources. Resource bundles use global resource cache (ResourceCacheManager (maintained by I18n) to create the resource objects.
  • Localizer can localize individual objects or whole object hierarchies. When localizing an object hierarchy, localizer iterates through the hierarchy and localizes the different attributes (e.g. text, icon) of the objects by finding localization data from the resource bundles.

    Internationalization resources are stored in resource bundles. Most common file format for a resource bundle is Java property (extension .properties). Java property is currently the only file format supported by I18n. See java.util.properties for more information about property file format. 

    Resource bundles are stored in tree-hierarchy.  To help to organize the hierarchy, I18n provides a special type of a resource bundle: a resource bundle group. Resource bundle group does not include own resources, but instead it hosts other resource bundles. Every resource bundle hierarchy has at least one bundle group, the base, that is generated and maintained automatically by I18n. All resource bundles added to the hierarchy are sub-bundles of the base node.

    Resource bundles must have unique names; resource bundle hierarchy can not contain two resources bundles with the same name. Resource bundles can be retrieved using bundle or class name. By using class names, hard-coded string literals can be avoided, but it also requires that class (or package) is pre-configured to the resource bundle. 

    Example:

  • I18n.getResourceBundle("poseidon.strings"). Requesting by bundle name.
  • I18n.getResourceBundle(this.getClass()). Requesting by class name. Association between requesting class and resource bundle must be set before method is called.

  • All other resource types than java.lang.String will be created by ResourceCacheManager class. It maintains an in-memory cache for created objects. In-memory cache ensures, that a resource will be created only once, even if it is defined in many resource bundles.
    Objects are created by resource builder classes. I18n package has three default resource builders for java.awt.Color, java.awt.Font and javax.swing.ImageIcon classes. New resource builders can also be created and registered to cache manager. Existing resource builders can also be overwritten with new implementations.

    Large object structures can be localized easily with localizer package. It defines a base implementation for localizers, which iterate through object hierarchy and localize different attributes of objects. Localizers identify hierarchy objects by their class type and use object localizer classes for settings the attributes of the objects . localizer.swing package contains a default implementation of localizer for swing component hierarchies. Many object localizer classes are provided for the most typical objects of swing hierarchy (JLabel, JTextComponent, ...). New object localizers can also be added or existing ones overwritten.

    I18n can be configured using a configuration file and I18nConfigurator class. Using configuration file frees the client of the I18n package from tedious manual configuration and enables flexible and dynamic runtime configuration of resource bundles. All the settings that be configured using the I18n interfaces, can also be set in the configuration file.

    Code examples:

    Creating a new resource bundle and adding to it the bundle hierarchy

    I18n i18n = I18n.getI18n();
    // base name: application_strings, default locale: german -> load properties file: application_strings_de-DE.properties
    PropertiesBundle bundle = new PropertiesBundle("application.strings", "application_strings", "de-De");
    // add bundle directly under base bundle
    i18n.addResourceBundle(bundle, I18n.getBaseBundle()); 

    Adding a resource bundle class association and retrieving resource bundle by class name

    I18n i18n = I18n.getI18n();
    // file name: application_strings_de-De.properties
    PropertiesBundle bundle = new PropertiesBundle("application.strings", "application_strings", "de-De");
    i18n.addResourceBundle(bundle, I18n.getBaseBundle()); 
    i18n.addResourceBundleClassAssociation(this.getClass().getName(), bundle);
    // retrieving resource bundle
    ResourceBundle resultBundle = i18n.getResourceBundle(getClass());

    Adding a resource bundle package association and retrieving resource bundle by class name

    I18n i18n = I18n.getI18n();
    // file name: application_strings_de-De.properties
    PropertiesBundle bundle = new PropertiesBundle("application.strings", "application_strings", "de-De");
    i18n.addResourceBundle(bundle, I18n.getBaseBundle()); 
    i18n.addResourceBundlePackageAssociation("com.application.*", bundle);
    // retrieving resource bundle
    // note that calling class must be part of com.application package!
    ResourceBundle resultBundle = i18n.getResourceBundle(this.class);

    Creating and registering new resource builder

    public class PointBuilder implements IResourceBuilder
    {

    public Object buildResource( String key )
    {     
        return new java.awt.Point(1,1);
    }

    }

    // somewhere else...
    I18n i18n = getI18n();
    i18n.getResourceCacheManager().registerResourceBuilder(java.awt.Point.class, new PointBuilder());

    Using default swing localizer

    I18n i18n = I18n.getI18n();
    ResourceBundle bundle = i18n.getBundle("applicationBundle");
    JContainer container = new JContainer(); 

    Localizer localizer = LocalizerRegistry.lookup(LocalizerRegistry.SWING_LOCALIZER);
    localizer.setResourceBundle(bundle);

    localizer.localizeObjectHierarchy(container);