Skip Headers

Oracle® Application Development Framework Developer's Guide 10g Release 3 (10.1.3) B25386-01 |
| Home | Solution Area | Contents | Index

Previous | Next |

# 14.4 Internationalizing Your Application

When your application will be viewed by users in more than one country, you can configure your application to different locales so that it displays the correct language for the language setting of a user's browser. For example, if you know your application will be viewed in Germany, you can localize your application so that when a user's browser is set to use the German language, text strings in the application will appear in German.

ADF Faces components provide automatic translation. The resource bundle used for the components' skin (which determines look and feel, as well as the text within the component) is translated into 28 languages. If a user sets the browser to use the German (Germany) language, any text contained within the components will automatically display in German. For more information on skins and this resource bundle, see Section 14.3.1, "How to Use Skins". For a complete list of all text included in ADF Faces components, see the "Reference: Keys for Resource Bundle Used by Skins" topic of the JDeveloper online help.

For any text you add to the application, you need to provide a resource bundle that holds the actual text, and load that bundle into the page using the JSF `loadBundle` tag. Then, instead of directly entering the text on the JSF page or entering the text as a value for the `Text` attribute of an object, you bind that attribute to a key in the resource bundle. You then create a version of the resource bundle for each locale.

Note: Any text retrieved from the database is not translated. This document covers how to localize static text, not text that is stored in the database.

Figure 14-5 shows the SRList page from the SRDemo application in a browser set to use the English (United States) language.

Figure 14-5 The SRList Page in English

Although the title of this page is "My Service Requests," instead of having "My Service Requests" as the value for the `title` attribute of the `PanelPage` component, the value is bound to a key in a resource bundle. The `UIResources` resource bundle is loaded into the page using the `loadBundle` tag, as shown in Example 14-7. The resource bundle is given a variable name (in this case `res`) that can then be used in EL expressions. The `title` attribute of the `panelPage` component is then bound to the `srlist.pageTitle` key in that resource bundle.

Example 14-7 Resource Bundles Used in a JSF Page

    <f:view>
      <f:loadBundle basename="oracle.srdemo.view.resources.UIResources"
                      var="res"/>
      <af:document title="#{res['srdemo.browserTitle']}"
                   initialFocusId="viewButton">
        <af:form>
          <af:panelPage title="#{res['srlist.pageTitle']}">

The `UIResources` resource bundle has an entry in the English language for all static text displayed on each page in the SRDemo application, as well as text for messages and global text, such as generic labels. Example 14-8 shows the keys for the SRList page.

Example 14-8 Resource Bundle Keys for the SRList Page Displayed in English

    #SRList Screen
    srlist.pageTitle=My Service Requests
    srlist.menubar.openLink=Open Requests
    srlist.menubar.pendingLink=Requests Awaiting Customer
    srlist.menubar.closedLink=Closed Requests
    srlist.menubar.allRequests=All Requests
    srlist.menubar.newLink=Create New Service Request
    srlist.selectAnd=Select and
    srlist.buttonbar.view=View
    srlist.buttonbar.edit=Edit
    srlist.buttonbar.assign=Assign

Figure 14-6 also shows the SRList page, but with the browser set to use the German (Germany).

Figure 14-6 The SRList Page in German

Note: The column headings were not translated because the values are bound to the label property of the binding object. This value is set as a control hint in the entities structure XML file. Whenever any values are set for the label, a resource bundle is automatically created. To translate these, you must create localized versions of these resource bundles.

Example 14-9 shows the resource bundle version for the German (Germany) language, `UIResource.de`. Note that there is not an entry for the selection facet's title, yet it was translated from "Select" to "Auswahlen" automatically. That is because this text is part of the ADF Faces table component's selection facet.

Example 14-9 Resource Bundle Keys for the SRList Page Displayed in German

    #SRList Screen
    srlist.pageTitle=Meine Service Anfragen
    srlist.menubar.openLink=Offene Anfragen
    srlist.menubar.pendingLink=Anfrage wartet auf Kunden
    srlist.menubar.closedLink=Geschlossene Anfragen
    srlist.menubar.allRequests=Alle Anfragen
    srlist.menubar.newLink=Erstelle neue Service Anfrage
    srlist.selectAnd=Kommentare wählen und
    srlist.buttonbar.view=Ansich

