<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd">
<chapter id="i18n">
   <title>Internationalization, localization and themes</title>

   <para>
      Seam makes it easy to build internationalized applications. First, let's 
      walk through all the stages needed to internationalize and localize your 
      app. Then we'll take a look at the components Seam bundles.
   </para>

   <section>
      <title>Internationalizing your app</title>

      <para>
         A JEE application consists of many components and all of them must be 
         configured properly for your application to be localized.
      </para>

      <para>
         Starting at the bottom, the first step is to ensure that your database 
         server and client is using the correct character encoding for your 
         locale. Normally you'll want to use UTF-8. How to do this is outside
         the scope of this tutorial.
      </para>

      <section>
         <title>Application server configuration</title>

         <para>
            To ensure that the application server receives the request 
            parameters in the correct encoding from client requests you have to 
            configure the tomcat connector. If you use Tomcat or JBoss AS, add
            the <literal>URIEncoding="UTF-8"</literal> attribute to the 
            connector configuration. For JBoss EAP AS 4.3 change 
            <literal>${JBOSS_HOME}/server/production/deploy/jboss-web.deployer/server.xml</literal>:
         </para>

         <programlisting role="XML">&lt;Connector port="8080" URIEncoding="UTF-8"/&gt;</programlisting>

         <para>
            There is alternative which is probably better. You can tell JBoss AS
            that the encoding for the request parameters will be taken from the
            request:
         </para>

         <programlisting role="XML">&lt;Connector port="8080" useBodyEncodingForURI="true"/&gt;</programlisting>
      </section>

      <section>
         <title>Translated application strings</title>

         <para>
            You'll also need localized strings for all the <emphasis>messages</emphasis>
            in your application (for example field labels on your views). First 
            you need to ensure that your resource bundle is encoded using the 
            desired character encoding. By default ASCII is used. Although ASCII 
            is enough for many languages, it doesn't provide characters for all 
            languages.
         </para>

         <para>
            Resource bundles must be created in ASCII, or use Unicode escape 
            codes to represent Unicode characters. Since you don't compile a 
            property file to byte code, there is no way to tell the JVM which 
            character set to use.  So you must use either ASCII characters or 
            escape characters not in the ASCII character set.
            You can represent a Unicode character in any Java file using \uXXXX,
            where XXXX is the hexidecimal representation of the character.
         </para>
         
         <para>
            You can write your translation of labels to your messages resource 
            bundle in the native encoding and then convert the content of the 
            file into the escaped format through the tool <literal>native2ascii</literal>
            provided in the JDK. This tool will convert a file written in your 
            native encoding to one that represents non-ASCII characters as
            Unicode escape sequences.
         </para>

         <para>
            Usage of this tool is described 
            <ulink url="http://java.sun.com/j2se/1.5.0/docs/tooldocs/index.html#intl">here for Java 5</ulink>
            or 
            <ulink url="http://java.sun.com/javase/6/docs/technotes/tools/#intl">here for Java 6</ulink>.
            For example, to convert a file from UTF-8:
         </para>
         
         <programlisting><prompt>$ native2ascii -encoding UTF-8 messages_cs.properties &gt; messages_cs_escaped.properties</prompt></programlisting>
   
      </section>

      <section>
         <title>Other encoding settings</title>

         <para>
            We need to make sure that the view displays your localized data and 
            messages using the correct character set and also any data submitted
            uses the correct encoding.
         </para>

         <para>
            To set the display character encoding, you need to use the 
            <literal>&lt;f:view locale="cs_CZ"/&gt;</literal> tag (here we tell 
            JSF to use the Czech locale). You may want to change the encoding of 
            the xml document itself if you want to embed localized strings in the
            xml. To do this alter the encoding attribute in xml declaration 
            <literal>&lt;?xml version="1.0" encoding="UTF-8"?&gt;</literal> as 
            required.
         </para>

         <para>
            Also JSF/Facelets should submit any requests using the specified
            character encoding, but to make sure any requests that don't specify
            an encoding you can force the request encoding using a servlet 
            filter. Configure this in <literal>components.xml</literal>:
         </para>

         <programlisting role="XML"><![CDATA[<web:character-encoding-filter encoding="UTF-8" 
   override-client="true" 
   url-pattern="*.seam" />]]></programlisting>
      </section>
   </section>

  <section>
    <title>Locales<anchor id="locales" /></title>

    <para>Each user login session has an associated instance of
    <literal>java.util.Locale</literal> (available to the application as a
    component named <literal>locale</literal>). 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:</para>

    <itemizedlist>
      <listitem>
        <para>If there is a locale associated with the HTTP request (the
        browser locale), and that locale is in the list of supported locales
        from <literal>faces-config.xml</literal>, use that locale for the rest
        of the session.</para>
      </listitem>

      <listitem>
        <para>Otherwise, if a default locale was specified in the
        <literal>faces-config.xml</literal>, use that locale for the rest of
        the session.</para>
      </listitem>

      <listitem>
        <para>Otherwise, use the default locale of the server.</para>
      </listitem>
    </itemizedlist>

    <para>It is <emphasis>possible</emphasis> to set the locale manually via
    the Seam configuration properties <literal>
    org.jboss.seam.international.localeSelector.language</literal>, <literal>
    org.jboss.seam.international.localeSelector.country</literal> and
    <literal> org.jboss.seam.international.localeSelector.variant</literal>,
    but we can't think of any good reason to ever do this.</para>

    <para>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:</para>

    <programlisting role="XHTML">&lt;h:selectOneMenu value="#{localeSelector.language}"&gt;
    &lt;f:selectItem itemLabel="English" itemValue="en"/&gt;
    &lt;f:selectItem itemLabel="Deutsch" itemValue="de"/&gt;
    &lt;f:selectItem itemLabel="Francais" itemValue="fr"/&gt;
