<chapter id="I18N">
   <title>Internationalization and Localization</title>

   <para>
   With the help of the JBoss Logging project, all log and exception messages in RESTEasy are internationalized. That is, they
   have a default value in English which can be overridden in any given locale by a file which gives translated values. For
   more information about internationalization and localization in Java, see, for example,
   <ulink url="http://docs.oracle.com/javase/tutorial/i18n">http://docs.oracle.com/javase/tutorial/i18n</ulink>. For more about
   JBoss Logging Tooling, see
   <ulink url="https://jboss-logging.github.io/jboss-logging-tools/">
      https://jboss-logging.github.io/jboss-logging-tools/</ulink>,
   Chapters 4 and 5.
   </para>

   <section>
   <title>Internationalization</title>
   <para>
   Each module in RESTEasy that produces any text in the form of logging messages or exception messages
   has an interface named org.jboss.resteasy...i18n.Messages which contains the default messages. Those
   modules which do any logging also have an interface named org.jboss.resteasy...i18n.LogMessages which gives access to an
   underlying logger. With the exception of the resteasy-core-spi module, all messages are in the Messages class. resteasy-core-spi
   has exception messages in the Messages class and log messages in the LogMessages class.
   </para>

   <para>
   Each message is prefixed by the project code "RESTEASY" followed by an ID which is unique to RESTEasy. These IDs belong to the
   following ranges:
   </para>

   <table frame="topbot">
   <tgroup cols="2" rowsep="1" colsep="1">
      <thead>
         <row>
            <entry align="center">Range</entry>
            <entry align="center">Module</entry>
         </row>
      </thead>
      <tbody>
         <row>
            <entry align="left">2000-2999</entry>
            <entry align="left">resteasy-core-spi log messages</entry>
         </row>
         <row>
            <entry align="left">3000-4499</entry>
            <entry align="left">resteasy-core-spi exception messages</entry>
         </row>
         <row>
            <entry align="left">4500-4999</entry>
            <entry align="left">resteasy-client</entry>
         </row>
         <row>
            <entry align="left">5000-5499</entry>
            <entry align="left">providers/resteasy-atom</entry>
         </row>
         <row>
            <entry align="left">5500-5999</entry>
            <entry align="left">providers/fastinfoset</entry>
         </row>
         <row>
            <entry align="left">6000-6499</entry>
            <entry align="left">providers/resteasy-html</entry>
         </row>
         <row>
            <entry align="left">6500-6999</entry>
            <entry align="left">providers/jaxb</entry>
         </row>
         <row>
            <entry align="left">7500-7999</entry>
            <entry align="left">providers/multipart</entry>
         </row>
         <row>
            <entry align="left">8000-8499</entry>
            <entry align="left">providers/resteasy-hibernatevalidator-provider</entry>
         </row>
         <row>
            <entry align="left">8500-8999</entry>
            <entry align="left">providers/resteasy-validator-provider</entry>
         </row>
         <row>
            <entry align="left">9500-9999</entry>
            <entry align="left">async-http-servlet-3.0</entry>
         </row>
         <row>
            <entry align="left">10000-10499</entry>
            <entry align="left">cache-core</entry>
         </row>
         <row>
            <entry align="left">10500-10999</entry>
            <entry align="left">resteasy-cdi</entry>
         </row>
         <row>
            <entry align="left">11500-11999</entry>
            <entry align="left">resteasy-jsapi</entry>
         </row>
         <row>
            <entry align="left">12000-12499</entry>
            <entry align="left">resteasy-links</entry>
         </row>
         <row>
            <entry align="left">12500-12999</entry>
            <entry align="left">resteasy-servlet-initializer</entry>
         </row>
         <row>
            <entry align="left">13000-13499</entry>
            <entry align="left">resteasy-spring</entry>
         </row>
         <row>
            <entry align="left">13500-13999</entry>
            <entry align="left">security/resteasy-crypto</entry>
         </row>
         <row>
            <entry align="left">14000-14499</entry>
            <entry align="left">security/jose-jwt</entry>
         </row>
         <row>
            <entry align="left">14500-14999</entry>
            <entry align="left">security/keystone/keystone-as7</entry>
         </row>
         <row>
            <entry align="left">15000-15499</entry>
            <entry align="left">security/keystone/keystone-core</entry>
         </row>
         <row>
            <entry align="left">15500-15999</entry>
            <entry align="left">security/resteasy-oauth</entry>
         </row>
         <row>
            <entry align="left">16000-16499</entry>
            <entry align="left">security/skeleton-key-idm/skeleton-key-as7</entry>
         </row>
         <row>
            <entry align="left">16500-16999</entry>
            <entry align="left">security/skeleton-key-idm/skeleton-key-core</entry>
         </row>
         <row>
            <entry align="left">17000-17499</entry>
            <entry align="left">security/skeleton-key-idm/skeleton-key-idp</entry>
         </row>
         <row>
            <entry align="left">17500-17999</entry>
            <entry align="left">server-adapters/resteasy-jdk-http</entry>
         </row>
         <row>
            <entry align="left">18500-18999</entry>
            <entry align="left">server-adapters/resteasy-netty4</entry>
         </row>
      </tbody>
   </tgroup>
   </table>

   <para>
   For example, the &XML-BIND-API; provider contains the interface
   </para>

   <blockquote>
   <classname>org.jboss.resteasy.plugins.providers.jaxb.i18.Messages</classname>
   </blockquote>

   <para>
   which looks like
   </para>

   <programlisting>
