@vielzeug/lingua 1.1.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 +86 -0
- package/dist/_catalog-store.cjs +2 -0
- package/dist/_catalog-store.cjs.map +1 -0
- package/dist/_catalog-store.d.ts +33 -0
- package/dist/_catalog-store.d.ts.map +1 -0
- package/dist/_catalog-store.js +74 -0
- package/dist/_catalog-store.js.map +1 -0
- package/dist/_catalog.cjs +2 -0
- package/dist/_catalog.cjs.map +1 -0
- package/dist/_catalog.d.ts +18 -0
- package/dist/_catalog.d.ts.map +1 -0
- package/dist/_catalog.js +42 -0
- package/dist/_catalog.js.map +1 -0
- package/dist/_chain.cjs +2 -0
- package/dist/_chain.cjs.map +1 -0
- package/dist/_chain.d.ts +21 -0
- package/dist/_chain.d.ts.map +1 -0
- package/dist/_chain.js +45 -0
- package/dist/_chain.js.map +1 -0
- package/dist/_constants.cjs +2 -0
- package/dist/_constants.cjs.map +1 -0
- package/dist/_constants.d.ts +3 -0
- package/dist/_constants.d.ts.map +1 -0
- package/dist/_constants.js +17 -0
- package/dist/_constants.js.map +1 -0
- package/dist/_dev.cjs +2 -0
- package/dist/_dev.cjs.map +1 -0
- package/dist/_dev.d.ts +2 -0
- package/dist/_dev.d.ts.map +1 -0
- package/dist/_dev.js +12 -0
- package/dist/_dev.js.map +1 -0
- package/dist/_namespace-store.cjs +2 -0
- package/dist/_namespace-store.cjs.map +1 -0
- package/dist/_namespace-store.d.ts +31 -0
- package/dist/_namespace-store.d.ts.map +1 -0
- package/dist/_namespace-store.js +54 -0
- package/dist/_namespace-store.js.map +1 -0
- package/dist/errors.cjs +2 -0
- package/dist/errors.cjs.map +1 -0
- package/dist/errors.d.ts +30 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +23 -0
- package/dist/errors.js.map +1 -0
- package/dist/format.cjs +2 -0
- package/dist/format.cjs.map +1 -0
- package/dist/format.d.ts +73 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +91 -0
- package/dist/format.js.map +1 -0
- package/dist/i18n.cjs +2 -0
- package/dist/i18n.cjs.map +1 -0
- package/dist/i18n.d.ts +283 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +234 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/lingua.cjs +2 -0
- package/dist/lingua.cjs.map +1 -0
- package/dist/lingua.iife.js +2 -0
- package/dist/lingua.iife.js.map +1 -0
- package/dist/lingua.js +2 -0
- package/dist/lingua.js.map +1 -0
- package/dist/template.cjs +2 -0
- package/dist/template.cjs.map +1 -0
- package/dist/template.d.ts +15 -0
- package/dist/template.d.ts.map +1 -0
- package/dist/template.js +49 -0
- package/dist/template.js.map +1 -0
- package/dist/validate.cjs +2 -0
- package/dist/validate.cjs.map +1 -0
- package/dist/validate.d.ts +40 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +59 -0
- package/dist/validate.js.map +1 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# @vielzeug/lingua
|
|
2
|
+
|
|
3
|
+
> Minimal i18n runtime with typed keys, deterministic locale fallback, and framework-agnostic reactive subscriptions.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@vielzeug/lingua) [](https://opensource.org/licenses/MIT)
|
|
6
|
+
|
|
7
|
+
<details>
|
|
8
|
+
<summary>Quick Reference</summary>
|
|
9
|
+
|
|
10
|
+
**Package:** `@vielzeug/lingua` · **Category:** i18n
|
|
11
|
+
|
|
12
|
+
**Key exports:** `createI18n` · `createFormatter` (from `@vielzeug/lingua/format`) · `validateCatalog` (from `@vielzeug/lingua/validate`)
|
|
13
|
+
|
|
14
|
+
**When to use:** Minimal i18n runtime with typed keys, deterministic locale fallback, and framework-agnostic reactive subscriptions.
|
|
15
|
+
|
|
16
|
+
**Related:** [@vielzeug/ripple](https://vielzeug.dev/ripple/) · [@vielzeug/wayfinder](https://vielzeug.dev/wayfinder/) · [@vielzeug/courier](https://vielzeug.dev/courier/)
|
|
17
|
+
|
|
18
|
+
</details>
|
|
19
|
+
|
|
20
|
+
`@vielzeug/lingua` is part of Vielzeug and ships as a zero-dependency TypeScript package with ESM+CJS output.
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
pnpm add @vielzeug/lingua
|
|
26
|
+
npm install @vielzeug/lingua
|
|
27
|
+
yarn add @vielzeug/lingua
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { createI18n } from '@vielzeug/lingua';
|
|
34
|
+
import { createFormatter } from '@vielzeug/lingua/format';
|
|
35
|
+
|
|
36
|
+
const i18n = createI18n({
|
|
37
|
+
locale: 'en',
|
|
38
|
+
fallback: 'en',
|
|
39
|
+
catalogs: {
|
|
40
|
+
en: {
|
|
41
|
+
greeting: 'Hello, {name}!',
|
|
42
|
+
inbox: {
|
|
43
|
+
zero: 'No messages',
|
|
44
|
+
one: 'One message',
|
|
45
|
+
other: '{count} messages',
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
de: () => import('./locales/de.json').then((m) => m.default),
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
await i18n.setLocale('de');
|
|
53
|
+
|
|
54
|
+
i18n.t('greeting', { name: 'Alice' });
|
|
55
|
+
i18n.tp('inbox', 3);
|
|
56
|
+
|
|
57
|
+
// Scope reduces key repetition inside a namespace
|
|
58
|
+
const nav = i18n.scope('nav');
|
|
59
|
+
nav.t('home'); // resolves 'nav.home'
|
|
60
|
+
|
|
61
|
+
// Bind a cached per-key function for hot-path rendering
|
|
62
|
+
const greet = i18n.bind('greeting');
|
|
63
|
+
const users = [{ name: 'Alice' }, { name: 'Bob' }];
|
|
64
|
+
users.forEach((u) => greet({ name: u.name }));
|
|
65
|
+
|
|
66
|
+
// Merge route-specific keys on top of the base catalog
|
|
67
|
+
await i18n.merge('en', () => import('./routes/settings.i18n.json').then((m) => m.default));
|
|
68
|
+
|
|
69
|
+
// Fork the shared instance for SSR per-request isolation
|
|
70
|
+
const reqI18n = i18n.fork({ locale: req.locale });
|
|
71
|
+
|
|
72
|
+
// Formatter bound to the current locale — follows locale changes automatically
|
|
73
|
+
const fmt = createFormatter(() => i18n.locale);
|
|
74
|
+
fmt.currency(19.99, 'EUR');
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Documentation
|
|
78
|
+
|
|
79
|
+
- [Overview](https://vielzeug.dev/lingua/)
|
|
80
|
+
- [Usage Guide](https://vielzeug.dev/lingua/usage)
|
|
81
|
+
- [API Reference](https://vielzeug.dev/lingua/api)
|
|
82
|
+
- [Examples](https://vielzeug.dev/lingua/examples)
|
|
83
|
+
|
|
84
|
+
## License
|
|
85
|
+
|
|
86
|
+
MIT © [Helmuth Saatkamp](https://github.com/helmuthdu) — part of the [Vielzeug](https://github.com/helmuthdu/vielzeug) monorepo.
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("./_dev.cjs"),t=require("./_catalog.cjs"),n=require("./errors.cjs");function r(r){let i=new Map,a=new Map,o=new Map,s=new Set,c,l=(e,n)=>{let r=i.get(e);r||(r=new t.CatalogEntry,i.set(e,r)),r.setAll(n)},u=e=>{let s=n.checkDisposedAsync(r());if(s)return s;if(i.has(e))return Promise.resolve();let u=a.get(e);if(!u)return Promise.reject(new n.LinguaMissingLocaleError(`Missing locale source for "${e}".`));let d=o.get(e);if(d)return d;let f=u().then(n=>{a.get(e)===u&&(a.delete(e),l(e,t.flattenStrings(n)),o.delete(e),c?.(e))},t=>{throw a.get(e)===u&&o.delete(e),t});return o.set(e,f),f};return{get catalogs(){return i},dispose(){i.clear(),a.clear(),o.clear(),s.clear(),c=void 0},isLoaded(e){return i.has(e)},isRegistered(e){return s.has(e)},knownLocales(){return[...s]},get onChange(){return c},set onChange(e){c=e},patch(e,i){return n.checkDisposedAsync(r())||(a.has(e)?u(e).then(()=>{r()||(l(e,t.flattenStrings(i)),s.add(e),c?.(e))}):(l(e,t.flattenStrings(i)),s.add(e),c?.(e),Promise.resolve()))},get pendingLoaders(){return a},preload:u,register(d,f,p){n.checkDisposed(r()),o.delete(d),s.add(d);let m=p.clearLocale(d);m.length>0&&e.warn(`register('${d}') cleared loaded namespace markers for: ${m.map(e=>`'${e}'`).join(`, `)}. Call loadNamespace() again to reload.`);let h;return typeof f==`function`?(a.set(d,f),i.delete(d),h=u(d)):(a.delete(d),i.delete(d),l(d,t.flattenStrings(f)),h=Promise.resolve(),c?.(d)),h},resolve(e){return i.get(e)},seedFrom(e,t){for(let[t,n]of e)i.set(t,n.clone()),s.add(t);for(let[e,n]of t)a.set(e,n),s.add(e)}}}exports.createCatalogStore=r;
|
|
2
|
+
//# sourceMappingURL=_catalog-store.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_catalog-store.cjs","names":[],"sources":["../src/_catalog-store.ts"],"sourcesContent":["// Internal — not part of the public API.\n// Owns all locale → CatalogEntry state, loaders, and in-flight loading tasks.\n\nimport type { NamespaceStore } from './_namespace-store';\n\nimport { CatalogEntry, type Messages, flattenStrings } from './_catalog';\nimport { warn } from './_dev';\nimport { LinguaMissingLocaleError, checkDisposed, checkDisposedAsync } from './errors';\n\nexport type Locale = string;\nexport type Loader<M extends Messages = Messages> = () => Promise<M>;\nexport type LocaleSource<M extends Messages = Messages> = M | Loader<M>;\n\nexport type CatalogStore<M extends Messages = Messages> = {\n /** Direct access to the raw catalogs map (for SSR serialization). */\n readonly catalogs: ReadonlyMap<Locale, CatalogEntry>;\n dispose(): void;\n isLoaded(loc: Locale): boolean;\n isRegistered(loc: Locale): boolean;\n /** All registered locale keys in insertion order. */\n knownLocales(): readonly Locale[];\n /** Callback invoked whenever a catalog changes (drives bump/notify). */\n onChange: ((loc: Locale) => void) | undefined;\n /** Patch a locale catalog with additional flat messages (used by loadNamespace). */\n patch(loc: Locale, messages: Messages): Promise<void>;\n /** Direct access to the pending loaders map (for fork propagation). */\n readonly pendingLoaders: ReadonlyMap<Locale, Loader<M>>;\n /** Pre-load a locale catalog without switching. */\n preload(loc: Locale): Promise<void>;\n /** Register (or replace) a locale's source. Returns a Promise that resolves when the catalog is loaded. */\n register(loc: Locale, source: LocaleSource<M>, nsStore: NamespaceStore): Promise<void>;\n /** Resolve a compiled CatalogEntry for a locale (undefined if not loaded). */\n resolve(loc: Locale): CatalogEntry | undefined;\n /**\n * Seed the store with pre-compiled entries from a parent fork.\n * Called during fork() — compiled templates are shared by reference.\n */\n seedFrom(entries: ReadonlyMap<Locale, CatalogEntry>, loaderMap: ReadonlyMap<Locale, Loader<M>>): void;\n};\n\nexport function createCatalogStore<M extends Messages = Messages>(disposed: () => boolean): CatalogStore<M> {\n const catalogs = new Map<Locale, CatalogEntry>();\n const loaders = new Map<Locale, Loader<M>>();\n const loadingTasks = new Map<Locale, Promise<void>>();\n const known = new Set<Locale>();\n\n let onChange: ((loc: Locale) => void) | undefined;\n\n const registerRaw = (normalized: Locale, flat: Map<string, string>): void => {\n let entry = catalogs.get(normalized);\n\n if (!entry) {\n entry = new CatalogEntry();\n catalogs.set(normalized, entry);\n }\n\n entry.setAll(flat);\n };\n\n const preload = (loc: Locale): Promise<void> => {\n const early = checkDisposedAsync(disposed());\n\n if (early) return early;\n\n if (catalogs.has(loc)) return Promise.resolve();\n\n const loader = loaders.get(loc);\n\n if (!loader) return Promise.reject(new LinguaMissingLocaleError(`Missing locale source for \"${loc}\".`));\n\n const existing = loadingTasks.get(loc);\n\n if (existing) return existing;\n\n const task = loader().then(\n (messages) => {\n if (loaders.get(loc) !== loader) return;\n\n loaders.delete(loc);\n registerRaw(loc, flattenStrings(messages));\n loadingTasks.delete(loc);\n onChange?.(loc);\n },\n (error: unknown) => {\n if (loaders.get(loc) === loader) loadingTasks.delete(loc);\n\n throw error;\n },\n );\n\n loadingTasks.set(loc, task);\n\n return task;\n };\n\n return {\n get catalogs() {\n return catalogs as ReadonlyMap<Locale, CatalogEntry>;\n },\n\n dispose() {\n catalogs.clear();\n loaders.clear();\n loadingTasks.clear();\n known.clear();\n onChange = undefined;\n },\n\n isLoaded(loc) {\n return catalogs.has(loc);\n },\n\n isRegistered(loc) {\n return known.has(loc);\n },\n\n knownLocales() {\n return [...known];\n },\n\n get onChange() {\n return onChange;\n },\n\n set onChange(fn: ((loc: Locale) => void) | undefined) {\n onChange = fn;\n },\n\n patch(loc, messages) {\n const early = checkDisposedAsync(disposed());\n\n if (early) return early;\n\n if (loaders.has(loc)) {\n return preload(loc).then(() => {\n if (disposed()) return;\n\n registerRaw(loc, flattenStrings(messages));\n known.add(loc);\n onChange?.(loc);\n });\n }\n\n registerRaw(loc, flattenStrings(messages));\n known.add(loc);\n onChange?.(loc);\n\n return Promise.resolve();\n },\n\n get pendingLoaders() {\n return loaders as ReadonlyMap<Locale, Loader<M>>;\n },\n\n preload,\n\n register(loc, source, nsStore) {\n checkDisposed(disposed());\n\n loadingTasks.delete(loc);\n known.add(loc);\n\n // Clear namespace loaded-markers for this locale so namespaces can be re-applied\n // after catalog replacement.\n const clearedNs = nsStore.clearLocale(loc);\n\n if (clearedNs.length > 0) {\n warn(\n `register('${loc}') cleared loaded namespace markers for: ${clearedNs.map((ns) => `'${ns}'`).join(', ')}. Call loadNamespace() again to reload.`,\n );\n }\n\n let loadPromise: Promise<void>;\n\n if (typeof source === 'function') {\n loaders.set(loc, source as Loader<M>);\n catalogs.delete(loc);\n loadPromise = preload(loc);\n } else {\n loaders.delete(loc);\n catalogs.delete(loc);\n registerRaw(loc, flattenStrings(source as M));\n loadPromise = Promise.resolve();\n onChange?.(loc);\n }\n\n return loadPromise;\n },\n\n resolve(loc) {\n return catalogs.get(loc);\n },\n\n seedFrom(entries, loaderMap) {\n for (const [loc, entry] of entries) {\n catalogs.set(loc, entry.clone());\n known.add(loc);\n }\n\n for (const [loc, loader] of loaderMap) {\n loaders.set(loc, loader);\n known.add(loc);\n }\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { NamespaceStore } from './_namespace-store';
|
|
2
|
+
import { CatalogEntry, type Messages } from './_catalog';
|
|
3
|
+
export type Locale = string;
|
|
4
|
+
export type Loader<M extends Messages = Messages> = () => Promise<M>;
|
|
5
|
+
export type LocaleSource<M extends Messages = Messages> = M | Loader<M>;
|
|
6
|
+
export type CatalogStore<M extends Messages = Messages> = {
|
|
7
|
+
/** Direct access to the raw catalogs map (for SSR serialization). */
|
|
8
|
+
readonly catalogs: ReadonlyMap<Locale, CatalogEntry>;
|
|
9
|
+
dispose(): void;
|
|
10
|
+
isLoaded(loc: Locale): boolean;
|
|
11
|
+
isRegistered(loc: Locale): boolean;
|
|
12
|
+
/** All registered locale keys in insertion order. */
|
|
13
|
+
knownLocales(): readonly Locale[];
|
|
14
|
+
/** Callback invoked whenever a catalog changes (drives bump/notify). */
|
|
15
|
+
onChange: ((loc: Locale) => void) | undefined;
|
|
16
|
+
/** Patch a locale catalog with additional flat messages (used by loadNamespace). */
|
|
17
|
+
patch(loc: Locale, messages: Messages): Promise<void>;
|
|
18
|
+
/** Direct access to the pending loaders map (for fork propagation). */
|
|
19
|
+
readonly pendingLoaders: ReadonlyMap<Locale, Loader<M>>;
|
|
20
|
+
/** Pre-load a locale catalog without switching. */
|
|
21
|
+
preload(loc: Locale): Promise<void>;
|
|
22
|
+
/** Register (or replace) a locale's source. Returns a Promise that resolves when the catalog is loaded. */
|
|
23
|
+
register(loc: Locale, source: LocaleSource<M>, nsStore: NamespaceStore): Promise<void>;
|
|
24
|
+
/** Resolve a compiled CatalogEntry for a locale (undefined if not loaded). */
|
|
25
|
+
resolve(loc: Locale): CatalogEntry | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Seed the store with pre-compiled entries from a parent fork.
|
|
28
|
+
* Called during fork() — compiled templates are shared by reference.
|
|
29
|
+
*/
|
|
30
|
+
seedFrom(entries: ReadonlyMap<Locale, CatalogEntry>, loaderMap: ReadonlyMap<Locale, Loader<M>>): void;
|
|
31
|
+
};
|
|
32
|
+
export declare function createCatalogStore<M extends Messages = Messages>(disposed: () => boolean): CatalogStore<M>;
|
|
33
|
+
//# sourceMappingURL=_catalog-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_catalog-store.d.ts","sourceRoot":"","sources":["../src/_catalog-store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD,OAAO,EAAE,YAAY,EAAE,KAAK,QAAQ,EAAkB,MAAM,YAAY,CAAC;AAIzE,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC;AAC5B,MAAM,MAAM,MAAM,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC;AACrE,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;AAExE,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,IAAI;IACxD,qEAAqE;IACrE,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACrD,OAAO,IAAI,IAAI,CAAC;IAChB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAC/B,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACnC,qDAAqD;IACrD,YAAY,IAAI,SAAS,MAAM,EAAE,CAAC;IAClC,wEAAwE;IACxE,QAAQ,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC9C,oFAAoF;IACpF,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,uEAAuE;IACvE,QAAQ,CAAC,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACxD,mDAAmD;IACnD,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,2GAA2G;IAC3G,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvF,8EAA8E;IAC9E,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAAC;IAC/C;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,EAAE,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;CACvG,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,EAAE,QAAQ,EAAE,MAAM,OAAO,GAAG,YAAY,CAAC,CAAC,CAAC,CAqK1G"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { warn as e } from "./_dev.js";
|
|
2
|
+
import { CatalogEntry as t, flattenStrings as n } from "./_catalog.js";
|
|
3
|
+
import { LinguaMissingLocaleError as r, checkDisposed as i, checkDisposedAsync as a } from "./errors.js";
|
|
4
|
+
//#region src/_catalog-store.ts
|
|
5
|
+
function o(o) {
|
|
6
|
+
let s = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Map(), u = /* @__PURE__ */ new Set(), d, f = (e, n) => {
|
|
7
|
+
let r = s.get(e);
|
|
8
|
+
r || (r = new t(), s.set(e, r)), r.setAll(n);
|
|
9
|
+
}, p = (e) => {
|
|
10
|
+
let t = a(o());
|
|
11
|
+
if (t) return t;
|
|
12
|
+
if (s.has(e)) return Promise.resolve();
|
|
13
|
+
let i = c.get(e);
|
|
14
|
+
if (!i) return Promise.reject(new r(`Missing locale source for "${e}".`));
|
|
15
|
+
let u = l.get(e);
|
|
16
|
+
if (u) return u;
|
|
17
|
+
let p = i().then((t) => {
|
|
18
|
+
c.get(e) === i && (c.delete(e), f(e, n(t)), l.delete(e), d?.(e));
|
|
19
|
+
}, (t) => {
|
|
20
|
+
throw c.get(e) === i && l.delete(e), t;
|
|
21
|
+
});
|
|
22
|
+
return l.set(e, p), p;
|
|
23
|
+
};
|
|
24
|
+
return {
|
|
25
|
+
get catalogs() {
|
|
26
|
+
return s;
|
|
27
|
+
},
|
|
28
|
+
dispose() {
|
|
29
|
+
s.clear(), c.clear(), l.clear(), u.clear(), d = void 0;
|
|
30
|
+
},
|
|
31
|
+
isLoaded(e) {
|
|
32
|
+
return s.has(e);
|
|
33
|
+
},
|
|
34
|
+
isRegistered(e) {
|
|
35
|
+
return u.has(e);
|
|
36
|
+
},
|
|
37
|
+
knownLocales() {
|
|
38
|
+
return [...u];
|
|
39
|
+
},
|
|
40
|
+
get onChange() {
|
|
41
|
+
return d;
|
|
42
|
+
},
|
|
43
|
+
set onChange(e) {
|
|
44
|
+
d = e;
|
|
45
|
+
},
|
|
46
|
+
patch(e, t) {
|
|
47
|
+
return a(o()) || (c.has(e) ? p(e).then(() => {
|
|
48
|
+
o() || (f(e, n(t)), u.add(e), d?.(e));
|
|
49
|
+
}) : (f(e, n(t)), u.add(e), d?.(e), Promise.resolve()));
|
|
50
|
+
},
|
|
51
|
+
get pendingLoaders() {
|
|
52
|
+
return c;
|
|
53
|
+
},
|
|
54
|
+
preload: p,
|
|
55
|
+
register(t, r, a) {
|
|
56
|
+
i(o()), l.delete(t), u.add(t);
|
|
57
|
+
let m = a.clearLocale(t);
|
|
58
|
+
m.length > 0 && e(`register('${t}') cleared loaded namespace markers for: ${m.map((e) => `'${e}'`).join(", ")}. Call loadNamespace() again to reload.`);
|
|
59
|
+
let h;
|
|
60
|
+
return typeof r == "function" ? (c.set(t, r), s.delete(t), h = p(t)) : (c.delete(t), s.delete(t), f(t, n(r)), h = Promise.resolve(), d?.(t)), h;
|
|
61
|
+
},
|
|
62
|
+
resolve(e) {
|
|
63
|
+
return s.get(e);
|
|
64
|
+
},
|
|
65
|
+
seedFrom(e, t) {
|
|
66
|
+
for (let [t, n] of e) s.set(t, n.clone()), u.add(t);
|
|
67
|
+
for (let [e, n] of t) c.set(e, n), u.add(e);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
//#endregion
|
|
72
|
+
export { o as createCatalogStore };
|
|
73
|
+
|
|
74
|
+
//# sourceMappingURL=_catalog-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_catalog-store.js","names":[],"sources":["../src/_catalog-store.ts"],"sourcesContent":["// Internal — not part of the public API.\n// Owns all locale → CatalogEntry state, loaders, and in-flight loading tasks.\n\nimport type { NamespaceStore } from './_namespace-store';\n\nimport { CatalogEntry, type Messages, flattenStrings } from './_catalog';\nimport { warn } from './_dev';\nimport { LinguaMissingLocaleError, checkDisposed, checkDisposedAsync } from './errors';\n\nexport type Locale = string;\nexport type Loader<M extends Messages = Messages> = () => Promise<M>;\nexport type LocaleSource<M extends Messages = Messages> = M | Loader<M>;\n\nexport type CatalogStore<M extends Messages = Messages> = {\n /** Direct access to the raw catalogs map (for SSR serialization). */\n readonly catalogs: ReadonlyMap<Locale, CatalogEntry>;\n dispose(): void;\n isLoaded(loc: Locale): boolean;\n isRegistered(loc: Locale): boolean;\n /** All registered locale keys in insertion order. */\n knownLocales(): readonly Locale[];\n /** Callback invoked whenever a catalog changes (drives bump/notify). */\n onChange: ((loc: Locale) => void) | undefined;\n /** Patch a locale catalog with additional flat messages (used by loadNamespace). */\n patch(loc: Locale, messages: Messages): Promise<void>;\n /** Direct access to the pending loaders map (for fork propagation). */\n readonly pendingLoaders: ReadonlyMap<Locale, Loader<M>>;\n /** Pre-load a locale catalog without switching. */\n preload(loc: Locale): Promise<void>;\n /** Register (or replace) a locale's source. Returns a Promise that resolves when the catalog is loaded. */\n register(loc: Locale, source: LocaleSource<M>, nsStore: NamespaceStore): Promise<void>;\n /** Resolve a compiled CatalogEntry for a locale (undefined if not loaded). */\n resolve(loc: Locale): CatalogEntry | undefined;\n /**\n * Seed the store with pre-compiled entries from a parent fork.\n * Called during fork() — compiled templates are shared by reference.\n */\n seedFrom(entries: ReadonlyMap<Locale, CatalogEntry>, loaderMap: ReadonlyMap<Locale, Loader<M>>): void;\n};\n\nexport function createCatalogStore<M extends Messages = Messages>(disposed: () => boolean): CatalogStore<M> {\n const catalogs = new Map<Locale, CatalogEntry>();\n const loaders = new Map<Locale, Loader<M>>();\n const loadingTasks = new Map<Locale, Promise<void>>();\n const known = new Set<Locale>();\n\n let onChange: ((loc: Locale) => void) | undefined;\n\n const registerRaw = (normalized: Locale, flat: Map<string, string>): void => {\n let entry = catalogs.get(normalized);\n\n if (!entry) {\n entry = new CatalogEntry();\n catalogs.set(normalized, entry);\n }\n\n entry.setAll(flat);\n };\n\n const preload = (loc: Locale): Promise<void> => {\n const early = checkDisposedAsync(disposed());\n\n if (early) return early;\n\n if (catalogs.has(loc)) return Promise.resolve();\n\n const loader = loaders.get(loc);\n\n if (!loader) return Promise.reject(new LinguaMissingLocaleError(`Missing locale source for \"${loc}\".`));\n\n const existing = loadingTasks.get(loc);\n\n if (existing) return existing;\n\n const task = loader().then(\n (messages) => {\n if (loaders.get(loc) !== loader) return;\n\n loaders.delete(loc);\n registerRaw(loc, flattenStrings(messages));\n loadingTasks.delete(loc);\n onChange?.(loc);\n },\n (error: unknown) => {\n if (loaders.get(loc) === loader) loadingTasks.delete(loc);\n\n throw error;\n },\n );\n\n loadingTasks.set(loc, task);\n\n return task;\n };\n\n return {\n get catalogs() {\n return catalogs as ReadonlyMap<Locale, CatalogEntry>;\n },\n\n dispose() {\n catalogs.clear();\n loaders.clear();\n loadingTasks.clear();\n known.clear();\n onChange = undefined;\n },\n\n isLoaded(loc) {\n return catalogs.has(loc);\n },\n\n isRegistered(loc) {\n return known.has(loc);\n },\n\n knownLocales() {\n return [...known];\n },\n\n get onChange() {\n return onChange;\n },\n\n set onChange(fn: ((loc: Locale) => void) | undefined) {\n onChange = fn;\n },\n\n patch(loc, messages) {\n const early = checkDisposedAsync(disposed());\n\n if (early) return early;\n\n if (loaders.has(loc)) {\n return preload(loc).then(() => {\n if (disposed()) return;\n\n registerRaw(loc, flattenStrings(messages));\n known.add(loc);\n onChange?.(loc);\n });\n }\n\n registerRaw(loc, flattenStrings(messages));\n known.add(loc);\n onChange?.(loc);\n\n return Promise.resolve();\n },\n\n get pendingLoaders() {\n return loaders as ReadonlyMap<Locale, Loader<M>>;\n },\n\n preload,\n\n register(loc, source, nsStore) {\n checkDisposed(disposed());\n\n loadingTasks.delete(loc);\n known.add(loc);\n\n // Clear namespace loaded-markers for this locale so namespaces can be re-applied\n // after catalog replacement.\n const clearedNs = nsStore.clearLocale(loc);\n\n if (clearedNs.length > 0) {\n warn(\n `register('${loc}') cleared loaded namespace markers for: ${clearedNs.map((ns) => `'${ns}'`).join(', ')}. Call loadNamespace() again to reload.`,\n );\n }\n\n let loadPromise: Promise<void>;\n\n if (typeof source === 'function') {\n loaders.set(loc, source as Loader<M>);\n catalogs.delete(loc);\n loadPromise = preload(loc);\n } else {\n loaders.delete(loc);\n catalogs.delete(loc);\n registerRaw(loc, flattenStrings(source as M));\n loadPromise = Promise.resolve();\n onChange?.(loc);\n }\n\n return loadPromise;\n },\n\n resolve(loc) {\n return catalogs.get(loc);\n },\n\n seedFrom(entries, loaderMap) {\n for (const [loc, entry] of entries) {\n catalogs.set(loc, entry.clone());\n known.add(loc);\n }\n\n for (const [loc, loader] of loaderMap) {\n loaders.set(loc, loader);\n known.add(loc);\n }\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("./_constants.cjs"),t=require("./template.cjs");var n=class e{entries=new Map;prefixes=new Set;get(e){return this.entries.get(e)}set(e,n){this.entries.set(e,{compiled:t.compileTemplate(n),message:n});let r=e.indexOf(`.`);for(;r!==-1;)this.prefixes.add(e.slice(0,r)),r=e.indexOf(`.`,r+1)}setAll(e){for(let[t,n]of e)this.set(t,n)}clone(){let t=new e;for(let[e,n]of this.entries)t.entries.set(e,n);for(let e of this.prefixes)t.prefixes.add(e);return t}};function r(n,i=new Map,a){for(let[o,s]of Object.entries(n)){if(e.UNSAFE_KEYS.has(o))continue;let n=a?`${a}.${o}`:o;if(typeof s==`string`){let e=t.parsePipePlural(s);e?r(e,i,n):i.set(n,s)}else r(s,i,n)}return i}exports.CatalogEntry=n,exports.flattenStrings=r;
|
|
2
|
+
//# sourceMappingURL=_catalog.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_catalog.cjs","names":[],"sources":["../src/_catalog.ts"],"sourcesContent":["// Internal — not part of the public API.\n// Encapsulates the CatalogEntry class, flattenStrings, and related utilities.\n\nimport { UNSAFE_KEYS } from './_constants';\nimport { compileTemplate, type CompiledTemplate, parsePipePlural } from './template';\n\nexport interface Messages {\n [key: string]: string | Messages;\n}\n\nexport type CatalogEntryData = {\n compiled: CompiledTemplate;\n message: string;\n};\n\nexport class CatalogEntry {\n readonly entries = new Map<string, CatalogEntryData>();\n readonly prefixes = new Set<string>();\n\n get(key: string): CatalogEntryData | undefined {\n return this.entries.get(key);\n }\n\n set(key: string, value: string): void {\n this.entries.set(key, { compiled: compileTemplate(value), message: value });\n\n // Populate prefix set for O(1) branch detection in has().\n let dot = key.indexOf('.');\n\n while (dot !== -1) {\n this.prefixes.add(key.slice(0, dot));\n dot = key.indexOf('.', dot + 1);\n }\n }\n\n setAll(flat: Iterable<[string, string]>): void {\n for (const [k, v] of flat) this.set(k, v);\n }\n\n clone(): CatalogEntry {\n const copy = new CatalogEntry();\n\n for (const [k, v] of this.entries) copy.entries.set(k, v);\n for (const p of this.prefixes) copy.prefixes.add(p);\n\n return copy;\n }\n}\n\nexport function flattenStrings(\n messages: Messages,\n result = new Map<string, string>(),\n prefix?: string,\n): Map<string, string> {\n for (const [key, value] of Object.entries(messages)) {\n if (UNSAFE_KEYS.has(key)) continue;\n\n const fullKey = prefix ? `${prefix}.${key}` : key;\n\n if (typeof value === 'string') {\n const plural = parsePipePlural(value);\n\n if (plural) {\n flattenStrings(plural, result, fullKey);\n } else {\n result.set(fullKey, value);\n }\n } else {\n flattenStrings(value as Messages, result, fullKey);\n }\n }\n\n return result;\n}\n"],"mappings":"gEAeA,IAAa,EAAb,MAAa,CAAa,CACxB,QAAmB,IAAI,IACvB,SAAoB,IAAI,IAExB,IAAI,EAA2C,CAC7C,OAAO,KAAK,QAAQ,IAAI,CAAG,CAC7B,CAEA,IAAI,EAAa,EAAqB,CACpC,KAAK,QAAQ,IAAI,EAAK,CAAE,SAAU,EAAA,gBAAgB,CAAK,EAAG,QAAS,CAAM,CAAC,EAG1E,IAAI,EAAM,EAAI,QAAQ,GAAG,EAEzB,KAAO,IAAQ,IACb,KAAK,SAAS,IAAI,EAAI,MAAM,EAAG,CAAG,CAAC,EACnC,EAAM,EAAI,QAAQ,IAAK,EAAM,CAAC,CAElC,CAEA,OAAO,EAAwC,CAC7C,IAAK,GAAM,CAAC,EAAG,KAAM,EAAM,KAAK,IAAI,EAAG,CAAC,CAC1C,CAEA,OAAsB,CACpB,IAAM,EAAO,IAAI,EAEjB,IAAK,GAAM,CAAC,EAAG,KAAM,KAAK,QAAS,EAAK,QAAQ,IAAI,EAAG,CAAC,EACxD,IAAK,IAAM,KAAK,KAAK,SAAU,EAAK,SAAS,IAAI,CAAC,EAElD,OAAO,CACT,CACF,EAEA,SAAgB,EACd,EACA,EAAS,IAAI,IACb,EACqB,CACrB,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,CAAQ,EAAG,CACnD,GAAI,EAAA,YAAY,IAAI,CAAG,EAAG,SAE1B,IAAM,EAAU,EAAS,GAAG,EAAO,GAAG,IAAQ,EAE9C,GAAI,OAAO,GAAU,SAAU,CAC7B,IAAM,EAAS,EAAA,gBAAgB,CAAK,EAEhC,EACF,EAAe,EAAQ,EAAQ,CAAO,EAEtC,EAAO,IAAI,EAAS,CAAK,CAE7B,MACE,EAAe,EAAmB,EAAQ,CAAO,CAErD,CAEA,OAAO,CACT"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type CompiledTemplate } from './template';
|
|
2
|
+
export interface Messages {
|
|
3
|
+
[key: string]: string | Messages;
|
|
4
|
+
}
|
|
5
|
+
export type CatalogEntryData = {
|
|
6
|
+
compiled: CompiledTemplate;
|
|
7
|
+
message: string;
|
|
8
|
+
};
|
|
9
|
+
export declare class CatalogEntry {
|
|
10
|
+
readonly entries: Map<string, CatalogEntryData>;
|
|
11
|
+
readonly prefixes: Set<string>;
|
|
12
|
+
get(key: string): CatalogEntryData | undefined;
|
|
13
|
+
set(key: string, value: string): void;
|
|
14
|
+
setAll(flat: Iterable<[string, string]>): void;
|
|
15
|
+
clone(): CatalogEntry;
|
|
16
|
+
}
|
|
17
|
+
export declare function flattenStrings(messages: Messages, result?: Map<string, string>, prefix?: string): Map<string, string>;
|
|
18
|
+
//# sourceMappingURL=_catalog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_catalog.d.ts","sourceRoot":"","sources":["../src/_catalog.ts"],"names":[],"mappings":"AAIA,OAAO,EAAmB,KAAK,gBAAgB,EAAmB,MAAM,YAAY,CAAC;AAErF,MAAM,WAAW,QAAQ;IACvB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;CAClC;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,qBAAa,YAAY;IACvB,QAAQ,CAAC,OAAO,gCAAuC;IACvD,QAAQ,CAAC,QAAQ,cAAqB;IAEtC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IAI9C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAYrC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,IAAI;IAI9C,KAAK,IAAI,YAAY;CAQtB;AAED,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,QAAQ,EAClB,MAAM,sBAA4B,EAClC,MAAM,CAAC,EAAE,MAAM,GACd,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAoBrB"}
|
package/dist/_catalog.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { UNSAFE_KEYS as e } from "./_constants.js";
|
|
2
|
+
import { compileTemplate as t, parsePipePlural as n } from "./template.js";
|
|
3
|
+
//#region src/_catalog.ts
|
|
4
|
+
var r = class e {
|
|
5
|
+
entries = /* @__PURE__ */ new Map();
|
|
6
|
+
prefixes = /* @__PURE__ */ new Set();
|
|
7
|
+
get(e) {
|
|
8
|
+
return this.entries.get(e);
|
|
9
|
+
}
|
|
10
|
+
set(e, n) {
|
|
11
|
+
this.entries.set(e, {
|
|
12
|
+
compiled: t(n),
|
|
13
|
+
message: n
|
|
14
|
+
});
|
|
15
|
+
let r = e.indexOf(".");
|
|
16
|
+
for (; r !== -1;) this.prefixes.add(e.slice(0, r)), r = e.indexOf(".", r + 1);
|
|
17
|
+
}
|
|
18
|
+
setAll(e) {
|
|
19
|
+
for (let [t, n] of e) this.set(t, n);
|
|
20
|
+
}
|
|
21
|
+
clone() {
|
|
22
|
+
let t = new e();
|
|
23
|
+
for (let [e, n] of this.entries) t.entries.set(e, n);
|
|
24
|
+
for (let e of this.prefixes) t.prefixes.add(e);
|
|
25
|
+
return t;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
function i(t, r = /* @__PURE__ */ new Map(), a) {
|
|
29
|
+
for (let [o, s] of Object.entries(t)) {
|
|
30
|
+
if (e.has(o)) continue;
|
|
31
|
+
let t = a ? `${a}.${o}` : o;
|
|
32
|
+
if (typeof s == "string") {
|
|
33
|
+
let e = n(s);
|
|
34
|
+
e ? i(e, r, t) : r.set(t, s);
|
|
35
|
+
} else i(s, r, t);
|
|
36
|
+
}
|
|
37
|
+
return r;
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
export { r as CatalogEntry, i as flattenStrings };
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=_catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_catalog.js","names":[],"sources":["../src/_catalog.ts"],"sourcesContent":["// Internal — not part of the public API.\n// Encapsulates the CatalogEntry class, flattenStrings, and related utilities.\n\nimport { UNSAFE_KEYS } from './_constants';\nimport { compileTemplate, type CompiledTemplate, parsePipePlural } from './template';\n\nexport interface Messages {\n [key: string]: string | Messages;\n}\n\nexport type CatalogEntryData = {\n compiled: CompiledTemplate;\n message: string;\n};\n\nexport class CatalogEntry {\n readonly entries = new Map<string, CatalogEntryData>();\n readonly prefixes = new Set<string>();\n\n get(key: string): CatalogEntryData | undefined {\n return this.entries.get(key);\n }\n\n set(key: string, value: string): void {\n this.entries.set(key, { compiled: compileTemplate(value), message: value });\n\n // Populate prefix set for O(1) branch detection in has().\n let dot = key.indexOf('.');\n\n while (dot !== -1) {\n this.prefixes.add(key.slice(0, dot));\n dot = key.indexOf('.', dot + 1);\n }\n }\n\n setAll(flat: Iterable<[string, string]>): void {\n for (const [k, v] of flat) this.set(k, v);\n }\n\n clone(): CatalogEntry {\n const copy = new CatalogEntry();\n\n for (const [k, v] of this.entries) copy.entries.set(k, v);\n for (const p of this.prefixes) copy.prefixes.add(p);\n\n return copy;\n }\n}\n\nexport function flattenStrings(\n messages: Messages,\n result = new Map<string, string>(),\n prefix?: string,\n): Map<string, string> {\n for (const [key, value] of Object.entries(messages)) {\n if (UNSAFE_KEYS.has(key)) continue;\n\n const fullKey = prefix ? `${prefix}.${key}` : key;\n\n if (typeof value === 'string') {\n const plural = parsePipePlural(value);\n\n if (plural) {\n flattenStrings(plural, result, fullKey);\n } else {\n result.set(fullKey, value);\n }\n } else {\n flattenStrings(value as Messages, result, fullKey);\n }\n }\n\n return result;\n}\n"],"mappings":";;;AAeA,IAAa,IAAb,MAAa,EAAa;CACxB,0BAAmB,IAAI,IAA8B;CACrD,2BAAoB,IAAI,IAAY;CAEpC,IAAI,GAA2C;EAC7C,OAAO,KAAK,QAAQ,IAAI,CAAG;CAC7B;CAEA,IAAI,GAAa,GAAqB;EACpC,KAAK,QAAQ,IAAI,GAAK;GAAE,UAAU,EAAgB,CAAK;GAAG,SAAS;EAAM,CAAC;EAG1E,IAAI,IAAM,EAAI,QAAQ,GAAG;EAEzB,OAAO,MAAQ,KAEb,AADA,KAAK,SAAS,IAAI,EAAI,MAAM,GAAG,CAAG,CAAC,GACnC,IAAM,EAAI,QAAQ,KAAK,IAAM,CAAC;CAElC;CAEA,OAAO,GAAwC;EAC7C,KAAK,IAAM,CAAC,GAAG,MAAM,GAAM,KAAK,IAAI,GAAG,CAAC;CAC1C;CAEA,QAAsB;EACpB,IAAM,IAAO,IAAI,EAAa;EAE9B,KAAK,IAAM,CAAC,GAAG,MAAM,KAAK,SAAS,EAAK,QAAQ,IAAI,GAAG,CAAC;EACxD,KAAK,IAAM,KAAK,KAAK,UAAU,EAAK,SAAS,IAAI,CAAC;EAElD,OAAO;CACT;AACF;AAEA,SAAgB,EACd,GACA,oBAAS,IAAI,IAAoB,GACjC,GACqB;CACrB,KAAK,IAAM,CAAC,GAAK,MAAU,OAAO,QAAQ,CAAQ,GAAG;EACnD,IAAI,EAAY,IAAI,CAAG,GAAG;EAE1B,IAAM,IAAU,IAAS,GAAG,EAAO,GAAG,MAAQ;EAE9C,IAAI,OAAO,KAAU,UAAU;GAC7B,IAAM,IAAS,EAAgB,CAAK;GAEpC,AAAI,IACF,EAAe,GAAQ,GAAQ,CAAO,IAEtC,EAAO,IAAI,GAAS,CAAK;EAE7B,OACE,EAAe,GAAmB,GAAQ,CAAO;CAErD;CAEA,OAAO;AACT"}
|
package/dist/_chain.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("./errors.cjs");function t(){return{canon:new Map,chain:new Map,plural:new Map}}function n(t,n){let r=n.canon.get(t);if(r!==void 0)return r;let i;try{[i]=Intl.getCanonicalLocales(t)}catch{}if(!i)throw new e.LinguaInvalidLocaleError(`Invalid BCP 47 locale tag: "${t}".`);return n.canon.set(t,i),i}function r(e,t,n,r){let i=`${e}:${n?`ordinal`:`cardinal`}`,a=r.plural.get(i);return a||(a=new Intl.PluralRules(e,{type:n?`ordinal`:`cardinal`}),r.plural.set(i,a)),a.select(t)}function i(e,t){let n=new Set;for(let r of[e,...t]){n.add(r);let e=r.split(`-`);for(let t=e.length-1;t>0;t--)n.add(e.slice(0,t).join(`-`))}return{chain:[...n],set:n}}function a(e,t,n){let r=t.length===0?e:`${e}|${t.join(`,`)}`,a=n.chain.get(r);if(a)return a;let o=i(e,t);return n.chain.set(r,o),o}exports.buildLocaleChain=a,exports.canon=n,exports.createLocaleCaches=t,exports.selectPluralForm=r;
|
|
2
|
+
//# sourceMappingURL=_chain.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_chain.cjs","names":[],"sources":["../src/_chain.ts"],"sourcesContent":["// Internal — not part of the public API.\n// Locale chain building, canonicalization, and plural-rules selection.\n// All caches are per-instance — no shared module-level state.\n\nimport { LinguaInvalidLocaleError } from './errors';\n\nexport type Locale = string;\n\n// ─── Per-instance caches ──────────────────────────────────────────────────────\n\nexport type LocaleCaches = {\n canon: Map<string, string>;\n chain: Map<string, { chain: Locale[]; set: Set<Locale> }>;\n plural: Map<string, Intl.PluralRules>;\n};\n\nexport function createLocaleCaches(): LocaleCaches {\n return { canon: new Map(), chain: new Map(), plural: new Map() };\n}\n\n// ─── Canon ────────────────────────────────────────────────────────────────────\n\nexport function canon(locale: string, cache: LocaleCaches): string {\n const cached = cache.canon.get(locale);\n\n if (cached !== undefined) return cached;\n\n let canonical: string | undefined;\n\n try {\n [canonical] = Intl.getCanonicalLocales(locale);\n } catch {\n // Invalid BCP 47 tag — canonical stays undefined, guard below throws.\n }\n\n if (!canonical) throw new LinguaInvalidLocaleError(`Invalid BCP 47 locale tag: \"${locale}\".`);\n\n cache.canon.set(locale, canonical);\n\n return canonical;\n}\n\n// ─── Plural form selection ────────────────────────────────────────────────────\n\nexport function selectPluralForm(locale: Locale, count: number, ordinal: boolean, cache: LocaleCaches): string {\n const key = `${locale}:${ordinal ? 'ordinal' : 'cardinal'}`;\n let rules = cache.plural.get(key);\n\n if (!rules) {\n rules = new Intl.PluralRules(locale, { type: ordinal ? 'ordinal' : 'cardinal' });\n cache.plural.set(key, rules);\n }\n\n return rules.select(count);\n}\n\n// ─── Locale chain ─────────────────────────────────────────────────────────────\n\nfunction buildLocaleChainRaw(locale: Locale, fallback: Locale[]): { chain: Locale[]; set: Set<Locale> } {\n const set = new Set<Locale>();\n\n for (const value of [locale, ...fallback]) {\n set.add(value);\n\n const parts = value.split('-');\n\n for (let i = parts.length - 1; i > 0; i--) {\n set.add(parts.slice(0, i).join('-'));\n }\n }\n\n return { chain: [...set], set };\n}\n\n/**\n * Build a locale fallback chain, memoized per `(locale, fallback)` key using a provided cache.\n * The cache is per-instance (lives on LocaleCaches) — no shared module-level state.\n */\nexport function buildLocaleChain(\n locale: Locale,\n fallback: Locale[],\n cache: LocaleCaches,\n): { chain: Locale[]; set: Set<Locale> } {\n const key = fallback.length === 0 ? locale : `${locale}|${fallback.join(',')}`;\n const cached = cache.chain.get(key);\n\n if (cached) return cached;\n\n const result = buildLocaleChainRaw(locale, fallback);\n\n cache.chain.set(key, result);\n\n return result;\n}\n"],"mappings":"gCAgBA,SAAgB,GAAmC,CACjD,MAAO,CAAE,MAAO,IAAI,IAAO,MAAO,IAAI,IAAO,OAAQ,IAAI,GAAM,CACjE,CAIA,SAAgB,EAAM,EAAgB,EAA6B,CACjE,IAAM,EAAS,EAAM,MAAM,IAAI,CAAM,EAErC,GAAI,IAAW,IAAA,GAAW,OAAO,EAEjC,IAAI,EAEJ,GAAI,CACF,CAAC,GAAa,KAAK,oBAAoB,CAAM,CAC/C,MAAQ,CAER,CAEA,GAAI,CAAC,EAAW,MAAM,IAAI,EAAA,yBAAyB,+BAA+B,EAAO,GAAG,EAI5F,OAFA,EAAM,MAAM,IAAI,EAAQ,CAAS,EAE1B,CACT,CAIA,SAAgB,EAAiB,EAAgB,EAAe,EAAkB,EAA6B,CAC7G,IAAM,EAAM,GAAG,EAAO,GAAG,EAAU,UAAY,aAC3C,EAAQ,EAAM,OAAO,IAAI,CAAG,EAOhC,OALK,IACH,EAAQ,IAAI,KAAK,YAAY,EAAQ,CAAE,KAAM,EAAU,UAAY,UAAW,CAAC,EAC/E,EAAM,OAAO,IAAI,EAAK,CAAK,GAGtB,EAAM,OAAO,CAAK,CAC3B,CAIA,SAAS,EAAoB,EAAgB,EAA2D,CACtG,IAAM,EAAM,IAAI,IAEhB,IAAK,IAAM,IAAS,CAAC,EAAQ,GAAG,CAAQ,EAAG,CACzC,EAAI,IAAI,CAAK,EAEb,IAAM,EAAQ,EAAM,MAAM,GAAG,EAE7B,IAAK,IAAI,EAAI,EAAM,OAAS,EAAG,EAAI,EAAG,IACpC,EAAI,IAAI,EAAM,MAAM,EAAG,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAEvC,CAEA,MAAO,CAAE,MAAO,CAAC,GAAG,CAAG,EAAG,KAAI,CAChC,CAMA,SAAgB,EACd,EACA,EACA,EACuC,CACvC,IAAM,EAAM,EAAS,SAAW,EAAI,EAAS,GAAG,EAAO,GAAG,EAAS,KAAK,GAAG,IACrE,EAAS,EAAM,MAAM,IAAI,CAAG,EAElC,GAAI,EAAQ,OAAO,EAEnB,IAAM,EAAS,EAAoB,EAAQ,CAAQ,EAInD,OAFA,EAAM,MAAM,IAAI,EAAK,CAAM,EAEpB,CACT"}
|
package/dist/_chain.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type Locale = string;
|
|
2
|
+
export type LocaleCaches = {
|
|
3
|
+
canon: Map<string, string>;
|
|
4
|
+
chain: Map<string, {
|
|
5
|
+
chain: Locale[];
|
|
6
|
+
set: Set<Locale>;
|
|
7
|
+
}>;
|
|
8
|
+
plural: Map<string, Intl.PluralRules>;
|
|
9
|
+
};
|
|
10
|
+
export declare function createLocaleCaches(): LocaleCaches;
|
|
11
|
+
export declare function canon(locale: string, cache: LocaleCaches): string;
|
|
12
|
+
export declare function selectPluralForm(locale: Locale, count: number, ordinal: boolean, cache: LocaleCaches): string;
|
|
13
|
+
/**
|
|
14
|
+
* Build a locale fallback chain, memoized per `(locale, fallback)` key using a provided cache.
|
|
15
|
+
* The cache is per-instance (lives on LocaleCaches) — no shared module-level state.
|
|
16
|
+
*/
|
|
17
|
+
export declare function buildLocaleChain(locale: Locale, fallback: Locale[], cache: LocaleCaches): {
|
|
18
|
+
chain: Locale[];
|
|
19
|
+
set: Set<Locale>;
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=_chain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_chain.d.ts","sourceRoot":"","sources":["../src/_chain.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC;AAI5B,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;KAAE,CAAC,CAAC;IAC1D,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;CACvC,CAAC;AAEF,wBAAgB,kBAAkB,IAAI,YAAY,CAEjD;AAID,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,MAAM,CAkBjE;AAID,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,GAAG,MAAM,CAU7G;AAoBD;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAAE,EAClB,KAAK,EAAE,YAAY,GAClB;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CAAE,CAWvC"}
|
package/dist/_chain.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { LinguaInvalidLocaleError as e } from "./errors.js";
|
|
2
|
+
//#region src/_chain.ts
|
|
3
|
+
function t() {
|
|
4
|
+
return {
|
|
5
|
+
canon: /* @__PURE__ */ new Map(),
|
|
6
|
+
chain: /* @__PURE__ */ new Map(),
|
|
7
|
+
plural: /* @__PURE__ */ new Map()
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
function n(t, n) {
|
|
11
|
+
let r = n.canon.get(t);
|
|
12
|
+
if (r !== void 0) return r;
|
|
13
|
+
let i;
|
|
14
|
+
try {
|
|
15
|
+
[i] = Intl.getCanonicalLocales(t);
|
|
16
|
+
} catch {}
|
|
17
|
+
if (!i) throw new e(`Invalid BCP 47 locale tag: "${t}".`);
|
|
18
|
+
return n.canon.set(t, i), i;
|
|
19
|
+
}
|
|
20
|
+
function r(e, t, n, r) {
|
|
21
|
+
let i = `${e}:${n ? "ordinal" : "cardinal"}`, a = r.plural.get(i);
|
|
22
|
+
return a || (a = new Intl.PluralRules(e, { type: n ? "ordinal" : "cardinal" }), r.plural.set(i, a)), a.select(t);
|
|
23
|
+
}
|
|
24
|
+
function i(e, t) {
|
|
25
|
+
let n = /* @__PURE__ */ new Set();
|
|
26
|
+
for (let r of [e, ...t]) {
|
|
27
|
+
n.add(r);
|
|
28
|
+
let e = r.split("-");
|
|
29
|
+
for (let t = e.length - 1; t > 0; t--) n.add(e.slice(0, t).join("-"));
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
chain: [...n],
|
|
33
|
+
set: n
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function a(e, t, n) {
|
|
37
|
+
let r = t.length === 0 ? e : `${e}|${t.join(",")}`, a = n.chain.get(r);
|
|
38
|
+
if (a) return a;
|
|
39
|
+
let o = i(e, t);
|
|
40
|
+
return n.chain.set(r, o), o;
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
export { a as buildLocaleChain, n as canon, t as createLocaleCaches, r as selectPluralForm };
|
|
44
|
+
|
|
45
|
+
//# sourceMappingURL=_chain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_chain.js","names":[],"sources":["../src/_chain.ts"],"sourcesContent":["// Internal — not part of the public API.\n// Locale chain building, canonicalization, and plural-rules selection.\n// All caches are per-instance — no shared module-level state.\n\nimport { LinguaInvalidLocaleError } from './errors';\n\nexport type Locale = string;\n\n// ─── Per-instance caches ──────────────────────────────────────────────────────\n\nexport type LocaleCaches = {\n canon: Map<string, string>;\n chain: Map<string, { chain: Locale[]; set: Set<Locale> }>;\n plural: Map<string, Intl.PluralRules>;\n};\n\nexport function createLocaleCaches(): LocaleCaches {\n return { canon: new Map(), chain: new Map(), plural: new Map() };\n}\n\n// ─── Canon ────────────────────────────────────────────────────────────────────\n\nexport function canon(locale: string, cache: LocaleCaches): string {\n const cached = cache.canon.get(locale);\n\n if (cached !== undefined) return cached;\n\n let canonical: string | undefined;\n\n try {\n [canonical] = Intl.getCanonicalLocales(locale);\n } catch {\n // Invalid BCP 47 tag — canonical stays undefined, guard below throws.\n }\n\n if (!canonical) throw new LinguaInvalidLocaleError(`Invalid BCP 47 locale tag: \"${locale}\".`);\n\n cache.canon.set(locale, canonical);\n\n return canonical;\n}\n\n// ─── Plural form selection ────────────────────────────────────────────────────\n\nexport function selectPluralForm(locale: Locale, count: number, ordinal: boolean, cache: LocaleCaches): string {\n const key = `${locale}:${ordinal ? 'ordinal' : 'cardinal'}`;\n let rules = cache.plural.get(key);\n\n if (!rules) {\n rules = new Intl.PluralRules(locale, { type: ordinal ? 'ordinal' : 'cardinal' });\n cache.plural.set(key, rules);\n }\n\n return rules.select(count);\n}\n\n// ─── Locale chain ─────────────────────────────────────────────────────────────\n\nfunction buildLocaleChainRaw(locale: Locale, fallback: Locale[]): { chain: Locale[]; set: Set<Locale> } {\n const set = new Set<Locale>();\n\n for (const value of [locale, ...fallback]) {\n set.add(value);\n\n const parts = value.split('-');\n\n for (let i = parts.length - 1; i > 0; i--) {\n set.add(parts.slice(0, i).join('-'));\n }\n }\n\n return { chain: [...set], set };\n}\n\n/**\n * Build a locale fallback chain, memoized per `(locale, fallback)` key using a provided cache.\n * The cache is per-instance (lives on LocaleCaches) — no shared module-level state.\n */\nexport function buildLocaleChain(\n locale: Locale,\n fallback: Locale[],\n cache: LocaleCaches,\n): { chain: Locale[]; set: Set<Locale> } {\n const key = fallback.length === 0 ? locale : `${locale}|${fallback.join(',')}`;\n const cached = cache.chain.get(key);\n\n if (cached) return cached;\n\n const result = buildLocaleChainRaw(locale, fallback);\n\n cache.chain.set(key, result);\n\n return result;\n}\n"],"mappings":";;AAgBA,SAAgB,IAAmC;CACjD,OAAO;EAAE,uBAAO,IAAI,IAAI;EAAG,uBAAO,IAAI,IAAI;EAAG,wBAAQ,IAAI,IAAI;CAAE;AACjE;AAIA,SAAgB,EAAM,GAAgB,GAA6B;CACjE,IAAM,IAAS,EAAM,MAAM,IAAI,CAAM;CAErC,IAAI,MAAW,KAAA,GAAW,OAAO;CAEjC,IAAI;CAEJ,IAAI;EACF,CAAC,KAAa,KAAK,oBAAoB,CAAM;CAC/C,QAAQ,CAER;CAEA,IAAI,CAAC,GAAW,MAAM,IAAI,EAAyB,+BAA+B,EAAO,GAAG;CAI5F,OAFA,EAAM,MAAM,IAAI,GAAQ,CAAS,GAE1B;AACT;AAIA,SAAgB,EAAiB,GAAgB,GAAe,GAAkB,GAA6B;CAC7G,IAAM,IAAM,GAAG,EAAO,GAAG,IAAU,YAAY,cAC3C,IAAQ,EAAM,OAAO,IAAI,CAAG;CAOhC,OALK,MACH,IAAQ,IAAI,KAAK,YAAY,GAAQ,EAAE,MAAM,IAAU,YAAY,WAAW,CAAC,GAC/E,EAAM,OAAO,IAAI,GAAK,CAAK,IAGtB,EAAM,OAAO,CAAK;AAC3B;AAIA,SAAS,EAAoB,GAAgB,GAA2D;CACtG,IAAM,oBAAM,IAAI,IAAY;CAE5B,KAAK,IAAM,KAAS,CAAC,GAAQ,GAAG,CAAQ,GAAG;EACzC,EAAI,IAAI,CAAK;EAEb,IAAM,IAAQ,EAAM,MAAM,GAAG;EAE7B,KAAK,IAAI,IAAI,EAAM,SAAS,GAAG,IAAI,GAAG,KACpC,EAAI,IAAI,EAAM,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC;CAEvC;CAEA,OAAO;EAAE,OAAO,CAAC,GAAG,CAAG;EAAG;CAAI;AAChC;AAMA,SAAgB,EACd,GACA,GACA,GACuC;CACvC,IAAM,IAAM,EAAS,WAAW,IAAI,IAAS,GAAG,EAAO,GAAG,EAAS,KAAK,GAAG,KACrE,IAAS,EAAM,MAAM,IAAI,CAAG;CAElC,IAAI,GAAQ,OAAO;CAEnB,IAAM,IAAS,EAAoB,GAAQ,CAAQ;CAInD,OAFA,EAAM,MAAM,IAAI,GAAK,CAAM,GAEpB;AACT"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_constants.cjs","names":[],"sources":["../src/_constants.ts"],"sourcesContent":["// Shared constants used by both i18n.ts and validate.ts.\n// Not part of the public API — internal module only.\n\nexport const UNSAFE_KEYS = new Set(['__proto__', 'constructor', 'prototype']);\n\nexport const CLDR_FORMS = new Set(['zero', 'one', 'two', 'few', 'many', 'other']);\n"],"mappings":"AAGA,IAAa,EAAc,IAAI,IAAI,CAAC,YAAa,cAAe,WAAW,CAAC,EAE/D,EAAa,IAAI,IAAI,CAAC,OAAQ,MAAO,MAAO,MAAO,OAAQ,OAAO,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_constants.d.ts","sourceRoot":"","sources":["../src/_constants.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,WAAW,aAAqD,CAAC;AAE9E,eAAO,MAAM,UAAU,aAA0D,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/_constants.ts
|
|
2
|
+
var e = /* @__PURE__ */ new Set([
|
|
3
|
+
"__proto__",
|
|
4
|
+
"constructor",
|
|
5
|
+
"prototype"
|
|
6
|
+
]), t = /* @__PURE__ */ new Set([
|
|
7
|
+
"zero",
|
|
8
|
+
"one",
|
|
9
|
+
"two",
|
|
10
|
+
"few",
|
|
11
|
+
"many",
|
|
12
|
+
"other"
|
|
13
|
+
]);
|
|
14
|
+
//#endregion
|
|
15
|
+
export { t as CLDR_FORMS, e as UNSAFE_KEYS };
|
|
16
|
+
|
|
17
|
+
//# sourceMappingURL=_constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_constants.js","names":[],"sources":["../src/_constants.ts"],"sourcesContent":["// Shared constants used by both i18n.ts and validate.ts.\n// Not part of the public API — internal module only.\n\nexport const UNSAFE_KEYS = new Set(['__proto__', 'constructor', 'prototype']);\n\nexport const CLDR_FORMS = new Set(['zero', 'one', 'two', 'few', 'many', 'other']);\n"],"mappings":";AAGA,IAAa,oBAAc,IAAI,IAAI;CAAC;CAAa;CAAe;AAAW,CAAC,GAE/D,oBAAa,IAAI,IAAI;CAAC;CAAQ;CAAO;CAAO;CAAO;CAAQ;AAAO,CAAC"}
|
package/dist/_dev.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_dev.cjs","names":[],"sources":["../src/_dev.ts"],"sourcesContent":["const isDev = !(globalThis as { __LINGUA_PROD__?: boolean }).__LINGUA_PROD__;\n\n/** @internal @security Messages may include user-supplied data. */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/lingua] ${msg}`);\n}\n\n/** @internal */\nexport function error(msg: string, ...args: unknown[]): void {\n if (isDev) console.error(`[@vielzeug/lingua] ${msg}`, ...args);\n}\n\n/** @internal — Run fn only in dev builds. Use when dev-only logic goes beyond a single warn() / error() call. */\nexport function devOnly(fn: () => void): void {\n if (isDev) fn();\n}\n"],"mappings":"AAAA,IAAM,EAAQ,CAAE,WAA6C,gBAG7D,SAAgB,EAAK,EAAmB,CAClC,GAAO,QAAQ,KAAK,sBAAsB,GAAK,CACrD,CAGA,SAAgB,EAAM,EAAa,GAAG,EAAuB,CACvD,GAAO,QAAQ,MAAM,sBAAsB,IAAO,GAAG,CAAI,CAC/D"}
|
package/dist/_dev.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_dev.d.ts","sourceRoot":"","sources":["../src/_dev.ts"],"names":[],"mappings":""}
|
package/dist/_dev.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/_dev.ts
|
|
2
|
+
var e = !globalThis.__LINGUA_PROD__;
|
|
3
|
+
function t(t) {
|
|
4
|
+
e && console.warn(`[@vielzeug/lingua] ${t}`);
|
|
5
|
+
}
|
|
6
|
+
function n(t, ...n) {
|
|
7
|
+
e && console.error(`[@vielzeug/lingua] ${t}`, ...n);
|
|
8
|
+
}
|
|
9
|
+
//#endregion
|
|
10
|
+
export { n as error, t as warn };
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=_dev.js.map
|
package/dist/_dev.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_dev.js","names":[],"sources":["../src/_dev.ts"],"sourcesContent":["const isDev = !(globalThis as { __LINGUA_PROD__?: boolean }).__LINGUA_PROD__;\n\n/** @internal @security Messages may include user-supplied data. */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/lingua] ${msg}`);\n}\n\n/** @internal */\nexport function error(msg: string, ...args: unknown[]): void {\n if (isDev) console.error(`[@vielzeug/lingua] ${msg}`, ...args);\n}\n\n/** @internal — Run fn only in dev builds. Use when dev-only logic goes beyond a single warn() / error() call. */\nexport function devOnly(fn: () => void): void {\n if (isDev) fn();\n}\n"],"mappings":";AAAA,IAAM,IAAQ,CAAE,WAA6C;AAG7D,SAAgB,EAAK,GAAmB;CACtC,AAAI,KAAO,QAAQ,KAAK,sBAAsB,GAAK;AACrD;AAGA,SAAgB,EAAM,GAAa,GAAG,GAAuB;CAC3D,AAAI,KAAO,QAAQ,MAAM,sBAAsB,KAAO,GAAG,CAAI;AAC/D"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("./errors.cjs");function t(t){let n=new Map,r=new Map,i=new Map;return{clearLocale(e){let t=[];for(let[n,i]of r.entries())i.delete(e)&&t.push(n);return t},dispose(){n.clear(),r.clear(),i.clear()},isLoaded(e,t){return r.get(e)?.has(t)??!1},isRegistered(e){return n.has(e)},loadNamespace(a,o,s){let c=e.checkDisposedAsync(t());if(c)return c;let l=n.get(a);if(!l)return Promise.reject(new e.LinguaNamespaceMissingError(`Namespace '${a}' is not registered. Call registerNamespace() first.`));if(r.get(a)?.has(o))return Promise.resolve();let u=i.get(a)?.get(o);if(u)return u;let d=l(o).then(e=>s(o,e)).then(()=>{let e=r.get(a);e||(e=new Set,r.set(a,e)),e.add(o),i.get(a)?.delete(o)},e=>{throw i.get(a)?.delete(o),e});return i.has(a)||i.set(a,new Map),i.get(a).set(o,d),d},registerNamespace(r,i){e.checkDisposed(t()),n.set(r,i)},seedFrom(e){for(let[t,r]of e.snapshotRegistry())n.set(t,r);for(let[t,n]of e.snapshotLoaded())r.set(t,new Set(n))},snapshotLoaded(){return r},snapshotRegistry(){return n}}}exports.createNamespaceStore=t;
|
|
2
|
+
//# sourceMappingURL=_namespace-store.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_namespace-store.cjs","names":[],"sources":["../src/_namespace-store.ts"],"sourcesContent":["// Internal — not part of the public API.\n// Owns namespace factory registry, per-locale loaded markers, and in-flight namespace tasks.\n\nimport type { Messages } from './_catalog';\n\nimport { LinguaNamespaceMissingError, checkDisposed, checkDisposedAsync } from './errors';\n\nexport type Locale = string;\nexport type NamespaceFactory<M extends Messages = Messages> = (locale: Locale) => Promise<M>;\n\nexport type NamespaceStore<M extends Messages = Messages> = {\n /**\n * Remove loaded-markers for a locale across all namespaces.\n * Called by CatalogStore.register() when a catalog is replaced.\n * Returns the list of namespace names whose markers were cleared.\n */\n clearLocale(loc: Locale): string[];\n dispose(): void;\n /** Returns true if the namespace has been loaded for the given locale. */\n isLoaded(ns: string, loc: Locale): boolean;\n /** Returns true if the namespace factory is registered. */\n isRegistered(ns: string): boolean;\n /**\n * Load a namespace for the given locale. Deduplicates concurrent and repeated calls.\n * The `patch` callback is responsible for merging the loaded messages into the catalog.\n */\n loadNamespace(ns: string, loc: Locale, patch: (loc: Locale, messages: Messages) => Promise<void>): Promise<void>;\n /** Register a namespace factory. Idempotent — re-registration updates the factory for future loads. */\n registerNamespace(ns: string, factory: NamespaceFactory<M>): void;\n /** Seed from a parent instance (fork). Copies loaded markers; registry is shared by reference. */\n seedFrom(parent: NamespaceStore<M>): void;\n /** Snapshot of loaded markers for fork() */\n snapshotLoaded(): ReadonlyMap<string, ReadonlySet<string>>;\n /** Snapshot of the registry for fork() */\n snapshotRegistry(): ReadonlyMap<string, NamespaceFactory<M>>;\n};\n\nexport function createNamespaceStore<M extends Messages = Messages>(disposed: () => boolean): NamespaceStore<M> {\n const registry = new Map<string, NamespaceFactory<M>>();\n // Two-level: Map<namespace, Set<locale>>\n const loaded = new Map<string, Set<string>>();\n const tasks = new Map<string, Map<string, Promise<void>>>();\n\n return {\n clearLocale(loc) {\n const cleared: string[] = [];\n\n for (const [ns, localeSet] of loaded.entries()) {\n if (localeSet.delete(loc)) cleared.push(ns);\n }\n\n return cleared;\n },\n\n dispose() {\n registry.clear();\n loaded.clear();\n tasks.clear();\n },\n\n isLoaded(ns, loc) {\n return loaded.get(ns)?.has(loc) ?? false;\n },\n\n isRegistered(ns) {\n return registry.has(ns);\n },\n\n loadNamespace(ns, loc, patch) {\n const early = checkDisposedAsync(disposed());\n\n if (early) return early;\n\n const factory = registry.get(ns);\n\n if (!factory) {\n return Promise.reject(\n new LinguaNamespaceMissingError(`Namespace '${ns}' is not registered. Call registerNamespace() first.`),\n );\n }\n\n if (loaded.get(ns)?.has(loc)) return Promise.resolve();\n\n const nsTasks = tasks.get(ns);\n const existing = nsTasks?.get(loc);\n\n if (existing) return existing;\n\n const task = factory(loc)\n .then((messages) => patch(loc, messages as Messages))\n .then(\n () => {\n let localeSet = loaded.get(ns);\n\n if (!localeSet) {\n localeSet = new Set();\n loaded.set(ns, localeSet);\n }\n\n localeSet.add(loc);\n tasks.get(ns)?.delete(loc);\n },\n (err: unknown) => {\n tasks.get(ns)?.delete(loc);\n throw err;\n },\n );\n\n if (!tasks.has(ns)) tasks.set(ns, new Map());\n\n tasks.get(ns)!.set(loc, task);\n\n return task;\n },\n\n registerNamespace(ns, factory) {\n checkDisposed(disposed());\n registry.set(ns, factory);\n },\n\n seedFrom(parent) {\n for (const [ns, factory] of parent.snapshotRegistry()) {\n registry.set(ns, factory);\n }\n\n for (const [ns, localeSet] of parent.snapshotLoaded()) {\n loaded.set(ns, new Set(localeSet));\n }\n },\n\n snapshotLoaded() {\n return loaded as ReadonlyMap<string, ReadonlySet<string>>;\n },\n\n snapshotRegistry() {\n return registry as ReadonlyMap<string, NamespaceFactory<M>>;\n },\n };\n}\n"],"mappings":"gCAqCA,SAAgB,EAAoD,EAA4C,CAC9G,IAAM,EAAW,IAAI,IAEf,EAAS,IAAI,IACb,EAAQ,IAAI,IAElB,MAAO,CACL,YAAY,EAAK,CACf,IAAM,EAAoB,CAAC,EAE3B,IAAK,GAAM,CAAC,EAAI,KAAc,EAAO,QAAQ,EACvC,EAAU,OAAO,CAAG,GAAG,EAAQ,KAAK,CAAE,EAG5C,OAAO,CACT,EAEA,SAAU,CACR,EAAS,MAAM,EACf,EAAO,MAAM,EACb,EAAM,MAAM,CACd,EAEA,SAAS,EAAI,EAAK,CAChB,OAAO,EAAO,IAAI,CAAE,CAAC,EAAE,IAAI,CAAG,GAAK,EACrC,EAEA,aAAa,EAAI,CACf,OAAO,EAAS,IAAI,CAAE,CACxB,EAEA,cAAc,EAAI,EAAK,EAAO,CAC5B,IAAM,EAAQ,EAAA,mBAAmB,EAAS,CAAC,EAE3C,GAAI,EAAO,OAAO,EAElB,IAAM,EAAU,EAAS,IAAI,CAAE,EAE/B,GAAI,CAAC,EACH,OAAO,QAAQ,OACb,IAAI,EAAA,4BAA4B,cAAc,EAAG,qDAAqD,CACxG,EAGF,GAAI,EAAO,IAAI,CAAE,CAAC,EAAE,IAAI,CAAG,EAAG,OAAO,QAAQ,QAAQ,EAGrD,IAAM,EADU,EAAM,IAAI,CACT,CAAA,EAAS,IAAI,CAAG,EAEjC,GAAI,EAAU,OAAO,EAErB,IAAM,EAAO,EAAQ,CAAG,CAAC,CACtB,KAAM,GAAa,EAAM,EAAK,CAAoB,CAAC,CAAC,CACpD,SACO,CACJ,IAAI,EAAY,EAAO,IAAI,CAAE,EAExB,IACH,EAAY,IAAI,IAChB,EAAO,IAAI,EAAI,CAAS,GAG1B,EAAU,IAAI,CAAG,EACjB,EAAM,IAAI,CAAE,CAAC,EAAE,OAAO,CAAG,CAC3B,EACC,GAAiB,CAEhB,MADA,EAAM,IAAI,CAAE,CAAC,EAAE,OAAO,CAAG,EACnB,CACR,CACF,EAMF,OAJK,EAAM,IAAI,CAAE,GAAG,EAAM,IAAI,EAAI,IAAI,GAAK,EAE3C,EAAM,IAAI,CAAE,CAAC,CAAE,IAAI,EAAK,CAAI,EAErB,CACT,EAEA,kBAAkB,EAAI,EAAS,CAC7B,EAAA,cAAc,EAAS,CAAC,EACxB,EAAS,IAAI,EAAI,CAAO,CAC1B,EAEA,SAAS,EAAQ,CACf,IAAK,GAAM,CAAC,EAAI,KAAY,EAAO,iBAAiB,EAClD,EAAS,IAAI,EAAI,CAAO,EAG1B,IAAK,GAAM,CAAC,EAAI,KAAc,EAAO,eAAe,EAClD,EAAO,IAAI,EAAI,IAAI,IAAI,CAAS,CAAC,CAErC,EAEA,gBAAiB,CACf,OAAO,CACT,EAEA,kBAAmB,CACjB,OAAO,CACT,CACF,CACF"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Messages } from './_catalog';
|
|
2
|
+
export type Locale = string;
|
|
3
|
+
export type NamespaceFactory<M extends Messages = Messages> = (locale: Locale) => Promise<M>;
|
|
4
|
+
export type NamespaceStore<M extends Messages = Messages> = {
|
|
5
|
+
/**
|
|
6
|
+
* Remove loaded-markers for a locale across all namespaces.
|
|
7
|
+
* Called by CatalogStore.register() when a catalog is replaced.
|
|
8
|
+
* Returns the list of namespace names whose markers were cleared.
|
|
9
|
+
*/
|
|
10
|
+
clearLocale(loc: Locale): string[];
|
|
11
|
+
dispose(): void;
|
|
12
|
+
/** Returns true if the namespace has been loaded for the given locale. */
|
|
13
|
+
isLoaded(ns: string, loc: Locale): boolean;
|
|
14
|
+
/** Returns true if the namespace factory is registered. */
|
|
15
|
+
isRegistered(ns: string): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Load a namespace for the given locale. Deduplicates concurrent and repeated calls.
|
|
18
|
+
* The `patch` callback is responsible for merging the loaded messages into the catalog.
|
|
19
|
+
*/
|
|
20
|
+
loadNamespace(ns: string, loc: Locale, patch: (loc: Locale, messages: Messages) => Promise<void>): Promise<void>;
|
|
21
|
+
/** Register a namespace factory. Idempotent — re-registration updates the factory for future loads. */
|
|
22
|
+
registerNamespace(ns: string, factory: NamespaceFactory<M>): void;
|
|
23
|
+
/** Seed from a parent instance (fork). Copies loaded markers; registry is shared by reference. */
|
|
24
|
+
seedFrom(parent: NamespaceStore<M>): void;
|
|
25
|
+
/** Snapshot of loaded markers for fork() */
|
|
26
|
+
snapshotLoaded(): ReadonlyMap<string, ReadonlySet<string>>;
|
|
27
|
+
/** Snapshot of the registry for fork() */
|
|
28
|
+
snapshotRegistry(): ReadonlyMap<string, NamespaceFactory<M>>;
|
|
29
|
+
};
|
|
30
|
+
export declare function createNamespaceStore<M extends Messages = Messages>(disposed: () => boolean): NamespaceStore<M>;
|
|
31
|
+
//# sourceMappingURL=_namespace-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_namespace-store.d.ts","sourceRoot":"","sources":["../src/_namespace-store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI3C,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC;AAC5B,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,IAAI,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;AAE7F,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,IAAI;IAC1D;;;;OAIG;IACH,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACnC,OAAO,IAAI,IAAI,CAAC;IAChB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3C,2DAA2D;IAC3D,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;IAClC;;;OAGG;IACH,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjH,uGAAuG;IACvG,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAClE,kGAAkG;IAClG,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAC1C,4CAA4C;IAC5C,cAAc,IAAI,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;IAC3D,0CAA0C;IAC1C,gBAAgB,IAAI,WAAW,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;CAC9D,CAAC;AAEF,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,EAAE,QAAQ,EAAE,MAAM,OAAO,GAAG,cAAc,CAAC,CAAC,CAAC,CAqG9G"}
|