Internationalization

Some applications need to use more than one language in the user interface. Changing a program to allow for this is called "internationalization", while the actual translation is called "localization". Translation is usually applied only to user interface elements (menus, labels, and so on), and not to business data stored in the database.

Most implementations of multilingual applications use ResourceBundle and Locale. However, there are some problems with this style, so one might consider alternatives to ResourceBundle.

Here's a simple illustration of the basic ResourceBundle mechanism:

BankMachine is a user of a ResourceBundle, whose Locale is set by the end user. This illustration uses ListResourceBundle, but PropertyResourceBundle is likely used more often.

import java.util.ResourceBundle;
import java.util.Locale;

public final class BankMachine {

  /**
  * Run first a French version, then an English version.
  */
  public static void main(String[] arguments) {
    BankMachine bankMachine = new BankMachine();
    bankMachine.selectLanguage(FRENCH);
    bankMachine.showDisplay();
    bankMachine.selectLanguage(ENGLISH);
    bankMachine.showDisplay();
  }

  /**
  * The user's first action is to select a language.
  */
  public void selectLanguage(String language){
    if (ENGLISH.equals(language)) {
      text = ResourceBundle.getBundle(BUNDLE_NAME, Locale.ENGLISH);
    }
    else if (FRENCH.equals(language)) {
      text = ResourceBundle.getBundle(BUNDLE_NAME, Locale.FRENCH);
    }
    else {
      throw new IllegalStateException("Unknown language");
    }
  }

  public void showDisplay() {
    //use the bundle to get the proper version of a string
    //note that the variable names - Text.Hello, etc -  reflect the content,
    //so these method calls clearly indicate what is being displayed
    //to the user
    log(text.getString(Text.Hello));
    log(text.getString(Text.PleaseSelectAction));
  }

  // PRIVATE
  private static String ENGLISH = Text.English;
  private static String FRENCH = Text.French;
  private static String BUNDLE_NAME = "Text";

  /**
  * Default is English.
  * Note that this default is perfectly suitable for any initial user
  * selection of language, since the Strings representing the languages
  * themselves have only one representation, which are defined in the
  * default bundle.
  */
  private ResourceBundle text = ResourceBundle.getBundle(BUNDLE_NAME, Locale.ENGLISH);
  
  private static void log(String msg) {
    System.out.println(msg);
  }
}
 

An example run of BankMachine gives:

Bonjour
Veuillez choisir une action
Hello
Please select an action

The default ResourceBundle contains both constants and the default representations of all text:

import java.util.*;

public final class Text extends ListResourceBundle {

  public final Object[][] getContents() {
    return contents;
  }

  /**
  * These constants are used by the caller to identify what text is
  * needed; which version of the text is actually returned is determined
  * by the ResourceBundle mechanism.
  *
  * Using variable names which reflect the content clarifies the
  * intent of the code in the user of this class.
  */
  public static final String Hello = "Hello";
  public static final String PleaseSelectAction = "PleaseSelectAction";

  /**
  * Language names presented as a list of choices to the user
  * are special, since they are always presented in the native language.
  * Thus, this default bundle defines the
  * unique representations of all language names, and no other
  * bundle provides a translation for them.
  */
  public static final String English = "English";
  public static final String French = "Francais";

  // PRIVATE
  private static final Object[][] contents = {
    {Text.Hello, "Hello"},
    {Text.PleaseSelectAction, "Please select an action"} ,
    {Text.English, "English"},  //never defined elsewhere
    {Text.French, "Francais"},  //never defined elsewhere
  };
}
 

The other ResourceBundle classes do not define constants, just the translations :

import java.util.*;

public final class Text_fr extends ListResourceBundle {

  public final Object[][] getContents() {
    return contents;
  }

  //No constants are defined here

  // PRIVATE
  private static final Object[][] contents = {
    {Text.Hello, "Bonjour"},
    {Text.PleaseSelectAction, "Veuillez choisir une action"}
  };
}
 

See Also :
Try alternatives to ResourceBundle