ckeditor5-livewire 1.5.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hooks/context/context.d.ts.map +1 -1
- package/dist/hooks/editor/editor.d.ts.map +1 -1
- package/dist/hooks/editor/utils/index.d.ts +1 -0
- package/dist/hooks/editor/utils/index.d.ts.map +1 -1
- package/dist/hooks/editor/utils/load-editor-translations.d.ts +2 -1
- package/dist/hooks/editor/utils/load-editor-translations.d.ts.map +1 -1
- package/dist/hooks/editor/utils/resolve-editor-config-translations.d.ts +25 -0
- package/dist/hooks/editor/utils/resolve-editor-config-translations.d.ts.map +1 -0
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +216 -191
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/hooks/context/context.test.ts +77 -52
- package/src/hooks/context/context.ts +9 -1
- package/src/hooks/editor/editor.test.ts +33 -0
- package/src/hooks/editor/editor.ts +8 -1
- package/src/hooks/editor/utils/index.ts +1 -0
- package/src/hooks/editor/utils/load-editor-translations.ts +3 -1
- package/src/hooks/editor/utils/resolve-editor-config-translations.test.ts +131 -0
- package/src/hooks/editor/utils/resolve-editor-config-translations.ts +77 -0
package/package.json
CHANGED
|
@@ -106,7 +106,7 @@ describe('context component', () => {
|
|
|
106
106
|
expect(context?.plugins.get('CustomPlugin')).toBeInstanceOf(CustomPlugin);
|
|
107
107
|
});
|
|
108
108
|
|
|
109
|
-
|
|
109
|
+
describe('language', () => {
|
|
110
110
|
class CustomPlugin extends ContextPlugin {
|
|
111
111
|
static get pluginName() {
|
|
112
112
|
return 'CustomPlugin';
|
|
@@ -117,71 +117,96 @@ describe('context component', () => {
|
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
|
|
120
|
+
beforeEach(() => {
|
|
121
|
+
CustomEditorPluginsRegistry.the.register('CustomPlugin', () => CustomPlugin);
|
|
122
|
+
});
|
|
121
123
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
124
|
+
it('registered plugins should support custom translations', async () => {
|
|
125
|
+
livewireStub.$internal.appendComponentToDOM({
|
|
126
|
+
name: 'ckeditor5-context',
|
|
127
|
+
el: createContextHtmlElement(),
|
|
128
|
+
canonical: createContextSnapshot(DEFAULT_TEST_CONTEXT_ID, {
|
|
129
|
+
customTranslations: {
|
|
130
|
+
en: {
|
|
131
|
+
HELLO: 'Hello from CustomPlugin',
|
|
132
|
+
},
|
|
129
133
|
},
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
},
|
|
134
|
-
})
|
|
135
|
-
});
|
|
134
|
+
config: {
|
|
135
|
+
plugins: ['CustomPlugin'],
|
|
136
|
+
},
|
|
137
|
+
}),
|
|
138
|
+
});
|
|
136
139
|
|
|
137
|
-
|
|
138
|
-
|
|
140
|
+
const { context } = await waitForTestContext();
|
|
141
|
+
const plugin = context?.plugins.get('CustomPlugin') as CustomPlugin;
|
|
139
142
|
|
|
140
|
-
|
|
141
|
-
|
|
143
|
+
expect(plugin.getHelloTitle()).toBe('Hello from CustomPlugin');
|
|
144
|
+
});
|
|
142
145
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
146
|
+
it('should support custom language for context translations', async () => {
|
|
147
|
+
livewireStub.$internal.appendComponentToDOM({
|
|
148
|
+
name: 'ckeditor5-context',
|
|
149
|
+
el: createContextHtmlElement(),
|
|
150
|
+
canonical: createContextSnapshot(
|
|
151
|
+
DEFAULT_TEST_CONTEXT_ID,
|
|
152
|
+
{
|
|
153
|
+
customTranslations: {
|
|
154
|
+
en: {
|
|
155
|
+
HELLO: 'Hello from CustomPlugin',
|
|
156
|
+
},
|
|
157
|
+
pl: {
|
|
158
|
+
HELLO: 'Witaj z CustomPlugin',
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
config: {
|
|
162
|
+
plugins: ['CustomPlugin'],
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
ui: 'pl',
|
|
167
|
+
content: 'pl',
|
|
168
|
+
},
|
|
169
|
+
),
|
|
170
|
+
});
|
|
148
171
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
}
|
|
172
|
+
const { context } = await waitForTestContext();
|
|
173
|
+
const plugin = context?.plugins.get('CustomPlugin') as CustomPlugin;
|
|
153
174
|
|
|
154
|
-
|
|
175
|
+
expect(plugin.getHelloTitle()).toBe('Witaj z CustomPlugin');
|
|
176
|
+
});
|
|
155
177
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
178
|
+
it('should resolve $translation references in the context configuration', async () => {
|
|
179
|
+
livewireStub.$internal.appendComponentToDOM({
|
|
180
|
+
name: 'ckeditor5-context',
|
|
181
|
+
el: createContextHtmlElement(),
|
|
182
|
+
canonical: createContextSnapshot(
|
|
183
|
+
DEFAULT_TEST_CONTEXT_ID,
|
|
184
|
+
{
|
|
185
|
+
customTranslations: {
|
|
186
|
+
en: {
|
|
187
|
+
Custom: 'Custom value',
|
|
188
|
+
},
|
|
189
|
+
pl: {
|
|
190
|
+
Custom: 'Wartość niestandardowa',
|
|
191
|
+
},
|
|
165
192
|
},
|
|
166
|
-
|
|
167
|
-
|
|
193
|
+
config: {
|
|
194
|
+
customPlugin: {
|
|
195
|
+
label: { $translation: 'Custom' },
|
|
196
|
+
},
|
|
168
197
|
},
|
|
169
198
|
},
|
|
170
|
-
|
|
171
|
-
|
|
199
|
+
{
|
|
200
|
+
ui: 'pl',
|
|
201
|
+
content: 'pl',
|
|
172
202
|
},
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
ui: 'pl',
|
|
176
|
-
content: 'pl',
|
|
177
|
-
},
|
|
178
|
-
),
|
|
179
|
-
});
|
|
203
|
+
),
|
|
204
|
+
});
|
|
180
205
|
|
|
181
|
-
|
|
182
|
-
const plugin = context?.plugins.get('CustomPlugin') as CustomPlugin;
|
|
206
|
+
const { context } = await waitForTestContext();
|
|
183
207
|
|
|
184
|
-
|
|
208
|
+
expect((context!.config.get('customPlugin') as any).label).toBe('Wartość niestandardowa');
|
|
209
|
+
});
|
|
185
210
|
});
|
|
186
211
|
});
|
|
187
212
|
|
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
loadAllEditorTranslations,
|
|
10
10
|
loadEditorPlugins,
|
|
11
11
|
normalizeCustomTranslations,
|
|
12
|
+
resolveEditorConfigElementReferences,
|
|
13
|
+
resolveEditorConfigTranslations,
|
|
12
14
|
} from '../editor/utils';
|
|
13
15
|
import { ContextsRegistry } from './contexts-registry';
|
|
14
16
|
|
|
@@ -47,8 +49,14 @@ export class ContextComponentHook extends ClassHook<Snapshot> {
|
|
|
47
49
|
...watchdogConfig,
|
|
48
50
|
});
|
|
49
51
|
|
|
52
|
+
// Construct parsed config. First resolve DOM element references in the provided configuration.
|
|
53
|
+
let resolvedConfig = resolveEditorConfigElementReferences(config);
|
|
54
|
+
|
|
55
|
+
// Then resolve translation references in the provided configuration, using the mixed translations.
|
|
56
|
+
resolvedConfig = resolveEditorConfigTranslations([...mixedTranslations].reverse(), language.ui, resolvedConfig);
|
|
57
|
+
|
|
50
58
|
await instance.create({
|
|
51
|
-
...
|
|
59
|
+
...resolvedConfig,
|
|
52
60
|
language,
|
|
53
61
|
plugins: loadedPlugins,
|
|
54
62
|
...mixedTranslations.length && {
|
|
@@ -531,6 +531,39 @@ describe('editor component', () => {
|
|
|
531
531
|
|
|
532
532
|
expect(editor.t('Bold')).toBe('Czcionka grubaśna');
|
|
533
533
|
});
|
|
534
|
+
|
|
535
|
+
it('should resolve $translation references in the editor configuration', async () => {
|
|
536
|
+
const preset = createEditorPreset(
|
|
537
|
+
'classic',
|
|
538
|
+
{
|
|
539
|
+
customPlugin: {
|
|
540
|
+
label: { $translation: 'Custom' },
|
|
541
|
+
},
|
|
542
|
+
},
|
|
543
|
+
{
|
|
544
|
+
pl: {
|
|
545
|
+
Custom: 'Mocarna czcionka',
|
|
546
|
+
},
|
|
547
|
+
},
|
|
548
|
+
);
|
|
549
|
+
|
|
550
|
+
livewireStub.$internal.appendComponentToDOM<EditorSnapshot>({
|
|
551
|
+
name: 'ckeditor5',
|
|
552
|
+
el: createEditorHtmlElement(),
|
|
553
|
+
canonical: {
|
|
554
|
+
...createEditorSnapshot(),
|
|
555
|
+
preset,
|
|
556
|
+
language: {
|
|
557
|
+
ui: 'pl',
|
|
558
|
+
content: 'pl',
|
|
559
|
+
},
|
|
560
|
+
},
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
const editor = await waitForTestEditor();
|
|
564
|
+
|
|
565
|
+
expect((editor.config.get('customPlugin') as any).label).toBe('Mocarna czcionka');
|
|
566
|
+
});
|
|
534
567
|
});
|
|
535
568
|
|
|
536
569
|
describe('`watchdog` snapshot parameter`', () => {
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
queryEditablesElements,
|
|
22
22
|
queryEditablesSnapshotContent,
|
|
23
23
|
resolveEditorConfigElementReferences,
|
|
24
|
+
resolveEditorConfigTranslations,
|
|
24
25
|
setEditorEditableHeight,
|
|
25
26
|
unwrapEditorContext,
|
|
26
27
|
unwrapEditorWatchdog,
|
|
@@ -222,9 +223,15 @@ export class EditorComponentHook extends ClassHook<Snapshot> {
|
|
|
222
223
|
sourceElements = sourceElements['main'];
|
|
223
224
|
}
|
|
224
225
|
|
|
226
|
+
// Construct parsed config. First resolve DOM element references in the provided configuration.
|
|
227
|
+
let resolvedConfig = resolveEditorConfigElementReferences(config);
|
|
228
|
+
|
|
229
|
+
// Then resolve translation references in the provided configuration, using the mixed translations.
|
|
230
|
+
resolvedConfig = resolveEditorConfigTranslations([...mixedTranslations].reverse(), language.ui, resolvedConfig);
|
|
231
|
+
|
|
225
232
|
// Construct parsed config.
|
|
226
233
|
const parsedConfig = {
|
|
227
|
-
...
|
|
234
|
+
...resolvedConfig,
|
|
228
235
|
initialData,
|
|
229
236
|
licenseKey,
|
|
230
237
|
plugins: loadedPlugins,
|
|
@@ -8,5 +8,6 @@ export * from './load-editor-translations';
|
|
|
8
8
|
export * from './normalize-custom-translations';
|
|
9
9
|
export * from './query-editor-editables';
|
|
10
10
|
export * from './resolve-editor-config-elements-references';
|
|
11
|
+
export * from './resolve-editor-config-translations';
|
|
11
12
|
export * from './set-editor-editable-height';
|
|
12
13
|
export * from './wrap-with-watchdog';
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { Translations } from 'ckeditor5';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Loads all required translations for the editor based on the language configuration.
|
|
3
5
|
*
|
|
@@ -10,7 +12,7 @@
|
|
|
10
12
|
export async function loadAllEditorTranslations(
|
|
11
13
|
language: { ui: string; content: string; },
|
|
12
14
|
hasPremium: boolean,
|
|
13
|
-
) {
|
|
15
|
+
): Promise<Translations[]> {
|
|
14
16
|
const translations = [language.ui, language.content];
|
|
15
17
|
const loadedTranslations = await Promise.all(
|
|
16
18
|
[
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import type { Translations } from 'ckeditor5';
|
|
2
|
+
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
4
|
+
|
|
5
|
+
import { resolveEditorConfigTranslations } from './resolve-editor-config-translations';
|
|
6
|
+
|
|
7
|
+
describe('resolveEditorConfigTranslations', () => {
|
|
8
|
+
let translationsPacks: Translations[];
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
translationsPacks = [
|
|
12
|
+
makePack('en', {
|
|
13
|
+
HELLO: 'Hello world',
|
|
14
|
+
NESTED: 'nested value',
|
|
15
|
+
ARRAY: 'array value',
|
|
16
|
+
}),
|
|
17
|
+
];
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
vi.restoreAllMocks();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('resolves a single translation reference', () => {
|
|
25
|
+
const config = {
|
|
26
|
+
foo: { $translation: 'HELLO' },
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const result = resolveEditorConfigTranslations(translationsPacks, 'en', config);
|
|
30
|
+
expect(result.foo).toBe('Hello world');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('respects specified language when multiple packs present', () => {
|
|
34
|
+
const packs: Translations[] = [
|
|
35
|
+
makePack('en', { KEY: 'english' }),
|
|
36
|
+
makePack('pl', { KEY: 'polish' }),
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
const result = resolveEditorConfigTranslations(packs, 'pl', { foo: { $translation: 'KEY' } });
|
|
40
|
+
expect(result.foo).toBe('polish');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('returns null if translation key not found', () => {
|
|
44
|
+
const config = {
|
|
45
|
+
foo: { $translation: 'MISSING' },
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const result = resolveEditorConfigTranslations(translationsPacks, 'en', config);
|
|
49
|
+
expect(result.foo).toBeNull();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('recursively resolves nested translation references', () => {
|
|
53
|
+
const config = {
|
|
54
|
+
nested: {
|
|
55
|
+
bar: { $translation: 'NESTED' },
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const result = resolveEditorConfigTranslations(translationsPacks, 'en', config);
|
|
60
|
+
expect(result.nested.bar).toBe('nested value');
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('resolves translation references in arrays', () => {
|
|
64
|
+
const config = [
|
|
65
|
+
{ $translation: 'HELLO' },
|
|
66
|
+
{ $translation: 'ARRAY' },
|
|
67
|
+
{ notTranslation: 123 },
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
const result = resolveEditorConfigTranslations(translationsPacks, 'en', config);
|
|
71
|
+
|
|
72
|
+
expect(result[0]).toBe('Hello world');
|
|
73
|
+
expect(result[1]).toBe('array value');
|
|
74
|
+
expect(result[2]).toEqual({ notTranslation: 123 });
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('returns primitives as is', () => {
|
|
78
|
+
expect(resolveEditorConfigTranslations(translationsPacks, 'en', 42 as any)).toBe(42);
|
|
79
|
+
expect(resolveEditorConfigTranslations(translationsPacks, 'en', 'foo' as any)).toBe('foo');
|
|
80
|
+
expect(resolveEditorConfigTranslations(translationsPacks, 'en', null as any)).toBe(null);
|
|
81
|
+
expect(resolveEditorConfigTranslations(translationsPacks, 'en', undefined as any)).toBe(undefined);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('warns for missing translation key', () => {
|
|
85
|
+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
86
|
+
const config = { foo: { $translation: 'UNKNOWN' } };
|
|
87
|
+
|
|
88
|
+
resolveEditorConfigTranslations(translationsPacks, 'en', config);
|
|
89
|
+
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('Translation not found for key: UNKNOWN'));
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('selects translations based on the provided language when multiple packs are given', () => {
|
|
93
|
+
const packs: Translations[] = [
|
|
94
|
+
makePack('en', { HELLO: 'Hello world', ARRAY: 'array value' }),
|
|
95
|
+
makePack('pl', { NESTED: 'nested value' }),
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
const config = {
|
|
99
|
+
foo: { $translation: 'HELLO' },
|
|
100
|
+
nested: { bar: { $translation: 'NESTED' } },
|
|
101
|
+
arr: [{ $translation: 'ARRAY' }],
|
|
102
|
+
missing: { $translation: 'NOTHING' },
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
106
|
+
const resultEn = resolveEditorConfigTranslations(packs, 'en', config);
|
|
107
|
+
|
|
108
|
+
expect(resultEn.foo).toBe('Hello world');
|
|
109
|
+
expect(resultEn.nested.bar).toBeNull();
|
|
110
|
+
expect(resultEn.arr[0]).toBe('array value');
|
|
111
|
+
expect(resultEn.missing).toBeNull();
|
|
112
|
+
|
|
113
|
+
const resultPl = resolveEditorConfigTranslations(packs, 'pl', config);
|
|
114
|
+
|
|
115
|
+
expect(resultPl.foo).toBeNull();
|
|
116
|
+
expect(resultPl.nested.bar).toBe('nested value');
|
|
117
|
+
expect(resultPl.arr[0]).toBeNull();
|
|
118
|
+
expect(resultPl.missing).toBeNull();
|
|
119
|
+
|
|
120
|
+
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('Translation not found for key: NOTHING'));
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
function makePack(lang: string, dict: Record<string, string>): Translations {
|
|
125
|
+
return {
|
|
126
|
+
[lang]: {
|
|
127
|
+
dictionary: dict,
|
|
128
|
+
getPluralForm: null,
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { Translations } from 'ckeditor5';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Resolves translation references in a configuration object.
|
|
5
|
+
*
|
|
6
|
+
* The configuration may contain objects with the form `{ $translation: "some.key" }`.
|
|
7
|
+
* These are replaced with the actual string from the provided translations map.
|
|
8
|
+
*
|
|
9
|
+
* The function will walk the provided object recursively, handling arrays and
|
|
10
|
+
* nested objects. Primitive values are returned as-is. If a translation key is
|
|
11
|
+
* not present in the map, a warning is logged and `null` is returned for that
|
|
12
|
+
* value.
|
|
13
|
+
*
|
|
14
|
+
* @param translations - An array of CKEditor `Translations` objects. Each translation
|
|
15
|
+
* pack will be searched in order for the requested key, and the
|
|
16
|
+
* first matching value will be returned. This mirrors the format
|
|
17
|
+
* returned by `loadAllEditorTranslations` and simplifies the
|
|
18
|
+
* caller's API.
|
|
19
|
+
* @param language - Language identifier to look up in the packs. Only this locale
|
|
20
|
+
* will be consulted, ensuring that keys from other languages are
|
|
21
|
+
* ignored even if they appear earlier in the array.
|
|
22
|
+
* @param obj - Configuration object to process
|
|
23
|
+
* @returns Processed configuration object with resolved translations.
|
|
24
|
+
*/
|
|
25
|
+
export function resolveEditorConfigTranslations<T>(
|
|
26
|
+
translations: Translations[],
|
|
27
|
+
language: string,
|
|
28
|
+
obj: T,
|
|
29
|
+
): T {
|
|
30
|
+
if (!obj || typeof obj !== 'object') {
|
|
31
|
+
return obj;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (Array.isArray(obj)) {
|
|
35
|
+
return obj.map(item => resolveEditorConfigTranslations(translations, language, item)) as T;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const anyObj = obj as any;
|
|
39
|
+
|
|
40
|
+
if (anyObj.$translation && typeof anyObj.$translation === 'string') {
|
|
41
|
+
const key: string = anyObj.$translation;
|
|
42
|
+
const value = getTranslationValue(translations, key, language);
|
|
43
|
+
|
|
44
|
+
if (value === undefined) {
|
|
45
|
+
console.warn(`Translation not found for key: ${key}`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return (value !== undefined ? value : null) as T;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const result = Object.create(null);
|
|
52
|
+
|
|
53
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
54
|
+
result[key] = resolveEditorConfigTranslations(translations, language, value);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return result as T;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Look up a translation value inside the provided map or array of CKEditor packs.
|
|
62
|
+
*/
|
|
63
|
+
function getTranslationValue(
|
|
64
|
+
translations: Translations[],
|
|
65
|
+
key: string,
|
|
66
|
+
language: string,
|
|
67
|
+
): string | ReadonlyArray<string> | undefined {
|
|
68
|
+
for (const pack of translations) {
|
|
69
|
+
const langData = pack[language];
|
|
70
|
+
|
|
71
|
+
if (langData?.dictionary && key in langData.dictionary) {
|
|
72
|
+
return langData.dictionary[key] as string | ReadonlyArray<string>;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|