Home | Download | PDF | API | FAQ | Search | Feedback | History

> ## Performing Localization

> As mentioned in Rendering Components for Selecting Multiple Values (page 339), data and messages in the Duke's Bookstore application have been localized for French, German, Spanish, and American English.

> This section explains how to produce the localized error messages as well as how to localize dynamic data and messages.

> Rendering Components for Selecting Multiple Values (page 339) describes how page authors access localized data from the page.

> If you are not familiar with the basics of localizing web applications, see Chapter 14.

> ### Creating a Resource Bundle

> A `ResourceBundle` contains a set of localized messages. To learn how to create a `ResourceBundle`, see

>     http://java.sun.com/docs/books/tutorial/i18n/index.html

> After you create the `ResourceBundle`, put it in the same directory as your classes. Much of the data for the Duke's Bookstore application is stored in a `ResourceBundle` called `BookstoreMessages,` located in `<INSTALL>``/javaeetutorial5/examples/web/bookstore/src/java/com/sun/bookstore/messages/`.

> ### Localizing Dynamic Data

> The Duke's Bookstore application has some data that is set dynamically in backing beans. Because of this, the beans must load the localized data themselves; the data can't be loaded from the page.

> The `message` method in `AbstractBean` is a general-purpose method that looks up localized data used in the backing beans:

>     protected void message(String clientId, String key) {
>       // Look up the requested message text
>       String text = null;
>       try {
>         ResourceBundle bundle =
>           ResourceBundle.getBundle("messages.BookstoreMessages",
>             context().getViewRoot().getLocale());
>         text = bundle.getString(key);
>       } catch (Exception e) {
>         text = "???" + key + "???";
>       }
>       // Construct and add a FacesMessage containing it
>       context().addMessage(clientId, new FacesMessage(text));
>     }

> This method gets the current locale from the `UIViewRoot` instance of the current request and loads the localized data for the messages using the `getBundle` method, passing in the path to the `ResourceBundle` and the current locale.

> The other backing beans call this method by using the key to the message that they are trying to retrieve from the resource bundle. Here is a call to the `message` method from `ShowCartBean`:

>     message(null, "Quantities Updated");

> ### Localizing Messages

> The JavaServer Faces API provides two ways to create messages from a resource bundle:

> - You can register the `ResourceBundle` instance with the application configuration resource file and use a message factory pattern to examine the `ResouceBundle` and to generate localized `FacesMessage` instances, which represent single localized messages. The message factory pattern is required to access messages that are registered with the `Application` instance. Instead of writing your own message factory pattern, you can use the one included with the Duke's Bookstore application. It is called `MessageFactory` and is located in `<INSTALL>``/javaeetutorial5/examples/web/bookstore6/src/java/com/sun/bookstore6/util/`.
> - You can use the `FacesMessage` class to get the localized string directly from the `ResourceBundle` instance.

> Registering Custom Error Messages (page 461) includes an example of registering a `ResourceBundle` in the application configuration resource file.

> #### Creating a Message with a Message Factory

> To use a message factory to create a message, follow these steps:

> 1. Register the `ResourceBundle` instance with the application. This is explained in Registering Custom Error Messages (page 461).
> 2. Create a message factory implementation. You can simply copy the `MessageFactory` class included with the Duke's Bookstore application to your application.
> 3. Access a message from your application by calling the `getMessage(FacesContext, String, Object)` method of the `MessageFactory` class. The `MessageFactory` class uses the `FacesContext` to access the `Application` instance on which the messages are registered. The `String` argument is the key that corresponds to the message in the `ResourceBundle`. The `Object` instance typically contains the substitution parameters that are embedded in the message. For example, the custom validator described in Implementing the Validator Interface will substitute the format pattern for the `{0}` in this error message:

> `Input must match one of the following patterns {0}`

> Implementing the Validator Interface gives an example of accessing messages.

> #### Using FacesMessage to Create a Message

> Instead of registering messages in the application configuration resource file, you can access the `ResourceBundle` directly from the code. The `validateEmail` method from the Coffee Break example does this:

>     ...
>     String message = "";
>     ...
>     message = CoffeeBreakBean.loadErrorMessage(context,
>       CoffeeBreakBean.CB_RESOURCE_BUNDLE_NAME,
>         "EMailError");
>     context.addMessage(toValidate.getClientId(context),
>       new FacesMessage(message));
>     ...

> These lines also call the `loadErrorMessage` to get the message from the `ResourceBundle`. Here is the `loadErrorMessage` method from `CoffeeBreakBean`:

>     public static String loadErrorMessage(FacesContext context,
>       String basename, String key) {
>       if ( bundle == null ) {
>         try {
>           bundle = ResourceBundle.getBundle(basename,
>             context.getViewRoot().getLocale());
>         } catch (Exception e) {
>           return null;
>         }
>       }
>       return bundle.getString(key);
>     }