As mentioned in Introduction, message files are located under the <installation-dir>/usr/share/messages directory’s “root” subdirectories:
<installation-dir>/usr/share/messages
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.
en
sv_SE
Message files should be added to one of the root directories mentioned in the Message lookup section.
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.
Localization
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.
ui_locales
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.
Accept-Language
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.
<language>[_<country>]
<language>[-<country>]
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.
en_US
en-us-xx-yy
en-us.backup-copy
Templates may include localized messages with the #message() directive. The following is an example template that uses that:
#message()
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.
#message("view.some-info")
"view.some-info"
"some-info"
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.
<template-area>.<template-prefix>.email.subject
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.
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.
some.msg
root.some.msg
msg
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.
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:
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.
template-area
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.
#message('some.key')
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.
`abc.def
def
abc.def
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.
my-templates
my-templates.abc.def
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.
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.
overrides/sv_SE
If the key is not found, the server tries under the next root directory, core/sv_SE.
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.
sv
page.title
title
In case the key is not found, the process starts again, this time using the configured default-locale (en in this example).
Message files may have one of the following formats:
File names not matching the formats specified here are ignored.
Any file called messages is a messages file.
messages
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.
UTF-8
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.
ISO 8859-1
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.
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.
_templatePrefix
The _templatePrefix variable is normally used as follows:
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.
_errorMessage
It can then be used in layouts/error.vm:
layouts/error.vm
1
<h3>$!_errorMessage</h3>
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.
$
$variable_name
To show nothing instead, prefix the variable name with $!, as shown in the example above.
$!