This post describes a custom JavaServer Faces component for controlling the flow layout of controls based on localised strings.
The h:outputFormat
component
The h:outputFormat control is a standard JSF control for formatting strings. It is often used with resource bundles.
This is a faces-config.xml
declaration for adding
two languages to a JSF application and defining a resource bundle resources/messages.properties
.
<application> <locale-config> <default-locale>en</default-locale> <supported-locale>fr</supported-locale> </locale-config> <message-bundle>resources.messages</message-bundle> </application>
The bundle provides the following value:
staticCalc={0} divided by {1} is {2,number,#0.000}
By loading the resource bundle in a view, we can insert parameter
values into the string using h:outputFormat
:
<h:outputFormat value="#{bundle.staticCalc}"> <f:param value="1" /> <f:param value="3" /> <f:param value="#{1 div 3}" /> </h:outputFormat>
This is great, but h:outputFormat
only accepts
parameters as children.
Introducing the i18n:formatPanel
custom component
Lets say we want to build something like this in JSF:
This is straightforward enough. But we have a problem when it comes to localisation. Grammatical differences between languages may require the controls to appear in any order, depending on the user's Locale. The simplest approach is to redesign the dialog to tabular form. The old-school approach would be to do a separate version for each language, but this is crude and repetitive. We need a custom control.
You can find information on writing JSF controls in the Java EE 5 Tutorial.
The custom control is made up of the following artifacts:
- HtmlFormatPanel. A concrete component. This bean-like class allows programmatic access to properties in backing beans. The core logic of the control (a panel) already exists in the API, so the class just extends UIPanel.
- FormatPanelRenderer. The renderer. This emits the HTML and controls how child components are rendered.
- META-INF/faces-config.xml. The file for registering the component with the JSF implementation.
- FormatPanelTag. The JSP custom tag implementation.
- META-INF/i18n.tld. The tag library definition file for use with JSPs.
- META-INF/i18n.taglib.xml. The tag library for Facelets, an alternative view technology to JSPs that is included as standard in JSF 2.0.
This component works much like h:outputFormat
, but
accepts a wider range of children.
Using the component
To demonstrate the component, a new string resource is added to messages.properties
:
#the translatable string form behind a formatPanel activeCalc={0} divided by {1} {2} {3,number,#0.000}
Also, a translated version of the file (messages_fr.properties
)
is added where the sentence structure has changed:
#Let's pretend this is French activeCalc=Sacr\u00E9 Bleu! {3,number,#0.000} {2} {1} by divided {0}
In order to use the component in a page, the tag library must be declared. (The exact form will vary depending the view technology you are using; see the existing JSF declarations for examples.)
xmlns:i18n="http://illegalargumentexception.googlecode.com/i18n"
Here, the sentence is built using a mixture of input components, output components and parameters combined with the string from the resource bundle:
<i18n:formatPanel formatString="#{bundle.activeCalc}"> <h:inputText value="#{numberBean.a}" /> <h:inputText value="#{numberBean.b}" /> <h:commandButton action="#{numberBean.calculate}" value="equals" /> <f:param value="#{numberBean.result}" /> </i18n:formatPanel>
The order of the children corresponds to the order of the parameters in the resource string.
The component as it appears when the browser language preference is set to French:
Sources
All the sources are available in a public Subversion repository.
Repository:
http://illegalargumentexception.googlecode.com/svn/trunk/code/java/
License: MIT
Project: JsfFormatPanel
You can download a binary version here: jsfFormatPanel_1.0.zip.
Notes
This code was cursorily tested using JSPs on JBoss 4.2.2 (JSF 1.2) and Facelets on Glassfish 2.1 (upgraded to use JSF 2.0).
No doubt a similar control has already been implemented for a commercial or free component library. If you know of one, go add an answer to the stackoverflow.com question that inspired this post. Such a control is likely to have undergone more testing than I have put into this one.
No comments:
Post a Comment
All comments are moderated