Localisation

Introduction

The Modern UI supports internationalisation/localisation of form files, allowing a single form file to provide search results in a variety of languages: A set of translations can be defined per language, and the form file will be displayed with the relevant translations according to the language selected by the search user.

Quickstart

Create $SEARCH_HOME/conf/<collection>/_default/ui.en_US.cfg with the following content:

 search=Search
 results_found=%d results found for %s

Update your form file with:

 ${response.translations.search!"Search"}
 <!-- Or alternatively -->
 <@fb.Format key="search" args="" />
 <@fb.Format key="results_found" args=[response.resultPacket.resultsSummary.totalMatching, question.query] />

Specifying the locale at query time

There are multiple ways to specify which locale should be used to process a search at query time:

Using auto-detection

This is the default mechanism which will detect the best locale based on the information sent by the search user browser (The Accept-Language request header).

Setting the lang CGI parameter

Setting this parameter will affect both the user interface locale, as well as the language used in the Query Processor. Please consult the documentation of the lang query processor option for more details.

Setting the lang.ui CGI parameter

Setting this parameter will only affect the user interface, not the query processor. It allows you to use a given locale for the form file, but a different lang parameter for the query processor.The locale must be specified as a ISO 639 language code such as en or fr. Additionally, a ISO 3166 country code can be appended with an underscore, i. e. en_GB or fr_BE.

Examples:

 ...&lang=en...
 ...&lang=en_GB...
 ...&lang=en&lang.ui=fr_FR...

The locale is available in the Data Model under the question.locale node.

Defining translations

Translations should be defined in configuration files, either on a global scope that will be available for all collections, or on a per-collection/profile basis. Translations for the global scope should be created under $SEARCH_HOME/conf/ and per-collection/profile translations should be created in the profile directory under the collection configuration directory $SEARCH_HOME/conf/<collection>/<profile>.

The file format is the usual key/value format. Translation files must be encoded in UTF-8. Lines starting with a hash are treated as comments. For example:

 # French translations as of July 2012
 search=Rechercher
 results_found=%d résultats trouvés
 ...

The value can contain format specifiers such as %d, %s, etc. These specifiers will be replaced with provided values, allowing the translations to be dynamic when needed. In the previous example the %d would be replaced by the number of results found (See below the section about accessing the translations in the form file for more information). The formatting system is based on Java Formatter class, please refer to this documentation for more details.

File naming conventions and precedence order

A file must be created for each locale, containing the translations for that locale. In addition, a generic locale-independent file can be created to contain fall-back values when a translation is missing for a specific term.

  • The locale-independent file is named ui.cfg
  • Locale specific files are named ui.<locale>.cfg. For the en locale, the file must be named ui.en.cfg. For the en_GB locale, the file must be named ui.en_GB.cfg

For example for an en and en_GB locales, the following files could be created:

  • $SEARCH_HOME/conf/ui.cfg: Locale-independent values, for all collections
  • $SEARCH_HOME/conf/ui.en.cfg: Generic translations for all collections for the 'en' locale
  • $SEARCH_HOME/conf/ui.en_GB.cfg: Generic translations for all collections for the 'en_GB' locale
  • $SEARCH_HOME/conf/intranet/_default_preview/ui.cfg: Locale-independent values, specific to the intranet collection and the _default_preview profile
  • $SEARCH_HOME/conf/intranet/_default_preview/ui.en.cfg: Translations specific to the intranet collection and the _default_preview profile, for the en locale
  • $SEARCH_HOME/conf/intranet/_default_preview/ui.en_GB.cfg: Translations specific to the intranet collection and the _default_preview profile, for the en_GB locale

Note: Translation files under the collection folder (outside a profile folder) are not supported. These files will be ignored.

If multiple translation files are found, they will be merged together with the more specific specific values overriding the more global ones. The priority order is shown below, with later values overriding earlier ones.

  • $SEARCH_HOME/conf/ui.cfg
  • $SEARCH_HOME/conf/<collection>/<profile>/ui.cfg
  • $SEARCH_HOME/conf/ui.<lang>.cfg
  • $SEARCH_HOME/conf/<collection>/<profile>/ui.<lang>.cfg
  • $SEARCH_HOME/conf/ui.<lang>_<country>.cfg
  • $SEARCH_HOME/conf/<collection>/<profile>/ui.<lang>_<country.cfg>

For example if every file contains a different translation for the key search, the one in $SEARCH_HOME/conf/<collection>/<profile>/ui.fr_BE.cfg would take precedence because it is the most specific.

Accessing translations in the template

Translations are included in the Data Model under the response.translations node, as a key-value map. Only the translations for the current locale (and the locale-independent ones) are available. This means that if your current locale is fr_BE you will only find one entry for the key search with the value Rechercher. If you switch the locale to en, the value for search will become Search.

The map uses the same keys as in the translation files and can be accessed as a regular FreeMarker map:

 ${response.translations["search"]} or ${response.translations.search}

The FreeMarker syntax also allows a fall-back value to be specified with the standard default value operator:

 ${response.translations.search!"Rechercher"}

In addition a custom FreeMarker tag is available, which supports passing arguments to be inserted within the translations:

 <@fb.Format key="results" /> (no arguments)
 <@fb.Format key="results_found" args=42 /> will result in "42 results found"

Multiple arguments can be passed using a FreeMarker array:

 <@fb.Format key="results" args=[42, "abc"] />

In addition you can take advantage of the built-in FreeMarker localisation support of the #include directive to have per-locale sub-templates. Please refer to the FreeMarker documentation for more information.

Caveats

Faceted Navigation

When using Faceted Navigation the recommended way to translate facet labels is to create an entry per Facet Name in the translation file, using the actual name of the facet in the key.

In the following example, we'll consider that we have two facets Location and Document type. Create the following translations resources:

facet_Location=Location
facet_Document_type=Document type

In the FreeMarker form, rather than using the <@s.FacetLabel> tag, access directly the translation data:

<@s.Facet>
 <!-- Don't use label tag <h3><@s.FacetLabel /></h3> -->
 <h3>${response.translations["facet_"+s.facet.name?replace(" ", "_")]!s.facet.name}</h3>
 <@s.Category> ... </@s.Category>
</@s.Facet>

Note:

  • Translation files do not support whitespace in the key names, that's why the key used is facet_Document_type rather than facet_Document type, and when looking up the key the white spaces in the facet name are replaced with underscores.
  • The !s.facet.name statement will cause the actual facet label to be displayed if the translation is not found.

See also

top