@urbicon-ui/i18n 6.3.9 → 6.3.10
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/i18n/package-integration.js +50 -32
- package/package.json +2 -2
|
@@ -15,32 +15,39 @@ import { getRegistry } from './registry.svelte.js';
|
|
|
15
15
|
* out of the initial bundle as dynamic-import chunks, loaded only when activated.
|
|
16
16
|
*/
|
|
17
17
|
export function createPackageI18n(packageName, translations, options) {
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
18
|
+
// Lazy, first-use registration — deliberately NOT at module-eval (Codeberg #22).
|
|
19
|
+
// A consumer's top-level `export const x = createPackageI18n(...)` must not call
|
|
20
|
+
// getRegistry() during module initialisation: in a reordered *production* chunk
|
|
21
|
+
// (Rollup, `sideEffects: false`) that call can run before the registry module's
|
|
22
|
+
// `class I18nRegistry` statement, hitting the class temporal dead zone →
|
|
23
|
+
// `new (undefined)()` → "is not a constructor" → blank page on hydration. The
|
|
24
|
+
// hoisted getRegistry() keeps the *getter* reachable, but the *class* it
|
|
25
|
+
// constructs is still a TDZ binding, so the hoist guard alone was insufficient.
|
|
22
26
|
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
//
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
// setLocale. Parity for lazy bundles is a runtime concern (validatePackageTranslations).
|
|
37
|
-
if (options?.loaders) {
|
|
27
|
+
// Deferring registration to the first useTranslate()/t()/exists() call removes
|
|
28
|
+
// the ordering dependency at the source: by render / first-call time every module
|
|
29
|
+
// is fully evaluated, so `new I18nRegistry()` is always safe. Registration is
|
|
30
|
+
// synchronous (it runs before the translate read), so the first call resolves the
|
|
31
|
+
// real string — unlike the old queueMicrotask variant that returned the raw key.
|
|
32
|
+
// registerPackage mutates the reactive SvelteMap, but first touch is a component
|
|
33
|
+
// init (`useTranslate` body) or a non-reactive call (`t`/tests), never inside a
|
|
34
|
+
// `$derived`, so it cannot trip `state_unsafe_mutation`.
|
|
35
|
+
let registered = false;
|
|
36
|
+
const ensureRegistered = () => {
|
|
37
|
+
if (registered)
|
|
38
|
+
return;
|
|
39
|
+
registered = true;
|
|
38
40
|
const registry = getRegistry();
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
registry.registerPackage(packageName, translations);
|
|
42
|
+
// Opt-in lazy locales (WP4): dynamic-import loaders alongside the eager base
|
|
43
|
+
// bundle, loaded on demand by the provider / setLocale.
|
|
44
|
+
if (options?.loaders) {
|
|
45
|
+
for (const [locale, loader] of Object.entries(options.loaders)) {
|
|
46
|
+
if (loader)
|
|
47
|
+
registry.registerPackageLoader(packageName, locale, loader);
|
|
48
|
+
}
|
|
42
49
|
}
|
|
43
|
-
}
|
|
50
|
+
};
|
|
44
51
|
// Context-scoped hook — the SSR-correct, reactive accessor. Captures the
|
|
45
52
|
// request-scoped locale state at component init (or `undefined` without a
|
|
46
53
|
// provider → base locale), then resolves against the static registry. Reading
|
|
@@ -48,6 +55,7 @@ export function createPackageI18n(packageName, translations, options) {
|
|
|
48
55
|
// call-sites re-render on locale change; reading the registry's SvelteMap makes
|
|
49
56
|
// them re-render when a package registers more translations.
|
|
50
57
|
const useTranslate = () => {
|
|
58
|
+
ensureRegistered();
|
|
51
59
|
const state = useI18nState();
|
|
52
60
|
const registry = getRegistry();
|
|
53
61
|
return ((key, params, options) => registry.translate(key, state?.locale ?? BASE_LOCALE, state?.fallbackLocale ?? BASE_LOCALE, params, { packageName, ...options }));
|
|
@@ -56,15 +64,25 @@ export function createPackageI18n(packageName, translations, options) {
|
|
|
56
64
|
// against the base locale — there is no request-scoped state outside a
|
|
57
65
|
// component. Components use `useTranslate` for the reactive, provider-scoped
|
|
58
66
|
// locale.
|
|
59
|
-
const t = ((key, params, options) =>
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
const t = ((key, params, options) => {
|
|
68
|
+
ensureRegistered();
|
|
69
|
+
return getRegistry().translate(key, BASE_LOCALE, BASE_LOCALE, params, {
|
|
70
|
+
packageName,
|
|
71
|
+
...options
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
const exists = (key) => {
|
|
75
|
+
ensureRegistered();
|
|
76
|
+
return getRegistry().exists(key, BASE_LOCALE, packageName);
|
|
77
|
+
};
|
|
78
|
+
const getLocales = () => {
|
|
79
|
+
ensureRegistered();
|
|
80
|
+
return getRegistry().getPackageLocales(packageName);
|
|
81
|
+
};
|
|
82
|
+
// Eager-register escape hatch: a consumer that wants the package present before
|
|
83
|
+
// the first useTranslate()/t() (e.g. to preload a lazy locale) can call this.
|
|
84
|
+
// Previously a no-op; now it performs the idempotent first-use registration.
|
|
85
|
+
const register = () => ensureRegistered();
|
|
68
86
|
return {
|
|
69
87
|
useTranslate,
|
|
70
88
|
t,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@urbicon-ui/i18n",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.10",
|
|
4
4
|
"description": "Runes-based localization for Svelte 5 apps and the Urbicon UI design system",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"@sveltejs/package": "^2.5.8",
|
|
25
25
|
"@sveltejs/vite-plugin-svelte": "^7.0.0",
|
|
26
26
|
"@types/node": "^25.9.4",
|
|
27
|
-
"@urbicon-ui/shared-types": "6.3.
|
|
27
|
+
"@urbicon-ui/shared-types": "6.3.10",
|
|
28
28
|
"prettier": "^3.8.4",
|
|
29
29
|
"prettier-plugin-svelte": "^4.1.1",
|
|
30
30
|
"prettier-plugin-tailwindcss": "^0.8.0",
|