@vielzeug/i18nit 2.1.0 → 3.0.3
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 +145 -51
- package/dist/format.d.ts +54 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/i18n.cjs +1 -1
- package/dist/i18n.cjs.map +1 -1
- package/dist/i18n.d.ts +4 -2
- package/dist/i18n.d.ts.map +1 -1
- package/dist/i18n.js +156 -165
- package/dist/i18n.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/types.d.ts +62 -103
- package/dist/types.d.ts.map +1 -1
- package/package.json +11 -12
- package/dist/helpers.cjs +0 -2
- package/dist/helpers.cjs.map +0 -1
- package/dist/helpers.d.ts +0 -20
- package/dist/helpers.d.ts.map +0 -1
- package/dist/helpers.js +0 -47
- package/dist/helpers.js.map +0 -1
- package/dist/i18nit.cjs +0 -2
- package/dist/i18nit.cjs.map +0 -1
- package/dist/i18nit.js +0 -2
- package/dist/i18nit.js.map +0 -1
- package/dist/interpolate.cjs +0 -2
- package/dist/interpolate.cjs.map +0 -1
- package/dist/interpolate.d.ts +0 -11
- package/dist/interpolate.d.ts.map +0 -1
- package/dist/interpolate.js +0 -13
- package/dist/interpolate.js.map +0 -1
- package/dist/intl.cjs +0 -2
- package/dist/intl.cjs.map +0 -1
- package/dist/intl.d.ts +0 -16
- package/dist/intl.d.ts.map +0 -1
- package/dist/intl.js +0 -65
- package/dist/intl.js.map +0 -1
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vielzeug/i18nit",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -15,16 +15,15 @@
|
|
|
15
15
|
"import": "./dist/index.js",
|
|
16
16
|
"require": "./dist/index.cjs"
|
|
17
17
|
},
|
|
18
|
-
"./
|
|
19
|
-
"source": "./src/
|
|
20
|
-
"types": "./dist/
|
|
21
|
-
"import": "./dist/
|
|
22
|
-
"require": "./dist/
|
|
18
|
+
"./format": {
|
|
19
|
+
"source": "./src/format.ts",
|
|
20
|
+
"types": "./dist/format.d.ts",
|
|
21
|
+
"import": "./dist/format.js",
|
|
22
|
+
"require": "./dist/format.cjs"
|
|
23
23
|
}
|
|
24
24
|
},
|
|
25
25
|
"scripts": {
|
|
26
|
-
"build": "vite build && pnpm run build:
|
|
27
|
-
"build:core": "vite build --config vite.bundle.config.ts",
|
|
26
|
+
"build": "vite build && pnpm run build:types",
|
|
28
27
|
"build:types": "tsc -p tsconfig.declarations.json",
|
|
29
28
|
"fix": "eslint --fix src",
|
|
30
29
|
"lint": "eslint src",
|
|
@@ -37,9 +36,9 @@
|
|
|
37
36
|
"registry": "https://registry.npmjs.org/"
|
|
38
37
|
},
|
|
39
38
|
"devDependencies": {
|
|
40
|
-
"@types/node": "^25.
|
|
41
|
-
"typescript": "~6.0.
|
|
42
|
-
"vite": "^8.0.
|
|
43
|
-
"vitest": "^4.1.
|
|
39
|
+
"@types/node": "^25.8.0",
|
|
40
|
+
"typescript": "~6.0.3",
|
|
41
|
+
"vite": "^8.0.13",
|
|
42
|
+
"vitest": "^4.1.6"
|
|
44
43
|
}
|
|
45
44
|
}
|
package/dist/helpers.cjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
function e(e,t){if(Object.hasOwn(e,t))return e[t];let n=t.match(/[^.[\]]+/gu)??[],r=e;for(let e of n){if(typeof r!=`object`||!r||!Object.hasOwn(r,e))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
|
package/dist/helpers.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
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 (Object.hasOwn(obj, path)) 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 if (!Object.hasOwn(value as object, part)) 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,OAAO,OAAO,EAAK,EAAK,CAAE,OAAO,EAAI,GAEzC,IAAM,EAAQ,EAAK,MAAM,aAAa,EAAI,EAAE,CACxC,EAAiB,EAErB,IAAK,IAAM,KAAQ,EAAO,CAGxB,GAFqB,OAAO,GAAU,WAAlC,GAEA,CAAC,OAAO,OAAO,EAAiB,EAAK,CAAE,OAE3C,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"}
|
package/dist/helpers.d.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
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
|
package/dist/helpers.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
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,CAgB/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
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
//#region src/helpers.ts
|
|
2
|
-
function e(e, t) {
|
|
3
|
-
if (Object.hasOwn(e, t)) return e[t];
|
|
4
|
-
let n = t.match(/[^.[\]]+/gu) ?? [], r = e;
|
|
5
|
-
for (let e of n) {
|
|
6
|
-
if (typeof r != "object" || !r || !Object.hasOwn(r, e)) 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
|
package/dist/helpers.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
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 (Object.hasOwn(obj, path)) 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 if (!Object.hasOwn(value as object, part)) 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,OAAO,OAAO,GAAK,EAAK,CAAE,QAAO,EAAI;CAEzC,IAAM,IAAQ,EAAK,MAAM,aAAa,IAAI,EAAE,EACxC,IAAiB;AAErB,MAAK,IAAM,KAAQ,GAAO;AAGxB,MAFqB,OAAO,KAAU,aAAlC,KAEA,CAAC,OAAO,OAAO,GAAiB,EAAK,CAAE;AAE3C,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/i18nit.cjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(e,t){if(Object.hasOwn(e,t))return e[t];let n=t.match(/[^.[\]]+/gu)??[],r=e;for(let e of n){if(typeof r!=`object`||!r||!Object.hasOwn(r,e))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)}};function a(){return{dateFormat:new Map,listFormat:new Map,numberFormat:new Map,pluralRules:new Map,relativeTimeFormat:new Map}}function o(e,t,n){let r=e.get(t);return r||(r=n(),e.set(t,r)),r}function s(e,t){return t?`${e}:${JSON.stringify(t,Object.keys(t).sort())}`:e}function c(e,t,n,r){let i=s(r,n);try{return o(e.numberFormat,i,()=>new Intl.NumberFormat(r,n)).format(t)}catch{return String(t)}}function l(e,t,n,r){let i=typeof t==`number`?new Date(t):t,a=s(r,n);try{return o(e.dateFormat,a,()=>new Intl.DateTimeFormat(r,n)).format(i)}catch{return i.toString()}}function u(e,t,n,r,i){let a=s(i,r);try{return o(e.relativeTimeFormat,a,()=>new Intl.RelativeTimeFormat(i,r)).format(t,n)}catch{return String(t)}}function d(e,t,n,r){if(t.length===0)return``;let i=t.map(String),a=r===`and`?`conjunction`:`disjunction`;try{return o(e.listFormat,`${n}:${a}`,()=>new Intl.ListFormat(n,{style:`long`,type:a})).format(i)}catch{return i.length===1?i[0]:i.length===2?`${i[0]} ${r} ${i[1]}`:`${i.slice(0,-1).join(`, `)} ${r} ${i.at(-1)}`}}function f(e,t,n){let r=Math.floor(Math.abs(n));try{return o(e.pluralRules,t,()=>new Intl.PluralRules(t)).select(r)}catch{return r===1?`one`:`other`}}function p(e,t,n,r){return t==null?``:Array.isArray(t)?n===`and`?d(e,t,r,`and`):n===`or`?d(e,t,r,`or`):n===void 0?t.map(String).join(`, `):t.map(String).join(n):typeof t==`number`?c(e,t,void 0,r):String(t)}function m(t,n,r,i){return t.includes(`{`)?t.replace(/\{([\p{ID_Continue}\-.[\]]+)(?:\|([^}]+))?\}/gu,(t,a,o)=>p(i,e(n,a),o,r)):t}function h(t={}){let o=t.locale??`en`,s=t.switchMode??`strict`,p=Array.isArray(t.fallback)?t.fallback:t.fallback?[t.fallback]:[],h=new Map,g=new Map,_=new Map,v=new Set,y=new i(128),b=a(),x=null,S=null,C=!1,w=0,T=null,E=t.onMissing,D=t.onDiagnostic;if(t.messages)for(let[e,n]of Object.entries(t.messages))h.set(e,structuredClone(n));if(t.loaders)for(let[e,n]of Object.entries(t.loaders))g.set(e,n);function O(e){D?D({error:e,kind:`subscriber-error`}):console.error(`[i18nit] Subscriber threw:`,e)}function k(e,t){D?D({error:e,kind:`loader-error`,locale:t}):console.warn(`[i18nit] Loader error:`,e)}function A(e){if(w>0){T!==`locale-change`&&(T=e);return}let t={locale:o,reason:e};for(let e of v)try{e(t)}catch(e){O(e)}}function j(e){let t=y.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 p)r(e);let i=[...n];return y.set(e,i),i}function M(t,r){let i=h.get(r);if(!i)return!1;let a=e(i,t);return a!==void 0&&n(a)}function N(t,r){for(let i of j(r)){let r=h.get(i);if(!r)continue;let a=e(r,t);if(a!==void 0&&n(a))return a}}function P(e,t,n){let r=N(e,n);if(r===void 0)return E?.(e,n)??e;if(typeof r==`string`)return m(r,t??{},n,b);let i=t??{},a=Number(i.count??0);return m(r[a===0&&r.zero!==void 0?`zero`:f(b,n,a)]??r.other,i,n,b)}function F(e,t){if(_.has(e))return _.get(e);if(h.has(e))return Promise.resolve();let n=g.get(e);if(!n)return t===`strict`?Promise.reject(Error(`[i18nit] Missing loader for locale "${e}".`)):Promise.resolve();let r=(async()=>{try{let t=await n(e);C||R.replace(e,t)}catch(t){throw k(t,e),t}finally{_.delete(e)}})();return _.set(e,r),r}function I(e,t){let n=()=>e??o,r=e=>t?`${t}.${e}`:e;return{currency(e,t,r){return c(b,e,{...r,currency:t,style:`currency`},n())},date(e,t){return l(b,e,t,n())},has(e){return N(r(e),n())!==void 0},hasOwn(e){return M(r(e),n())},list(e,t=`and`){return d(b,e,n(),t)},get locale(){return n()},number(e,t){return c(b,e,t,n())},relative(e,t,r){return u(b,e,t,r,n())},scope(n){return I(e,t?`${t}.${String(n)}`:String(n))},t:(e,t)=>P(r(e),t,n()),withLocale(e){return I(e,t)}}}let L=I(null),R=Object.create(L);return R.add=(e,t)=>{let n=h.get(e)??{};h.set(e,r(n,t)),x=null,j(o).includes(e)&&A(`catalog-update`)},R.batch=e=>{w++;try{e()}finally{if(w--,w===0&&T!==null){let e=T;T=null,A(e)}}},R.dispose=()=>{C=!0,v.clear(),h.clear(),g.clear(),_.clear(),y.clear(),x=null,S=null},R.ensureLocale=async(e,t=s)=>{await F(e,t)},R.hasLocale=e=>h.has(e),R.isReady=e=>h.has(e),Object.defineProperties(R,{loadableLocales:{get(){return S??=[...g.keys()],S}},locales:{get(){return x??=[...h.keys()],x}}}),R.registerLoader=(e,t)=>{g.set(e,t),S=null},R.reload=async e=>{if(!g.has(e))throw Error(`[i18nit] Cannot reload locale "${e}" without a registered loader.`);h.delete(e),x=null,await F(e,`strict`)},R.replace=(e,t)=>{h.set(e,structuredClone(t)),x=null,j(o).includes(e)&&A(`catalog-update`)},R.subscribe=(e,t)=>{if(v.add(e),t)try{e({locale:o,reason:`locale-change`})}catch(e){O(e)}return()=>v.delete(e)},R.switchLocale=async(e,t=s)=>{e!==o&&(await F(e,t),o=e,A(`locale-change`))},R[Symbol.asyncDispose]=async()=>{await Promise.allSettled([..._.values()]),R.dispose()},R[Symbol.dispose]=()=>{R.dispose()},R}exports.createI18n=h;
|
|
2
|
-
//# sourceMappingURL=i18nit.cjs.map
|
package/dist/i18nit.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"i18nit.cjs","names":["#cap"],"sources":["../src/helpers.ts","../src/intl.ts","../src/interpolate.ts","../src/i18n.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 (Object.hasOwn(obj, path)) 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 if (!Object.hasOwn(value as object, part)) 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","import type { Locale, PluralForm } from './types';\n\n/* -------------------- Cache Container -------------------- */\n\n/** Holds all Intl formatter caches for one I18n instance — GC'd with the instance. */\nexport type IntlCaches = {\n dateFormat: Map<string, Intl.DateTimeFormat>;\n listFormat: Map<string, Intl.ListFormat>;\n numberFormat: Map<string, Intl.NumberFormat>;\n pluralRules: Map<string, Intl.PluralRules>;\n relativeTimeFormat: Map<string, Intl.RelativeTimeFormat>;\n};\n\nexport function makeIntlCaches(): IntlCaches {\n return {\n dateFormat: new Map(),\n listFormat: new Map(),\n numberFormat: new Map(),\n pluralRules: new Map(),\n relativeTimeFormat: new Map(),\n };\n}\n\n/* -------------------- Cache Helpers -------------------- */\n\nfunction intlFmt<F extends object>(cache: Map<string, F>, key: string, build: () => F): F {\n let fmt = cache.get(key);\n\n if (!fmt) {\n fmt = build();\n cache.set(key, fmt);\n }\n\n return fmt;\n}\n\n/**\n * Builds a stable string key for an Intl formatter cache.\n * Call this once per formatter construction path — not on every format call — so key\n * serialization cost is paid only on cache misses.\n */\nfunction intlKey(locale: string, options?: object): string {\n return options ? `${locale}:${JSON.stringify(options, Object.keys(options).sort())}` : locale;\n}\n\n/* -------------------- Format Functions -------------------- */\n\nexport function formatNumber(\n caches: IntlCaches,\n value: number,\n options: Intl.NumberFormatOptions | undefined,\n locale: Locale,\n): string {\n const key = intlKey(locale, options);\n\n try {\n return intlFmt(caches.numberFormat, key, () => new Intl.NumberFormat(locale, options)).format(value);\n } catch {\n return String(value);\n }\n}\n\nexport function formatDate(\n caches: IntlCaches,\n value: Date | number,\n options: Intl.DateTimeFormatOptions | undefined,\n locale: Locale,\n): string {\n const d = typeof value === 'number' ? new Date(value) : value;\n const key = intlKey(locale, options);\n\n try {\n return intlFmt(caches.dateFormat, key, () => new Intl.DateTimeFormat(locale, options)).format(d);\n } catch {\n return d.toString();\n }\n}\n\nexport function formatRelative(\n caches: IntlCaches,\n value: number,\n unit: Intl.RelativeTimeFormatUnit,\n options: Intl.RelativeTimeFormatOptions | undefined,\n locale: Locale,\n): string {\n const key = intlKey(locale, options);\n\n try {\n return intlFmt(caches.relativeTimeFormat, key, () => new Intl.RelativeTimeFormat(locale, options)).format(\n value,\n unit,\n );\n } catch {\n return String(value);\n }\n}\n\nexport function formatList(caches: IntlCaches, items: unknown[], locale: string, type: 'and' | 'or'): string {\n if (items.length === 0) return '';\n\n const stringItems = items.map(String);\n const intlType = type === 'and' ? 'conjunction' : 'disjunction';\n\n try {\n return intlFmt(\n caches.listFormat,\n `${locale}:${intlType}`,\n () => new Intl.ListFormat(locale, { style: 'long', type: intlType }),\n ).format(stringItems);\n } catch {\n // Fallback for environments without Intl.ListFormat\n if (stringItems.length === 1) return stringItems[0];\n\n if (stringItems.length === 2) return `${stringItems[0]} ${type} ${stringItems[1]}`;\n\n return `${stringItems.slice(0, -1).join(', ')} ${type} ${stringItems.at(-1)}`;\n }\n}\n\nexport function getPluralForm(caches: IntlCaches, locale: Locale, count: number): PluralForm {\n const n = Math.floor(Math.abs(count));\n\n try {\n return intlFmt(caches.pluralRules, locale, () => new Intl.PluralRules(locale)).select(n) as PluralForm;\n } catch {\n return n === 1 ? 'one' : 'other';\n }\n}\n","import type { Vars } from './types';\n\nimport { resolvePath } from './helpers';\nimport { type IntlCaches, formatList, formatNumber } from './intl';\n\n/* -------------------- Token Resolution -------------------- */\n\nfunction resolveToken(caches: IntlCaches, value: unknown, separator: string | undefined, locale: string): string {\n if (value == null) return '';\n\n if (Array.isArray(value)) {\n if (separator === 'and') return formatList(caches, value, locale, 'and');\n\n if (separator === 'or') return formatList(caches, value, locale, 'or');\n\n if (separator !== undefined) return value.map(String).join(separator);\n\n return value.map(String).join(', ');\n }\n\n if (typeof value === 'number') {\n return formatNumber(caches, value, undefined, locale);\n }\n\n return String(value);\n}\n\n/* -------------------- Interpolation -------------------- */\n\n/**\n * Interpolates variables into a template string. Supports Unicode variable names\n * via `\\p{ID_Continue}` so non-ASCII identifiers like `{prénom}` or `{名前}` work correctly.\n *\n * Supported formats: `{name}` · `{user.name}` · `{items[0]}` · `{items}` ·\n * `{items|and}` · `{items|or}` · `{items| - }` · `{items.length}`\n */\nexport function interpolate(template: string, vars: Vars, locale: string, caches: IntlCaches): string {\n if (!template.includes('{')) return template;\n\n return template.replace(/\\{([\\p{ID_Continue}\\-.[\\]]+)(?:\\|([^}]+))?\\}/gu, (_match, key: string, separator?: string) =>\n resolveToken(caches, resolvePath(vars, key), separator, locale),\n );\n}\n","import type {\n BoundI18n,\n I18n,\n I18nOptions,\n Loader,\n Locale,\n LocaleChangeEvent,\n LocaleChangeReason,\n Messages,\n MessageValue,\n NamespaceKeys,\n SwitchMode,\n Unsubscribe,\n Vars,\n} from './types';\n\nimport { BoundedMap, deepMerge, isMessageValue, resolvePath } from './helpers';\nimport { interpolate } from './interpolate';\nimport {\n formatDate,\n formatList,\n formatNumber,\n formatRelative,\n getPluralForm,\n type IntlCaches,\n makeIntlCaches,\n} from './intl';\n\nexport function createI18n<T extends Messages = Messages>(config: I18nOptions<T> = {}): I18n<T> {\n let locale = config.locale ?? 'en';\n const defaultSwitchMode: SwitchMode = config.switchMode ?? 'strict';\n const fallbacks = Array.isArray(config.fallback) ? config.fallback : config.fallback ? [config.fallback] : [];\n const catalogs = new Map<Locale, Messages>();\n const loaders = new Map<Locale, Loader>();\n const loading = new Map<Locale, Promise<void>>();\n const subscribers = new Set<(event: LocaleChangeEvent) => void>();\n const chainCache = new BoundedMap<Locale, Locale[]>(128);\n const caches: IntlCaches = makeIntlCaches();\n\n let localesCache: Locale[] | null = null;\n let loadersCache: Locale[] | null = null;\n let disposed = false;\n let batchDepth = 0;\n let pendingNotify: LocaleChangeReason | null = null;\n\n const onMissing = config.onMissing;\n const onDiagnostic = config.onDiagnostic;\n\n if (config.messages) {\n for (const [loc, messages] of Object.entries(config.messages)) {\n catalogs.set(loc, structuredClone(messages) as Messages);\n }\n }\n\n if (config.loaders) {\n for (const [loc, loader] of Object.entries(config.loaders)) {\n loaders.set(loc, loader);\n }\n }\n\n function diagnoseSubscriber(error: unknown): void {\n if (onDiagnostic) {\n onDiagnostic({ error, kind: 'subscriber-error' });\n } else {\n console.error('[i18nit] Subscriber threw:', error);\n }\n }\n\n function diagnoseLoader(error: unknown, loc: Locale): void {\n if (onDiagnostic) {\n onDiagnostic({ error, kind: 'loader-error', locale: loc });\n } else {\n console.warn('[i18nit] Loader error:', error);\n }\n }\n\n function notify(reason: LocaleChangeReason): void {\n if (batchDepth > 0) {\n if (pendingNotify !== 'locale-change') pendingNotify = reason;\n\n return;\n }\n\n const event: LocaleChangeEvent = { locale, reason };\n\n for (const listener of subscribers) {\n try {\n listener(event);\n } catch (error) {\n diagnoseSubscriber(error);\n }\n }\n }\n\n function getLocaleChain(loc: Locale): Locale[] {\n const cached = chainCache.get(loc);\n\n if (cached) return cached;\n\n const seen = new Set<Locale>();\n\n const push = (value: Locale) => {\n seen.add(value);\n\n const parts = value.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(loc);\n for (const fallback of fallbacks) push(fallback);\n\n const chain = [...seen];\n\n chainCache.set(loc, chain);\n\n return chain;\n }\n\n function checkOwn(key: string, loc: Locale): boolean {\n const catalog = catalogs.get(loc);\n\n if (!catalog) return false;\n\n const value = resolvePath(catalog, key);\n\n return value !== undefined && isMessageValue(value);\n }\n\n function findMessage(key: string, loc: Locale): MessageValue | undefined {\n for (const localeInChain of getLocaleChain(loc)) {\n const messages = catalogs.get(localeInChain);\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 function translate(key: string, vars: Vars | undefined, loc: Locale): string {\n const message = findMessage(key, loc);\n\n if (message === undefined) return onMissing?.(key, loc) ?? key;\n\n if (typeof message === 'string') {\n return interpolate(message, vars ?? {}, loc, caches);\n }\n\n const context = vars ?? {};\n\n if (import.meta.env?.DEV && context.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(context.count ?? 0);\n const form = count === 0 && message.zero !== undefined ? 'zero' : getPluralForm(caches, loc, count);\n\n return interpolate(message[form] ?? message.other, context, loc, caches);\n }\n\n function loadOne(loc: Locale, mode: SwitchMode): Promise<void> {\n if (loading.has(loc)) return loading.get(loc)!;\n\n if (catalogs.has(loc)) return Promise.resolve();\n\n const loader = loaders.get(loc);\n\n if (!loader) {\n if (mode === 'strict') {\n return Promise.reject(new Error(`[i18nit] Missing loader for locale \"${loc}\".`));\n }\n\n return Promise.resolve();\n }\n\n const promise = (async () => {\n try {\n const messages = await loader(loc);\n\n if (!disposed) api.replace(loc, messages);\n } catch (error) {\n diagnoseLoader(error, loc);\n throw error;\n } finally {\n loading.delete(loc);\n }\n })();\n\n loading.set(loc, promise);\n\n return promise;\n }\n\n function createView<U extends Messages = Messages>(fixedLocale: Locale | null, prefix?: string): BoundI18n<U> {\n const activeLocale = (): Locale => fixedLocale ?? locale;\n const keyWithPrefix = (key: string): string => (prefix ? `${prefix}.${key}` : key);\n const t: BoundI18n<U>['t'] = (key: NamespaceKeys<U>, vars?: Record<string, unknown>) =>\n translate(keyWithPrefix(key as string), vars, activeLocale());\n\n const view = {\n currency(\n value: number,\n currency: string,\n options?: Omit<Intl.NumberFormatOptions, 'style' | 'currency'>,\n ): string {\n return formatNumber(caches, value, { ...options, currency, style: 'currency' }, activeLocale());\n },\n date(value: Date | number, options?: Intl.DateTimeFormatOptions): string {\n return formatDate(caches, value, options, activeLocale());\n },\n has(key: string): boolean {\n return findMessage(keyWithPrefix(key), activeLocale()) !== undefined;\n },\n hasOwn(key: string): boolean {\n return checkOwn(keyWithPrefix(key), activeLocale());\n },\n list(items: unknown[], type: 'and' | 'or' = 'and'): string {\n return formatList(caches, items, activeLocale(), type);\n },\n get locale(): Locale {\n return activeLocale();\n },\n number(value: number, options?: Intl.NumberFormatOptions): string {\n return formatNumber(caches, value, options, activeLocale());\n },\n relative(value: number, unit: Intl.RelativeTimeFormatUnit, options?: Intl.RelativeTimeFormatOptions): string {\n return formatRelative(caches, value, unit, options, activeLocale());\n },\n scope<K extends NamespaceKeys<U>>(ns: K): BoundI18n<U[K] & Messages> {\n const nextPrefix = prefix ? `${prefix}.${String(ns)}` : String(ns);\n\n return createView<U[K] & Messages>(fixedLocale, nextPrefix);\n },\n t,\n withLocale(nextLocale: Locale): BoundI18n<U> {\n return createView<U>(nextLocale, prefix);\n },\n } satisfies BoundI18n<U>;\n\n return view;\n }\n\n const rootView = createView<T>(null);\n\n const api = Object.create(rootView) as I18n<T>;\n\n api.add = (loc: Locale, messages: Messages): void => {\n const existing = catalogs.get(loc) ?? {};\n\n catalogs.set(loc, deepMerge(existing, messages));\n localesCache = null;\n\n if (getLocaleChain(locale).includes(loc)) notify('catalog-update');\n };\n\n api.batch = (fn: () => void): void => {\n batchDepth++;\n\n try {\n fn();\n } finally {\n batchDepth--;\n\n if (batchDepth === 0 && pendingNotify !== null) {\n const reason = pendingNotify;\n\n pendingNotify = null;\n notify(reason);\n }\n }\n };\n\n api.dispose = (): void => {\n disposed = true;\n subscribers.clear();\n catalogs.clear();\n loaders.clear();\n loading.clear();\n chainCache.clear();\n localesCache = null;\n loadersCache = null;\n };\n\n api.ensureLocale = async (loc: Locale, mode: SwitchMode = defaultSwitchMode): Promise<void> => {\n await loadOne(loc, mode);\n };\n\n api.hasLocale = (loc: Locale): boolean => catalogs.has(loc);\n api.isReady = (loc: Locale): boolean => catalogs.has(loc);\n\n Object.defineProperties(api, {\n loadableLocales: {\n get(): Locale[] {\n loadersCache ??= [...loaders.keys()];\n\n return loadersCache;\n },\n },\n locales: {\n get(): Locale[] {\n localesCache ??= [...catalogs.keys()];\n\n return localesCache;\n },\n },\n });\n\n api.registerLoader = (loc: Locale, loader: Loader): void => {\n loaders.set(loc, loader);\n loadersCache = null;\n };\n\n api.reload = async (loc: Locale): Promise<void> => {\n if (!loaders.has(loc)) {\n throw new Error(`[i18nit] Cannot reload locale \"${loc}\" without a registered loader.`);\n }\n\n catalogs.delete(loc);\n localesCache = null;\n await loadOne(loc, 'strict');\n };\n\n api.replace = (loc: Locale, messages: Messages): void => {\n catalogs.set(loc, structuredClone(messages));\n localesCache = null;\n\n if (getLocaleChain(locale).includes(loc)) notify('catalog-update');\n };\n\n api.subscribe = (listener: (event: LocaleChangeEvent) => void, immediate?: boolean): Unsubscribe => {\n subscribers.add(listener);\n\n if (immediate) {\n try {\n listener({ locale, reason: 'locale-change' });\n } catch (error) {\n diagnoseSubscriber(error);\n }\n }\n\n return () => subscribers.delete(listener);\n };\n\n api.switchLocale = async (nextLocale: Locale, mode: SwitchMode = defaultSwitchMode): Promise<void> => {\n if (nextLocale === locale) return;\n\n await loadOne(nextLocale, mode);\n locale = nextLocale;\n notify('locale-change');\n };\n\n api[Symbol.asyncDispose] = async (): Promise<void> => {\n await Promise.allSettled([...loading.values()]);\n api.dispose();\n };\n\n api[Symbol.dispose] = (): void => {\n api.dispose();\n };\n\n return api;\n}\n\nexport type { I18n };\n"],"mappings":"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"}
|
package/dist/i18nit.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
function e(e,t){if(Object.hasOwn(e,t))return e[t];let n=t.match(/[^.[\]]+/gu)??[],r=e;for(let e of n){if(typeof r!=`object`||!r||!Object.hasOwn(r,e))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)}};function a(){return{dateFormat:new Map,listFormat:new Map,numberFormat:new Map,pluralRules:new Map,relativeTimeFormat:new Map}}function o(e,t,n){let r=e.get(t);return r||(r=n(),e.set(t,r)),r}function s(e,t){return t?`${e}:${JSON.stringify(t,Object.keys(t).sort())}`:e}function c(e,t,n,r){let i=s(r,n);try{return o(e.numberFormat,i,()=>new Intl.NumberFormat(r,n)).format(t)}catch{return String(t)}}function l(e,t,n,r){let i=typeof t==`number`?new Date(t):t,a=s(r,n);try{return o(e.dateFormat,a,()=>new Intl.DateTimeFormat(r,n)).format(i)}catch{return i.toString()}}function u(e,t,n,r,i){let a=s(i,r);try{return o(e.relativeTimeFormat,a,()=>new Intl.RelativeTimeFormat(i,r)).format(t,n)}catch{return String(t)}}function d(e,t,n,r){if(t.length===0)return``;let i=t.map(String),a=r===`and`?`conjunction`:`disjunction`;try{return o(e.listFormat,`${n}:${a}`,()=>new Intl.ListFormat(n,{style:`long`,type:a})).format(i)}catch{return i.length===1?i[0]:i.length===2?`${i[0]} ${r} ${i[1]}`:`${i.slice(0,-1).join(`, `)} ${r} ${i.at(-1)}`}}function f(e,t,n){let r=Math.floor(Math.abs(n));try{return o(e.pluralRules,t,()=>new Intl.PluralRules(t)).select(r)}catch{return r===1?`one`:`other`}}function p(e,t,n,r){return t==null?``:Array.isArray(t)?n===`and`?d(e,t,r,`and`):n===`or`?d(e,t,r,`or`):n===void 0?t.map(String).join(`, `):t.map(String).join(n):typeof t==`number`?c(e,t,void 0,r):String(t)}function m(t,n,r,i){return t.includes(`{`)?t.replace(/\{([\p{ID_Continue}\-.[\]]+)(?:\|([^}]+))?\}/gu,(t,a,o)=>p(i,e(n,a),o,r)):t}function h(t={}){let o=t.locale??`en`,s=t.switchMode??`strict`,p=Array.isArray(t.fallback)?t.fallback:t.fallback?[t.fallback]:[],h=new Map,g=new Map,_=new Map,v=new Set,y=new i(128),b=a(),x=null,S=null,C=!1,w=0,T=null,E=t.onMissing,D=t.onDiagnostic;if(t.messages)for(let[e,n]of Object.entries(t.messages))h.set(e,structuredClone(n));if(t.loaders)for(let[e,n]of Object.entries(t.loaders))g.set(e,n);function O(e){D?D({error:e,kind:`subscriber-error`}):console.error(`[i18nit] Subscriber threw:`,e)}function k(e,t){D?D({error:e,kind:`loader-error`,locale:t}):console.warn(`[i18nit] Loader error:`,e)}function A(e){if(w>0){T!==`locale-change`&&(T=e);return}let t={locale:o,reason:e};for(let e of v)try{e(t)}catch(e){O(e)}}function j(e){let t=y.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 p)r(e);let i=[...n];return y.set(e,i),i}function M(t,r){let i=h.get(r);if(!i)return!1;let a=e(i,t);return a!==void 0&&n(a)}function N(t,r){for(let i of j(r)){let r=h.get(i);if(!r)continue;let a=e(r,t);if(a!==void 0&&n(a))return a}}function P(e,t,n){let r=N(e,n);if(r===void 0)return E?.(e,n)??e;if(typeof r==`string`)return m(r,t??{},n,b);let i=t??{},a=Number(i.count??0);return m(r[a===0&&r.zero!==void 0?`zero`:f(b,n,a)]??r.other,i,n,b)}function F(e,t){if(_.has(e))return _.get(e);if(h.has(e))return Promise.resolve();let n=g.get(e);if(!n)return t===`strict`?Promise.reject(Error(`[i18nit] Missing loader for locale "${e}".`)):Promise.resolve();let r=(async()=>{try{let t=await n(e);C||R.replace(e,t)}catch(t){throw k(t,e),t}finally{_.delete(e)}})();return _.set(e,r),r}function I(e,t){let n=()=>e??o,r=e=>t?`${t}.${e}`:e;return{currency(e,t,r){return c(b,e,{...r,currency:t,style:`currency`},n())},date(e,t){return l(b,e,t,n())},has(e){return N(r(e),n())!==void 0},hasOwn(e){return M(r(e),n())},list(e,t=`and`){return d(b,e,n(),t)},get locale(){return n()},number(e,t){return c(b,e,t,n())},relative(e,t,r){return u(b,e,t,r,n())},scope(n){return I(e,t?`${t}.${String(n)}`:String(n))},t:(e,t)=>P(r(e),t,n()),withLocale(e){return I(e,t)}}}let L=I(null),R=Object.create(L);return R.add=(e,t)=>{let n=h.get(e)??{};h.set(e,r(n,t)),x=null,j(o).includes(e)&&A(`catalog-update`)},R.batch=e=>{w++;try{e()}finally{if(w--,w===0&&T!==null){let e=T;T=null,A(e)}}},R.dispose=()=>{C=!0,v.clear(),h.clear(),g.clear(),_.clear(),y.clear(),x=null,S=null},R.ensureLocale=async(e,t=s)=>{await F(e,t)},R.hasLocale=e=>h.has(e),R.isReady=e=>h.has(e),Object.defineProperties(R,{loadableLocales:{get(){return S??=[...g.keys()],S}},locales:{get(){return x??=[...h.keys()],x}}}),R.registerLoader=(e,t)=>{g.set(e,t),S=null},R.reload=async e=>{if(!g.has(e))throw Error(`[i18nit] Cannot reload locale "${e}" without a registered loader.`);h.delete(e),x=null,await F(e,`strict`)},R.replace=(e,t)=>{h.set(e,structuredClone(t)),x=null,j(o).includes(e)&&A(`catalog-update`)},R.subscribe=(e,t)=>{if(v.add(e),t)try{e({locale:o,reason:`locale-change`})}catch(e){O(e)}return()=>v.delete(e)},R.switchLocale=async(e,t=s)=>{e!==o&&(await F(e,t),o=e,A(`locale-change`))},R[Symbol.asyncDispose]=async()=>{await Promise.allSettled([..._.values()]),R.dispose()},R[Symbol.dispose]=()=>{R.dispose()},R}export{h as createI18n};
|
|
2
|
-
//# sourceMappingURL=i18nit.js.map
|
package/dist/i18nit.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"i18nit.js","names":["#cap"],"sources":["../src/helpers.ts","../src/intl.ts","../src/interpolate.ts","../src/i18n.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 (Object.hasOwn(obj, path)) 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 if (!Object.hasOwn(value as object, part)) 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","import type { Locale, PluralForm } from './types';\n\n/* -------------------- Cache Container -------------------- */\n\n/** Holds all Intl formatter caches for one I18n instance — GC'd with the instance. */\nexport type IntlCaches = {\n dateFormat: Map<string, Intl.DateTimeFormat>;\n listFormat: Map<string, Intl.ListFormat>;\n numberFormat: Map<string, Intl.NumberFormat>;\n pluralRules: Map<string, Intl.PluralRules>;\n relativeTimeFormat: Map<string, Intl.RelativeTimeFormat>;\n};\n\nexport function makeIntlCaches(): IntlCaches {\n return {\n dateFormat: new Map(),\n listFormat: new Map(),\n numberFormat: new Map(),\n pluralRules: new Map(),\n relativeTimeFormat: new Map(),\n };\n}\n\n/* -------------------- Cache Helpers -------------------- */\n\nfunction intlFmt<F extends object>(cache: Map<string, F>, key: string, build: () => F): F {\n let fmt = cache.get(key);\n\n if (!fmt) {\n fmt = build();\n cache.set(key, fmt);\n }\n\n return fmt;\n}\n\n/**\n * Builds a stable string key for an Intl formatter cache.\n * Call this once per formatter construction path — not on every format call — so key\n * serialization cost is paid only on cache misses.\n */\nfunction intlKey(locale: string, options?: object): string {\n return options ? `${locale}:${JSON.stringify(options, Object.keys(options).sort())}` : locale;\n}\n\n/* -------------------- Format Functions -------------------- */\n\nexport function formatNumber(\n caches: IntlCaches,\n value: number,\n options: Intl.NumberFormatOptions | undefined,\n locale: Locale,\n): string {\n const key = intlKey(locale, options);\n\n try {\n return intlFmt(caches.numberFormat, key, () => new Intl.NumberFormat(locale, options)).format(value);\n } catch {\n return String(value);\n }\n}\n\nexport function formatDate(\n caches: IntlCaches,\n value: Date | number,\n options: Intl.DateTimeFormatOptions | undefined,\n locale: Locale,\n): string {\n const d = typeof value === 'number' ? new Date(value) : value;\n const key = intlKey(locale, options);\n\n try {\n return intlFmt(caches.dateFormat, key, () => new Intl.DateTimeFormat(locale, options)).format(d);\n } catch {\n return d.toString();\n }\n}\n\nexport function formatRelative(\n caches: IntlCaches,\n value: number,\n unit: Intl.RelativeTimeFormatUnit,\n options: Intl.RelativeTimeFormatOptions | undefined,\n locale: Locale,\n): string {\n const key = intlKey(locale, options);\n\n try {\n return intlFmt(caches.relativeTimeFormat, key, () => new Intl.RelativeTimeFormat(locale, options)).format(\n value,\n unit,\n );\n } catch {\n return String(value);\n }\n}\n\nexport function formatList(caches: IntlCaches, items: unknown[], locale: string, type: 'and' | 'or'): string {\n if (items.length === 0) return '';\n\n const stringItems = items.map(String);\n const intlType = type === 'and' ? 'conjunction' : 'disjunction';\n\n try {\n return intlFmt(\n caches.listFormat,\n `${locale}:${intlType}`,\n () => new Intl.ListFormat(locale, { style: 'long', type: intlType }),\n ).format(stringItems);\n } catch {\n // Fallback for environments without Intl.ListFormat\n if (stringItems.length === 1) return stringItems[0];\n\n if (stringItems.length === 2) return `${stringItems[0]} ${type} ${stringItems[1]}`;\n\n return `${stringItems.slice(0, -1).join(', ')} ${type} ${stringItems.at(-1)}`;\n }\n}\n\nexport function getPluralForm(caches: IntlCaches, locale: Locale, count: number): PluralForm {\n const n = Math.floor(Math.abs(count));\n\n try {\n return intlFmt(caches.pluralRules, locale, () => new Intl.PluralRules(locale)).select(n) as PluralForm;\n } catch {\n return n === 1 ? 'one' : 'other';\n }\n}\n","import type { Vars } from './types';\n\nimport { resolvePath } from './helpers';\nimport { type IntlCaches, formatList, formatNumber } from './intl';\n\n/* -------------------- Token Resolution -------------------- */\n\nfunction resolveToken(caches: IntlCaches, value: unknown, separator: string | undefined, locale: string): string {\n if (value == null) return '';\n\n if (Array.isArray(value)) {\n if (separator === 'and') return formatList(caches, value, locale, 'and');\n\n if (separator === 'or') return formatList(caches, value, locale, 'or');\n\n if (separator !== undefined) return value.map(String).join(separator);\n\n return value.map(String).join(', ');\n }\n\n if (typeof value === 'number') {\n return formatNumber(caches, value, undefined, locale);\n }\n\n return String(value);\n}\n\n/* -------------------- Interpolation -------------------- */\n\n/**\n * Interpolates variables into a template string. Supports Unicode variable names\n * via `\\p{ID_Continue}` so non-ASCII identifiers like `{prénom}` or `{名前}` work correctly.\n *\n * Supported formats: `{name}` · `{user.name}` · `{items[0]}` · `{items}` ·\n * `{items|and}` · `{items|or}` · `{items| - }` · `{items.length}`\n */\nexport function interpolate(template: string, vars: Vars, locale: string, caches: IntlCaches): string {\n if (!template.includes('{')) return template;\n\n return template.replace(/\\{([\\p{ID_Continue}\\-.[\\]]+)(?:\\|([^}]+))?\\}/gu, (_match, key: string, separator?: string) =>\n resolveToken(caches, resolvePath(vars, key), separator, locale),\n );\n}\n","import type {\n BoundI18n,\n I18n,\n I18nOptions,\n Loader,\n Locale,\n LocaleChangeEvent,\n LocaleChangeReason,\n Messages,\n MessageValue,\n NamespaceKeys,\n SwitchMode,\n Unsubscribe,\n Vars,\n} from './types';\n\nimport { BoundedMap, deepMerge, isMessageValue, resolvePath } from './helpers';\nimport { interpolate } from './interpolate';\nimport {\n formatDate,\n formatList,\n formatNumber,\n formatRelative,\n getPluralForm,\n type IntlCaches,\n makeIntlCaches,\n} from './intl';\n\nexport function createI18n<T extends Messages = Messages>(config: I18nOptions<T> = {}): I18n<T> {\n let locale = config.locale ?? 'en';\n const defaultSwitchMode: SwitchMode = config.switchMode ?? 'strict';\n const fallbacks = Array.isArray(config.fallback) ? config.fallback : config.fallback ? [config.fallback] : [];\n const catalogs = new Map<Locale, Messages>();\n const loaders = new Map<Locale, Loader>();\n const loading = new Map<Locale, Promise<void>>();\n const subscribers = new Set<(event: LocaleChangeEvent) => void>();\n const chainCache = new BoundedMap<Locale, Locale[]>(128);\n const caches: IntlCaches = makeIntlCaches();\n\n let localesCache: Locale[] | null = null;\n let loadersCache: Locale[] | null = null;\n let disposed = false;\n let batchDepth = 0;\n let pendingNotify: LocaleChangeReason | null = null;\n\n const onMissing = config.onMissing;\n const onDiagnostic = config.onDiagnostic;\n\n if (config.messages) {\n for (const [loc, messages] of Object.entries(config.messages)) {\n catalogs.set(loc, structuredClone(messages) as Messages);\n }\n }\n\n if (config.loaders) {\n for (const [loc, loader] of Object.entries(config.loaders)) {\n loaders.set(loc, loader);\n }\n }\n\n function diagnoseSubscriber(error: unknown): void {\n if (onDiagnostic) {\n onDiagnostic({ error, kind: 'subscriber-error' });\n } else {\n console.error('[i18nit] Subscriber threw:', error);\n }\n }\n\n function diagnoseLoader(error: unknown, loc: Locale): void {\n if (onDiagnostic) {\n onDiagnostic({ error, kind: 'loader-error', locale: loc });\n } else {\n console.warn('[i18nit] Loader error:', error);\n }\n }\n\n function notify(reason: LocaleChangeReason): void {\n if (batchDepth > 0) {\n if (pendingNotify !== 'locale-change') pendingNotify = reason;\n\n return;\n }\n\n const event: LocaleChangeEvent = { locale, reason };\n\n for (const listener of subscribers) {\n try {\n listener(event);\n } catch (error) {\n diagnoseSubscriber(error);\n }\n }\n }\n\n function getLocaleChain(loc: Locale): Locale[] {\n const cached = chainCache.get(loc);\n\n if (cached) return cached;\n\n const seen = new Set<Locale>();\n\n const push = (value: Locale) => {\n seen.add(value);\n\n const parts = value.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(loc);\n for (const fallback of fallbacks) push(fallback);\n\n const chain = [...seen];\n\n chainCache.set(loc, chain);\n\n return chain;\n }\n\n function checkOwn(key: string, loc: Locale): boolean {\n const catalog = catalogs.get(loc);\n\n if (!catalog) return false;\n\n const value = resolvePath(catalog, key);\n\n return value !== undefined && isMessageValue(value);\n }\n\n function findMessage(key: string, loc: Locale): MessageValue | undefined {\n for (const localeInChain of getLocaleChain(loc)) {\n const messages = catalogs.get(localeInChain);\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 function translate(key: string, vars: Vars | undefined, loc: Locale): string {\n const message = findMessage(key, loc);\n\n if (message === undefined) return onMissing?.(key, loc) ?? key;\n\n if (typeof message === 'string') {\n return interpolate(message, vars ?? {}, loc, caches);\n }\n\n const context = vars ?? {};\n\n if (import.meta.env?.DEV && context.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(context.count ?? 0);\n const form = count === 0 && message.zero !== undefined ? 'zero' : getPluralForm(caches, loc, count);\n\n return interpolate(message[form] ?? message.other, context, loc, caches);\n }\n\n function loadOne(loc: Locale, mode: SwitchMode): Promise<void> {\n if (loading.has(loc)) return loading.get(loc)!;\n\n if (catalogs.has(loc)) return Promise.resolve();\n\n const loader = loaders.get(loc);\n\n if (!loader) {\n if (mode === 'strict') {\n return Promise.reject(new Error(`[i18nit] Missing loader for locale \"${loc}\".`));\n }\n\n return Promise.resolve();\n }\n\n const promise = (async () => {\n try {\n const messages = await loader(loc);\n\n if (!disposed) api.replace(loc, messages);\n } catch (error) {\n diagnoseLoader(error, loc);\n throw error;\n } finally {\n loading.delete(loc);\n }\n })();\n\n loading.set(loc, promise);\n\n return promise;\n }\n\n function createView<U extends Messages = Messages>(fixedLocale: Locale | null, prefix?: string): BoundI18n<U> {\n const activeLocale = (): Locale => fixedLocale ?? locale;\n const keyWithPrefix = (key: string): string => (prefix ? `${prefix}.${key}` : key);\n const t: BoundI18n<U>['t'] = (key: NamespaceKeys<U>, vars?: Record<string, unknown>) =>\n translate(keyWithPrefix(key as string), vars, activeLocale());\n\n const view = {\n currency(\n value: number,\n currency: string,\n options?: Omit<Intl.NumberFormatOptions, 'style' | 'currency'>,\n ): string {\n return formatNumber(caches, value, { ...options, currency, style: 'currency' }, activeLocale());\n },\n date(value: Date | number, options?: Intl.DateTimeFormatOptions): string {\n return formatDate(caches, value, options, activeLocale());\n },\n has(key: string): boolean {\n return findMessage(keyWithPrefix(key), activeLocale()) !== undefined;\n },\n hasOwn(key: string): boolean {\n return checkOwn(keyWithPrefix(key), activeLocale());\n },\n list(items: unknown[], type: 'and' | 'or' = 'and'): string {\n return formatList(caches, items, activeLocale(), type);\n },\n get locale(): Locale {\n return activeLocale();\n },\n number(value: number, options?: Intl.NumberFormatOptions): string {\n return formatNumber(caches, value, options, activeLocale());\n },\n relative(value: number, unit: Intl.RelativeTimeFormatUnit, options?: Intl.RelativeTimeFormatOptions): string {\n return formatRelative(caches, value, unit, options, activeLocale());\n },\n scope<K extends NamespaceKeys<U>>(ns: K): BoundI18n<U[K] & Messages> {\n const nextPrefix = prefix ? `${prefix}.${String(ns)}` : String(ns);\n\n return createView<U[K] & Messages>(fixedLocale, nextPrefix);\n },\n t,\n withLocale(nextLocale: Locale): BoundI18n<U> {\n return createView<U>(nextLocale, prefix);\n },\n } satisfies BoundI18n<U>;\n\n return view;\n }\n\n const rootView = createView<T>(null);\n\n const api = Object.create(rootView) as I18n<T>;\n\n api.add = (loc: Locale, messages: Messages): void => {\n const existing = catalogs.get(loc) ?? {};\n\n catalogs.set(loc, deepMerge(existing, messages));\n localesCache = null;\n\n if (getLocaleChain(locale).includes(loc)) notify('catalog-update');\n };\n\n api.batch = (fn: () => void): void => {\n batchDepth++;\n\n try {\n fn();\n } finally {\n batchDepth--;\n\n if (batchDepth === 0 && pendingNotify !== null) {\n const reason = pendingNotify;\n\n pendingNotify = null;\n notify(reason);\n }\n }\n };\n\n api.dispose = (): void => {\n disposed = true;\n subscribers.clear();\n catalogs.clear();\n loaders.clear();\n loading.clear();\n chainCache.clear();\n localesCache = null;\n loadersCache = null;\n };\n\n api.ensureLocale = async (loc: Locale, mode: SwitchMode = defaultSwitchMode): Promise<void> => {\n await loadOne(loc, mode);\n };\n\n api.hasLocale = (loc: Locale): boolean => catalogs.has(loc);\n api.isReady = (loc: Locale): boolean => catalogs.has(loc);\n\n Object.defineProperties(api, {\n loadableLocales: {\n get(): Locale[] {\n loadersCache ??= [...loaders.keys()];\n\n return loadersCache;\n },\n },\n locales: {\n get(): Locale[] {\n localesCache ??= [...catalogs.keys()];\n\n return localesCache;\n },\n },\n });\n\n api.registerLoader = (loc: Locale, loader: Loader): void => {\n loaders.set(loc, loader);\n loadersCache = null;\n };\n\n api.reload = async (loc: Locale): Promise<void> => {\n if (!loaders.has(loc)) {\n throw new Error(`[i18nit] Cannot reload locale \"${loc}\" without a registered loader.`);\n }\n\n catalogs.delete(loc);\n localesCache = null;\n await loadOne(loc, 'strict');\n };\n\n api.replace = (loc: Locale, messages: Messages): void => {\n catalogs.set(loc, structuredClone(messages));\n localesCache = null;\n\n if (getLocaleChain(locale).includes(loc)) notify('catalog-update');\n };\n\n api.subscribe = (listener: (event: LocaleChangeEvent) => void, immediate?: boolean): Unsubscribe => {\n subscribers.add(listener);\n\n if (immediate) {\n try {\n listener({ locale, reason: 'locale-change' });\n } catch (error) {\n diagnoseSubscriber(error);\n }\n }\n\n return () => subscribers.delete(listener);\n };\n\n api.switchLocale = async (nextLocale: Locale, mode: SwitchMode = defaultSwitchMode): Promise<void> => {\n if (nextLocale === locale) return;\n\n await loadOne(nextLocale, mode);\n locale = nextLocale;\n notify('locale-change');\n };\n\n api[Symbol.asyncDispose] = async (): Promise<void> => {\n await Promise.allSettled([...loading.values()]);\n api.dispose();\n };\n\n api[Symbol.dispose] = (): void => {\n api.dispose();\n };\n\n return api;\n}\n\nexport type { I18n };\n"],"mappings":"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"}
|
package/dist/interpolate.cjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const e=require(`./helpers.cjs`),t=require(`./intl.cjs`);function n(e,n,r,i){return n==null?``:Array.isArray(n)?r===`and`?t.formatList(e,n,i,`and`):r===`or`?t.formatList(e,n,i,`or`):r===void 0?n.map(String).join(`, `):n.map(String).join(r):typeof n==`number`?t.formatNumber(e,n,void 0,i):String(n)}function r(t,r,i,a){return t.includes(`{`)?t.replace(/\{([\p{ID_Continue}\-.[\]]+)(?:\|([^}]+))?\}/gu,(t,o,s)=>n(a,e.resolvePath(r,o),s,i)):t}exports.interpolate=r;
|
|
2
|
-
//# sourceMappingURL=interpolate.cjs.map
|
package/dist/interpolate.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"interpolate.cjs","names":[],"sources":["../src/interpolate.ts"],"sourcesContent":["import type { Vars } from './types';\n\nimport { resolvePath } from './helpers';\nimport { type IntlCaches, formatList, formatNumber } from './intl';\n\n/* -------------------- Token Resolution -------------------- */\n\nfunction resolveToken(caches: IntlCaches, value: unknown, separator: string | undefined, locale: string): string {\n if (value == null) return '';\n\n if (Array.isArray(value)) {\n if (separator === 'and') return formatList(caches, value, locale, 'and');\n\n if (separator === 'or') return formatList(caches, value, locale, 'or');\n\n if (separator !== undefined) return value.map(String).join(separator);\n\n return value.map(String).join(', ');\n }\n\n if (typeof value === 'number') {\n return formatNumber(caches, value, undefined, locale);\n }\n\n return String(value);\n}\n\n/* -------------------- Interpolation -------------------- */\n\n/**\n * Interpolates variables into a template string. Supports Unicode variable names\n * via `\\p{ID_Continue}` so non-ASCII identifiers like `{prénom}` or `{名前}` work correctly.\n *\n * Supported formats: `{name}` · `{user.name}` · `{items[0]}` · `{items}` ·\n * `{items|and}` · `{items|or}` · `{items| - }` · `{items.length}`\n */\nexport function interpolate(template: string, vars: Vars, locale: string, caches: IntlCaches): string {\n if (!template.includes('{')) return template;\n\n return template.replace(/\\{([\\p{ID_Continue}\\-.[\\]]+)(?:\\|([^}]+))?\\}/gu, (_match, key: string, separator?: string) =>\n resolveToken(caches, resolvePath(vars, key), separator, locale),\n );\n}\n"],"mappings":"yDAOA,SAAS,EAAa,EAAoB,EAAgB,EAA+B,EAAwB,CAiB/G,OAhBI,GAAS,KAAa,GAEtB,MAAM,QAAQ,EAAM,CAClB,IAAc,MAAc,EAAA,WAAW,EAAQ,EAAO,EAAQ,MAAM,CAEpE,IAAc,KAAa,EAAA,WAAW,EAAQ,EAAO,EAAQ,KAAK,CAElE,IAAc,IAAA,GAEX,EAAM,IAAI,OAAO,CAAC,KAAK,KAAK,CAFC,EAAM,IAAI,OAAO,CAAC,KAAK,EAAU,CAKnE,OAAO,GAAU,SACZ,EAAA,aAAa,EAAQ,EAAO,IAAA,GAAW,EAAO,CAGhD,OAAO,EAAM,CAYtB,SAAgB,EAAY,EAAkB,EAAY,EAAgB,EAA4B,CAGpG,OAFK,EAAS,SAAS,IAAI,CAEpB,EAAS,QAAQ,kDAAmD,EAAQ,EAAa,IAC9F,EAAa,EAAQ,EAAA,YAAY,EAAM,EAAI,CAAE,EAAW,EAAO,CAChE,CAJmC"}
|
package/dist/interpolate.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { Vars } from './types';
|
|
2
|
-
import { type IntlCaches } from './intl';
|
|
3
|
-
/**
|
|
4
|
-
* Interpolates variables into a template string. Supports Unicode variable names
|
|
5
|
-
* via `\p{ID_Continue}` so non-ASCII identifiers like `{prénom}` or `{名前}` work correctly.
|
|
6
|
-
*
|
|
7
|
-
* Supported formats: `{name}` · `{user.name}` · `{items[0]}` · `{items}` ·
|
|
8
|
-
* `{items|and}` · `{items|or}` · `{items| - }` · `{items.length}`
|
|
9
|
-
*/
|
|
10
|
-
export declare function interpolate(template: string, vars: Vars, locale: string, caches: IntlCaches): string;
|
|
11
|
-
//# sourceMappingURL=interpolate.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"interpolate.d.ts","sourceRoot":"","sources":["../src/interpolate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAGpC,OAAO,EAAE,KAAK,UAAU,EAA4B,MAAM,QAAQ,CAAC;AA0BnE;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAMpG"}
|
package/dist/interpolate.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { resolvePath as e } from "./helpers.js";
|
|
2
|
-
import { formatList as t, formatNumber as n } from "./intl.js";
|
|
3
|
-
//#region src/interpolate.ts
|
|
4
|
-
function r(e, r, i, a) {
|
|
5
|
-
return r == null ? "" : Array.isArray(r) ? i === "and" ? t(e, r, a, "and") : i === "or" ? t(e, r, a, "or") : i === void 0 ? r.map(String).join(", ") : r.map(String).join(i) : typeof r == "number" ? n(e, r, void 0, a) : String(r);
|
|
6
|
-
}
|
|
7
|
-
function i(t, n, i, a) {
|
|
8
|
-
return t.includes("{") ? t.replace(/\{([\p{ID_Continue}\-.[\]]+)(?:\|([^}]+))?\}/gu, (t, o, s) => r(a, e(n, o), s, i)) : t;
|
|
9
|
-
}
|
|
10
|
-
//#endregion
|
|
11
|
-
export { i as interpolate };
|
|
12
|
-
|
|
13
|
-
//# sourceMappingURL=interpolate.js.map
|
package/dist/interpolate.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"interpolate.js","names":[],"sources":["../src/interpolate.ts"],"sourcesContent":["import type { Vars } from './types';\n\nimport { resolvePath } from './helpers';\nimport { type IntlCaches, formatList, formatNumber } from './intl';\n\n/* -------------------- Token Resolution -------------------- */\n\nfunction resolveToken(caches: IntlCaches, value: unknown, separator: string | undefined, locale: string): string {\n if (value == null) return '';\n\n if (Array.isArray(value)) {\n if (separator === 'and') return formatList(caches, value, locale, 'and');\n\n if (separator === 'or') return formatList(caches, value, locale, 'or');\n\n if (separator !== undefined) return value.map(String).join(separator);\n\n return value.map(String).join(', ');\n }\n\n if (typeof value === 'number') {\n return formatNumber(caches, value, undefined, locale);\n }\n\n return String(value);\n}\n\n/* -------------------- Interpolation -------------------- */\n\n/**\n * Interpolates variables into a template string. Supports Unicode variable names\n * via `\\p{ID_Continue}` so non-ASCII identifiers like `{prénom}` or `{名前}` work correctly.\n *\n * Supported formats: `{name}` · `{user.name}` · `{items[0]}` · `{items}` ·\n * `{items|and}` · `{items|or}` · `{items| - }` · `{items.length}`\n */\nexport function interpolate(template: string, vars: Vars, locale: string, caches: IntlCaches): string {\n if (!template.includes('{')) return template;\n\n return template.replace(/\\{([\\p{ID_Continue}\\-.[\\]]+)(?:\\|([^}]+))?\\}/gu, (_match, key: string, separator?: string) =>\n resolveToken(caches, resolvePath(vars, key), separator, locale),\n );\n}\n"],"mappings":";;;AAOA,SAAS,EAAa,GAAoB,GAAgB,GAA+B,GAAwB;AAiB/G,QAhBI,KAAS,OAAa,KAEtB,MAAM,QAAQ,EAAM,GAClB,MAAc,QAAc,EAAW,GAAQ,GAAO,GAAQ,MAAM,GAEpE,MAAc,OAAa,EAAW,GAAQ,GAAO,GAAQ,KAAK,GAElE,MAAc,KAAA,IAEX,EAAM,IAAI,OAAO,CAAC,KAAK,KAAK,GAFC,EAAM,IAAI,OAAO,CAAC,KAAK,EAAU,GAKnE,OAAO,KAAU,WACZ,EAAa,GAAQ,GAAO,KAAA,GAAW,EAAO,GAGhD,OAAO,EAAM;;AAYtB,SAAgB,EAAY,GAAkB,GAAY,GAAgB,GAA4B;AAGpG,QAFK,EAAS,SAAS,IAAI,GAEpB,EAAS,QAAQ,mDAAmD,GAAQ,GAAa,MAC9F,EAAa,GAAQ,EAAY,GAAM,EAAI,EAAE,GAAW,EAAO,CAChE,GAJmC"}
|
package/dist/intl.cjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
function e(){return{dateFormat:new Map,listFormat:new Map,numberFormat:new Map,pluralRules:new Map,relativeTimeFormat:new Map}}function t(e,t,n){let r=e.get(t);return r||(r=n(),e.set(t,r)),r}function n(e,t){return t?`${e}:${JSON.stringify(t,Object.keys(t).sort())}`:e}function r(e,r,i,a){let o=n(a,i);try{return t(e.numberFormat,o,()=>new Intl.NumberFormat(a,i)).format(r)}catch{return String(r)}}function i(e,r,i,a){let o=typeof r==`number`?new Date(r):r,s=n(a,i);try{return t(e.dateFormat,s,()=>new Intl.DateTimeFormat(a,i)).format(o)}catch{return o.toString()}}function a(e,r,i,a,o){let s=n(o,a);try{return t(e.relativeTimeFormat,s,()=>new Intl.RelativeTimeFormat(o,a)).format(r,i)}catch{return String(r)}}function o(e,n,r,i){if(n.length===0)return``;let a=n.map(String),o=i===`and`?`conjunction`:`disjunction`;try{return t(e.listFormat,`${r}:${o}`,()=>new Intl.ListFormat(r,{style:`long`,type:o})).format(a)}catch{return a.length===1?a[0]:a.length===2?`${a[0]} ${i} ${a[1]}`:`${a.slice(0,-1).join(`, `)} ${i} ${a.at(-1)}`}}function s(e,n,r){let i=Math.floor(Math.abs(r));try{return t(e.pluralRules,n,()=>new Intl.PluralRules(n)).select(i)}catch{return i===1?`one`:`other`}}exports.formatDate=i,exports.formatList=o,exports.formatNumber=r,exports.formatRelative=a,exports.getPluralForm=s,exports.makeIntlCaches=e;
|
|
2
|
-
//# sourceMappingURL=intl.cjs.map
|
package/dist/intl.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"intl.cjs","names":[],"sources":["../src/intl.ts"],"sourcesContent":["import type { Locale, PluralForm } from './types';\n\n/* -------------------- Cache Container -------------------- */\n\n/** Holds all Intl formatter caches for one I18n instance — GC'd with the instance. */\nexport type IntlCaches = {\n dateFormat: Map<string, Intl.DateTimeFormat>;\n listFormat: Map<string, Intl.ListFormat>;\n numberFormat: Map<string, Intl.NumberFormat>;\n pluralRules: Map<string, Intl.PluralRules>;\n relativeTimeFormat: Map<string, Intl.RelativeTimeFormat>;\n};\n\nexport function makeIntlCaches(): IntlCaches {\n return {\n dateFormat: new Map(),\n listFormat: new Map(),\n numberFormat: new Map(),\n pluralRules: new Map(),\n relativeTimeFormat: new Map(),\n };\n}\n\n/* -------------------- Cache Helpers -------------------- */\n\nfunction intlFmt<F extends object>(cache: Map<string, F>, key: string, build: () => F): F {\n let fmt = cache.get(key);\n\n if (!fmt) {\n fmt = build();\n cache.set(key, fmt);\n }\n\n return fmt;\n}\n\n/**\n * Builds a stable string key for an Intl formatter cache.\n * Call this once per formatter construction path — not on every format call — so key\n * serialization cost is paid only on cache misses.\n */\nfunction intlKey(locale: string, options?: object): string {\n return options ? `${locale}:${JSON.stringify(options, Object.keys(options).sort())}` : locale;\n}\n\n/* -------------------- Format Functions -------------------- */\n\nexport function formatNumber(\n caches: IntlCaches,\n value: number,\n options: Intl.NumberFormatOptions | undefined,\n locale: Locale,\n): string {\n const key = intlKey(locale, options);\n\n try {\n return intlFmt(caches.numberFormat, key, () => new Intl.NumberFormat(locale, options)).format(value);\n } catch {\n return String(value);\n }\n}\n\nexport function formatDate(\n caches: IntlCaches,\n value: Date | number,\n options: Intl.DateTimeFormatOptions | undefined,\n locale: Locale,\n): string {\n const d = typeof value === 'number' ? new Date(value) : value;\n const key = intlKey(locale, options);\n\n try {\n return intlFmt(caches.dateFormat, key, () => new Intl.DateTimeFormat(locale, options)).format(d);\n } catch {\n return d.toString();\n }\n}\n\nexport function formatRelative(\n caches: IntlCaches,\n value: number,\n unit: Intl.RelativeTimeFormatUnit,\n options: Intl.RelativeTimeFormatOptions | undefined,\n locale: Locale,\n): string {\n const key = intlKey(locale, options);\n\n try {\n return intlFmt(caches.relativeTimeFormat, key, () => new Intl.RelativeTimeFormat(locale, options)).format(\n value,\n unit,\n );\n } catch {\n return String(value);\n }\n}\n\nexport function formatList(caches: IntlCaches, items: unknown[], locale: string, type: 'and' | 'or'): string {\n if (items.length === 0) return '';\n\n const stringItems = items.map(String);\n const intlType = type === 'and' ? 'conjunction' : 'disjunction';\n\n try {\n return intlFmt(\n caches.listFormat,\n `${locale}:${intlType}`,\n () => new Intl.ListFormat(locale, { style: 'long', type: intlType }),\n ).format(stringItems);\n } catch {\n // Fallback for environments without Intl.ListFormat\n if (stringItems.length === 1) return stringItems[0];\n\n if (stringItems.length === 2) return `${stringItems[0]} ${type} ${stringItems[1]}`;\n\n return `${stringItems.slice(0, -1).join(', ')} ${type} ${stringItems.at(-1)}`;\n }\n}\n\nexport function getPluralForm(caches: IntlCaches, locale: Locale, count: number): PluralForm {\n const n = Math.floor(Math.abs(count));\n\n try {\n return intlFmt(caches.pluralRules, locale, () => new Intl.PluralRules(locale)).select(n) as PluralForm;\n } catch {\n return n === 1 ? 'one' : 'other';\n }\n}\n"],"mappings":"AAaA,SAAgB,GAA6B,CAC3C,MAAO,CACL,WAAY,IAAI,IAChB,WAAY,IAAI,IAChB,aAAc,IAAI,IAClB,YAAa,IAAI,IACjB,mBAAoB,IAAI,IACzB,CAKH,SAAS,EAA0B,EAAuB,EAAa,EAAmB,CACxF,IAAI,EAAM,EAAM,IAAI,EAAI,CAOxB,OALK,IACH,EAAM,GAAO,CACb,EAAM,IAAI,EAAK,EAAI,EAGd,EAQT,SAAS,EAAQ,EAAgB,EAA0B,CACzD,OAAO,EAAU,GAAG,EAAO,GAAG,KAAK,UAAU,EAAS,OAAO,KAAK,EAAQ,CAAC,MAAM,CAAC,GAAK,EAKzF,SAAgB,EACd,EACA,EACA,EACA,EACQ,CACR,IAAM,EAAM,EAAQ,EAAQ,EAAQ,CAEpC,GAAI,CACF,OAAO,EAAQ,EAAO,aAAc,MAAW,IAAI,KAAK,aAAa,EAAQ,EAAQ,CAAC,CAAC,OAAO,EAAM,MAC9F,CACN,OAAO,OAAO,EAAM,EAIxB,SAAgB,EACd,EACA,EACA,EACA,EACQ,CACR,IAAM,EAAI,OAAO,GAAU,SAAW,IAAI,KAAK,EAAM,CAAG,EAClD,EAAM,EAAQ,EAAQ,EAAQ,CAEpC,GAAI,CACF,OAAO,EAAQ,EAAO,WAAY,MAAW,IAAI,KAAK,eAAe,EAAQ,EAAQ,CAAC,CAAC,OAAO,EAAE,MAC1F,CACN,OAAO,EAAE,UAAU,EAIvB,SAAgB,EACd,EACA,EACA,EACA,EACA,EACQ,CACR,IAAM,EAAM,EAAQ,EAAQ,EAAQ,CAEpC,GAAI,CACF,OAAO,EAAQ,EAAO,mBAAoB,MAAW,IAAI,KAAK,mBAAmB,EAAQ,EAAQ,CAAC,CAAC,OACjG,EACA,EACD,MACK,CACN,OAAO,OAAO,EAAM,EAIxB,SAAgB,EAAW,EAAoB,EAAkB,EAAgB,EAA4B,CAC3G,GAAI,EAAM,SAAW,EAAG,MAAO,GAE/B,IAAM,EAAc,EAAM,IAAI,OAAO,CAC/B,EAAW,IAAS,MAAQ,cAAgB,cAElD,GAAI,CACF,OAAO,EACL,EAAO,WACP,GAAG,EAAO,GAAG,QACP,IAAI,KAAK,WAAW,EAAQ,CAAE,MAAO,OAAQ,KAAM,EAAU,CAAC,CACrE,CAAC,OAAO,EAAY,MACf,CAMN,OAJI,EAAY,SAAW,EAAU,EAAY,GAE7C,EAAY,SAAW,EAAU,GAAG,EAAY,GAAG,GAAG,EAAK,GAAG,EAAY,KAEvE,GAAG,EAAY,MAAM,EAAG,GAAG,CAAC,KAAK,KAAK,CAAC,GAAG,EAAK,GAAG,EAAY,GAAG,GAAG,IAI/E,SAAgB,EAAc,EAAoB,EAAgB,EAA2B,CAC3F,IAAM,EAAI,KAAK,MAAM,KAAK,IAAI,EAAM,CAAC,CAErC,GAAI,CACF,OAAO,EAAQ,EAAO,YAAa,MAAc,IAAI,KAAK,YAAY,EAAO,CAAC,CAAC,OAAO,EAAE,MAClF,CACN,OAAO,IAAM,EAAI,MAAQ"}
|
package/dist/intl.d.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { Locale, PluralForm } from './types';
|
|
2
|
-
/** Holds all Intl formatter caches for one I18n instance — GC'd with the instance. */
|
|
3
|
-
export type IntlCaches = {
|
|
4
|
-
dateFormat: Map<string, Intl.DateTimeFormat>;
|
|
5
|
-
listFormat: Map<string, Intl.ListFormat>;
|
|
6
|
-
numberFormat: Map<string, Intl.NumberFormat>;
|
|
7
|
-
pluralRules: Map<string, Intl.PluralRules>;
|
|
8
|
-
relativeTimeFormat: Map<string, Intl.RelativeTimeFormat>;
|
|
9
|
-
};
|
|
10
|
-
export declare function makeIntlCaches(): IntlCaches;
|
|
11
|
-
export declare function formatNumber(caches: IntlCaches, value: number, options: Intl.NumberFormatOptions | undefined, locale: Locale): string;
|
|
12
|
-
export declare function formatDate(caches: IntlCaches, value: Date | number, options: Intl.DateTimeFormatOptions | undefined, locale: Locale): string;
|
|
13
|
-
export declare function formatRelative(caches: IntlCaches, value: number, unit: Intl.RelativeTimeFormatUnit, options: Intl.RelativeTimeFormatOptions | undefined, locale: Locale): string;
|
|
14
|
-
export declare function formatList(caches: IntlCaches, items: unknown[], locale: string, type: 'and' | 'or'): string;
|
|
15
|
-
export declare function getPluralForm(caches: IntlCaches, locale: Locale, count: number): PluralForm;
|
|
16
|
-
//# sourceMappingURL=intl.d.ts.map
|
package/dist/intl.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"intl.d.ts","sourceRoot":"","sources":["../src/intl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAIlD,sFAAsF;AACtF,MAAM,MAAM,UAAU,GAAG;IACvB,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;IAC7C,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IACzC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;IAC7C,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IAC3C,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,kBAAkB,CAAC,CAAC;CAC1D,CAAC;AAEF,wBAAgB,cAAc,IAAI,UAAU,CAQ3C;AA0BD,wBAAgB,YAAY,CAC1B,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,IAAI,CAAC,mBAAmB,GAAG,SAAS,EAC7C,MAAM,EAAE,MAAM,GACb,MAAM,CAQR;AAED,wBAAgB,UAAU,CACxB,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,IAAI,GAAG,MAAM,EACpB,OAAO,EAAE,IAAI,CAAC,qBAAqB,GAAG,SAAS,EAC/C,MAAM,EAAE,MAAM,GACb,MAAM,CASR;AAED,wBAAgB,cAAc,CAC5B,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,IAAI,CAAC,sBAAsB,EACjC,OAAO,EAAE,IAAI,CAAC,yBAAyB,GAAG,SAAS,EACnD,MAAM,EAAE,MAAM,GACb,MAAM,CAWR;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,GAAG,IAAI,GAAG,MAAM,CAoB3G;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,CAQ3F"}
|
package/dist/intl.js
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
//#region src/intl.ts
|
|
2
|
-
function e() {
|
|
3
|
-
return {
|
|
4
|
-
dateFormat: /* @__PURE__ */ new Map(),
|
|
5
|
-
listFormat: /* @__PURE__ */ new Map(),
|
|
6
|
-
numberFormat: /* @__PURE__ */ new Map(),
|
|
7
|
-
pluralRules: /* @__PURE__ */ new Map(),
|
|
8
|
-
relativeTimeFormat: /* @__PURE__ */ new Map()
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
function t(e, t, n) {
|
|
12
|
-
let r = e.get(t);
|
|
13
|
-
return r || (r = n(), e.set(t, r)), r;
|
|
14
|
-
}
|
|
15
|
-
function n(e, t) {
|
|
16
|
-
return t ? `${e}:${JSON.stringify(t, Object.keys(t).sort())}` : e;
|
|
17
|
-
}
|
|
18
|
-
function r(e, r, i, a) {
|
|
19
|
-
let o = n(a, i);
|
|
20
|
-
try {
|
|
21
|
-
return t(e.numberFormat, o, () => new Intl.NumberFormat(a, i)).format(r);
|
|
22
|
-
} catch {
|
|
23
|
-
return String(r);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
function i(e, r, i, a) {
|
|
27
|
-
let o = typeof r == "number" ? new Date(r) : r, s = n(a, i);
|
|
28
|
-
try {
|
|
29
|
-
return t(e.dateFormat, s, () => new Intl.DateTimeFormat(a, i)).format(o);
|
|
30
|
-
} catch {
|
|
31
|
-
return o.toString();
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
function a(e, r, i, a, o) {
|
|
35
|
-
let s = n(o, a);
|
|
36
|
-
try {
|
|
37
|
-
return t(e.relativeTimeFormat, s, () => new Intl.RelativeTimeFormat(o, a)).format(r, i);
|
|
38
|
-
} catch {
|
|
39
|
-
return String(r);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
function o(e, n, r, i) {
|
|
43
|
-
if (n.length === 0) return "";
|
|
44
|
-
let a = n.map(String), o = i === "and" ? "conjunction" : "disjunction";
|
|
45
|
-
try {
|
|
46
|
-
return t(e.listFormat, `${r}:${o}`, () => new Intl.ListFormat(r, {
|
|
47
|
-
style: "long",
|
|
48
|
-
type: o
|
|
49
|
-
})).format(a);
|
|
50
|
-
} catch {
|
|
51
|
-
return a.length === 1 ? a[0] : a.length === 2 ? `${a[0]} ${i} ${a[1]}` : `${a.slice(0, -1).join(", ")} ${i} ${a.at(-1)}`;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
function s(e, n, r) {
|
|
55
|
-
let i = Math.floor(Math.abs(r));
|
|
56
|
-
try {
|
|
57
|
-
return t(e.pluralRules, n, () => new Intl.PluralRules(n)).select(i);
|
|
58
|
-
} catch {
|
|
59
|
-
return i === 1 ? "one" : "other";
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
//#endregion
|
|
63
|
-
export { i as formatDate, o as formatList, r as formatNumber, a as formatRelative, s as getPluralForm, e as makeIntlCaches };
|
|
64
|
-
|
|
65
|
-
//# sourceMappingURL=intl.js.map
|
package/dist/intl.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"intl.js","names":[],"sources":["../src/intl.ts"],"sourcesContent":["import type { Locale, PluralForm } from './types';\n\n/* -------------------- Cache Container -------------------- */\n\n/** Holds all Intl formatter caches for one I18n instance — GC'd with the instance. */\nexport type IntlCaches = {\n dateFormat: Map<string, Intl.DateTimeFormat>;\n listFormat: Map<string, Intl.ListFormat>;\n numberFormat: Map<string, Intl.NumberFormat>;\n pluralRules: Map<string, Intl.PluralRules>;\n relativeTimeFormat: Map<string, Intl.RelativeTimeFormat>;\n};\n\nexport function makeIntlCaches(): IntlCaches {\n return {\n dateFormat: new Map(),\n listFormat: new Map(),\n numberFormat: new Map(),\n pluralRules: new Map(),\n relativeTimeFormat: new Map(),\n };\n}\n\n/* -------------------- Cache Helpers -------------------- */\n\nfunction intlFmt<F extends object>(cache: Map<string, F>, key: string, build: () => F): F {\n let fmt = cache.get(key);\n\n if (!fmt) {\n fmt = build();\n cache.set(key, fmt);\n }\n\n return fmt;\n}\n\n/**\n * Builds a stable string key for an Intl formatter cache.\n * Call this once per formatter construction path — not on every format call — so key\n * serialization cost is paid only on cache misses.\n */\nfunction intlKey(locale: string, options?: object): string {\n return options ? `${locale}:${JSON.stringify(options, Object.keys(options).sort())}` : locale;\n}\n\n/* -------------------- Format Functions -------------------- */\n\nexport function formatNumber(\n caches: IntlCaches,\n value: number,\n options: Intl.NumberFormatOptions | undefined,\n locale: Locale,\n): string {\n const key = intlKey(locale, options);\n\n try {\n return intlFmt(caches.numberFormat, key, () => new Intl.NumberFormat(locale, options)).format(value);\n } catch {\n return String(value);\n }\n}\n\nexport function formatDate(\n caches: IntlCaches,\n value: Date | number,\n options: Intl.DateTimeFormatOptions | undefined,\n locale: Locale,\n): string {\n const d = typeof value === 'number' ? new Date(value) : value;\n const key = intlKey(locale, options);\n\n try {\n return intlFmt(caches.dateFormat, key, () => new Intl.DateTimeFormat(locale, options)).format(d);\n } catch {\n return d.toString();\n }\n}\n\nexport function formatRelative(\n caches: IntlCaches,\n value: number,\n unit: Intl.RelativeTimeFormatUnit,\n options: Intl.RelativeTimeFormatOptions | undefined,\n locale: Locale,\n): string {\n const key = intlKey(locale, options);\n\n try {\n return intlFmt(caches.relativeTimeFormat, key, () => new Intl.RelativeTimeFormat(locale, options)).format(\n value,\n unit,\n );\n } catch {\n return String(value);\n }\n}\n\nexport function formatList(caches: IntlCaches, items: unknown[], locale: string, type: 'and' | 'or'): string {\n if (items.length === 0) return '';\n\n const stringItems = items.map(String);\n const intlType = type === 'and' ? 'conjunction' : 'disjunction';\n\n try {\n return intlFmt(\n caches.listFormat,\n `${locale}:${intlType}`,\n () => new Intl.ListFormat(locale, { style: 'long', type: intlType }),\n ).format(stringItems);\n } catch {\n // Fallback for environments without Intl.ListFormat\n if (stringItems.length === 1) return stringItems[0];\n\n if (stringItems.length === 2) return `${stringItems[0]} ${type} ${stringItems[1]}`;\n\n return `${stringItems.slice(0, -1).join(', ')} ${type} ${stringItems.at(-1)}`;\n }\n}\n\nexport function getPluralForm(caches: IntlCaches, locale: Locale, count: number): PluralForm {\n const n = Math.floor(Math.abs(count));\n\n try {\n return intlFmt(caches.pluralRules, locale, () => new Intl.PluralRules(locale)).select(n) as PluralForm;\n } catch {\n return n === 1 ? 'one' : 'other';\n }\n}\n"],"mappings":";AAaA,SAAgB,IAA6B;AAC3C,QAAO;EACL,4BAAY,IAAI,KAAK;EACrB,4BAAY,IAAI,KAAK;EACrB,8BAAc,IAAI,KAAK;EACvB,6BAAa,IAAI,KAAK;EACtB,oCAAoB,IAAI,KAAK;EAC9B;;AAKH,SAAS,EAA0B,GAAuB,GAAa,GAAmB;CACxF,IAAI,IAAM,EAAM,IAAI,EAAI;AAOxB,QALK,MACH,IAAM,GAAO,EACb,EAAM,IAAI,GAAK,EAAI,GAGd;;AAQT,SAAS,EAAQ,GAAgB,GAA0B;AACzD,QAAO,IAAU,GAAG,EAAO,GAAG,KAAK,UAAU,GAAS,OAAO,KAAK,EAAQ,CAAC,MAAM,CAAC,KAAK;;AAKzF,SAAgB,EACd,GACA,GACA,GACA,GACQ;CACR,IAAM,IAAM,EAAQ,GAAQ,EAAQ;AAEpC,KAAI;AACF,SAAO,EAAQ,EAAO,cAAc,SAAW,IAAI,KAAK,aAAa,GAAQ,EAAQ,CAAC,CAAC,OAAO,EAAM;SAC9F;AACN,SAAO,OAAO,EAAM;;;AAIxB,SAAgB,EACd,GACA,GACA,GACA,GACQ;CACR,IAAM,IAAI,OAAO,KAAU,WAAW,IAAI,KAAK,EAAM,GAAG,GAClD,IAAM,EAAQ,GAAQ,EAAQ;AAEpC,KAAI;AACF,SAAO,EAAQ,EAAO,YAAY,SAAW,IAAI,KAAK,eAAe,GAAQ,EAAQ,CAAC,CAAC,OAAO,EAAE;SAC1F;AACN,SAAO,EAAE,UAAU;;;AAIvB,SAAgB,EACd,GACA,GACA,GACA,GACA,GACQ;CACR,IAAM,IAAM,EAAQ,GAAQ,EAAQ;AAEpC,KAAI;AACF,SAAO,EAAQ,EAAO,oBAAoB,SAAW,IAAI,KAAK,mBAAmB,GAAQ,EAAQ,CAAC,CAAC,OACjG,GACA,EACD;SACK;AACN,SAAO,OAAO,EAAM;;;AAIxB,SAAgB,EAAW,GAAoB,GAAkB,GAAgB,GAA4B;AAC3G,KAAI,EAAM,WAAW,EAAG,QAAO;CAE/B,IAAM,IAAc,EAAM,IAAI,OAAO,EAC/B,IAAW,MAAS,QAAQ,gBAAgB;AAElD,KAAI;AACF,SAAO,EACL,EAAO,YACP,GAAG,EAAO,GAAG,WACP,IAAI,KAAK,WAAW,GAAQ;GAAE,OAAO;GAAQ,MAAM;GAAU,CAAC,CACrE,CAAC,OAAO,EAAY;SACf;AAMN,SAJI,EAAY,WAAW,IAAU,EAAY,KAE7C,EAAY,WAAW,IAAU,GAAG,EAAY,GAAG,GAAG,EAAK,GAAG,EAAY,OAEvE,GAAG,EAAY,MAAM,GAAG,GAAG,CAAC,KAAK,KAAK,CAAC,GAAG,EAAK,GAAG,EAAY,GAAG,GAAG;;;AAI/E,SAAgB,EAAc,GAAoB,GAAgB,GAA2B;CAC3F,IAAM,IAAI,KAAK,MAAM,KAAK,IAAI,EAAM,CAAC;AAErC,KAAI;AACF,SAAO,EAAQ,EAAO,aAAa,SAAc,IAAI,KAAK,YAAY,EAAO,CAAC,CAAC,OAAO,EAAE;SAClF;AACN,SAAO,MAAM,IAAI,QAAQ"}
|