Chapter 7. Internationalization And Localization [DRAFT]

Table of Contents

7.1. This is a DRAFT! Give your opinion!
7.2. I18N and l10n
7.2.1. Setting your preferred language and locale
7.3. Finding language files
7.3.1. A word about organization
7.4. Internationalizing the Upcoming document type
7.5. Exercises

Objective: To understand how to create a Nuxeo bundle that correctly adapts to different languages.

I speak Spanish to God, Italian to women, French to men and German to my horse. Charles V, Holy Roman Emperor (1500-1558).

7.1. This is a DRAFT! Give your opinion!

If you have any comments, questions, or general-purpose harassment you would like give us about this book, then please use the comment form at the bottom of each page! We promise that we will try to incorporate any feedback you give (minus the profanity, of course), will respond to your questions, and credit you appropriately.

7.2. I18N and l10n

In the United States, the term "I18N" is pronounced "eye-eighteen-en." This is a shortening, at least when written, of the word "Internationalization" because the word has 18 characters between the leading 'L' and trailing 'N'. Internationalization, at least traditionally, has meant translating the text of applications (or websites) so that the application can be used by folks who speak (and read) different languages. Similarly, l10n has come to mean "localization" and the definition of localization is normally taken to be slightly larger than internationalization since localization includes not only the language issues, which are largely ones of text presentation, but also those associated with differences in the way that dates and times are displayed, currencies, the way decimal points are presented, and so on. Using these definitions, the United States and Great Britain would be almost identical for the purpose of Internationalization (color vs. colour) but quite different in localization terms because they use different currencies (with different currency markers, £ vs $) and write dates in different orders, 11/9/2001 vs 9/11/2001.

7.2.1. Setting your preferred language and locale

To see the effects of any work you do to localize your plugin, you will need to set your web browser to the language you wish to see. Normally, this is done through the preferences panel. The screen shot below shows the Content Preferences tab from the main preferences dialog in FireFox version 3. You can also see the Language choice dialog in the lower left. By promoting a particular language to the top position, you can can different output from Nuxeo. You can see a bit of the text of the login screen in the background that has been rendered in French.

7.3. Finding language files

If you have intsalled your copy of Nuxeo 5 in the normal place, /nuxeo/tools/NuxeoEP5, then you should perform a couple of commands as shown here:

[~]
$ cd /nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/deploy/nuxeo.ear/nuxeo.war/WEB-INF/classes

[/nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/deploy/nuxeo.ear/nuxeo.war/WEB-INF/classes]
$ ls messages*
messages_ar.properties  messages_es.properties  messages.properties
messages_cn.properties  messages_fr.properties  messages_pt_BR.properties
messages_de.properties  messages_it.properties  messages_ru.properties
messages_en.properties  messages_ja.properties  messages_vn.properties

[/nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/deploy/nuxeo.ear/nuxeo.war/WEB-INF/classes]
$ head messages_en.properties 
#
# Translations of action labels
#
#: nuxeo-platform/nuxeo-platform-notification-web/src/main/resources/OSGI-INF/actions-contrib.xml
#: nuxeo-platform/nuxeo-platform-webapp-core/src/main/resources/OSGI-INF/actions-contrib.xml
action.email.document=Email

#: nuxeo-platform/nuxeo-platform-forum/src/main/resources/OSGI-INF/forum-actions-contrib.xml
action.forum.content=Forum

So, the above example script shows that inside the nuxeo.ear/nuxeo.war directory that we have seen before is the root of the web directory for Nuxeo's UI, is the directory WEB-INF/classes. This is the directory where "resources" (in Java parlance) are located. Java web developers will recognize this as the directory referenced by the Java API System.getResourceAsStream(). Each of the files shown shown above that start with messages_ is a translation of the Nuxeo web UI. The abbreviations for languages, noted in the suffixes after the underscore, are quite standardized with English being en, French being fr, Japanese being ja, and so on. (These correspond to the notion in Java of a "locale" such as in the Java API Locale.getDefault().) These files are in the standard Java "properties" format: blank lines and lines that start with a # are comments and the rest are in key=value format and are terminated by the end of the line. In the case of the properties here, the left (key) side of the equals sign is a "label" referred to in the Java program or the configuration files of a bundle. The right hand side is the value to output to the user for this label.

It is worth noting a couple of files that are slightly different. First, the file messages_pt_BR.properties is the translation of the Nuxeo UI into Brazilian Portuguese. This specialization for a specific country's variant of a language is signified by the second part of the suffix, BR in this case. Although Nuxeo does not provide a translation to standard Portugese at the time of this writing, if we did it would be named messages_pt.properties. This specialization (or, to be more clear, "specialisation") for English might be done with a version of the UI for the United Kingdom labelled messages_en_UK, another for Canada labelled messages_en_CA, and one for the United States labelled messages_en_US. The contents of messages_en.properties, in this case, would be for all the other english speakers and, much more crucially, all the strings that do not need to change based on the country and the same for all English speakers. This prevents needing to copy all the strings into each file; messages_en_UK can contain only those strings that need to change for folks that are in the United Kingdom.

