i18n
Please note that the renderer sets themselves are not yet translatable. You can find the current status here: https://github.com/eclipsesource/jsonforms/issues/1826
The translate functionality of JSON Forms is integrated into the core component. In order to translate JSON Forms, you need to set a translation function and provide it to the JSON Forms component:
const createTranslator = (locale) => (key, defaultMessage) => {
console.log(`Locale: ${locale}, Key: ${key}, Default Message: ${defaultMessage}`);
return defaultMessage;
};
const [locale, setLocale] = useState<'de'|'en'>('de');
const translation = useMemo(() => createTranslator(locale), [locale]);
<JsonForms
i18n={{locale: locale, translate: translation}}
...
/>
The i18n
prop consists of three components: locale
, translate
and translateError
.
locale
Specifies the current locale of the application. This can be used by renderers to render locale specific UI elements, for example for locale-aware formatting of numbers.
translate
Provides a translation function handling the actual translation.
The translate function should be side effect free and should be stable (memoized) to avoid unnecessary re-renderings, i.e. the translate function should only change if there are new translations.
The type of the translate is
(key: string, defaultMessage: string | undefined, context: any) => string | undefined)
with the following parameters:
key
The key is used to identify the string that needs to be translated.
It can be set using the UI Schema
, the JSON Schema
or is generated by default based on the property path.
UI Schema option
The key can be set via the i18n
UI Schema option:
{
"type": "Control",
"label": "name",
"scope": "#/properties/name",
"i18n": "customName"
}
Therefore, the translation will be invoked with customName.label
& customName.description
.
JSON Schema
The key can also be set with the custom JSON Schema i18n
option:
{
"name": {
"type": "string",
"i18n": "myCustomName"
}
}
Therefore, the translation will be invoked with myCustomName.label
& myCustomName.description
.
Default: Property path
If none of the above is set, the property path will be used as the key.
{
"properties": {
"firstName": {
"type": "string"
},
"address": {
"type": "object",
"properties": {
"street": {
"type": "string"
}
}
},
"comments": {
"type": "array",
"items": {
"type": "object",
"properties": {
"message": {
"type": "string"
},
}
}
}
}
}
The paths in the above example are:
firstName.label
&firstName.description
address.label
&address.description
address.street.label
&address.street.description
comments.message.label
&comments.message.description
(the path for arrays will not contain indices)
defaultMessage
The default message is provided by JSON Forms and can act as a fallback or could be translated.
If the defaultMessage
is undefined
, you should also return undefined
if there is no translation for the given key.
Returning an empty string (or something similar) instead may result in undesired behavior.
JSON Forms will use undefined
when the message could be skipped or another more generic key could be tried.
context
context
can contain additional information for the current translation. The following parameters can be provided:
Parameter | Description |
---|---|
errors | Array of AJV errors, that occurred during validation |
path | The path of the translated element |
schema | The schema of the translated element |
uischema | The uischema of the translated element |
Schema translations provide all properties, while UI schema translations only provide the uischema
property.
translateError
The translateError
function is called whenever a single message is to be extracted from an AJV error object.
The type of the translateError
function is
(error: ErrorObject, translate: Translator, uischema?: UISchemaElement) => string
- The
error
is the AJV error object translate
is the i18ntranslate
function handed over to JSON Forms- In cases where a UI Schema Element can be correlated to an
error
it will also be handed over - The
translateError
function always returns astring
Usually this method does not need to be customized as JSON Forms already provides a sensible default implementation.
A reason to customize this method could be to integrate third party frameworks like ajv-i18n
.
For more information about how errors can be customized, see the following section:
Error Customizations
For each control a list of errors is determined. This section describes the default behavior of JSON forms to offer translation support for them.
<i18nkey>.error.custom
Before invoking the translateError
function, JSON Forms will check whether a <i18nkey>.error.custom
translation exists.
This is useful if there are many JSON Schema validaton keywords defined for a single property, but a single cohesive message shall be displayed.
If no <i18nkey>.error.custom
message is returned by the translate
function, translateError
will be called for each AJV error and the results combined.
The default implementation of translateError
will invoke translate
multiple times to determine the best message for the given error. Therefore it's usually not necessary to customize translateError
itself.
By default error it works like this:
<i18nkey>
in the sections below refers to the key of the field (see key
section above).
Evaluation order
<i18nkey>.error.<keyword>
Example keys: name.error.required
, address.street.error.pattern
The default translateError
will first look for a concrete message for a specific field and a specific error type.
error.<keyword>
Example keys: error.required
, error.pattern
After checking field specific translations, translateError
will then look for form-wide translations of errors, independent of each respective field.
This is useful to customize for example required
or pattern
messages for all properties.
error message
At last the default translateError
implementation will check whether the message
of the error object has a specific translation.
Default AJV error message
If none of the above apply, the message
provided by the AJV error object will be used.
Example
Consider the following schema for an object attribute:
{
phone: {
type: "string",
minLength: 10,
pattern: "^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$"
}
}
The order in which the error keys are evaluated is the following:
phone.error.custom
: if this is set, thepattern
andminLength
errors will be ignores and just this message is usedphone.error.pattern
&phone.error.minLength
error.pattern
&error.minLength
Enum translation
Enum translations are based on the respective entries:
- For JSON Schema
enum
, the stringified value is used. - For JSON Schema
oneOf
enums which consist of (title
,const
) pairs a specializedi18n
key ortitle
is used.
Therefore, in order to translate enum values, an additional key is checked for each enum entry.
For example:
Let's assume we have an enum attribute gender
, which looks like this:
{
gender: {
type: "string",
enum: ["male", "female", "other"]
}
}
In this case the translate
function will be invoked with the keys gender.male
, gender.female
and gender.other
to translate these enum values. In case gender
had an i18n
property, it would be used instead, i.e. <i18nkey>.male
etc.
Let's assume we have a oneOf
enum attribute gender which looks like this:
{
gender: {
oneOf: [
{
title: "Male",
const: 0
},
{
title: "Female",
const: "f",
i18n: "fem"
},
{
const: null
}
]
}
}
Here the requested keys are:
gender.Male
- property path +title
of theoneOf
entryfem
- direct usage of thei18n
property for theoneOf
entrynull
- thetitle
attribute is missing, therefore thenull
value is stringified to'null'
.
UI Schema Translation
The UI schema has the elements group
, category
and label
, which can also be translated.
If a i18n-key is provided in a group
or category
element, <i18n>.label
will be used as key.
If no i18n key is provided, the value of the label
-property is used as key.
In case neither a i18n-key nor a label is provided, <property-path>.label
will be used as default key.
The label
UI schema element will use <i18n>.text
as key, if provided.
If no i18n key is provided, the value of the text
-property is used as key.
Let's assume we have the following UI schema:
const uischema = {
type: 'VerticalLayout',
elements: [
{
type: 'Control',
scope: '#/properties/user',
options: {
detail: {
type: 'Group',
i18n: 'i18nUser',
}
}
},
{
type: 'Control',
scope: '#/properties/address',
options: {
detail: {
type: 'Group',
label: 'labelAddress',
}
}
},
{
type: 'Control',
scope: '#/properties/address'
},
{
type: 'Label',
i18n: 'i18nLabel'
},
{
type: 'Label',
text: 'textLabel'
},
]
};
Here the requested keys are:
i18nUser.label
- i18n +label
labelAddress
- direct usage of thelabel
propertyaddress.label
- property path +label
i18nLabel.text
- i18n +text
textLabel
- direct usage of thetext
property
Access translation in custom renderer sets
If you want to directly access the i18n properties within a custom renderer, you can use the JSON Forms context for that:
const ctx = useJsonForms();
const locale = ctx.i18n.locale;
const translate = ctx.i18n.translate;
const translateError = ctx.i18n.translateError;
With this you can for example change phone number patterns based on the current locale for validation.
Example
Current language: de