Java & internationalization / localization

by Piotr Likus on January 25, 2015

Introduction

Below you will find necessary tips to implement internationalized texts in Java / JSF applications.

Main areas:

  • message files (file name, file format, ide)
  • Java code: resource bundle + bean
  • JSF: define message bundle (faces-config.xml), extract texts from JAR
  • PrimeFaces: JavaScript + XHTML / resource bundle + message bundle, extract texts from JAR

Define resource(s)

Message files

Messages are stored inside *.properties files with name pattern Name_xx.properties where xx is locale code like “en” (English) or “fr” (French). Files should be stored under “src” directory directly or inside selected package. File format is a standard “.properties” format, encoding “ISO 8859-1”, UTF-8 can be used with additional class (see below). Default encoding (understood by Netbeans, IntelliJ IDEA) uses Unicode characters in form u00f1a, so it’s safe for each language, it just doesn’t look nice outside of IDE when you view the messae file.

Example file for English (file name “MyMessages_en.properties”):

auto.config.successful=Auto-config successful!
auto.config.failed=Auto-config failed!
error=Error
successful=Successful
reg.welcome.mail=Welcome to '{'service-name'}'n
n
Please keep this e-mail for your records. Your account information is asn
followsn:

Message bundle

  • used to replace build-in messages
  • define in faces-config.xml

    <application>
            <locale-config>
                   <default-locale>en</default-locale>
                   <supported-locale>pl</supported-locale>
           </locale-config>
           <message-bundle>ApplicationResource</message-bundle>
    </application>
    

Resource bundle

  • used to define own messages (one or more sets)

  • define in faces-config.xml (for resource files src/com.dev/Messages_xx.properties)

    <application>
        <locale-config>
            <default-locale>en</default-locale>
            <supported-locale>pl</supported-locale>
        </locale-config>
        <resource-bundle>
        <base-name>com.dev.Messages</base-name>
        <var>msgs</var>
        </resource-bundle>
    </application>
    
  • can be defined as class name that supports reading of texts:

    <resource-bundle>
        <base-name>com.dev.utils.ResourceBundleUtf8</base-name>
        <var>msg</var>
    </resource-bundle>
    

loadBundle

  • use to specify message bundle at document (XHTML) level

  • inside XHTML write:

    <f:loadBundle   var="msg"     basename="ApplicationResource"/>
    

Resource encoding

  • normally you can use only ISO 8859-1 in properties files
  • if you want something more, you can use “native2ascii” command

    /path/to/jdk/bin/native2ascii -encoding UTF-8 text_nl.utf8.properties text_nl.properties
    
  • example output:

    some.dutch.text = u00c9u00e9n van de wijken van Curau00e7ao heet Saliu00f1a
    
  • in order to use UTF-8 inside properties you must use own ResourceBundle class:

    • http://jdevelopment.nl/internationalization-jsf-utf8-encoded-properties-files/
  • you can load texts from database

    • http://blog.eisele.net/2012/08/resource-bundle-tricks-and-best.html

Use in XHTML

  • select locale in XHTML

    <f:view locale="fr">
    
  • example using EL with var “msg” and message code “welcome.general”

    <h:outputLabel value="#{msg['welcome.general']}" />
    
  • example with variable fragments (parameters) inside text

    <h:outputFormat value="Hello {0}!.">                
       <f:param value="World" />
    </h:outputFormat>
    
  • example with escaping value

    <h:outputFormat value="#{msg['welcome']}" escape="false">
        <f:param value="#{fn:escapeXml(param)}"/>
    </h:outputFormat>
    

