Java ME Guideline: How to create a localized application

Problem Description

Designing an application so that it can be adapted to various languages and regions without engineering changes

Use Cases

Any application that displayes text

2. Solution Description

Solution Requirements

All devices and platforms

Solution Approach

SUBJECTIVE - query the locale and encoding of the device and display appropriate lables accoring to the device locale

Retrieve appropriate lables based on the locale at runtime from resource files or from JAD file.

Solutions Overview

Solution description:

Query the current locale of the device using " microedition.locale" attribute [ example]

Options for creating labels according to the locale:

1. Read labels as user-defined JAD attributes [ example]

1.1 Use JAD file for L10N resources, Adding user-defined attributes to the JAD

1.2 At application runtime, use the MIDlet.getAppProperty() method to retrieve resources

1.3 The JAD file contains one attribute per application string per locale supported

1.4 The attribute name represents the locale context

For example:
exit-en-US: Exit
exit-fr-FR: Sortie

  • Very simple, does not require extra coding
  • Easy for translators
  • Deployment system can be used to create seperate JAD files for different locales
  • This approach might not be useful for large amount of resources
  • Performance might be affected due to reading of large JAD file
  • This approach addresses only string resources

2. Use text files as localized resources [ example]

2.1 Application specific text files that contains localized attributes

2.2 Define one file for each locale

2.3 File name contains the locale destination

For example:
en-US.txt for English
fr-FR.txt for French
ja-JP.txt for Japan

Resource files are part of the JAR

  • Easy for translators
  • Each locale is represented in separate file
  • Need to write your own stream parser
  • No StringTokenizer, need to parse stream one character at a time
  • Application need to hold the resources in an internal structure
  • Conversion of byte stream to character stream is required (using InputStreamReader)
  • Increase startup time

3. Using Java Class files as resources [ example]

3.1 Java classes contains localized resources

3.2 Each class contains resources for one locale

3.3 The classes are compiled and packaged as part of the JAR file

3.4 Design your own version of J2SE Resource Bundles

  • No stream handling
  • No file parsing
  • This approach addresses all l10n resources, not only strings
  • Hard for non-technical translators since strings are mixed with code
  • Requires more storage on the device
  • Memory consumption

Alternative Solutions

Use JSR 238 - Mobile Internationalization API, if the device support it.
The API provides the locale-specific formatting of dates, times, numbers and currency amounts
The API also defines a mechanism to retrieve application-specific and device-specific resources, and provides services for the locale-specific collation (sorting) of strings

Examples, Illustrations

Example for querying the locale of the device and retrieving the appropriate attribute from the JAD



      ...

    /* This code can be called anywhere in the application */
    // get the current locale of the device

    String locale = System.getProperty("microedition.locale");

    //Get User-Defined attribute from JAD

    String exitStr = getAppProperty("exit" + "-" + locale);
    Command exitCommand = new Command(exitStr, Command.EXIT, 1);

  ...

Example for using text files as localized resources



    ...

    /* This code can be called anywhere in the application */
    // get the current locale of the device

    String locale = System.getProperty("microedition.locale");

    //Read the resource file from JAR

    InputStream is = this.getClass().getResourceAsStream(locale + ".txt");
    Reader stream = new InputStreamReader(is, "UTF-8");
    Hashtable resources = new Hashtable();
    StringBuffer key = new StringBuffer();
    StringBuffer value = new StringBuffer();

    //Read each line as key: value
    while(true){
      int status = readLine(key, value, stream);
      if (status == -1) break;
      resources.put(key, value);
    }
  ...

  int readLine(StringBuffer key, StringBuffer value,Reader stream){
    while (true){
          c = (char) stream.read();
          //Read key until delimiter or space
          if (c == ' ' || c == ':'){
                 break;
          }
          key.append(c);
    }

    while (true){
          c = (char) stream.read();
          if (c == '\n'){
                 break;
          }

          //Read value until end of line
          value.append(c);
    }
  }

Example for using class files as localized resources



    ...

    /* This code can be called anywhere in the application */
    // get the current locale of the device

    String locale = System.getProperty("microedition.locale");
    ResouceBundle bundle = ResourceBundle.getBundle("Resources", locale);
    String exitStr = (String)bundle.handleGetObject("exit");
    Command exitCommand = new Command(exitStr, Command.EXIT, 1);

  ...

  public abstract class ResourceBundle {

    // Gets a resource bundle using the specified base name and locale

    public static final ResourceBundle getBundle(String baseName, String locale){
      String className = baseName + "_" + locale;
      Class c = Class.forName(className);
      ResourceBundle bundle = (ResourceBundle)c.newInstance();
      return bundle;
    }

    //Gets an object for the given key from this resource bundle

    protected abstract Object handleGetObject(String key);
  }

  public class Resources_fr_FR extends ResourceBundle {
    private Hashtable resources = new Hashtable();

    public Resources_fr_FR() {
      resources.put("exit", "Sortie");
      resources.put("cancel", "Quitter");
      ...
    }

    protected Object handleGetObject(String key){
      return resources.get(key);
    }
}

3. List of Affected Devices

All devices

4. Keywords

Language, locale, I10n, translation, localization