Java EE 6 - JSF 2.0 Internationalization with session scoped language switcher bean

Java EE 6 – JSF 2.0 Internationalization with session scoped language switcher bean

Today I will present a short tutorial on how to implement internationalization feature in your JSF 2.0 web application. This tutorial is based on the previous one called Java EE 6 – Getting Started (maven, CDI and persistence) ready project.

We will continue from that point and add simple i18n feature with language switching capabilities.
First of all you need to define available languages for your application in faces-config.xml found in (src/main/webapp/WEB-INF/faces-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- This file is not required if you don't need any extra configuration. -->
<faces-config version="2.0"
   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">

   <!-- Write your navigation rules here. You are encouraged to use CDI for creating @Named managed beans. -->
<application>      
        <locale-config>
            <default-locale>en</default-locale>
            <supported-locale>pl</supported-locale>
        </locale-config>
        <resource-bundle>
            <base-name>com.softwarepassion.j2ee6tutorial.messages</base-name>
            <var>msg</var>
        </resource-bundle>
    </application>
</faces-config>

As you can see, I have defined support for two languages here, ‘pl’ – Polish and English which is the default one.
In order to use your language specific messages you need to define ‘.properties’ file for each single language.
Place your files in /src/main/resources/name/of/your/package/*.properties’ We will start with the english version first (messages.properties):

I have added just one single property for the string key called ‘Title’

Do the same for the second properties file called ‘messages_pl_PL.properties’ and place the file in the same location. As you have probably noticed already, the file for each language must follow simple naming convention like messages_+your language code+.properties

Now its time to actually implement i18n handling logic. To save selected language for each user we will use the most natural option which is a session scoped JSF managed bean.

import java.io.Serializable;
import java.util.Locale;
import java.util.logging.Logger;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;



/**
 * Used for managing i18n in application for each user
 * @author Krzysztof Grajek
 *
 */

@ManagedBean
@SessionScoped
public class LanguageSwitcher implements Serializable {

    private static final long serialVersionUID = 2756934361134603857L;
    private static final Logger LOG = Logger.getLogger(LanguageSwitcher.class.getName());
   
    private Locale locale = FacesContext.getCurrentInstance().getViewRoot().getLocale();

    public Locale getLocale() {
        return locale;
    }

    public String getLanguage() {
        return locale.getLanguage();
    }

    /**
     * Sets the current {@code Locale} for each user session
     *
     * @param languageCode - ISO-639 language code
     */

    public void changeLanguage(String language) {
        locale = new Locale(language);
        FacesContext.getCurrentInstance().getViewRoot().setLocale(locale);
    }
   
}

Once we have properties files defined, created our session scoped managed JSF bean, its time to wire it up in your xhtml documents.
I will add all language switching code inside my xhtml template which is used throughout the project as the template for all xhtml documents.
Locate your template file called ‘default.xhtml’ (src/main/webapp/WEB-INF/templates/default.xhtml) and add change it to the following:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html lang="#{languageSwitcher.language}"
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:f="http://java.sun.com/jsf/core"
        xmlns:h="http://java.sun.com/jsf/html"
        xmlns:ui="http://java.sun.com/jsf/facelets">
   <f:view locale="#{languageSwitcher.locale}">
   <h:head>
      <title>Java EE 6 Starter Application</title>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
      <h:outputStylesheet name="css/screen.css"/>
   </h:head>
   <h:body>
      <div id="container">
         <div id="content">
            <div id="sidebar">
               <h3>Language switcher:</h3>
               <h:form id="langauge_form">
                  <h:commandLink action="#{languageSwitcher.changeLanguage('pl')}" value="Polski" /> |
                  <h:commandLink action="#{languageSwitcher.changeLanguage('en')}" value="English" />
               </h:form>
            </div>
            <ui:insert name="content">
               [Template content will be inserted here]
            </ui:insert>
         </div>
         <div id="footer">
            <h:graphicImage value="/resources/gfx/weld.png" alt="Weld logo"/>
            <p>
               This project was generated from a Maven archetype maintained by the Weld team.<br/>
               Weld is the reference implementation of CDI, released under the Apache License, Version 2.0.<br/>
            </p>
         </div>
      </div>
   </h:body>
   </f:view>
</html>

Final webpage with language switcher:

You can download the project files from here: sp_J2EE6Tutorial

5 responses on “Java EE 6 – JSF 2.0 Internationalization with session scoped language switcher bean

  1. Geraldo p. April 7, 2011 at 7:45 pm

    Thanks for this article! It’s helpful 🙂

  2. Paweł Dyda April 7, 2011 at 7:55 pm

    I just like to point out few things:

    1. It is generally very easy to configure string externalization using JBoss Tools (you won’t have to manually modify faces-config.xml).

    2. You hardcoded language name, which is not very good idea. Instead you should use locale.getDisplayName(locale) to obtain language name in given locale (you would need to enumerate suppoorted locales, which doesn’t seem to be a problem, does it?). I suggest getDisplayName(locale) instead of getDisplayLanguage(locale) because i.e. Portuguese (Brazil) and Portuguese (Portugal) are totally different languages (more or less). The same applies to Chinese Traditional and Chinese Simplified.

    3. Your language switching method won’t work correctly for locales with defined country name (see Portuguese Brazil above), because locale.toString() will give you something like pt_BR and Locale constructor is not so smart to include country name (not saying anything about locale variant) – you have to split it by yourself and pass it as another parameter.

    4. You have multiple hardcoded strings in your tutorial…

    Cheers,
    Paweł.

  3. admin April 7, 2011 at 9:27 pm

    Wow, man you are my localization guru :). Thanks for the tips!

  4. admin April 7, 2011 at 9:29 pm

    Heh, now I got it, saw your profile on LinkedIn. Keep up the good work!

  5. Kamal July 26, 2011 at 9:25 pm

    Hi guys;
    I have a jsf webapp and I am able to do i18n for arabic, but the only problem is that Arabic is right to left and I can’t find a way to switch the page orientation.
    Any ideas is greatly appreciated.

    Kamal

Leave a Reply