&lt;/h:selectOneMenu&gt;
&lt;h:commandButton action="#{localeSelector.select}" value="#{messages['ChangeLanguage']}"/&gt;</programlisting>

    <para>Or, if you want a list of all supported locales from <literal>
    faces-config.xml</literal>, just use:</para>

    <programlisting role="XHTML">&lt;h:selectOneMenu value="#{localeSelector.localeString}"&gt;
    &lt;f:selectItems value="#{localeSelector.supportedLocales}"/&gt;
&lt;/h:selectOneMenu&gt;
&lt;h:commandButton action="#{localeSelector.select}" value="#{messages['ChangeLanguage']}"/&gt;</programlisting>

    <para>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.</para>
  </section>

  <section>
    <title>Labels<anchor id="labels" /></title>

    <para>JSF supports internationalization of user interface labels and
    descriptive text via the use of <literal>&lt;f:loadBundle /&gt;</literal>.
    You can use this approach in Seam applications. Alternatively, you can
    take advantage of the Seam <literal> messages</literal> component to
    display templated labels with embedded EL expressions.</para>

    <section>
      <title>Defining labels</title>

      <para>Seam provides a <literal>java.util.ResourceBundle</literal>
      (available to the application as a <literal>
      org.jboss.seam.core.resourceBundle</literal>). You'll need to make your
      internationalized labels available via this special resource bundle. By
      default, the resource bundle used by Seam is named
      <literal>messages</literal> and so you'll need to define your labels in
      files named <literal> messages.properties</literal>, <literal>
      messages_en.properties</literal>, <literal>
      messages_en_AU.properties</literal>, etc. These files usually belong in
      the <literal>WEB-INF/classes</literal> directory.</para>

      <para>So, in <literal>messages_en.properties</literal>:</para>

      <programlisting>Hello=Hello</programlisting>

      <para>And in <literal>messages_en_AU.properties</literal>:</para>

      <programlisting>Hello=G'day</programlisting>

      <para>You can select a different name for the resource bundle by setting
      the Seam configuration property named <literal>
      org.jboss.seam.core.resourceLoader.bundleNames</literal>. You can even
      specify a list of resource bundle names to be searched (depth first) for
      messages.</para>

      <programlisting role="XML">&lt;core:resource-loader&gt;
    &lt;core:bundle-names&gt;
        &lt;value&gt;mycompany_messages&lt;/value&gt;
        &lt;value&gt;standard_messages&lt;/value&gt;       
    &lt;/core:bundle-names&gt;
&lt;/core:resource-loader&gt;</programlisting>

      <para>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 <literal>/</literal> and trailing file extension
      removed. So we could put our message in <literal>
      welcome/hello_en.properties</literal> if we only needed to display the
      message on <literal> /welcome/hello.jsp</literal>.</para>

      <para>You can even specify an explicit bundle name in <literal>
      pages.xml</literal>:</para>

      <programlisting role="XML">&lt;page view-id="/welcome/hello.jsp" bundle="HelloMessages"/&gt;</programlisting>

      <para>Then we could use messages defined in <literal>
      HelloMessages.properties</literal> on <literal>
      /welcome/hello.jsp</literal>.</para>
    </section>

    <section>
      <title>Displaying labels</title>

      <para>If you define your labels using the Seam resource bundle, you'll
      be able to use them without having to type <literal> &lt;f:loadBundle
      ... /&gt;</literal> on every page. Instead, you can simply type:</para>

      <programlisting role="XHTML">&lt;h:outputText value="#{messages['Hello']}"/&gt;</programlisting>

      <para>or:</para>

      <programlisting role="XHTML">&lt;h:outputText value="#{messages.Hello}"/&gt;</programlisting>

      <para>Even better, the messages themselves may contain EL
      expressions:</para>

      <programlisting>Hello=Hello, #{user.firstName} #{user.lastName}</programlisting>

      <programlisting>Hello=G'day, #{user.firstName}</programlisting>

      <para>You can even use the messages in your code:</para>

      <programlisting role="JAVA">@In private Map&lt;String, String&gt; messages;</programlisting>

      <programlisting role="JAVA">@In("#{messages['Hello']}") private String helloMessage;</programlisting>
    </section>

    <section>
      <title>Faces messages</title>

      <para>The <literal>facesMessages</literal> 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:</para>

      <programlisting role="JAVA">@Name("hello")