The resource bundles for the application can be either Java classes or property files. The abstract class `ResourceBundle` has two subclasses: `PropertyResourceBundle` and `ListResourceBundle`. A `PropertyResourceBundle` is stored in a property file, which is a plain-text file containing translatable text. Property files can contain values only for `String` objects. If you need to store other types of objects, you must use a `ListResourceBundle` instead. The contents of a property file must be encoded as ISO 8859-1. Any characters not in that character set must be stored as escaped Unicode.

To add support for an additional locale, you simply replace the values for the keys with localized values and save the property file appending a language code (mandatory), and an optional country code and variant as identifiers to the name, for example, `UIResources_de.properties`. The SRDemo application uses property files.

Note: Property files must contain characters in the IS0 8859-1 character set. If you need to use other characters, use a `ListResourceBundle` class instead. All non-8859-1 character sets must be converted to escaped UTF-8 characters, or they will not display correctly.

The `ListResourceBundle` class manages resources in a name, value array. Each `ListResourceBundle` class is contained within a Java class file. You can store any locale-specific object in a `ListResourceBundle` class. To add support for an additional locale, you subclass the base class, save it to a file with an locale / language extension, translate it, and compile it into a class file.

The `ResourceBundle` class is flexible. If you first put your locale-specific `String` objects in a `PropertyResourceBundle` file, you can still move them to a `ListResourceBundle` class later. There is no impact on your code, since any call to find your key will look in both the `ListResourceBundle` class as well as the `PropertyResourceBundle` file.

The precedence order is class before properties. So if a key exists for the same language in both a class file and in a property file, the value in the class file will be the value presented to the user. Additionally, the search algorithm for determining which bundle to load is as follows:

1. (baseclass)+(specific language)+(specific country)+(specific variant)

2. (baseclass)+(specific language)+(specific country)

3. (baseclass)+(specific language)

4. (baseclass)+(default language)+(default country)+(default variant)

5. (baseclass)+(default language)+(default country)

6. (baseclass)+(default language)

For example, if a user's browser is set to the German (Germany) locale and the default locale of the application is US English, the application will attempt to find the closest match, looking in the following order:

1. de_Germany

2. de

3. en_US

4. en

5. The base class bundle

Tip: The `getBundle` method used to load the bundle looks for the default locale classes before it returns the base class bundle. If it fails to find a match, it throws a `MissingResourceException` error. A base class with no suffixes should always exist in order to avoid throwing this exception

## 14.4.1 How to Internationalize an Application

To internationalize your application, you need to do the following:

Tip: These procedures will allow the application to display the correct language based on the browser settings of the user. You may also want to create your application in a way that allows the user to manually set the locale they wish to use. The current locale is stored in the viewRoot of `FacesContext`.

1. Create a base resource bundle that contains all the text strings that are not part of the components themselves. This bundle should be in the default language of the application.

   Tips: Instead of creating one resource bundle for the entire application, you can create multiple resource bundles. For example, in a JSF application, you must register the resource bundle that holds error messages with the application in the `faces-config.xml` file. For this reason, you may want to create a separate bundle for messages. Create your resource bundle as a Java class instead of a property file if you need to include values for objects other than Strings, or if you need slightly enhanced performance. The `getBundle` method used to load the bundle looks for the default locale classes before it returns the base class bundle. However if it fails to find a match, it throws a `MissingResourceException` error. A base class with no suffixes should always exist in order to avoid throwing this exception

2. Use the base resource bundle on the JSF pages by loading the bundle and then binding component attributes to keys in the bundle.

3. Create a localized resource bundle for each locale supported by the application.

4. Register the locales with the application.

5. Register the bundle used for application messages.

Note: If you use a custom skin and have created a custom resource bundle for the skin, you must also create localized versions of that resource bundle. Similarly if your application uses control hints on data controls to set any text, you must create localized versions of the generated resource bundles for that text.

Detailed procedures for each step follow.

To create a resource bundle as a property file:

