JBoss.org Community Documentation
Seam makes it easy to build internationalized applications by providing several built-in components for handling multi-language UI messages.
Each user login session has an associated instance of
java.util.Locale
(available to the
application as a component named
locale
). Under normal circumstances,
you won't need to do any special configuration to set
the locale. Seam just delegates to JSF to determine
the active locale:
If there is a locale associated with the HTTP request
(the browser locale), and that locale is in the list
of supported locales from faces-config.xml
,
use that locale for the rest of the session.
Otherwise, if a default locale was specified in the
faces-config.xml
, use that locale
for the rest of the session.
Otherwise, use the default locale of the server.
It is
possible
to set the locale
manually via the Seam configuration properties
org.jboss.seam.international.localeSelector.language
,
org.jboss.seam.international.localeSelector.country
and
org.jboss.seam.international.localeSelector.variant
, but
we can't think of any good reason to ever do this.
It is, however, useful to allow the user to set the locale manually via the application user interface. Seam provides built-in functionality for overriding the locale determined by the algorithm above. All you have to do is add the following fragment to a form in your JSP or Facelets page:
<h:selectOneMenu value="#{localeSelector.language}">
<f:selectItem itemLabel="English" itemValue="en"/>
<f:selectItem itemLabel="Deutsch" itemValue="de"/>
<f:selectItem itemLabel="Francais" itemValue="fr"/>
</h:selectOneMenu>
<h:commandButton action="#{localeSelector.select}" value="#{messages['ChangeLanguage']}"/>
Or, if you want a list of all supported locales from
faces-config.xml
, just use:
<h:selectOneMenu value="#{localeSelector.localeString}">
<f:selectItems value="#{localeSelector.supportedLocales}"/>
</h:selectOneMenu>
<h:commandButton action="#{localeSelector.select}" value="#{messages['ChangeLanguage']}"/>
When this use selects an item from the drop-down, and clicks the button, the Seam and JSF locales will be overridden for the rest of the session.
JSF supports internationalization of user interface labels and
descriptive text via the use of <f:loadBundle />
.
You can use this approach in Seam applications. Alternatively, you can
take advantage of the Seam messages
component to
display templated labels with embedded EL expressions.
Seam provides a java.util.ResourceBundle
(available
to the application as a org.jboss.seam.core.resourceBundle
).
You'll need to make your internationalized labels available via this special
resource bundle. By default, the resource bundle used by Seam is named
messages
and so you'll need to define your labels
in files named messages.properties
,
messages_en.properties
,
messages_en_AU.properties
, etc. These
files usually belong in the WEB-INF/classes
directory.
So, in messages_en.properties
:
Hello=Hello
And in messages_en_AU.properties
:
Hello=G'day
You can select a different name for the resource bundle by setting
the Seam configuration property named
org.jboss.seam.core.resourceLoader.bundleNames
. You can even specify
a list of resource bundle names to be searched (depth first) for
messages.
<core:resource-loader>
<core:bundle-names>
<value>mycompany_messages</value>
<value>standard_messages</value>
</core:bundle-names>
</core:resource-loader>
If you want to define a message just for a particular page, you
can specify it in a resource bundle with the same name as the
JSF view id, with the leading /
and trailing
file extension removed. So we could put our message in
welcome/hello_en.properties
if we only needed
to display the message on /welcome/hello.jsp
.
You can even specify an explicit bundle name in pages.xml
:
<page view-id="/welcome/hello.jsp" bundle="HelloMessages"/>
Then we could use messages defined in HelloMessages.properties
on /welcome/hello.jsp
.
If you define your labels using the Seam resource bundle, you'll
be able to use them without having to type <f:loadBundle ... />
on every page. Instead, you can simply type:
<h:outputText value="#{messages['Hello']}"/>
or:
<h:outputText value="#{messages.Hello}"/>
Even better, the messages themselves may contain EL expressions:
Hello=Hello, #{user.firstName} #{user.lastName}
Hello=G'day, #{user.firstName}
You can even use the messages in your code:
@In private Map<String, String> messages;
@In("#{messages['Hello']}") private String helloMessage;
The facesMessages
component is a super-convenient
way to display success or failure messages to the user. The functionality
we just described also works for faces messages:
@Name("hello")
@Stateless
public class HelloBean implements Hello {
@In FacesMessages facesMessages;
public String sayIt() {
facesMessages.addFromResourceBundle("Hello");
}
}
This will display Hello, Gavin King
or G'day, Gavin
,
depending upon the user's locale.
There is also a session-scoped instance of java.util.Timezone
,
named org.jboss.seam.international.timezone
, and a Seam component for changing
the timezone named org.jboss.seam.international.timezoneSelector
. By default,
the timezone is the default timezone of the server. Unfortunately, the JSF specification
says that all dates and times should be assumed to be UTC, and displayed as UTC, unless
a timezone is explicitly specified using <f:convertDateTime>
.
This is an extremely inconvenient default behavior.
Seam overrides this behavior, and defaults all dates and times to the Seam timezone.
In addition, Seam provides the <s:convertDateTime>
tag which
always performs conversions in the Seam timezone.
Seam applications are also very easily skinnable. The theme API is very similar to the localization API, but of course these two concerns are orthogonal, and some applications support both localization and themes.
First, configure the set of supported themes:
<theme:theme-selector cookie-enabled="true">
<theme:available-themes>
<value>default</value>
<value>accessible</value>
<value>printable</value>
</theme:available-themes>
</theme:theme-selector>
Note that the first theme listed is the default theme.
Themes are defined in a properties file with the same name as the theme.
For example, the default
theme is defined as a set of
entries in default.properties
. For example,
default.properties
might define:
css ../screen.css template /template.xhtml
Usually the entries in a theme resource bundle will be paths to CSS styles or images and names of facelets templates (unlike localization resource bundles which are usually text).
Now we can use these entries in our JSP or facelets pages. For example, to theme the stylesheet in a facelets page:
<link href="#{theme.css}" rel="stylesheet" type="text/css" />
Or, when the page definition resides in a subdirectory:
<link href="#{facesContext.externalContext.requestContextPath}#{theme.css}"
rel="stylesheet" type="text/css" />
Most powerfully, facelets lets us theme the template used by a <ui:composition>
:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
template="#{theme.template}">
Just like the locale selector, there is a built-in theme selector to allow the user to freely switch themes:
<h:selectOneMenu value="#{themeSelector.theme}">
<f:selectItems value="#{themeSelector.themes}"/>
</h:selectOneMenu>
<h:commandButton action="#{themeSelector.select}" value="Select Theme"/>
The locale selector, theme selector and timezone selector all support
persistence of locale and theme preference to a cookie. Simply set the
cookie-enabled
property in components.xml
:
<theme:theme-selector cookie-enabled="true">
<theme:available-themes>
<value>default</value>
<value>accessible</value>
<value>printable</value>
</theme:available-themes>
</theme:theme-selector>
<international:locale-selector cookie-enabled="true"/>