@object-ui/i18n 17.5.0 → 17.7.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 +4954 -0
- package/README.md +234 -13
- package/dist/builtinAggregateLabels.d.ts +40 -0
- package/dist/builtinAggregateLabels.js +23 -0
- package/dist/currency.d.ts +27 -3
- package/dist/currency.js +28 -4
- package/dist/fallbackInterpolation.d.ts +79 -0
- package/dist/fallbackInterpolation.js +124 -0
- package/dist/i18n.d.ts +28 -2
- package/dist/i18n.js +99 -17
- package/dist/index.d.ts +17 -23
- package/dist/index.js +51 -27
- package/dist/locales/ar.d.ts +1113 -370
- package/dist/locales/ar.js +1276 -428
- package/dist/locales/de.d.ts +785 -370
- package/dist/locales/de.js +896 -401
- package/dist/locales/en.d.ts +800 -385
- package/dist/locales/en.js +1261 -419
- package/dist/locales/es.d.ts +867 -370
- package/dist/locales/es.js +976 -398
- package/dist/locales/fr.d.ts +867 -370
- package/dist/locales/fr.js +976 -399
- package/dist/locales/index.d.ts +8682 -3761
- package/dist/locales/index.js +68 -29
- package/dist/locales/ja.d.ts +785 -370
- package/dist/locales/ja.js +891 -395
- package/dist/locales/ko.d.ts +785 -370
- package/dist/locales/ko.js +893 -399
- package/dist/locales/pt.d.ts +867 -370
- package/dist/locales/pt.js +975 -397
- package/dist/locales/registry.d.ts +102 -0
- package/dist/locales/registry.js +220 -0
- package/dist/locales/rtl.d.ts +24 -0
- package/dist/locales/rtl.js +26 -0
- package/dist/locales/ru.d.ts +949 -370
- package/dist/locales/ru.js +1093 -419
- package/dist/locales/zh.d.ts +803 -388
- package/dist/locales/zh.js +899 -388
- package/dist/pickLocalized.d.ts +67 -0
- package/dist/pickLocalized.js +114 -0
- package/dist/provider.d.ts +102 -13
- package/dist/provider.js +335 -50
- package/dist/translateFn.d.ts +29 -0
- package/dist/translateFn.js +8 -0
- package/dist/useDisplayLocale.d.ts +11 -0
- package/dist/useDisplayLocale.js +13 -2
- package/dist/useObjectLabel.d.ts +118 -22
- package/dist/useObjectLabel.js +148 -23
- package/dist/useSafeTranslation.js +41 -43
- package/dist/utils/formatting.d.ts +16 -0
- package/dist/utils/formatting.js +23 -3
- package/dist/utils/index.d.ts +4 -4
- package/dist/utils/index.js +4 -4
- package/dist/utils/spec-formatters.d.ts +13 -23
- package/dist/utils/spec-formatters.js +41 -2
- package/dist/utils/spec-translations.d.ts +16 -3
- package/dist/utils/spec-translations.js +52 -13
- package/package.json +12 -6
package/dist/pickLocalized.d.ts
CHANGED
|
@@ -34,3 +34,70 @@
|
|
|
34
34
|
* `pickLocalized({ en: 'Pricing' }, 'constructor')` is `'Pricing'`, not `''`.
|
|
35
35
|
*/
|
|
36
36
|
export declare function pickLocalized(value: unknown, language: string | undefined | null): string;
|
|
37
|
+
/**
|
|
38
|
+
* Write `next` back into a possibly-localized value as the `language` entry,
|
|
39
|
+
* preserving every other locale — the write-side inverse of
|
|
40
|
+
* {@link pickLocalized}.
|
|
41
|
+
*
|
|
42
|
+
* An authoring surface that shows one locale in one text input has to answer
|
|
43
|
+
* two questions, and they are not the same question: which entry to DISPLAY
|
|
44
|
+
* (`pickLocalized`) and which entry a save REPLACES. Answering the second with
|
|
45
|
+
* "the whole value" is the data-loss shape this function exists to remove —
|
|
46
|
+
* `onChange(e.target.value)` straight back over `{ en, zh-CN }` destroys every
|
|
47
|
+
* locale the author was not looking at, silently, on the first keystroke.
|
|
48
|
+
*
|
|
49
|
+
* - Plain string / `null` / `undefined` / array input: there is no map to
|
|
50
|
+
* preserve, so the result is `next` itself. A string-valued label keeps
|
|
51
|
+
* behaving exactly as it always has.
|
|
52
|
+
* - Inline locale map: the result is the same map with exactly one entry
|
|
53
|
+
* replaced (or added — see {@link localeWriteKey}). Non-string entries and
|
|
54
|
+
* unrelated locales are carried across untouched.
|
|
55
|
+
*
|
|
56
|
+
* The pairing with `pickLocalized` is the invariant that matters and it is
|
|
57
|
+
* pinned in `__tests__/setLocalized.test.ts`: for any map and any language,
|
|
58
|
+
* `pickLocalized(setLocalized(map, lang, s), lang) === s`. If the two functions
|
|
59
|
+
* ever drift apart, an edit lands in an entry the panel does not display and
|
|
60
|
+
* the "saved" string vanishes — which is why they live in one file.
|
|
61
|
+
*
|
|
62
|
+
* ⚠️ This is the minimal non-destructive write for a SINGLE-locale editor. It
|
|
63
|
+
* is not a multi-locale authoring UI and does not pretend to be: an author can
|
|
64
|
+
* only ever reach the entry for the locale they are in.
|
|
65
|
+
*
|
|
66
|
+
* Authoring every locale from one surface remains an OPEN product question, and
|
|
67
|
+
* is deliberately not deferred to a tracker here: the deferral this replaced
|
|
68
|
+
* named objectui#4163, which closed as completed on 2026-08-15 with the question
|
|
69
|
+
* still unanswered. A comment pointing at a closed card reads as though the
|
|
70
|
+
* question were settled somewhere, which is how the previous stale premise in
|
|
71
|
+
* this area survived unread.
|
|
72
|
+
*/
|
|
73
|
+
export declare function setLocalized(value: unknown, language: string | undefined | null, next: string): string | Record<string, unknown>;
|
|
74
|
+
/**
|
|
75
|
+
* Remove the `language` entry from a possibly-localized value — the CLEAR arm
|
|
76
|
+
* of the same editor {@link setLocalized} serves, and the reason it cannot be
|
|
77
|
+
* spelled as `setLocalized(value, language, '')`.
|
|
78
|
+
*
|
|
79
|
+
* A single-line authoring input has three actions, not two: type, retype, and
|
|
80
|
+
* clear. `setLocalized` answers the first two. Answering the third with "write
|
|
81
|
+
* the empty string" stores `{ en: '' }` — an entry that claims "English has a
|
|
82
|
+
* title and it is blank", which then SHADOWS every display fallback: a viewer
|
|
83
|
+
* in `en` sees nothing where the map's other locales would have been offered.
|
|
84
|
+
* Answering it with "drop the whole value" is the objectui#9274 data loss
|
|
85
|
+
* itself, arriving through the clearing door instead of the typing door.
|
|
86
|
+
*
|
|
87
|
+
* So clearing removes exactly one entry — the same entry {@link setLocalized}
|
|
88
|
+
* would have written, chosen by the same {@link localeWriteKey} limbs, which is
|
|
89
|
+
* what keeps the cleared entry the one the author was actually looking at.
|
|
90
|
+
*
|
|
91
|
+
* - Plain string / `null` / `undefined` / array: there is no map, so there is
|
|
92
|
+
* nothing localized left — `undefined`. The caller decides how its own field
|
|
93
|
+
* spells empty (`undefined` for an optional key, `''` for a required one).
|
|
94
|
+
* - Map with the active entry present: that entry is removed and every other
|
|
95
|
+
* locale is carried across untouched. When it was the LAST entry the result
|
|
96
|
+
* is `undefined` rather than `{}`, because an empty map is not a title.
|
|
97
|
+
* - Map WITHOUT an entry for the active locale: returned unchanged. The box was
|
|
98
|
+
* showing a display fallback borrowed from another locale, and clearing a
|
|
99
|
+
* borrowed string must not delete the locale it was borrowed from — the same
|
|
100
|
+
* refusal {@link localeWriteKey} enforces on the write side, which is why
|
|
101
|
+
* both read the same limbs from the same file.
|
|
102
|
+
*/
|
|
103
|
+
export declare function clearLocalized(value: unknown, language: string | undefined | null): Record<string, unknown> | undefined;
|
package/dist/pickLocalized.js
CHANGED
|
@@ -69,3 +69,117 @@ export function pickLocalized(value, language) {
|
|
|
69
69
|
}
|
|
70
70
|
return String(value);
|
|
71
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* The map key an edit made in `language` must be WRITTEN to — the write-side
|
|
74
|
+
* twin of {@link pickLocalized}'s read limbs.
|
|
75
|
+
*
|
|
76
|
+
* It deliberately implements only the first three limbs (exact tag, base
|
|
77
|
+
* language, region-qualified sibling) and then STOPS. `pickLocalized` continues
|
|
78
|
+
* into `default` -> `en` -> first value, and those last three limbs must never
|
|
79
|
+
* be write targets: they are DISPLAY fallbacks that hand back *another*
|
|
80
|
+
* locale's string. Following them would mean an author editing in `fr`, shown
|
|
81
|
+
* the `en` entry because the map has no French, saves and overwrites English.
|
|
82
|
+
* When no entry for the active locale exists the edit ADDS one under the active
|
|
83
|
+
* tag and every stored entry survives untouched.
|
|
84
|
+
*
|
|
85
|
+
* The first three limbs are followed exactly because they identify the entry
|
|
86
|
+
* the author was actually looking at. Writing `zh` when the map stores `zh-CN`
|
|
87
|
+
* would leave the edited-away `zh-CN` string in place — invisible in the panel
|
|
88
|
+
* that just "changed" it, still live for any consumer that asks for `zh-CN`.
|
|
89
|
+
*
|
|
90
|
+
* Own properties only, `string` values only, for the same reason every
|
|
91
|
+
* `pickLocalized` limb narrowed that way in objectui#3907: a locale tag that
|
|
92
|
+
* names an `Object.prototype` member is not an entry, so it cannot be the entry
|
|
93
|
+
* the author edited.
|
|
94
|
+
*/
|
|
95
|
+
function localeWriteKey(o, language) {
|
|
96
|
+
const lang = (language || 'en').trim() || 'en';
|
|
97
|
+
const base = lang.split('-')[0];
|
|
98
|
+
const has = (key) => Object.prototype.hasOwnProperty.call(o, key) && typeof o[key] === 'string';
|
|
99
|
+
if (has(lang))
|
|
100
|
+
return lang;
|
|
101
|
+
if (has(base))
|
|
102
|
+
return base;
|
|
103
|
+
return Object.keys(o).find((k) => k.split('-')[0] === base && has(k)) ?? lang;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Write `next` back into a possibly-localized value as the `language` entry,
|
|
107
|
+
* preserving every other locale — the write-side inverse of
|
|
108
|
+
* {@link pickLocalized}.
|
|
109
|
+
*
|
|
110
|
+
* An authoring surface that shows one locale in one text input has to answer
|
|
111
|
+
* two questions, and they are not the same question: which entry to DISPLAY
|
|
112
|
+
* (`pickLocalized`) and which entry a save REPLACES. Answering the second with
|
|
113
|
+
* "the whole value" is the data-loss shape this function exists to remove —
|
|
114
|
+
* `onChange(e.target.value)` straight back over `{ en, zh-CN }` destroys every
|
|
115
|
+
* locale the author was not looking at, silently, on the first keystroke.
|
|
116
|
+
*
|
|
117
|
+
* - Plain string / `null` / `undefined` / array input: there is no map to
|
|
118
|
+
* preserve, so the result is `next` itself. A string-valued label keeps
|
|
119
|
+
* behaving exactly as it always has.
|
|
120
|
+
* - Inline locale map: the result is the same map with exactly one entry
|
|
121
|
+
* replaced (or added — see {@link localeWriteKey}). Non-string entries and
|
|
122
|
+
* unrelated locales are carried across untouched.
|
|
123
|
+
*
|
|
124
|
+
* The pairing with `pickLocalized` is the invariant that matters and it is
|
|
125
|
+
* pinned in `__tests__/setLocalized.test.ts`: for any map and any language,
|
|
126
|
+
* `pickLocalized(setLocalized(map, lang, s), lang) === s`. If the two functions
|
|
127
|
+
* ever drift apart, an edit lands in an entry the panel does not display and
|
|
128
|
+
* the "saved" string vanishes — which is why they live in one file.
|
|
129
|
+
*
|
|
130
|
+
* ⚠️ This is the minimal non-destructive write for a SINGLE-locale editor. It
|
|
131
|
+
* is not a multi-locale authoring UI and does not pretend to be: an author can
|
|
132
|
+
* only ever reach the entry for the locale they are in.
|
|
133
|
+
*
|
|
134
|
+
* Authoring every locale from one surface remains an OPEN product question, and
|
|
135
|
+
* is deliberately not deferred to a tracker here: the deferral this replaced
|
|
136
|
+
* named objectui#4163, which closed as completed on 2026-08-15 with the question
|
|
137
|
+
* still unanswered. A comment pointing at a closed card reads as though the
|
|
138
|
+
* question were settled somewhere, which is how the previous stale premise in
|
|
139
|
+
* this area survived unread.
|
|
140
|
+
*/
|
|
141
|
+
export function setLocalized(value, language, next) {
|
|
142
|
+
if (value == null || typeof value !== 'object' || Array.isArray(value))
|
|
143
|
+
return next;
|
|
144
|
+
const o = value;
|
|
145
|
+
return { ...o, [localeWriteKey(o, language)]: next };
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Remove the `language` entry from a possibly-localized value — the CLEAR arm
|
|
149
|
+
* of the same editor {@link setLocalized} serves, and the reason it cannot be
|
|
150
|
+
* spelled as `setLocalized(value, language, '')`.
|
|
151
|
+
*
|
|
152
|
+
* A single-line authoring input has three actions, not two: type, retype, and
|
|
153
|
+
* clear. `setLocalized` answers the first two. Answering the third with "write
|
|
154
|
+
* the empty string" stores `{ en: '' }` — an entry that claims "English has a
|
|
155
|
+
* title and it is blank", which then SHADOWS every display fallback: a viewer
|
|
156
|
+
* in `en` sees nothing where the map's other locales would have been offered.
|
|
157
|
+
* Answering it with "drop the whole value" is the objectui#9274 data loss
|
|
158
|
+
* itself, arriving through the clearing door instead of the typing door.
|
|
159
|
+
*
|
|
160
|
+
* So clearing removes exactly one entry — the same entry {@link setLocalized}
|
|
161
|
+
* would have written, chosen by the same {@link localeWriteKey} limbs, which is
|
|
162
|
+
* what keeps the cleared entry the one the author was actually looking at.
|
|
163
|
+
*
|
|
164
|
+
* - Plain string / `null` / `undefined` / array: there is no map, so there is
|
|
165
|
+
* nothing localized left — `undefined`. The caller decides how its own field
|
|
166
|
+
* spells empty (`undefined` for an optional key, `''` for a required one).
|
|
167
|
+
* - Map with the active entry present: that entry is removed and every other
|
|
168
|
+
* locale is carried across untouched. When it was the LAST entry the result
|
|
169
|
+
* is `undefined` rather than `{}`, because an empty map is not a title.
|
|
170
|
+
* - Map WITHOUT an entry for the active locale: returned unchanged. The box was
|
|
171
|
+
* showing a display fallback borrowed from another locale, and clearing a
|
|
172
|
+
* borrowed string must not delete the locale it was borrowed from — the same
|
|
173
|
+
* refusal {@link localeWriteKey} enforces on the write side, which is why
|
|
174
|
+
* both read the same limbs from the same file.
|
|
175
|
+
*/
|
|
176
|
+
export function clearLocalized(value, language) {
|
|
177
|
+
if (value == null || typeof value !== 'object' || Array.isArray(value))
|
|
178
|
+
return undefined;
|
|
179
|
+
const o = value;
|
|
180
|
+
const key = localeWriteKey(o, language);
|
|
181
|
+
if (!Object.prototype.hasOwnProperty.call(o, key))
|
|
182
|
+
return o;
|
|
183
|
+
const rest = Object.fromEntries(Object.entries(o).filter(([k]) => k !== key));
|
|
184
|
+
return Object.keys(rest).length > 0 ? rest : undefined;
|
|
185
|
+
}
|
package/dist/provider.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import React from 'react';
|
|
7
7
|
import type { i18n as I18nInstance } from 'i18next';
|
|
8
|
-
import { type I18nConfig } from './i18n';
|
|
8
|
+
import { type I18nConfig } from './i18n.js';
|
|
9
9
|
/**
|
|
10
10
|
* `localStorage` key holding the user's explicit language choice.
|
|
11
11
|
*
|
|
@@ -17,6 +17,22 @@ import { type I18nConfig } from './i18n';
|
|
|
17
17
|
* Exported so an app that builds its own i18next instance (and therefore owns
|
|
18
18
|
* its bootstrap language — see {@link I18nProviderProps.instance}) can honour
|
|
19
19
|
* the same preference, and so a sign-out flow can clear it.
|
|
20
|
+
*
|
|
21
|
+
* ⚠️ **What this slot means changed for a SIGNED-IN user (objectui#10059).**
|
|
22
|
+
* A signed-in user's language has one source of truth and it is not on the
|
|
23
|
+
* device: it is the server column `sys_user.locale`, read back through
|
|
24
|
+
* `GET /auth/me/localization` and written by both the profile page's language
|
|
25
|
+
* card and the console's globe menu. For that user this slot is a CACHE of the
|
|
26
|
+
* column — it still decides the first paint, because the column cannot be read
|
|
27
|
+
* synchronously, and it is then overwritten by whatever the column says. It
|
|
28
|
+
* decides on its own only BEFORE sign-in, which is the case this provider can
|
|
29
|
+
* see and the only one it adjudicates.
|
|
30
|
+
*
|
|
31
|
+
* This provider deliberately does not implement that rule: reading a `sys_user`
|
|
32
|
+
* row needs an authenticated data adapter, which is a host concern and not a
|
|
33
|
+
* dependency a renderer package takes. The host applies the column through
|
|
34
|
+
* {@link I18nContextValue.changeLanguage} like any other switch — in this
|
|
35
|
+
* repository, `@object-ui/app-shell`'s `useUserLocale`.
|
|
20
36
|
*/
|
|
21
37
|
export declare const LOCALE_STORAGE_KEY = "objectui-locale";
|
|
22
38
|
/**
|
|
@@ -29,28 +45,53 @@ export declare const LOCALE_STORAGE_KEY = "objectui-locale";
|
|
|
29
45
|
*/
|
|
30
46
|
export declare function readStoredLanguage(): string | null;
|
|
31
47
|
/**
|
|
32
|
-
* `localStorage` key caching the
|
|
33
|
-
* choice (objectui#4035).
|
|
48
|
+
* `localStorage` key caching the server's resolved locale for the signed-in
|
|
49
|
+
* caller — a *seed*, not a choice (objectui#4035).
|
|
50
|
+
*
|
|
51
|
+
* ⚠️ **The value is per-USER; the slot is per-DEVICE (objectui#10193).**
|
|
52
|
+
* `GET /auth/me/localization` answers `locale` as the caller's own
|
|
53
|
+
* `sys_user.locale` when set, else the request's `Accept-Language`, else the
|
|
54
|
+
* deployment default — and answers no locale at all before sign-in. It is not
|
|
55
|
+
* a tenant setting, whatever earlier prose here said. The slot is deliberately
|
|
56
|
+
* NOT keyed by user: the boot reads it before anyone is signed in, when no
|
|
57
|
+
* user id exists to key by. What bounds it to one owner is
|
|
58
|
+
* `@object-ui/auth`'s change-of-owner purge (objectui#5664), which deletes it
|
|
59
|
+
* when a different user adopts the browser, and which the host answers by
|
|
60
|
+
* re-resolving the live language (`@object-ui/app-shell`'s
|
|
61
|
+
* `useSignedInUserLocale`).
|
|
62
|
+
*
|
|
63
|
+
* **What a visitor who is not signed in reads**, declared as device behaviour:
|
|
64
|
+
* the language the LAST signed-in owner of this browser was served, until
|
|
65
|
+
* someone else signs in. That is the only server answer this device has ever
|
|
66
|
+
* received — the endpoint gives none before sign-in — and the sign-in page is
|
|
67
|
+
* the one surface it paints.
|
|
34
68
|
*
|
|
35
69
|
* Deliberately a separate slot from {@link LOCALE_STORAGE_KEY}, and that
|
|
36
70
|
* separation is the whole point rather than a tidiness preference. The two
|
|
37
71
|
* values have different provenance and therefore different rights:
|
|
38
72
|
*
|
|
39
|
-
* - {@link LOCALE_STORAGE_KEY} is what the *user* picked. It
|
|
40
|
-
* everything and must survive a
|
|
41
|
-
*
|
|
42
|
-
*
|
|
73
|
+
* - {@link LOCALE_STORAGE_KEY} is what the *user* picked on this device. It
|
|
74
|
+
* outranks everything this provider can see and must survive a change in
|
|
75
|
+
* what the server answers for the seed below. ⚠️ It does NOT outrank the signed-in user's own
|
|
76
|
+
* `sys_user.locale`, which no tier here represents — see that key's own
|
|
77
|
+
* docblock (objectui#10059).
|
|
78
|
+
* - This slot is what the server resolved for the signed-in caller, cached so
|
|
79
|
+
* the next boot can apply it synchronously. It outranks only the environment
|
|
80
|
+
* (browser language).
|
|
43
81
|
*
|
|
44
82
|
* Writing the server seed into the explicit-choice slot would erase that
|
|
45
83
|
* difference permanently: the seed would then be indistinguishable from a
|
|
46
|
-
* deliberate user choice, so it would (a) outrank a later
|
|
47
|
-
* the device to a stale locale forever, and (b) suppress browser
|
|
84
|
+
* deliberate user choice, so it would (a) outrank a later server-side change
|
|
85
|
+
* and pin the device to a stale locale forever, and (b) suppress browser
|
|
86
|
+
* detection for
|
|
48
87
|
* a user who never expressed a preference. Only a real switch promotes a
|
|
49
88
|
* language to the explicit slot — see the `languageChanged` choke point.
|
|
50
89
|
*/
|
|
51
90
|
export declare const LOCALE_SEED_STORAGE_KEY = "objectui-locale-seed";
|
|
52
91
|
/**
|
|
53
|
-
* Read the cached
|
|
92
|
+
* Read the cached locale seed — the server's last resolved locale for this
|
|
93
|
+
* browser's last signed-in caller (see {@link LOCALE_SEED_STORAGE_KEY}) — or
|
|
94
|
+
* `null` when nothing is cached.
|
|
54
95
|
*
|
|
55
96
|
* Same defensive posture as {@link readStoredLanguage}: `localStorage` is
|
|
56
97
|
* absent under SSR and *throws* in Safari private mode / partitioned iframes,
|
|
@@ -58,12 +99,13 @@ export declare const LOCALE_SEED_STORAGE_KEY = "objectui-locale-seed";
|
|
|
58
99
|
*/
|
|
59
100
|
export declare function readCachedLanguageSeed(): string | null;
|
|
60
101
|
/**
|
|
61
|
-
* Cache the
|
|
62
|
-
* of the stale-while-revalidate contract (objectstack#5419,
|
|
102
|
+
* Cache the locale the server just resolved for the signed-in caller — the
|
|
103
|
+
* "revalidate" half of the stale-while-revalidate contract (objectstack#5419,
|
|
104
|
+
* ruling point 2).
|
|
63
105
|
*
|
|
64
106
|
* Call this with whatever `/auth/me/localization` actually returned for an
|
|
65
107
|
* authenticated caller. A `null`/`undefined` locale CLEARS the cache rather
|
|
66
|
-
* than leaving the old value: a
|
|
108
|
+
* than leaving the old value: a server answer that drops the locale must reach
|
|
67
109
|
* choice-less devices on their next boot, and "keep the last good seed forever"
|
|
68
110
|
* is precisely the being-pinned-by-a-stale-seed failure the ruling forbids.
|
|
69
111
|
*
|
|
@@ -72,6 +114,53 @@ export declare function readCachedLanguageSeed(): string | null;
|
|
|
72
114
|
* cannot complete.
|
|
73
115
|
*/
|
|
74
116
|
export declare function cacheLanguageSeed(locale: string | null | undefined): void;
|
|
117
|
+
/**
|
|
118
|
+
* Options shared by {@link resolveBootstrapLanguage} and
|
|
119
|
+
* {@link preloadBootstrapLocale}. Each field mirrors the {@link I18nProvider}
|
|
120
|
+
* prop of the same name, because the two must answer identically — a host that
|
|
121
|
+
* preloads one catalogue while the provider boots into another has bought a
|
|
122
|
+
* flash of `en` instead of avoiding one.
|
|
123
|
+
*/
|
|
124
|
+
export interface BootstrapLocaleOptions {
|
|
125
|
+
/** The `config` you will pass to {@link I18nProvider}. */
|
|
126
|
+
config?: I18nConfig;
|
|
127
|
+
/** The `persistLanguage` you will pass to {@link I18nProvider}. Default `true`. */
|
|
128
|
+
persistLanguage?: boolean;
|
|
129
|
+
/** Whether you will pass a `loadLanguage` loader. Default `false`. */
|
|
130
|
+
hasLoader?: boolean;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* The language {@link I18nProvider} will boot in, computed WITHOUT creating an
|
|
134
|
+
* i18next instance (objectui#7479).
|
|
135
|
+
*
|
|
136
|
+
* The full precedence chain, unchanged: explicit choice → seed →
|
|
137
|
+
* browser language → `defaultLanguage` → `en`.
|
|
138
|
+
*/
|
|
139
|
+
export declare function resolveBootstrapLanguage(options?: BootstrapLocaleOptions): string;
|
|
140
|
+
/**
|
|
141
|
+
* Fetch the catalogue {@link I18nProvider} will boot in, BEFORE you render it.
|
|
142
|
+
*
|
|
143
|
+
* ## Why a host would await this
|
|
144
|
+
*
|
|
145
|
+
* Built-in catalogues are lazy since objectui#7479, so the provider can be in
|
|
146
|
+
* one of two states on its first render, and the difference is visible:
|
|
147
|
+
*
|
|
148
|
+
* - **catalogue already resident** — the first paint is in the user's
|
|
149
|
+
* language, exactly as it was when all ten packs shipped eagerly;
|
|
150
|
+
* - **catalogue still in flight** — the first paint renders through
|
|
151
|
+
* `fallbackLng: 'en'` and re-renders in the user's language when the fetch
|
|
152
|
+
* lands. Correct, never blank, and a flash of English for a `zh-CN` viewer.
|
|
153
|
+
*
|
|
154
|
+
* ⇒ any host that owns an await before `createRoot().render()` should spend it
|
|
155
|
+
* here; `apps/console/src/main.tsx` does, alongside the runtime-config and auth
|
|
156
|
+
* preflight round-trips it already waits on. A host that has no such seam gets
|
|
157
|
+
* the documented `en`-while-loading behaviour instead, which is why this is a
|
|
158
|
+
* function a host CALLS rather than a requirement the provider imposes.
|
|
159
|
+
*
|
|
160
|
+
* Never rejects: a catalogue that will not download must not take the boot
|
|
161
|
+
* down, and the provider retries on mount.
|
|
162
|
+
*/
|
|
163
|
+
export declare function preloadBootstrapLocale(options?: BootstrapLocaleOptions): Promise<void>;
|
|
75
164
|
interface I18nContextValue {
|
|
76
165
|
/** Current language code */
|
|
77
166
|
language: string;
|