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
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.
- 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 native2ascii file_with_special_char unicode_file
- 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
1.The simplest way is to supply the declaration in WEB-INF/faces-config.xml
<faces-config>
...
<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:
In either cases, the messages in the bundle are accessible through a map variable with the name "msgs".
For instance to get the localized string for "name" use #{msgs.name}
- 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.
<faces-config>
...
<application>
...
<!-- set locales -->
</application>
</faces-config>
Let's get an example
<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>
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";
}
}
<!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>
- 1.Get the locale used by the browser :
FacesContext context = FacesContext.getCurrentInstance();
Locale locale=context.getViewRoot().getLocale(); - Load the ResourceBundle associated with this locale, using the full path and base name :
rs=ResourceBundle.getBundle("com.java_javafx.ka.localizedMessages",locale);
- You can get any value using it's key in the properties file :
rs.getString("inscription_name");
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
/**
* @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";
}
}
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.
<?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>
</body>
</html>
inscription_firstName=First-Name
inscription_thanks=Thank you for your inscription {0}
inscription_firstName=Pr\u00e9nom
inscription_thanks=Merci {0} inscription termin\u00e9e
0 comments:
Post a Comment