Most modern browsers correctly set the language/locale option, so normally each request handled by nuxeo has both the language and the country set to the desired values for the user. Let's look at the sequence used for a example request by a browser, when the code is trying to output a label for a button. Given a user in Quebec, the likely value of the language desired is "fr_CA" to to indicate French Canadian. The system will look for a the text label of the button in these files, in this order:

  • messages_fr_CA.properties

  • messages_fr.properties

  • messages.properties

The first translation found is used any later translations will be ignored. This should help explain the presence of the undecorated messages.properties file in the list above! messages.properties is the file of last resort when the user's country-specific and language-specific translations are either not present or not neeeded.

7.3.1. A word about organization

Some people are tempted to put all the keys in each file and then just have someone do a complete translation by working through the file. While this apporach can work in the short term, it is storing up trouble. The point of having the sequence of files checked is to allow you to not have to duplicate things unnecessarily, facilitating change since far fewer files must be changed on average when you add or delete keys. Further, during development you can use this sequence as a reminder of things to do later, as you will see in the next section.

7.4. Internationalizing the Upcoming document type

Note

As in the previous lessons, you should export the skeleton of this lesson with svn from the nuxeo repository http://svn.nuxeo.org/nuxeo/sandbox/iansmith/book/lesson-l10n so you can begin the lesson with the results of previous lessons, use maven to create the Eclipse project, and then import the project (lesson6-l10n) into your workspace.

To begin the internationalization, you should update your contribution to the widgets point in file layout-contrib.xml

  <extension target="org.nuxeo.ecm.platform.forms.layout.WebLayoutManager"
    point="widgets">
          <widget name="upcoming_when" type="datetime">
        <labels>
          <label mode="any">upcoming.layout.label.when</label>
        </labels>
        <translated>true</translated>
        <fields>
          <field>up:occursOn</field>
        </fields>
        <properties widgetMode="edit">
          <property name="required">true</property>
        </properties>
      </widget>
      <widget name="upcoming_who" type="text">
        <labels>
          <label mode="any">upcoming.layout.label.who</label>
        </labels>
        <translated>true</translated>
        <fields>
          <field>up:presenter</field>
        </fields>
      </widget>
      <widget name="upcoming_howmuch" type="text">
        <labels>
          <label mode="any">upcoming.layout.label.howmuch</label>
        </labels>
        <translated>true</translated>
        <fields>
          <field>up:admissionPrice</field>
        </fields>
        <properties widgetMode="edit">
          <property name="required">true</property>
        </properties>
      </widget>
  </extension>
 

This sets the labels to be looked up in the various messages files to be upcoming.layout.label.when and so forth. It also alerts, with the translated tag, nuxeo that we would like it to check on these labels rather than using the text directly from this file, as we had done before.

You should now create a new subdirectory of resources in your project and call this directory l10n ("el-ten-en"). This directory will contain the translated text for your application. For now, we will create placeholders for the document type's UI you created in the last lesson. The first file, messages.properties is shown below:

upcoming.layout.label.when=untranslated: when
upcoming.layout.label.who=untranslated: who
upcoming.layout.label.howmuch=untranslated: how much

Finally, you need to create a deployment script to append your translated files with those of Nuxeo itself. These must be merged because your bundle is running as a part of Nuxeo. Naturally, you do this with a change to the deployment-fragment.xml file. Below is the new, complete listing of this file:

<fragment>

  <extension target="application#MODULE">
    <module>
      <java>${bundle.fileName}</java>
    </module>
  </extension>

  <install>

    <!-- Unzip the contents of our nuxeo.war into the real nuxeo.war on the server -->
    <unzip from="${bundle.fileName}" to="/">
      <include>nuxeo.war/**</include>
    </unzip>
    
    <!--make sure the directory is there for messages files-->
    <mkdir path="lesson-l10n.tmp"/>
     
    <!-- Unzip the l10n directory to a temporary place-->
    <unzip from="${bundle.fileName}" to="lesson-l10n.tmp">
      <include>l10n/**</include>
    </unzip>
 
    <!-- copy default text -->  
    <append 
      from="lesson-l10n.tmp/l10n/messages.properties"
      to="nuxeo.war/WEB-INF/classes/messages.properties"
      addNewLine="true"/>

  </install>
</fragment>

If you build and deploy this file, then run it inside Nuxeo, you will see something like this when you try to create a new Upcoming document:

We are using "untranslated" to remind us to build translations; this is recommended during development, since the text is visible through the browser interface. In production, you would place some default language in this file. Nuxeo has chosen English as its default, so the contents of the messages.properties files are in English, when there are strings that are overriden by other language files. Other than these, the contents should be things that do not need translating, like names of places, or the word "orange."

Once you have mastered how to deploy your bundle in multiple languages, it should be a simple exercise (!) to add the necessary support for other language such as French an English. It is important to remember, however, that the final selection of the language-and if necessary country-is up to the browser so you will need to select the correct browser settings to see your handiwork.

7.5. Exercises

  1. Add support for French and English in the Upcoming bundle. The French words are "Quand" (when), "Combien" (how much), and "Qui" (who). Verify that changes the languages in the browser correctly displays the right text.

  2. Add support for UK English to the Upcoming bundle but use cockney rhyming slang for the text (http://cockneyrhymingslang.co.uk). Since the rhymes are usually associated with nouns, you may want to change the text to be sentences, e.g. "What is the Condoleeza Rice?" Verify that changes the languages in the browser correctly displays the right (?) text.