Localization and customization of ARD Core validation messages
When resources are sent to the ARD Mediathek/Audiothek, they are validated by the ARD Core API and may return error messages. The Metadata Supplier catches these messages and returns them as feedback to the user. Unfortunately these messages are written in English, which can be confusing for users speaking other languages, e.g. if all users work in a German-speaking environment. That is why the Metadata Supplier comes with German translations for these validation messages. You only have to configure the locale.
Setting the locale
The Metadata Supplier uses the default locale to determine the language for messages. To set the default locale to the language of your users you have to start the Metadata Supplier with the parameters user.language
and user.country
. See the JAVA_OPTS section in the Administration documentation.
I18N files
The messages are defined in language specific properties files (e.g. messages_de.properties
, messages_en.properties
, messages_fr.properties
, ...). If a message is not defined in a language specific properties file, the common properties file is used (e.g. messages.properties
). If the message is not contained there either, a common default message may be used. In case of validation messages from the ARD Mediathek/Audiothek that default comes directly from the response, which is always in English.
It is possible to add your own properties file(s) for the language of your users and you are free to overwrite (adapt) existing message texts to your requirements. Just create and put your file(s) in the "i18n" folder of your Metadata Supplier installation or your custom mapper plugin project.
The Metadata Supplier reads the following properties files in the "i18n" folder (including their language specific companions, e.g. messages_de.properties
, messages_en.properties
, messages_fr.properties
, ...):
ard-commons-messages.properties
configuration-service-messages.properties
delivery-api-messages.properties
messages.properties
source-field-name-messages.properties
The content of the properties files looks like this:
error.validation.value_string_empty=Must not be empty.
error.validation.max_length_exceeded=Max length of ${maxLength} exceeded.
error.deliveryapi.service.programming.image_binary.invalid_aspect_ratio=The aspect ratio of the image with the dimension ${width} x ${height} is not valid
Each line consists of a message key and its message text. As you can see, texts can have named placeholders, which are then replaced with the respective values. To change message texts to your requirements just add them to your own (translated) properties file(s), e.g. to a messages_de.properties
file:
error.validation.value_string_empty=Darf nicht leer sein.
error.validation.max_length_exceeded=Die maximale L\u00E4nge von ${maxLength} wurde \u00FCberschritten.
error.deliveryapi.service.programming.image_binary.invalid_aspect_ratio=Das Seitenverh\u00E4ltnis des Bildes mit den Abmessungen ${width} x ${height} ist nicht zul\u00E4ssig.
Additional placeholders
Besides the placeholders in the original message of the ARD Core API the Metadata Supplier supports the following placeholders:
${coreId}
=> Replaced by the Core-Id of the validated resource, e.g. "urn:ard:show:df106d3365ca1444"${resourceTypeName}
=> Replaced by the name of the type of the validated resource, e.g. SHOW, SEASON, ...${resourceFieldName}
=> Replaced by the name of the validated field, e.g. "title", "description", ...${sourceFieldName}
=> Replaced by the name (or label) of the mapped source field, e.g. "Title", "Headline", ... (if defined in thesource-field-name-messages
, otherwise falls back to the name of the validated field, e.g. "title", "description", ...)
So you are able to add further information to the texts, e.g. in messages_de.properties
:
error.validation.value_string_empty=Das Feld '${resourceFieldName}' in Ressourcen vom Typ '${resourceTypeName}' darf nicht leer sein.
This results in a text like this: "Das Feld 'title' in Ressourcen vom Typ 'SHOW' darf nicht leer sein.".
Since users do not know anything about the "title" field in a SHOW but they know the source document they are working on from which the SHOW is generated, you can help them to correct the failure by giving a hint to the original source field with the ${sourceFieldName}
placeholder and an entry in the source-field-name-messages
for the title field of a SHOW.
The entry in the messages_de.properties
looks like this:
error.validation.value_string_empty=Das Feld '${sourceFieldName}' darf nicht leer sein.
Add an entry for each ARD resource type and field into the source-field-name-messages
:
# Format:
# <ARD resource type>.<ARD resource field>=<Source label>
show.description=Beschreibung
show.title=\u00DCberschrift
show.thematicCategoryIds=Themenkategorien
season.title=Staffeltitel
image.title=Titel
This results in the text: "Das Feld Überschrift' darf nicht leer sein.". If no entry exists in the source-field-name-messages
the name of the validated field is used as fallback (e.g. "title", "description", ...)
${sourceFieldName}
only works for field mappings where a resource field (e.g. the 'title' field of an IMAGE) is always mapped by source fields with the same name or label from different source types (e.g. the 'Headline" field of source type A and the 'Headline' field of source type B and nothing else). For more complex mappings, e.g. if the image title is mapped from the 'Title' field of source type A and from the 'Headline' field of source type B, the source field should be validated in the mapping code before mapping it, in order to give helpful messages to the user.Changing messages during runtime
By default the loaded properties files are cached for 10 minutes, so that you are able to change the files without restarting the Metadata Supplier. You can configure this cache duration in your application.yml
:
i18n:
cache:
durationInSeconds: 20
- A value of "-1" is indicating to cache forever.
- A positive number will cache the loaded properties files for the given number of seconds. This is essentially the interval between refresh checks. Note that a refresh attempt will first check the last-modified timestamp of the file before actually reloading it; so if files don't change, this interval can be set rather low, as refresh attempts will not actually reload.
- A value of "0" will check the last-modified timestamp of the file on every message access. Do not use this in a production environment!
I18N in custom mapper plugins
To use the localization feature in your own mapper plugins, just inject the instance of org.springframework.context.MessageSource
into your Spring component class and use the getMessage(...)
methods with message code and arguments. To replace named placeholders in the message texts the arguments have to be of type com.subshell.ardcore.i18n.IArgument
and can be created by com.subshell.sophora.metadatasupplier.i18n.ArgumentCreator
.
You need a dependency to the I18N project:
<dependency>
<groupId>com.subshell.sophora.metadatasupplier</groupId>
<artifactId>metadata-supplier-i18n</artifactId>
<scope>provided</scope>
</dependency>
Example messages.properties
in "i18n" folder of the Metadata Supplier installation or "i18n" folder in your plugin jar file:
error.validation.max_length_exceeded=Max length of ${maxLength} exceeded.
Example code:
import com.subshell.ardcore.i18n.IArgument;
import com.subshell.sophora.metadatasupplier.i18n.ArgumentCreator;
import org.springframework.context.MessageSource;
[...]
@Autowired
MessageSource messageSource;
[...]
IArgument maxLengthArgument = ArgumentCreator.of("maxLength", "255");
String text = messageSource.getMessage("error.validation.max_length_exceeded", new Object[] {maxLengthArgument}, Locale.getDefault());
[...]
The result is "Max length of 255 exceeded."
Feedback messages
The following snippet shows how to use I18N in your own feedback messages:
[...]
if (myImageSourceObjects.isEmpty()) {
mappingContext.addFeedback(FeedbackType.ERROR, "error.no.images", Map.of("sourcetype", "show"));
// or
mappingContext.addFeedback(FeedbackType.ERROR, "A default message text", "error.no.images", Map.of("sourcetype", "show"));
}
[...]
In that case the messages.properties
of your mapper plugin has to contain a corresponding message code entry:
error.no.images=The ${sourcetype} has no images.
The result is "The show has no images."