Translate Extension

The translate extension adds internationalization capabilities to Jtwig. It heavily relies on the concept of MessageSource, which will be detailed futher on. This extension is highly configurable and can be optimized for each specific use case.

Translation

The translation engine in Jtwig relies in two distinct concepts:

  • Message Source
  • Message Decoration

Message Source

Message source mechanism acts as a storage of translations, it allows one to get translations of text to another language, more specifically, to a Locale (check the official Java documentation java.util.Locale). In Jtwig, if such message source engine is unable to find a requested translation, then it returns the given text.

Key and Free Text

There are two typical approaches used as input for translations. It is either a Key or Free Text. The difference between this two approaches is that keys aren't readable, while the provided free text can be. Because keys are not shown to the end-user (at least they shouldn't), they can incorporate contextual information, like the purpose of the text, for example, registration.title or registration.subtitle. Free text approaches tend to define the wording directly, for example, Register or Please, fill the form below and submit. Jtwig allows for both approaches, where, for example, properties files can be used with the Key approach and Jtwig XLIFF can be used for the Free Text one.

We believe translations should be context independent, that is, locating a given text or identifying the purpose of a given text should not be the purpose of a translation mechanism. However, given the size of some platforms, decouple this two concepts can cause more harm than good.

Message Decoration

Message decoration is the engine which allows one to modify the output of the message source. Jtwig translate extension makes use of a replacement strategy as decorator, allowing users to specify a map of replacements to modify the output, such will be detailed further on.

Configuration

TranslateConfiguration configuration = TranslateConfigurationBuilder
                .translateConfiguration()
                    .withCurrentLocaleSupplier(currentLocaleSupplier)
                    .withStringLocaleResolver(localeResolver)
                    .withMessageSourceFactory(messageSourceFactory)
                .build();

As mentioned this extension is highly configurable, it allows, as seen in the example above, to specify a LocaleResolver, a locale supplier and a MessageSourceFactory.

Locale Supplier

A locale supplier gives Jtwig the capability to retrieve a locale from the context when no locale is specified. By default Jtwig returns a static supplier which returns Locale.ENGLISH as result.

LocaleResolver

The locale resolver is used to convert a raw String to a java.util.Locale, by default Jtwig will use the Locale::forLanguageTag method provided by the Java API.

MessageSourceFactory

The message source factory gets called when Jtwig is initializing the environment, it can be used to preload resources and provide and instance of the MessageSource interface.

public interface MessageSourceFactory {
    MessageSource create (Environment environment);
}

Jtwig provides several implementations of such factory. A singleton factory SingletonMessageSourceFactory, which only returns the provided MessageSource instance. A cached factory CachedMessageSourceFactory allowing to, given a specific cache implementation, put it in front of the generated MessageSource. Shipped within this extension it's also the PropertiesMessageSourceFactoryBuilder which give the developer a nice API to create a MessageSourceFactory to load messages from properties files.

Jtwig XLIFF

Jtwig XLIFF was developed as a way to support XLIFF defined translation files. It comes with a XliffMessageSourceFactoryBuilder quite similar to the properties message source factory.

Function translate

This function has two other alias, they are trans and message. It expects one argument at least, with the possibility of receiving two extra, optional, arguments. The first mandatory argument is the text to be translated.

{{ translate('Hello World') }}

If two arguments are provided it can either be a Locale, represented as a string or a map of replacements.

{{ translate('Hello World', 'pt') }}
{{ translate('Hello %name%', {'%name%': 'Jtwig'}) }}

If a map is provided Jtwig will use it as replacements applying to the message returned by the message source. Otherwise, if a string is provided, Jtwig will ask the message source mechanism for a given message with the locale provided.

{{ translate('Hello World', {'%name%': 'Jtwig'}, 'pt') }}

If three arguments are provided, then the map is expected as second argument and a string, representing a locale, the third.

The trans tag

The trans tag has the same capabilities as the translate function allowing to specify the text to translate as body.

{% trans %}Hello world{% endtrans %}
{% trans into 'pt' %}Hello world{% endtrans %}
{% trans with {'%name%': 'Jtwig'} into 'pt' %}Hello %name%{% endtrans %}
{% trans with {'%name%': 'Jtwig'} %}Hello %name%{% endtrans %}

Note that, the text is trimmed before querying the message source for the translation.

Pluralization

Plural handling in Jtwig it's an easy to use and powerfull engine. Project jtwig-pluralization implements the underlying functionality.

The counter (single)

This whole functionality derives from a key piece of information, the counter. Such counter is used to derive the plural form to be used, as so, this pluralization engine only supports one subject. For example, 1 apple and 2 oranges contains two subjects, therefore, outside of this engine capabilities, such can be address, for example, by splitting the sentence into two.

{0} No apples | {1} One apple | ]1, Inf[ Multiple apples

As per the previous example, the plural form contains three definitions (splitted by the | character). Definitions start with a range selector, which can either be a single value {<value>} or an interval of values, note that intervals can be inclusive or exclusive depending on the parentsis used. For example, [1, 2], ]0, 3[, [1, 3[, ]0, 2] are all equivalent intervals.

The pluralization engine also trims the selected value. It uses the String:trim method underneath.

Function translateChoice

This function allows for the same capabilities as the translate plus choosing the plural form to use after processing the translation.

{{ '{0} No apples | {1} One apple | ]1, Inf[ Multiple apples' 
    | translateChoice(numberOfApples, "pt") }}

The previous example will look for a pt translation of the sentence {0} No apples | {1} One apple | ]1, Inf[ Multiple apples and, only after retrieving the translation, uses the pluralization engine to select, based on the counter (here defined as the variable numberOfApples), the plural form.

Integration

Integrating Jtwig Translation Extension on your project is quite simple with the help of dependency managers. To check the most recent version, go to bintray.

Gradle

repositories {
    jcenter()
}
dependencies {
    compile 'org.jtwig:jtwig-translation-extension:1.X'
}

Maven

<repositories>
    <repository>
        <id>bintray</id>
        <url>https://jcenter.bintray.com/</url>
    </repository>
</repositories>

<dependencies>
    <dependency>
        <groupId>org.jtwig</groupId>
        <artifactId>jtwig-translation-extension</artifactId>
        <version>1.X</version>
    </dependency>
</dependencies>

Examples

Check the jtwig-examples project on github for examples using this translation engine.