@MessageBundle(projectCode = "RESTEASY")
public interface Messages
{
   Messages MESSAGES = org.jboss.logging.Messages.getBundle(Messages.class);
   int BASE = 6500;

   @Message(id = BASE + 00, value = "Collection wrapping failed, expected root element name of {0} got {1}", format=Format.MESSAGE_FORMAT)
   String collectionWrappingFailedLocalPart(String element, String localPart);

   @Message(id = BASE + 05, value = "Collection wrapping failed, expect namespace of {0} got {1}", format=Format.MESSAGE_FORMAT)
   String collectionWrappingFailedNamespace(String namespace, String uri);
   ...
   </programlisting>

   <para>
   The value of a message is retrieved by referencing a method and passing the appropriate parameters. For example,
   </para>

   <programlisting>
throw new JAXBUnmarshalException(Messages.MESSAGES.collectionWrappingFailedLocalPart(wrapped.element(), ele.getName().getLocalPart()));
   </programlisting>

   </section>

   <section>
   <title>Localization</title>

   <para>
   When RESTEasy is built with the "i18n" profile, a template properties file containing the default messages
   is created in a subdirectory of target/generated-translation-files. In the &XML-BIND-API; provider, for example,
   the
   </para>

   <blockquote>
   Messages.i18n_locale_COUNTRY_VARIANT.properties
   </blockquote>

   <para>
   goes in the
   </para>

   <blockquote>
   org/jboss/resteasy/plugins/providers/jaxb/i18n
   </blockquote>

   <para>
   directory, and the first few lines are
   </para>

   <programlisting>
# Id: 6500
# Message: Collection wrapping failed, expected root element name of {0} got {1}
# @param 1: element -
# @param 2: localPart -
collectionWrappingFailedLocalPart=Collection wrapping failed, expected root element name of {0} got {1}
# Id: 6505
# Message: Collection wrapping failed, expect namespace of {0} got {1}
# @param 1: namespace -
# @param 2: uri -
collectionWrappingFailedNamespace=Collection wrapping failed, expect namespace of {0} got {1}
   </programlisting>

   <para>
   To provide the translation of the messages for a particular locale, the file should be renamed, replacing
   "locale", "COUNTRY", and "VARIANT" as appropriate (possibly omitting the latter two), and copied to the
   src/main/resources directory. In the &XML-BIND-API; provider, it would go in
   </para>

   <blockquote>
   src/main/resources/org/jboss/resteasy/plugins/providers/jaxb/i18n
   </blockquote>

   <para>
   For testing purposes, each module containing a Messages interface has two sample properties files, for
   the locale "en" and the imaginary locale "xx", in the src/test/resources directory. They are copied to
   src/main/resources when the module is built and deleted when it is cleaned.
   </para>

   <para>
   The Messages.i18n_xx.properties file in the &XML-BIND-API; provider, for example, looks like
   </para>

   <programlisting>
# Id: 6500
# Message: Collection wrapping failed, expected root element name of {0} got {1}
# @param 1: element -
# @param 2: localPart -
collectionWrappingFailedLocalPart=Collection wrapping failed, expected root element name of {0} got {1}
# Id: 6505
# Message: Collection wrapping failed, expect namespace of {0} got {1}
# @param 1: namespace -
# @param 2: uri -
collectionWrappingFailedNamespace=aaa {0} bbb {1} ccc
...
   </programlisting>

   <para>
   Note that the value of collectionWrappingFailedNamespace is modified.
   </para>
   </section>
</chapter>
