This article introduces the mechanisms for internationalising a web application built using JavaServer Faces (JSF) application and the Seam Framework for language localisation (L10N), expanding on the brief introduction in the Seam manual, Chapter 16. Internationalization, localization and themes.
In the most simple case, as described in the Seam manual, you define a user-interface text labels in a properties file for each localisation.
# messages.properties - English localisation order = Order
# messages_fr.properties - French localisation order = Commande
Then display the label in a Facelets view using an Expression Language (EL) expression that uses the messages Seam component.
<h1>#{messages.order}</h1>
This syntax works, because the Messages component exposes a java.util.Map interface, keyed on the message key, which means that the EL expression above references the message for the Map key orders.
In practice, it is common to define hundreds or thousands of messages for an application user-interface, and to use a dot-hierarchy notation for the message keys, to organise them. For example:
model.Order = Order model.Order.carrierReference = Carrier reference model.Order.carrierReference.help = e.g. package tracking number. model.Order.deliveryAddress = Delivery address model.Order.dueDate = Due date
In this case, an expression like #{messages.model.Order} will no longer work: this is parsed as a reference to an Order property on the #{messages.model} map entry. If you try this you get the error:
javax.el.ELException: /example.xhtml: Property 'Order' not found on type java.lang.String
Instead, you have to use the more explicit Map look-up syntax:
<h1>#{messages['model.Order']}</h1>
So far, this is pretty neat, in both senses of the word.
In the application we are currently building, about a quarter of the messages contain a placeholder, whose value is inserted dynamically. For example:
# {0} date format, e.g. yyyy-MM-dd
action.order.orderDate.invalid=Order date must be in {0} format
You can replace the placeholder, as per java.text.MessageFormat, by using the JSF h:outputFormat tag. Unfortuntely, this is somewhat verbose:
<h:outputFormat value="#{messages['action.order.orderDate.invalid']}">
<!-- Insert the application date format from the configuration. -->
<f:param value="#{configuration.dateFormat}"/>
</h:outputFormat>
Note that the outputFormat tag works independently of the message look-up mechanism, so you could insert the message directly in its value attribute. For example, you can output the current year in a Facelets view by using the MessageFormat date format style to format the Seam currentDatetime component:
<!-- Output the current year -->
<h:outputFormat value="{0,date,yyyy}">
<f:param value="#{currentDatetime}"/>
</h:outputFormat>
Sooner or later, you are going to want to do one of the following things.
Unfortunately, these are not currently possible with the facilities in JSF, Seam and Facelets. You can either vote for javaserverfaces-spec-public issue 517 and wait for a new version of JSF 2, or you can write your own implementations.
Peter Hilton is a senior software developer at Lunatech Research.
Please send comments on this article to editorial@lunatech.com.
Copyright © 2005-2012, Lunatech Research B.V. All rights reserved.