Localizing Resources

As mentioned in Introduction, message files are located under the <installation-dir>/usr/share/messages directory’s “root” subdirectories:

  • template-areas/<template-area>
  • overrides
  • core

Each subdirectory of the root directories is expected to be named with the name of a locale such as en or sv_SE, so that messages can be localized correctly based on the requested locale.

Message files should be added to one of the root directories mentioned in the Message lookup section.

About Locales

The Curity Identity Server supports localization of messages using locales based on the IETF’s BCP 47.

A default locale may be configured for the server as explained in the Localization Guide.

To override a locale, it is possible to include the ui_locales-parameter in the querystring. The format of the ui_locales-parameter must be a whitespace-separated list of languages, that represent the user’s ordered language preference. See the OpenID Connect Specification for more about this parameter.

The ui_locales parameter is accepted by any endpoint, when applicable. The locale preference will be persisted in a cookie that is configured through the username cookie.

When a request is received, a preferred locale will be selected based on the user preference as set in the ui_locales-parameter. If that is not there, or unknown or unsupported languages are asked for, the request’s Accept-Language header will be evaluated. If this header is not specified or if the preferred locale is not one that messages have been localized into, the server’s default locale is used as the preferred locale.

Note

Locale directory names should follow the patterns <language>[_<country>] or <language>[-<country>]. Any part of the directory name not matching this pattern will be ignored.

For example, a directory named en represents the English language (no country is specified). en_US represents the English language, with the country being the United States. en-us-xx-yy and en-us.backup-copy are treated the same as en_US.

Using localized messages in templates

Templates may include localized messages with the #message() directive. The following is an example template that uses that:

Listing 201 Using messages in the templates
1
2
3
<div class="info">
    <h2>#message("${_templatePrefix}.view.some-info")</h2>
</div>

When the template is parsed, #message("view.some-info") will be replaced with a localized message from the message files unless no message is found for the "view.some-info" or "some-info" keys, in which case the message key itself, "view.some-info", will be shown. See Message keys for details.

Note

The subject in emails sent by the Curity Identity Server is set by <template-area>.<template-prefix>.email.subject so it is possible to have different email subjects for the same authenticator, based on the template-area of the client that is using it.

Message keys

Message keys are expected to be composed of parts separated with dots (i.e., .), where each part is a simple word.

Examples of valid message keys:

  • views.page.title
  • authenticators.html-form.login.submit

If a message file is not at one of the root locations, the location of a message file becomes part of the message keys it contains.

For example, suppose that under the root directory en there is a messages file with the following contents:

/core/en/messages

some.message=A message
another.key=Another key

This file would be exactly equivalent to the following two separate files:

/core/en/some/messages

message=A message

/core/en/another/messages

key=Another key

Whether you should use a single, file containing all the messages for your server, or split messages up into separate directories and smaller message files, is a matter of taste.

Note

Message keys are hierarchical. For example, some.msg is considered to be the parent of root.some.msg. So, when a message key is looked up, if it is not found, its parent key will be looked up, all the way to the root. If the server cannot find the root.some.msg key, for example, some.msg would be tried, and if that’s also not found, msg is also tried before giving up.

If a message key is defined in more than one message file under the same root directory, the order in which the message is resolved is undefined.

Warning

Prior to version 2.3.0, message files were only loaded on server startup, so if you are using a version prior to that and modify message files, changes will not be reflected in the running server until the next restart.

Message lookup

When a template uses the #message() directive, the Identity Server will try to resolve a message for the requested message key under the following subdirectories, in this order:

  1. template-areas/<template-area> (if applicable, see below)
  2. overrides
  3. core

Warning

The core directory should not be used for customizing messages: prefer to put all your custom messages files in either a template-area or overrides directories, as these directories are empty by default, making it easier to separate custom files from Curity default files.

Each directory under the above “root directories” is expected to match a particular Locale.

To lookup a message from a template, the #message('some.key') should is used. This directive is pre-loaded with the correct locale and template-area, if any.

