@object-ui/i18n 16.1.0 → 17.1.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/CHANGELOG.md +1133 -0
- package/dist/locales/ar.d.ts +825 -2
- package/dist/locales/ar.js +829 -5
- package/dist/locales/de.d.ts +823 -2
- package/dist/locales/de.js +827 -5
- package/dist/locales/en.d.ts +380 -6
- package/dist/locales/en.js +395 -8
- package/dist/locales/es.d.ts +823 -2
- package/dist/locales/es.js +827 -5
- package/dist/locales/fr.d.ts +825 -2
- package/dist/locales/fr.js +829 -5
- package/dist/locales/index.d.ts +7322 -76
- package/dist/locales/ja.d.ts +823 -2
- package/dist/locales/ja.js +827 -5
- package/dist/locales/ko.d.ts +823 -2
- package/dist/locales/ko.js +827 -5
- package/dist/locales/pt.d.ts +825 -2
- package/dist/locales/pt.js +829 -5
- package/dist/locales/ru.d.ts +825 -2
- package/dist/locales/ru.js +829 -5
- package/dist/locales/zh.d.ts +301 -5
- package/dist/locales/zh.js +303 -5
- package/dist/useObjectLabel.d.ts +24 -12
- package/dist/useObjectLabel.js +50 -41
- package/dist/useSafeTranslation.d.ts +2 -0
- package/dist/useSafeTranslation.js +7 -2
- package/package.json +3 -3
package/dist/useObjectLabel.js
CHANGED
|
@@ -57,6 +57,11 @@ export function useObjectLabel() {
|
|
|
57
57
|
* Returns top-level keys (outside built-in Object UI keys) that contain
|
|
58
58
|
* an `objects`, `fields`, or `apps` sub-key — e.g. "crm" when resources
|
|
59
59
|
* include crm.objects.* or crm.apps.*.
|
|
60
|
+
*
|
|
61
|
+
* `globalActions` is included so an app bundle whose only translated scope
|
|
62
|
+
* is global actions (no object/field entries) is still discovered — its
|
|
63
|
+
* `globalActions.<action>.*` overlays would otherwise be unreachable
|
|
64
|
+
* (objectui#3372).
|
|
60
65
|
*/
|
|
61
66
|
const getAppNamespaces = () => {
|
|
62
67
|
if (!i18n || typeof i18n.getResourceBundle !== 'function')
|
|
@@ -67,7 +72,8 @@ export function useObjectLabel() {
|
|
|
67
72
|
return [];
|
|
68
73
|
return Object.keys(bundle).filter((key) => !BUILTIN_KEYS.has(key) && bundle[key] && typeof bundle[key] === 'object'
|
|
69
74
|
&& (bundle[key].objects || bundle[key].fields || bundle[key].apps
|
|
70
|
-
|| bundle[key].dashboards || bundle[key].pages || bundle[key].reports
|
|
75
|
+
|| bundle[key].dashboards || bundle[key].pages || bundle[key].reports
|
|
76
|
+
|| bundle[key].globalActions));
|
|
71
77
|
};
|
|
72
78
|
/**
|
|
73
79
|
* Strip an ObjectStack namespace prefix (e.g. `crm__lead` → `lead`) so that
|
|
@@ -111,6 +117,30 @@ export function useObjectLabel() {
|
|
|
111
117
|
? [`objects.${objectName}.${tail}`, `objects.${base}.${tail}`]
|
|
112
118
|
: [`objects.${objectName}.${tail}`];
|
|
113
119
|
};
|
|
120
|
+
/**
|
|
121
|
+
* Build suffix candidates for an action-scoped key, mirroring the canonical
|
|
122
|
+
* `@objectstack/spec` resolver (`lookupActionField` in `system/i18n-resolver`).
|
|
123
|
+
*
|
|
124
|
+
* When the action is object-scoped, the object key
|
|
125
|
+
* (`objects.<obj>._actions.<action>.<tail>`) wins, but the global key
|
|
126
|
+
* (`globalActions.<action>.<tail>`) is appended as a fallback so a
|
|
127
|
+
* **globalAction surfaced on an object's action bar** still picks up its
|
|
128
|
+
* `globalActions.<action>.*` overlay when no object-scoped translation
|
|
129
|
+
* exists (objectui#3372). Without this fallback, a globalAction rendered on
|
|
130
|
+
* a record-detail action bar — where the caller passes `objectDef.name` for
|
|
131
|
+
* every action — misses `objects.<obj>._actions.<action>.label` and leaks the
|
|
132
|
+
* English metadata literal.
|
|
133
|
+
*
|
|
134
|
+
* Object-less actions (`objectName` omitted) resolve straight to the global
|
|
135
|
+
* namespace, as before. Object precedence is preserved: the global key is
|
|
136
|
+
* only consulted after every object-scoped candidate misses.
|
|
137
|
+
*/
|
|
138
|
+
const actionSuffixes = (objectName, actionName, tail) => {
|
|
139
|
+
const globalSuffix = `globalActions.${actionName}.${tail}`;
|
|
140
|
+
return objectName
|
|
141
|
+
? [...objectSuffixes(objectName, `_actions.${actionName}.${tail}`), globalSuffix]
|
|
142
|
+
: [globalSuffix];
|
|
143
|
+
};
|
|
114
144
|
const fieldSuffixes = (objectName, fieldName) => {
|
|
115
145
|
const base = stripNamespace(objectName);
|
|
116
146
|
return base !== objectName
|
|
@@ -298,38 +328,32 @@ export function useObjectLabel() {
|
|
|
298
328
|
sectionLabel: (objectName, sectionName, fallback) => resolve(objectSuffixes(objectName, `_sections.${sectionName}.label`), fallback),
|
|
299
329
|
/**
|
|
300
330
|
* Resolve translated action label.
|
|
301
|
-
* Convention: `{ns}.objects.{objectName}._actions.{actionName}.label
|
|
302
|
-
*
|
|
331
|
+
* Convention: `{ns}.objects.{objectName}._actions.{actionName}.label`,
|
|
332
|
+
* falling back to `{ns}.globalActions.{actionName}.label` — both when
|
|
333
|
+
* objectName is omitted AND when the object-scoped key misses (so a
|
|
334
|
+
* globalAction surfaced on a record-detail action bar still resolves;
|
|
335
|
+
* objectui#3372).
|
|
303
336
|
*/
|
|
304
|
-
actionLabel: (objectName, actionName, fallback) =>
|
|
305
|
-
if (objectName) {
|
|
306
|
-
return resolve(objectSuffixes(objectName, `_actions.${actionName}.label`), fallback);
|
|
307
|
-
}
|
|
308
|
-
return resolve(`globalActions.${actionName}.label`, fallback);
|
|
309
|
-
},
|
|
337
|
+
actionLabel: (objectName, actionName, fallback) => resolve(actionSuffixes(objectName, actionName, 'label'), fallback),
|
|
310
338
|
/**
|
|
311
339
|
* Resolve translated action confirmation prompt.
|
|
312
|
-
* Convention: `{ns}.objects.{objectName}._actions.{actionName}.confirmText
|
|
340
|
+
* Convention: `{ns}.objects.{objectName}._actions.{actionName}.confirmText`,
|
|
341
|
+
* falling back to `{ns}.globalActions.{actionName}.confirmText`.
|
|
313
342
|
* Returns undefined when no translation and no fallback exist.
|
|
314
343
|
*/
|
|
315
344
|
actionConfirm: (objectName, actionName, fallback) => {
|
|
316
345
|
const fb = fallback ?? '';
|
|
317
|
-
const
|
|
318
|
-
? objectSuffixes(objectName, `_actions.${actionName}.confirmText`)
|
|
319
|
-
: `globalActions.${actionName}.confirmText`;
|
|
320
|
-
const resolved = resolve(suffixes, fb);
|
|
346
|
+
const resolved = resolve(actionSuffixes(objectName, actionName, 'confirmText'), fb);
|
|
321
347
|
return resolved || undefined;
|
|
322
348
|
},
|
|
323
349
|
/**
|
|
324
350
|
* Resolve translated action success message.
|
|
325
|
-
* Convention: `{ns}.objects.{objectName}._actions.{actionName}.successMessage
|
|
351
|
+
* Convention: `{ns}.objects.{objectName}._actions.{actionName}.successMessage`,
|
|
352
|
+
* falling back to `{ns}.globalActions.{actionName}.successMessage`.
|
|
326
353
|
*/
|
|
327
354
|
actionSuccess: (objectName, actionName, fallback) => {
|
|
328
355
|
const fb = fallback ?? '';
|
|
329
|
-
const
|
|
330
|
-
? objectSuffixes(objectName, `_actions.${actionName}.successMessage`)
|
|
331
|
-
: `globalActions.${actionName}.successMessage`;
|
|
332
|
-
const resolved = resolve(suffixes, fb);
|
|
356
|
+
const resolved = resolve(actionSuffixes(objectName, actionName, 'successMessage'), fb);
|
|
333
357
|
return resolved || undefined;
|
|
334
358
|
},
|
|
335
359
|
/**
|
|
@@ -343,18 +367,16 @@ export function useObjectLabel() {
|
|
|
343
367
|
const fb = fallback ?? '';
|
|
344
368
|
if (!actionName)
|
|
345
369
|
return fb || undefined;
|
|
346
|
-
const
|
|
347
|
-
? objectSuffixes(objectName, `_actions.${actionName}.description`)
|
|
348
|
-
: `globalActions.${actionName}.description`;
|
|
349
|
-
const resolved = resolve(suffixes, fb);
|
|
370
|
+
const resolved = resolve(actionSuffixes(objectName, actionName, 'description'), fb);
|
|
350
371
|
return resolved || undefined;
|
|
351
372
|
},
|
|
352
373
|
/**
|
|
353
374
|
* Resolve a translated copy of an action's post-success RESULT DIALOG
|
|
354
375
|
* (`title` / `description` / `acknowledge` + per-field labels).
|
|
355
376
|
* Convention: `{ns}.objects.{objectName}._actions.{actionName}.resultDialog.*`,
|
|
356
|
-
* falling back to `{ns}.globalActions.{actionName}.resultDialog.*` when
|
|
357
|
-
* objectName is omitted, then to the
|
|
377
|
+
* falling back to `{ns}.globalActions.{actionName}.resultDialog.*` (when
|
|
378
|
+
* objectName is omitted OR the object-scoped key misses), then to the
|
|
379
|
+
* metadata's literal strings.
|
|
358
380
|
*
|
|
359
381
|
* The `fields` translation node is keyed by the LITERAL result-field path
|
|
360
382
|
* from the action metadata (may contain dots, e.g. `"user.email"`), so it
|
|
@@ -364,12 +386,7 @@ export function useObjectLabel() {
|
|
|
364
386
|
actionResultDialog: (objectName, actionName, spec) => {
|
|
365
387
|
if (!spec || !actionName)
|
|
366
388
|
return spec;
|
|
367
|
-
const suffixesFor = (attr) => {
|
|
368
|
-
const tail = `_actions.${actionName}.resultDialog.${attr}`;
|
|
369
|
-
return objectName
|
|
370
|
-
? objectSuffixes(objectName, tail)
|
|
371
|
-
: [`globalActions.${actionName}.resultDialog.${attr}`];
|
|
372
|
-
};
|
|
389
|
+
const suffixesFor = (attr) => actionSuffixes(objectName, actionName, `resultDialog.${attr}`);
|
|
373
390
|
const textFor = (attr) => {
|
|
374
391
|
const resolved = resolve(suffixesFor(attr), spec[attr] ?? '');
|
|
375
392
|
return resolved || spec[attr];
|
|
@@ -420,11 +437,7 @@ export function useObjectLabel() {
|
|
|
420
437
|
const fb = fallback ?? '';
|
|
421
438
|
if (!actionName || !paramName)
|
|
422
439
|
return fb || undefined;
|
|
423
|
-
const
|
|
424
|
-
const suffixes = objectName
|
|
425
|
-
? objectSuffixes(objectName, suffix)
|
|
426
|
-
: `globalActions.${actionName}.params.${paramName}.${attr}`;
|
|
427
|
-
const resolved = resolve(suffixes, fb);
|
|
440
|
+
const resolved = resolve(actionSuffixes(objectName, actionName, `params.${paramName}.${attr}`), fb);
|
|
428
441
|
return resolved || undefined;
|
|
429
442
|
},
|
|
430
443
|
/**
|
|
@@ -435,11 +448,7 @@ export function useObjectLabel() {
|
|
|
435
448
|
actionParamOptionLabel: (objectName, actionName, paramName, optionValue, fallback) => {
|
|
436
449
|
if (!actionName || !paramName)
|
|
437
450
|
return fallback;
|
|
438
|
-
|
|
439
|
-
const suffixes = objectName
|
|
440
|
-
? objectSuffixes(objectName, suffix)
|
|
441
|
-
: `globalActions.${actionName}.params.${paramName}.options.${optionValue}`;
|
|
442
|
-
return resolve(suffixes, fallback);
|
|
451
|
+
return resolve(actionSuffixes(objectName, actionName, `params.${paramName}.options.${optionValue}`), fallback);
|
|
443
452
|
},
|
|
444
453
|
};
|
|
445
454
|
}, [t, i18n]);
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export declare function createSafeTranslation(defaults: Record<string, string>, testKey: string): () => {
|
|
2
2
|
t: (key: string, options?: Record<string, unknown>) => string;
|
|
3
|
+
language: string;
|
|
3
4
|
} | {
|
|
4
5
|
t: import("i18next").TFunction<string, undefined>;
|
|
6
|
+
language: string;
|
|
5
7
|
};
|
|
6
8
|
/**
|
|
7
9
|
* Per-call graceful translate hook for plugin renderers.
|
|
@@ -32,10 +32,15 @@ export function createSafeTranslation(defaults, testKey) {
|
|
|
32
32
|
// "translations not configured" fallback.
|
|
33
33
|
const result = useObjectTranslation();
|
|
34
34
|
const testValue = result.t(testKey);
|
|
35
|
+
// `language` is surfaced so consumers that localize dates/numbers
|
|
36
|
+
// alongside their copy (data-table, gantt) don't have to call
|
|
37
|
+
// `useObjectTranslation` a second time just to read it. With no provider
|
|
38
|
+
// it is whatever react-i18next reports, which callers may treat as
|
|
39
|
+
// "follow the runtime default".
|
|
35
40
|
if (testValue === testKey) {
|
|
36
|
-
return { t: fallbackT };
|
|
41
|
+
return { t: fallbackT, language: result.language };
|
|
37
42
|
}
|
|
38
|
-
return { t: result.t };
|
|
43
|
+
return { t: result.t, language: result.language };
|
|
39
44
|
};
|
|
40
45
|
}
|
|
41
46
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@object-ui/i18n",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "17.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"license": "MIT",
|
|
@@ -31,14 +31,14 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"i18next": "^26.3.6",
|
|
34
|
-
"react-i18next": "^17.0.
|
|
34
|
+
"react-i18next": "^17.0.11"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
37
|
"react": "^18.0.0 || ^19.0.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/react": "19.2.17",
|
|
41
|
-
"react": "19.2.
|
|
41
|
+
"react": "19.2.8",
|
|
42
42
|
"typescript": "^6.0.3",
|
|
43
43
|
"vitest": "^4.1.10"
|
|
44
44
|
},
|