@adminiumjs/i18n 0.1.2 → 0.2.1
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/a11y-keys.d.ts +17 -0
- package/dist/a11y-keys.d.ts.map +1 -0
- package/dist/a11y-keys.js +478 -0
- package/dist/a11y-keys.js.map +1 -0
- package/dist/create-i18n.d.ts.map +1 -1
- package/dist/create-i18n.js +37 -4
- package/dist/create-i18n.js.map +1 -1
- package/dist/editing.d.ts +17 -0
- package/dist/editing.d.ts.map +1 -0
- package/dist/editing.js +16 -0
- package/dist/editing.js.map +1 -0
- package/dist/fallback.d.ts +24 -0
- package/dist/fallback.d.ts.map +1 -0
- package/dist/fallback.js +40 -0
- package/dist/fallback.js.map +1 -0
- package/dist/format-errors.d.ts +41 -0
- package/dist/format-errors.d.ts.map +1 -0
- package/dist/format-errors.js +63 -0
- package/dist/format-errors.js.map +1 -0
- package/dist/icu-format.d.ts +4 -0
- package/dist/icu-format.d.ts.map +1 -1
- package/dist/icu-format.js +43 -3
- package/dist/icu-format.js.map +1 -1
- package/dist/index.d.ts +10 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -1
- package/dist/index.js.map +1 -1
- package/dist/keys.d.ts +33 -0
- package/dist/keys.d.ts.map +1 -0
- package/dist/keys.js +77 -0
- package/dist/keys.js.map +1 -0
- package/dist/locales.d.ts +102 -13
- package/dist/locales.d.ts.map +1 -1
- package/dist/locales.js +142 -17
- package/dist/locales.js.map +1 -1
- package/dist/overrides.d.ts +62 -0
- package/dist/overrides.d.ts.map +1 -0
- package/dist/overrides.js +112 -0
- package/dist/overrides.js.map +1 -0
- package/dist/react.d.ts +6 -0
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +17 -26
- package/dist/react.js.map +1 -1
- package/dist/resources/ar-eg/common.d.ts +96 -0
- package/dist/resources/ar-eg/common.d.ts.map +1 -1
- package/dist/resources/ar-eg/common.js +103 -7
- package/dist/resources/ar-eg/common.js.map +1 -1
- package/dist/resources/ar-eg/ui.d.ts +586 -586
- package/dist/resources/ar-eg/ui.js +586 -586
- package/dist/resources/ar-eg/ui.js.map +1 -1
- package/dist/resources/cs-cz/common.d.ts +96 -0
- package/dist/resources/cs-cz/common.d.ts.map +1 -1
- package/dist/resources/cs-cz/common.js +101 -5
- package/dist/resources/cs-cz/common.js.map +1 -1
- package/dist/resources/cs-cz/ui.d.ts +582 -582
- package/dist/resources/cs-cz/ui.js +582 -582
- package/dist/resources/cs-cz/ui.js.map +1 -1
- package/dist/resources/da-dk/common.d.ts +97 -1
- package/dist/resources/da-dk/common.d.ts.map +1 -1
- package/dist/resources/da-dk/common.js +104 -8
- package/dist/resources/da-dk/common.js.map +1 -1
- package/dist/resources/da-dk/ui.d.ts +568 -568
- package/dist/resources/da-dk/ui.js +568 -568
- package/dist/resources/da-dk/ui.js.map +1 -1
- package/dist/resources/de-de/common.d.ts +100 -4
- package/dist/resources/de-de/common.d.ts.map +1 -1
- package/dist/resources/de-de/common.js +107 -11
- package/dist/resources/de-de/common.js.map +1 -1
- package/dist/resources/de-de/ui.d.ts +569 -569
- package/dist/resources/de-de/ui.js +569 -569
- package/dist/resources/de-de/ui.js.map +1 -1
- package/dist/resources/en-us/common.d.ts +96 -0
- package/dist/resources/en-us/common.d.ts.map +1 -1
- package/dist/resources/en-us/common.js +103 -7
- package/dist/resources/en-us/common.js.map +1 -1
- package/dist/resources/fr-fr/common.d.ts +98 -2
- package/dist/resources/fr-fr/common.d.ts.map +1 -1
- package/dist/resources/fr-fr/common.js +105 -9
- package/dist/resources/fr-fr/common.js.map +1 -1
- package/dist/resources/fr-fr/ui.d.ts +559 -559
- package/dist/resources/fr-fr/ui.js +559 -559
- package/dist/resources/fr-fr/ui.js.map +1 -1
- package/dist/resources/zh-cn/common.d.ts +97 -1
- package/dist/resources/zh-cn/common.d.ts.map +1 -1
- package/dist/resources/zh-cn/common.js +104 -8
- package/dist/resources/zh-cn/common.js.map +1 -1
- package/dist/resources/zh-cn/ui.d.ts +575 -575
- package/dist/resources/zh-cn/ui.js +575 -575
- package/dist/resources/zh-cn/ui.js.map +1 -1
- package/dist/resources/zh-tw/common.d.ts +96 -0
- package/dist/resources/zh-tw/common.d.ts.map +1 -1
- package/dist/resources/zh-tw/common.js +103 -7
- package/dist/resources/zh-tw/common.js.map +1 -1
- package/dist/resources/zh-tw/ui.d.ts +575 -575
- package/dist/resources/zh-tw/ui.js +575 -575
- package/dist/resources/zh-tw/ui.js.map +1 -1
- package/dist/review-status.d.ts +55 -0
- package/dist/review-status.d.ts.map +1 -0
- package/dist/review-status.js +59 -0
- package/dist/review-status.js.map +1 -0
- package/dist/revision.d.ts +35 -0
- package/dist/revision.d.ts.map +1 -0
- package/dist/revision.js +55 -0
- package/dist/revision.js.map +1 -0
- package/dist/server.d.ts +36 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +35 -0
- package/dist/server.js.map +1 -0
- package/dist/validate-message.d.ts +57 -0
- package/dist/validate-message.d.ts.map +1 -0
- package/dist/validate-message.js +178 -0
- package/dist/validate-message.js.map +1 -0
- package/locales/ar-EG/.meta.json +11134 -0
- package/locales/ar-EG/common.json +103 -7
- package/locales/ar-EG/ui.json +586 -586
- package/locales/cs-CZ/.meta.json +11134 -0
- package/locales/cs-CZ/common.json +101 -5
- package/locales/cs-CZ/ui.json +582 -582
- package/locales/da-DK/.meta.json +11134 -0
- package/locales/da-DK/common.json +104 -8
- package/locales/da-DK/ui.json +568 -568
- package/locales/de-DE/.meta.json +11134 -0
- package/locales/de-DE/common.json +107 -11
- package/locales/de-DE/ui.json +569 -569
- package/locales/en-US/common.json +103 -7
- package/locales/fr-FR/.meta.json +11134 -0
- package/locales/fr-FR/common.json +105 -9
- package/locales/fr-FR/ui.json +559 -559
- package/locales/zh-CN/.meta.json +11134 -0
- package/locales/zh-CN/common.json +104 -8
- package/locales/zh-CN/ui.json +575 -575
- package/locales/zh-TW/.meta.json +11134 -0
- package/locales/zh-TW/common.json +103 -7
- package/locales/zh-TW/ui.json +575 -575
- package/package.json +10 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editing.js","sourceRoot":"","sources":["../src/editing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,aAAa,EACb,QAAQ,EACR,UAAU,EACV,WAAW,EACX,cAAc,EACd,aAAa,GACd,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEvE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ICU formatting for the NO-INSTANCE path.
|
|
3
|
+
*
|
|
4
|
+
* Every `t(key, fallback, args)` in this repo has to work before
|
|
5
|
+
* `initDashboardI18n()` has run and inside unit tests that never boot i18next
|
|
6
|
+
* — components render, and the English fallback is what they show. Returning
|
|
7
|
+
* the fallback *raw* in that state is wrong the moment the fallback has
|
|
8
|
+
* placeholders: the user (or the test) sees the literal `{count} changes`.
|
|
9
|
+
*
|
|
10
|
+
* That defect used to be invisible because 48 call sites hand-substituted
|
|
11
|
+
* their tokens with `.replace('{count}', …)` AFTER `t()` returned, which
|
|
12
|
+
* silently papered over it. Once those became real ICU arguments (23-T06)
|
|
13
|
+
* the gap showed up, so both fallback paths — `useMaybeT` in the React
|
|
14
|
+
* bindings and the dashboard's module-level `t()` — now share this one
|
|
15
|
+
* implementation.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Format `fallback` (always en-US source text) with `args`. Returns the
|
|
19
|
+
* fallback unchanged when there is nothing to interpolate or when the message
|
|
20
|
+
* does not parse — this path must never throw, since it is what renders when
|
|
21
|
+
* i18n is not up.
|
|
22
|
+
*/
|
|
23
|
+
export declare function formatFallback(fallback: string, args?: Record<string, unknown>): string;
|
|
24
|
+
//# sourceMappingURL=fallback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fallback.d.ts","sourceRoot":"","sources":["../src/fallback.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAYvF"}
|
package/dist/fallback.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ICU formatting for the NO-INSTANCE path.
|
|
3
|
+
*
|
|
4
|
+
* Every `t(key, fallback, args)` in this repo has to work before
|
|
5
|
+
* `initDashboardI18n()` has run and inside unit tests that never boot i18next
|
|
6
|
+
* — components render, and the English fallback is what they show. Returning
|
|
7
|
+
* the fallback *raw* in that state is wrong the moment the fallback has
|
|
8
|
+
* placeholders: the user (or the test) sees the literal `{count} changes`.
|
|
9
|
+
*
|
|
10
|
+
* That defect used to be invisible because 48 call sites hand-substituted
|
|
11
|
+
* their tokens with `.replace('{count}', …)` AFTER `t()` returned, which
|
|
12
|
+
* silently papered over it. Once those became real ICU arguments (23-T06)
|
|
13
|
+
* the gap showed up, so both fallback paths — `useMaybeT` in the React
|
|
14
|
+
* bindings and the dashboard's module-level `t()` — now share this one
|
|
15
|
+
* implementation.
|
|
16
|
+
*/
|
|
17
|
+
import { IntlMessageFormat } from 'intl-messageformat';
|
|
18
|
+
const cache = new Map();
|
|
19
|
+
/**
|
|
20
|
+
* Format `fallback` (always en-US source text) with `args`. Returns the
|
|
21
|
+
* fallback unchanged when there is nothing to interpolate or when the message
|
|
22
|
+
* does not parse — this path must never throw, since it is what renders when
|
|
23
|
+
* i18n is not up.
|
|
24
|
+
*/
|
|
25
|
+
export function formatFallback(fallback, args) {
|
|
26
|
+
if (args === undefined || !fallback.includes('{'))
|
|
27
|
+
return fallback;
|
|
28
|
+
try {
|
|
29
|
+
let message = cache.get(fallback);
|
|
30
|
+
if (message === undefined) {
|
|
31
|
+
message = new IntlMessageFormat(fallback, 'en-US', undefined, { ignoreTag: true });
|
|
32
|
+
cache.set(fallback, message);
|
|
33
|
+
}
|
|
34
|
+
return String(message.format(args));
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return fallback;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=fallback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fallback.js","sourceRoot":"","sources":["../src/fallback.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,KAAK,GAAG,IAAI,GAAG,EAA6B,CAAC;AAEnD;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,IAA8B;IAC7E,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,QAAQ,CAAC;IACnE,IAAI,CAAC;QACH,IAAI,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAClC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,OAAO,GAAG,IAAI,iBAAiB,CAAC,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACnF,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC/B,CAAC;QACD,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,IAAuC,CAAC,CAAC,CAAC;IACzE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAC;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded ring of ICU format failures (23-runtime-translations.md §4.5, T12).
|
|
3
|
+
*
|
|
4
|
+
* When a message throws at format time, `IcuFormat` returns the RAW string —
|
|
5
|
+
* so the user sees `{count, plural, one {…}}` sitting in the UI — and logs one
|
|
6
|
+
* `console.warn`. For compiled bundles that is acceptable: the parity gate
|
|
7
|
+
* makes it nearly impossible, and a developer sees the console.
|
|
8
|
+
*
|
|
9
|
+
* For admin-authored overrides it is not. The person who caused the failure is
|
|
10
|
+
* an admin in the Translations editor, not a developer with devtools open, and
|
|
11
|
+
* the write validator cannot catch everything (it checks the message against
|
|
12
|
+
* its source, but the ARGUMENTS a call site actually passes are not knowable
|
|
13
|
+
* statically). So failures land here, and the editor can show them.
|
|
14
|
+
*
|
|
15
|
+
* Deliberately bounded and in-memory: this is a diagnostic aid, not an audit
|
|
16
|
+
* trail. A runaway render loop over one bad message must not grow without
|
|
17
|
+
* limit.
|
|
18
|
+
*/
|
|
19
|
+
export interface FormatFailure {
|
|
20
|
+
/** `namespace:key` where resolvable, else the bare key i18next gave us. */
|
|
21
|
+
key: string;
|
|
22
|
+
/** Language the failure happened under. */
|
|
23
|
+
lng: string;
|
|
24
|
+
message: string;
|
|
25
|
+
/** Epoch ms; the caller supplies it so this module stays clock-free. */
|
|
26
|
+
at: number;
|
|
27
|
+
/** How many times this exact (key, lng, message) has failed. */
|
|
28
|
+
count: number;
|
|
29
|
+
}
|
|
30
|
+
export declare function recordFormatFailure(input: Omit<FormatFailure, 'count'>): void;
|
|
31
|
+
/**
|
|
32
|
+
* Most recent first.
|
|
33
|
+
*
|
|
34
|
+
* Entries are COPIED: the records are mutated in place on every repeat, so
|
|
35
|
+
* handing out live references would let a caller's snapshot change under it
|
|
36
|
+
* (and let a caller write into the ring). `Readonly` states that guarantee;
|
|
37
|
+
* the copy is what actually provides it.
|
|
38
|
+
*/
|
|
39
|
+
export declare function formatFailures(): readonly Readonly<FormatFailure>[];
|
|
40
|
+
export declare function clearFormatFailures(): void;
|
|
41
|
+
//# sourceMappingURL=format-errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-errors.d.ts","sourceRoot":"","sources":["../src/format-errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,WAAW,aAAa;IAC5B,2EAA2E;IAC3E,GAAG,EAAE,MAAM,CAAC;IACZ,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,EAAE,EAAE,MAAM,CAAC;IACX,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC;CACf;AAaD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,GAAG,IAAI,CAmB7E;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,IAAI,SAAS,QAAQ,CAAC,aAAa,CAAC,EAAE,CAEnE;AAED,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded ring of ICU format failures (23-runtime-translations.md §4.5, T12).
|
|
3
|
+
*
|
|
4
|
+
* When a message throws at format time, `IcuFormat` returns the RAW string —
|
|
5
|
+
* so the user sees `{count, plural, one {…}}` sitting in the UI — and logs one
|
|
6
|
+
* `console.warn`. For compiled bundles that is acceptable: the parity gate
|
|
7
|
+
* makes it nearly impossible, and a developer sees the console.
|
|
8
|
+
*
|
|
9
|
+
* For admin-authored overrides it is not. The person who caused the failure is
|
|
10
|
+
* an admin in the Translations editor, not a developer with devtools open, and
|
|
11
|
+
* the write validator cannot catch everything (it checks the message against
|
|
12
|
+
* its source, but the ARGUMENTS a call site actually passes are not knowable
|
|
13
|
+
* statically). So failures land here, and the editor can show them.
|
|
14
|
+
*
|
|
15
|
+
* Deliberately bounded and in-memory: this is a diagnostic aid, not an audit
|
|
16
|
+
* trail. A runaway render loop over one bad message must not grow without
|
|
17
|
+
* limit.
|
|
18
|
+
*/
|
|
19
|
+
const MAX_ENTRIES = 50;
|
|
20
|
+
/**
|
|
21
|
+
* Keyed by `key\0lng\0message` so a repeat increments rather than evicts.
|
|
22
|
+
*
|
|
23
|
+
* Insertion order is maintained as RECENCY order (see the re-insert below), so
|
|
24
|
+
* the first key is always the least recently seen — which is exactly what
|
|
25
|
+
* eviction takes.
|
|
26
|
+
*/
|
|
27
|
+
const failures = new Map();
|
|
28
|
+
export function recordFormatFailure(input) {
|
|
29
|
+
const id = `${input.key}\x00${input.lng}\x00${input.message}`;
|
|
30
|
+
const existing = failures.get(id);
|
|
31
|
+
if (existing !== undefined) {
|
|
32
|
+
existing.count += 1;
|
|
33
|
+
existing.at = input.at;
|
|
34
|
+
// Re-insert to move this key to the end. Updating in place would leave it
|
|
35
|
+
// wherever it first landed, and eviction below takes the FIRST key — so a
|
|
36
|
+
// message that is still failing would be evicted by unrelated one-offs.
|
|
37
|
+
// That runaway loop is the case this ring exists for; it must survive.
|
|
38
|
+
failures.delete(id);
|
|
39
|
+
failures.set(id, existing);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (failures.size >= MAX_ENTRIES) {
|
|
43
|
+
const oldest = failures.keys().next().value;
|
|
44
|
+
if (oldest !== undefined)
|
|
45
|
+
failures.delete(oldest);
|
|
46
|
+
}
|
|
47
|
+
failures.set(id, { ...input, count: 1 });
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Most recent first.
|
|
51
|
+
*
|
|
52
|
+
* Entries are COPIED: the records are mutated in place on every repeat, so
|
|
53
|
+
* handing out live references would let a caller's snapshot change under it
|
|
54
|
+
* (and let a caller write into the ring). `Readonly` states that guarantee;
|
|
55
|
+
* the copy is what actually provides it.
|
|
56
|
+
*/
|
|
57
|
+
export function formatFailures() {
|
|
58
|
+
return [...failures.values()].map((f) => ({ ...f })).sort((a, b) => b.at - a.at);
|
|
59
|
+
}
|
|
60
|
+
export function clearFormatFailures() {
|
|
61
|
+
failures.clear();
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=format-errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-errors.js","sourceRoot":"","sources":["../src/format-errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAcH,MAAM,WAAW,GAAG,EAAE,CAAC;AAEvB;;;;;;GAMG;AACH,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAyB,CAAC;AAElD,MAAM,UAAU,mBAAmB,CAAC,KAAmC;IACrE,MAAM,EAAE,GAAG,GAAG,KAAK,CAAC,GAAG,OAAO,KAAK,CAAC,GAAG,OAAO,KAAK,CAAC,OAAO,EAAE,CAAC;IAC9D,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,QAAQ,CAAC,KAAK,IAAI,CAAC,CAAC;QACpB,QAAQ,CAAC,EAAE,GAAG,KAAK,CAAC,EAAE,CAAC;QACvB,0EAA0E;QAC1E,0EAA0E;QAC1E,wEAAwE;QACxE,uEAAuE;QACvE,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACpB,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;QAC3B,OAAO;IACT,CAAC;IACD,IAAI,QAAQ,CAAC,IAAI,IAAI,WAAW,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;QAC5C,IAAI,MAAM,KAAK,SAAS;YAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACpD,CAAC;IACD,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;AACnF,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,QAAQ,CAAC,KAAK,EAAE,CAAC;AACnB,CAAC"}
|
package/dist/icu-format.d.ts
CHANGED
|
@@ -5,6 +5,8 @@ export declare class IcuFormat {
|
|
|
5
5
|
readonly type: "i18nFormat";
|
|
6
6
|
constructor(opts?: {
|
|
7
7
|
onError?: (key: string, error: unknown) => void;
|
|
8
|
+
/** Override the i18next tag → Intl tag mapping (tests, embedding). */
|
|
9
|
+
resolveIntlTag?: (lng: string) => string;
|
|
8
10
|
});
|
|
9
11
|
/** i18next module hook (called by i18next during init; extra args ignored). */
|
|
10
12
|
init(): void;
|
|
@@ -12,6 +14,8 @@ export declare class IcuFormat {
|
|
|
12
14
|
parse(res: string, options: FormatValues, lng: string, _ns: string, key: string): string;
|
|
13
15
|
/** i18next asks the format plugin whether to add ordinal/plural key suffixes — ICU handles plurals itself. */
|
|
14
16
|
getSuffixes(): string[];
|
|
17
|
+
/** Drop compiled messages — call after a bundle swap so edits take effect. */
|
|
18
|
+
clearCache(): void;
|
|
15
19
|
}
|
|
16
20
|
export {};
|
|
17
21
|
//# sourceMappingURL=icu-format.d.ts.map
|
package/dist/icu-format.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icu-format.d.ts","sourceRoot":"","sources":["../src/icu-format.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"icu-format.d.ts","sourceRoot":"","sources":["../src/icu-format.ts"],"names":[],"mappings":"AAeA,KAAK,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;AAExD,qBAAa,SAAS;;IACpB,MAAM,CAAC,QAAQ,CAAC,IAAI,gBAAgB;IACpC,QAAQ,CAAC,IAAI,EAAG,YAAY,CAAU;gBASpC,IAAI,GAAE;QACJ,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;QAChD,sEAAsE;QACtE,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;KACrC;IAoBR,+EAA+E;IAC/E,IAAI,IAAI,IAAI;IAIZ,qGAAqG;IACrG,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM;IAyBxF,8GAA8G;IAC9G,WAAW,IAAI,MAAM,EAAE;IAIvB,8EAA8E;IAC9E,UAAU,IAAI,IAAI;CAGnB"}
|
package/dist/icu-format.js
CHANGED
|
@@ -9,18 +9,33 @@
|
|
|
9
9
|
* removes the interop landmine and gives us explicit error surfacing.
|
|
10
10
|
*/
|
|
11
11
|
import { IntlMessageFormat } from 'intl-messageformat';
|
|
12
|
+
import { recordFormatFailure } from './format-errors.js';
|
|
13
|
+
import { intlTagForLocale, localeFromTag } from './locales.js';
|
|
12
14
|
export class IcuFormat {
|
|
13
15
|
static type = 'i18nFormat';
|
|
14
16
|
type = 'i18nFormat';
|
|
15
17
|
#cache = new Map();
|
|
16
18
|
#onError;
|
|
19
|
+
#resolveIntlTag;
|
|
20
|
+
/** Language of the most recent parse — the error hook has no other source. */
|
|
21
|
+
#lastLng = 'en-US';
|
|
17
22
|
constructor(opts = {}) {
|
|
18
23
|
this.#onError =
|
|
19
24
|
opts.onError ??
|
|
20
25
|
((key, error) => {
|
|
21
|
-
//
|
|
26
|
+
// Never throw at render time. The console warning is for developers;
|
|
27
|
+
// the ring is what the Translations editor reads, because the person
|
|
28
|
+
// who broke an admin-authored message is not looking at devtools
|
|
29
|
+
// (23 §4.5).
|
|
22
30
|
console.warn(`[adminium/i18n] ICU parse failed for "${key}":`, error);
|
|
31
|
+
recordFormatFailure({
|
|
32
|
+
key,
|
|
33
|
+
lng: this.#lastLng,
|
|
34
|
+
message: error instanceof Error ? error.message : String(error),
|
|
35
|
+
at: Date.now(),
|
|
36
|
+
});
|
|
23
37
|
});
|
|
38
|
+
this.#resolveIntlTag = opts.resolveIntlTag ?? defaultIntlTag;
|
|
24
39
|
}
|
|
25
40
|
/** i18next module hook (called by i18next during init; extra args ignored). */
|
|
26
41
|
init() {
|
|
@@ -31,10 +46,19 @@ export class IcuFormat {
|
|
|
31
46
|
if (typeof res !== 'string' || !res.includes('{'))
|
|
32
47
|
return res;
|
|
33
48
|
try {
|
|
34
|
-
|
|
49
|
+
// The tag handed to ICU is the locale's INTL tag, not i18next's active
|
|
50
|
+
// language (23 §4.5). For the compiled eight they are the same string;
|
|
51
|
+
// for an admin-created locale they are not, and using `lng` there means
|
|
52
|
+
// ICU has no plural data for the tag and silently resolves every
|
|
53
|
+
// message to `other` — with nothing thrown and nothing logged. The
|
|
54
|
+
// borrow tag is also part of the cache key, so re-pointing a locale's
|
|
55
|
+
// `intlTag` invalidates its compiled messages.
|
|
56
|
+
this.#lastLng = lng;
|
|
57
|
+
const intlTag = this.#resolveIntlTag(lng);
|
|
58
|
+
const cacheKey = `${intlTag}\x00${key}\x00${res}`;
|
|
35
59
|
let message = this.#cache.get(cacheKey);
|
|
36
60
|
if (message === undefined) {
|
|
37
|
-
message = new IntlMessageFormat(res,
|
|
61
|
+
message = new IntlMessageFormat(res, intlTag, undefined, { ignoreTag: true });
|
|
38
62
|
this.#cache.set(cacheKey, message);
|
|
39
63
|
}
|
|
40
64
|
return String(message.format(options));
|
|
@@ -48,5 +72,21 @@ export class IcuFormat {
|
|
|
48
72
|
getSuffixes() {
|
|
49
73
|
return [];
|
|
50
74
|
}
|
|
75
|
+
/** Drop compiled messages — call after a bundle swap so edits take effect. */
|
|
76
|
+
clearCache() {
|
|
77
|
+
this.#cache.clear();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* i18next language tag → the tag ICU should format under. Runs through the
|
|
82
|
+
* locale registry so a custom locale gets its admin-chosen borrow tag; falls
|
|
83
|
+
* back to the tag itself for anything the registry does not know.
|
|
84
|
+
*/
|
|
85
|
+
function defaultIntlTag(lng) {
|
|
86
|
+
const id = localeFromTag(lng);
|
|
87
|
+
const intlTag = intlTagForLocale(id);
|
|
88
|
+
// `localeFromTag` coalesces unknown tags to en_US; don't let that silently
|
|
89
|
+
// re-map a tag ICU would have handled perfectly well on its own.
|
|
90
|
+
return id === 'en_US' && lng !== 'en-US' ? lng : intlTag;
|
|
51
91
|
}
|
|
52
92
|
//# sourceMappingURL=icu-format.js.map
|
package/dist/icu-format.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icu-format.js","sourceRoot":"","sources":["../src/icu-format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"icu-format.js","sourceRoot":"","sources":["../src/icu-format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAI/D,MAAM,OAAO,SAAS;IACpB,MAAM,CAAU,IAAI,GAAG,YAAY,CAAC;IAC3B,IAAI,GAAG,YAAqB,CAAC;IAEtC,MAAM,GAAG,IAAI,GAAG,EAA6B,CAAC;IAC9C,QAAQ,CAAwC;IAChD,eAAe,CAA0B;IACzC,8EAA8E;IAC9E,QAAQ,GAAG,OAAO,CAAC;IAEnB,YACE,OAII,EAAE;QAEN,IAAI,CAAC,QAAQ;YACX,IAAI,CAAC,OAAO;gBACZ,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;oBACd,qEAAqE;oBACrE,qEAAqE;oBACrE,iEAAiE;oBACjE,aAAa;oBACb,OAAO,CAAC,IAAI,CAAC,yCAAyC,GAAG,IAAI,EAAE,KAAK,CAAC,CAAC;oBACtE,mBAAmB,CAAC;wBAClB,GAAG;wBACH,GAAG,EAAE,IAAI,CAAC,QAAQ;wBAClB,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;wBAC/D,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;qBACf,CAAC,CAAC;gBACL,CAAC,CAAC,CAAC;QACL,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,cAAc,IAAI,cAAc,CAAC;IAC/D,CAAC;IAED,+EAA+E;IAC/E,IAAI;QACF,8BAA8B;IAChC,CAAC;IAED,qGAAqG;IACrG,KAAK,CAAC,GAAW,EAAE,OAAqB,EAAE,GAAW,EAAE,GAAW,EAAE,GAAW;QAC7E,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,OAAO,GAAG,CAAC;QAC9D,IAAI,CAAC;YACH,uEAAuE;YACvE,uEAAuE;YACvE,wEAAwE;YACxE,iEAAiE;YACjE,mEAAmE;YACnE,sEAAsE;YACtE,+CAA+C;YAC/C,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC;YACpB,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;YAC1C,MAAM,QAAQ,GAAG,GAAG,OAAO,OAAO,GAAG,OAAO,GAAG,EAAE,CAAC;YAClD,IAAI,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACxC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC1B,OAAO,GAAG,IAAI,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC9E,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACrC,CAAC;YACD,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAsD,CAAC,CAAC,CAAC;QACxF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YAC1B,OAAO,GAAG,CAAC;QACb,CAAC;IACH,CAAC;IAED,8GAA8G;IAC9G,WAAW;QACT,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,8EAA8E;IAC9E,UAAU;QACR,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;;AAGH;;;;GAIG;AACH,SAAS,cAAc,CAAC,GAAW;IACjC,MAAM,EAAE,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IAC9B,MAAM,OAAO,GAAG,gBAAgB,CAAC,EAAE,CAAC,CAAC;IACrC,2EAA2E;IAC3E,iEAAiE;IACjE,OAAO,EAAE,KAAK,OAAO,IAAI,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC;AAC3D,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,13 +4,21 @@
|
|
|
4
4
|
* React bindings live in the `@adminium/i18n/react` entry.
|
|
5
5
|
*/
|
|
6
6
|
export declare const PACKAGE_NAME = "@adminium/i18n";
|
|
7
|
-
export { LOCALES, LOCALE_IDS, dirForLocale, isLocaleId, isRtlLocale, localeEntry, localeFromTag, tagForLocale, } from './locales.js';
|
|
8
|
-
export type { LocaleEntry, LocaleId } from './locales.js';
|
|
7
|
+
export { BUILTIN_LOCALE_IDS, LOCALES, LOCALE_ID_RE, LOCALE_IDS, allLocales, availableLocales, dirForLocale, intlTagForLocale, isBuiltinLocaleId, isLocaleId, isRtlLocale, localeEntry, localeFromTag, pluralCategoriesForLocale, resetRuntimeLocales, setRuntimeLocales, tagForLocale, tagFromLocaleId, } from './locales.js';
|
|
8
|
+
export type { BuiltinLocaleId, LocaleEntry, LocaleId, RuntimeLocaleEntry } from './locales.js';
|
|
9
9
|
export { createI18n, switchLocale } from './create-i18n.js';
|
|
10
|
+
export { createI18nWithOverrides, mergeOverrides, overrideTag, rebuildWithOverrides, } from './overrides.js';
|
|
11
|
+
export type { CreateI18nWithOverridesOptions, OverrideMap } from './overrides.js';
|
|
12
|
+
export { clearFormatFailures, formatFailures, recordFormatFailure, } from './format-errors.js';
|
|
13
|
+
export type { FormatFailure } from './format-errors.js';
|
|
10
14
|
export type { BundleLoader, CreateI18nOptions, I18nInstance } from './create-i18n.js';
|
|
11
15
|
export { EN_US_RESOURCES, NAMESPACES } from './resources/index.js';
|
|
12
16
|
export type { Namespace, ResourceBundle } from './resources/index.js';
|
|
13
17
|
export { loadLocaleBundle } from './resources/lazy.js';
|
|
18
|
+
export { formatFallback } from './fallback.js';
|
|
19
|
+
export { bumpI18nRevision, getI18nRevision, resetI18nRevision, subscribeI18nRevision, } from './revision.js';
|
|
20
|
+
export { REVIEW_STATUS, isReviewed, reviewedFraction } from './review-status.js';
|
|
21
|
+
export type { LocaleReview, ReviewCoverage } from './review-status.js';
|
|
14
22
|
export { getFormatters, latnDataTag, weekInfo } from './format/index.js';
|
|
15
23
|
export type { FmtContext, Formatters, WeekInfo } from './format/index.js';
|
|
16
24
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,YAAY,mBAAmB,CAAC;AAE7C,OAAO,EACL,OAAO,EACP,UAAU,EACV,YAAY,EACZ,UAAU,EACV,WAAW,EACX,WAAW,EACX,aAAa,EACb,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,YAAY,mBAAmB,CAAC;AAE7C,OAAO,EACL,kBAAkB,EAClB,OAAO,EACP,YAAY,EACZ,UAAU,EACV,UAAU,EACV,gBAAgB,EAChB,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,UAAU,EACV,WAAW,EACX,WAAW,EACX,aAAa,EACb,yBAAyB,EACzB,mBAAmB,EACnB,iBAAiB,EACjB,YAAY,EACZ,eAAe,GAChB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAE/F,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EACL,uBAAuB,EACvB,cAAc,EACd,WAAW,EACX,oBAAoB,GACrB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,8BAA8B,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClF,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,mBAAmB,GACpB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEtF,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACnE,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAWvD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACjF,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEvE,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACzE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -4,9 +4,22 @@
|
|
|
4
4
|
* React bindings live in the `@adminium/i18n/react` entry.
|
|
5
5
|
*/
|
|
6
6
|
export const PACKAGE_NAME = '@adminium/i18n';
|
|
7
|
-
export { LOCALES, LOCALE_IDS, dirForLocale, isLocaleId, isRtlLocale, localeEntry, localeFromTag, tagForLocale, } from './locales.js';
|
|
7
|
+
export { BUILTIN_LOCALE_IDS, LOCALES, LOCALE_ID_RE, LOCALE_IDS, allLocales, availableLocales, dirForLocale, intlTagForLocale, isBuiltinLocaleId, isLocaleId, isRtlLocale, localeEntry, localeFromTag, pluralCategoriesForLocale, resetRuntimeLocales, setRuntimeLocales, tagForLocale, tagFromLocaleId, } from './locales.js';
|
|
8
8
|
export { createI18n, switchLocale } from './create-i18n.js';
|
|
9
|
+
export { createI18nWithOverrides, mergeOverrides, overrideTag, rebuildWithOverrides, } from './overrides.js';
|
|
10
|
+
export { clearFormatFailures, formatFailures, recordFormatFailure, } from './format-errors.js';
|
|
9
11
|
export { EN_US_RESOURCES, NAMESPACES } from './resources/index.js';
|
|
10
12
|
export { loadLocaleBundle } from './resources/lazy.js';
|
|
13
|
+
// NOTE: the key index (`./keys.js`), the write validator
|
|
14
|
+
// (`./validate-message.js`) and the generated a11y-critical key list
|
|
15
|
+
// (`./a11y-keys.js`) are deliberately NOT re-exported here. They are
|
|
16
|
+
// EDIT-TIME concerns — only the server's translation routes and the editor
|
|
17
|
+
// need them — and the 458-entry `Set` literal in particular is not something
|
|
18
|
+
// Rollup will drop from the dashboard's entry chunk just because nothing
|
|
19
|
+
// references it. Import them from `@adminium/i18n/editing` instead; the
|
|
20
|
+
// dashboard's entry budget (`check-entry-budget.mjs`) is why.
|
|
21
|
+
export { formatFallback } from './fallback.js';
|
|
22
|
+
export { bumpI18nRevision, getI18nRevision, resetI18nRevision, subscribeI18nRevision, } from './revision.js';
|
|
23
|
+
export { REVIEW_STATUS, isReviewed, reviewedFraction } from './review-status.js';
|
|
11
24
|
export { getFormatters, latnDataTag, weekInfo } from './format/index.js';
|
|
12
25
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,gBAAgB,CAAC;AAE7C,OAAO,EACL,OAAO,EACP,UAAU,EACV,YAAY,EACZ,UAAU,EACV,WAAW,EACX,WAAW,EACX,aAAa,EACb,YAAY,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,gBAAgB,CAAC;AAE7C,OAAO,EACL,kBAAkB,EAClB,OAAO,EACP,YAAY,EACZ,UAAU,EACV,UAAU,EACV,gBAAgB,EAChB,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,UAAU,EACV,WAAW,EACX,WAAW,EACX,aAAa,EACb,yBAAyB,EACzB,mBAAmB,EACnB,iBAAiB,EACjB,YAAY,EACZ,eAAe,GAChB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EACL,uBAAuB,EACvB,cAAc,EACd,WAAW,EACX,oBAAoB,GACrB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,mBAAmB,GACpB,MAAM,oBAAoB,CAAC;AAI5B,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEvD,yDAAyD;AACzD,qEAAqE;AACrE,qEAAqE;AACrE,2EAA2E;AAC3E,6EAA6E;AAC7E,yEAAyE;AACzE,wEAAwE;AACxE,8DAA8D;AAE9D,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGjF,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/keys.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The flattened en-US key surface (23-runtime-translations.md §6.1).
|
|
3
|
+
*
|
|
4
|
+
* The Translations editor has to let an admin find one message among ~2,800,
|
|
5
|
+
* and the server has to answer "is this a real key?" on every write. Both run
|
|
6
|
+
* against THIS index, in process, so the DB is only ever asked for an
|
|
7
|
+
* `(namespace, key) IN (…)` slice — never a portable `LIKE '%q%'` scan over a
|
|
8
|
+
* table that grows with every override.
|
|
9
|
+
*
|
|
10
|
+
* Built lazily and cached: a server that never opens the editor never pays
|
|
11
|
+
* for it.
|
|
12
|
+
*/
|
|
13
|
+
import { type Namespace, type ResourceBundle } from './resources/index.js';
|
|
14
|
+
/** Nested bundle → flat `dot.path` → message. */
|
|
15
|
+
export declare function flattenBundle(bundle: ResourceBundle, prefix?: string, out?: Map<string, string>): Map<string, string>;
|
|
16
|
+
/** Flat map → nested bundle, the shape i18next's resource store wants. */
|
|
17
|
+
export declare function nestBundle(flat: ReadonlyMap<string, string>): ResourceBundle;
|
|
18
|
+
/** `namespace → key → en-US source text`, built once per process. */
|
|
19
|
+
export declare function sourceIndex(): ReadonlyMap<Namespace, ReadonlyMap<string, string>>;
|
|
20
|
+
/** The en-US source for a key, or `null` when the key does not exist. */
|
|
21
|
+
export declare function sourceMessage(namespace: string, key: string): string | null;
|
|
22
|
+
/** Total number of authored keys across every namespace. */
|
|
23
|
+
export declare function sourceKeyCount(): number;
|
|
24
|
+
/**
|
|
25
|
+
* The first segment of a key (`widgets.charts.foo` → `widgets`).
|
|
26
|
+
*
|
|
27
|
+
* The editor groups by this rather than by namespace, because the namespace
|
|
28
|
+
* axis is badly unbalanced in practice — `common` and `ui` hold effectively
|
|
29
|
+
* every key while `studio` and `generated` hold a handful each — so namespace
|
|
30
|
+
* is a poor primary navigation and a fine secondary filter.
|
|
31
|
+
*/
|
|
32
|
+
export declare function keyGroup(key: string): string;
|
|
33
|
+
//# sourceMappingURL=keys.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAA+B,KAAK,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAExG,iDAAiD;AACjD,wBAAgB,aAAa,CAC3B,MAAM,EAAE,cAAc,EACtB,MAAM,SAAK,EACX,GAAG,sBAA4B,GAC9B,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAOrB;AAED,0EAA0E;AAC1E,wBAAgB,UAAU,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,cAAc,CAc5E;AAID,qEAAqE;AACrE,wBAAgB,WAAW,IAAI,WAAW,CAAC,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAOjF;AAED,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG3E;AAED,4DAA4D;AAC5D,wBAAgB,cAAc,IAAI,MAAM,CAIvC;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG5C"}
|
package/dist/keys.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The flattened en-US key surface (23-runtime-translations.md §6.1).
|
|
3
|
+
*
|
|
4
|
+
* The Translations editor has to let an admin find one message among ~2,800,
|
|
5
|
+
* and the server has to answer "is this a real key?" on every write. Both run
|
|
6
|
+
* against THIS index, in process, so the DB is only ever asked for an
|
|
7
|
+
* `(namespace, key) IN (…)` slice — never a portable `LIKE '%q%'` scan over a
|
|
8
|
+
* table that grows with every override.
|
|
9
|
+
*
|
|
10
|
+
* Built lazily and cached: a server that never opens the editor never pays
|
|
11
|
+
* for it.
|
|
12
|
+
*/
|
|
13
|
+
import { EN_US_RESOURCES, NAMESPACES } from './resources/index.js';
|
|
14
|
+
/** Nested bundle → flat `dot.path` → message. */
|
|
15
|
+
export function flattenBundle(bundle, prefix = '', out = new Map()) {
|
|
16
|
+
for (const [key, value] of Object.entries(bundle)) {
|
|
17
|
+
const path = prefix === '' ? key : `${prefix}.${key}`;
|
|
18
|
+
if (typeof value === 'string')
|
|
19
|
+
out.set(path, value);
|
|
20
|
+
else
|
|
21
|
+
flattenBundle(value, path, out);
|
|
22
|
+
}
|
|
23
|
+
return out;
|
|
24
|
+
}
|
|
25
|
+
/** Flat map → nested bundle, the shape i18next's resource store wants. */
|
|
26
|
+
export function nestBundle(flat) {
|
|
27
|
+
const root = {};
|
|
28
|
+
for (const [path, value] of flat) {
|
|
29
|
+
const parts = path.split('.');
|
|
30
|
+
let node = root;
|
|
31
|
+
for (let i = 0; i < parts.length - 1; i += 1) {
|
|
32
|
+
const part = parts[i];
|
|
33
|
+
const next = node[part];
|
|
34
|
+
if (typeof next !== 'object' || next === null)
|
|
35
|
+
node[part] = {};
|
|
36
|
+
node = node[part];
|
|
37
|
+
}
|
|
38
|
+
node[parts[parts.length - 1]] = value;
|
|
39
|
+
}
|
|
40
|
+
return root;
|
|
41
|
+
}
|
|
42
|
+
let index = null;
|
|
43
|
+
/** `namespace → key → en-US source text`, built once per process. */
|
|
44
|
+
export function sourceIndex() {
|
|
45
|
+
if (index === null) {
|
|
46
|
+
const built = new Map();
|
|
47
|
+
for (const ns of NAMESPACES)
|
|
48
|
+
built.set(ns, flattenBundle(EN_US_RESOURCES[ns]));
|
|
49
|
+
index = built;
|
|
50
|
+
}
|
|
51
|
+
return index;
|
|
52
|
+
}
|
|
53
|
+
/** The en-US source for a key, or `null` when the key does not exist. */
|
|
54
|
+
export function sourceMessage(namespace, key) {
|
|
55
|
+
const ns = sourceIndex().get(namespace);
|
|
56
|
+
return ns?.get(key) ?? null;
|
|
57
|
+
}
|
|
58
|
+
/** Total number of authored keys across every namespace. */
|
|
59
|
+
export function sourceKeyCount() {
|
|
60
|
+
let total = 0;
|
|
61
|
+
for (const ns of sourceIndex().values())
|
|
62
|
+
total += ns.size;
|
|
63
|
+
return total;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The first segment of a key (`widgets.charts.foo` → `widgets`).
|
|
67
|
+
*
|
|
68
|
+
* The editor groups by this rather than by namespace, because the namespace
|
|
69
|
+
* axis is badly unbalanced in practice — `common` and `ui` hold effectively
|
|
70
|
+
* every key while `studio` and `generated` hold a handful each — so namespace
|
|
71
|
+
* is a poor primary navigation and a fine secondary filter.
|
|
72
|
+
*/
|
|
73
|
+
export function keyGroup(key) {
|
|
74
|
+
const dot = key.indexOf('.');
|
|
75
|
+
return dot === -1 ? key : key.slice(0, dot);
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=keys.js.map
|
package/dist/keys.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"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"}
|