1. In JDeveloper, create a new simple file.

   1. In the Application Navigator, right-click where you want the file to be placed and choose New to open the New Gallery.

      Note: If you are creating a localized version of the base resource bundle, save the file to the same directory as the base file.

   2. In the Categories tree, select Simple Files, and in the Items list, select File.

   3. Enter a name for the file, using the extension `.properties`.

      Note: If you are creating a localized version of a base resource bundle, you must append the ISO 639 lowercase language code to the name of the file. For example, the German version of the `UIResources` bundle is `UIResources_de.properties`. You can add the ISO 3166 uppercase country code (for example de_DE) if one language is used by more than one country. You can also add an optional non standard variant (for example, to provide platform or region information). If you are creating the base resource bundle, no codes should be appended.

2. Create a key and value for each string of static text for this bundle. The key is a unique identifier for the string. The value is the string of text in the language for the bundle. If you are creating a localized version of the base resource bundle, any key not found in this version will inherit the values from the base class.

   Note: All non-ASCII characters must be either UNICODE escaped or the encoding must be explicitly specified when compiling, for example:
       javac -encoding ISO8859_5 UIResources_de.java

   For example the key and value for the title of the SRList page is:

       srlist.pageTitle=My Service Requests

   Note: All non-8859-1 character sets must be converted to escaped UTF-8 characters, or they will not display correctly.

To create a resource bundle as a Java Class:

1. In JDeveloper, create a new simple Java class:

   - In the Application Navigator, right-click where you want the file to be placed and choose New to open the New Gallery.

     Note: If you are creating a localized version of the base resource bundle, this must reside in the same directory as the base file.

   - In the Categories tree, select Simple Files, and in the Items list, select Java Class.

   - Enter a name and package for the class. The class must extend `java.util.ListResourceBundle`.

     Note: If you are creating a localized version of a base resource bundle, you must append the ISO 639 lowercase language code to the name of the class. For example, the German version of the `UIResources` bundle might be `UIResources_de.java`. You can add the ISO 3166 uppercase country code (for example de_DE) if one language is used by more than one country. You can also add an optional non standard variant (for example, to provide platform or region information). If you are creating the base resource bundle, no codes should be appended.

2. Implement the `getContents()` method, which simply returns an array of key-value pairs. Create the array of keys for the bundle with the appropriate values. Example 14-10 shows a sample base resource bundle java class.

   Note: Keys must be `Strings`. If you are creating a localized version of the base resource bundle, any key not found in this version will inherit the values from the base class.

   Example 14-10 Base Resource Bundle Java Class

       package sample;import java.util.ListResourceBundle;public class MyResources extends ListResourceBundle {  public Object[][] getContents() {    return contents;  }  static final Object[][] contents = {    {"button_Search", "Search"},    {"button_Reset", "Reset"},  };}

To use a base resource bundle on a page:

You need to load only the base resource bundle on the page. The application will automatically use the correct version based on the user's locale setting in their browser.

1. Set your page encoding and response encoding to be a superset of all supported languages. If no encoding is set, the page encoding defaults to the value of the response encoding set using the `contentType` attribute of the page directive. Example 14-11 shows the encoding for the SRList page.

   Example 14-11 Page and Response Encoding

       <?xml version='1.0' encoding='windows-1252'?>
       <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"
                 xmlns:h="http://java.sun.com/jsf/html"
                 xmlns:f="http://java.sun.com/jsf/core"
                 xmlns:af="http://xmlns.oracle.com/adf/faces"
                 xmlns:afh="http://xmlns.oracle.com/adf/faces/html"
                 xmlns:afc="http://xmlns.oracle.com/adf/faces/webcache">
         <jsp:output omit-xml-declaration="true" doctype-root-element="HTML"
                     doctype-system="http://www.w3.org/TR/html4/loose.dtd"
                     doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"/>
         <jsp:directive.page contentType="text/html;charset=UTF-8"/>
         <f:view>

   Tip: By default JDeveloper sets the page encoding to `windows-1252`. To set the default to a different page encoding: From the menu, choose Tools > Preferences. In the left-hand pane, select Environment if it is not already selected. Set Encoding to the preferred default.

