@object-ui/i18n 13.2.0 → 14.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.
@@ -10,38 +10,32 @@
10
10
  */
11
11
  import { useObjectTranslation } from './provider';
12
12
  export function createSafeTranslation(defaults, testKey) {
13
- return function useSafeTranslation() {
14
- try {
15
- const result = useObjectTranslation();
16
- const testValue = result.t(testKey);
17
- if (testValue === testKey) {
18
- return {
19
- t: (key, options) => {
20
- let value = defaults[key] || key;
21
- if (options) {
22
- for (const [k, v] of Object.entries(options)) {
23
- value = value.replace(`{{${k}}}`, String(v));
24
- }
25
- }
26
- return value;
27
- },
28
- };
13
+ // Factory-level fallback: one stable reference per defaults map, so
14
+ // downstream useMemo/useCallback deps don't invalidate every render in
15
+ // the no-translations case.
16
+ const fallbackT = (key, options) => {
17
+ let value = defaults[key] || key;
18
+ if (options) {
19
+ for (const [k, v] of Object.entries(options)) {
20
+ value = value.replace(`{{${k}}}`, String(v));
29
21
  }
30
- return { t: result.t };
31
22
  }
32
- catch {
33
- return {
34
- t: (key, options) => {
35
- let value = defaults[key] || key;
36
- if (options) {
37
- for (const [k, v] of Object.entries(options)) {
38
- value = value.replace(`{{${k}}}`, String(v));
39
- }
40
- }
41
- return value;
42
- },
43
- };
23
+ return value;
24
+ };
25
+ return function useSafeTranslation() {
26
+ // No try/catch around the hook: useObjectTranslation is provider-safe
27
+ // (optional context read + react-i18next global-instance fallback), and
28
+ // wrapping a hook call in try/catch violates rules-of-hooks — a throw
29
+ // after the hook ran would desync hook order on the next render (same
30
+ // fix as objectui#2595/#2596; this factory closure just escaped the
31
+ // static lint). The testKey probe below carries the actual
32
+ // "translations not configured" fallback.
33
+ const result = useObjectTranslation();
34
+ const testValue = result.t(testKey);
35
+ if (testValue === testKey) {
36
+ return { t: fallbackT };
44
37
  }
38
+ return { t: result.t };
45
39
  };
46
40
  }
47
41
  /**
@@ -57,16 +51,11 @@ export function createSafeTranslation(defaults, testKey) {
57
51
  * `tt(['common.total', 'dashboard.total'], 'Total')`.
58
52
  */
59
53
  export function useSafeTranslate() {
60
- let t;
61
- try {
62
- t = useObjectTranslation().t;
63
- }
64
- catch {
65
- t = undefined;
66
- }
54
+ // Unconditional hook call (rules-of-hooks) — the hook is provider-safe,
55
+ // and a missing translation surfaces as `t(key) === key` per key below,
56
+ // never as a throw. Same fix as createSafeTranslation above.
57
+ const { t } = useObjectTranslation();
67
58
  return (keyOrKeys, fallback) => {
68
- if (!t)
69
- return fallback;
70
59
  const keys = Array.isArray(keyOrKeys) ? keyOrKeys : [keyOrKeys];
71
60
  for (const key of keys) {
72
61
  const v = t(key);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@object-ui/i18n",
3
- "version": "13.2.0",
3
+ "version": "14.1.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "license": "MIT",
@@ -30,8 +30,8 @@
30
30
  }
31
31
  },
32
32
  "dependencies": {
33
- "i18next": "^26.3.4",
34
- "react-i18next": "^17.0.8"
33
+ "i18next": "^26.3.6",
34
+ "react-i18next": "^17.0.9"
35
35
  },
36
36
  "peerDependencies": {
37
37
  "react": "^18.0.0 || ^19.0.0"