i18n

Apache Causeway' support for internationlization (i18n) allows every element of the domain model (the class names, property names, action names, parameter names and so forth) to be translated.

It also supports translations of messages raised imperatively, by which we mean as the result of a call to title() to obtain an object’s title, or messages resulting from any business rule violations (eg disable…​() or validate…​(), and so on.

The Web UI (Wicket viewer) (that is, its labels and messages) is also internationalized using the same mechanism. If no translations are available, then the Wicket viewer falls back to using Wicket resource bundles.

Causeway does not translate the values of your domain objects, though. So, if you have a domain concept such as Country whose name is intended to be localized according to the current user, you will need to model this yourself.

Implementation Approach

Most Java frameworks tackle i18n by using Java’s own ResourceBundle API. However, there are some serious drawbacks in this approach, including:

  • if a string appears more than once (eg "name" or "description") then it must be translated everywhere it appears in every resource bundle file

  • there is no support for plural forms (see this SO answer)

  • there is no tooling support for translators

Apache Causeway therefore takes a different approach, drawing inspiration from GNU’s gettext API and specifically its .pot and .po files. These are intended to be used as follows:

  • the .pot (portable object template) file holds the message text to be translated

  • this file is translated into multiple .po (portable object) files, one per supported locale

  • these .po files are renamed according to their locale, and placed into the 'appropriate' location to be picked up by the runtime. The name of each .po resolved in a very similar way to resource bundles.

The format of the .pot and .po files is identical; the only difference is that the .po file has translations for each of the message strings. These message strings can also have singular and plural forms.

Although Apache Causeway' implementation is modelled after GNU’s API, it does not use any GNU software. This is for two reasons: (a) to simplify the toolchain/developer experience, and (b) because GNU software is usually GPL, which would be incompatible with the Apache license.

This design tackles all the issues of ResourceBundles:

  • the .po message format is such that any given message text to translate need only be translated once, even if it appears in multiple places in the application (eg "Name")

  • the .po message format includes translations for (optional) plural form as well as singular form

  • there are lots of freely available editors to be found, many summarized on this Drupal.org webpage.

    In fact, there are also online communities/platforms of translators to assist with translating files. One such is crowdin (nb: this link does not imply endorsement).

In Apache Causeway' implementation, if the translation is missing from the .po file then the original message text from the .pot file will be returned. In fact, it isn’t even necessary for there to be any .po files; .po translations can be added piecemeal as the need arises.

API

The main API is the TranslationService:

The translate(…​) methods are closely modelled on GNU’s gettext API. The first version is used when no translation is required, the second is when both a singular and plural form will be required, with the num parameter being used to select which is returned. In both cases the context parameter provides some contextual information for the translator; this generally corresponds to the class member.

The mode meanwhile determines the behaviour of the service. More on this below.