2. Load the base resource bundle onto the page using the `loadBundle` tag, as shown in Example 14-12. The `basename` attribute specifies the fully qualified name of the resource bundle to be loaded. This resource bundle should be the one created for the default language of the application. The `var` attribute specifies the name of a request scope attribute under which the resource bundle will be exposed as a `Map`, and will be used in the EL expressions that bind component attributes to a key in the resource bundle.

   Example 14-12 The loadBundle Tag

       <f:loadBundle basename="oracle.srdemo.view.resources.UIResources"
                     var="res"/>

3. Bind all attributes that represent strings of static text displayed on the page to the appropriate key in the resource bundle, using the variable created in the previous step. Example 14-13 shows the code for the View button on the SRList page.

   Example 14-13 Binding to a Resource Bundle

       <af:commandButton text="#{res['srlist.buttonbar.view']}"
                         action="#{backing_SRList.viewButton_action}"
                         id="viewButton"/>

To register locales:

1. Open the `faces-config.xml` file and select the Overview tab in the editor window. The `faces-config.xml` file is located in the `<View_Project>/WEB-INF` directory.

2. In the JSF Configuration Editor, select Application.

3. If not already displayed, click the Local Config's triangle to display the Default Locale and Supported Locales fields.

4. For Default Locale, enter the ISO locale identifier for the default language to be used by the application. This identifier should represent the language used in the base resource bundle.

5. Add additional supported locales by clicking New. Click Help or press F1 for additional help in registering the locales.

To register the message bundle:

1. Open the `faces-config.xml` file and click on the Overview tab in the editor window. The `faces-config.xml` file is located in the `<View_Project>/WEB-INF` directory.

2. In the window, select Application.

3. For Message Bundle, enter the fully qualified name of the base bundle that contains messages to be used by the application.

## 14.4.2 How to Configure Optional Localization Properties for ADF Faces

Along with providing text translation, ADF Faces also automatically provides other types of translation, such as text direction and currency codes. The application will automatically display appropriately based on the user's selected locale. However, you can also manually set the following localization settings for an application in the `adf-faces-config.xml` file.

- `<currency-code>`: Defines the default ISO 4217 currency code used by `oracle.adf.view.faces.converter.NumberConverter` to format currency fields that do not specify a currency code in their own converter.

- `<number-grouping-separator>`: Defines the separator used for groups of numbers (for example, a comma). ADF Faces automatically derives the separator from the current locale, but you can override this default by specifying a value in this element. If set, this value is used by `oracle.adf.view.faces.converter.NumberConverter` while it parses and formats.

- `<decimal-separator>`: Defines the separator (for example, a period or a comma) used for the decimal point. ADF Faces automatically derives the separator from the current locale, but you can override this default by specifying a value in this element. If set, this value is used by `oracle.adf.view.faces.converter.NumberConverter` while it parses and formats.

- `<right-to-left>`: ADF Faces automatically derives the rendering direction from the current locale, but you can explicitly set the default page rendering direction by using the values `true` or `false`.

- `<time-zone>`: ADF Faces automatically uses the time zone used by the client browser. This value is used by `oracle.adf.view.faces.converter.DateTimeConverter` while it converts `Strings` to `Date`.

To configure optional localization properties:

1. Open the `adf-faces-config.xml` file. The file is located in the `<View_Project>/WEB-INF` directory.

2. From the Component Palette, drag the element you wish to add to the file into the Structure window. An empty element is added to the page.

3. Enter the desired value.

Example 14-14 shows a sample `adf-faces-config.xml` file with all the optional localization elements set.

Example 14-14 Configuring Currency Code and Separators for Numbers and Decimal Point

    <!-- Set the currency code to US dollars. -->
    <currency-code>USD</currency-code>

    <!-- Set the number grouping separator to period for German -->
    <!-- and comma for all other languages -->
    <number-grouping-separator>
     #{view.locale.language=='de' ? '.' : ','}
    </number-grouping-separator>

    <!-- Set the decimal separator to comma for German -->
    <!-- and period for all other languages -->
    <decimal-separator>
     #{view.locale.language=='de' ? ',' : '.'}
    </decimal-separator>

    <!-- Render the page right-to-left for Arabic -->
    <!-- and left-to-right for all other languages -->
    <right-to-left>
     #{view.locale.language=='ar' ? 'true' : 'false'}
    </right-to-left>

    <!-- Set the time zone to Pacific Daylight Savings Time -->
    <time-zone>PDT</time-zone>