First, the server will look for messages under the preferred locale, and if no message can be found, the server may also try the server’s default locale if this locale is not the same as, or a subset of, the preferred locale.

The server always attempts to find the message in the most specific locale possible. If the message is not found in the most specific locale, a less specific locale is tried if it exists.

If a message cannot be found even in the least specific locale that matches the preferred locale, the server’s default locale is tried (unless the default locale is a superset of the tried locales, as in that case it would never succeed).

Within each Locale, if a message cannot be found that matches exactly a specified key, a parent key is tried, up to the last remaining key part. A parent key is defined as the message key after removing the leftmost part. Different parts are separated by dots.

For example, the parent of message key `abc.def is def, hence if a template requests the key abc.def but no message is defined for that key, the def key will be used if it’s defined.

If a template-area is defined under a certain context (e.g. it is configured for an authenticator or OAuth Client), then the template-area is prepended to the message key. As an example, consider an authenticator which is configured to use the template area my-templates. When a template used by that authenticator requests message key abc.def, the initial message key will actually be my-templates.abc.def. This allows overriding only certain messages within a particular context, similar to how templates can be overridden within a certain template-area, as explained in The Template Override System.

Note

The template-areas/<template-area> directories can be used in such way that makes the templates directories mirror exactly the messages directories. This makes is easier to find messages that are only applicable on certain templates. However, note that, following the rules explained above, it is possible to define messages for a specific template-area even from the overrides messages files.

Message Lookup Use Case

To understand more easily how the lookup algorithm works, consider this common use case:

Default Locale: en.

Preferred Locale: sv_SE.

Message key requested: views.page.title.

The server will start looking for the message at messages files located under overrides/sv_SE.

If the key is not found, the server tries under the next root directory, core/sv_SE.

If the key is still not found, the server tries the sv locale. If the key is not found, the parent key page.title is searched for using the same process. If that’s also not found, title is looked for.

In case the key is not found, the process starts again, this time using the configured default-locale (en in this example).

Message Files Format

Message files may have one of the following formats:

Note

File names not matching the formats specified here are ignored.

messages files

Any file called messages is a messages file.

This is the simplest format and consists of single lines of message keys separated from the actual messages by an = character. Any lines not containing an = character is ignored.

Example of a messages file:

some.key=Some Message
this line is ignored
another.message=Another Message

The encoding should always be UTF-8.

Simple properties files

Any file with the .properties extension is considered a properties file.

The format of a properties file is specified in the Java properties class documentation.

The encoding of properties files may be either UTF-8 or ISO 8859-1.

XML properties files

Any file with the .xml extension is considered a properties file.

The format of a XML properties file is also specified in the Java properties class documentation.

The encoding of XML properties files must be specified in the file header.

Using plugin-specific messages in re-usable templates

Re-usable templates might be able to display messages for the specific plugin/template being rendered.

To make that easier, a variable called _templatePrefix is made available in the context of all templates, and can be used to specify that a message should come preferably from the message file that is specific to the page being rendered.

The _templatePrefix variable is normally used as follows:

Listing 202 Using reusable messages
1
2
3
4
5
6
7
  ## set a name-spaced message key
  #set($_errorMessageKey = "${_templatePrefix}.system.status.bad.request")

  ## set the actual error message using the name-spaced message key
  #set($_errorMessage = "#message($_errorMessageKey)")

  #parse("layouts/error")

The above template makes the plugin-specific message available for the error-layout template by setting the _errorMessage variable.

It can then be used in layouts/error.vm:

Listing 203 Using the _errorMessage variable
1
<h3>$!_errorMessage</h3>

Note

In Velocity templates, referring to a context variable is normally done by prefixing the variable name with a dollar sign $, as in $variable_name. If the variable does not exist, the literal value of the variable will be shown in the rendered page, in this case, $variable_name.

To show nothing instead, prefix the variable name with $!, as shown in the example above.