java.net member

Rechercher dans ce site

JSF2 and Internationalization (I18N)

>> 07 September 2010

JSF as many Java based products is designed for easy internationalization experience. One of the main feature used in localizing components is the Message Bundles.

Message Bundles are simply text files (properties files), and composed of key/value pairs. These are easy to use. The big picture is to have one properties file per language that you want to use, for instance one for English, another for French, Arabic, Russian or whatever else language, you load a MessageBundle with the current locale and get values from files. You can at any time add other files and merely other languages.

In this tutorial I'll take a sample example of an inscription form, and see how to internationalize it. I'll put only two components for the name and first name to have a compact, clear sources. I'll take two languages as example English and French

Message Bundles
We have two files, for English and French, you can give these files any name you want, with some restrictions : every file must have a suffix to identify the language and it must have ".properties" extension

I'll call my files localizedMessages_fr.properties for the French file and
localizedMessages_en.properties for the English. So the base name for every Message Bundle (or properties file) is localizedMessages. You have a suffix part to identify language : an underscore followed by the lowercase, two-letter ISO-639 language code (_fr and _en)

localizedMessages_en.properties
inscription_name=Name
inscription_firstName=First-Name

localizedMessages_fr.properties
inscription_name=Nom
inscription_firstName=Prénom

You need to note here that in the French version, "inscription_firstName" has "Prénom" as a value, this word has a special character "é". Message Bundle has to be in ASCII. To use Unicode for special characters you have two ways.

  1. Leave your properties file as is and use a program included with the JDK "native2ascii". To use it add JAVA_HOME/bin to your path and type
  2.        native2ascii file_with_special_char unicode_file
  3. Instead of using native2ascii you can replace the special character in the file with it's Unicode code for instance "é" is "\u00e9" and Prénom became  Pr\u00e9nom

Where to put Message Bundles
Save the files together with your classes, in Eclipse for example, in src/com/java_javafx/ka/ (Any way they must at the end be with the compiled classes. The properties file is loaded by the class loader)


Declare the files in your application
You can declare the Message Bundles in two ways.
1.The simplest way is to supply the declaration in WEB-INF/faces-config.xml

<faces-config>
...
<application>
<resource-bundle>
<base-name>com.java_javafx.ka.localizedMessages</base-name>
<var>msgs</var>
</resource-bundle>
</application>
...
</faces-config>

2.Instead of using a global resource bundle declaration, you can add the f:load-Bundle element to each JSF page that needs access to the bundle, like this:

<f:loadBundle basename="com.java_javafx.ka.localizedMessages" var="msgs"/>

In either cases, the messages in the bundle are accessible through a map variable with the name "msgs".

How to use these files
In any .jsf file use the variable defined in faces-config.xml or with <f:loadBundle. The variable is called here "msgs". This variable is to be used  with a key defined in a properties file

For instance to get the localized string for "name" use #{msgs.name}

How the locale is selected
  • As part of the internationalization support in Java, the bundle that matches the current locale is automatically loaded.
  • The current locale can be selected, for instance by selecting the preferred language in the browser.

Declare the accepted locales in the application
In WEB-INF/faces-config.xml
<faces-config>
...
<application>
...
<!-- set locales -->
<locale-config>
<default-locale>en</default-locale>
<supported-locale>fr</supported-locale>

</locale-config>
<!-- end locals -->
</application>
</faces-config>

Let's get an example

faces-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
 version="2.0">

<application>


<resource-bundle>
<base-name>com.java_javafx.ka.localizedMessages</base-name>
<var>msgs</var>
</resource-bundle>
<!-- set locales -->
<locale-config>
<default-locale>en</default-locale>
<supported-locale>fr</supported-locale>
</locale-config>
<!-- end locals -->
</application>

 <!-- navigation for inscription -->
 <navigation-rule>
 <from-view-id>/inscriptionForm.xhtml</from-view-id>
 <navigation-case>
 <from-outcome>true</from-outcome>
 <to-view-id>/result.xhtml</to-view-id>
  </navigation-case>
  </navigation-rule>
 <!-- end inscription -->
 </faces-config>


Person.java

package com.java_javafx.ka;

import java.io.Serializable;
import javax.faces.bean.*;




/**
 * @author Kaesar ALNIJRES
 *
 */
@ManagedBean(name="person")
@SessionScoped
public class Person implements Serializable {
    private String name="";
    private String firstName="";
  
    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name the name to set
     */
    public void setName(String name) {
      
        this.name = name;
    }

