[UP]
Reference
 Dialogs
 Data types
 Events
 Templates
 Session management and security
 Internationalization
 Output encodings
 Processing instructions
 The UI language
 The standard UI library
 WDialog API (O'Caml)
 Runtime models
   
Internationalization

Internationalization (I18N) is the ability to support several languages, character encodings, and local notation conventions. Currently, WDialog has some support for that, but I18N is not yet done. In particular, the following features already work:

  • UTF-8 support: It is possible to represent all character data as UTF-8 strings. By default, character data are encoded as ISO-8859-1 (Latin-1) strings. UTF-8 does not only support many languages, but also special characters such as mathematical symbols. In order to switch from ISO-8859-1 to UTF-8, pass the ~charset:`Enc_utf8 argument to the Wd_run_cgi.run function (or Wd_run_jserv.run).

    The consequence is that all strings are now UTF-8 strings, and that the generated HTML output is UTF-8, too.

    The XML file(s) that contain the UI definition can be encoded differently, however. These files begin with <?xml version='1.0' encoding='ENC'?> where ENC is the name of a character encoding, for example ISO-8859-1, or UTF-8. Many other encodings of the ISO-8859 series are possible, too. The characters read from these files are automatically recoded to the character set demanded by the charset option. This means that your text editor need not to support UTF-8.

    As alternative to the direct inclusion of characters, the notation &#n; (where n is a decimal number) can be used to denote the character number n in the input text (the Unicode character set is assumed). For the default ISO-8859-1 encoding the number n must be less than 256, but for UTF-8 all valid Unicode character codes are allowed.

  • The 'language' variable: Every dialog object may contain a language variable that selects the language of the user interface. The name of this variable must be declared in the ui:dialog element, for example:

    <ui:dialog name="foo" lang-variable="current-language">
      ...
      <ui:variable name="current-language">
        <ui:string-value>en</ui:string-value>
      </ui:variable>
      ...
    </ui:dialog>
    

    Here, the variable is initialized with the string "en". It is recommended to store two-letter ISO language codes as abbreviations for the meant languages into the variable. The language variable can be used as any other variable, but there are some statements that access the variable automatically. Read on for more.

  • Language conditions: The ui:iflang element can be used to expand text only if the language variable has a certain value. An application are message catalogs like:

    <ui:cond>
      <ui:iflang xml:lang="en">
        This is English.
      </ui:iflang>
      <ui:iflang xml:lang="de">
        Dies ist Deutsch.
      </ui:iflang>
    </ui:cond>
    

    Of course, the ui:iflang conditions are evaluated sequentially, and such "catalogs" should only be used if the number of languages is small. Nevertheless, this construct seems to be reasonable, and there is even an abbreviation to avoid notation overhead:

    <ui:cond>
      <l:en>
        This is English.
      </l:en>
      <l:de>
        Dies ist Deutsch.
      </l:de>
    </ui:cond>
    

    This means exactly the same as the example above.

  • Language-sensitive templates: Another way to select UI code depending on the language are templates that are defined differently for different languages. For instance:

    <ui:template name="salutation" xml:lang="en" from-caller="user title">
      Good morning, $title $user!
    </ui:template>
    
    <ui:template name="salutation" xml:lang="de" from-caller="user title">
     Guten Morgen, $title $user!
    </ui:template>
    

    If you invoke the template, one of the definitions is selected depending on the current state of the language variable. You can also define a "fallback" version without xml:lang attribute, it is used when no special version for the template is defined.

    In reality, the above templates have the full names salutation#en and salutation#de, i.e. the language code is appended to the name after the hash mark. Because of this, the language code is sometimes also called language suffix. Of course, you can call the template by its full name, and bypass the automatic selection rules, e.g. <ui:use template="salutation#de">.

And these features would be nice to have, but are not yet available:

  • More character sets: Currently, only ISO-8859-1 and UTF-8 are possible. Other character sets should be supported, too.

  • Localized enumerations: It is not possible to define enumerations differently depending on the selected language.

  • Accepted languages: There should be a library function to determine the languages accepted/preferred by the browser.

What is really missing is a good example. I have not yet enough experience to say whether we need more features or not.

Last but not least some interesting code snippets. There are already some tricks that I should mention, as they simplify localization a lot.

Localized attributes: Imagine you want to have a button with localized labels. The string for the label is passed as XML attribute, and the question is: how to select attributes in a language-dependent way?

The straight-forward solution simply repeats the button:

<ui:cond>
  <l:en>
    <ui:button name="foo" label="Press here"/>
  </l:en>
  <l:de>
    <ui:button name="foo" label="Hier drücken"/>
  </l:de>
</ui:cond>

The drawback is that you must repeat the whole button element although only one attribute is different. Is there a better solution?

The idea is to define a template for the button, and to pass different labels. There are several possibilities:

  • (1)

    <ui:template name="button_foo" from-caller="$label">
      <ui:button name="foo" label="$label"/>
    </ui:template>
    ...
    <ui:cond>
      <l:en>
        <t:button_foo label="Press here"/>
      </l:en>
      <l:de>
        <t:button_foo label="Hier drücken"/>
      </l:de>
    </ui:cond>
    

  • (2)

    <ui:template name="button_foo" from-caller="$label">
      <ui:button name="foo" label="$label"/>
    </ui:template>
    ...
    <t:button_foo>
      <p:label
         ><ui:cond
            ><l:en>Press Here</l:en><l:de>Hier drücken</l:de></ui:cond></p:label>
    </t:button_foo>
    

  • (3)

    <ui:template name="button_foo" from-caller="$label">
      <ui:default param="label"
        ><ui:cond
          ><l:en>Press Here</l:en><l:de>Hier drücken</l:de><ui:cond></ui:default>
      <ui:button name="foo" label="$label"/>
    </ui:template>
    ...
    <t:button_foo/>
    

Unfortunately, these tricks work only for template invocations, so we must define button_foo and cannot do the same with ui:button directly.

Using enumerations for localization: If the string to localize is constant, an alternative for condition testing may be an enumeration. Continuing the last example, another solution is:

<ui:template name="button_foo" from-caller="$label">
  <ui:button name="foo" label="$label"/>
</ui:template>
...
<ui:enumeration name="label_for_foo">
  <ui:enum internal="en" external="Press here"/>
  <ui:enum internal="de" external="Hier drücken"/>
</ui:enumeration>
...
<t:button_foo>
  <p:label
    ><ui:translate type="label_for_foo" 
                   internal="$[language()]"/></p:label>
</t:button_foo>

Here, $[language()] expands to the current language code, and the ui:translate element finds the corresponding external string for this code.

With enumerations it is even possible to avoid the extra template definition completely:

<ui:enumeration name="label_for_foo">
  <ui:enum internal="en" external="Press here"/>
  <ui:enum internal="de" external="Hier drücken"/>
</ui:enumeration>
...
<ui:button name="foo" label="$[translate(enum(label_for_foo),language())]"/>

The enum expression is a special form that returns the declaration of the named enumeration. The translate function does the same as ui:translate, but can be used in a bracket expression.