@object-ui/i18n 15.0.0 → 16.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.
@@ -349,6 +349,67 @@ export function useObjectLabel() {
349
349
  const resolved = resolve(suffixes, fb);
350
350
  return resolved || undefined;
351
351
  },
352
+ /**
353
+ * Resolve a translated copy of an action's post-success RESULT DIALOG
354
+ * (`title` / `description` / `acknowledge` + per-field labels).
355
+ * Convention: `{ns}.objects.{objectName}._actions.{actionName}.resultDialog.*`,
356
+ * falling back to `{ns}.globalActions.{actionName}.resultDialog.*` when
357
+ * objectName is omitted, then to the metadata's literal strings.
358
+ *
359
+ * The `fields` translation node is keyed by the LITERAL result-field path
360
+ * from the action metadata (may contain dots, e.g. `"user.email"`), so it
361
+ * is fetched whole with `returnObjects` and indexed directly — never
362
+ * resolved through a dotted i18next key.
363
+ */
364
+ actionResultDialog: (objectName, actionName, spec) => {
365
+ if (!spec || !actionName)
366
+ 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
+ };
373
+ const textFor = (attr) => {
374
+ const resolved = resolve(suffixesFor(attr), spec[attr] ?? '');
375
+ return resolved || spec[attr];
376
+ };
377
+ const fieldsMap = (() => {
378
+ try {
379
+ for (const ns of getAppNamespaces()) {
380
+ for (const suffix of suffixesFor('fields')) {
381
+ const node = t(`${ns}.${suffix}`, {
382
+ returnObjects: true,
383
+ defaultValue: null,
384
+ [I18N_PROBE_FLAG]: true,
385
+ });
386
+ if (node && typeof node === 'object' && !Array.isArray(node)) {
387
+ return node;
388
+ }
389
+ }
390
+ }
391
+ }
392
+ catch {
393
+ // Graceful degradation when i18n provider is not available
394
+ }
395
+ return undefined;
396
+ })();
397
+ const fields = Array.isArray(spec.fields)
398
+ ? spec.fields.map((field) => {
399
+ if (!field || typeof field.path !== 'string')
400
+ return field;
401
+ const label = fieldsMap?.[field.path];
402
+ return typeof label === 'string' && label.length > 0 ? { ...field, label } : field;
403
+ })
404
+ : spec.fields;
405
+ return {
406
+ ...spec,
407
+ title: textFor('title'),
408
+ description: textFor('description'),
409
+ acknowledge: textFor('acknowledge'),
410
+ fields,
411
+ };
412
+ },
352
413
  /**
353
414
  * Resolve translated action-PARAMETER text (label / placeholder / helpText).
354
415
  * Convention: `{ns}.objects.{objectName}._actions.{actionName}.params.{paramName}.{attr}`.
@@ -402,15 +463,10 @@ const SAFE_FIELD_LABEL_FALLBACK = {
402
463
  * may be rendered outside an i18n context.
403
464
  */
404
465
  export function useSafeFieldLabel() {
405
- let resolved = null;
406
- try {
407
- resolved = useObjectLabel();
408
- }
409
- catch {
410
- resolved = null;
411
- }
412
- // useObjectLabel already returns a stable (memoized) object per language —
413
- // pass-through avoids creating a fresh wrapper here. The module-level
414
- // fallback object is reused when no provider is mounted.
415
- return resolved ?? SAFE_FIELD_LABEL_FALLBACK;
466
+ // useObjectLabel delegates to the provider-safe useObjectTranslation (react-
467
+ // i18next falls back to the global instance and never throws), so it needs no
468
+ // try/catch — wrapping the hook call would violate rules-of-hooks. It already
469
+ // returns a stable memoized object; the module-level fallback stays as a
470
+ // defensive default, reached only if it ever returns nullish.
471
+ return useObjectLabel() ?? SAFE_FIELD_LABEL_FALLBACK;
416
472
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@object-ui/i18n",
3
- "version": "15.0.0",
3
+ "version": "16.1.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "license": "MIT",
@@ -31,7 +31,7 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "i18next": "^26.3.6",
34
- "react-i18next": "^17.0.9"
34
+ "react-i18next": "^17.0.10"
35
35
  },
36
36
  "peerDependencies": {
37
37
  "react": "^18.0.0 || ^19.0.0"