Skip to content

Commit 43bc382

Browse files
committed
Move i18n key specification from UI Schema options to ControlElement
* The i18n base key can no longer be specified as part of the UI Schema `options` * Add optional `i18n` property to `ControlElement` * Adapt i18n key resolution * Add explicit tests for i18n key extraction from UI Schema and Json Schema Fix #1942
1 parent 44070b3 commit 43bc382

File tree

4 files changed

+55
-4
lines changed

4 files changed

+55
-4
lines changed

packages/core/src/i18n/i18nUtil.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ErrorObject } from 'ajv';
2-
import { UISchemaElement } from '../models';
2+
import { isControlElement, UISchemaElement } from '../models';
33
import { getControlPath } from '../reducers';
44
import { formatErrorMessage } from '../util';
55
import { i18nJsonSchema, ErrorTranslator, Translator } from './i18nTypes';
@@ -8,7 +8,10 @@ export const getI18nKeyPrefixBySchema = (
88
schema: i18nJsonSchema | undefined,
99
uischema: UISchemaElement | undefined
1010
): string | undefined => {
11-
return uischema?.options?.i18n ?? schema?.i18n ?? undefined;
11+
if (uischema && isControlElement(uischema) && uischema.i18n) {
12+
return uischema.i18n;
13+
}
14+
return schema?.i18n ?? undefined;
1215
};
1316

1417
/**

packages/core/src/models/uischema.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,11 @@ export interface ControlElement extends UISchemaElement, Scopable {
213213
* An optional label that will be associated with the control
214214
*/
215215
label?: string | boolean | LabelDescription;
216+
/**
217+
* The i18n key for the control. It is used to identify the string that needs to be translated.
218+
* It is suffixed with `.label`, `.description` and `.error.<keyword>` to derive the corresponding message keys for the control.
219+
*/
220+
i18n?: string;
216221
}
217222

218223
/**
@@ -244,6 +249,9 @@ export interface Categorization extends UISchemaElement {
244249
elements: (Category | Categorization)[];
245250
}
246251

252+
export const isControlElement = (element: UISchemaElement): element is ControlElement =>
253+
element.type === 'Control';
254+
247255
export const isGroup = (layout: Layout): layout is GroupLayout =>
248256
layout.type === 'Group';
249257

packages/core/test/i18n/i18nUtil.test.ts

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
*/
2525
import test from 'ava';
2626

27-
import { transformPathToI18nPrefix } from '../../src';
27+
import { ControlElement, getI18nKeyPrefixBySchema, i18nJsonSchema, transformPathToI18nPrefix } from '../../src';
2828

2929
test('transformPathToI18nPrefix returns root when empty', t => {
3030
t.is(transformPathToI18nPrefix(''), 'root');
@@ -46,3 +46,43 @@ test('transformPathToI18nPrefix removes array indices', t => {
4646
t.is(transformPathToI18nPrefix('foo1.23.b2ar3.1.5.foo'), 'foo1.b2ar3.foo');
4747
t.is(transformPathToI18nPrefix('3'), 'root');
4848
});
49+
50+
test('getI18nKeyPrefixBySchema gets key from uischema over schema', t => {
51+
const control: ControlElement = {
52+
type: 'Control',
53+
scope: '#/properties/foo',
54+
i18n: 'controlFoo'
55+
};
56+
const schema: i18nJsonSchema = {
57+
type: 'string',
58+
i18n: 'schemaFoo'
59+
}
60+
t.is(getI18nKeyPrefixBySchema(schema, control), 'controlFoo');
61+
});
62+
63+
test('getI18nKeyPrefixBySchema gets schema key for missing uischema key', t => {
64+
const control: ControlElement = {
65+
type: 'Control',
66+
scope: '#/properties/foo',
67+
};
68+
const schema: i18nJsonSchema = {
69+
type: 'string',
70+
i18n: 'schemaFoo'
71+
}
72+
t.is(getI18nKeyPrefixBySchema(schema, control), 'schemaFoo');
73+
});
74+
75+
test('getI18nKeyPrefixBySchema returns undefined for missing uischema and schema keys', t => {
76+
const control: ControlElement = {
77+
type: 'Control',
78+
scope: '#/properties/foo',
79+
};
80+
const schema: i18nJsonSchema = {
81+
type: 'string',
82+
}
83+
t.is(getI18nKeyPrefixBySchema(schema, control), undefined);
84+
});
85+
86+
test('getI18nKeyPrefixBySchema returns undefined for undefined parameters', t => {
87+
t.is(getI18nKeyPrefixBySchema(undefined, undefined), undefined);
88+
});

packages/core/test/util/renderer.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1344,7 +1344,7 @@ test('mapStateToControlProps - i18n - translation via UI Schema i18n key', t =>
13441344
};
13451345
const state: JsonFormsState = createState(coreUISchema);
13461346
state.jsonforms.i18n = defaultJsonFormsI18nState;
1347-
ownProps.uischema = {...ownProps.uischema, options: {i18n: 'my-key'}};
1347+
ownProps.uischema = {...ownProps.uischema, i18n: 'my-key'};
13481348
state.jsonforms.i18n.translate = (key: string, defaultMessage: string | undefined) => {
13491349
switch(key){
13501350
case 'my-key.label': return 'my label';

0 commit comments

Comments
 (0)