@vielzeug/i18nit 1.1.4 → 2.0.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/README.md +52 -710
- package/dist/core.cjs +2 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.d.ts +35 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +53 -0
- package/dist/core.js.map +1 -0
- package/dist/helpers.cjs +2 -0
- package/dist/helpers.cjs.map +1 -0
- package/dist/helpers.d.ts +20 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/helpers.js +47 -0
- package/dist/helpers.js.map +1 -0
- package/dist/i18n.cjs +2 -0
- package/dist/i18n.cjs.map +1 -0
- package/dist/i18n.d.ts +78 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +218 -0
- package/dist/i18n.js.map +1 -0
- package/dist/i18nit.cjs +2 -2
- package/dist/i18nit.cjs.map +1 -1
- package/dist/i18nit.d.ts +3 -0
- package/dist/i18nit.d.ts.map +1 -0
- package/dist/i18nit.js +2 -222
- package/dist/i18nit.js.map +1 -1
- package/dist/index.cjs +1 -2
- package/dist/index.d.ts +4 -75
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -5
- package/dist/interpolate.cjs +2 -0
- package/dist/interpolate.cjs.map +1 -0
- package/dist/interpolate.d.ts +11 -0
- package/dist/interpolate.d.ts.map +1 -0
- package/dist/interpolate.js +13 -0
- package/dist/interpolate.js.map +1 -0
- package/dist/intl.cjs +2 -0
- package/dist/intl.cjs.map +1 -0
- package/dist/intl.d.ts +16 -0
- package/dist/intl.d.ts.map +1 -0
- package/dist/intl.js +65 -0
- package/dist/intl.js.map +1 -0
- package/dist/types.d.ts +97 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +19 -9
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
package/dist/core.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=class e{#e;#t;#n;constructor(e,t,n){this.#e=e,this.#t=t,this.#n=n}get locale(){return this.#t??this.#e.getLocale()}#r(e){return this.#n?`${this.#n}.${e}`:e}t(e,t){return this.#e.translate(this.#r(e),t,this.locale)}has(e){return this.#e.findMessage(this.#r(e),this.locale)!==void 0}hasOwn(e){return this.#e.checkOwn(this.#r(e),this.locale)}number(e,t){return this.#e.formatNumber(e,t,this.locale)}date(e,t){return this.#e.formatDate(e,t,this.locale)}list(e,t=`and`){return this.#e.formatList(e,this.locale,t)}relative(e,t,n){return this.#e.formatRelative(e,t,n,this.locale)}currency(e,t,n){return this.#e.formatNumber(e,{...n,currency:t,style:`currency`},this.locale)}scope(t){return new e(this.#e,this.#t,this.#n?`${this.#n}.${String(t)}`:String(t))}withLocale(t){return new e(this.#e,t,this.#n)}};exports.BoundView=e;
|
|
2
|
+
//# sourceMappingURL=core.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.cjs","names":["#core","#fixedLocale","#prefix","#key"],"sources":["../src/core.ts"],"sourcesContent":["import type { BoundI18n, Locale, MessageValue, Messages, NamespaceKeys, TranslationKeyParam, Vars } from './types';\n\n/* -------------------- I18nCore -------------------- */\n\n/**\n * Module-private interface given to every `BoundView` — exposes only the operations views need.\n * Created once per `I18n` instance so `scope()` / `withLocale()` allocate no closures per call.\n */\nexport type I18nCore = {\n checkOwn(key: string, locale: Locale): boolean;\n findMessage(key: string, locale: Locale): MessageValue | undefined;\n formatDate(value: Date | number, options: Intl.DateTimeFormatOptions | undefined, locale: Locale): string;\n formatList(items: unknown[], locale: string, type: 'and' | 'or'): string;\n formatNumber(value: number, options: Intl.NumberFormatOptions | undefined, locale: Locale): string;\n formatRelative(\n value: number,\n unit: Intl.RelativeTimeFormatUnit,\n options: Intl.RelativeTimeFormatOptions | undefined,\n locale: Locale,\n ): string;\n getLocale(): Locale;\n translate(key: string, vars: Vars | undefined, locale: Locale): string;\n};\n\n/* -------------------- BoundView -------------------- */\n\n/**\n * Lightweight view over an `I18n` instance, fixed to a locale and/or key namespace prefix.\n * All methods live on the prototype — no closures are allocated per `scope()` / `withLocale()` call.\n */\nexport class BoundView<T extends Messages = Messages> implements BoundI18n<T> {\n readonly #core: I18nCore;\n readonly #fixedLocale: Locale | null;\n readonly #prefix: string | undefined;\n\n constructor(core: I18nCore, fixedLocale: Locale | null, prefix?: string) {\n this.#core = core;\n this.#fixedLocale = fixedLocale;\n this.#prefix = prefix;\n }\n\n get locale(): Locale {\n return this.#fixedLocale ?? this.#core.getLocale();\n }\n\n #key(key: string): string {\n return this.#prefix ? `${this.#prefix}.${key}` : key;\n }\n\n t(key: TranslationKeyParam<T>, vars?: Vars): string {\n return this.#core.translate(this.#key(key as string), vars, this.locale);\n }\n\n has(key: string): boolean {\n return this.#core.findMessage(this.#key(key), this.locale) !== undefined;\n }\n\n hasOwn(key: string): boolean {\n return this.#core.checkOwn(this.#key(key), this.locale);\n }\n\n number(value: number, options?: Intl.NumberFormatOptions): string {\n return this.#core.formatNumber(value, options, this.locale);\n }\n\n date(value: Date | number, options?: Intl.DateTimeFormatOptions): string {\n return this.#core.formatDate(value, options, this.locale);\n }\n\n list(items: unknown[], type: 'and' | 'or' = 'and'): string {\n return this.#core.formatList(items, this.locale, type);\n }\n\n relative(value: number, unit: Intl.RelativeTimeFormatUnit, options?: Intl.RelativeTimeFormatOptions): string {\n return this.#core.formatRelative(value, unit, options, this.locale);\n }\n\n currency(value: number, currency: string, options?: Omit<Intl.NumberFormatOptions, 'style' | 'currency'>): string {\n return this.#core.formatNumber(value, { ...options, currency, style: 'currency' }, this.locale);\n }\n\n scope<K extends NamespaceKeys<T>>(ns: K): BoundI18n<T[K] & Messages> {\n return new BoundView(\n this.#core,\n this.#fixedLocale,\n this.#prefix ? `${this.#prefix}.${String(ns)}` : String(ns),\n ) as BoundI18n<T[K] & Messages>;\n }\n\n withLocale(locale: Locale): BoundI18n<T> {\n return new BoundView<T>(this.#core, locale, this.#prefix);\n }\n}\n"],"mappings":"AA8BA,IAAa,EAAb,MAAa,CAAiE,CAC5E,GACA,GACA,GAEA,YAAY,EAAgB,EAA4B,EAAiB,CACvE,MAAA,EAAa,EACb,MAAA,EAAoB,EACpB,MAAA,EAAe,EAGjB,IAAI,QAAiB,CACnB,OAAO,MAAA,GAAqB,MAAA,EAAW,WAAW,CAGpD,GAAK,EAAqB,CACxB,OAAO,MAAA,EAAe,GAAG,MAAA,EAAa,GAAG,IAAQ,EAGnD,EAAE,EAA6B,EAAqB,CAClD,OAAO,MAAA,EAAW,UAAU,MAAA,EAAU,EAAc,CAAE,EAAM,KAAK,OAAO,CAG1E,IAAI,EAAsB,CACxB,OAAO,MAAA,EAAW,YAAY,MAAA,EAAU,EAAI,CAAE,KAAK,OAAO,GAAK,IAAA,GAGjE,OAAO,EAAsB,CAC3B,OAAO,MAAA,EAAW,SAAS,MAAA,EAAU,EAAI,CAAE,KAAK,OAAO,CAGzD,OAAO,EAAe,EAA4C,CAChE,OAAO,MAAA,EAAW,aAAa,EAAO,EAAS,KAAK,OAAO,CAG7D,KAAK,EAAsB,EAA8C,CACvE,OAAO,MAAA,EAAW,WAAW,EAAO,EAAS,KAAK,OAAO,CAG3D,KAAK,EAAkB,EAAqB,MAAe,CACzD,OAAO,MAAA,EAAW,WAAW,EAAO,KAAK,OAAQ,EAAK,CAGxD,SAAS,EAAe,EAAmC,EAAkD,CAC3G,OAAO,MAAA,EAAW,eAAe,EAAO,EAAM,EAAS,KAAK,OAAO,CAGrE,SAAS,EAAe,EAAkB,EAAwE,CAChH,OAAO,MAAA,EAAW,aAAa,EAAO,CAAE,GAAG,EAAS,WAAU,MAAO,WAAY,CAAE,KAAK,OAAO,CAGjG,MAAkC,EAAmC,CACnE,OAAO,IAAI,EACT,MAAA,EACA,MAAA,EACA,MAAA,EAAe,GAAG,MAAA,EAAa,GAAG,OAAO,EAAG,GAAK,OAAO,EAAG,CAC5D,CAGH,WAAW,EAA8B,CACvC,OAAO,IAAI,EAAa,MAAA,EAAY,EAAQ,MAAA,EAAa"}
|
package/dist/core.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { BoundI18n, Locale, MessageValue, Messages, NamespaceKeys, TranslationKeyParam, Vars } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Module-private interface given to every `BoundView` — exposes only the operations views need.
|
|
4
|
+
* Created once per `I18n` instance so `scope()` / `withLocale()` allocate no closures per call.
|
|
5
|
+
*/
|
|
6
|
+
export type I18nCore = {
|
|
7
|
+
checkOwn(key: string, locale: Locale): boolean;
|
|
8
|
+
findMessage(key: string, locale: Locale): MessageValue | undefined;
|
|
9
|
+
formatDate(value: Date | number, options: Intl.DateTimeFormatOptions | undefined, locale: Locale): string;
|
|
10
|
+
formatList(items: unknown[], locale: string, type: 'and' | 'or'): string;
|
|
11
|
+
formatNumber(value: number, options: Intl.NumberFormatOptions | undefined, locale: Locale): string;
|
|
12
|
+
formatRelative(value: number, unit: Intl.RelativeTimeFormatUnit, options: Intl.RelativeTimeFormatOptions | undefined, locale: Locale): string;
|
|
13
|
+
getLocale(): Locale;
|
|
14
|
+
translate(key: string, vars: Vars | undefined, locale: Locale): string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Lightweight view over an `I18n` instance, fixed to a locale and/or key namespace prefix.
|
|
18
|
+
* All methods live on the prototype — no closures are allocated per `scope()` / `withLocale()` call.
|
|
19
|
+
*/
|
|
20
|
+
export declare class BoundView<T extends Messages = Messages> implements BoundI18n<T> {
|
|
21
|
+
#private;
|
|
22
|
+
constructor(core: I18nCore, fixedLocale: Locale | null, prefix?: string);
|
|
23
|
+
get locale(): Locale;
|
|
24
|
+
t(key: TranslationKeyParam<T>, vars?: Vars): string;
|
|
25
|
+
has(key: string): boolean;
|
|
26
|
+
hasOwn(key: string): boolean;
|
|
27
|
+
number(value: number, options?: Intl.NumberFormatOptions): string;
|
|
28
|
+
date(value: Date | number, options?: Intl.DateTimeFormatOptions): string;
|
|
29
|
+
list(items: unknown[], type?: 'and' | 'or'): string;
|
|
30
|
+
relative(value: number, unit: Intl.RelativeTimeFormatUnit, options?: Intl.RelativeTimeFormatOptions): string;
|
|
31
|
+
currency(value: number, currency: string, options?: Omit<Intl.NumberFormatOptions, 'style' | 'currency'>): string;
|
|
32
|
+
scope<K extends NamespaceKeys<T>>(ns: K): BoundI18n<T[K] & Messages>;
|
|
33
|
+
withLocale(locale: Locale): BoundI18n<T>;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,mBAAmB,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAInH;;;GAGG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IAC/C,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAAC;IACnE,UAAU,CAAC,KAAK,EAAE,IAAI,GAAG,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,qBAAqB,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1G,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,GAAG,IAAI,GAAG,MAAM,CAAC;IACzE,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,mBAAmB,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACnG,cAAc,CACZ,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,IAAI,CAAC,sBAAsB,EACjC,OAAO,EAAE,IAAI,CAAC,yBAAyB,GAAG,SAAS,EACnD,MAAM,EAAE,MAAM,GACb,MAAM,CAAC;IACV,SAAS,IAAI,MAAM,CAAC;IACpB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;CACxE,CAAC;AAIF;;;GAGG;AACH,qBAAa,SAAS,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,CAAE,YAAW,SAAS,CAAC,CAAC,CAAC;;gBAK/D,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM;IAMvE,IAAI,MAAM,IAAI,MAAM,CAEnB;IAMD,CAAC,CAAC,GAAG,EAAE,mBAAmB,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,MAAM;IAInD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI5B,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,mBAAmB,GAAG,MAAM;IAIjE,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,qBAAqB,GAAG,MAAM;IAIxE,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,IAAI,GAAE,KAAK,GAAG,IAAY,GAAG,MAAM;IAI1D,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,sBAAsB,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,yBAAyB,GAAG,MAAM;IAI5G,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,OAAO,GAAG,UAAU,CAAC,GAAG,MAAM;IAIjH,KAAK,CAAC,CAAC,SAAS,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC;IAQpE,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;CAGzC"}
|
package/dist/core.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
//#region src/core.ts
|
|
2
|
+
var e = class e {
|
|
3
|
+
#e;
|
|
4
|
+
#t;
|
|
5
|
+
#n;
|
|
6
|
+
constructor(e, t, n) {
|
|
7
|
+
this.#e = e, this.#t = t, this.#n = n;
|
|
8
|
+
}
|
|
9
|
+
get locale() {
|
|
10
|
+
return this.#t ?? this.#e.getLocale();
|
|
11
|
+
}
|
|
12
|
+
#r(e) {
|
|
13
|
+
return this.#n ? `${this.#n}.${e}` : e;
|
|
14
|
+
}
|
|
15
|
+
t(e, t) {
|
|
16
|
+
return this.#e.translate(this.#r(e), t, this.locale);
|
|
17
|
+
}
|
|
18
|
+
has(e) {
|
|
19
|
+
return this.#e.findMessage(this.#r(e), this.locale) !== void 0;
|
|
20
|
+
}
|
|
21
|
+
hasOwn(e) {
|
|
22
|
+
return this.#e.checkOwn(this.#r(e), this.locale);
|
|
23
|
+
}
|
|
24
|
+
number(e, t) {
|
|
25
|
+
return this.#e.formatNumber(e, t, this.locale);
|
|
26
|
+
}
|
|
27
|
+
date(e, t) {
|
|
28
|
+
return this.#e.formatDate(e, t, this.locale);
|
|
29
|
+
}
|
|
30
|
+
list(e, t = "and") {
|
|
31
|
+
return this.#e.formatList(e, this.locale, t);
|
|
32
|
+
}
|
|
33
|
+
relative(e, t, n) {
|
|
34
|
+
return this.#e.formatRelative(e, t, n, this.locale);
|
|
35
|
+
}
|
|
36
|
+
currency(e, t, n) {
|
|
37
|
+
return this.#e.formatNumber(e, {
|
|
38
|
+
...n,
|
|
39
|
+
currency: t,
|
|
40
|
+
style: "currency"
|
|
41
|
+
}, this.locale);
|
|
42
|
+
}
|
|
43
|
+
scope(t) {
|
|
44
|
+
return new e(this.#e, this.#t, this.#n ? `${this.#n}.${String(t)}` : String(t));
|
|
45
|
+
}
|
|
46
|
+
withLocale(t) {
|
|
47
|
+
return new e(this.#e, t, this.#n);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
//#endregion
|
|
51
|
+
export { e as BoundView };
|
|
52
|
+
|
|
53
|
+
//# sourceMappingURL=core.js.map
|
package/dist/core.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.js","names":["#core","#fixedLocale","#prefix","#key"],"sources":["../src/core.ts"],"sourcesContent":["import type { BoundI18n, Locale, MessageValue, Messages, NamespaceKeys, TranslationKeyParam, Vars } from './types';\n\n/* -------------------- I18nCore -------------------- */\n\n/**\n * Module-private interface given to every `BoundView` — exposes only the operations views need.\n * Created once per `I18n` instance so `scope()` / `withLocale()` allocate no closures per call.\n */\nexport type I18nCore = {\n checkOwn(key: string, locale: Locale): boolean;\n findMessage(key: string, locale: Locale): MessageValue | undefined;\n formatDate(value: Date | number, options: Intl.DateTimeFormatOptions | undefined, locale: Locale): string;\n formatList(items: unknown[], locale: string, type: 'and' | 'or'): string;\n formatNumber(value: number, options: Intl.NumberFormatOptions | undefined, locale: Locale): string;\n formatRelative(\n value: number,\n unit: Intl.RelativeTimeFormatUnit,\n options: Intl.RelativeTimeFormatOptions | undefined,\n locale: Locale,\n ): string;\n getLocale(): Locale;\n translate(key: string, vars: Vars | undefined, locale: Locale): string;\n};\n\n/* -------------------- BoundView -------------------- */\n\n/**\n * Lightweight view over an `I18n` instance, fixed to a locale and/or key namespace prefix.\n * All methods live on the prototype — no closures are allocated per `scope()` / `withLocale()` call.\n */\nexport class BoundView<T extends Messages = Messages> implements BoundI18n<T> {\n readonly #core: I18nCore;\n readonly #fixedLocale: Locale | null;\n readonly #prefix: string | undefined;\n\n constructor(core: I18nCore, fixedLocale: Locale | null, prefix?: string) {\n this.#core = core;\n this.#fixedLocale = fixedLocale;\n this.#prefix = prefix;\n }\n\n get locale(): Locale {\n return this.#fixedLocale ?? this.#core.getLocale();\n }\n\n #key(key: string): string {\n return this.#prefix ? `${this.#prefix}.${key}` : key;\n }\n\n t(key: TranslationKeyParam<T>, vars?: Vars): string {\n return this.#core.translate(this.#key(key as string), vars, this.locale);\n }\n\n has(key: string): boolean {\n return this.#core.findMessage(this.#key(key), this.locale) !== undefined;\n }\n\n hasOwn(key: string): boolean {\n return this.#core.checkOwn(this.#key(key), this.locale);\n }\n\n number(value: number, options?: Intl.NumberFormatOptions): string {\n return this.#core.formatNumber(value, options, this.locale);\n }\n\n date(value: Date | number, options?: Intl.DateTimeFormatOptions): string {\n return this.#core.formatDate(value, options, this.locale);\n }\n\n list(items: unknown[], type: 'and' | 'or' = 'and'): string {\n return this.#core.formatList(items, this.locale, type);\n }\n\n relative(value: number, unit: Intl.RelativeTimeFormatUnit, options?: Intl.RelativeTimeFormatOptions): string {\n return this.#core.formatRelative(value, unit, options, this.locale);\n }\n\n currency(value: number, currency: string, options?: Omit<Intl.NumberFormatOptions, 'style' | 'currency'>): string {\n return this.#core.formatNumber(value, { ...options, currency, style: 'currency' }, this.locale);\n }\n\n scope<K extends NamespaceKeys<T>>(ns: K): BoundI18n<T[K] & Messages> {\n return new BoundView(\n this.#core,\n this.#fixedLocale,\n this.#prefix ? `${this.#prefix}.${String(ns)}` : String(ns),\n ) as BoundI18n<T[K] & Messages>;\n }\n\n withLocale(locale: Locale): BoundI18n<T> {\n return new BoundView<T>(this.#core, locale, this.#prefix);\n }\n}\n"],"mappings":";AA8BA,IAAa,IAAb,MAAa,EAAiE;CAC5E;CACA;CACA;CAEA,YAAY,GAAgB,GAA4B,GAAiB;AAGvE,EAFA,MAAA,IAAa,GACb,MAAA,IAAoB,GACpB,MAAA,IAAe;;CAGjB,IAAI,SAAiB;AACnB,SAAO,MAAA,KAAqB,MAAA,EAAW,WAAW;;CAGpD,GAAK,GAAqB;AACxB,SAAO,MAAA,IAAe,GAAG,MAAA,EAAa,GAAG,MAAQ;;CAGnD,EAAE,GAA6B,GAAqB;AAClD,SAAO,MAAA,EAAW,UAAU,MAAA,EAAU,EAAc,EAAE,GAAM,KAAK,OAAO;;CAG1E,IAAI,GAAsB;AACxB,SAAO,MAAA,EAAW,YAAY,MAAA,EAAU,EAAI,EAAE,KAAK,OAAO,KAAK,KAAA;;CAGjE,OAAO,GAAsB;AAC3B,SAAO,MAAA,EAAW,SAAS,MAAA,EAAU,EAAI,EAAE,KAAK,OAAO;;CAGzD,OAAO,GAAe,GAA4C;AAChE,SAAO,MAAA,EAAW,aAAa,GAAO,GAAS,KAAK,OAAO;;CAG7D,KAAK,GAAsB,GAA8C;AACvE,SAAO,MAAA,EAAW,WAAW,GAAO,GAAS,KAAK,OAAO;;CAG3D,KAAK,GAAkB,IAAqB,OAAe;AACzD,SAAO,MAAA,EAAW,WAAW,GAAO,KAAK,QAAQ,EAAK;;CAGxD,SAAS,GAAe,GAAmC,GAAkD;AAC3G,SAAO,MAAA,EAAW,eAAe,GAAO,GAAM,GAAS,KAAK,OAAO;;CAGrE,SAAS,GAAe,GAAkB,GAAwE;AAChH,SAAO,MAAA,EAAW,aAAa,GAAO;GAAE,GAAG;GAAS;GAAU,OAAO;GAAY,EAAE,KAAK,OAAO;;CAGjG,MAAkC,GAAmC;AACnE,SAAO,IAAI,EACT,MAAA,GACA,MAAA,GACA,MAAA,IAAe,GAAG,MAAA,EAAa,GAAG,OAAO,EAAG,KAAK,OAAO,EAAG,CAC5D;;CAGH,WAAW,GAA8B;AACvC,SAAO,IAAI,EAAa,MAAA,GAAY,GAAQ,MAAA,EAAa"}
|
package/dist/helpers.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function e(e,t){if(t in e)return e[t];let n=t.match(/[^.[\]]+/gu)??[],r=e;for(let e of n){if(typeof r!=`object`||!r)return;r=r[e]}return r}var t=new Set([`zero`,`one`,`two`,`few`,`many`,`other`]);function n(e){if(typeof e==`string`)return!0;if(typeof e!=`object`||!e||Array.isArray(e))return!1;let n=e;if(!(`other`in n))return!1;let r=Object.keys(n);return r.length>t.size?!1:r.every(e=>t.has(e))&&Object.values(n).every(e=>typeof e==`string`)}function r(e,t){let i={...e};for(let[e,a]of Object.entries(t)){let t=i[e];!n(a)&&!n(t)&&typeof t==`object`&&t?i[e]=r(t,a):i[e]=typeof a==`object`&&a?{...a}:a}return i}var i=class extends Map{#e;constructor(e){super(),this.#e=e}set(e,t){return!this.has(e)&&this.size>=this.#e&&this.delete(this.keys().next().value),super.set(e,t)}};exports.BoundedMap=i,exports.deepMerge=r,exports.isMessageValue=n,exports.resolvePath=e;
|
|
2
|
+
//# sourceMappingURL=helpers.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.cjs","names":["#cap"],"sources":["../src/helpers.ts"],"sourcesContent":["import type { MessageValue, Messages } from './types';\n\n/* -------------------- Path Resolution -------------------- */\n\n/**\n * Resolves nested properties using dot notation and bracket notation.\n * Supports: 'user.name', 'items[0]', 'user.items[0].name'\n */\nexport function resolvePath(obj: Record<string, unknown>, path: string): unknown {\n // Try direct access first (handles keys with literal dots)\n if (path in obj) return obj[path];\n\n const parts = path.match(/[^.[\\]]+/gu) ?? [];\n let value: unknown = obj;\n\n for (const part of parts) {\n if (value == null || typeof value !== 'object') return undefined;\n\n value = (value as Record<string, unknown>)[part];\n }\n\n return value;\n}\n\n/* -------------------- Message Value Guard -------------------- */\n\nexport const PLURAL_FORMS = new Set<string>(['zero', 'one', 'two', 'few', 'many', 'other']);\n\nexport function isMessageValue(value: unknown): value is MessageValue {\n if (typeof value === 'string') return true;\n\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n\n const obj = value as Record<string, unknown>;\n\n if (!('other' in obj)) return false;\n\n const keys = Object.keys(obj);\n\n if (keys.length > PLURAL_FORMS.size) return false;\n\n return keys.every((k) => PLURAL_FORMS.has(k)) && Object.values(obj).every((v) => typeof v === 'string');\n}\n\n/* -------------------- Deep Merge -------------------- */\n\nexport function deepMerge(target: Messages, source: Messages): Messages {\n const result = { ...target };\n\n for (const [key, val] of Object.entries(source)) {\n const existing = result[key];\n\n if (!isMessageValue(val) && !isMessageValue(existing) && typeof existing === 'object' && existing !== null) {\n result[key] = deepMerge(existing as Messages, val as Messages);\n } else {\n // Clone PluralMessages objects to prevent external mutations from corrupting the catalog.\n result[key] = typeof val === 'object' && val !== null ? ({ ...(val as object) } as MessageValue) : val;\n }\n }\n\n return result;\n}\n\n/* -------------------- BoundedMap -------------------- */\n\n/**\n * Size-bounded Map that evicts the oldest entry (insertion order) when the cap is reached.\n * Used by I18n's chain cache to prevent unbounded growth in long-lived SSR singletons when\n * locale tags are derived from arbitrary user input (e.g. Accept-Language headers).\n */\nexport class BoundedMap<K, V> extends Map<K, V> {\n readonly #cap: number;\n\n constructor(cap: number) {\n super();\n this.#cap = cap;\n }\n\n override set(key: K, value: V): this {\n if (!this.has(key) && this.size >= this.#cap) {\n this.delete(this.keys().next().value as K);\n }\n\n return super.set(key, value);\n }\n}\n"],"mappings":"AAQA,SAAgB,EAAY,EAA8B,EAAuB,CAE/E,GAAI,KAAQ,EAAK,OAAO,EAAI,GAE5B,IAAM,EAAQ,EAAK,MAAM,aAAa,EAAI,EAAE,CACxC,EAAiB,EAErB,IAAK,IAAM,KAAQ,EAAO,CACxB,GAAqB,OAAO,GAAU,WAAlC,EAA4C,OAEhD,EAAS,EAAkC,GAG7C,OAAO,EAKT,IAAa,EAAe,IAAI,IAAY,CAAC,OAAQ,MAAO,MAAO,MAAO,OAAQ,QAAQ,CAAC,CAE3F,SAAgB,EAAe,EAAuC,CACpE,GAAI,OAAO,GAAU,SAAU,MAAO,GAEtC,GAAI,OAAO,GAAU,WAAY,GAAkB,MAAM,QAAQ,EAAM,CAAE,MAAO,GAEhF,IAAM,EAAM,EAEZ,GAAI,EAAE,UAAW,GAAM,MAAO,GAE9B,IAAM,EAAO,OAAO,KAAK,EAAI,CAI7B,OAFI,EAAK,OAAS,EAAa,KAAa,GAErC,EAAK,MAAO,GAAM,EAAa,IAAI,EAAE,CAAC,EAAI,OAAO,OAAO,EAAI,CAAC,MAAO,GAAM,OAAO,GAAM,SAAS,CAKzG,SAAgB,EAAU,EAAkB,EAA4B,CACtE,IAAM,EAAS,CAAE,GAAG,EAAQ,CAE5B,IAAK,GAAM,CAAC,EAAK,KAAQ,OAAO,QAAQ,EAAO,CAAE,CAC/C,IAAM,EAAW,EAAO,GAEpB,CAAC,EAAe,EAAI,EAAI,CAAC,EAAe,EAAS,EAAI,OAAO,GAAa,UAAY,EACvF,EAAO,GAAO,EAAU,EAAsB,EAAgB,CAG9D,EAAO,GAAO,OAAO,GAAQ,UAAY,EAAgB,CAAE,GAAI,EAAgB,CAAoB,EAIvG,OAAO,EAUT,IAAa,EAAb,cAAsC,GAAU,CAC9C,GAEA,YAAY,EAAa,CACvB,OAAO,CACP,MAAA,EAAY,EAGd,IAAa,EAAQ,EAAgB,CAKnC,MAJI,CAAC,KAAK,IAAI,EAAI,EAAI,KAAK,MAAQ,MAAA,GACjC,KAAK,OAAO,KAAK,MAAM,CAAC,MAAM,CAAC,MAAW,CAGrC,MAAM,IAAI,EAAK,EAAM"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { MessageValue, Messages } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Resolves nested properties using dot notation and bracket notation.
|
|
4
|
+
* Supports: 'user.name', 'items[0]', 'user.items[0].name'
|
|
5
|
+
*/
|
|
6
|
+
export declare function resolvePath(obj: Record<string, unknown>, path: string): unknown;
|
|
7
|
+
export declare const PLURAL_FORMS: Set<string>;
|
|
8
|
+
export declare function isMessageValue(value: unknown): value is MessageValue;
|
|
9
|
+
export declare function deepMerge(target: Messages, source: Messages): Messages;
|
|
10
|
+
/**
|
|
11
|
+
* Size-bounded Map that evicts the oldest entry (insertion order) when the cap is reached.
|
|
12
|
+
* Used by I18n's chain cache to prevent unbounded growth in long-lived SSR singletons when
|
|
13
|
+
* locale tags are derived from arbitrary user input (e.g. Accept-Language headers).
|
|
14
|
+
*/
|
|
15
|
+
export declare class BoundedMap<K, V> extends Map<K, V> {
|
|
16
|
+
#private;
|
|
17
|
+
constructor(cap: number);
|
|
18
|
+
set(key: K, value: V): this;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAItD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAc/E;AAID,eAAO,MAAM,YAAY,aAAkE,CAAC;AAE5F,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,YAAY,CAcpE;AAID,wBAAgB,SAAS,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAetE;AAID;;;;GAIG;AACH,qBAAa,UAAU,CAAC,CAAC,EAAE,CAAC,CAAE,SAAQ,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;;gBAGjC,GAAG,EAAE,MAAM;IAKd,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI;CAOrC"}
|
package/dist/helpers.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
//#region src/helpers.ts
|
|
2
|
+
function e(e, t) {
|
|
3
|
+
if (t in e) return e[t];
|
|
4
|
+
let n = t.match(/[^.[\]]+/gu) ?? [], r = e;
|
|
5
|
+
for (let e of n) {
|
|
6
|
+
if (typeof r != "object" || !r) return;
|
|
7
|
+
r = r[e];
|
|
8
|
+
}
|
|
9
|
+
return r;
|
|
10
|
+
}
|
|
11
|
+
var t = new Set([
|
|
12
|
+
"zero",
|
|
13
|
+
"one",
|
|
14
|
+
"two",
|
|
15
|
+
"few",
|
|
16
|
+
"many",
|
|
17
|
+
"other"
|
|
18
|
+
]);
|
|
19
|
+
function n(e) {
|
|
20
|
+
if (typeof e == "string") return !0;
|
|
21
|
+
if (typeof e != "object" || !e || Array.isArray(e)) return !1;
|
|
22
|
+
let n = e;
|
|
23
|
+
if (!("other" in n)) return !1;
|
|
24
|
+
let r = Object.keys(n);
|
|
25
|
+
return r.length > t.size ? !1 : r.every((e) => t.has(e)) && Object.values(n).every((e) => typeof e == "string");
|
|
26
|
+
}
|
|
27
|
+
function r(e, t) {
|
|
28
|
+
let i = { ...e };
|
|
29
|
+
for (let [e, a] of Object.entries(t)) {
|
|
30
|
+
let t = i[e];
|
|
31
|
+
!n(a) && !n(t) && typeof t == "object" && t ? i[e] = r(t, a) : i[e] = typeof a == "object" && a ? { ...a } : a;
|
|
32
|
+
}
|
|
33
|
+
return i;
|
|
34
|
+
}
|
|
35
|
+
var i = class extends Map {
|
|
36
|
+
#e;
|
|
37
|
+
constructor(e) {
|
|
38
|
+
super(), this.#e = e;
|
|
39
|
+
}
|
|
40
|
+
set(e, t) {
|
|
41
|
+
return !this.has(e) && this.size >= this.#e && this.delete(this.keys().next().value), super.set(e, t);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
//#endregion
|
|
45
|
+
export { i as BoundedMap, r as deepMerge, n as isMessageValue, e as resolvePath };
|
|
46
|
+
|
|
47
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.js","names":["#cap"],"sources":["../src/helpers.ts"],"sourcesContent":["import type { MessageValue, Messages } from './types';\n\n/* -------------------- Path Resolution -------------------- */\n\n/**\n * Resolves nested properties using dot notation and bracket notation.\n * Supports: 'user.name', 'items[0]', 'user.items[0].name'\n */\nexport function resolvePath(obj: Record<string, unknown>, path: string): unknown {\n // Try direct access first (handles keys with literal dots)\n if (path in obj) return obj[path];\n\n const parts = path.match(/[^.[\\]]+/gu) ?? [];\n let value: unknown = obj;\n\n for (const part of parts) {\n if (value == null || typeof value !== 'object') return undefined;\n\n value = (value as Record<string, unknown>)[part];\n }\n\n return value;\n}\n\n/* -------------------- Message Value Guard -------------------- */\n\nexport const PLURAL_FORMS = new Set<string>(['zero', 'one', 'two', 'few', 'many', 'other']);\n\nexport function isMessageValue(value: unknown): value is MessageValue {\n if (typeof value === 'string') return true;\n\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n\n const obj = value as Record<string, unknown>;\n\n if (!('other' in obj)) return false;\n\n const keys = Object.keys(obj);\n\n if (keys.length > PLURAL_FORMS.size) return false;\n\n return keys.every((k) => PLURAL_FORMS.has(k)) && Object.values(obj).every((v) => typeof v === 'string');\n}\n\n/* -------------------- Deep Merge -------------------- */\n\nexport function deepMerge(target: Messages, source: Messages): Messages {\n const result = { ...target };\n\n for (const [key, val] of Object.entries(source)) {\n const existing = result[key];\n\n if (!isMessageValue(val) && !isMessageValue(existing) && typeof existing === 'object' && existing !== null) {\n result[key] = deepMerge(existing as Messages, val as Messages);\n } else {\n // Clone PluralMessages objects to prevent external mutations from corrupting the catalog.\n result[key] = typeof val === 'object' && val !== null ? ({ ...(val as object) } as MessageValue) : val;\n }\n }\n\n return result;\n}\n\n/* -------------------- BoundedMap -------------------- */\n\n/**\n * Size-bounded Map that evicts the oldest entry (insertion order) when the cap is reached.\n * Used by I18n's chain cache to prevent unbounded growth in long-lived SSR singletons when\n * locale tags are derived from arbitrary user input (e.g. Accept-Language headers).\n */\nexport class BoundedMap<K, V> extends Map<K, V> {\n readonly #cap: number;\n\n constructor(cap: number) {\n super();\n this.#cap = cap;\n }\n\n override set(key: K, value: V): this {\n if (!this.has(key) && this.size >= this.#cap) {\n this.delete(this.keys().next().value as K);\n }\n\n return super.set(key, value);\n }\n}\n"],"mappings":";AAQA,SAAgB,EAAY,GAA8B,GAAuB;AAE/E,KAAI,KAAQ,EAAK,QAAO,EAAI;CAE5B,IAAM,IAAQ,EAAK,MAAM,aAAa,IAAI,EAAE,EACxC,IAAiB;AAErB,MAAK,IAAM,KAAQ,GAAO;AACxB,MAAqB,OAAO,KAAU,aAAlC,EAA4C;AAEhD,MAAS,EAAkC;;AAG7C,QAAO;;AAKT,IAAa,IAAe,IAAI,IAAY;CAAC;CAAQ;CAAO;CAAO;CAAO;CAAQ;CAAQ,CAAC;AAE3F,SAAgB,EAAe,GAAuC;AACpE,KAAI,OAAO,KAAU,SAAU,QAAO;AAEtC,KAAI,OAAO,KAAU,aAAY,KAAkB,MAAM,QAAQ,EAAM,CAAE,QAAO;CAEhF,IAAM,IAAM;AAEZ,KAAI,EAAE,WAAW,GAAM,QAAO;CAE9B,IAAM,IAAO,OAAO,KAAK,EAAI;AAI7B,QAFI,EAAK,SAAS,EAAa,OAAa,KAErC,EAAK,OAAO,MAAM,EAAa,IAAI,EAAE,CAAC,IAAI,OAAO,OAAO,EAAI,CAAC,OAAO,MAAM,OAAO,KAAM,SAAS;;AAKzG,SAAgB,EAAU,GAAkB,GAA4B;CACtE,IAAM,IAAS,EAAE,GAAG,GAAQ;AAE5B,MAAK,IAAM,CAAC,GAAK,MAAQ,OAAO,QAAQ,EAAO,EAAE;EAC/C,IAAM,IAAW,EAAO;AAExB,EAAI,CAAC,EAAe,EAAI,IAAI,CAAC,EAAe,EAAS,IAAI,OAAO,KAAa,YAAY,IACvF,EAAO,KAAO,EAAU,GAAsB,EAAgB,GAG9D,EAAO,KAAO,OAAO,KAAQ,YAAY,IAAgB,EAAE,GAAI,GAAgB,GAAoB;;AAIvG,QAAO;;AAUT,IAAa,IAAb,cAAsC,IAAU;CAC9C;CAEA,YAAY,GAAa;AAEvB,EADA,OAAO,EACP,MAAA,IAAY;;CAGd,IAAa,GAAQ,GAAgB;AAKnC,SAJI,CAAC,KAAK,IAAI,EAAI,IAAI,KAAK,QAAQ,MAAA,KACjC,KAAK,OAAO,KAAK,MAAM,CAAC,MAAM,CAAC,MAAW,EAGrC,MAAM,IAAI,GAAK,EAAM"}
|
package/dist/i18n.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require(`./core.cjs`),t=require(`./helpers.cjs`),n=require(`./intl.cjs`),r=require(`./interpolate.cjs`);var i=class{#e;#t;#n=new Map;#r=new Map;#i=new Map;#a=new Set;#o=new t.BoundedMap(128);#s;#c;#l=null;#u=null;#d=!1;#f=0;#p=null;#m;#h=n.makeIntlCaches();#g;constructor({fallback:r,loaders:i,locale:a=`en`,messages:o,onDiagnostic:s,onMissing:c}={}){if(this.#e=a,this.#t=Array.isArray(r)?r:r?[r]:[],this.#s=c,this.#c=s,o)for(let[e,t]of Object.entries(o))this.#n.set(e,structuredClone(t));if(i)for(let[e,t]of Object.entries(i))this.#r.set(e,t);this.#m={checkOwn:(e,n)=>{let r=this.#n.get(n);if(!r)return!1;let i=t.resolvePath(r,e);return i!==void 0&&t.isMessageValue(i)},findMessage:(e,t)=>this.#b(e,t),formatDate:(e,t,r)=>n.formatDate(this.#h,e,t,r),formatList:(e,t,r)=>n.formatList(this.#h,e,t,r),formatNumber:(e,t,r)=>n.formatNumber(this.#h,e,t,r),formatRelative:(e,t,r,i)=>n.formatRelative(this.#h,e,t,r,i),getLocale:()=>this.#e,translate:(e,t,n)=>this.#S(e,t,n)},this.#g=new e.BoundView(this.#m,null)}get locale(){return this.#e}get locales(){return this.#l??=[...this.#n.keys()],this.#l}set locale(e){this.#e!==e&&(this.#e=e,this.#y(`locale-change`))}async setLocale(e){e!==this.#e&&(await this.load(e),this.locale=e)}add(e,n){let r=this.#n.get(e)??{};this.#n.set(e,t.deepMerge(r,n)),this.#l=null,this.#x(this.#e).includes(e)&&this.#y(`catalog-update`)}replace(e,t){this.#n.set(e,structuredClone(t)),this.#l=null,this.#x(this.#e).includes(e)&&this.#y(`catalog-update`)}has(e){return this.#g.has(e)}hasOwn(e){return this.#g.hasOwn(e)}hasLocale(e){return this.#n.has(e)}async load(...e){await Promise.all(e.map(e=>this.#C(e)))}async reload(e){this.#r.has(e)&&(this.#n.delete(e),this.#l=null,await this.#C(e))}registerLoader(e,t){this.#r.set(e,t),this.#u=null}get loadableLocales(){return this.#u??=[...this.#r.keys()],this.#u}t(e,t){return this.#g.t(e,t)}number(e,t){return this.#g.number(e,t)}date(e,t){return this.#g.date(e,t)}list(e,t=`and`){return this.#g.list(e,t)}relative(e,t,n){return this.#g.relative(e,t,n)}currency(e,t,n){return this.#g.currency(e,t,n)}withLocale(e){return this.#g.withLocale(e)}scope(e){return this.#g.scope(e)}batch(e){this.#f++;try{e()}finally{if(this.#f--,this.#f===0&&this.#p!==null){let e=this.#p;this.#p=null,this.#y(e)}}}subscribe(e,t){if(this.#a.add(e),t)try{e({locale:this.#e,reason:`locale-change`})}catch(e){this.#_(e)}return()=>this.#a.delete(e)}dispose(){this.#d=!0,this.#a.clear(),this.#n.clear(),this.#r.clear(),this.#i.clear(),this.#o.clear(),this.#l=null,this.#u=null}[Symbol.dispose](){this.dispose()}async[Symbol.asyncDispose](){await Promise.allSettled([...this.#i.values()]),this.dispose()}#_(e){this.#c?this.#c({error:e,kind:`subscriber-error`}):console.error(`[i18nit] Subscriber threw:`,e)}#v(e,t){this.#c?this.#c({error:e,kind:`loader-error`,locale:t}):console.warn(`[i18nit] Loader error:`,e)}#y(e){if(this.#f>0){this.#p!==`locale-change`&&(this.#p=e);return}let t={locale:this.#e,reason:e};for(let e of this.#a)try{e(t)}catch(e){this.#_(e)}}#b(e,n){for(let r of this.#x(n)){let n=this.#n.get(r);if(!n)continue;let i=t.resolvePath(n,e);if(i!==void 0&&t.isMessageValue(i))return i}}#x(e){let t=this.#o.get(e);if(t)return t;let n=new Set,r=e=>{n.add(e);let t=e.split(`-`);for(let e=t.length-1;e>0;e--)n.add(t.slice(0,e).join(`-`))};r(e);for(let e of this.#t)r(e);let i=[...n];return this.#o.set(e,i),i}#S(e,t,i){let a=this.#b(e,i);if(a===void 0)return this.#s?.(e,i)??e;if(typeof a==`string`)return r.interpolate(a,t??{},i,this.#h);let o=t??{},s=Number(o.count??0);return r.interpolate(a[s===0&&a.zero!==void 0?`zero`:n.getPluralForm(this.#h,i,s)]??a.other,o,i,this.#h)}#C(e){if(this.#i.has(e))return this.#i.get(e);if(this.#n.has(e))return Promise.resolve();let t=this.#r.get(e);if(!t)return Promise.resolve();let n=(async()=>{try{let n=await t(e);this.#d||this.replace(e,n)}catch(t){throw this.#v(t,e),t}finally{this.#i.delete(e)}})();return this.#i.set(e,n),n}};function a(e){return new i(e)}exports.I18n=i,exports.createI18n=a;
|
|
2
|
+
//# sourceMappingURL=i18n.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.cjs","names":["#caches","#view","#locale","#fallbacks","#onMissing","#onDiagnostic","#catalogs","#loaders","#core","#findMessage","#translate","#localesCache","#notify","#getLocaleChain","#loadOne","#loadersCache","#batchDepth","#pendingNotify","#subscribers","#diagnoseSubscriber","#disposed","#loading","#chainCache","#diagnoseLoader"],"sources":["../src/i18n.ts"],"sourcesContent":["import type {\n BoundI18n,\n DiagnosticEvent,\n I18nOptions,\n Loader,\n Locale,\n LocaleChangeEvent,\n LocaleChangeReason,\n MessageValue,\n Messages,\n NamespaceKeys,\n TranslationKeyParam,\n Unsubscribe,\n Vars,\n} from './types';\n\nimport { BoundView, type I18nCore } from './core';\nimport { BoundedMap, deepMerge, isMessageValue, resolvePath } from './helpers';\nimport { interpolate } from './interpolate';\nimport {\n type IntlCaches,\n formatDate,\n formatList,\n formatNumber,\n formatRelative,\n getPluralForm,\n makeIntlCaches,\n} from './intl';\n\nexport class I18n<T extends Messages = Messages> implements BoundI18n<T> {\n #locale: Locale;\n #fallbacks: Locale[];\n #catalogs = new Map<Locale, Messages>();\n #loaders = new Map<Locale, Loader>();\n #loading = new Map<Locale, Promise<void>>();\n #subscribers = new Set<(event: LocaleChangeEvent) => void>();\n /** Bounded at 128 entries — prevents unbounded growth when locale tags come from user input. */\n #chainCache = new BoundedMap<Locale, Locale[]>(128);\n #onMissing?: (key: string, locale: Locale) => string | undefined;\n #onDiagnostic?: (event: DiagnosticEvent) => void;\n #localesCache: Locale[] | null = null;\n #loadersCache: Locale[] | null = null;\n #disposed = false;\n #batchDepth = 0;\n #pendingNotify: LocaleChangeReason | null = null;\n #core: I18nCore;\n\n // Instance-scoped Intl caches — GC'd with the instance (important for SSR with many locales).\n readonly #caches: IntlCaches = makeIntlCaches();\n\n /** Internal BoundView — I18n delegates its BoundI18n surface here to avoid duplicating every method. */\n readonly #view: BoundView<T>;\n\n constructor({ fallback, loaders, locale = 'en', messages, onDiagnostic, onMissing }: I18nOptions<T> = {}) {\n this.#locale = locale;\n this.#fallbacks = Array.isArray(fallback) ? fallback : fallback ? [fallback] : [];\n this.#onMissing = onMissing;\n this.#onDiagnostic = onDiagnostic;\n\n if (messages) {\n for (const [l, m] of Object.entries(messages)) {\n // Deep-clone at init so external mutations to the source object can't corrupt the catalog.\n this.#catalogs.set(l, structuredClone(m) as Messages);\n }\n }\n\n if (loaders) for (const [l, fn] of Object.entries(loaders)) this.#loaders.set(l, fn);\n\n this.#core = {\n checkOwn: (key: string, locale: Locale) => {\n const catalog = this.#catalogs.get(locale);\n\n if (!catalog) return false;\n\n const value = resolvePath(catalog, key);\n\n return value !== undefined && isMessageValue(value);\n },\n findMessage: (key: string, locale: Locale) => this.#findMessage(key, locale),\n formatDate: (value, options, locale) => formatDate(this.#caches, value, options, locale),\n formatList: (items, locale, type) => formatList(this.#caches, items, locale, type),\n formatNumber: (value, options, locale) => formatNumber(this.#caches, value, options, locale),\n formatRelative: (value, unit, options, locale) => formatRelative(this.#caches, value, unit, options, locale),\n getLocale: () => this.#locale,\n translate: (key, vars, locale) => this.#translate(key, vars, locale),\n };\n\n this.#view = new BoundView<T>(this.#core, null);\n }\n\n /* -------------------- Locale -------------------- */\n\n get locale(): Locale {\n return this.#locale;\n }\n\n get locales(): Locale[] {\n this.#localesCache ??= [...this.#catalogs.keys()];\n\n return this.#localesCache;\n }\n\n set locale(value: Locale) {\n if (this.#locale === value) return;\n\n if (import.meta.env?.DEV && !this.#catalogs.has(value) && this.#loaders.has(value)) {\n console.warn(\n `[i18nit] locale \"${value}\" has a registered loader but is not loaded. ` +\n 'Use setLocale() to load and switch atomically.',\n );\n }\n\n this.#locale = value;\n this.#notify('locale-change');\n }\n\n async setLocale(locale: Locale): Promise<void> {\n if (locale === this.#locale) return;\n\n await this.load(locale);\n this.locale = locale;\n }\n\n /* -------------------- Message Management -------------------- */\n\n /** Deep-merges messages into an existing locale catalog. */\n add(locale: Locale, messages: Messages): void {\n const existing = this.#catalogs.get(locale) ?? {};\n\n this.#catalogs.set(locale, deepMerge(existing, messages));\n this.#localesCache = null;\n\n if (this.#getLocaleChain(this.#locale).includes(locale)) this.#notify('catalog-update');\n }\n\n /** Replaces the entire locale catalog for `locale` with a deep clone of `messages`. */\n replace(locale: Locale, messages: Messages): void {\n this.#catalogs.set(locale, structuredClone(messages));\n this.#localesCache = null;\n\n if (this.#getLocaleChain(this.#locale).includes(locale)) this.#notify('catalog-update');\n }\n\n has(key: string): boolean {\n return this.#view.has(key);\n }\n\n /** Like `has()`, but only checks the exact locale without walking the fallback chain. */\n hasOwn(key: string): boolean {\n return this.#view.hasOwn(key);\n }\n\n hasLocale(locale: Locale): boolean {\n return this.#catalogs.has(locale);\n }\n\n /* -------------------- Async Loaders -------------------- */\n\n async load(...locales: Locale[]): Promise<void> {\n await Promise.all(locales.map((locale) => this.#loadOne(locale)));\n }\n\n /**\n * Force-reloads a locale catalog even if already populated. Useful for hot-reload and forced bundle refresh.\n * No-op (with a dev warning) when no loader is registered for the locale, to prevent silently clearing the catalog.\n */\n async reload(locale: Locale): Promise<void> {\n if (!this.#loaders.has(locale)) {\n if (import.meta.env?.DEV) {\n console.warn(`[i18nit] reload(\"${locale}\") skipped — no loader registered for this locale.`);\n }\n\n return;\n }\n\n this.#catalogs.delete(locale);\n this.#localesCache = null;\n await this.#loadOne(locale);\n }\n\n registerLoader(locale: Locale, loader: Loader): void {\n this.#loaders.set(locale, loader);\n this.#loadersCache = null;\n }\n\n /** Returns the locale keys for which a loader has been registered. */\n get loadableLocales(): Locale[] {\n this.#loadersCache ??= [...this.#loaders.keys()];\n\n return this.#loadersCache;\n }\n\n /* -------------------- BoundI18n surface (delegated to #view) -------------------- */\n\n /**\n * Translates a key with optional interpolation variables.\n * Locale must be loaded first via `load()` or provided via `messages` in config.\n * For a per-call locale override use `withLocale(locale).t(key, vars)`.\n */\n t(key: TranslationKeyParam<T>, vars?: Vars): string {\n return this.#view.t(key, vars);\n }\n\n number(value: number, options?: Intl.NumberFormatOptions): string {\n return this.#view.number(value, options);\n }\n\n date(value: Date | number, options?: Intl.DateTimeFormatOptions): string {\n return this.#view.date(value, options);\n }\n\n list(items: unknown[], type: 'and' | 'or' = 'and'): string {\n return this.#view.list(items, type);\n }\n\n relative(value: number, unit: Intl.RelativeTimeFormatUnit, options?: Intl.RelativeTimeFormatOptions): string {\n return this.#view.relative(value, unit, options);\n }\n\n currency(value: number, currency: string, options?: Omit<Intl.NumberFormatOptions, 'style' | 'currency'>): string {\n return this.#view.currency(value, currency, options);\n }\n\n /**\n * Returns a bound interface that translates in the given locale without\n * changing the active locale on the instance. Useful for SSR and\n * multi-locale rendering in a single pass.\n */\n withLocale(locale: Locale): BoundI18n<T> {\n return this.#view.withLocale(locale);\n }\n\n /**\n * Returns a translator scoped to a key namespace prefix. Reacts to locale changes on the\n * instance. When `T` is a concrete message type, the returned `BoundI18n` is narrowed to\n * the subtree type so `t()` autocomplete works within the scope.\n * Only keys whose values are nested message objects are valid scope targets.\n */\n scope<K extends NamespaceKeys<T>>(ns: K): BoundI18n<T[K] & Messages> {\n return this.#view.scope(ns);\n }\n\n /* -------------------- Subscriptions -------------------- */\n\n /**\n * Executes `fn` while deferring subscriber notifications. A single notification fires\n * after `fn` completes, collapsing any number of `add()` / `replace()` calls made within.\n * Nested `batch()` calls are supported; notification fires when the outermost batch exits.\n * If both a locale change and a catalog update are triggered, `'locale-change'` takes priority.\n *\n * @remarks\n * `batch()` is synchronous. Async operations (e.g. `load()`) started inside `fn` complete\n * after the batch exits and will notify subscribers individually. To batch-load multiple\n * locales and notify once, await `load()` before entering the batch:\n * ```ts\n * await i18n.load('fr', 'de');\n * i18n.batch(() => { i18n.locale = 'fr'; });\n * ```\n */\n batch(fn: () => void): void {\n this.#batchDepth++;\n\n try {\n fn();\n } finally {\n this.#batchDepth--;\n\n if (this.#batchDepth === 0 && this.#pendingNotify !== null) {\n const reason = this.#pendingNotify;\n\n this.#pendingNotify = null;\n this.#notify(reason);\n }\n }\n }\n\n subscribe(listener: (event: LocaleChangeEvent) => void, immediate?: boolean): Unsubscribe {\n this.#subscribers.add(listener);\n\n if (immediate) {\n try {\n listener({ locale: this.#locale, reason: 'locale-change' });\n } catch (err) {\n this.#diagnoseSubscriber(err);\n }\n }\n\n return () => this.#subscribers.delete(listener);\n }\n\n /** Releases all resources held by this instance. */\n dispose(): void {\n this.#disposed = true;\n this.#subscribers.clear();\n this.#catalogs.clear();\n this.#loaders.clear();\n this.#loading.clear();\n this.#chainCache.clear();\n this.#localesCache = null;\n this.#loadersCache = null;\n }\n\n /** Enables `using i18n = createI18n(...)` for deterministic resource release. */\n [Symbol.dispose](): void {\n this.dispose();\n }\n\n /**\n * Awaits any in-flight `load()` calls and then releases all resources.\n * Enables `await using i18n = createI18n(...)` in environments that support `Symbol.asyncDispose`.\n */\n async [Symbol.asyncDispose](): Promise<void> {\n await Promise.allSettled([...this.#loading.values()]);\n this.dispose();\n }\n\n /* -------------------- Private -------------------- */\n\n #diagnoseSubscriber(error: unknown): void {\n if (this.#onDiagnostic) {\n this.#onDiagnostic({ error, kind: 'subscriber-error' });\n } else {\n console.error('[i18nit] Subscriber threw:', error);\n }\n }\n\n #diagnoseLoader(error: unknown, locale: Locale): void {\n if (this.#onDiagnostic) {\n this.#onDiagnostic({ error, kind: 'loader-error', locale });\n } else {\n console.warn('[i18nit] Loader error:', error);\n }\n }\n\n #notify(reason: LocaleChangeReason): void {\n if (this.#batchDepth > 0) {\n // 'locale-change' takes priority over 'catalog-update' if both occur in one batch\n if (this.#pendingNotify !== 'locale-change') this.#pendingNotify = reason;\n\n return;\n }\n\n const event: LocaleChangeEvent = { locale: this.#locale, reason };\n\n for (const listener of this.#subscribers) {\n try {\n listener(event);\n } catch (err) {\n this.#diagnoseSubscriber(err);\n }\n }\n }\n\n #findMessage(key: string, locale: Locale): MessageValue | undefined {\n for (const loc of this.#getLocaleChain(locale)) {\n const messages = this.#catalogs.get(loc);\n\n if (!messages) continue;\n\n const value = resolvePath(messages, key);\n\n if (value !== undefined && isMessageValue(value)) return value;\n }\n\n return undefined;\n }\n\n #getLocaleChain(locale: Locale): Locale[] {\n const cached = this.#chainCache.get(locale);\n\n if (cached) return cached;\n\n const seen = new Set<Locale>();\n const push = (l: Locale) => {\n seen.add(l);\n\n const parts = l.split('-');\n\n for (let i = parts.length - 1; i > 0; i--) {\n seen.add(parts.slice(0, i).join('-'));\n }\n };\n\n push(locale);\n for (const fallback of this.#fallbacks) push(fallback);\n\n const chain = [...seen];\n\n this.#chainCache.set(locale, chain);\n\n return chain;\n }\n\n #translate(key: string, vars: Vars | undefined, locale: Locale): string {\n const message = this.#findMessage(key, locale);\n\n if (message === undefined) return this.#onMissing?.(key, locale) ?? key;\n\n if (typeof message === 'string') return interpolate(message, vars ?? {}, locale, this.#caches);\n\n const v = vars ?? {};\n\n if (import.meta.env?.DEV && v.count === undefined) {\n console.warn(`[i18nit] Key \"${key}\" is a plural message but vars.count is missing. Defaulting to 0.`);\n }\n\n const count = Number(v.count ?? 0);\n const form = count === 0 && message.zero !== undefined ? 'zero' : getPluralForm(this.#caches, locale, count);\n\n return interpolate(message[form] ?? message.other, v, locale, this.#caches);\n }\n\n #loadOne(locale: Locale): Promise<void> {\n if (this.#loading.has(locale)) return this.#loading.get(locale)!;\n\n if (this.#catalogs.has(locale)) return Promise.resolve();\n\n const loader = this.#loaders.get(locale);\n\n if (!loader) return Promise.resolve();\n\n const promise = (async () => {\n try {\n const messages = await loader(locale);\n\n // Use replace() so the loader result is the authoritative catalog for this locale,\n // not merged on top of any pre-seeded static messages.\n if (!this.#disposed) this.replace(locale, messages);\n } catch (error) {\n this.#diagnoseLoader(error, locale);\n throw error;\n } finally {\n this.#loading.delete(locale);\n }\n })();\n\n this.#loading.set(locale, promise);\n\n return promise;\n }\n}\n\nexport function createI18n<T extends Messages = Messages>(config?: I18nOptions<T>): I18n<T> {\n return new I18n<T>(config);\n}\n"],"mappings":"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"}
|
package/dist/i18n.d.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { BoundI18n, I18nOptions, Loader, Locale, LocaleChangeEvent, Messages, NamespaceKeys, TranslationKeyParam, Unsubscribe, Vars } from './types';
|
|
2
|
+
export declare class I18n<T extends Messages = Messages> implements BoundI18n<T> {
|
|
3
|
+
#private;
|
|
4
|
+
constructor({ fallback, loaders, locale, messages, onDiagnostic, onMissing }?: I18nOptions<T>);
|
|
5
|
+
get locale(): Locale;
|
|
6
|
+
get locales(): Locale[];
|
|
7
|
+
set locale(value: Locale);
|
|
8
|
+
setLocale(locale: Locale): Promise<void>;
|
|
9
|
+
/** Deep-merges messages into an existing locale catalog. */
|
|
10
|
+
add(locale: Locale, messages: Messages): void;
|
|
11
|
+
/** Replaces the entire locale catalog for `locale` with a deep clone of `messages`. */
|
|
12
|
+
replace(locale: Locale, messages: Messages): void;
|
|
13
|
+
has(key: string): boolean;
|
|
14
|
+
/** Like `has()`, but only checks the exact locale without walking the fallback chain. */
|
|
15
|
+
hasOwn(key: string): boolean;
|
|
16
|
+
hasLocale(locale: Locale): boolean;
|
|
17
|
+
load(...locales: Locale[]): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Force-reloads a locale catalog even if already populated. Useful for hot-reload and forced bundle refresh.
|
|
20
|
+
* No-op (with a dev warning) when no loader is registered for the locale, to prevent silently clearing the catalog.
|
|
21
|
+
*/
|
|
22
|
+
reload(locale: Locale): Promise<void>;
|
|
23
|
+
registerLoader(locale: Locale, loader: Loader): void;
|
|
24
|
+
/** Returns the locale keys for which a loader has been registered. */
|
|
25
|
+
get loadableLocales(): Locale[];
|
|
26
|
+
/**
|
|
27
|
+
* Translates a key with optional interpolation variables.
|
|
28
|
+
* Locale must be loaded first via `load()` or provided via `messages` in config.
|
|
29
|
+
* For a per-call locale override use `withLocale(locale).t(key, vars)`.
|
|
30
|
+
*/
|
|
31
|
+
t(key: TranslationKeyParam<T>, vars?: Vars): string;
|
|
32
|
+
number(value: number, options?: Intl.NumberFormatOptions): string;
|
|
33
|
+
date(value: Date | number, options?: Intl.DateTimeFormatOptions): string;
|
|
34
|
+
list(items: unknown[], type?: 'and' | 'or'): string;
|
|
35
|
+
relative(value: number, unit: Intl.RelativeTimeFormatUnit, options?: Intl.RelativeTimeFormatOptions): string;
|
|
36
|
+
currency(value: number, currency: string, options?: Omit<Intl.NumberFormatOptions, 'style' | 'currency'>): string;
|
|
37
|
+
/**
|
|
38
|
+
* Returns a bound interface that translates in the given locale without
|
|
39
|
+
* changing the active locale on the instance. Useful for SSR and
|
|
40
|
+
* multi-locale rendering in a single pass.
|
|
41
|
+
*/
|
|
42
|
+
withLocale(locale: Locale): BoundI18n<T>;
|
|
43
|
+
/**
|
|
44
|
+
* Returns a translator scoped to a key namespace prefix. Reacts to locale changes on the
|
|
45
|
+
* instance. When `T` is a concrete message type, the returned `BoundI18n` is narrowed to
|
|
46
|
+
* the subtree type so `t()` autocomplete works within the scope.
|
|
47
|
+
* Only keys whose values are nested message objects are valid scope targets.
|
|
48
|
+
*/
|
|
49
|
+
scope<K extends NamespaceKeys<T>>(ns: K): BoundI18n<T[K] & Messages>;
|
|
50
|
+
/**
|
|
51
|
+
* Executes `fn` while deferring subscriber notifications. A single notification fires
|
|
52
|
+
* after `fn` completes, collapsing any number of `add()` / `replace()` calls made within.
|
|
53
|
+
* Nested `batch()` calls are supported; notification fires when the outermost batch exits.
|
|
54
|
+
* If both a locale change and a catalog update are triggered, `'locale-change'` takes priority.
|
|
55
|
+
*
|
|
56
|
+
* @remarks
|
|
57
|
+
* `batch()` is synchronous. Async operations (e.g. `load()`) started inside `fn` complete
|
|
58
|
+
* after the batch exits and will notify subscribers individually. To batch-load multiple
|
|
59
|
+
* locales and notify once, await `load()` before entering the batch:
|
|
60
|
+
* ```ts
|
|
61
|
+
* await i18n.load('fr', 'de');
|
|
62
|
+
* i18n.batch(() => { i18n.locale = 'fr'; });
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
batch(fn: () => void): void;
|
|
66
|
+
subscribe(listener: (event: LocaleChangeEvent) => void, immediate?: boolean): Unsubscribe;
|
|
67
|
+
/** Releases all resources held by this instance. */
|
|
68
|
+
dispose(): void;
|
|
69
|
+
/** Enables `using i18n = createI18n(...)` for deterministic resource release. */
|
|
70
|
+
[Symbol.dispose](): void;
|
|
71
|
+
/**
|
|
72
|
+
* Awaits any in-flight `load()` calls and then releases all resources.
|
|
73
|
+
* Enables `await using i18n = createI18n(...)` in environments that support `Symbol.asyncDispose`.
|
|
74
|
+
*/
|
|
75
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
76
|
+
}
|
|
77
|
+
export declare function createI18n<T extends Messages = Messages>(config?: I18nOptions<T>): I18n<T>;
|
|
78
|
+
//# sourceMappingURL=i18n.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"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"}
|
package/dist/i18n.js
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { BoundView as e } from "./core.js";
|
|
2
|
+
import { BoundedMap as t, deepMerge as n, isMessageValue as r, resolvePath as i } from "./helpers.js";
|
|
3
|
+
import { formatDate as a, formatList as o, formatNumber as s, formatRelative as c, getPluralForm as l, makeIntlCaches as u } from "./intl.js";
|
|
4
|
+
import { interpolate as d } from "./interpolate.js";
|
|
5
|
+
//#region src/i18n.ts
|
|
6
|
+
var f = class {
|
|
7
|
+
#e;
|
|
8
|
+
#t;
|
|
9
|
+
#n = /* @__PURE__ */ new Map();
|
|
10
|
+
#r = /* @__PURE__ */ new Map();
|
|
11
|
+
#i = /* @__PURE__ */ new Map();
|
|
12
|
+
#a = /* @__PURE__ */ new Set();
|
|
13
|
+
#o = new t(128);
|
|
14
|
+
#s;
|
|
15
|
+
#c;
|
|
16
|
+
#l = null;
|
|
17
|
+
#u = null;
|
|
18
|
+
#d = !1;
|
|
19
|
+
#f = 0;
|
|
20
|
+
#p = null;
|
|
21
|
+
#m;
|
|
22
|
+
#h = u();
|
|
23
|
+
#g;
|
|
24
|
+
constructor({ fallback: t, loaders: n, locale: l = "en", messages: u, onDiagnostic: d, onMissing: f } = {}) {
|
|
25
|
+
if (this.#e = l, this.#t = Array.isArray(t) ? t : t ? [t] : [], this.#s = f, this.#c = d, u) for (let [e, t] of Object.entries(u)) this.#n.set(e, structuredClone(t));
|
|
26
|
+
if (n) for (let [e, t] of Object.entries(n)) this.#r.set(e, t);
|
|
27
|
+
this.#m = {
|
|
28
|
+
checkOwn: (e, t) => {
|
|
29
|
+
let n = this.#n.get(t);
|
|
30
|
+
if (!n) return !1;
|
|
31
|
+
let a = i(n, e);
|
|
32
|
+
return a !== void 0 && r(a);
|
|
33
|
+
},
|
|
34
|
+
findMessage: (e, t) => this.#b(e, t),
|
|
35
|
+
formatDate: (e, t, n) => a(this.#h, e, t, n),
|
|
36
|
+
formatList: (e, t, n) => o(this.#h, e, t, n),
|
|
37
|
+
formatNumber: (e, t, n) => s(this.#h, e, t, n),
|
|
38
|
+
formatRelative: (e, t, n, r) => c(this.#h, e, t, n, r),
|
|
39
|
+
getLocale: () => this.#e,
|
|
40
|
+
translate: (e, t, n) => this.#S(e, t, n)
|
|
41
|
+
}, this.#g = new e(this.#m, null);
|
|
42
|
+
}
|
|
43
|
+
get locale() {
|
|
44
|
+
return this.#e;
|
|
45
|
+
}
|
|
46
|
+
get locales() {
|
|
47
|
+
return this.#l ??= [...this.#n.keys()], this.#l;
|
|
48
|
+
}
|
|
49
|
+
set locale(e) {
|
|
50
|
+
this.#e !== e && (this.#e = e, this.#y("locale-change"));
|
|
51
|
+
}
|
|
52
|
+
async setLocale(e) {
|
|
53
|
+
e !== this.#e && (await this.load(e), this.locale = e);
|
|
54
|
+
}
|
|
55
|
+
add(e, t) {
|
|
56
|
+
let r = this.#n.get(e) ?? {};
|
|
57
|
+
this.#n.set(e, n(r, t)), this.#l = null, this.#x(this.#e).includes(e) && this.#y("catalog-update");
|
|
58
|
+
}
|
|
59
|
+
replace(e, t) {
|
|
60
|
+
this.#n.set(e, structuredClone(t)), this.#l = null, this.#x(this.#e).includes(e) && this.#y("catalog-update");
|
|
61
|
+
}
|
|
62
|
+
has(e) {
|
|
63
|
+
return this.#g.has(e);
|
|
64
|
+
}
|
|
65
|
+
hasOwn(e) {
|
|
66
|
+
return this.#g.hasOwn(e);
|
|
67
|
+
}
|
|
68
|
+
hasLocale(e) {
|
|
69
|
+
return this.#n.has(e);
|
|
70
|
+
}
|
|
71
|
+
async load(...e) {
|
|
72
|
+
await Promise.all(e.map((e) => this.#C(e)));
|
|
73
|
+
}
|
|
74
|
+
async reload(e) {
|
|
75
|
+
this.#r.has(e) && (this.#n.delete(e), this.#l = null, await this.#C(e));
|
|
76
|
+
}
|
|
77
|
+
registerLoader(e, t) {
|
|
78
|
+
this.#r.set(e, t), this.#u = null;
|
|
79
|
+
}
|
|
80
|
+
get loadableLocales() {
|
|
81
|
+
return this.#u ??= [...this.#r.keys()], this.#u;
|
|
82
|
+
}
|
|
83
|
+
t(e, t) {
|
|
84
|
+
return this.#g.t(e, t);
|
|
85
|
+
}
|
|
86
|
+
number(e, t) {
|
|
87
|
+
return this.#g.number(e, t);
|
|
88
|
+
}
|
|
89
|
+
date(e, t) {
|
|
90
|
+
return this.#g.date(e, t);
|
|
91
|
+
}
|
|
92
|
+
list(e, t = "and") {
|
|
93
|
+
return this.#g.list(e, t);
|
|
94
|
+
}
|
|
95
|
+
relative(e, t, n) {
|
|
96
|
+
return this.#g.relative(e, t, n);
|
|
97
|
+
}
|
|
98
|
+
currency(e, t, n) {
|
|
99
|
+
return this.#g.currency(e, t, n);
|
|
100
|
+
}
|
|
101
|
+
withLocale(e) {
|
|
102
|
+
return this.#g.withLocale(e);
|
|
103
|
+
}
|
|
104
|
+
scope(e) {
|
|
105
|
+
return this.#g.scope(e);
|
|
106
|
+
}
|
|
107
|
+
batch(e) {
|
|
108
|
+
this.#f++;
|
|
109
|
+
try {
|
|
110
|
+
e();
|
|
111
|
+
} finally {
|
|
112
|
+
if (this.#f--, this.#f === 0 && this.#p !== null) {
|
|
113
|
+
let e = this.#p;
|
|
114
|
+
this.#p = null, this.#y(e);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
subscribe(e, t) {
|
|
119
|
+
if (this.#a.add(e), t) try {
|
|
120
|
+
e({
|
|
121
|
+
locale: this.#e,
|
|
122
|
+
reason: "locale-change"
|
|
123
|
+
});
|
|
124
|
+
} catch (e) {
|
|
125
|
+
this.#_(e);
|
|
126
|
+
}
|
|
127
|
+
return () => this.#a.delete(e);
|
|
128
|
+
}
|
|
129
|
+
dispose() {
|
|
130
|
+
this.#d = !0, this.#a.clear(), this.#n.clear(), this.#r.clear(), this.#i.clear(), this.#o.clear(), this.#l = null, this.#u = null;
|
|
131
|
+
}
|
|
132
|
+
[Symbol.dispose]() {
|
|
133
|
+
this.dispose();
|
|
134
|
+
}
|
|
135
|
+
async [Symbol.asyncDispose]() {
|
|
136
|
+
await Promise.allSettled([...this.#i.values()]), this.dispose();
|
|
137
|
+
}
|
|
138
|
+
#_(e) {
|
|
139
|
+
this.#c ? this.#c({
|
|
140
|
+
error: e,
|
|
141
|
+
kind: "subscriber-error"
|
|
142
|
+
}) : console.error("[i18nit] Subscriber threw:", e);
|
|
143
|
+
}
|
|
144
|
+
#v(e, t) {
|
|
145
|
+
this.#c ? this.#c({
|
|
146
|
+
error: e,
|
|
147
|
+
kind: "loader-error",
|
|
148
|
+
locale: t
|
|
149
|
+
}) : console.warn("[i18nit] Loader error:", e);
|
|
150
|
+
}
|
|
151
|
+
#y(e) {
|
|
152
|
+
if (this.#f > 0) {
|
|
153
|
+
this.#p !== "locale-change" && (this.#p = e);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
let t = {
|
|
157
|
+
locale: this.#e,
|
|
158
|
+
reason: e
|
|
159
|
+
};
|
|
160
|
+
for (let e of this.#a) try {
|
|
161
|
+
e(t);
|
|
162
|
+
} catch (e) {
|
|
163
|
+
this.#_(e);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
#b(e, t) {
|
|
167
|
+
for (let n of this.#x(t)) {
|
|
168
|
+
let t = this.#n.get(n);
|
|
169
|
+
if (!t) continue;
|
|
170
|
+
let a = i(t, e);
|
|
171
|
+
if (a !== void 0 && r(a)) return a;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
#x(e) {
|
|
175
|
+
let t = this.#o.get(e);
|
|
176
|
+
if (t) return t;
|
|
177
|
+
let n = /* @__PURE__ */ new Set(), r = (e) => {
|
|
178
|
+
n.add(e);
|
|
179
|
+
let t = e.split("-");
|
|
180
|
+
for (let e = t.length - 1; e > 0; e--) n.add(t.slice(0, e).join("-"));
|
|
181
|
+
};
|
|
182
|
+
r(e);
|
|
183
|
+
for (let e of this.#t) r(e);
|
|
184
|
+
let i = [...n];
|
|
185
|
+
return this.#o.set(e, i), i;
|
|
186
|
+
}
|
|
187
|
+
#S(e, t, n) {
|
|
188
|
+
let r = this.#b(e, n);
|
|
189
|
+
if (r === void 0) return this.#s?.(e, n) ?? e;
|
|
190
|
+
if (typeof r == "string") return d(r, t ?? {}, n, this.#h);
|
|
191
|
+
let i = t ?? {}, a = Number(i.count ?? 0);
|
|
192
|
+
return d(r[a === 0 && r.zero !== void 0 ? "zero" : l(this.#h, n, a)] ?? r.other, i, n, this.#h);
|
|
193
|
+
}
|
|
194
|
+
#C(e) {
|
|
195
|
+
if (this.#i.has(e)) return this.#i.get(e);
|
|
196
|
+
if (this.#n.has(e)) return Promise.resolve();
|
|
197
|
+
let t = this.#r.get(e);
|
|
198
|
+
if (!t) return Promise.resolve();
|
|
199
|
+
let n = (async () => {
|
|
200
|
+
try {
|
|
201
|
+
let n = await t(e);
|
|
202
|
+
this.#d || this.replace(e, n);
|
|
203
|
+
} catch (t) {
|
|
204
|
+
throw this.#v(t, e), t;
|
|
205
|
+
} finally {
|
|
206
|
+
this.#i.delete(e);
|
|
207
|
+
}
|
|
208
|
+
})();
|
|
209
|
+
return this.#i.set(e, n), n;
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
function p(e) {
|
|
213
|
+
return new f(e);
|
|
214
|
+
}
|
|
215
|
+
//#endregion
|
|
216
|
+
export { f as I18n, p as createI18n };
|
|
217
|
+
|
|
218
|
+
//# sourceMappingURL=i18n.js.map
|