HTML tags inside texts

  • using getBookmarkableURL

    <h:outputFormat value="#{msg['activation.failed.desc']}" escape="false">
        <f:param value="&lt;a href='#{facesContext.application.viewHandler.getBookmarkableURL(facesContext, '/register', null, false)}'&gt;#{msg['register']}&lt;/a&gt;" />
    </h:outputFormat>
    
  • using encoded code

    <h:outputFormat value="#{msg['activation.failed.desc']}" escape="false">
        <f:param value="&lt;a href='#{request.contextPath}/register.xhtml'&gt;#{template['activation.register']}&lt;/a&gt;" />
    </h:outputFormat>
    
  • using omniFaces o:param

    <h:outputFormat value="#{msg['activation.failed.desc']}" escape="false">
        <o:param><h:link outcome="register" value="#{template['activation.register']}" /></o:param>
    </h:outputFormat>
    
  • using backing bean

        <h:outputFormat value="#{msg['activation.failed.desc']}"
                        escape="false">
            <f:param value="#{activateController.textLinkRegister}" />
            <f:param value="#{activateController.textLinkEnd}" />
            <f:param value="#{activateController.textLinkHome}" />
            <f:param value="#{activateController.textLinkEnd}" />
        </h:outputFormat>
    

Language selection

Session storage

    // From: http://jdevelopment.nl/internationalization-jsf-utf8-encoded-properties-files/
    package com.dev.beans;

    import java.util.Locale;

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

    @ManagedBean
    @SessionScoped
    public class LocaleBean {
        private Locale locale = FacesContext.getCurrentInstance().getViewRoot().getLocale();

        public Locale getLocale() {
            return locale;
        }

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

        public void setLanguage(String language) {
            this.locale = new Locale(language);
        }
    }

Dynamic locale in XHTML

  • code example

    <f:view locale="#{localeBean.locale}">
    

Change global language in code

   public String changeLanguage(Locale locale) {
      FacesContext.getCurrentInstance().getViewRoot().setLocale(locale);

In-code usage of texts

  • define helper class for reading texts from resource bundle

    // From: JSF 2.0 Cookbook, Anghel Leonard, PACKT Publishing, 2010
    public class LocaleHelper {
        protected static ClassLoader getClassLoader(Object defaultObject)
        {
            ClassLoader loader =
                    Thread.currentThread().getContextClassLoader();
            if (loader == null) {
                loader = defaultObject.getClass().getClassLoader();
            }
            return loader;
        }
        public static String getLocaleString(
                String bundle,
                String key,
                Object parameters[],
                Locale locale) {
            String message = null;
            ResourceBundle resourceBundle = ResourceBundle.getBundle(bundle,
                    locale, getClassLoader(parameters));
            try {
                message = resourceBundle.getString(key);
            } catch (MissingResourceException e) {
                message = "ERROR MESSAGE!";
            }
            if (parameters != null) {
                StringBuffer stringBuffer=new StringBuffer();
                MessageFormat messageFormat = new MessageFormat(message,
                        locale);
                message = messageFormat.format(parameters, stringBuffer,
                        null).toString();
            }
            return message;
        }
    }
    
  • usage

    // From: JSF 2.0 Cookbook, Anghel Leonard, PACKT Publishing, 2010
    FacesContext context = FacesContext.getCurrentInstance();
    
    //get default locale
    Locale myLoc = context.getViewRoot().getLocale();
    
    String message = LocaleHelper.getLocaleString(
            context.getApplication().getMessageBundle(),
            "USER_AGE", null, myLoc);
    
  • read application message bundle name

    public static String getMessageBundle(FacesContext context) {
      return context.getApplication().getMessageBundle();
    }
    

JSF

  • define message bundle in faces-config.xml
  • extract messages from file: javax.faces.jarjavaxfacesMessages_en.properties
  • translate these messages and include in your own message bundle file

PrimeFaces

  • extract messages from file: primefaces-a.b.jarorgprimefacesMessages_en.properties

  • add JS script with texts from Primefaces page: https://code.google.com/p/primefaces/wiki/PrimeFacesLocales

    • upload to resources/default/js/primefaces_xx.js
    • add to page <h:outputScript library="default" name="js/primefaces_pl.js" />
  • add message attributes in HTML:

    • p:inputText requeredMessage
    • p:dataTable emptyMessage
    • p:password *Label
Fonts by Google Fonts. Icons by Fontello. Full Credits here »