@craft-ts/i18n 0.7.0-beta.15
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/package.json +28 -0
- package/src/index.d.ts +2 -0
- package/src/index.d.ts.map +1 -0
- package/src/index.js +2 -0
- package/src/index.js.map +1 -0
- package/src/lib/i18n.d.ts +194 -0
- package/src/lib/i18n.d.ts.map +1 -0
- package/src/lib/i18n.js +361 -0
- package/src/lib/i18n.js.map +1 -0
- package/src/lib/i18n.types.d.ts +2 -0
- package/src/lib/i18n.types.d.ts.map +1 -0
- package/src/lib/i18n.types.js +31 -0
- package/src/lib/i18n.types.js.map +1 -0
- package/src/testing.d.ts +2 -0
- package/src/testing.d.ts.map +1 -0
- package/src/testing.js +2 -0
- package/src/testing.js.map +1 -0
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@craft-ts/i18n",
|
|
3
|
+
"version": "0.7.0-beta.15",
|
|
4
|
+
"description": "Framework-independent, type-safe internationalisation for CraftTS",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./src/index.js",
|
|
8
|
+
"types": "./src/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./src/index.d.ts",
|
|
12
|
+
"default": "./src/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./package.json": "./package.json",
|
|
15
|
+
"./testing": {
|
|
16
|
+
"types": "./src/testing.d.ts",
|
|
17
|
+
"default": "./src/testing.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=20.19.0"
|
|
22
|
+
},
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"sideEffects": false,
|
|
27
|
+
"module": "./src/index.js"
|
|
28
|
+
}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../libs/i18n/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC"}
|
package/src/index.js
ADDED
package/src/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/i18n/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC","sourcesContent":["export * from './lib/i18n';\n"]}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
export type PluralCategory = 'zero' | 'one' | 'two' | 'few' | 'many' | 'other';
|
|
2
|
+
export type FormatterContext = {
|
|
3
|
+
readonly locale: string;
|
|
4
|
+
readonly timeZone?: string;
|
|
5
|
+
};
|
|
6
|
+
export type TokenFormatter<Value> = ((value: Value, context: FormatterContext) => string) & {
|
|
7
|
+
readonly id?: string;
|
|
8
|
+
};
|
|
9
|
+
export type TokenValueAdapter<Value> = {
|
|
10
|
+
readonly validate?: (value: unknown) => value is Value;
|
|
11
|
+
readonly name?: string;
|
|
12
|
+
} | ((value: unknown) => value is Value);
|
|
13
|
+
export type I18nToken<Name extends string = string, Value = unknown, Kind extends string = string> = {
|
|
14
|
+
readonly __i18nToken: true;
|
|
15
|
+
readonly name: Name;
|
|
16
|
+
readonly kind: Kind;
|
|
17
|
+
readonly tokenId: string;
|
|
18
|
+
readonly validate?: (value: unknown) => value is Value;
|
|
19
|
+
readonly format: TokenFormatter<Value>;
|
|
20
|
+
};
|
|
21
|
+
type Simplify<T> = {
|
|
22
|
+
[Key in keyof T]: T[Key];
|
|
23
|
+
} & {};
|
|
24
|
+
type UnionToIntersection<T> = (T extends unknown ? (value: T) => void : never) extends (value: infer I) => void ? I : never;
|
|
25
|
+
type TokenParams<T> = T extends I18nToken<infer Name, infer Value, infer _Kind> ? {
|
|
26
|
+
[Key in Name]: Value;
|
|
27
|
+
} : Record<never, never>;
|
|
28
|
+
type ParamsFromTokens<T extends readonly unknown[]> = Simplify<UnionToIntersection<TokenParams<T[number]>>>;
|
|
29
|
+
export type Message<Params = Record<never, never>> = {
|
|
30
|
+
readonly kind: 'message';
|
|
31
|
+
readonly parts: readonly (string | I18nToken<string, any, string>)[];
|
|
32
|
+
readonly params: Params;
|
|
33
|
+
};
|
|
34
|
+
export type PluralMessage<CountName extends string = string, CountValue extends number = number, Branches extends Partial<Record<PluralCategory, Message<unknown>>> = Partial<Record<PluralCategory, Message<unknown>>>> = {
|
|
35
|
+
readonly kind: 'plural';
|
|
36
|
+
readonly count: I18nToken<CountName, CountValue, string>;
|
|
37
|
+
readonly branches: Branches;
|
|
38
|
+
readonly params: Simplify<{
|
|
39
|
+
[Key in CountName]: CountValue;
|
|
40
|
+
} & (Branches[keyof Branches] extends Message<infer Params> ? Params : Record<never, never>)>;
|
|
41
|
+
};
|
|
42
|
+
export type CatalogNode = Message | PluralMessage | {
|
|
43
|
+
readonly [key: string]: CatalogNode;
|
|
44
|
+
};
|
|
45
|
+
export type Catalog = {
|
|
46
|
+
readonly [key: string]: CatalogNode;
|
|
47
|
+
};
|
|
48
|
+
export declare function defineCatalog<const T extends Catalog>(catalog: T): T;
|
|
49
|
+
export declare function msg<const Parts extends readonly I18nToken<string, any, string>[]>(strings: TemplateStringsArray, ...tokens: Parts): Message<ParamsFromTokens<Parts>>;
|
|
50
|
+
export type PluralBranches = Partial<Record<PluralCategory, Message<unknown>>> & Pick<Record<PluralCategory, Message<unknown>>, 'other'>;
|
|
51
|
+
export declare function plural<CountName extends string, CountValue extends number, const Branches extends PluralBranches>(count: I18nToken<CountName, CountValue, string>, branches: Branches): PluralMessage<CountName, CountValue, Branches>;
|
|
52
|
+
export type TokenDefinition<Name extends string, Value, Kind extends string = string> = {
|
|
53
|
+
readonly name: Name;
|
|
54
|
+
readonly kind: Kind;
|
|
55
|
+
readonly tokenId?: string;
|
|
56
|
+
readonly validate?: (value: unknown) => value is Value;
|
|
57
|
+
readonly format: TokenFormatter<Value>;
|
|
58
|
+
};
|
|
59
|
+
export declare function defineToken<Name extends string, Value, Kind extends string = string>(definition: TokenDefinition<Name, Value, Kind>): I18nToken<Name, Value, Kind>;
|
|
60
|
+
export declare function defineTokenFactory<Kind extends string, Value, Options = undefined>(definition: {
|
|
61
|
+
readonly kind: Kind;
|
|
62
|
+
readonly tokenId?: string;
|
|
63
|
+
readonly format: (options: Options | undefined) => TokenFormatter<Value>;
|
|
64
|
+
}): <Name extends string>(name: Name, adapter?: TokenValueAdapter<Value>, options?: Options) => I18nToken<Name, Value, Kind>;
|
|
65
|
+
export type NumberFormatterOptions = Intl.NumberFormatOptions & {
|
|
66
|
+
readonly timeZone?: never;
|
|
67
|
+
};
|
|
68
|
+
export type DateFormatterOptions = Intl.DateTimeFormatOptions;
|
|
69
|
+
export type RelativeTimeFormatterOptions = {
|
|
70
|
+
readonly unit?: Intl.RelativeTimeFormatUnit;
|
|
71
|
+
readonly numeric?: 'always' | 'auto';
|
|
72
|
+
};
|
|
73
|
+
declare function numberFormat(options?: Intl.NumberFormatOptions): TokenFormatter<number>;
|
|
74
|
+
declare function relativeTimeFormat(options?: RelativeTimeFormatterOptions): TokenFormatter<number>;
|
|
75
|
+
export declare const formatters: {
|
|
76
|
+
readonly number: typeof numberFormat;
|
|
77
|
+
readonly integer: () => TokenFormatter<number>;
|
|
78
|
+
readonly percent: (options?: Intl.NumberFormatOptions) => TokenFormatter<number>;
|
|
79
|
+
readonly compactNumber: (options?: Intl.NumberFormatOptions) => TokenFormatter<number>;
|
|
80
|
+
readonly money: (currency?: string, options?: Intl.NumberFormatOptions) => TokenFormatter<number>;
|
|
81
|
+
readonly dateShort: () => TokenFormatter<number | Date>;
|
|
82
|
+
readonly dateLong: () => TokenFormatter<number | Date>;
|
|
83
|
+
readonly dateTime: (options?: Intl.DateTimeFormatOptions) => TokenFormatter<number | Date>;
|
|
84
|
+
readonly relativeTime: typeof relativeTimeFormat;
|
|
85
|
+
};
|
|
86
|
+
export declare const number: <Name extends string>(name: Name, adapter?: TokenValueAdapter<number> | undefined, options?: NumberFormatterOptions | undefined) => I18nToken<Name, number, "number">;
|
|
87
|
+
export declare const integer: <Name extends string>(name: Name, adapter?: TokenValueAdapter<number> | undefined, options?: undefined) => I18nToken<Name, number, "integer">;
|
|
88
|
+
export declare const percent: <Name extends string>(name: Name, adapter?: TokenValueAdapter<number> | undefined, options?: NumberFormatterOptions | undefined) => I18nToken<Name, number, "percent">;
|
|
89
|
+
export declare const compactNumber: <Name extends string>(name: Name, adapter?: TokenValueAdapter<number> | undefined, options?: NumberFormatterOptions | undefined) => I18nToken<Name, number, "compact-number">;
|
|
90
|
+
export declare const money: <Name extends string>(name: Name, adapter?: TokenValueAdapter<number> | undefined, options?: ({
|
|
91
|
+
readonly currency?: string;
|
|
92
|
+
} & Intl.NumberFormatOptions & {
|
|
93
|
+
readonly timeZone?: never;
|
|
94
|
+
}) | undefined) => I18nToken<Name, number, "money">;
|
|
95
|
+
export declare const dateShort: <Name extends string>(name: Name, adapter?: TokenValueAdapter<number | Date> | undefined, options?: undefined) => I18nToken<Name, number | Date, "date-short">;
|
|
96
|
+
export declare const dateLong: <Name extends string>(name: Name, adapter?: TokenValueAdapter<number | Date> | undefined, options?: undefined) => I18nToken<Name, number | Date, "date-long">;
|
|
97
|
+
export declare const dateTime: <Name extends string>(name: Name, adapter?: TokenValueAdapter<number | Date> | undefined, options?: Intl.DateTimeFormatOptions | undefined) => I18nToken<Name, number | Date, "date-time">;
|
|
98
|
+
export declare const relativeTime: <Name extends string>(name: Name, adapter?: TokenValueAdapter<number> | undefined, options?: RelativeTimeFormatterOptions | undefined) => I18nToken<Name, number, "relative-time">;
|
|
99
|
+
declare const pluralCategoriesByLanguage: {
|
|
100
|
+
readonly ar: readonly ["zero", "one", "two", "few", "many", "other"];
|
|
101
|
+
readonly cy: readonly ["zero", "one", "two", "few", "many", "other"];
|
|
102
|
+
readonly ga: readonly ["one", "two", "few", "many", "other"];
|
|
103
|
+
readonly pl: readonly ["one", "few", "many", "other"];
|
|
104
|
+
readonly ru: readonly ["one", "few", "many", "other"];
|
|
105
|
+
readonly uk: readonly ["one", "few", "many", "other"];
|
|
106
|
+
readonly cs: readonly ["one", "few", "many", "other"];
|
|
107
|
+
readonly sk: readonly ["one", "few", "many", "other"];
|
|
108
|
+
readonly sl: readonly ["one", "two", "few", "other"];
|
|
109
|
+
readonly fr: readonly ["one", "other"];
|
|
110
|
+
readonly en: readonly ["one", "other"];
|
|
111
|
+
};
|
|
112
|
+
export type RequiredPluralCategories<Locale extends string> = Lowercase<Locale> extends `${infer Language}-${string}` ? Language extends keyof typeof pluralCategoriesByLanguage ? (typeof pluralCategoriesByLanguage)[Language][number] : 'one' | 'other' : Lowercase<Locale> extends keyof typeof pluralCategoriesByLanguage ? (typeof pluralCategoriesByLanguage)[Lowercase<Locale>][number] : 'one' | 'other';
|
|
113
|
+
type KeysEqual<Left, Right> = Exclude<keyof Left, keyof Right> extends never ? Exclude<keyof Right, keyof Left> extends never ? true : false : false;
|
|
114
|
+
type MessageParams<T> = T extends Message<infer Params> ? Params : T extends PluralMessage ? T['params'] : never;
|
|
115
|
+
type ValidatePlural<Locale extends string, T> = T extends PluralMessage<infer _CountName, infer _CountValue, infer Branches> ? Exclude<RequiredPluralCategories<Locale>, keyof Branches> extends never ? T : never : T;
|
|
116
|
+
type ValidateCatalog<Locale extends string, T> = T extends PluralMessage ? ValidatePlural<Locale, T> : T extends Message ? T : T extends object ? {
|
|
117
|
+
[Key in keyof T]: ValidateCatalog<Locale, T[Key]>;
|
|
118
|
+
} : T;
|
|
119
|
+
type CompatibleCatalog<Locale extends string, Actual, Expected> = Actual extends Message | PluralMessage ? Expected extends Message | PluralMessage ? [ValidatePlural<Locale, Actual>] extends [never] ? never : KeysEqual<MessageParams<Actual>, MessageParams<Expected>> extends true ? Actual : never : never : Actual extends object ? Expected extends object ? KeysEqual<Actual, Expected> extends true ? {
|
|
120
|
+
[Key in keyof Actual]: CompatibleCatalog<Locale, Actual[Key], Key extends keyof Expected ? Expected[Key] : never>;
|
|
121
|
+
} : never : never : never;
|
|
122
|
+
export type LocaleDefinition<Id extends string = string, T extends Catalog = Catalog> = {
|
|
123
|
+
readonly id: Id;
|
|
124
|
+
readonly catalog: T;
|
|
125
|
+
};
|
|
126
|
+
export type LocaleId<T> = T extends LocaleDefinition<infer Id, Catalog> ? Id : string;
|
|
127
|
+
export declare function defineLocale<const Id extends string, const T extends Catalog>(id: Id, catalog: T & ValidateCatalog<Id, T>): LocaleDefinition<Id, T>;
|
|
128
|
+
export declare function defineLocaleLike<const Reference extends LocaleDefinition, const Id extends string, const T extends Catalog>(_reference: Reference, id: Id, catalog: T & CompatibleCatalog<Id, T, Reference['catalog']>): LocaleDefinition<Id, T>;
|
|
129
|
+
type CatalogOf<T> = T extends LocaleDefinition<string, infer CatalogValue> ? CatalogValue : T;
|
|
130
|
+
type CatalogKeys<T, Prefix extends string = ''> = {
|
|
131
|
+
[Key in keyof T & string]: T[Key] extends Message | PluralMessage ? `${Prefix}${Key}` : T[Key] extends object ? CatalogKeys<T[Key], `${Prefix}${Key}.`> : never;
|
|
132
|
+
}[keyof T & string];
|
|
133
|
+
export type TranslationKey<C> = CatalogKeys<CatalogOf<C>>;
|
|
134
|
+
type NodeAtPath<T, Path extends string> = Path extends `${infer Head}.${infer Tail}` ? Head extends keyof T ? NodeAtPath<T[Head], Tail> : never : Path extends keyof T ? T[Path] : never;
|
|
135
|
+
export type TranslationParams<C, Key extends string> = MessageParams<NodeAtPath<CatalogOf<C>, Key>>;
|
|
136
|
+
export type TranslationParamsArgument<Params> = keyof Params extends never ? [params?: Params] : [params: Params];
|
|
137
|
+
export type CatalogDiagnostic = {
|
|
138
|
+
readonly code: 'MISSING_PLURAL_CATEGORY' | 'INVALID_CATALOG' | 'LOCALE_MISMATCH';
|
|
139
|
+
readonly path: string;
|
|
140
|
+
readonly message: string;
|
|
141
|
+
};
|
|
142
|
+
export declare class I18nRuntimeError extends Error {
|
|
143
|
+
readonly code: string;
|
|
144
|
+
constructor(code: string, message: string);
|
|
145
|
+
}
|
|
146
|
+
export declare function validateCatalog(catalog: Catalog, locale: string, options?: {
|
|
147
|
+
readonly strictPlural?: boolean;
|
|
148
|
+
}): readonly CatalogDiagnostic[];
|
|
149
|
+
export declare function assertValidCatalog(catalog: Catalog, locale: string): void;
|
|
150
|
+
export declare function validateLocaleParity(reference: Catalog, candidate: Catalog): readonly CatalogDiagnostic[];
|
|
151
|
+
export declare function assertLocaleParity(reference: Catalog, candidate: Catalog): void;
|
|
152
|
+
export type I18nLoader<Locale extends LocaleDefinition = LocaleDefinition> = {
|
|
153
|
+
readonly load: (id: string) => Promise<Locale>;
|
|
154
|
+
readonly clear: () => void;
|
|
155
|
+
readonly has: (id: string) => boolean;
|
|
156
|
+
};
|
|
157
|
+
export declare function createI18nLoader<Locale extends LocaleDefinition>(load: (id: string) => Promise<Locale>): I18nLoader<Locale>;
|
|
158
|
+
export type I18nRuntime<Locales extends readonly LocaleDefinition[]> = {
|
|
159
|
+
readonly locale: () => Locales[number]['id'];
|
|
160
|
+
readonly setLocale: (id: Locales[number]['id']) => void;
|
|
161
|
+
readonly translate: <Key extends TranslationKey<Locales[number]>>(key: Key, ...params: TranslationParamsArgument<TranslationParams<Locales[number], Key & string>>) => string;
|
|
162
|
+
readonly t: I18nRuntime<Locales>['translate'];
|
|
163
|
+
readonly bind: (dependency: ReactiveTranslationDependency) => ReactiveTranslator<Locales>;
|
|
164
|
+
readonly loadLocale: (id: Locales[number]['id']) => Promise<void>;
|
|
165
|
+
};
|
|
166
|
+
export type ReactiveTranslationDependency = () => Generator<unknown, unknown, unknown>;
|
|
167
|
+
export type ReactiveTranslator<Locales extends readonly LocaleDefinition[]> = <Key extends TranslationKey<Locales[number]>>(key: Key, ...params: TranslationParamsArgument<TranslationParams<Locales[number], Key & string>>) => () => Generator<unknown, string, unknown>;
|
|
168
|
+
export declare function createI18nRuntime<const Locales extends readonly LocaleDefinition[]>(options: {
|
|
169
|
+
readonly locales: Locales;
|
|
170
|
+
readonly defaultLocale?: Locales[number]['id'];
|
|
171
|
+
readonly strict?: boolean;
|
|
172
|
+
readonly timeZone?: string;
|
|
173
|
+
readonly loader?: I18nLoader;
|
|
174
|
+
}): I18nRuntime<Locales>;
|
|
175
|
+
export declare function createReactiveTranslator<const Locales extends readonly LocaleDefinition[]>(options: {
|
|
176
|
+
readonly runtime: Pick<I18nRuntime<Locales>, 'translate'>;
|
|
177
|
+
readonly dependency: ReactiveTranslationDependency;
|
|
178
|
+
}): ReactiveTranslator<Locales>;
|
|
179
|
+
export declare function serializeToken<Name extends string, Value, Kind extends string>(token: I18nToken<Name, Value, Kind>): {
|
|
180
|
+
readonly token: string;
|
|
181
|
+
readonly name: string;
|
|
182
|
+
};
|
|
183
|
+
export type SerializedCatalog = {
|
|
184
|
+
readonly kind: 'catalog';
|
|
185
|
+
readonly entries: Readonly<Record<string, unknown>>;
|
|
186
|
+
};
|
|
187
|
+
/**
|
|
188
|
+
* Produces a JSON-safe delivery representation. Formatters are deliberately
|
|
189
|
+
* represented by stable token ids; the application registers their executable
|
|
190
|
+
* formatters when it renders the catalogue.
|
|
191
|
+
*/
|
|
192
|
+
export declare function serializeCatalog(catalog: Catalog): SerializedCatalog;
|
|
193
|
+
export {};
|
|
194
|
+
//# sourceMappingURL=i18n.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../../../../libs/i18n/src/lib/i18n.ts"],"names":[],"mappings":"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"}
|
package/src/lib/i18n.js
ADDED
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file intentionally has no CraftTS, Angular or Effect import. The
|
|
3
|
+
* catalogue is a plain TypeScript value and the runtime is usable in a
|
|
4
|
+
* browser, a server, a worker, or a test without a framework.
|
|
5
|
+
*/
|
|
6
|
+
function isMessage(value) {
|
|
7
|
+
return typeof value === 'object' && value !== null && value.kind === 'message';
|
|
8
|
+
}
|
|
9
|
+
function isPlural(value) {
|
|
10
|
+
return typeof value === 'object' && value !== null && value.kind === 'plural';
|
|
11
|
+
}
|
|
12
|
+
export function defineCatalog(catalog) {
|
|
13
|
+
return catalog;
|
|
14
|
+
}
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16
|
+
export function msg(strings, ...tokens) {
|
|
17
|
+
const parts = [];
|
|
18
|
+
for (let index = 0; index < strings.length; index += 1) {
|
|
19
|
+
const text = strings[index];
|
|
20
|
+
if (text)
|
|
21
|
+
parts.push(text);
|
|
22
|
+
const token = tokens[index];
|
|
23
|
+
if (token)
|
|
24
|
+
parts.push(token);
|
|
25
|
+
}
|
|
26
|
+
return { kind: 'message', parts, params: undefined };
|
|
27
|
+
}
|
|
28
|
+
export function plural(count, branches) {
|
|
29
|
+
return {
|
|
30
|
+
kind: 'plural',
|
|
31
|
+
count,
|
|
32
|
+
branches,
|
|
33
|
+
params: undefined,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export function defineToken(definition) {
|
|
37
|
+
return {
|
|
38
|
+
__i18nToken: true,
|
|
39
|
+
name: definition.name,
|
|
40
|
+
kind: definition.kind,
|
|
41
|
+
tokenId: definition.tokenId ?? `app.${definition.kind}`,
|
|
42
|
+
validate: definition.validate,
|
|
43
|
+
format: definition.format,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export function defineTokenFactory(definition) {
|
|
47
|
+
return function create(name, adapter, options) {
|
|
48
|
+
return defineToken({
|
|
49
|
+
name,
|
|
50
|
+
kind: definition.kind,
|
|
51
|
+
tokenId: definition.tokenId,
|
|
52
|
+
validate: typeof adapter === 'function' ? adapter : adapter?.validate,
|
|
53
|
+
format: definition.format(options),
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function numberFormat(options = {}) {
|
|
58
|
+
const formatter = ((value, context) => {
|
|
59
|
+
if (!Number.isFinite(value))
|
|
60
|
+
throw new I18nRuntimeError('INVALID_NUMBER', 'Cannot format a non-finite number.');
|
|
61
|
+
return new Intl.NumberFormat(context.locale, options).format(value);
|
|
62
|
+
});
|
|
63
|
+
Object.defineProperty(formatter, 'id', { value: 'number', enumerable: true });
|
|
64
|
+
return formatter;
|
|
65
|
+
}
|
|
66
|
+
function dateFormat(options = {}) {
|
|
67
|
+
const formatter = ((value, context) => {
|
|
68
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
69
|
+
if (Number.isNaN(date.getTime()))
|
|
70
|
+
throw new I18nRuntimeError('INVALID_DATE', 'Cannot format an invalid date.');
|
|
71
|
+
return new Intl.DateTimeFormat(context.locale, { ...options, timeZone: context.timeZone ?? options.timeZone }).format(date);
|
|
72
|
+
});
|
|
73
|
+
Object.defineProperty(formatter, 'id', { value: 'date', enumerable: true });
|
|
74
|
+
return formatter;
|
|
75
|
+
}
|
|
76
|
+
function relativeTimeFormat(options = {}) {
|
|
77
|
+
const formatter = ((value, context) => {
|
|
78
|
+
if (!Number.isFinite(value))
|
|
79
|
+
throw new I18nRuntimeError('INVALID_NUMBER', 'Cannot format a non-finite relative time.');
|
|
80
|
+
return new Intl.RelativeTimeFormat(context.locale, {
|
|
81
|
+
numeric: options.numeric ?? 'auto',
|
|
82
|
+
}).format(value, options.unit ?? 'day');
|
|
83
|
+
});
|
|
84
|
+
Object.defineProperty(formatter, 'id', { value: 'relative-time', enumerable: true });
|
|
85
|
+
return formatter;
|
|
86
|
+
}
|
|
87
|
+
export const formatters = {
|
|
88
|
+
number: numberFormat,
|
|
89
|
+
integer: () => numberFormat({ maximumFractionDigits: 0 }),
|
|
90
|
+
percent: (options = {}) => numberFormat({ style: 'percent', ...options }),
|
|
91
|
+
compactNumber: (options = {}) => numberFormat({ notation: 'compact', ...options }),
|
|
92
|
+
money: (currency = 'EUR', options = {}) => numberFormat({ style: 'currency', currency, ...options }),
|
|
93
|
+
dateShort: () => dateFormat({ dateStyle: 'short' }),
|
|
94
|
+
dateLong: () => dateFormat({ dateStyle: 'long' }),
|
|
95
|
+
dateTime: (options = {}) => dateFormat(options),
|
|
96
|
+
relativeTime: relativeTimeFormat,
|
|
97
|
+
};
|
|
98
|
+
export const number = defineTokenFactory({ kind: 'number', format: (options) => numberFormat(options) });
|
|
99
|
+
export const integer = defineTokenFactory({ kind: 'integer', format: () => formatters.integer() });
|
|
100
|
+
export const percent = defineTokenFactory({ kind: 'percent', format: (options) => formatters.percent(options) });
|
|
101
|
+
export const compactNumber = defineTokenFactory({ kind: 'compact-number', format: (options) => formatters.compactNumber(options) });
|
|
102
|
+
export const money = defineTokenFactory({ kind: 'money', format: (options) => formatters.money(options?.currency ?? 'EUR', options) });
|
|
103
|
+
export const dateShort = defineTokenFactory({ kind: 'date-short', format: () => formatters.dateShort() });
|
|
104
|
+
export const dateLong = defineTokenFactory({ kind: 'date-long', format: () => formatters.dateLong() });
|
|
105
|
+
export const dateTime = defineTokenFactory({ kind: 'date-time', format: (options) => formatters.dateTime(options) });
|
|
106
|
+
export const relativeTime = defineTokenFactory({ kind: 'relative-time', format: (options) => formatters.relativeTime(options) });
|
|
107
|
+
const pluralCategoriesByLanguage = {
|
|
108
|
+
ar: ['zero', 'one', 'two', 'few', 'many', 'other'],
|
|
109
|
+
cy: ['zero', 'one', 'two', 'few', 'many', 'other'],
|
|
110
|
+
ga: ['one', 'two', 'few', 'many', 'other'],
|
|
111
|
+
pl: ['one', 'few', 'many', 'other'],
|
|
112
|
+
ru: ['one', 'few', 'many', 'other'],
|
|
113
|
+
uk: ['one', 'few', 'many', 'other'],
|
|
114
|
+
cs: ['one', 'few', 'many', 'other'],
|
|
115
|
+
sk: ['one', 'few', 'many', 'other'],
|
|
116
|
+
sl: ['one', 'two', 'few', 'other'],
|
|
117
|
+
fr: ['one', 'other'],
|
|
118
|
+
en: ['one', 'other'],
|
|
119
|
+
};
|
|
120
|
+
function requiredPluralCategories(locale) {
|
|
121
|
+
const language = locale.toLowerCase().split('-')[0] ?? locale.toLowerCase();
|
|
122
|
+
return pluralCategoriesByLanguage[language] ?? new Intl.PluralRules(locale).resolvedOptions().pluralCategories;
|
|
123
|
+
}
|
|
124
|
+
export function defineLocale(id, catalog) {
|
|
125
|
+
// Asserts rather than validates: `validateCatalog` only *returns*
|
|
126
|
+
// diagnostics, so calling it here computed the answer and dropped it. The
|
|
127
|
+
// type-level check covers a catalogue written by hand; this one covers the
|
|
128
|
+
// rest — a catalogue built dynamically, deserialised, or cast.
|
|
129
|
+
assertValidCatalog(catalog, id);
|
|
130
|
+
return { id, catalog };
|
|
131
|
+
}
|
|
132
|
+
export function defineLocaleLike(_reference, id, catalog) {
|
|
133
|
+
assertValidCatalog(catalog, id);
|
|
134
|
+
assertLocaleParity(_reference.catalog, catalog);
|
|
135
|
+
return { id, catalog };
|
|
136
|
+
}
|
|
137
|
+
export class I18nRuntimeError extends Error {
|
|
138
|
+
code;
|
|
139
|
+
constructor(code, message) {
|
|
140
|
+
super(message);
|
|
141
|
+
this.name = 'I18nRuntimeError';
|
|
142
|
+
this.code = code;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
export function validateCatalog(catalog, locale, options = {}) {
|
|
146
|
+
const diagnostics = [];
|
|
147
|
+
const visit = (node, path) => {
|
|
148
|
+
if (isPlural(node)) {
|
|
149
|
+
if (options.strictPlural !== false) {
|
|
150
|
+
for (const category of requiredPluralCategories(locale)) {
|
|
151
|
+
if (!node.branches[category])
|
|
152
|
+
diagnostics.push({
|
|
153
|
+
code: 'MISSING_PLURAL_CATEGORY',
|
|
154
|
+
path,
|
|
155
|
+
message: `Locale ${locale} requires plural category ${category}.`,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
for (const [category, branch] of Object.entries(node.branches)) {
|
|
160
|
+
if (branch)
|
|
161
|
+
visit(branch, `${path}.${category}`);
|
|
162
|
+
}
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (isMessage(node))
|
|
166
|
+
return;
|
|
167
|
+
if (typeof node !== 'object' || node === null) {
|
|
168
|
+
diagnostics.push({ code: 'INVALID_CATALOG', path, message: 'Catalog nodes must be messages, plurals, or objects.' });
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
for (const [key, child] of Object.entries(node))
|
|
172
|
+
visit(child, path ? `${path}.${key}` : key);
|
|
173
|
+
};
|
|
174
|
+
visit(catalog, '');
|
|
175
|
+
return diagnostics;
|
|
176
|
+
}
|
|
177
|
+
export function assertValidCatalog(catalog, locale) {
|
|
178
|
+
const diagnostics = validateCatalog(catalog, locale, { strictPlural: true });
|
|
179
|
+
if (diagnostics.length > 0)
|
|
180
|
+
throw new I18nRuntimeError('INVALID_CATALOG', diagnostics.map((item) => `${item.path}: ${item.message}`).join('\n'));
|
|
181
|
+
}
|
|
182
|
+
export function validateLocaleParity(reference, candidate) {
|
|
183
|
+
const diagnostics = [];
|
|
184
|
+
const compare = (left, right, path) => {
|
|
185
|
+
if (isMessage(left) || isMessage(right)) {
|
|
186
|
+
if (!isMessage(left) || !isMessage(right)) {
|
|
187
|
+
diagnostics.push({ code: 'LOCALE_MISMATCH', path, message: 'Locale message shape does not match the reference.' });
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const leftTokens = left.parts.filter((part) => typeof part !== 'string').map((part) => `${part.name}:${part.kind}`).sort();
|
|
191
|
+
const rightTokens = right.parts.filter((part) => typeof part !== 'string').map((part) => `${part.name}:${part.kind}`).sort();
|
|
192
|
+
if (leftTokens.join('|') !== rightTokens.join('|'))
|
|
193
|
+
diagnostics.push({ code: 'LOCALE_MISMATCH', path, message: 'Locale token set does not match the reference.' });
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (isPlural(left) || isPlural(right)) {
|
|
197
|
+
if (!isPlural(left) || !isPlural(right) || left.count.name !== right.count.name || left.count.kind !== right.count.kind) {
|
|
198
|
+
diagnostics.push({ code: 'LOCALE_MISMATCH', path, message: 'Locale plural selector does not match the reference.' });
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
for (const category of Object.keys(left.branches)) {
|
|
202
|
+
const branch = left.branches[category];
|
|
203
|
+
const candidateBranch = right.branches[category];
|
|
204
|
+
if (!candidateBranch)
|
|
205
|
+
diagnostics.push({ code: 'LOCALE_MISMATCH', path: `${path}.${category}`, message: 'Locale is missing a reference plural branch.' });
|
|
206
|
+
else if (branch)
|
|
207
|
+
compare(branch, candidateBranch, `${path}.${category}`);
|
|
208
|
+
}
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (typeof left !== 'object' || left === null || typeof right !== 'object' || right === null) {
|
|
212
|
+
diagnostics.push({ code: 'LOCALE_MISMATCH', path, message: 'Locale node shape does not match the reference.' });
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
const leftKeys = Object.keys(left).sort();
|
|
216
|
+
const rightKeys = Object.keys(right).sort();
|
|
217
|
+
if (leftKeys.join('|') !== rightKeys.join('|')) {
|
|
218
|
+
diagnostics.push({ code: 'LOCALE_MISMATCH', path, message: 'Locale keys do not match the reference.' });
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
for (const key of leftKeys)
|
|
222
|
+
compare(left[key], right[key], path ? `${path}.${key}` : key);
|
|
223
|
+
};
|
|
224
|
+
compare(reference, candidate, '');
|
|
225
|
+
return diagnostics;
|
|
226
|
+
}
|
|
227
|
+
export function assertLocaleParity(reference, candidate) {
|
|
228
|
+
const diagnostics = validateLocaleParity(reference, candidate);
|
|
229
|
+
if (diagnostics.length > 0)
|
|
230
|
+
throw new I18nRuntimeError('LOCALE_MISMATCH', diagnostics.map((item) => `${item.path}: ${item.message}`).join('\n'));
|
|
231
|
+
}
|
|
232
|
+
function nodeAt(catalog, key) {
|
|
233
|
+
let node = catalog;
|
|
234
|
+
for (const part of key.split('.'))
|
|
235
|
+
node = node[part];
|
|
236
|
+
if (isMessage(node) || isPlural(node))
|
|
237
|
+
return node;
|
|
238
|
+
throw new I18nRuntimeError('UNKNOWN_KEY', `Unknown translation key: ${key}`);
|
|
239
|
+
}
|
|
240
|
+
function renderMessage(message, params, context) {
|
|
241
|
+
return message.parts.map((part) => {
|
|
242
|
+
if (typeof part === 'string')
|
|
243
|
+
return part;
|
|
244
|
+
const value = params[part.name];
|
|
245
|
+
if (value === undefined)
|
|
246
|
+
throw new I18nRuntimeError('MISSING_PARAM', `Missing parameter ${part.name}.`);
|
|
247
|
+
if (part.validate && !part.validate(value))
|
|
248
|
+
throw new I18nRuntimeError('INVALID_PARAM', `Invalid parameter ${part.name}.`);
|
|
249
|
+
return part.format(value, context);
|
|
250
|
+
}).join('');
|
|
251
|
+
}
|
|
252
|
+
function renderNode(node, params, context) {
|
|
253
|
+
if (isMessage(node))
|
|
254
|
+
return renderMessage(node, params, context);
|
|
255
|
+
const count = params[node.count.name];
|
|
256
|
+
if (typeof count !== 'number' || !Number.isFinite(count))
|
|
257
|
+
throw new I18nRuntimeError('INVALID_PLURAL_COUNT', `Plural count ${node.count.name} must be a finite number.`);
|
|
258
|
+
const category = new Intl.PluralRules(context.locale).select(count);
|
|
259
|
+
const branch = node.branches[category];
|
|
260
|
+
if (!branch)
|
|
261
|
+
throw new I18nRuntimeError('MISSING_PLURAL_CATEGORY', `Missing plural category ${category} for ${context.locale}.`);
|
|
262
|
+
return renderMessage(branch, params, context);
|
|
263
|
+
}
|
|
264
|
+
export function createI18nLoader(load) {
|
|
265
|
+
const cache = new Map();
|
|
266
|
+
return {
|
|
267
|
+
load: (id) => {
|
|
268
|
+
const current = cache.get(id);
|
|
269
|
+
if (current)
|
|
270
|
+
return current;
|
|
271
|
+
const pending = load(id);
|
|
272
|
+
cache.set(id, pending);
|
|
273
|
+
return pending.catch((error) => {
|
|
274
|
+
cache.delete(id);
|
|
275
|
+
throw error;
|
|
276
|
+
});
|
|
277
|
+
},
|
|
278
|
+
clear: () => cache.clear(),
|
|
279
|
+
has: (id) => cache.has(id),
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
export function createI18nRuntime(options) {
|
|
283
|
+
if (options.locales.length === 0)
|
|
284
|
+
throw new I18nRuntimeError('NO_LOCALES', 'At least one locale is required.');
|
|
285
|
+
const locales = new Map(options.locales.map((locale) => [locale.id, locale]));
|
|
286
|
+
let current = options.defaultLocale ?? options.locales[0].id;
|
|
287
|
+
const loaded = new Map(locales);
|
|
288
|
+
if (options.strict !== false)
|
|
289
|
+
for (const locale of options.locales)
|
|
290
|
+
assertValidCatalog(locale.catalog, locale.id);
|
|
291
|
+
if (options.strict !== false)
|
|
292
|
+
for (const locale of options.locales.slice(1))
|
|
293
|
+
assertLocaleParity(options.locales[0].catalog, locale.catalog);
|
|
294
|
+
const loadLocale = async (id) => {
|
|
295
|
+
if (loaded.has(id))
|
|
296
|
+
return;
|
|
297
|
+
if (!options.loader)
|
|
298
|
+
throw new I18nRuntimeError('LOCALE_NOT_LOADED', `Locale ${id} has not been loaded.`);
|
|
299
|
+
const locale = await options.loader.load(id);
|
|
300
|
+
loaded.set(id, locale);
|
|
301
|
+
};
|
|
302
|
+
const translate = ((key, params) => {
|
|
303
|
+
const locale = loaded.get(current);
|
|
304
|
+
if (!locale)
|
|
305
|
+
throw new I18nRuntimeError('LOCALE_NOT_LOADED', `Locale ${current} has not been loaded.`);
|
|
306
|
+
const node = nodeAt(locale.catalog, key);
|
|
307
|
+
return renderNode(node, params ?? {}, { locale: current, timeZone: options.timeZone });
|
|
308
|
+
});
|
|
309
|
+
return {
|
|
310
|
+
locale: () => current,
|
|
311
|
+
setLocale: (id) => {
|
|
312
|
+
if (!loaded.has(id))
|
|
313
|
+
throw new I18nRuntimeError('LOCALE_NOT_LOADED', `Locale ${id} has not been loaded.`);
|
|
314
|
+
current = id;
|
|
315
|
+
},
|
|
316
|
+
translate,
|
|
317
|
+
t: translate,
|
|
318
|
+
bind: (dependency) => createReactiveTranslator({
|
|
319
|
+
runtime: { translate },
|
|
320
|
+
dependency,
|
|
321
|
+
}),
|
|
322
|
+
loadLocale,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
export function createReactiveTranslator(options) {
|
|
326
|
+
return ((key, params) => function* () {
|
|
327
|
+
yield* options.dependency();
|
|
328
|
+
return options.runtime.translate(key, params);
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
export function serializeToken(token) {
|
|
332
|
+
return { token: token.tokenId, name: token.name };
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Produces a JSON-safe delivery representation. Formatters are deliberately
|
|
336
|
+
* represented by stable token ids; the application registers their executable
|
|
337
|
+
* formatters when it renders the catalogue.
|
|
338
|
+
*/
|
|
339
|
+
export function serializeCatalog(catalog) {
|
|
340
|
+
const serialize = (node) => {
|
|
341
|
+
if (isMessage(node)) {
|
|
342
|
+
return {
|
|
343
|
+
kind: 'message',
|
|
344
|
+
parts: node.parts.map((part) => typeof part === 'string' ? part : serializeToken(part)),
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
if (isPlural(node)) {
|
|
348
|
+
return {
|
|
349
|
+
kind: 'plural',
|
|
350
|
+
count: serializeToken(node.count),
|
|
351
|
+
branches: Object.fromEntries(Object.entries(node.branches).map(([category, branch]) => [category, serialize(branch)])),
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
if (typeof node === 'object' && node !== null) {
|
|
355
|
+
return Object.fromEntries(Object.entries(node).map(([key, value]) => [key, serialize(value)]));
|
|
356
|
+
}
|
|
357
|
+
return node;
|
|
358
|
+
};
|
|
359
|
+
return { kind: 'catalog', entries: serialize(catalog) };
|
|
360
|
+
}
|
|
361
|
+
//# sourceMappingURL=i18n.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.js","sourceRoot":"","sources":["../../../../../libs/i18n/src/lib/i18n.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * This file intentionally has no CraftTS, Angular or Effect import. The\n * catalogue is a plain TypeScript value and the runtime is usable in a\n * browser, a server, a worker, or a test without a framework.\n */\n\nexport type PluralCategory = 'zero' | 'one' | 'two' | 'few' | 'many' | 'other';\nexport type FormatterContext = {\n readonly locale: string;\n readonly timeZone?: string;\n};\nexport type TokenFormatter<Value> = ((value: Value, context: FormatterContext) => string) & {\n readonly id?: string;\n};\nexport type TokenValueAdapter<Value> = {\n readonly validate?: (value: unknown) => value is Value;\n readonly name?: string;\n} | ((value: unknown) => value is Value);\n\nexport type I18nToken<Name extends string = string, Value = unknown, Kind extends string = string> = {\n readonly __i18nToken: true;\n readonly name: Name;\n readonly kind: Kind;\n readonly tokenId: string;\n readonly validate?: (value: unknown) => value is Value;\n readonly format: TokenFormatter<Value>;\n};\n\ntype Simplify<T> = { [Key in keyof T]: T[Key] } & {};\ntype UnionToIntersection<T> =\n (T extends unknown ? (value: T) => void : never) extends (value: infer I) => void\n ? I\n : never;\ntype TokenParams<T> = T extends I18nToken<infer Name, infer Value, infer _Kind>\n ? { [Key in Name]: Value }\n : Record<never, never>;\ntype ParamsFromTokens<T extends readonly unknown[]> = Simplify<\n UnionToIntersection<TokenParams<T[number]>>\n>;\n\nexport type Message<Params = Record<never, never>> = {\n readonly kind: 'message';\n // The erased token union is intentionally bivariant; concrete tokens keep their value type in Params.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n readonly parts: readonly (string | I18nToken<string, any, string>)[];\n readonly params: Params;\n};\n\nexport type PluralMessage<\n CountName extends string = string,\n CountValue extends number = number,\n Branches extends Partial<Record<PluralCategory, Message<unknown>>> = Partial<Record<PluralCategory, Message<unknown>>>,\n> = {\n readonly kind: 'plural';\n readonly count: I18nToken<CountName, CountValue, string>;\n readonly branches: Branches;\n readonly params: Simplify<\n { [Key in CountName]: CountValue } &\n (Branches[keyof Branches] extends Message<infer Params> ? Params : Record<never, never>)\n >;\n};\n\nexport type CatalogNode = Message | PluralMessage | { readonly [key: string]: CatalogNode };\nexport type Catalog = { readonly [key: string]: CatalogNode };\n\nfunction isMessage(value: unknown): value is Message<unknown> {\n return typeof value === 'object' && value !== null && (value as { kind?: unknown }).kind === 'message';\n}\n\nfunction isPlural(value: unknown): value is PluralMessage {\n return typeof value === 'object' && value !== null && (value as { kind?: unknown }).kind === 'plural';\n}\n\nexport function defineCatalog<const T extends Catalog>(catalog: T): T {\n return catalog;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function msg<const Parts extends readonly I18nToken<string, any, string>[]>(\n strings: TemplateStringsArray,\n ...tokens: Parts\n): Message<ParamsFromTokens<Parts>> {\n const parts: (string | I18nToken)[] = [];\n for (let index = 0; index < strings.length; index += 1) {\n const text = strings[index];\n if (text) parts.push(text);\n const token = tokens[index];\n if (token) parts.push(token);\n }\n return { kind: 'message', parts, params: undefined as unknown as ParamsFromTokens<Parts> };\n}\n\nexport type PluralBranches = Partial<Record<PluralCategory, Message<unknown>>> &\n Pick<Record<PluralCategory, Message<unknown>>, 'other'>;\n\nexport function plural<\n CountName extends string,\n CountValue extends number,\n const Branches extends PluralBranches,\n>(\n count: I18nToken<CountName, CountValue, string>,\n branches: Branches,\n): PluralMessage<CountName, CountValue, Branches> {\n return {\n kind: 'plural',\n count,\n branches,\n params: undefined as unknown as PluralMessage<CountName, CountValue, Branches>['params'],\n };\n}\n\nexport type TokenDefinition<Name extends string, Value, Kind extends string = string> = {\n readonly name: Name;\n readonly kind: Kind;\n readonly tokenId?: string;\n readonly validate?: (value: unknown) => value is Value;\n readonly format: TokenFormatter<Value>;\n};\n\nexport function defineToken<Name extends string, Value, Kind extends string = string>(\n definition: TokenDefinition<Name, Value, Kind>,\n): I18nToken<Name, Value, Kind> {\n return {\n __i18nToken: true,\n name: definition.name,\n kind: definition.kind,\n tokenId: definition.tokenId ?? `app.${definition.kind}`,\n validate: definition.validate,\n format: definition.format,\n };\n}\n\nexport function defineTokenFactory<Kind extends string, Value, Options = undefined>(definition: {\n readonly kind: Kind;\n readonly tokenId?: string;\n readonly format: (options: Options | undefined) => TokenFormatter<Value>;\n}) {\n return function create<Name extends string>(\n name: Name,\n adapter?: TokenValueAdapter<Value>,\n options?: Options,\n ): I18nToken<Name, Value, Kind> {\n return defineToken({\n name,\n kind: definition.kind,\n tokenId: definition.tokenId,\n validate: typeof adapter === 'function' ? adapter : adapter?.validate,\n format: definition.format(options),\n });\n };\n}\n\nexport type NumberFormatterOptions = Intl.NumberFormatOptions & {\n readonly timeZone?: never;\n};\nexport type DateFormatterOptions = Intl.DateTimeFormatOptions;\nexport type RelativeTimeFormatterOptions = {\n readonly unit?: Intl.RelativeTimeFormatUnit;\n readonly numeric?: 'always' | 'auto';\n};\n\nfunction numberFormat(options: Intl.NumberFormatOptions = {}): TokenFormatter<number> {\n const formatter = ((value: number, context: FormatterContext) => {\n if (!Number.isFinite(value)) throw new I18nRuntimeError('INVALID_NUMBER', 'Cannot format a non-finite number.');\n return new Intl.NumberFormat(context.locale, options).format(value);\n }) as unknown as TokenFormatter<number>;\n Object.defineProperty(formatter, 'id', { value: 'number', enumerable: true });\n return formatter;\n}\n\nfunction dateFormat(options: Intl.DateTimeFormatOptions = {}): TokenFormatter<Date | number> {\n const formatter = ((value: Date | number, context: FormatterContext) => {\n const date = value instanceof Date ? value : new Date(value);\n if (Number.isNaN(date.getTime())) throw new I18nRuntimeError('INVALID_DATE', 'Cannot format an invalid date.');\n return new Intl.DateTimeFormat(context.locale, { ...options, timeZone: context.timeZone ?? options.timeZone }).format(date);\n }) as unknown as TokenFormatter<Date | number>;\n Object.defineProperty(formatter, 'id', { value: 'date', enumerable: true });\n return formatter;\n}\n\nfunction relativeTimeFormat(options: RelativeTimeFormatterOptions = {}): TokenFormatter<number> {\n const formatter = ((value: number, context: FormatterContext) => {\n if (!Number.isFinite(value)) throw new I18nRuntimeError('INVALID_NUMBER', 'Cannot format a non-finite relative time.');\n return new Intl.RelativeTimeFormat(context.locale, {\n numeric: options.numeric ?? 'auto',\n }).format(value, options.unit ?? 'day');\n }) as unknown as TokenFormatter<number>;\n Object.defineProperty(formatter, 'id', { value: 'relative-time', enumerable: true });\n return formatter;\n}\n\nexport const formatters = {\n number: numberFormat,\n integer: () => numberFormat({ maximumFractionDigits: 0 }),\n percent: (options: Intl.NumberFormatOptions = {}) => numberFormat({ style: 'percent', ...options }),\n compactNumber: (options: Intl.NumberFormatOptions = {}) => numberFormat({ notation: 'compact', ...options }),\n money: (currency = 'EUR', options: Intl.NumberFormatOptions = {}) =>\n numberFormat({ style: 'currency', currency, ...options }),\n dateShort: () => dateFormat({ dateStyle: 'short' }),\n dateLong: () => dateFormat({ dateStyle: 'long' }),\n dateTime: (options: Intl.DateTimeFormatOptions = {}) => dateFormat(options),\n relativeTime: relativeTimeFormat,\n} as const;\n\nexport const number = defineTokenFactory({ kind: 'number', format: (options?: NumberFormatterOptions) => numberFormat(options) });\nexport const integer = defineTokenFactory({ kind: 'integer', format: () => formatters.integer() });\nexport const percent = defineTokenFactory({ kind: 'percent', format: (options?: NumberFormatterOptions) => formatters.percent(options) });\nexport const compactNumber = defineTokenFactory({ kind: 'compact-number', format: (options?: NumberFormatterOptions) => formatters.compactNumber(options) });\nexport const money = defineTokenFactory({ kind: 'money', format: (options?: { readonly currency?: string } & NumberFormatterOptions) => formatters.money(options?.currency ?? 'EUR', options) });\nexport const dateShort = defineTokenFactory({ kind: 'date-short', format: () => formatters.dateShort() });\nexport const dateLong = defineTokenFactory({ kind: 'date-long', format: () => formatters.dateLong() });\nexport const dateTime = defineTokenFactory({ kind: 'date-time', format: (options?: DateFormatterOptions) => formatters.dateTime(options) });\nexport const relativeTime = defineTokenFactory({ kind: 'relative-time', format: (options?: RelativeTimeFormatterOptions) => formatters.relativeTime(options) });\n\nconst pluralCategoriesByLanguage = {\n ar: ['zero', 'one', 'two', 'few', 'many', 'other'],\n cy: ['zero', 'one', 'two', 'few', 'many', 'other'],\n ga: ['one', 'two', 'few', 'many', 'other'],\n pl: ['one', 'few', 'many', 'other'],\n ru: ['one', 'few', 'many', 'other'],\n uk: ['one', 'few', 'many', 'other'],\n cs: ['one', 'few', 'many', 'other'],\n sk: ['one', 'few', 'many', 'other'],\n sl: ['one', 'two', 'few', 'other'],\n fr: ['one', 'other'],\n en: ['one', 'other'],\n} as const;\n\nexport type RequiredPluralCategories<Locale extends string> =\n Lowercase<Locale> extends `${infer Language}-${string}`\n ? Language extends keyof typeof pluralCategoriesByLanguage\n ? (typeof pluralCategoriesByLanguage)[Language][number]\n : 'one' | 'other'\n : Lowercase<Locale> extends keyof typeof pluralCategoriesByLanguage\n ? (typeof pluralCategoriesByLanguage)[Lowercase<Locale>][number]\n : 'one' | 'other';\n\nfunction requiredPluralCategories(locale: string): readonly PluralCategory[] {\n const language = locale.toLowerCase().split('-')[0] ?? locale.toLowerCase();\n return (pluralCategoriesByLanguage as Record<string, readonly PluralCategory[]>)[language] ?? new Intl.PluralRules(locale).resolvedOptions().pluralCategories as PluralCategory[];\n}\n\ntype KeysEqual<Left, Right> =\n Exclude<keyof Left, keyof Right> extends never\n ? Exclude<keyof Right, keyof Left> extends never ? true : false\n : false;\ntype MessageParams<T> = T extends Message<infer Params> ? Params : T extends PluralMessage ? T['params'] : never;\ntype ValidatePlural<Locale extends string, T> = T extends PluralMessage<infer _CountName, infer _CountValue, infer Branches>\n ? Exclude<RequiredPluralCategories<Locale>, keyof Branches> extends never\n ? T\n : never\n : T;\ntype ValidateCatalog<Locale extends string, T> = T extends PluralMessage\n ? ValidatePlural<Locale, T>\n : T extends Message\n ? T\n : T extends object\n ? { [Key in keyof T]: ValidateCatalog<Locale, T[Key]> }\n : T;\ntype CompatibleCatalog<Locale extends string, Actual, Expected> =\n Actual extends Message | PluralMessage\n ? Expected extends Message | PluralMessage\n ? [ValidatePlural<Locale, Actual>] extends [never]\n ? never\n : KeysEqual<MessageParams<Actual>, MessageParams<Expected>> extends true ? Actual : never\n : never\n : Actual extends object\n ? Expected extends object\n ? KeysEqual<Actual, Expected> extends true\n ? { [Key in keyof Actual]: CompatibleCatalog<Locale, Actual[Key], Key extends keyof Expected ? Expected[Key] : never> }\n : never\n : never\n : never;\n\nexport type LocaleDefinition<Id extends string = string, T extends Catalog = Catalog> = {\n readonly id: Id;\n readonly catalog: T;\n};\nexport type LocaleId<T> = T extends LocaleDefinition<infer Id, Catalog> ? Id : string;\n\nexport function defineLocale<const Id extends string, const T extends Catalog>(\n id: Id,\n catalog: T & ValidateCatalog<Id, T>,\n): LocaleDefinition<Id, T> {\n // Asserts rather than validates: `validateCatalog` only *returns*\n // diagnostics, so calling it here computed the answer and dropped it. The\n // type-level check covers a catalogue written by hand; this one covers the\n // rest — a catalogue built dynamically, deserialised, or cast.\n assertValidCatalog(catalog, id);\n return { id, catalog };\n}\n\nexport function defineLocaleLike<\n const Reference extends LocaleDefinition,\n const Id extends string,\n const T extends Catalog,\n>(\n _reference: Reference,\n id: Id,\n catalog: T & CompatibleCatalog<Id, T, Reference['catalog']>,\n): LocaleDefinition<Id, T> {\n assertValidCatalog(catalog, id);\n assertLocaleParity(_reference.catalog, catalog);\n return { id, catalog };\n}\n\ntype CatalogOf<T> = T extends LocaleDefinition<string, infer CatalogValue> ? CatalogValue : T;\ntype CatalogKeys<T, Prefix extends string = ''> = {\n [Key in keyof T & string]: T[Key] extends Message | PluralMessage\n ? `${Prefix}${Key}`\n : T[Key] extends object\n ? CatalogKeys<T[Key], `${Prefix}${Key}.`>\n : never;\n}[keyof T & string];\nexport type TranslationKey<C> = CatalogKeys<CatalogOf<C>>;\n\ntype NodeAtPath<T, Path extends string> = Path extends `${infer Head}.${infer Tail}`\n ? Head extends keyof T ? NodeAtPath<T[Head], Tail> : never\n : Path extends keyof T ? T[Path] : never;\nexport type TranslationParams<C, Key extends string> = MessageParams<NodeAtPath<CatalogOf<C>, Key>>;\n\nexport type TranslationParamsArgument<Params> = keyof Params extends never\n ? [params?: Params]\n : [params: Params];\n\nexport type CatalogDiagnostic = {\n readonly code: 'MISSING_PLURAL_CATEGORY' | 'INVALID_CATALOG' | 'LOCALE_MISMATCH';\n readonly path: string;\n readonly message: string;\n};\n\nexport class I18nRuntimeError extends Error {\n readonly code: string;\n constructor(code: string, message: string) {\n super(message);\n this.name = 'I18nRuntimeError';\n this.code = code;\n }\n}\n\nexport function validateCatalog(\n catalog: Catalog,\n locale: string,\n options: { readonly strictPlural?: boolean } = {},\n): readonly CatalogDiagnostic[] {\n const diagnostics: CatalogDiagnostic[] = [];\n const visit = (node: unknown, path: string): void => {\n if (isPlural(node)) {\n if (options.strictPlural !== false) {\n for (const category of requiredPluralCategories(locale)) {\n if (!node.branches[category]) diagnostics.push({\n code: 'MISSING_PLURAL_CATEGORY',\n path,\n message: `Locale ${locale} requires plural category ${category}.`,\n });\n }\n }\n for (const [category, branch] of Object.entries(node.branches)) {\n if (branch) visit(branch, `${path}.${category}`);\n }\n return;\n }\n if (isMessage(node)) return;\n if (typeof node !== 'object' || node === null) {\n diagnostics.push({ code: 'INVALID_CATALOG', path, message: 'Catalog nodes must be messages, plurals, or objects.' });\n return;\n }\n for (const [key, child] of Object.entries(node)) visit(child, path ? `${path}.${key}` : key);\n };\n visit(catalog, '');\n return diagnostics;\n}\n\nexport function assertValidCatalog(catalog: Catalog, locale: string): void {\n const diagnostics = validateCatalog(catalog, locale, { strictPlural: true });\n if (diagnostics.length > 0) throw new I18nRuntimeError('INVALID_CATALOG', diagnostics.map((item) => `${item.path}: ${item.message}`).join('\\n'));\n}\n\nexport function validateLocaleParity(reference: Catalog, candidate: Catalog): readonly CatalogDiagnostic[] {\n const diagnostics: CatalogDiagnostic[] = [];\n const compare = (left: unknown, right: unknown, path: string): void => {\n if (isMessage(left) || isMessage(right)) {\n if (!isMessage(left) || !isMessage(right)) {\n diagnostics.push({ code: 'LOCALE_MISMATCH', path, message: 'Locale message shape does not match the reference.' });\n return;\n }\n const leftTokens = left.parts.filter((part): part is I18nToken => typeof part !== 'string').map((part) => `${part.name}:${part.kind}`).sort();\n const rightTokens = right.parts.filter((part): part is I18nToken => typeof part !== 'string').map((part) => `${part.name}:${part.kind}`).sort();\n if (leftTokens.join('|') !== rightTokens.join('|')) diagnostics.push({ code: 'LOCALE_MISMATCH', path, message: 'Locale token set does not match the reference.' });\n return;\n }\n if (isPlural(left) || isPlural(right)) {\n if (!isPlural(left) || !isPlural(right) || left.count.name !== right.count.name || left.count.kind !== right.count.kind) {\n diagnostics.push({ code: 'LOCALE_MISMATCH', path, message: 'Locale plural selector does not match the reference.' });\n return;\n }\n for (const category of Object.keys(left.branches)) {\n const branch = left.branches[category as PluralCategory];\n const candidateBranch = right.branches[category as PluralCategory];\n if (!candidateBranch) diagnostics.push({ code: 'LOCALE_MISMATCH', path: `${path}.${category}`, message: 'Locale is missing a reference plural branch.' });\n else if (branch) compare(branch, candidateBranch, `${path}.${category}`);\n }\n return;\n }\n if (typeof left !== 'object' || left === null || typeof right !== 'object' || right === null) {\n diagnostics.push({ code: 'LOCALE_MISMATCH', path, message: 'Locale node shape does not match the reference.' });\n return;\n }\n const leftKeys = Object.keys(left).sort();\n const rightKeys = Object.keys(right).sort();\n if (leftKeys.join('|') !== rightKeys.join('|')) {\n diagnostics.push({ code: 'LOCALE_MISMATCH', path, message: 'Locale keys do not match the reference.' });\n return;\n }\n for (const key of leftKeys) compare((left as Record<string, unknown>)[key], (right as Record<string, unknown>)[key], path ? `${path}.${key}` : key);\n };\n compare(reference, candidate, '');\n return diagnostics;\n}\n\nexport function assertLocaleParity(reference: Catalog, candidate: Catalog): void {\n const diagnostics = validateLocaleParity(reference, candidate);\n if (diagnostics.length > 0) throw new I18nRuntimeError('LOCALE_MISMATCH', diagnostics.map((item) => `${item.path}: ${item.message}`).join('\\n'));\n}\n\nfunction nodeAt(catalog: Catalog, key: string): Message<unknown> | PluralMessage {\n let node: unknown = catalog;\n for (const part of key.split('.')) node = (node as Record<string, unknown>)[part];\n if (isMessage(node) || isPlural(node)) return node;\n throw new I18nRuntimeError('UNKNOWN_KEY', `Unknown translation key: ${key}`);\n}\n\nfunction renderMessage(message: Message<unknown>, params: Record<string, unknown>, context: FormatterContext): string {\n return message.parts.map((part) => {\n if (typeof part === 'string') return part;\n const value = params[part.name];\n if (value === undefined) throw new I18nRuntimeError('MISSING_PARAM', `Missing parameter ${part.name}.`);\n if (part.validate && !part.validate(value)) throw new I18nRuntimeError('INVALID_PARAM', `Invalid parameter ${part.name}.`);\n return part.format(value, context);\n }).join('');\n}\n\nfunction renderNode(node: Message<unknown> | PluralMessage, params: Record<string, unknown>, context: FormatterContext): string {\n if (isMessage(node)) return renderMessage(node, params, context);\n const count = params[node.count.name];\n if (typeof count !== 'number' || !Number.isFinite(count)) throw new I18nRuntimeError('INVALID_PLURAL_COUNT', `Plural count ${node.count.name} must be a finite number.`);\n const category = new Intl.PluralRules(context.locale).select(count) as PluralCategory;\n const branch = node.branches[category];\n if (!branch) throw new I18nRuntimeError('MISSING_PLURAL_CATEGORY', `Missing plural category ${category} for ${context.locale}.`);\n return renderMessage(branch, params, context);\n}\n\nexport type I18nLoader<Locale extends LocaleDefinition = LocaleDefinition> = {\n readonly load: (id: string) => Promise<Locale>;\n readonly clear: () => void;\n readonly has: (id: string) => boolean;\n};\n\nexport function createI18nLoader<Locale extends LocaleDefinition>(\n load: (id: string) => Promise<Locale>,\n): I18nLoader<Locale> {\n const cache = new Map<string, Promise<Locale>>();\n return {\n load: (id) => {\n const current = cache.get(id);\n if (current) return current;\n const pending = load(id);\n cache.set(id, pending);\n return pending.catch((error: unknown) => {\n cache.delete(id);\n throw error;\n });\n },\n clear: () => cache.clear(),\n has: (id) => cache.has(id),\n };\n}\n\nexport type I18nRuntime<Locales extends readonly LocaleDefinition[]> = {\n readonly locale: () => Locales[number]['id'];\n readonly setLocale: (id: Locales[number]['id']) => void;\n readonly translate: <Key extends TranslationKey<Locales[number]>>(\n key: Key,\n ...params: TranslationParamsArgument<\n TranslationParams<Locales[number], Key & string>\n >\n ) => string;\n readonly t: I18nRuntime<Locales>['translate'];\n readonly bind: (\n dependency: ReactiveTranslationDependency,\n ) => ReactiveTranslator<Locales>;\n readonly loadLocale: (id: Locales[number]['id']) => Promise<void>;\n};\n\nexport type ReactiveTranslationDependency = () => Generator<\n unknown,\n unknown,\n unknown\n>;\n\nexport type ReactiveTranslator<\n Locales extends readonly LocaleDefinition[],\n> = <Key extends TranslationKey<Locales[number]>>(\n key: Key,\n ...params: TranslationParamsArgument<\n TranslationParams<Locales[number], Key & string>\n >\n) => () => Generator<unknown, string, unknown>;\n\nexport function createI18nRuntime<const Locales extends readonly LocaleDefinition[]>(options: {\n readonly locales: Locales;\n readonly defaultLocale?: Locales[number]['id'];\n readonly strict?: boolean;\n readonly timeZone?: string;\n readonly loader?: I18nLoader;\n}): I18nRuntime<Locales> {\n if (options.locales.length === 0) throw new I18nRuntimeError('NO_LOCALES', 'At least one locale is required.');\n const locales = new Map(options.locales.map((locale) => [locale.id, locale]));\n let current = options.defaultLocale ?? options.locales[0].id;\n const loaded = new Map(locales);\n if (options.strict !== false) for (const locale of options.locales) assertValidCatalog(locale.catalog, locale.id);\n if (options.strict !== false) for (const locale of options.locales.slice(1)) assertLocaleParity(options.locales[0].catalog, locale.catalog);\n const loadLocale = async (id: Locales[number]['id']): Promise<void> => {\n if (loaded.has(id)) return;\n if (!options.loader) throw new I18nRuntimeError('LOCALE_NOT_LOADED', `Locale ${id} has not been loaded.`);\n const locale = await options.loader.load(id);\n loaded.set(id, locale);\n };\n const translate = ((key: string, params?: Record<string, unknown>) => {\n const locale = loaded.get(current);\n if (!locale) throw new I18nRuntimeError('LOCALE_NOT_LOADED', `Locale ${current} has not been loaded.`);\n const node = nodeAt(locale.catalog, key);\n return renderNode(node, params ?? {}, { locale: current, timeZone: options.timeZone });\n }) as I18nRuntime<Locales>['translate'];\n return {\n locale: () => current,\n setLocale: (id) => {\n if (!loaded.has(id)) throw new I18nRuntimeError('LOCALE_NOT_LOADED', `Locale ${id} has not been loaded.`);\n current = id;\n },\n translate,\n t: translate,\n bind: (dependency: ReactiveTranslationDependency) =>\n createReactiveTranslator<Locales>({\n runtime: { translate },\n dependency,\n }),\n loadLocale,\n };\n}\n\nexport function createReactiveTranslator<\n const Locales extends readonly LocaleDefinition[],\n>(options: {\n readonly runtime: Pick<I18nRuntime<Locales>, 'translate'>;\n readonly dependency: ReactiveTranslationDependency;\n}): ReactiveTranslator<Locales> {\n return ((key: string, params?: Record<string, unknown>) =>\n function* () {\n yield* options.dependency();\n return options.runtime.translate(key as never, params as never);\n }) as ReactiveTranslator<Locales>;\n}\n\nexport function serializeToken<Name extends string, Value, Kind extends string>(token: I18nToken<Name, Value, Kind>): { readonly token: string; readonly name: string } {\n return { token: token.tokenId, name: token.name };\n}\n\nexport type SerializedCatalog = {\n readonly kind: 'catalog';\n readonly entries: Readonly<Record<string, unknown>>;\n};\n\n/**\n * Produces a JSON-safe delivery representation. Formatters are deliberately\n * represented by stable token ids; the application registers their executable\n * formatters when it renders the catalogue.\n */\nexport function serializeCatalog(catalog: Catalog): SerializedCatalog {\n const serialize = (node: unknown): unknown => {\n if (isMessage(node)) {\n return {\n kind: 'message',\n parts: node.parts.map((part) => typeof part === 'string' ? part : serializeToken(part)),\n };\n }\n if (isPlural(node)) {\n return {\n kind: 'plural',\n count: serializeToken(node.count),\n branches: Object.fromEntries(Object.entries(node.branches).map(([category, branch]) => [category, serialize(branch)])),\n };\n }\n if (typeof node === 'object' && node !== null) {\n return Object.fromEntries(Object.entries(node).map(([key, value]) => [key, serialize(value)]));\n }\n return node;\n };\n return { kind: 'catalog', entries: serialize(catalog) as Readonly<Record<string, unknown>> };\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.types.d.ts","sourceRoot":"","sources":["../../../../../libs/i18n/src/lib/i18n.types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { createI18nRuntime, defineLocale, defineLocaleLike, msg, number, plural, } from './i18n.js';
|
|
2
|
+
const count = number('count');
|
|
3
|
+
const en = defineLocale('en-US', {
|
|
4
|
+
cart: {
|
|
5
|
+
items: plural(count, {
|
|
6
|
+
one: msg `${count} item`,
|
|
7
|
+
other: msg `${count} items`,
|
|
8
|
+
}),
|
|
9
|
+
},
|
|
10
|
+
});
|
|
11
|
+
const fr = defineLocaleLike(en, 'fr-FR', {
|
|
12
|
+
cart: {
|
|
13
|
+
items: plural(count, {
|
|
14
|
+
one: msg `${count} article`,
|
|
15
|
+
other: msg `${count} articles`,
|
|
16
|
+
}),
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
const runtime = createI18nRuntime({ locales: [en, fr] });
|
|
20
|
+
runtime.translate('cart.items', { count: 2 });
|
|
21
|
+
// @ts-expect-error Translation keys are a closed union.
|
|
22
|
+
runtime.translate('cart.unknown', { count: 2 });
|
|
23
|
+
// @ts-expect-error The token parameter is required.
|
|
24
|
+
runtime.translate('cart.items', {});
|
|
25
|
+
// @ts-expect-error Token parameters retain their value type.
|
|
26
|
+
runtime.translate('cart.items', { count: 'two' });
|
|
27
|
+
// @ts-expect-error A French catalogue must preserve the reference key shape.
|
|
28
|
+
defineLocaleLike(en, 'fr-FR', { cart: {} });
|
|
29
|
+
// @ts-expect-error English needs the `one` plural category.
|
|
30
|
+
defineLocale('en-US', { cart: { items: plural(count, { other: msg `${count}` }) } });
|
|
31
|
+
//# sourceMappingURL=i18n.types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.types.js","sourceRoot":"","sources":["../../../../../libs/i18n/src/lib/i18n.types.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,EAChB,GAAG,EACH,MAAM,EACN,MAAM,GACP,MAAM,QAAQ,CAAC;AAEhB,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;AAC9B,MAAM,EAAE,GAAG,YAAY,CAAC,OAAO,EAAE;IAC/B,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE;YACnB,GAAG,EAAE,GAAG,CAAA,GAAG,KAAK,OAAO;YACvB,KAAK,EAAE,GAAG,CAAA,GAAG,KAAK,QAAQ;SAC3B,CAAC;KACH;CACF,CAAC,CAAC;AACH,MAAM,EAAE,GAAG,gBAAgB,CAAC,EAAE,EAAE,OAAO,EAAE;IACvC,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE;YACnB,GAAG,EAAE,GAAG,CAAA,GAAG,KAAK,UAAU;YAC1B,KAAK,EAAE,GAAG,CAAA,GAAG,KAAK,WAAW;SAC9B,CAAC;KACH;CACF,CAAC,CAAC;AACH,MAAM,OAAO,GAAG,iBAAiB,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;AAEzD,OAAO,CAAC,SAAS,CAAC,YAAY,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;AAE9C,wDAAwD;AACxD,OAAO,CAAC,SAAS,CAAC,cAAc,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;AAChD,oDAAoD;AACpD,OAAO,CAAC,SAAS,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;AACpC,6DAA6D;AAC7D,OAAO,CAAC,SAAS,CAAC,YAAY,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;AAElD,6EAA6E;AAC7E,gBAAgB,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;AAE5C,4DAA4D;AAC5D,YAAY,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAG,CAAA,GAAG,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC","sourcesContent":["import {\n createI18nRuntime,\n defineLocale,\n defineLocaleLike,\n msg,\n number,\n plural,\n} from './i18n';\n\nconst count = number('count');\nconst en = defineLocale('en-US', {\n cart: {\n items: plural(count, {\n one: msg`${count} item`,\n other: msg`${count} items`,\n }),\n },\n});\nconst fr = defineLocaleLike(en, 'fr-FR', {\n cart: {\n items: plural(count, {\n one: msg`${count} article`,\n other: msg`${count} articles`,\n }),\n },\n});\nconst runtime = createI18nRuntime({ locales: [en, fr] });\n\nruntime.translate('cart.items', { count: 2 });\n\n// @ts-expect-error Translation keys are a closed union.\nruntime.translate('cart.unknown', { count: 2 });\n// @ts-expect-error The token parameter is required.\nruntime.translate('cart.items', {});\n// @ts-expect-error Token parameters retain their value type.\nruntime.translate('cart.items', { count: 'two' });\n\n// @ts-expect-error A French catalogue must preserve the reference key shape.\ndefineLocaleLike(en, 'fr-FR', { cart: {} });\n\n// @ts-expect-error English needs the `one` plural category.\ndefineLocale('en-US', { cart: { items: plural(count, { other: msg`${count}` }) } });\n"]}
|
package/src/testing.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../../../../libs/i18n/src/testing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
|
package/src/testing.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.js","sourceRoot":"","sources":["../../../../libs/i18n/src/testing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAA0B,MAAM,YAAY,CAAC","sourcesContent":["export { assertValidCatalog, validateCatalog, type CatalogDiagnostic } from './lib/i18n';\n"]}
|