    /**
     * @return the firstName
     */
    public String getFirstName() {
        return firstName;
    }

    /**
     * @param firstName the firstName to set
     */
    public void setFirstName(String firstName) {
         this.firstName=firstName;
    }
public String validate()
{
    return "true";
}
}



InscriptionForm.xhtml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"

      xmlns:h="http://java.sun.com/jsf/html">


<h:head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

</h:head>
<body>
<f:view>

<h:form prependId="false" id="form">

<h:panelGrid columns="1">

<h:panelGroup><h:outputText value="#{msgs.inscription_name}" />
<h:inputText value="#{person.name}" id="name"/>
</h:panelGroup>

<h:panelGroup>
<h:outputText value="#{msgs.inscription_firstName}" />
<h:inputText value="#{person.firstName}"  id="firstName"/>
</h:panelGroup>
</h:panelGrid>

<h:commandButton id="cmdBtn" value="OK" action="#{person.validate}" />

</h:form>

</f:view>
</body>
</html>

Display
When French is the preferred language in the browser. And English






What if we want to use localized Strings in the bean
  1. 1.Get the locale used by the browser :

    FacesContext context = FacesContext.getCurrentInstance();
    Locale locale=context.getViewRoot().getLocale();
  2. Load the ResourceBundle associated with this locale, using the full path and base name :

    rs=ResourceBundle.getBundle("com.java_javafx.ka.localizedMessages",locale);
  3. You can get any value using it's key in the properties file :

    rs.getString("inscription_name");



Person.java
With 2 added methods, one to load Resource Bundle (for instance in a method annotated with @PostConstruct, if you want a call once init method), the other to get a greeting message.


package com.java_javafx.ka;

import java.io.Serializable;
import java.util.Locale;
import java.util.ResourceBundle;

import javax.annotation.PostConstruct;
import javax.faces.bean.*;
import javax.faces.context.FacesContext;




/**
 * @author Kaesar ALNIJRES
 *
 */
@ManagedBean(name="person")
@SessionScoped
public class Person implements Serializable {
    private String name="";
    private String firstName="";
    private ResourceBundle rs;
    private String greeting;
   
    @PostConstruct
    public  void init() {
   
       
       
        FacesContext context = FacesContext.getCurrentInstance();
        Locale locale=context.getViewRoot().getLocale();
        rs=ResourceBundle.getBundle("com.java_javafx.ka.localizedMessages",locale);
       
       
    }
   
   
    /**
     * @return the greeting
     */
    public String getGreeting() {
        greeting=rs.getString("inscription_thanks");
        return greeting;
    }


    /**
     * @param greeting the greeting to set
     */
    public void setGreeting(String greeting) {
        this.greeting = greeting;
    }


    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name the name to set
     */
    public void setName(String name) {
       
        this.name = name;
    }

    /**
     * @return the firstName
     */
    public String getFirstName() {
        return firstName;
    }

    /**
     * @param firstName the firstName to set
     */
    public void setFirstName(String firstName) {
      this.firstName=firstName;
    }
public String validate()
{
    return "true";
}
}

Messages with Variable Parts
It's possible to add localized Strings in MessageBundles (properties files)and pass them some parameters from the calling page. They are Strings with placeholders like "hello {0}"

Placeholders are numbered {0}, {1}, {2}, and so on.

We'll get the greeting message from the bean in "result.xhtml" using <f:outputFormat, we pass a parameter to the value of "inscription_thanks" in properties files. In the example the parameter use the first name and name used in the inscription. To pass a parameter to <f:outputFormat. Use <f:param

Note:
The h:outputFormat tag uses the MessageFormat class from the standard library to
format the message string. That class has several features for locale-aware
formatting.

resultat.xhtml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title></title>
</head>
<body>
<f:view>

<h:outputFormat value="#{person.greeting}">
<f:param value="#{person.firstName} #{person.name}"/>
</h:outputFormat>
</f:view>
</body>
</html>

localizedMessages_en.properties
inscription_name=Name
inscription_firstName=First-Name
inscription_thanks=Thank you for your inscription {0}

localizedMessages_fr.properites
inscription_name=Nom
inscription_firstName=Pr\u00e9nom
inscription_thanks=Merci {0} inscription termin\u00e9e



0 comments:

Post a Comment

  © Blogger template Simple n' Sweet by Ourblogtemplates.com 2009

Back to TOP