@vielzeug/lingua 1.1.3 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -54
- package/dist/_bounded-cache.cjs +2 -0
- package/dist/_bounded-cache.cjs.map +1 -0
- package/dist/_bounded-cache.d.ts +2 -0
- package/dist/_bounded-cache.d.ts.map +1 -0
- package/dist/_bounded-cache.js +10 -0
- package/dist/_bounded-cache.js.map +1 -0
- package/dist/_catalog.cjs +1 -1
- package/dist/_catalog.cjs.map +1 -1
- package/dist/_catalog.d.ts +13 -16
- package/dist/_catalog.d.ts.map +1 -1
- package/dist/_catalog.js +43 -36
- package/dist/_catalog.js.map +1 -1
- package/dist/_dev.cjs +1 -1
- package/dist/_dev.cjs.map +1 -1
- package/dist/_dev.js +3 -8
- package/dist/_dev.js.map +1 -1
- package/dist/_locale.cjs +2 -0
- package/dist/_locale.cjs.map +1 -0
- package/dist/_locale.d.ts +5 -0
- package/dist/_locale.d.ts.map +1 -0
- package/dist/_locale.js +26 -0
- package/dist/_locale.js.map +1 -0
- package/dist/_resources.cjs +2 -0
- package/dist/_resources.cjs.map +1 -0
- package/dist/_resources.d.ts +10 -0
- package/dist/_resources.d.ts.map +1 -0
- package/dist/_resources.js +51 -0
- package/dist/_resources.js.map +1 -0
- package/dist/_template.cjs +2 -0
- package/dist/_template.cjs.map +1 -0
- package/dist/_template.d.ts +8 -0
- package/dist/_template.d.ts.map +1 -0
- package/dist/_template.js +32 -0
- package/dist/_template.js.map +1 -0
- package/dist/errors.cjs +1 -1
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.ts +6 -18
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +3 -9
- package/dist/errors.js.map +1 -1
- package/dist/format.cjs +1 -1
- package/dist/format.cjs.map +1 -1
- package/dist/format.d.ts +0 -9
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +40 -46
- package/dist/format.js.map +1 -1
- package/dist/i18n.cjs +1 -1
- package/dist/i18n.cjs.map +1 -1
- package/dist/i18n.d.ts +25 -39
- package/dist/i18n.d.ts.map +1 -1
- package/dist/i18n.js +65 -218
- package/dist/i18n.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +4 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/lingua.cjs +1 -1
- package/dist/lingua.cjs.map +1 -1
- package/dist/lingua.iife.js +1 -1
- package/dist/lingua.iife.js.map +1 -1
- package/dist/lingua.js +1 -1
- package/dist/lingua.js.map +1 -1
- package/dist/translator.cjs +2 -0
- package/dist/translator.cjs.map +1 -0
- package/dist/translator.d.ts +20 -0
- package/dist/translator.d.ts.map +1 -0
- package/dist/translator.js +61 -0
- package/dist/translator.js.map +1 -0
- package/dist/types.d.ts +53 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/validate.cjs +1 -1
- package/dist/validate.cjs.map +1 -1
- package/dist/validate.d.ts +5 -36
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +21 -52
- package/dist/validate.js.map +1 -1
- package/package.json +4 -4
- package/dist/_catalog-store.cjs +0 -2
- package/dist/_catalog-store.cjs.map +0 -1
- package/dist/_catalog-store.d.ts +0 -33
- package/dist/_catalog-store.d.ts.map +0 -1
- package/dist/_catalog-store.js +0 -74
- package/dist/_catalog-store.js.map +0 -1
- package/dist/_chain.cjs +0 -2
- package/dist/_chain.cjs.map +0 -1
- package/dist/_chain.d.ts +0 -21
- package/dist/_chain.d.ts.map +0 -1
- package/dist/_chain.js +0 -45
- package/dist/_chain.js.map +0 -1
- package/dist/_constants.cjs +0 -2
- package/dist/_constants.cjs.map +0 -1
- package/dist/_constants.d.ts +0 -3
- package/dist/_constants.d.ts.map +0 -1
- package/dist/_constants.js +0 -17
- package/dist/_constants.js.map +0 -1
- package/dist/_namespace-store.cjs +0 -2
- package/dist/_namespace-store.cjs.map +0 -1
- package/dist/_namespace-store.d.ts +0 -31
- package/dist/_namespace-store.d.ts.map +0 -1
- package/dist/_namespace-store.js +0 -54
- package/dist/_namespace-store.js.map +0 -1
- package/dist/i18n-types.d.ts +0 -250
- package/dist/i18n-types.d.ts.map +0 -1
- package/dist/template.cjs +0 -2
- package/dist/template.cjs.map +0 -1
- package/dist/template.d.ts +0 -15
- package/dist/template.d.ts.map +0 -1
- package/dist/template.js +0 -49
- package/dist/template.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,86 +1,47 @@
|
|
|
1
1
|
# @vielzeug/lingua
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Explicit, framework-neutral localization for TypeScript.
|
|
4
4
|
|
|
5
|
-
|
|
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.
|
|
5
|
+
`@vielzeug/lingua` provides an immutable translator for fixed locales and a stateful i18n store for locale changes and optional lazy catalogs.
|
|
21
6
|
|
|
22
7
|
## Installation
|
|
23
8
|
|
|
24
9
|
```sh
|
|
25
10
|
pnpm add @vielzeug/lingua
|
|
26
|
-
npm install @vielzeug/lingua
|
|
27
|
-
yarn add @vielzeug/lingua
|
|
28
11
|
```
|
|
29
12
|
|
|
30
13
|
## Quick Start
|
|
31
14
|
|
|
32
15
|
```ts
|
|
33
|
-
import {
|
|
34
|
-
import { createFormatter } from '@vielzeug/lingua/format';
|
|
16
|
+
import { createTranslationStore } from '@vielzeug/lingua';
|
|
35
17
|
|
|
36
|
-
const
|
|
37
|
-
locale: 'en',
|
|
38
|
-
fallback: 'en',
|
|
18
|
+
const translations = createTranslationStore({
|
|
39
19
|
catalogs: {
|
|
40
20
|
en: {
|
|
41
21
|
greeting: 'Hello, {name}!',
|
|
42
|
-
inbox: {
|
|
43
|
-
zero: 'No messages',
|
|
44
|
-
one: 'One message',
|
|
45
|
-
other: '{count} messages',
|
|
46
|
-
},
|
|
22
|
+
inbox: { plural: { one: 'One message', other: '{count} messages' } },
|
|
47
23
|
},
|
|
48
|
-
de: () => import('./locales/de.json').then((m) => m.default),
|
|
49
24
|
},
|
|
25
|
+
locale: 'en',
|
|
50
26
|
});
|
|
51
27
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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));
|
|
28
|
+
translations.translate('greeting', { values: { name: 'Ada' } });
|
|
29
|
+
translations.translate('inbox', { count: 3 });
|
|
30
|
+
```
|
|
68
31
|
|
|
69
|
-
|
|
70
|
-
const reqI18n = i18n.fork({ locale: req.locale });
|
|
32
|
+
## Exports
|
|
71
33
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
34
|
+
- `createTranslator` — immutable translation engine for fixed-locale catalogs.
|
|
35
|
+
- `createTranslationStore` / `hydrateTranslationStore` — mutable locale state, lazy catalog loading, and SSR state.
|
|
36
|
+
- `createFormatter` from `@vielzeug/lingua/format`.
|
|
37
|
+
- `validateCatalog` from `@vielzeug/lingua/validate`.
|
|
76
38
|
|
|
77
39
|
## Documentation
|
|
78
40
|
|
|
79
41
|
- [Overview](https://vielzeug.dev/lingua/)
|
|
80
42
|
- [Usage Guide](https://vielzeug.dev/lingua/usage)
|
|
81
43
|
- [API Reference](https://vielzeug.dev/lingua/api)
|
|
82
|
-
- [Examples](https://vielzeug.dev/lingua/examples)
|
|
83
44
|
|
|
84
45
|
## License
|
|
85
46
|
|
|
86
|
-
MIT ©
|
|
47
|
+
MIT © Helmuth Saatkamp
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_bounded-cache.cjs","names":[],"sources":["../src/_bounded-cache.ts"],"sourcesContent":["// Internal — not part of the public API.\n// Minimal bounded cache: evicts the oldest entry (insertion order) once `maxSize` is exceeded.\n// Not LRU — no access-time reordering, only insertion order matters. These caches exist purely\n// to avoid rebuilding cheap-but-not-free values (compiled `Intl` formatters, scoped translator\n// objects) for a bounded number of frequently-reused keys, not to model real recency.\n\nexport function getOrCreate<K, V>(cache: Map<K, V>, key: K, maxSize: number, build: () => V): V {\n if (cache.has(key)) return cache.get(key)!;\n\n const value = build();\n\n if (cache.size >= maxSize) cache.delete(cache.keys().next().value as K);\n\n cache.set(key, value);\n\n return value;\n}\n"],"mappings":"AAMA,SAAgB,EAAkB,EAAkB,EAAQ,EAAiB,EAAmB,CAC9F,GAAI,EAAM,IAAI,CAAG,EAAG,OAAO,EAAM,IAAI,CAAG,EAExC,IAAM,EAAQ,EAAM,EAMpB,OAJI,EAAM,MAAQ,GAAS,EAAM,OAAO,EAAM,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,KAAU,EAEtE,EAAM,IAAI,EAAK,CAAK,EAEb,CACT"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_bounded-cache.d.ts","sourceRoot":"","sources":["../src/_bounded-cache.ts"],"names":[],"mappings":"AAMA,wBAAgB,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,CAU9F"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/_bounded-cache.ts
|
|
2
|
+
function e(e, t, n, r) {
|
|
3
|
+
if (e.has(t)) return e.get(t);
|
|
4
|
+
let i = r();
|
|
5
|
+
return e.size >= n && e.delete(e.keys().next().value), e.set(t, i), i;
|
|
6
|
+
}
|
|
7
|
+
//#endregion
|
|
8
|
+
export { e as getOrCreate };
|
|
9
|
+
|
|
10
|
+
//# sourceMappingURL=_bounded-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_bounded-cache.js","names":[],"sources":["../src/_bounded-cache.ts"],"sourcesContent":["// Internal — not part of the public API.\n// Minimal bounded cache: evicts the oldest entry (insertion order) once `maxSize` is exceeded.\n// Not LRU — no access-time reordering, only insertion order matters. These caches exist purely\n// to avoid rebuilding cheap-but-not-free values (compiled `Intl` formatters, scoped translator\n// objects) for a bounded number of frequently-reused keys, not to model real recency.\n\nexport function getOrCreate<K, V>(cache: Map<K, V>, key: K, maxSize: number, build: () => V): V {\n if (cache.has(key)) return cache.get(key)!;\n\n const value = build();\n\n if (cache.size >= maxSize) cache.delete(cache.keys().next().value as K);\n\n cache.set(key, value);\n\n return value;\n}\n"],"mappings":";AAMA,SAAgB,EAAkB,GAAkB,GAAQ,GAAiB,GAAmB;CAC9F,IAAI,EAAM,IAAI,CAAG,GAAG,OAAO,EAAM,IAAI,CAAG;CAExC,IAAM,IAAQ,EAAM;CAMpB,OAJI,EAAM,QAAQ,KAAS,EAAM,OAAO,EAAM,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,KAAU,GAEtE,EAAM,IAAI,GAAK,CAAK,GAEb;AACT"}
|
package/dist/_catalog.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("./
|
|
1
|
+
const e=require("./errors.cjs"),t=require("./_template.cjs");var n=new Set([`__proto__`,`constructor`,`prototype`]);function r(e){return typeof e==`object`&&!!e&&Object.hasOwn(e,`plural`)}function i(i){let a=new Map,o=(i,s)=>{if(typeof i==`string`){a.set(s,{kind:`text`,template:t.compileTemplate(i)});return}if(typeof i!=`object`||!i||Array.isArray(i))throw new e.LinguaInvalidCatalogError(`Catalog node "${s}" must be a string, plural message, or object.`);if(r(i)){if(typeof i.plural!=`object`||i.plural===null||Array.isArray(i.plural))throw new e.LinguaInvalidCatalogError(`Plural message "${s}" must provide an object of string forms.`);let n=new Map;for(let[r,a]of Object.entries(i.plural)){if(typeof a!=`string`)throw new e.LinguaInvalidCatalogError(`Plural form "${s}.${r}" must be a string.`);n.set(r,t.compileTemplate(a))}a.set(s,{forms:n,kind:`plural`});return}for(let[t,r]of Object.entries(i)){if(n.has(t))throw new e.LinguaInvalidCatalogError(`Catalog key "${t}" is reserved.`);o(r,s?`${s}.${t}`:t)}};for(let[t,r]of Object.entries(i)){if(n.has(t))throw new e.LinguaInvalidCatalogError(`Catalog key "${t}" is reserved.`);o(r,t)}return a}exports.compileCatalog=i;
|
|
2
2
|
//# sourceMappingURL=_catalog.cjs.map
|
package/dist/_catalog.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_catalog.cjs","names":[],"sources":["../src/_catalog.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"_catalog.cjs","names":[],"sources":["../src/_catalog.ts"],"sourcesContent":["import type { Catalog, CatalogNode, PluralMessage } from './types';\n\nimport { compileTemplate, type Template } from './_template';\nimport { LinguaInvalidCatalogError } from './errors';\n\nconst unsafeKeys = new Set(['__proto__', 'constructor', 'prototype']);\n\nexport type CompiledText = { readonly kind: 'text'; readonly template: Template };\nexport type CompiledPlural = { readonly forms: ReadonlyMap<string, Template>; readonly kind: 'plural' };\nexport type CompiledMessage = CompiledPlural | CompiledText;\nexport type CompiledCatalog = ReadonlyMap<string, CompiledMessage>;\n\nfunction isPluralMessage(node: CatalogNode): node is PluralMessage {\n return typeof node === 'object' && node !== null && Object.hasOwn(node, 'plural');\n}\n\n/** Compile explicit catalog nodes once. Nested objects only group keys; plural intent is never inferred. */\nexport function compileCatalog(catalog: Catalog): CompiledCatalog {\n const messages = new Map<string, CompiledMessage>();\n\n const visit = (node: CatalogNode, prefix: string): void => {\n if (typeof node === 'string') {\n messages.set(prefix, { kind: 'text', template: compileTemplate(node) });\n\n return;\n }\n\n if (typeof node !== 'object' || node === null || Array.isArray(node)) {\n throw new LinguaInvalidCatalogError(`Catalog node \"${prefix}\" must be a string, plural message, or object.`);\n }\n\n if (isPluralMessage(node)) {\n if (typeof node.plural !== 'object' || node.plural === null || Array.isArray(node.plural)) {\n throw new LinguaInvalidCatalogError(`Plural message \"${prefix}\" must provide an object of string forms.`);\n }\n\n const forms = new Map<string, Template>();\n\n for (const [form, template] of Object.entries(node.plural)) {\n if (typeof template !== 'string') {\n throw new LinguaInvalidCatalogError(`Plural form \"${prefix}.${form}\" must be a string.`);\n }\n\n forms.set(form, compileTemplate(template));\n }\n\n messages.set(prefix, { forms, kind: 'plural' });\n\n return;\n }\n\n for (const [key, value] of Object.entries(node)) {\n if (unsafeKeys.has(key)) {\n throw new LinguaInvalidCatalogError(`Catalog key \"${key}\" is reserved.`);\n }\n\n visit(value, prefix ? `${prefix}.${key}` : key);\n }\n };\n\n for (const [key, value] of Object.entries(catalog)) {\n if (unsafeKeys.has(key)) throw new LinguaInvalidCatalogError(`Catalog key \"${key}\" is reserved.`);\n\n visit(value, key);\n }\n\n return messages;\n}\n"],"mappings":"6DAKA,IAAM,EAAa,IAAI,IAAI,CAAC,YAAa,cAAe,WAAW,CAAC,EAOpE,SAAS,EAAgB,EAA0C,CACjE,OAAO,OAAO,GAAS,YAAY,GAAiB,OAAO,OAAO,EAAM,QAAQ,CAClF,CAGA,SAAgB,EAAe,EAAmC,CAChE,IAAM,EAAW,IAAI,IAEf,GAAS,EAAmB,IAAyB,CACzD,GAAI,OAAO,GAAS,SAAU,CAC5B,EAAS,IAAI,EAAQ,CAAE,KAAM,OAAQ,SAAU,EAAA,gBAAgB,CAAI,CAAE,CAAC,EAEtE,MACF,CAEA,GAAI,OAAO,GAAS,WAAY,GAAiB,MAAM,QAAQ,CAAI,EACjE,MAAM,IAAI,EAAA,0BAA0B,iBAAiB,EAAO,+CAA+C,EAG7G,GAAI,EAAgB,CAAI,EAAG,CACzB,GAAI,OAAO,EAAK,QAAW,UAAY,EAAK,SAAW,MAAQ,MAAM,QAAQ,EAAK,MAAM,EACtF,MAAM,IAAI,EAAA,0BAA0B,mBAAmB,EAAO,0CAA0C,EAG1G,IAAM,EAAQ,IAAI,IAElB,IAAK,GAAM,CAAC,EAAM,KAAa,OAAO,QAAQ,EAAK,MAAM,EAAG,CAC1D,GAAI,OAAO,GAAa,SACtB,MAAM,IAAI,EAAA,0BAA0B,gBAAgB,EAAO,GAAG,EAAK,oBAAoB,EAGzF,EAAM,IAAI,EAAM,EAAA,gBAAgB,CAAQ,CAAC,CAC3C,CAEA,EAAS,IAAI,EAAQ,CAAE,QAAO,KAAM,QAAS,CAAC,EAE9C,MACF,CAEA,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,CAAI,EAAG,CAC/C,GAAI,EAAW,IAAI,CAAG,EACpB,MAAM,IAAI,EAAA,0BAA0B,gBAAgB,EAAI,eAAe,EAGzE,EAAM,EAAO,EAAS,GAAG,EAAO,GAAG,IAAQ,CAAG,CAChD,CACF,EAEA,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,CAAO,EAAG,CAClD,GAAI,EAAW,IAAI,CAAG,EAAG,MAAM,IAAI,EAAA,0BAA0B,gBAAgB,EAAI,eAAe,EAEhG,EAAM,EAAO,CAAG,CAClB,CAEA,OAAO,CACT"}
|
package/dist/_catalog.d.ts
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
compiled: CompiledTemplate;
|
|
7
|
-
message: string;
|
|
1
|
+
import type { Catalog } from './types';
|
|
2
|
+
import { type Template } from './_template';
|
|
3
|
+
export type CompiledText = {
|
|
4
|
+
readonly kind: 'text';
|
|
5
|
+
readonly template: Template;
|
|
8
6
|
};
|
|
9
|
-
export
|
|
10
|
-
readonly
|
|
11
|
-
readonly
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
export declare function flattenStrings(messages: Messages, result?: Map<string, string>, prefix?: string): Map<string, string>;
|
|
7
|
+
export type CompiledPlural = {
|
|
8
|
+
readonly forms: ReadonlyMap<string, Template>;
|
|
9
|
+
readonly kind: 'plural';
|
|
10
|
+
};
|
|
11
|
+
export type CompiledMessage = CompiledPlural | CompiledText;
|
|
12
|
+
export type CompiledCatalog = ReadonlyMap<string, CompiledMessage>;
|
|
13
|
+
/** Compile explicit catalog nodes once. Nested objects only group keys; plural intent is never inferred. */
|
|
14
|
+
export declare function compileCatalog(catalog: Catalog): CompiledCatalog;
|
|
18
15
|
//# sourceMappingURL=_catalog.d.ts.map
|
package/dist/_catalog.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_catalog.d.ts","sourceRoot":"","sources":["../src/_catalog.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"_catalog.d.ts","sourceRoot":"","sources":["../src/_catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAA8B,MAAM,SAAS,CAAC;AAEnE,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAK7D,MAAM,MAAM,YAAY,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC;AAClF,MAAM,MAAM,cAAc,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC;AACxG,MAAM,MAAM,eAAe,GAAG,cAAc,GAAG,YAAY,CAAC;AAC5D,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAMnE,4GAA4G;AAC5G,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,eAAe,CAkDhE"}
|
package/dist/_catalog.js
CHANGED
|
@@ -1,42 +1,49 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { compileTemplate as t
|
|
1
|
+
import { LinguaInvalidCatalogError as e } from "./errors.js";
|
|
2
|
+
import { compileTemplate as t } from "./_template.js";
|
|
3
3
|
//#region src/_catalog.ts
|
|
4
|
-
var
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
4
|
+
var n = /* @__PURE__ */ new Set([
|
|
5
|
+
"__proto__",
|
|
6
|
+
"constructor",
|
|
7
|
+
"prototype"
|
|
8
|
+
]);
|
|
9
|
+
function r(e) {
|
|
10
|
+
return typeof e == "object" && !!e && Object.hasOwn(e, "plural");
|
|
11
|
+
}
|
|
12
|
+
function i(i) {
|
|
13
|
+
let a = /* @__PURE__ */ new Map(), o = (i, s) => {
|
|
14
|
+
if (typeof i == "string") {
|
|
15
|
+
a.set(s, {
|
|
16
|
+
kind: "text",
|
|
17
|
+
template: t(i)
|
|
18
|
+
});
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (typeof i != "object" || !i || Array.isArray(i)) throw new e(`Catalog node "${s}" must be a string, plural message, or object.`);
|
|
22
|
+
if (r(i)) {
|
|
23
|
+
if (typeof i.plural != "object" || i.plural === null || Array.isArray(i.plural)) throw new e(`Plural message "${s}" must provide an object of string forms.`);
|
|
24
|
+
let n = /* @__PURE__ */ new Map();
|
|
25
|
+
for (let [r, a] of Object.entries(i.plural)) {
|
|
26
|
+
if (typeof a != "string") throw new e(`Plural form "${s}.${r}" must be a string.`);
|
|
27
|
+
n.set(r, t(a));
|
|
28
|
+
}
|
|
29
|
+
a.set(s, {
|
|
30
|
+
forms: n,
|
|
31
|
+
kind: "plural"
|
|
32
|
+
});
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
for (let [t, r] of Object.entries(i)) {
|
|
36
|
+
if (n.has(t)) throw new e(`Catalog key "${t}" is reserved.`);
|
|
37
|
+
o(r, s ? `${s}.${t}` : t);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
for (let [t, r] of Object.entries(i)) {
|
|
41
|
+
if (n.has(t)) throw new e(`Catalog key "${t}" is reserved.`);
|
|
42
|
+
o(r, t);
|
|
36
43
|
}
|
|
37
|
-
return
|
|
44
|
+
return a;
|
|
38
45
|
}
|
|
39
46
|
//#endregion
|
|
40
|
-
export {
|
|
47
|
+
export { i as compileCatalog };
|
|
41
48
|
|
|
42
49
|
//# sourceMappingURL=_catalog.js.map
|
package/dist/_catalog.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_catalog.js","names":[],"sources":["../src/_catalog.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"_catalog.js","names":[],"sources":["../src/_catalog.ts"],"sourcesContent":["import type { Catalog, CatalogNode, PluralMessage } from './types';\n\nimport { compileTemplate, type Template } from './_template';\nimport { LinguaInvalidCatalogError } from './errors';\n\nconst unsafeKeys = new Set(['__proto__', 'constructor', 'prototype']);\n\nexport type CompiledText = { readonly kind: 'text'; readonly template: Template };\nexport type CompiledPlural = { readonly forms: ReadonlyMap<string, Template>; readonly kind: 'plural' };\nexport type CompiledMessage = CompiledPlural | CompiledText;\nexport type CompiledCatalog = ReadonlyMap<string, CompiledMessage>;\n\nfunction isPluralMessage(node: CatalogNode): node is PluralMessage {\n return typeof node === 'object' && node !== null && Object.hasOwn(node, 'plural');\n}\n\n/** Compile explicit catalog nodes once. Nested objects only group keys; plural intent is never inferred. */\nexport function compileCatalog(catalog: Catalog): CompiledCatalog {\n const messages = new Map<string, CompiledMessage>();\n\n const visit = (node: CatalogNode, prefix: string): void => {\n if (typeof node === 'string') {\n messages.set(prefix, { kind: 'text', template: compileTemplate(node) });\n\n return;\n }\n\n if (typeof node !== 'object' || node === null || Array.isArray(node)) {\n throw new LinguaInvalidCatalogError(`Catalog node \"${prefix}\" must be a string, plural message, or object.`);\n }\n\n if (isPluralMessage(node)) {\n if (typeof node.plural !== 'object' || node.plural === null || Array.isArray(node.plural)) {\n throw new LinguaInvalidCatalogError(`Plural message \"${prefix}\" must provide an object of string forms.`);\n }\n\n const forms = new Map<string, Template>();\n\n for (const [form, template] of Object.entries(node.plural)) {\n if (typeof template !== 'string') {\n throw new LinguaInvalidCatalogError(`Plural form \"${prefix}.${form}\" must be a string.`);\n }\n\n forms.set(form, compileTemplate(template));\n }\n\n messages.set(prefix, { forms, kind: 'plural' });\n\n return;\n }\n\n for (const [key, value] of Object.entries(node)) {\n if (unsafeKeys.has(key)) {\n throw new LinguaInvalidCatalogError(`Catalog key \"${key}\" is reserved.`);\n }\n\n visit(value, prefix ? `${prefix}.${key}` : key);\n }\n };\n\n for (const [key, value] of Object.entries(catalog)) {\n if (unsafeKeys.has(key)) throw new LinguaInvalidCatalogError(`Catalog key \"${key}\" is reserved.`);\n\n visit(value, key);\n }\n\n return messages;\n}\n"],"mappings":";;;AAKA,IAAM,oBAAa,IAAI,IAAI;CAAC;CAAa;CAAe;AAAW,CAAC;AAOpE,SAAS,EAAgB,GAA0C;CACjE,OAAO,OAAO,KAAS,cAAY,KAAiB,OAAO,OAAO,GAAM,QAAQ;AAClF;AAGA,SAAgB,EAAe,GAAmC;CAChE,IAAM,oBAAW,IAAI,IAA6B,GAE5C,KAAS,GAAmB,MAAyB;EACzD,IAAI,OAAO,KAAS,UAAU;GAC5B,EAAS,IAAI,GAAQ;IAAE,MAAM;IAAQ,UAAU,EAAgB,CAAI;GAAE,CAAC;GAEtE;EACF;EAEA,IAAI,OAAO,KAAS,aAAY,KAAiB,MAAM,QAAQ,CAAI,GACjE,MAAM,IAAI,EAA0B,iBAAiB,EAAO,+CAA+C;EAG7G,IAAI,EAAgB,CAAI,GAAG;GACzB,IAAI,OAAO,EAAK,UAAW,YAAY,EAAK,WAAW,QAAQ,MAAM,QAAQ,EAAK,MAAM,GACtF,MAAM,IAAI,EAA0B,mBAAmB,EAAO,0CAA0C;GAG1G,IAAM,oBAAQ,IAAI,IAAsB;GAExC,KAAK,IAAM,CAAC,GAAM,MAAa,OAAO,QAAQ,EAAK,MAAM,GAAG;IAC1D,IAAI,OAAO,KAAa,UACtB,MAAM,IAAI,EAA0B,gBAAgB,EAAO,GAAG,EAAK,oBAAoB;IAGzF,EAAM,IAAI,GAAM,EAAgB,CAAQ,CAAC;GAC3C;GAEA,EAAS,IAAI,GAAQ;IAAE;IAAO,MAAM;GAAS,CAAC;GAE9C;EACF;EAEA,KAAK,IAAM,CAAC,GAAK,MAAU,OAAO,QAAQ,CAAI,GAAG;GAC/C,IAAI,EAAW,IAAI,CAAG,GACpB,MAAM,IAAI,EAA0B,gBAAgB,EAAI,eAAe;GAGzE,EAAM,GAAO,IAAS,GAAG,EAAO,GAAG,MAAQ,CAAG;EAChD;CACF;CAEA,KAAK,IAAM,CAAC,GAAK,MAAU,OAAO,QAAQ,CAAO,GAAG;EAClD,IAAI,EAAW,IAAI,CAAG,GAAG,MAAM,IAAI,EAA0B,gBAAgB,EAAI,eAAe;EAEhG,EAAM,GAAO,CAAG;CAClB;CAEA,OAAO;AACT"}
|
package/dist/_dev.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
function e(e){}function t(e,...t){}exports.error=t,exports.warn=e;
|
|
2
2
|
//# sourceMappingURL=_dev.cjs.map
|
package/dist/_dev.cjs.map
CHANGED
|
@@ -1 +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":"
|
|
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":"AAGA,SAAgB,EAAK,EAAmB,CAExC,CAGA,SAAgB,EAAM,EAAa,GAAG,EAAuB,CAE7D"}
|
package/dist/_dev.js
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
//#region src/_dev.ts
|
|
2
|
-
|
|
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
|
-
}
|
|
2
|
+
function e(e) {}
|
|
3
|
+
function t(e, ...t) {}
|
|
9
4
|
//#endregion
|
|
10
|
-
export {
|
|
5
|
+
export { t as error, e as warn };
|
|
11
6
|
|
|
12
7
|
//# sourceMappingURL=_dev.js.map
|
package/dist/_dev.js.map
CHANGED
|
@@ -1 +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":";
|
|
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":";AAGA,SAAgB,EAAK,GAAmB,CAExC;AAGA,SAAgB,EAAM,GAAa,GAAG,GAAuB,CAE7D"}
|
package/dist/_locale.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("./errors.cjs");var t=new Map;function n(t){try{let[e]=Intl.getCanonicalLocales(t);if(e)return e}catch{}throw new e.LinguaInvalidLocaleError(`Invalid BCP 47 locale tag: "${t}".`)}function r(e,t){let n=new Set;for(let r of[e,...t]){let e=r.split(`-`);for(let t=e.length;t>0;t--)n.add(e.slice(0,t).join(`-`))}return[...n]}function i(e,n,r){let i=`${e}:${r?`ordinal`:`cardinal`}`,a=t.get(i);return a||(a=new Intl.PluralRules(e,{type:r?`ordinal`:`cardinal`}),t.set(i,a)),a.select(n)}exports.canonicalLocale=n,exports.localeChain=r,exports.pluralCategory=i;
|
|
2
|
+
//# sourceMappingURL=_locale.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_locale.cjs","names":[],"sources":["../src/_locale.ts"],"sourcesContent":["import type { Locale } from './types';\n\nimport { LinguaInvalidLocaleError } from './errors';\n\nconst pluralRules = new Map<string, Intl.PluralRules>();\n\nexport function canonicalLocale(locale: string): Locale {\n try {\n const [canonical] = Intl.getCanonicalLocales(locale);\n\n if (canonical) return canonical;\n } catch {\n // Error below names the failed public input.\n }\n\n throw new LinguaInvalidLocaleError(`Invalid BCP 47 locale tag: \"${locale}\".`);\n}\n\nexport function localeChain(locale: Locale, fallback: readonly Locale[]): readonly Locale[] {\n const chain = new Set<Locale>();\n\n for (const candidate of [locale, ...fallback]) {\n const parts = candidate.split('-');\n\n for (let length = parts.length; length > 0; length--) {\n chain.add(parts.slice(0, length).join('-'));\n }\n }\n\n return [...chain];\n}\n\nexport function pluralCategory(locale: Locale, count: number, ordinal: boolean): Intl.LDMLPluralRule {\n const key = `${locale}:${ordinal ? 'ordinal' : 'cardinal'}`;\n let rules = pluralRules.get(key);\n\n if (!rules) {\n rules = new Intl.PluralRules(locale, { type: ordinal ? 'ordinal' : 'cardinal' });\n pluralRules.set(key, rules);\n }\n\n return rules.select(count);\n}\n"],"mappings":"gCAIA,IAAM,EAAc,IAAI,IAExB,SAAgB,EAAgB,EAAwB,CACtD,GAAI,CACF,GAAM,CAAC,GAAa,KAAK,oBAAoB,CAAM,EAEnD,GAAI,EAAW,OAAO,CACxB,MAAQ,CAER,CAEA,MAAM,IAAI,EAAA,yBAAyB,+BAA+B,EAAO,GAAG,CAC9E,CAEA,SAAgB,EAAY,EAAgB,EAAgD,CAC1F,IAAM,EAAQ,IAAI,IAElB,IAAK,IAAM,IAAa,CAAC,EAAQ,GAAG,CAAQ,EAAG,CAC7C,IAAM,EAAQ,EAAU,MAAM,GAAG,EAEjC,IAAK,IAAI,EAAS,EAAM,OAAQ,EAAS,EAAG,IAC1C,EAAM,IAAI,EAAM,MAAM,EAAG,CAAM,CAAC,CAAC,KAAK,GAAG,CAAC,CAE9C,CAEA,MAAO,CAAC,GAAG,CAAK,CAClB,CAEA,SAAgB,EAAe,EAAgB,EAAe,EAAuC,CACnG,IAAM,EAAM,GAAG,EAAO,GAAG,EAAU,UAAY,aAC3C,EAAQ,EAAY,IAAI,CAAG,EAO/B,OALK,IACH,EAAQ,IAAI,KAAK,YAAY,EAAQ,CAAE,KAAM,EAAU,UAAY,UAAW,CAAC,EAC/E,EAAY,IAAI,EAAK,CAAK,GAGrB,EAAM,OAAO,CAAK,CAC3B"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Locale } from './types';
|
|
2
|
+
export declare function canonicalLocale(locale: string): Locale;
|
|
3
|
+
export declare function localeChain(locale: Locale, fallback: readonly Locale[]): readonly Locale[];
|
|
4
|
+
export declare function pluralCategory(locale: Locale, count: number, ordinal: boolean): Intl.LDMLPluralRule;
|
|
5
|
+
//# sourceMappingURL=_locale.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_locale.d.ts","sourceRoot":"","sources":["../src/_locale.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAMtC,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAUtD;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,MAAM,EAAE,CAY1F;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC,cAAc,CAUnG"}
|
package/dist/_locale.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { LinguaInvalidLocaleError as e } from "./errors.js";
|
|
2
|
+
//#region src/_locale.ts
|
|
3
|
+
var t = /* @__PURE__ */ new Map();
|
|
4
|
+
function n(t) {
|
|
5
|
+
try {
|
|
6
|
+
let [e] = Intl.getCanonicalLocales(t);
|
|
7
|
+
if (e) return e;
|
|
8
|
+
} catch {}
|
|
9
|
+
throw new e(`Invalid BCP 47 locale tag: "${t}".`);
|
|
10
|
+
}
|
|
11
|
+
function r(e, t) {
|
|
12
|
+
let n = /* @__PURE__ */ new Set();
|
|
13
|
+
for (let r of [e, ...t]) {
|
|
14
|
+
let e = r.split("-");
|
|
15
|
+
for (let t = e.length; t > 0; t--) n.add(e.slice(0, t).join("-"));
|
|
16
|
+
}
|
|
17
|
+
return [...n];
|
|
18
|
+
}
|
|
19
|
+
function i(e, n, r) {
|
|
20
|
+
let i = `${e}:${r ? "ordinal" : "cardinal"}`, a = t.get(i);
|
|
21
|
+
return a || (a = new Intl.PluralRules(e, { type: r ? "ordinal" : "cardinal" }), t.set(i, a)), a.select(n);
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
export { n as canonicalLocale, r as localeChain, i as pluralCategory };
|
|
25
|
+
|
|
26
|
+
//# sourceMappingURL=_locale.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_locale.js","names":[],"sources":["../src/_locale.ts"],"sourcesContent":["import type { Locale } from './types';\n\nimport { LinguaInvalidLocaleError } from './errors';\n\nconst pluralRules = new Map<string, Intl.PluralRules>();\n\nexport function canonicalLocale(locale: string): Locale {\n try {\n const [canonical] = Intl.getCanonicalLocales(locale);\n\n if (canonical) return canonical;\n } catch {\n // Error below names the failed public input.\n }\n\n throw new LinguaInvalidLocaleError(`Invalid BCP 47 locale tag: \"${locale}\".`);\n}\n\nexport function localeChain(locale: Locale, fallback: readonly Locale[]): readonly Locale[] {\n const chain = new Set<Locale>();\n\n for (const candidate of [locale, ...fallback]) {\n const parts = candidate.split('-');\n\n for (let length = parts.length; length > 0; length--) {\n chain.add(parts.slice(0, length).join('-'));\n }\n }\n\n return [...chain];\n}\n\nexport function pluralCategory(locale: Locale, count: number, ordinal: boolean): Intl.LDMLPluralRule {\n const key = `${locale}:${ordinal ? 'ordinal' : 'cardinal'}`;\n let rules = pluralRules.get(key);\n\n if (!rules) {\n rules = new Intl.PluralRules(locale, { type: ordinal ? 'ordinal' : 'cardinal' });\n pluralRules.set(key, rules);\n }\n\n return rules.select(count);\n}\n"],"mappings":";;AAIA,IAAM,oBAAc,IAAI,IAA8B;AAEtD,SAAgB,EAAgB,GAAwB;CACtD,IAAI;EACF,IAAM,CAAC,KAAa,KAAK,oBAAoB,CAAM;EAEnD,IAAI,GAAW,OAAO;CACxB,QAAQ,CAER;CAEA,MAAM,IAAI,EAAyB,+BAA+B,EAAO,GAAG;AAC9E;AAEA,SAAgB,EAAY,GAAgB,GAAgD;CAC1F,IAAM,oBAAQ,IAAI,IAAY;CAE9B,KAAK,IAAM,KAAa,CAAC,GAAQ,GAAG,CAAQ,GAAG;EAC7C,IAAM,IAAQ,EAAU,MAAM,GAAG;EAEjC,KAAK,IAAI,IAAS,EAAM,QAAQ,IAAS,GAAG,KAC1C,EAAM,IAAI,EAAM,MAAM,GAAG,CAAM,CAAC,CAAC,KAAK,GAAG,CAAC;CAE9C;CAEA,OAAO,CAAC,GAAG,CAAK;AAClB;AAEA,SAAgB,EAAe,GAAgB,GAAe,GAAuC;CACnG,IAAM,IAAM,GAAG,EAAO,GAAG,IAAU,YAAY,cAC3C,IAAQ,EAAY,IAAI,CAAG;CAO/B,OALK,MACH,IAAQ,IAAI,KAAK,YAAY,GAAQ,EAAE,MAAM,IAAU,YAAY,WAAW,CAAC,GAC/E,EAAY,IAAI,GAAK,CAAK,IAGrB,EAAM,OAAO,CAAK;AAC3B"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("./errors.cjs"),t=require("./_locale.cjs"),n=require("./_catalog.cjs");function r(r){let i=new Map,a=new Map,o=new Map;for(let[e,n]of Object.entries(r))i.set(t.canonicalLocale(e),n);let s=(e,t)=>{a.set(e,{catalog:t,compiled:n.compileCatalog(t)})};for(let[e,t]of i)typeof t!=`function`&&s(e,t);return{catalogMap(){return new Map([...a].map(([e,{compiled:t}])=>[e,t]))},isLoaded(e){return a.has(t.canonicalLocale(e))},load:async n=>{let r=t.canonicalLocale(n);if(a.has(r))return!1;let c=i.get(r);if(!c)throw new e.LinguaMissingCatalogError(`Catalog has no source for locale "${r}".`);if(typeof c!=`function`)return s(r,c),!0;let l=o.get(r);if(l)return await l,!1;let u=c().then(e=>{s(r,e),o.delete(r)},e=>{throw o.delete(r),e});return o.set(r,u),await u,!0},state(e){let t={};for(let[e,{catalog:n}]of a)t[e]=n;return{catalogs:t,locale:e,version:3}}}}exports.createCatalogStore=r;
|
|
2
|
+
//# sourceMappingURL=_resources.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_resources.cjs","names":[],"sources":["../src/_resources.ts"],"sourcesContent":["import type { Catalog, CatalogSources, TranslationState, LoadedCatalogs, Locale } from './types';\n\nimport { type CompiledCatalog, compileCatalog } from './_catalog';\nimport { canonicalLocale } from './_locale';\nimport { LinguaMissingCatalogError } from './errors';\n\n/** One catalog state machine owns static sources, lazy sources, and in-flight work. */\nexport function createCatalogStore<C extends Catalog>(sources: CatalogSources<C>) {\n const definitions = new Map<Locale, C | (() => Promise<C>)>();\n const loaded = new Map<Locale, { readonly catalog: C; readonly compiled: CompiledCatalog }>();\n const tasks = new Map<Locale, Promise<void>>();\n\n for (const [locale, source] of Object.entries(sources)) definitions.set(canonicalLocale(locale), source);\n\n const add = (locale: Locale, catalog: C): void => {\n loaded.set(locale, { catalog, compiled: compileCatalog(catalog) });\n };\n\n for (const [locale, source] of definitions) {\n if (typeof source !== 'function') add(locale, source);\n }\n\n const load = async (requestedLocale: Locale): Promise<boolean> => {\n const locale = canonicalLocale(requestedLocale);\n\n if (loaded.has(locale)) return false;\n\n const source = definitions.get(locale);\n\n if (!source) throw new LinguaMissingCatalogError(`Catalog has no source for locale \"${locale}\".`);\n\n if (typeof source !== 'function') {\n add(locale, source);\n\n return true;\n }\n\n const existing = tasks.get(locale);\n\n if (existing) {\n await existing;\n\n return false;\n }\n\n const task = source().then(\n (catalog) => {\n add(locale, catalog);\n tasks.delete(locale);\n },\n (error: unknown) => {\n tasks.delete(locale);\n throw error;\n },\n );\n\n tasks.set(locale, task);\n await task;\n\n return true;\n };\n\n return {\n catalogMap(): ReadonlyMap<Locale, CompiledCatalog> {\n return new Map([...loaded].map(([locale, { compiled }]) => [locale, compiled]));\n },\n isLoaded(locale: Locale): boolean {\n return loaded.has(canonicalLocale(locale));\n },\n load,\n state(locale: Locale): TranslationState<C> {\n const catalogs: LoadedCatalogs<C> = {};\n\n for (const [loadedLocale, { catalog }] of loaded) catalogs[loadedLocale] = catalog;\n\n return { catalogs, locale, version: 3 };\n },\n };\n}\n"],"mappings":"uFAOA,SAAgB,EAAsC,EAA4B,CAChF,IAAM,EAAc,IAAI,IAClB,EAAS,IAAI,IACb,EAAQ,IAAI,IAElB,IAAK,GAAM,CAAC,EAAQ,KAAW,OAAO,QAAQ,CAAO,EAAG,EAAY,IAAI,EAAA,gBAAgB,CAAM,EAAG,CAAM,EAEvG,IAAM,GAAO,EAAgB,IAAqB,CAChD,EAAO,IAAI,EAAQ,CAAE,UAAS,SAAU,EAAA,eAAe,CAAO,CAAE,CAAC,CACnE,EAEA,IAAK,GAAM,CAAC,EAAQ,KAAW,EACzB,OAAO,GAAW,YAAY,EAAI,EAAQ,CAAM,EA2CtD,MAAO,CACL,YAAmD,CACjD,OAAO,IAAI,IAAI,CAAC,GAAG,CAAM,CAAC,CAAC,KAAK,CAAC,EAAQ,CAAE,eAAgB,CAAC,EAAQ,CAAQ,CAAC,CAAC,CAChF,EACA,SAAS,EAAyB,CAChC,OAAO,EAAO,IAAI,EAAA,gBAAgB,CAAM,CAAC,CAC3C,EACA,UA/CkB,IAA8C,CAChE,IAAM,EAAS,EAAA,gBAAgB,CAAe,EAE9C,GAAI,EAAO,IAAI,CAAM,EAAG,MAAO,GAE/B,IAAM,EAAS,EAAY,IAAI,CAAM,EAErC,GAAI,CAAC,EAAQ,MAAM,IAAI,EAAA,0BAA0B,qCAAqC,EAAO,GAAG,EAEhG,GAAI,OAAO,GAAW,WAGpB,OAFA,EAAI,EAAQ,CAAM,EAEX,GAGT,IAAM,EAAW,EAAM,IAAI,CAAM,EAEjC,GAAI,EAGF,OAFA,MAAM,EAEC,GAGT,IAAM,EAAO,EAAO,CAAC,CAAC,KACnB,GAAY,CACX,EAAI,EAAQ,CAAO,EACnB,EAAM,OAAO,CAAM,CACrB,EACC,GAAmB,CAElB,MADA,EAAM,OAAO,CAAM,EACb,CACR,CACF,EAKA,OAHA,EAAM,IAAI,EAAQ,CAAI,EACtB,MAAM,EAEC,EACT,EAUE,MAAM,EAAqC,CACzC,IAAM,EAA8B,CAAC,EAErC,IAAK,GAAM,CAAC,EAAc,CAAE,cAAc,EAAQ,EAAS,GAAgB,EAE3E,MAAO,CAAE,WAAU,SAAQ,QAAS,CAAE,CACxC,CACF,CACF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Catalog, CatalogSources, TranslationState, Locale } from './types';
|
|
2
|
+
import { type CompiledCatalog } from './_catalog';
|
|
3
|
+
/** One catalog state machine owns static sources, lazy sources, and in-flight work. */
|
|
4
|
+
export declare function createCatalogStore<C extends Catalog>(sources: CatalogSources<C>): {
|
|
5
|
+
catalogMap(): ReadonlyMap<Locale, CompiledCatalog>;
|
|
6
|
+
isLoaded(locale: Locale): boolean;
|
|
7
|
+
load: (requestedLocale: Locale) => Promise<boolean>;
|
|
8
|
+
state(locale: Locale): TranslationState<C>;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=_resources.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_resources.d.ts","sourceRoot":"","sources":["../src/_resources.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAkB,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjG,OAAO,EAAE,KAAK,eAAe,EAAkB,MAAM,YAAY,CAAC;AAIlE,uFAAuF;AACvF,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,OAAO,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC;kBAwD9D,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC;qBAGjC,MAAM,GAAG,OAAO;4BA5CE,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;kBAgD9C,MAAM,GAAG,gBAAgB,CAAC,CAAC,CAAC;EAQ7C"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { LinguaMissingCatalogError as e } from "./errors.js";
|
|
2
|
+
import { canonicalLocale as t } from "./_locale.js";
|
|
3
|
+
import { compileCatalog as n } from "./_catalog.js";
|
|
4
|
+
//#region src/_resources.ts
|
|
5
|
+
function r(r) {
|
|
6
|
+
let i = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Map();
|
|
7
|
+
for (let [e, n] of Object.entries(r)) i.set(t(e), n);
|
|
8
|
+
let s = (e, t) => {
|
|
9
|
+
a.set(e, {
|
|
10
|
+
catalog: t,
|
|
11
|
+
compiled: n(t)
|
|
12
|
+
});
|
|
13
|
+
};
|
|
14
|
+
for (let [e, t] of i) typeof t != "function" && s(e, t);
|
|
15
|
+
return {
|
|
16
|
+
catalogMap() {
|
|
17
|
+
return new Map([...a].map(([e, { compiled: t }]) => [e, t]));
|
|
18
|
+
},
|
|
19
|
+
isLoaded(e) {
|
|
20
|
+
return a.has(t(e));
|
|
21
|
+
},
|
|
22
|
+
load: async (n) => {
|
|
23
|
+
let r = t(n);
|
|
24
|
+
if (a.has(r)) return !1;
|
|
25
|
+
let c = i.get(r);
|
|
26
|
+
if (!c) throw new e(`Catalog has no source for locale "${r}".`);
|
|
27
|
+
if (typeof c != "function") return s(r, c), !0;
|
|
28
|
+
let l = o.get(r);
|
|
29
|
+
if (l) return await l, !1;
|
|
30
|
+
let u = c().then((e) => {
|
|
31
|
+
s(r, e), o.delete(r);
|
|
32
|
+
}, (e) => {
|
|
33
|
+
throw o.delete(r), e;
|
|
34
|
+
});
|
|
35
|
+
return o.set(r, u), await u, !0;
|
|
36
|
+
},
|
|
37
|
+
state(e) {
|
|
38
|
+
let t = {};
|
|
39
|
+
for (let [e, { catalog: n }] of a) t[e] = n;
|
|
40
|
+
return {
|
|
41
|
+
catalogs: t,
|
|
42
|
+
locale: e,
|
|
43
|
+
version: 3
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
export { r as createCatalogStore };
|
|
50
|
+
|
|
51
|
+
//# sourceMappingURL=_resources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_resources.js","names":[],"sources":["../src/_resources.ts"],"sourcesContent":["import type { Catalog, CatalogSources, TranslationState, LoadedCatalogs, Locale } from './types';\n\nimport { type CompiledCatalog, compileCatalog } from './_catalog';\nimport { canonicalLocale } from './_locale';\nimport { LinguaMissingCatalogError } from './errors';\n\n/** One catalog state machine owns static sources, lazy sources, and in-flight work. */\nexport function createCatalogStore<C extends Catalog>(sources: CatalogSources<C>) {\n const definitions = new Map<Locale, C | (() => Promise<C>)>();\n const loaded = new Map<Locale, { readonly catalog: C; readonly compiled: CompiledCatalog }>();\n const tasks = new Map<Locale, Promise<void>>();\n\n for (const [locale, source] of Object.entries(sources)) definitions.set(canonicalLocale(locale), source);\n\n const add = (locale: Locale, catalog: C): void => {\n loaded.set(locale, { catalog, compiled: compileCatalog(catalog) });\n };\n\n for (const [locale, source] of definitions) {\n if (typeof source !== 'function') add(locale, source);\n }\n\n const load = async (requestedLocale: Locale): Promise<boolean> => {\n const locale = canonicalLocale(requestedLocale);\n\n if (loaded.has(locale)) return false;\n\n const source = definitions.get(locale);\n\n if (!source) throw new LinguaMissingCatalogError(`Catalog has no source for locale \"${locale}\".`);\n\n if (typeof source !== 'function') {\n add(locale, source);\n\n return true;\n }\n\n const existing = tasks.get(locale);\n\n if (existing) {\n await existing;\n\n return false;\n }\n\n const task = source().then(\n (catalog) => {\n add(locale, catalog);\n tasks.delete(locale);\n },\n (error: unknown) => {\n tasks.delete(locale);\n throw error;\n },\n );\n\n tasks.set(locale, task);\n await task;\n\n return true;\n };\n\n return {\n catalogMap(): ReadonlyMap<Locale, CompiledCatalog> {\n return new Map([...loaded].map(([locale, { compiled }]) => [locale, compiled]));\n },\n isLoaded(locale: Locale): boolean {\n return loaded.has(canonicalLocale(locale));\n },\n load,\n state(locale: Locale): TranslationState<C> {\n const catalogs: LoadedCatalogs<C> = {};\n\n for (const [loadedLocale, { catalog }] of loaded) catalogs[loadedLocale] = catalog;\n\n return { catalogs, locale, version: 3 };\n },\n };\n}\n"],"mappings":";;;;AAOA,SAAgB,EAAsC,GAA4B;CAChF,IAAM,oBAAc,IAAI,IAAoC,GACtD,oBAAS,IAAI,IAAyE,GACtF,oBAAQ,IAAI,IAA2B;CAE7C,KAAK,IAAM,CAAC,GAAQ,MAAW,OAAO,QAAQ,CAAO,GAAG,EAAY,IAAI,EAAgB,CAAM,GAAG,CAAM;CAEvG,IAAM,KAAO,GAAgB,MAAqB;EAChD,EAAO,IAAI,GAAQ;GAAE;GAAS,UAAU,EAAe,CAAO;EAAE,CAAC;CACnE;CAEA,KAAK,IAAM,CAAC,GAAQ,MAAW,GAC7B,AAAI,OAAO,KAAW,cAAY,EAAI,GAAQ,CAAM;CA2CtD,OAAO;EACL,aAAmD;GACjD,OAAO,IAAI,IAAI,CAAC,GAAG,CAAM,CAAC,CAAC,KAAK,CAAC,GAAQ,EAAE,mBAAgB,CAAC,GAAQ,CAAQ,CAAC,CAAC;EAChF;EACA,SAAS,GAAyB;GAChC,OAAO,EAAO,IAAI,EAAgB,CAAM,CAAC;EAC3C;EACA,aA/CkB,MAA8C;GAChE,IAAM,IAAS,EAAgB,CAAe;GAE9C,IAAI,EAAO,IAAI,CAAM,GAAG,OAAO;GAE/B,IAAM,IAAS,EAAY,IAAI,CAAM;GAErC,IAAI,CAAC,GAAQ,MAAM,IAAI,EAA0B,qCAAqC,EAAO,GAAG;GAEhG,IAAI,OAAO,KAAW,YAGpB,OAFA,EAAI,GAAQ,CAAM,GAEX;GAGT,IAAM,IAAW,EAAM,IAAI,CAAM;GAEjC,IAAI,GAGF,OAFA,MAAM,GAEC;GAGT,IAAM,IAAO,EAAO,CAAC,CAAC,MACnB,MAAY;IAEX,AADA,EAAI,GAAQ,CAAO,GACnB,EAAM,OAAO,CAAM;GACrB,IACC,MAAmB;IAElB,MADA,EAAM,OAAO,CAAM,GACb;GACR,CACF;GAKA,OAHA,EAAM,IAAI,GAAQ,CAAI,GACtB,MAAM,GAEC;EACT;EAUE,MAAM,GAAqC;GACzC,IAAM,IAA8B,CAAC;GAErC,KAAK,IAAM,CAAC,GAAc,EAAE,iBAAc,GAAQ,EAAS,KAAgB;GAE3E,OAAO;IAAE;IAAU;IAAQ,SAAS;GAAE;EACxC;CACF;AACF"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=/\{([\p{ID_Continue}-]+)\}/gu;function t(t){let n=[],r=0;for(let i of t.matchAll(e)){let e=i.index??0;e>r&&n.push(t.slice(r,e)),n.push({value:i[1]}),r=e+i[0].length}return r<t.length&&n.push(t.slice(r)),n}function n(e,t,n){return e.map(e=>{if(typeof e==`string`)return e;let r=Object.hasOwn(t,e.value)?t[e.value]:void 0;return r==null?n(e.value):String(r)}).join(``)}function r(e,t,n){let r=[];for(let i of e){if(typeof i==`string`){i!==``&&r.push(i);continue}r.push(Object.hasOwn(t,i.value)?t[i.value]:n(i.value))}return r}exports.compileTemplate=t,exports.renderSegments=r,exports.renderText=n;
|
|
2
|
+
//# sourceMappingURL=_template.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_template.cjs","names":[],"sources":["../src/_template.ts"],"sourcesContent":["export type TemplatePart = string | { readonly value: string };\nexport type Template = readonly TemplatePart[];\n\nconst interpolation = /\\{([\\p{ID_Continue}-]+)\\}/gu;\n\nexport function compileTemplate(value: string): Template {\n const parts: TemplatePart[] = [];\n let offset = 0;\n\n for (const match of value.matchAll(interpolation)) {\n const index = match.index ?? 0;\n\n if (index > offset) parts.push(value.slice(offset, index));\n\n parts.push({ value: match[1] });\n offset = index + match[0].length;\n }\n\n if (offset < value.length) parts.push(value.slice(offset));\n\n return parts;\n}\n\nexport function renderText(\n parts: Template,\n values: Record<string, unknown>,\n missing: (name: string) => string,\n): string {\n return parts\n .map((part) => {\n if (typeof part === 'string') return part;\n\n const value = Object.hasOwn(values, part.value) ? values[part.value] : undefined;\n\n return value == null ? missing(part.value) : String(value);\n })\n .join('');\n}\n\nexport function renderSegments<V>(\n parts: Template,\n values: Record<string, V | number>,\n missing: (name: string) => string,\n): Array<string | number | V> {\n const result: Array<string | number | V> = [];\n\n for (const part of parts) {\n if (typeof part === 'string') {\n if (part !== '') result.push(part);\n\n continue;\n }\n\n result.push(Object.hasOwn(values, part.value) ? values[part.value]! : missing(part.value));\n }\n\n return result;\n}\n"],"mappings":"AAGA,IAAM,EAAgB,8BAEtB,SAAgB,EAAgB,EAAyB,CACvD,IAAM,EAAwB,CAAC,EAC3B,EAAS,EAEb,IAAK,IAAM,KAAS,EAAM,SAAS,CAAa,EAAG,CACjD,IAAM,EAAQ,EAAM,OAAS,EAEzB,EAAQ,GAAQ,EAAM,KAAK,EAAM,MAAM,EAAQ,CAAK,CAAC,EAEzD,EAAM,KAAK,CAAE,MAAO,EAAM,EAAG,CAAC,EAC9B,EAAS,EAAQ,EAAM,EAAE,CAAC,MAC5B,CAIA,OAFI,EAAS,EAAM,QAAQ,EAAM,KAAK,EAAM,MAAM,CAAM,CAAC,EAElD,CACT,CAEA,SAAgB,EACd,EACA,EACA,EACQ,CACR,OAAO,EACJ,IAAK,GAAS,CACb,GAAI,OAAO,GAAS,SAAU,OAAO,EAErC,IAAM,EAAQ,OAAO,OAAO,EAAQ,EAAK,KAAK,EAAI,EAAO,EAAK,OAAS,IAAA,GAEvE,OAAO,GAAS,KAAO,EAAQ,EAAK,KAAK,EAAI,OAAO,CAAK,CAC3D,CAAC,CAAC,CACD,KAAK,EAAE,CACZ,CAEA,SAAgB,EACd,EACA,EACA,EAC4B,CAC5B,IAAM,EAAqC,CAAC,EAE5C,IAAK,IAAM,KAAQ,EAAO,CACxB,GAAI,OAAO,GAAS,SAAU,CACxB,IAAS,IAAI,EAAO,KAAK,CAAI,EAEjC,QACF,CAEA,EAAO,KAAK,OAAO,OAAO,EAAQ,EAAK,KAAK,EAAI,EAAO,EAAK,OAAU,EAAQ,EAAK,KAAK,CAAC,CAC3F,CAEA,OAAO,CACT"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type TemplatePart = string | {
|
|
2
|
+
readonly value: string;
|
|
3
|
+
};
|
|
4
|
+
export type Template = readonly TemplatePart[];
|
|
5
|
+
export declare function compileTemplate(value: string): Template;
|
|
6
|
+
export declare function renderText(parts: Template, values: Record<string, unknown>, missing: (name: string) => string): string;
|
|
7
|
+
export declare function renderSegments<V>(parts: Template, values: Record<string, V | number>, missing: (name: string) => string): Array<string | number | V>;
|
|
8
|
+
//# sourceMappingURL=_template.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_template.d.ts","sourceRoot":"","sources":["../src/_template.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAC/D,MAAM,MAAM,QAAQ,GAAG,SAAS,YAAY,EAAE,CAAC;AAI/C,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAgBvD;AAED,wBAAgB,UAAU,CACxB,KAAK,EAAE,QAAQ,EACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAChC,MAAM,CAUR;AAED,wBAAgB,cAAc,CAAC,CAAC,EAC9B,KAAK,EAAE,QAAQ,EACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,MAAM,CAAC,EAClC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAChC,KAAK,CAAC,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC,CAc5B"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//#region src/_template.ts
|
|
2
|
+
var e = /\{([\p{ID_Continue}-]+)\}/gu;
|
|
3
|
+
function t(t) {
|
|
4
|
+
let n = [], r = 0;
|
|
5
|
+
for (let i of t.matchAll(e)) {
|
|
6
|
+
let e = i.index ?? 0;
|
|
7
|
+
e > r && n.push(t.slice(r, e)), n.push({ value: i[1] }), r = e + i[0].length;
|
|
8
|
+
}
|
|
9
|
+
return r < t.length && n.push(t.slice(r)), n;
|
|
10
|
+
}
|
|
11
|
+
function n(e, t, n) {
|
|
12
|
+
return e.map((e) => {
|
|
13
|
+
if (typeof e == "string") return e;
|
|
14
|
+
let r = Object.hasOwn(t, e.value) ? t[e.value] : void 0;
|
|
15
|
+
return r == null ? n(e.value) : String(r);
|
|
16
|
+
}).join("");
|
|
17
|
+
}
|
|
18
|
+
function r(e, t, n) {
|
|
19
|
+
let r = [];
|
|
20
|
+
for (let i of e) {
|
|
21
|
+
if (typeof i == "string") {
|
|
22
|
+
i !== "" && r.push(i);
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
r.push(Object.hasOwn(t, i.value) ? t[i.value] : n(i.value));
|
|
26
|
+
}
|
|
27
|
+
return r;
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { t as compileTemplate, r as renderSegments, n as renderText };
|
|
31
|
+
|
|
32
|
+
//# sourceMappingURL=_template.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_template.js","names":[],"sources":["../src/_template.ts"],"sourcesContent":["export type TemplatePart = string | { readonly value: string };\nexport type Template = readonly TemplatePart[];\n\nconst interpolation = /\\{([\\p{ID_Continue}-]+)\\}/gu;\n\nexport function compileTemplate(value: string): Template {\n const parts: TemplatePart[] = [];\n let offset = 0;\n\n for (const match of value.matchAll(interpolation)) {\n const index = match.index ?? 0;\n\n if (index > offset) parts.push(value.slice(offset, index));\n\n parts.push({ value: match[1] });\n offset = index + match[0].length;\n }\n\n if (offset < value.length) parts.push(value.slice(offset));\n\n return parts;\n}\n\nexport function renderText(\n parts: Template,\n values: Record<string, unknown>,\n missing: (name: string) => string,\n): string {\n return parts\n .map((part) => {\n if (typeof part === 'string') return part;\n\n const value = Object.hasOwn(values, part.value) ? values[part.value] : undefined;\n\n return value == null ? missing(part.value) : String(value);\n })\n .join('');\n}\n\nexport function renderSegments<V>(\n parts: Template,\n values: Record<string, V | number>,\n missing: (name: string) => string,\n): Array<string | number | V> {\n const result: Array<string | number | V> = [];\n\n for (const part of parts) {\n if (typeof part === 'string') {\n if (part !== '') result.push(part);\n\n continue;\n }\n\n result.push(Object.hasOwn(values, part.value) ? values[part.value]! : missing(part.value));\n }\n\n return result;\n}\n"],"mappings":";AAGA,IAAM,IAAgB;AAEtB,SAAgB,EAAgB,GAAyB;CACvD,IAAM,IAAwB,CAAC,GAC3B,IAAS;CAEb,KAAK,IAAM,KAAS,EAAM,SAAS,CAAa,GAAG;EACjD,IAAM,IAAQ,EAAM,SAAS;EAK7B,AAHI,IAAQ,KAAQ,EAAM,KAAK,EAAM,MAAM,GAAQ,CAAK,CAAC,GAEzD,EAAM,KAAK,EAAE,OAAO,EAAM,GAAG,CAAC,GAC9B,IAAS,IAAQ,EAAM,EAAE,CAAC;CAC5B;CAIA,OAFI,IAAS,EAAM,UAAQ,EAAM,KAAK,EAAM,MAAM,CAAM,CAAC,GAElD;AACT;AAEA,SAAgB,EACd,GACA,GACA,GACQ;CACR,OAAO,EACJ,KAAK,MAAS;EACb,IAAI,OAAO,KAAS,UAAU,OAAO;EAErC,IAAM,IAAQ,OAAO,OAAO,GAAQ,EAAK,KAAK,IAAI,EAAO,EAAK,SAAS,KAAA;EAEvE,OAAO,KAAS,OAAO,EAAQ,EAAK,KAAK,IAAI,OAAO,CAAK;CAC3D,CAAC,CAAC,CACD,KAAK,EAAE;AACZ;AAEA,SAAgB,EACd,GACA,GACA,GAC4B;CAC5B,IAAM,IAAqC,CAAC;CAE5C,KAAK,IAAM,KAAQ,GAAO;EACxB,IAAI,OAAO,KAAS,UAAU;GAC5B,AAAI,MAAS,MAAI,EAAO,KAAK,CAAI;GAEjC;EACF;EAEA,EAAO,KAAK,OAAO,OAAO,GAAQ,EAAK,KAAK,IAAI,EAAO,EAAK,SAAU,EAAQ,EAAK,KAAK,CAAC;CAC3F;CAEA,OAAO;AACT"}
|