@Stateless
public class HelloBean implements Hello {
    @In FacesMessages facesMessages;
    
    public String sayIt() {
        facesMessages.addFromResourceBundle("Hello");
    }
}</programlisting>

      <para>This will display <literal>Hello, Gavin King</literal> or
      <literal>G'day, Gavin</literal>, depending upon the user's
      locale.</para>
    </section>
  </section>

  <section>
    <title>Timezones</title>

    <para>There is also a session-scoped instance of <literal>
    java.util.Timezone</literal>, named <literal>
    org.jboss.seam.international.timezone</literal>, and a Seam component for
    changing the timezone named <literal>
    org.jboss.seam.international.timezoneSelector</literal>. 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
    <literal> &lt;f:convertDateTime&gt;</literal>. This is an extremely
    inconvenient default behavior.</para>

    <para>Seam overrides this behavior, and defaults all dates and times to
    the Seam timezone. In addition, Seam provides the <literal>
    &lt;s:convertDateTime&gt;</literal> tag which always performs conversions
    in the Seam timezone.</para>
  </section>

  <section>
    <title>Themes</title>

    <para>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.</para>

    <para>First, configure the set of supported themes:</para>

    <programlisting role="XML">&lt;theme:theme-selector cookie-enabled="true"&gt;
    &lt;theme:available-themes&gt;
        &lt;value&gt;default&lt;/value&gt;
        &lt;value&gt;accessible&lt;/value&gt;
        &lt;value&gt;printable&lt;/value&gt;
    &lt;/theme:available-themes&gt;
&lt;/theme:theme-selector&gt;</programlisting>

    <para>Note that the first theme listed is the default theme.</para>

    <para>Themes are defined in a properties file with the same name as the
    theme. For example, the <literal>default</literal> theme is defined as a
    set of entries in <literal> default.properties</literal>. For example,
    <literal> default.properties</literal> might define:</para>

    <programlisting>css ../screen.css
template /template.xhtml</programlisting>

    <para>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).</para>

    <para>Now we can use these entries in our JSP or facelets pages. For
    example, to theme the stylesheet in a facelets page:</para>

    <programlisting role="XHTML">&lt;link href="#{theme.css}" rel="stylesheet" type="text/css" /&gt;</programlisting>

    <para>Or, when the page definition resides in a subdirectory:</para>

    <programlisting role="XHTML">&lt;link href="#{facesContext.externalContext.requestContextPath}#{theme.css}" 
    rel="stylesheet" type="text/css" /&gt;</programlisting>

    <para>Most powerfully, facelets lets us theme the template used by a
    <literal>&lt;ui:composition&gt;</literal>:</para>

    <programlisting role="XHTML">&lt;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}"&gt;</programlisting>

    <para>Just like the locale selector, there is a built-in theme selector to
    allow the user to freely switch themes:</para>

    <programlisting role="XHTML">&lt;h:selectOneMenu value="#{themeSelector.theme}"&gt;
    &lt;f:selectItems value="#{themeSelector.themes}"/&gt;
&lt;/h:selectOneMenu&gt;
&lt;h:commandButton action="#{themeSelector.select}" value="Select Theme"/&gt;</programlisting>
  </section>

  <section>
    <title>Persisting locale and theme preferences via cookies</title>

    <para>The locale selector, theme selector and timezone selector all
    support persistence of locale and theme preference to a cookie. Simply set
    the <literal>cookie-enabled</literal> property in
    <literal>components.xml</literal>:</para>

    <programlisting role="XML">&lt;theme:theme-selector cookie-enabled="true"&gt;
    &lt;theme:available-themes&gt;
        &lt;value&gt;default&lt;/value&gt;
        &lt;value&gt;accessible&lt;/value&gt;
        &lt;value&gt;printable&lt;/value&gt;
    &lt;/theme:available-themes&gt;
&lt;/theme:theme-selector&gt;

&lt;international:locale-selector cookie-enabled="true"/&gt;</programlisting>
  </section>
</chapter>