@xndrjs/i18n 0.4.0 → 0.5.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 +156 -29
- package/dist/codegen/index.d.ts +85 -0
- package/dist/codegen/index.js +181 -0
- package/dist/codegen/index.js.map +1 -0
- package/dist/index.d.ts +34 -5
- package/dist/index.js +175 -74
- package/dist/index.js.map +1 -1
- package/dist/validation/index.d.ts +4 -0
- package/dist/validation/index.js.map +1 -1
- package/package.json +6 -1
- package/src/IcuTranslationProviderMulti.test.ts +47 -0
- package/src/IcuTranslationProviderMulti.ts +41 -61
- package/src/IcuTranslationProviderSingle.test.ts +67 -0
- package/src/IcuTranslationProviderSingle.ts +27 -51
- package/src/audit/audit-dictionaries.ts +4 -1
- package/src/audit/run-audit.test.ts +35 -1
- package/src/audit/run-audit.ts +15 -7
- package/src/codegen/codegen-config-schema.ts +68 -1
- package/src/codegen/config.test.ts +174 -39
- package/src/codegen/config.ts +14 -5
- package/src/codegen/constants.ts +8 -0
- package/src/codegen/delivery-artifacts.test.ts +142 -0
- package/src/codegen/delivery-artifacts.ts +124 -0
- package/src/codegen/emit/dictionary-file.test.ts +190 -0
- package/src/codegen/emit/dictionary-file.ts +163 -0
- package/src/codegen/emit/dictionary-schema-file.ts +5 -0
- package/src/codegen/emit/instance-file.ts +114 -28
- package/src/codegen/emit/namespace-loaders-file.test.ts +176 -0
- package/src/codegen/emit/namespace-loaders-file.ts +114 -6
- package/src/codegen/emit/types-file.test.ts +114 -0
- package/src/codegen/emit/types-file.ts +48 -11
- package/src/codegen/generate-i18n-types.test.ts +754 -16
- package/src/codegen/generate-i18n-types.ts +111 -47
- package/src/codegen/icu-analysis.ts +9 -2
- package/src/codegen/locale-fallback.ts +19 -10
- package/src/codegen/locale-policy.ts +4 -0
- package/src/codegen/paths.ts +9 -5
- package/src/codegen/project-locales-set-namespace.test.ts +5 -5
- package/src/codegen/read-dictionary.test.ts +474 -2
- package/src/codegen/read-dictionary.ts +164 -15
- package/src/codegen/write-file-if-changed.test.ts +42 -0
- package/src/codegen/write-file-if-changed.ts +20 -0
- package/src/codegen-config/build-config.ts +34 -0
- package/src/codegen-config/codegen-config.test.ts +32 -0
- package/src/codegen-config/index.ts +21 -0
- package/src/codegen-config/write-config.ts +8 -0
- package/src/deep-freeze.test.ts +13 -0
- package/src/deep-freeze.ts +5 -0
- package/src/format-core.ts +91 -0
- package/src/index.ts +8 -2
- package/src/project-locales.test.ts +129 -10
- package/src/project-locales.ts +90 -3
- package/src/setup/setup-i18n.test.ts +1 -1
- package/src/setup/setup-i18n.ts +6 -30
- package/src/types.ts +19 -4
- package/src/validation/normalize.ts +4 -0
- /package/src/{setup → codegen-config}/type-names.ts +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -10,9 +10,23 @@ type LocaleOfMulti<Schema extends MultiDictionary> = {
|
|
|
10
10
|
}[keyof Schema[NS]];
|
|
11
11
|
}[keyof Schema] & string;
|
|
12
12
|
type LocaleFallbackMap$1 = Record<string, string | null>;
|
|
13
|
-
type
|
|
13
|
+
type MissingTranslationContext = {
|
|
14
|
+
/** Only set by the multi-namespace provider. */
|
|
15
|
+
namespace?: string;
|
|
16
|
+
key: string;
|
|
17
|
+
locale: string;
|
|
18
|
+
fallbackChain: string;
|
|
19
|
+
};
|
|
20
|
+
type OnMissingTranslation = "throw" | "key" | ((context: MissingTranslationContext) => string);
|
|
14
21
|
type IcuTranslationProviderOptions<Fallback extends LocaleFallbackMap$1 | undefined = undefined> = {
|
|
15
22
|
localeFallback?: Fallback;
|
|
23
|
+
/**
|
|
24
|
+
* Strategy when no template resolves for a key/locale (after walking the
|
|
25
|
+
* fallback chain). "throw" (default) raises an error, "key" returns the
|
|
26
|
+
* translation key itself, a function receives the context and returns the
|
|
27
|
+
* string to display. ICU syntax and formatting errors always throw.
|
|
28
|
+
*/
|
|
29
|
+
onMissing?: OnMissingTranslation;
|
|
16
30
|
};
|
|
17
31
|
|
|
18
32
|
interface TranslationProviderSingleForLocale<Schema extends KeyDictionary, Params extends {
|
|
@@ -43,8 +57,10 @@ declare class IcuTranslationProviderSingle<Schema extends KeyDictionary, Params
|
|
|
43
57
|
private dictionary;
|
|
44
58
|
private compiledCache;
|
|
45
59
|
private readonly localeFallback?;
|
|
60
|
+
private readonly onMissing;
|
|
46
61
|
constructor(dictionary: Schema, options?: IcuTranslationProviderOptions<Fallback>);
|
|
47
62
|
get<K extends keyof Schema & string>(key: K, locale: RequestLocales, ...args: Params[K] extends never ? [] : [params: Params[K]]): string;
|
|
63
|
+
getWithLocale(key: string, locale: string, params?: Record<string, unknown>): string;
|
|
48
64
|
forLocale<Locale extends RequestLocales>(locale: Locale): IcuTranslationProviderSingleForLocale<Schema, Params, RequestLocales, Locale, Fallback>;
|
|
49
65
|
getAll(): Schema;
|
|
50
66
|
setAll(values: Schema): void;
|
|
@@ -88,9 +104,11 @@ declare class IcuTranslationProviderMulti<Schema extends MultiDictionary, Params
|
|
|
88
104
|
private dictionary;
|
|
89
105
|
private compiledCache;
|
|
90
106
|
private readonly localeFallback?;
|
|
107
|
+
private readonly onMissing;
|
|
91
108
|
private loadedNamespaces;
|
|
92
109
|
constructor(dictionary: Partial<Schema>, options?: IcuTranslationProviderOptions<Fallback>);
|
|
93
110
|
get<NS extends keyof Schema, K extends keyof Schema[NS] & keyof Params[NS] & string>(namespace: NS, key: K, locale: RequestLocales, ...args: Params[NS][K] extends never ? [] : [params: Params[NS][K]]): string;
|
|
111
|
+
getWithLocale(namespace: string, key: string, locale: string, params?: Record<string, unknown>): string;
|
|
94
112
|
forLocale<Locale extends RequestLocales>(locale: Locale): IcuTranslationProviderMultiForLocale<Schema, Params, RequestLocales, Locale, Fallback>;
|
|
95
113
|
getAll(): Schema;
|
|
96
114
|
hasNamespace<NS extends keyof Schema & string>(namespace: NS): boolean;
|
|
@@ -109,14 +127,25 @@ declare function resolveLocaleTemplate(localeByKey: Record<string, string | unde
|
|
|
109
127
|
declare function formatLocaleFallbackChain(requestedLocale: string, fallbackMap?: LocaleFallbackMap): string;
|
|
110
128
|
|
|
111
129
|
/**
|
|
112
|
-
* Builds a dictionary that contains only the requested locales.
|
|
130
|
+
* Builds a namespace dictionary that contains only the requested locales.
|
|
113
131
|
* For each key and target locale, copies the direct template when present;
|
|
114
132
|
* otherwise resolves through `localeFallback` (same rules as `.get()` at runtime).
|
|
115
133
|
*/
|
|
116
|
-
declare function
|
|
134
|
+
declare function projectNamespaceLocalesCore<T extends KeyDictionary>(dictionary: T, locales: readonly string[], localeFallback?: LocaleFallbackMap$1): T;
|
|
135
|
+
/**
|
|
136
|
+
* Projects a single namespace for a custom delivery area.
|
|
137
|
+
* Full locales resolve through `localeFallback` (e.g. external chains like `it → en-US`);
|
|
138
|
+
* preserve locales copy only their direct canonical entry when present.
|
|
139
|
+
*/
|
|
140
|
+
declare function projectNamespaceForDeliveryAreaCore<T extends KeyDictionary>(dictionary: T, areaLocales: readonly string[], localeFallback?: LocaleFallbackMap$1): T;
|
|
141
|
+
/**
|
|
142
|
+
* Projects a multi-namespace dictionary for a custom delivery area.
|
|
143
|
+
* Each namespace uses the same delivery-area rules as `projectNamespaceForDeliveryAreaCore`.
|
|
144
|
+
*/
|
|
145
|
+
declare function projectDictionaryForDeliveryAreaCore<T extends MultiDictionary>(dictionary: T, areaLocales: readonly string[], localeFallback?: LocaleFallbackMap$1): T;
|
|
117
146
|
/**
|
|
118
147
|
* Projects every namespace in a multi-namespace dictionary.
|
|
119
148
|
*/
|
|
120
|
-
declare function
|
|
149
|
+
declare function projectDictionaryLocalesCore<T extends MultiDictionary>(dictionary: T, locales: readonly string[], localeFallback?: LocaleFallbackMap$1): T;
|
|
121
150
|
|
|
122
|
-
export { IcuTranslationProviderMulti, type IcuTranslationProviderOptions, IcuTranslationProviderSingle, type KeyDictionary, type LocaleDictionary, type LocaleFallbackMap$1 as LocaleFallbackMap, type LocaleOfMulti, type LocaleOfSingle, type MultiDictionary, type
|
|
151
|
+
export { IcuTranslationProviderMulti, type IcuTranslationProviderOptions, IcuTranslationProviderSingle, type KeyDictionary, type LocaleDictionary, type LocaleFallbackMap$1 as LocaleFallbackMap, type LocaleOfMulti, type LocaleOfSingle, type MissingTranslationContext, type MultiDictionary, type OnMissingTranslation, type ResolvedLocaleTemplate, type TranslationProviderMulti, type TranslationProviderMultiForLocale, type TranslationProviderSingle, type TranslationProviderSingleForLocale, formatLocaleFallbackChain, projectDictionaryForDeliveryAreaCore, projectDictionaryLocalesCore, projectNamespaceForDeliveryAreaCore, projectNamespaceLocalesCore, resolveLocaleTemplate, validateLocaleFallback };
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { IntlMessageFormat } from 'intl-messageformat';
|
|
2
2
|
|
|
3
|
-
// src/IcuTranslationProviderSingle.ts
|
|
4
|
-
|
|
5
3
|
// src/deep-freeze.ts
|
|
6
4
|
function deepFreeze(value) {
|
|
7
5
|
if (value === null || typeof value !== "object") {
|
|
8
6
|
return value;
|
|
9
7
|
}
|
|
8
|
+
if (Object.isFrozen(value)) {
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
10
11
|
Object.freeze(value);
|
|
11
12
|
for (const child of Object.values(value)) {
|
|
12
13
|
deepFreeze(child);
|
|
@@ -80,6 +81,68 @@ function formatLocaleFallbackChain(requestedLocale, fallbackMap) {
|
|
|
80
81
|
return chain.join(" \u2192 ");
|
|
81
82
|
}
|
|
82
83
|
|
|
84
|
+
// src/format-core.ts
|
|
85
|
+
function formatErrorLabel(context) {
|
|
86
|
+
if (context.namespace !== void 0) {
|
|
87
|
+
return `namespace "${context.namespace}", key "${context.key}"`;
|
|
88
|
+
}
|
|
89
|
+
return `key "${context.key}"`;
|
|
90
|
+
}
|
|
91
|
+
function formatMissingError(context) {
|
|
92
|
+
const chain = formatLocaleFallbackChain(context.locale, context.localeFallback);
|
|
93
|
+
if (context.namespace !== void 0) {
|
|
94
|
+
return `[i18n] Missing key or locale: namespace "${context.namespace}", key "${context.key}" [${context.locale}] (fallback chain: ${chain})`;
|
|
95
|
+
}
|
|
96
|
+
return `[i18n] Missing key or locale: "${context.key}" [${context.locale}] (fallback chain: ${chain})`;
|
|
97
|
+
}
|
|
98
|
+
function resolveMissing(context) {
|
|
99
|
+
const chain = formatLocaleFallbackChain(context.locale, context.localeFallback);
|
|
100
|
+
if (context.onMissing === "key") {
|
|
101
|
+
if (context.namespace !== void 0) {
|
|
102
|
+
return `${context.namespace}.${context.key}`;
|
|
103
|
+
}
|
|
104
|
+
return context.key;
|
|
105
|
+
}
|
|
106
|
+
if (typeof context.onMissing === "function") {
|
|
107
|
+
return context.onMissing({
|
|
108
|
+
...context.namespace !== void 0 ? { namespace: context.namespace } : {},
|
|
109
|
+
key: context.key,
|
|
110
|
+
locale: context.locale,
|
|
111
|
+
fallbackChain: chain
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
throw new Error(formatMissingError(context));
|
|
115
|
+
}
|
|
116
|
+
function resolveAndFormat(options) {
|
|
117
|
+
const { localeByKey, locale, params, getCache, context } = options;
|
|
118
|
+
const resolved = resolveLocaleTemplate(localeByKey, locale, context.localeFallback);
|
|
119
|
+
if (!resolved) {
|
|
120
|
+
return resolveMissing(context);
|
|
121
|
+
}
|
|
122
|
+
const { template, resolvedLocale } = resolved;
|
|
123
|
+
const cache = getCache(resolvedLocale);
|
|
124
|
+
const cacheKey = context.key;
|
|
125
|
+
const label = formatErrorLabel(context);
|
|
126
|
+
if (!cache[cacheKey]) {
|
|
127
|
+
try {
|
|
128
|
+
cache[cacheKey] = new IntlMessageFormat(template, resolvedLocale);
|
|
129
|
+
} catch (err) {
|
|
130
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
131
|
+
throw new Error(
|
|
132
|
+
`[i18n ICU Syntax Error] Dictionary error for ${label} [${resolvedLocale}]: ${message}`
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
try {
|
|
137
|
+
return cache[cacheKey].format(params);
|
|
138
|
+
} catch (err) {
|
|
139
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
140
|
+
throw new Error(
|
|
141
|
+
`[i18n Formatting Error] Invalid or missing parameters for ${label} [${resolvedLocale}]: ${message}`
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
83
146
|
// src/IcuTranslationProviderSingle.ts
|
|
84
147
|
var IcuTranslationProviderSingleForLocale = class {
|
|
85
148
|
constructor(provider, locale) {
|
|
@@ -89,55 +152,45 @@ var IcuTranslationProviderSingleForLocale = class {
|
|
|
89
152
|
provider;
|
|
90
153
|
locale;
|
|
91
154
|
get(key, ...args) {
|
|
92
|
-
|
|
155
|
+
const params = args[0];
|
|
156
|
+
return this.provider.getWithLocale(String(key), this.locale, params);
|
|
93
157
|
}
|
|
94
158
|
};
|
|
95
159
|
var IcuTranslationProviderSingle = class {
|
|
96
160
|
dictionary;
|
|
97
161
|
compiledCache = {};
|
|
98
162
|
localeFallback;
|
|
163
|
+
onMissing;
|
|
99
164
|
constructor(dictionary, options) {
|
|
100
165
|
this.dictionary = structuredClone(dictionary);
|
|
101
166
|
if (options?.localeFallback) {
|
|
102
167
|
validateLocaleFallback(options.localeFallback);
|
|
103
168
|
this.localeFallback = options.localeFallback;
|
|
104
169
|
}
|
|
170
|
+
this.onMissing = options?.onMissing ?? "throw";
|
|
105
171
|
}
|
|
106
172
|
get(key, locale, ...args) {
|
|
107
173
|
const params = args[0];
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
} catch (err) {
|
|
127
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
128
|
-
throw new Error(
|
|
129
|
-
`[i18n ICU Syntax Error] Dictionary error for key "${String(key)}" [${resolvedLocale}]: ${message}`
|
|
130
|
-
);
|
|
174
|
+
return this.getWithLocale(String(key), locale, params);
|
|
175
|
+
}
|
|
176
|
+
getWithLocale(key, locale, params) {
|
|
177
|
+
return resolveAndFormat({
|
|
178
|
+
localeByKey: this.dictionary[key],
|
|
179
|
+
locale,
|
|
180
|
+
params,
|
|
181
|
+
getCache: (resolvedLocale) => {
|
|
182
|
+
if (!this.compiledCache[resolvedLocale]) {
|
|
183
|
+
this.compiledCache[resolvedLocale] = {};
|
|
184
|
+
}
|
|
185
|
+
return this.compiledCache[resolvedLocale];
|
|
186
|
+
},
|
|
187
|
+
context: {
|
|
188
|
+
key,
|
|
189
|
+
locale,
|
|
190
|
+
localeFallback: this.localeFallback,
|
|
191
|
+
onMissing: this.onMissing
|
|
131
192
|
}
|
|
132
|
-
}
|
|
133
|
-
try {
|
|
134
|
-
return this.compiledCache[resolvedLocale][cacheKey].format(params);
|
|
135
|
-
} catch (err) {
|
|
136
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
137
|
-
throw new Error(
|
|
138
|
-
`[i18n Formatting Error] Invalid or missing parameters for key "${String(key)}" [${resolvedLocale}]: ${message}`
|
|
139
|
-
);
|
|
140
|
-
}
|
|
193
|
+
});
|
|
141
194
|
}
|
|
142
195
|
forLocale(locale) {
|
|
143
196
|
return new IcuTranslationProviderSingleForLocale(this, locale);
|
|
@@ -150,6 +203,8 @@ var IcuTranslationProviderSingle = class {
|
|
|
150
203
|
this.compiledCache = {};
|
|
151
204
|
}
|
|
152
205
|
};
|
|
206
|
+
|
|
207
|
+
// src/IcuTranslationProviderMulti.ts
|
|
153
208
|
var IcuTranslationProviderMultiForLocale = class {
|
|
154
209
|
constructor(provider, locale) {
|
|
155
210
|
this.provider = provider;
|
|
@@ -158,13 +213,15 @@ var IcuTranslationProviderMultiForLocale = class {
|
|
|
158
213
|
provider;
|
|
159
214
|
locale;
|
|
160
215
|
get(namespace, key, ...args) {
|
|
161
|
-
|
|
216
|
+
const params = args[0];
|
|
217
|
+
return this.provider.getWithLocale(String(namespace), String(key), this.locale, params);
|
|
162
218
|
}
|
|
163
219
|
};
|
|
164
220
|
var IcuTranslationProviderMulti = class {
|
|
165
221
|
dictionary;
|
|
166
222
|
compiledCache = {};
|
|
167
223
|
localeFallback;
|
|
224
|
+
onMissing;
|
|
168
225
|
loadedNamespaces;
|
|
169
226
|
constructor(dictionary, options) {
|
|
170
227
|
this.dictionary = structuredClone(dictionary);
|
|
@@ -173,49 +230,40 @@ var IcuTranslationProviderMulti = class {
|
|
|
173
230
|
validateLocaleFallback(options.localeFallback);
|
|
174
231
|
this.localeFallback = options.localeFallback;
|
|
175
232
|
}
|
|
233
|
+
this.onMissing = options?.onMissing ?? "throw";
|
|
176
234
|
}
|
|
177
235
|
get(namespace, key, locale, ...args) {
|
|
236
|
+
const params = args[0];
|
|
237
|
+
return this.getWithLocale(String(namespace), String(key), locale, params);
|
|
238
|
+
}
|
|
239
|
+
getWithLocale(namespace, key, locale, params) {
|
|
178
240
|
if (!this.loadedNamespaces.has(namespace)) {
|
|
179
241
|
throw new Error(
|
|
180
|
-
`[i18n] Namespace not loaded: "${
|
|
242
|
+
`[i18n] Namespace not loaded: "${namespace}". Register it with setNamespace() before calling .get().`
|
|
181
243
|
);
|
|
182
244
|
}
|
|
183
|
-
const params = args[0];
|
|
184
245
|
const localeByKey = this.dictionary[namespace]?.[key];
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
} catch (err) {
|
|
205
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
206
|
-
throw new Error(
|
|
207
|
-
`[i18n ICU Syntax Error] namespace "${String(namespace)}", key "${String(key)}" [${resolvedLocale}]: ${message}`
|
|
208
|
-
);
|
|
246
|
+
return resolveAndFormat({
|
|
247
|
+
localeByKey,
|
|
248
|
+
locale,
|
|
249
|
+
params,
|
|
250
|
+
getCache: (resolvedLocale) => {
|
|
251
|
+
if (!this.compiledCache[resolvedLocale]) {
|
|
252
|
+
this.compiledCache[resolvedLocale] = {};
|
|
253
|
+
}
|
|
254
|
+
if (!this.compiledCache[resolvedLocale][namespace]) {
|
|
255
|
+
this.compiledCache[resolvedLocale][namespace] = {};
|
|
256
|
+
}
|
|
257
|
+
return this.compiledCache[resolvedLocale][namespace];
|
|
258
|
+
},
|
|
259
|
+
context: {
|
|
260
|
+
namespace,
|
|
261
|
+
key,
|
|
262
|
+
locale,
|
|
263
|
+
localeFallback: this.localeFallback,
|
|
264
|
+
onMissing: this.onMissing
|
|
209
265
|
}
|
|
210
|
-
}
|
|
211
|
-
try {
|
|
212
|
-
return namespaceCache[cacheKey].format(params);
|
|
213
|
-
} catch (err) {
|
|
214
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
215
|
-
throw new Error(
|
|
216
|
-
`[i18n Formatting Error] namespace "${String(namespace)}", key "${String(key)}" [${resolvedLocale}]: ${message}`
|
|
217
|
-
);
|
|
218
|
-
}
|
|
266
|
+
});
|
|
219
267
|
}
|
|
220
268
|
forLocale(locale) {
|
|
221
269
|
return new IcuTranslationProviderMultiForLocale(this, locale);
|
|
@@ -244,6 +292,20 @@ var IcuTranslationProviderMulti = class {
|
|
|
244
292
|
};
|
|
245
293
|
|
|
246
294
|
// src/project-locales.ts
|
|
295
|
+
function classifyAreaLocales(areaLocales, localeFallback) {
|
|
296
|
+
const areaSet = new Set(areaLocales);
|
|
297
|
+
const full = [];
|
|
298
|
+
const preserve = [];
|
|
299
|
+
for (const locale of areaLocales) {
|
|
300
|
+
const fallback = localeFallback?.[locale];
|
|
301
|
+
if (fallback !== null && fallback !== void 0 && areaSet.has(fallback)) {
|
|
302
|
+
preserve.push(locale);
|
|
303
|
+
} else {
|
|
304
|
+
full.push(locale);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return { full, preserve };
|
|
308
|
+
}
|
|
247
309
|
function projectKeyDictionary(dictionary, locales, localeFallback) {
|
|
248
310
|
const targetLocales = [...new Set(locales)];
|
|
249
311
|
const result = {};
|
|
@@ -261,10 +323,49 @@ function projectKeyDictionary(dictionary, locales, localeFallback) {
|
|
|
261
323
|
}
|
|
262
324
|
return result;
|
|
263
325
|
}
|
|
264
|
-
function
|
|
326
|
+
function projectNamespaceLocalesCore(dictionary, locales, localeFallback) {
|
|
265
327
|
return projectKeyDictionary(dictionary, locales, localeFallback);
|
|
266
328
|
}
|
|
267
|
-
function
|
|
329
|
+
function projectNamespaceForDeliveryAreaCore(dictionary, areaLocales, localeFallback) {
|
|
330
|
+
const { full, preserve } = classifyAreaLocales(areaLocales, localeFallback);
|
|
331
|
+
const fullProjection = full.length > 0 ? projectKeyDictionary(dictionary, full, localeFallback) : void 0;
|
|
332
|
+
const result = {};
|
|
333
|
+
for (const [key, localesByKey] of Object.entries(dictionary)) {
|
|
334
|
+
const projected = {};
|
|
335
|
+
if (fullProjection !== void 0) {
|
|
336
|
+
const fullEntry = fullProjection[key];
|
|
337
|
+
if (fullEntry !== void 0) {
|
|
338
|
+
Object.assign(projected, fullEntry);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
for (const locale of preserve) {
|
|
342
|
+
const template = localesByKey[locale];
|
|
343
|
+
if (template !== void 0) {
|
|
344
|
+
projected[locale] = template;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
if (Object.keys(projected).length > 0) {
|
|
348
|
+
result[key] = projected;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return result;
|
|
352
|
+
}
|
|
353
|
+
function projectDictionaryForDeliveryAreaCore(dictionary, areaLocales, localeFallback) {
|
|
354
|
+
const result = {};
|
|
355
|
+
for (const namespace of Object.keys(dictionary)) {
|
|
356
|
+
const namespaceDictionary = dictionary[namespace];
|
|
357
|
+
if (namespaceDictionary === void 0) {
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
result[namespace] = projectNamespaceForDeliveryAreaCore(
|
|
361
|
+
namespaceDictionary,
|
|
362
|
+
areaLocales,
|
|
363
|
+
localeFallback
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
return result;
|
|
367
|
+
}
|
|
368
|
+
function projectDictionaryLocalesCore(dictionary, locales, localeFallback) {
|
|
268
369
|
const result = {};
|
|
269
370
|
for (const namespace of Object.keys(dictionary)) {
|
|
270
371
|
const namespaceDictionary = dictionary[namespace];
|
|
@@ -280,6 +381,6 @@ function projectNamespacesLocales(dictionary, locales, localeFallback) {
|
|
|
280
381
|
return result;
|
|
281
382
|
}
|
|
282
383
|
|
|
283
|
-
export { IcuTranslationProviderMulti, IcuTranslationProviderSingle, formatLocaleFallbackChain,
|
|
384
|
+
export { IcuTranslationProviderMulti, IcuTranslationProviderSingle, formatLocaleFallbackChain, projectDictionaryForDeliveryAreaCore, projectDictionaryLocalesCore, projectNamespaceForDeliveryAreaCore, projectNamespaceLocalesCore, resolveLocaleTemplate, validateLocaleFallback };
|
|
284
385
|
//# sourceMappingURL=index.js.map
|
|
285
386
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/deep-freeze.ts","../src/resolve-locale.ts","../src/IcuTranslationProviderSingle.ts","../src/IcuTranslationProviderMulti.ts","../src/project-locales.ts"],"names":["IntlMessageFormat"],"mappings":"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","file":"index.js","sourcesContent":["export function deepFreeze<T>(value: T): T {\n if (value === null || typeof value !== \"object\") {\n return value;\n }\n\n Object.freeze(value);\n\n for (const child of Object.values(value)) {\n deepFreeze(child);\n }\n\n return value;\n}\n\nexport function cloneAndFreeze<T>(value: T): T {\n return deepFreeze(structuredClone(value));\n}\n","export type LocaleFallbackMap = Record<string, string | null>;\n\nexport interface ResolvedLocaleTemplate {\n template: string;\n resolvedLocale: string;\n fallbackChain: readonly string[];\n}\n\nexport function validateLocaleFallback(map: LocaleFallbackMap): void {\n for (const startLocale of Object.keys(map)) {\n const visited = new Set<string>();\n let current: string | undefined = startLocale;\n\n while (current !== undefined) {\n if (visited.has(current)) {\n throw new Error(`[i18n] Circular locale fallback detected involving \"${current}\"`);\n }\n visited.add(current);\n\n const next: string | null | undefined = map[current];\n if (next === undefined || next === null) {\n break;\n }\n current = next;\n }\n }\n}\n\nexport function resolveLocaleTemplate(\n localeByKey: Record<string, string | undefined> | undefined,\n requestedLocale: string,\n fallbackMap?: LocaleFallbackMap\n): ResolvedLocaleTemplate | undefined {\n const chain: string[] = [requestedLocale];\n let currentLocale = requestedLocale;\n\n while (true) {\n const template = localeByKey?.[currentLocale];\n if (template !== undefined) {\n return { template, resolvedLocale: currentLocale, fallbackChain: chain };\n }\n\n if (!fallbackMap) {\n return undefined;\n }\n\n const fallback = fallbackMap[currentLocale];\n if (fallback === undefined || fallback === null) {\n return undefined;\n }\n\n if (chain.includes(fallback)) {\n throw new Error(\n `[i18n] Circular locale fallback detected: ${[...chain, fallback].join(\" → \")}`\n );\n }\n\n chain.push(fallback);\n currentLocale = fallback;\n }\n}\n\nexport function formatLocaleFallbackChain(\n requestedLocale: string,\n fallbackMap?: LocaleFallbackMap\n): string {\n if (!fallbackMap) {\n return requestedLocale;\n }\n\n const chain: string[] = [requestedLocale];\n let current = requestedLocale;\n\n while (true) {\n const fallback = fallbackMap[current];\n if (fallback === undefined || fallback === null) {\n break;\n }\n if (chain.includes(fallback)) {\n chain.push(fallback);\n break;\n }\n chain.push(fallback);\n current = fallback;\n }\n\n return chain.join(\" → \");\n}\n","import { IntlMessageFormat } from \"intl-messageformat\";\nimport { cloneAndFreeze } from \"./deep-freeze.js\";\nimport {\n formatLocaleFallbackChain,\n resolveLocaleTemplate,\n validateLocaleFallback,\n} from \"./resolve-locale.js\";\nimport type {\n IcuTranslationProviderOptions,\n KeyDictionary,\n LocaleFallbackMap,\n LocaleOfSingle,\n SingleCompiledCache,\n} from \"./types.js\";\n\nexport interface TranslationProviderSingleForLocale<\n Schema extends KeyDictionary,\n Params extends { [K in keyof Schema]: unknown },\n Locale extends string,\n> {\n readonly locale: Locale;\n get<K extends keyof Schema & string>(\n key: K,\n ...params: Params[K] extends never ? [] : [params: Params[K]]\n ): string;\n}\n\nexport interface TranslationProviderSingle<\n Schema extends KeyDictionary,\n Params extends { [K in keyof Schema]: unknown },\n RequestLocales extends string = LocaleOfSingle<Schema>,\n> {\n get<K extends keyof Schema & string>(\n key: K,\n locale: RequestLocales,\n ...params: Params[K] extends never ? [] : [params: Params[K]]\n ): string;\n forLocale<Locale extends RequestLocales>(\n locale: Locale\n ): TranslationProviderSingleForLocale<Schema, Params, Locale>;\n getAll(): Schema;\n setAll(values: Schema): void;\n}\n\nexport class IcuTranslationProviderSingleForLocale<\n Schema extends KeyDictionary,\n Params extends { [K in keyof Schema]: unknown },\n RequestLocales extends string,\n Locale extends RequestLocales,\n Fallback extends LocaleFallbackMap | undefined,\n> implements TranslationProviderSingleForLocale<Schema, Params, Locale> {\n constructor(\n private readonly provider: IcuTranslationProviderSingle<\n Schema,\n Params,\n RequestLocales,\n Fallback\n >,\n readonly locale: Locale\n ) {}\n\n get<K extends keyof Schema & string>(\n key: K,\n ...args: Params[K] extends never ? [] : [params: Params[K]]\n ): string {\n return (\n this.provider.get as (\n key: K,\n locale: Locale,\n ...params: Params[K] extends never ? [] : [params: Params[K]]\n ) => string\n )(key, this.locale, ...args);\n }\n}\n\nexport class IcuTranslationProviderSingle<\n Schema extends KeyDictionary,\n Params extends { [K in keyof Schema]: unknown },\n RequestLocales extends string = LocaleOfSingle<Schema>,\n Fallback extends LocaleFallbackMap | undefined = undefined,\n> implements TranslationProviderSingle<Schema, Params, RequestLocales> {\n private dictionary: Schema;\n private compiledCache: SingleCompiledCache = {};\n private readonly localeFallback?: Fallback;\n\n constructor(dictionary: Schema, options?: IcuTranslationProviderOptions<Fallback>) {\n this.dictionary = structuredClone(dictionary);\n if (options?.localeFallback) {\n validateLocaleFallback(options.localeFallback);\n this.localeFallback = options.localeFallback;\n }\n }\n\n get<K extends keyof Schema & string>(\n key: K,\n locale: RequestLocales,\n ...args: Params[K] extends never ? [] : [params: Params[K]]\n ): string {\n const params = args[0] as Record<string, unknown> | undefined;\n const resolved = resolveLocaleTemplate(this.dictionary[key], locale, this.localeFallback);\n\n if (!resolved) {\n const chain = formatLocaleFallbackChain(locale, this.localeFallback);\n throw new Error(\n `[i18n] Missing key or locale: \"${String(key)}\" [${locale}] (fallback chain: ${chain})`\n );\n }\n\n const { template, resolvedLocale } = resolved;\n\n if (!this.compiledCache[resolvedLocale]) {\n this.compiledCache[resolvedLocale] = {};\n }\n\n const cacheKey = String(key);\n\n if (!this.compiledCache[resolvedLocale][cacheKey]) {\n try {\n this.compiledCache[resolvedLocale][cacheKey] = new IntlMessageFormat(\n template,\n resolvedLocale\n );\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(\n `[i18n ICU Syntax Error] Dictionary error for key \"${String(key)}\" [${resolvedLocale}]: ${message}`\n );\n }\n }\n\n try {\n return this.compiledCache[resolvedLocale][cacheKey].format(params) as string;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(\n `[i18n Formatting Error] Invalid or missing parameters for key \"${String(key)}\" [${resolvedLocale}]: ${message}`\n );\n }\n }\n\n forLocale<Locale extends RequestLocales>(\n locale: Locale\n ): IcuTranslationProviderSingleForLocale<Schema, Params, RequestLocales, Locale, Fallback> {\n return new IcuTranslationProviderSingleForLocale(this, locale);\n }\n\n getAll(): Schema {\n return cloneAndFreeze(this.dictionary);\n }\n\n setAll(values: Schema): void {\n this.dictionary = structuredClone(values);\n this.compiledCache = {};\n }\n}\n","import { IntlMessageFormat } from \"intl-messageformat\";\nimport { cloneAndFreeze } from \"./deep-freeze.js\";\nimport {\n formatLocaleFallbackChain,\n resolveLocaleTemplate,\n validateLocaleFallback,\n} from \"./resolve-locale.js\";\nimport type {\n IcuTranslationProviderOptions,\n LocaleFallbackMap,\n LocaleOfMulti,\n MultiCompiledCache,\n MultiDictionary,\n} from \"./types.js\";\n\nexport interface TranslationProviderMultiForLocale<\n Schema extends MultiDictionary,\n Params extends { [NS in keyof Schema]: { [K in keyof Schema[NS]]: unknown } },\n Locale extends string,\n> {\n readonly locale: Locale;\n get<NS extends keyof Schema, K extends keyof Schema[NS] & keyof Params[NS] & string>(\n namespace: NS,\n key: K,\n ...params: Params[NS][K] extends never ? [] : [params: Params[NS][K]]\n ): string;\n}\n\nexport interface TranslationProviderMulti<\n Schema extends MultiDictionary,\n Params extends { [NS in keyof Schema]: { [K in keyof Schema[NS]]: unknown } },\n RequestLocales extends string = LocaleOfMulti<Schema>,\n> {\n get<NS extends keyof Schema, K extends keyof Schema[NS] & keyof Params[NS] & string>(\n namespace: NS,\n key: K,\n locale: RequestLocales,\n ...params: Params[NS][K] extends never ? [] : [params: Params[NS][K]]\n ): string;\n forLocale<Locale extends RequestLocales>(\n locale: Locale\n ): TranslationProviderMultiForLocale<Schema, Params, Locale>;\n getAll(): Schema;\n hasNamespace<NS extends keyof Schema & string>(namespace: NS): boolean;\n setAll(values: Schema): void;\n setNamespace<NS extends keyof Schema>(namespace: NS, values: Schema[NS]): void;\n}\n\nexport class IcuTranslationProviderMultiForLocale<\n Schema extends MultiDictionary,\n Params extends { [NS in keyof Schema]: { [K in keyof Schema[NS]]: unknown } },\n RequestLocales extends string,\n Locale extends RequestLocales,\n Fallback extends LocaleFallbackMap | undefined,\n> implements TranslationProviderMultiForLocale<Schema, Params, Locale> {\n constructor(\n private readonly provider: IcuTranslationProviderMulti<\n Schema,\n Params,\n RequestLocales,\n Fallback\n >,\n readonly locale: Locale\n ) {}\n\n get<NS extends keyof Schema, K extends keyof Schema[NS] & keyof Params[NS] & string>(\n namespace: NS,\n key: K,\n ...args: Params[NS][K] extends never ? [] : [params: Params[NS][K]]\n ): string {\n return (\n this.provider.get as <\n NS extends keyof Schema,\n K extends keyof Schema[NS] & keyof Params[NS] & string,\n >(\n namespace: NS,\n key: K,\n locale: Locale,\n ...params: Params[NS][K] extends never ? [] : [params: Params[NS][K]]\n ) => string\n )(namespace, key, this.locale, ...args);\n }\n}\n\nexport class IcuTranslationProviderMulti<\n Schema extends MultiDictionary,\n Params extends { [NS in keyof Schema]: { [K in keyof Schema[NS]]: unknown } },\n RequestLocales extends string = LocaleOfMulti<Schema>,\n Fallback extends LocaleFallbackMap | undefined = undefined,\n> implements TranslationProviderMulti<Schema, Params, RequestLocales> {\n private dictionary: Schema;\n private compiledCache: MultiCompiledCache = {};\n private readonly localeFallback?: Fallback;\n private loadedNamespaces: Set<string>;\n\n constructor(dictionary: Partial<Schema>, options?: IcuTranslationProviderOptions<Fallback>) {\n this.dictionary = structuredClone(dictionary) as Schema;\n this.loadedNamespaces = new Set(Object.keys(dictionary));\n if (options?.localeFallback) {\n validateLocaleFallback(options.localeFallback);\n this.localeFallback = options.localeFallback;\n }\n }\n\n get<NS extends keyof Schema, K extends keyof Schema[NS] & keyof Params[NS] & string>(\n namespace: NS,\n key: K,\n locale: RequestLocales,\n ...args: Params[NS][K] extends never ? [] : [params: Params[NS][K]]\n ): string {\n if (!this.loadedNamespaces.has(namespace as string)) {\n throw new Error(\n `[i18n] Namespace not loaded: \"${String(namespace)}\". Register it with setNamespace() before calling .get().`\n );\n }\n\n const params = args[0] as Record<string, unknown> | undefined;\n const localeByKey = (\n this.dictionary[namespace as string] as Record<string, Record<string, string>>\n )?.[key];\n const resolved = resolveLocaleTemplate(localeByKey, locale, this.localeFallback);\n\n if (!resolved) {\n const chain = formatLocaleFallbackChain(locale, this.localeFallback);\n throw new Error(\n `[i18n] Missing key or locale: namespace \"${String(namespace)}\", key \"${String(key)}\" [${locale}] (fallback chain: ${chain})`\n );\n }\n\n const { template, resolvedLocale } = resolved;\n\n if (!this.compiledCache[resolvedLocale]) {\n this.compiledCache[resolvedLocale] = {};\n }\n\n if (!this.compiledCache[resolvedLocale][namespace as string]) {\n this.compiledCache[resolvedLocale][namespace as string] = {};\n }\n\n const namespaceCache = this.compiledCache[resolvedLocale][namespace as string]!;\n const cacheKey = String(key);\n\n if (!namespaceCache[cacheKey]) {\n try {\n namespaceCache[cacheKey] = new IntlMessageFormat(template, resolvedLocale);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(\n `[i18n ICU Syntax Error] namespace \"${String(namespace)}\", key \"${String(key)}\" [${resolvedLocale}]: ${message}`\n );\n }\n }\n\n try {\n return namespaceCache[cacheKey].format(params) as string;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(\n `[i18n Formatting Error] namespace \"${String(namespace)}\", key \"${String(key)}\" [${resolvedLocale}]: ${message}`\n );\n }\n }\n\n forLocale<Locale extends RequestLocales>(\n locale: Locale\n ): IcuTranslationProviderMultiForLocale<Schema, Params, RequestLocales, Locale, Fallback> {\n return new IcuTranslationProviderMultiForLocale(this, locale);\n }\n\n getAll(): Schema {\n return cloneAndFreeze(this.dictionary);\n }\n\n hasNamespace<NS extends keyof Schema & string>(namespace: NS): boolean {\n return this.loadedNamespaces.has(namespace);\n }\n\n setAll(values: Schema): void {\n this.dictionary = structuredClone(values);\n this.compiledCache = {};\n this.loadedNamespaces = new Set(Object.keys(values));\n }\n\n setNamespace<NS extends keyof Schema>(namespace: NS, values: Schema[NS]): void {\n this.dictionary = {\n ...this.dictionary,\n [namespace]: structuredClone(values),\n };\n this.loadedNamespaces.add(namespace as string);\n\n for (const locale of Object.keys(this.compiledCache)) {\n delete this.compiledCache[locale]?.[namespace as string];\n }\n }\n}\n","import { resolveLocaleTemplate } from \"./resolve-locale.js\";\nimport type { KeyDictionary, LocaleFallbackMap, MultiDictionary } from \"./types.js\";\n\nfunction projectKeyDictionary<T extends KeyDictionary>(\n dictionary: T,\n locales: readonly string[],\n localeFallback?: LocaleFallbackMap\n): T {\n const targetLocales = [...new Set(locales)];\n const result = {} as T;\n\n for (const [key, localesByKey] of Object.entries(dictionary)) {\n const projected: Record<string, string> = {};\n\n for (const locale of targetLocales) {\n const resolved = resolveLocaleTemplate(localesByKey, locale, localeFallback);\n if (resolved !== undefined) {\n projected[locale] = resolved.template;\n }\n }\n\n if (Object.keys(projected).length > 0) {\n result[key as keyof T] = projected as T[keyof T];\n }\n }\n\n return result;\n}\n\n/**\n * Builds a dictionary that contains only the requested locales.\n * For each key and target locale, copies the direct template when present;\n * otherwise resolves through `localeFallback` (same rules as `.get()` at runtime).\n */\nexport function projectLocales<T extends KeyDictionary>(\n dictionary: T,\n locales: readonly string[],\n localeFallback?: LocaleFallbackMap\n): T {\n return projectKeyDictionary(dictionary, locales, localeFallback);\n}\n\n/**\n * Projects every namespace in a multi-namespace dictionary.\n */\nexport function projectNamespacesLocales<T extends MultiDictionary>(\n dictionary: T,\n locales: readonly string[],\n localeFallback?: LocaleFallbackMap\n): T {\n const result = {} as T;\n\n for (const namespace of Object.keys(dictionary) as (keyof T & string)[]) {\n const namespaceDictionary = dictionary[namespace];\n if (namespaceDictionary === undefined) {\n continue;\n }\n\n result[namespace] = projectKeyDictionary(\n namespaceDictionary,\n locales,\n localeFallback\n ) as T[typeof namespace];\n }\n\n return result;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/deep-freeze.ts","../src/resolve-locale.ts","../src/format-core.ts","../src/IcuTranslationProviderSingle.ts","../src/IcuTranslationProviderMulti.ts","../src/project-locales.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export function deepFreeze<T>(value: T): T {\n if (value === null || typeof value !== \"object\") {\n return value;\n }\n\n // Guards against infinite recursion on cyclic structures.\n if (Object.isFrozen(value)) {\n return value;\n }\n\n Object.freeze(value);\n\n for (const child of Object.values(value)) {\n deepFreeze(child);\n }\n\n return value;\n}\n\nexport function cloneAndFreeze<T>(value: T): T {\n return deepFreeze(structuredClone(value));\n}\n","export type LocaleFallbackMap = Record<string, string | null>;\n\nexport interface ResolvedLocaleTemplate {\n template: string;\n resolvedLocale: string;\n fallbackChain: readonly string[];\n}\n\nexport function validateLocaleFallback(map: LocaleFallbackMap): void {\n for (const startLocale of Object.keys(map)) {\n const visited = new Set<string>();\n let current: string | undefined = startLocale;\n\n while (current !== undefined) {\n if (visited.has(current)) {\n throw new Error(`[i18n] Circular locale fallback detected involving \"${current}\"`);\n }\n visited.add(current);\n\n const next: string | null | undefined = map[current];\n if (next === undefined || next === null) {\n break;\n }\n current = next;\n }\n }\n}\n\nexport function resolveLocaleTemplate(\n localeByKey: Record<string, string | undefined> | undefined,\n requestedLocale: string,\n fallbackMap?: LocaleFallbackMap\n): ResolvedLocaleTemplate | undefined {\n const chain: string[] = [requestedLocale];\n let currentLocale = requestedLocale;\n\n while (true) {\n const template = localeByKey?.[currentLocale];\n if (template !== undefined) {\n return { template, resolvedLocale: currentLocale, fallbackChain: chain };\n }\n\n if (!fallbackMap) {\n return undefined;\n }\n\n const fallback = fallbackMap[currentLocale];\n if (fallback === undefined || fallback === null) {\n return undefined;\n }\n\n if (chain.includes(fallback)) {\n throw new Error(\n `[i18n] Circular locale fallback detected: ${[...chain, fallback].join(\" → \")}`\n );\n }\n\n chain.push(fallback);\n currentLocale = fallback;\n }\n}\n\nexport function formatLocaleFallbackChain(\n requestedLocale: string,\n fallbackMap?: LocaleFallbackMap\n): string {\n if (!fallbackMap) {\n return requestedLocale;\n }\n\n const chain: string[] = [requestedLocale];\n let current = requestedLocale;\n\n while (true) {\n const fallback = fallbackMap[current];\n if (fallback === undefined || fallback === null) {\n break;\n }\n if (chain.includes(fallback)) {\n chain.push(fallback);\n break;\n }\n chain.push(fallback);\n current = fallback;\n }\n\n return chain.join(\" → \");\n}\n","import { IntlMessageFormat } from \"intl-messageformat\";\nimport { formatLocaleFallbackChain, resolveLocaleTemplate } from \"./resolve-locale.js\";\nimport type { LocaleCache, LocaleFallbackMap, OnMissingTranslation } from \"./types.js\";\n\nexport type FormatCoreContext = {\n key: string;\n namespace?: string | undefined;\n locale: string;\n localeFallback?: LocaleFallbackMap | undefined;\n onMissing: OnMissingTranslation;\n};\n\nexport type ResolveAndFormatOptions = {\n localeByKey: Record<string, string | undefined> | undefined;\n locale: string;\n params?: Record<string, unknown> | undefined;\n getCache: (resolvedLocale: string) => LocaleCache;\n context: FormatCoreContext;\n};\n\nfunction formatErrorLabel(context: Pick<FormatCoreContext, \"key\" | \"namespace\">): string {\n if (context.namespace !== undefined) {\n return `namespace \"${context.namespace}\", key \"${context.key}\"`;\n }\n return `key \"${context.key}\"`;\n}\n\nfunction formatMissingError(context: FormatCoreContext): string {\n const chain = formatLocaleFallbackChain(context.locale, context.localeFallback);\n if (context.namespace !== undefined) {\n return `[i18n] Missing key or locale: namespace \"${context.namespace}\", key \"${context.key}\" [${context.locale}] (fallback chain: ${chain})`;\n }\n return `[i18n] Missing key or locale: \"${context.key}\" [${context.locale}] (fallback chain: ${chain})`;\n}\n\nfunction resolveMissing(context: FormatCoreContext): string {\n const chain = formatLocaleFallbackChain(context.locale, context.localeFallback);\n if (context.onMissing === \"key\") {\n if (context.namespace !== undefined) {\n return `${context.namespace}.${context.key}`;\n }\n return context.key;\n }\n if (typeof context.onMissing === \"function\") {\n return context.onMissing({\n ...(context.namespace !== undefined ? { namespace: context.namespace } : {}),\n key: context.key,\n locale: context.locale,\n fallbackChain: chain,\n });\n }\n throw new Error(formatMissingError(context));\n}\n\n/**\n * Shared runtime path for both ICU providers: resolve locale (with fallback) →\n * compile template (cached) → format with params; handles missing keys via `onMissing`.\n */\nexport function resolveAndFormat(options: ResolveAndFormatOptions): string {\n const { localeByKey, locale, params, getCache, context } = options;\n const resolved = resolveLocaleTemplate(localeByKey, locale, context.localeFallback);\n\n if (!resolved) {\n return resolveMissing(context);\n }\n\n const { template, resolvedLocale } = resolved;\n const cache = getCache(resolvedLocale);\n const cacheKey = context.key;\n const label = formatErrorLabel(context);\n\n if (!cache[cacheKey]) {\n try {\n cache[cacheKey] = new IntlMessageFormat(template, resolvedLocale);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(\n `[i18n ICU Syntax Error] Dictionary error for ${label} [${resolvedLocale}]: ${message}`\n );\n }\n }\n\n try {\n return cache[cacheKey].format(params) as string;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(\n `[i18n Formatting Error] Invalid or missing parameters for ${label} [${resolvedLocale}]: ${message}`\n );\n }\n}\n","import { cloneAndFreeze } from \"./deep-freeze.js\";\nimport { resolveAndFormat } from \"./format-core.js\";\nimport { validateLocaleFallback } from \"./resolve-locale.js\";\nimport type {\n IcuTranslationProviderOptions,\n KeyDictionary,\n LocaleFallbackMap,\n LocaleOfSingle,\n OnMissingTranslation,\n SingleCompiledCache,\n} from \"./types.js\";\n\nexport interface TranslationProviderSingleForLocale<\n Schema extends KeyDictionary,\n Params extends { [K in keyof Schema]: unknown },\n Locale extends string,\n> {\n readonly locale: Locale;\n get<K extends keyof Schema & string>(\n key: K,\n ...params: Params[K] extends never ? [] : [params: Params[K]]\n ): string;\n}\n\nexport interface TranslationProviderSingle<\n Schema extends KeyDictionary,\n Params extends { [K in keyof Schema]: unknown },\n RequestLocales extends string = LocaleOfSingle<Schema>,\n> {\n get<K extends keyof Schema & string>(\n key: K,\n locale: RequestLocales,\n ...params: Params[K] extends never ? [] : [params: Params[K]]\n ): string;\n forLocale<Locale extends RequestLocales>(\n locale: Locale\n ): TranslationProviderSingleForLocale<Schema, Params, Locale>;\n getAll(): Schema;\n setAll(values: Schema): void;\n}\n\nexport class IcuTranslationProviderSingleForLocale<\n Schema extends KeyDictionary,\n Params extends { [K in keyof Schema]: unknown },\n RequestLocales extends string,\n Locale extends RequestLocales,\n Fallback extends LocaleFallbackMap | undefined,\n> implements TranslationProviderSingleForLocale<Schema, Params, Locale> {\n constructor(\n private readonly provider: IcuTranslationProviderSingle<\n Schema,\n Params,\n RequestLocales,\n Fallback\n >,\n readonly locale: Locale\n ) {}\n\n get<K extends keyof Schema & string>(\n key: K,\n ...args: Params[K] extends never ? [] : [params: Params[K]]\n ): string {\n const params = args[0] as Record<string, unknown> | undefined;\n return this.provider.getWithLocale(String(key), this.locale, params);\n }\n}\n\nexport class IcuTranslationProviderSingle<\n Schema extends KeyDictionary,\n Params extends { [K in keyof Schema]: unknown },\n RequestLocales extends string = LocaleOfSingle<Schema>,\n Fallback extends LocaleFallbackMap | undefined = undefined,\n> implements TranslationProviderSingle<Schema, Params, RequestLocales> {\n private dictionary: Schema;\n private compiledCache: SingleCompiledCache = {};\n private readonly localeFallback?: Fallback;\n private readonly onMissing: OnMissingTranslation;\n\n constructor(dictionary: Schema, options?: IcuTranslationProviderOptions<Fallback>) {\n this.dictionary = structuredClone(dictionary);\n if (options?.localeFallback) {\n validateLocaleFallback(options.localeFallback);\n this.localeFallback = options.localeFallback;\n }\n this.onMissing = options?.onMissing ?? \"throw\";\n }\n\n get<K extends keyof Schema & string>(\n key: K,\n locale: RequestLocales,\n ...args: Params[K] extends never ? [] : [params: Params[K]]\n ): string {\n const params = args[0] as Record<string, unknown> | undefined;\n return this.getWithLocale(String(key), locale, params);\n }\n\n getWithLocale(key: string, locale: string, params?: Record<string, unknown>): string {\n return resolveAndFormat({\n localeByKey: this.dictionary[key],\n locale,\n params,\n getCache: (resolvedLocale) => {\n if (!this.compiledCache[resolvedLocale]) {\n this.compiledCache[resolvedLocale] = {};\n }\n return this.compiledCache[resolvedLocale]!;\n },\n context: {\n key,\n locale,\n localeFallback: this.localeFallback,\n onMissing: this.onMissing,\n },\n });\n }\n\n forLocale<Locale extends RequestLocales>(\n locale: Locale\n ): IcuTranslationProviderSingleForLocale<Schema, Params, RequestLocales, Locale, Fallback> {\n return new IcuTranslationProviderSingleForLocale(this, locale);\n }\n\n getAll(): Schema {\n return cloneAndFreeze(this.dictionary);\n }\n\n setAll(values: Schema): void {\n this.dictionary = structuredClone(values);\n this.compiledCache = {};\n }\n}\n","import { cloneAndFreeze } from \"./deep-freeze.js\";\nimport { resolveAndFormat } from \"./format-core.js\";\nimport { validateLocaleFallback } from \"./resolve-locale.js\";\nimport type {\n IcuTranslationProviderOptions,\n LocaleFallbackMap,\n LocaleOfMulti,\n MultiCompiledCache,\n MultiDictionary,\n OnMissingTranslation,\n} from \"./types.js\";\n\nexport interface TranslationProviderMultiForLocale<\n Schema extends MultiDictionary,\n Params extends { [NS in keyof Schema]: { [K in keyof Schema[NS]]: unknown } },\n Locale extends string,\n> {\n readonly locale: Locale;\n get<NS extends keyof Schema, K extends keyof Schema[NS] & keyof Params[NS] & string>(\n namespace: NS,\n key: K,\n ...params: Params[NS][K] extends never ? [] : [params: Params[NS][K]]\n ): string;\n}\n\nexport interface TranslationProviderMulti<\n Schema extends MultiDictionary,\n Params extends { [NS in keyof Schema]: { [K in keyof Schema[NS]]: unknown } },\n RequestLocales extends string = LocaleOfMulti<Schema>,\n> {\n get<NS extends keyof Schema, K extends keyof Schema[NS] & keyof Params[NS] & string>(\n namespace: NS,\n key: K,\n locale: RequestLocales,\n ...params: Params[NS][K] extends never ? [] : [params: Params[NS][K]]\n ): string;\n forLocale<Locale extends RequestLocales>(\n locale: Locale\n ): TranslationProviderMultiForLocale<Schema, Params, Locale>;\n getAll(): Schema;\n hasNamespace<NS extends keyof Schema & string>(namespace: NS): boolean;\n setAll(values: Schema): void;\n setNamespace<NS extends keyof Schema>(namespace: NS, values: Schema[NS]): void;\n}\n\nexport class IcuTranslationProviderMultiForLocale<\n Schema extends MultiDictionary,\n Params extends { [NS in keyof Schema]: { [K in keyof Schema[NS]]: unknown } },\n RequestLocales extends string,\n Locale extends RequestLocales,\n Fallback extends LocaleFallbackMap | undefined,\n> implements TranslationProviderMultiForLocale<Schema, Params, Locale> {\n constructor(\n private readonly provider: IcuTranslationProviderMulti<\n Schema,\n Params,\n RequestLocales,\n Fallback\n >,\n readonly locale: Locale\n ) {}\n\n get<NS extends keyof Schema, K extends keyof Schema[NS] & keyof Params[NS] & string>(\n namespace: NS,\n key: K,\n ...args: Params[NS][K] extends never ? [] : [params: Params[NS][K]]\n ): string {\n const params = args[0] as Record<string, unknown> | undefined;\n return this.provider.getWithLocale(String(namespace), String(key), this.locale, params);\n }\n}\n\nexport class IcuTranslationProviderMulti<\n Schema extends MultiDictionary,\n Params extends { [NS in keyof Schema]: { [K in keyof Schema[NS]]: unknown } },\n RequestLocales extends string = LocaleOfMulti<Schema>,\n Fallback extends LocaleFallbackMap | undefined = undefined,\n> implements TranslationProviderMulti<Schema, Params, RequestLocales> {\n private dictionary: Schema;\n private compiledCache: MultiCompiledCache = {};\n private readonly localeFallback?: Fallback;\n private readonly onMissing: OnMissingTranslation;\n private loadedNamespaces: Set<string>;\n\n constructor(dictionary: Partial<Schema>, options?: IcuTranslationProviderOptions<Fallback>) {\n this.dictionary = structuredClone(dictionary) as Schema;\n this.loadedNamespaces = new Set(Object.keys(dictionary));\n if (options?.localeFallback) {\n validateLocaleFallback(options.localeFallback);\n this.localeFallback = options.localeFallback;\n }\n this.onMissing = options?.onMissing ?? \"throw\";\n }\n\n get<NS extends keyof Schema, K extends keyof Schema[NS] & keyof Params[NS] & string>(\n namespace: NS,\n key: K,\n locale: RequestLocales,\n ...args: Params[NS][K] extends never ? [] : [params: Params[NS][K]]\n ): string {\n const params = args[0] as Record<string, unknown> | undefined;\n return this.getWithLocale(String(namespace), String(key), locale, params);\n }\n\n getWithLocale(\n namespace: string,\n key: string,\n locale: string,\n params?: Record<string, unknown>\n ): string {\n if (!this.loadedNamespaces.has(namespace)) {\n throw new Error(\n `[i18n] Namespace not loaded: \"${namespace}\". Register it with setNamespace() before calling .get().`\n );\n }\n\n const localeByKey = (\n this.dictionary[namespace] as Record<string, Record<string, string>> | undefined\n )?.[key];\n\n return resolveAndFormat({\n localeByKey,\n locale,\n params,\n getCache: (resolvedLocale) => {\n if (!this.compiledCache[resolvedLocale]) {\n this.compiledCache[resolvedLocale] = {};\n }\n if (!this.compiledCache[resolvedLocale]![namespace]) {\n this.compiledCache[resolvedLocale]![namespace] = {};\n }\n return this.compiledCache[resolvedLocale]![namespace]!;\n },\n context: {\n namespace,\n key,\n locale,\n localeFallback: this.localeFallback,\n onMissing: this.onMissing,\n },\n });\n }\n\n forLocale<Locale extends RequestLocales>(\n locale: Locale\n ): IcuTranslationProviderMultiForLocale<Schema, Params, RequestLocales, Locale, Fallback> {\n return new IcuTranslationProviderMultiForLocale(this, locale);\n }\n\n getAll(): Schema {\n return cloneAndFreeze(this.dictionary);\n }\n\n hasNamespace<NS extends keyof Schema & string>(namespace: NS): boolean {\n return this.loadedNamespaces.has(namespace);\n }\n\n setAll(values: Schema): void {\n this.dictionary = structuredClone(values);\n this.compiledCache = {};\n this.loadedNamespaces = new Set(Object.keys(values));\n }\n\n setNamespace<NS extends keyof Schema>(namespace: NS, values: Schema[NS]): void {\n this.dictionary = {\n ...this.dictionary,\n [namespace]: structuredClone(values),\n };\n this.loadedNamespaces.add(namespace as string);\n\n for (const locale of Object.keys(this.compiledCache)) {\n delete this.compiledCache[locale]?.[namespace as string];\n }\n }\n}\n","import { resolveLocaleTemplate } from \"./resolve-locale.js\";\nimport type { KeyDictionary, LocaleFallbackMap, MultiDictionary } from \"./types.js\";\n\nfunction classifyAreaLocales(\n areaLocales: readonly string[],\n localeFallback?: LocaleFallbackMap\n): { full: string[]; preserve: string[] } {\n const areaSet = new Set(areaLocales);\n const full: string[] = [];\n const preserve: string[] = [];\n\n for (const locale of areaLocales) {\n const fallback = localeFallback?.[locale];\n if (fallback !== null && fallback !== undefined && areaSet.has(fallback)) {\n preserve.push(locale);\n } else {\n full.push(locale);\n }\n }\n\n return { full, preserve };\n}\n\nfunction projectKeyDictionary<T extends KeyDictionary>(\n dictionary: T,\n locales: readonly string[],\n localeFallback?: LocaleFallbackMap\n): T {\n const targetLocales = [...new Set(locales)];\n const result = {} as T;\n\n for (const [key, localesByKey] of Object.entries(dictionary)) {\n const projected: Record<string, string> = {};\n\n for (const locale of targetLocales) {\n const resolved = resolveLocaleTemplate(localesByKey, locale, localeFallback);\n if (resolved !== undefined) {\n projected[locale] = resolved.template;\n }\n }\n\n if (Object.keys(projected).length > 0) {\n result[key as keyof T] = projected as T[keyof T];\n }\n }\n\n return result;\n}\n\n/**\n * Builds a namespace dictionary that contains only the requested locales.\n * For each key and target locale, copies the direct template when present;\n * otherwise resolves through `localeFallback` (same rules as `.get()` at runtime).\n */\nexport function projectNamespaceLocalesCore<T extends KeyDictionary>(\n dictionary: T,\n locales: readonly string[],\n localeFallback?: LocaleFallbackMap\n): T {\n return projectKeyDictionary(dictionary, locales, localeFallback);\n}\n\n/**\n * Projects a single namespace for a custom delivery area.\n * Full locales resolve through `localeFallback` (e.g. external chains like `it → en-US`);\n * preserve locales copy only their direct canonical entry when present.\n */\nexport function projectNamespaceForDeliveryAreaCore<T extends KeyDictionary>(\n dictionary: T,\n areaLocales: readonly string[],\n localeFallback?: LocaleFallbackMap\n): T {\n const { full, preserve } = classifyAreaLocales(areaLocales, localeFallback);\n const fullProjection =\n full.length > 0 ? projectKeyDictionary(dictionary, full, localeFallback) : undefined;\n const result = {} as T;\n\n for (const [key, localesByKey] of Object.entries(dictionary)) {\n const projected: Record<string, string> = {};\n\n if (fullProjection !== undefined) {\n const fullEntry = fullProjection[key as keyof T];\n if (fullEntry !== undefined) {\n Object.assign(projected, fullEntry);\n }\n }\n\n for (const locale of preserve) {\n const template = localesByKey[locale];\n if (template !== undefined) {\n projected[locale] = template;\n }\n }\n\n if (Object.keys(projected).length > 0) {\n result[key as keyof T] = projected as T[keyof T];\n }\n }\n\n return result;\n}\n\n/**\n * Projects a multi-namespace dictionary for a custom delivery area.\n * Each namespace uses the same delivery-area rules as `projectNamespaceForDeliveryAreaCore`.\n */\nexport function projectDictionaryForDeliveryAreaCore<T extends MultiDictionary>(\n dictionary: T,\n areaLocales: readonly string[],\n localeFallback?: LocaleFallbackMap\n): T {\n const result = {} as T;\n\n for (const namespace of Object.keys(dictionary) as (keyof T & string)[]) {\n const namespaceDictionary = dictionary[namespace];\n if (namespaceDictionary === undefined) {\n continue;\n }\n\n result[namespace] = projectNamespaceForDeliveryAreaCore(\n namespaceDictionary,\n areaLocales,\n localeFallback\n ) as T[typeof namespace];\n }\n\n return result;\n}\n\n/**\n * Projects every namespace in a multi-namespace dictionary.\n */\nexport function projectDictionaryLocalesCore<T extends MultiDictionary>(\n dictionary: T,\n locales: readonly string[],\n localeFallback?: LocaleFallbackMap\n): T {\n const result = {} as T;\n\n for (const namespace of Object.keys(dictionary) as (keyof T & string)[]) {\n const namespaceDictionary = dictionary[namespace];\n if (namespaceDictionary === undefined) {\n continue;\n }\n\n result[namespace] = projectKeyDictionary(\n namespaceDictionary,\n locales,\n localeFallback\n ) as T[typeof namespace];\n }\n\n return result;\n}\n"]}
|
|
@@ -81,6 +81,10 @@ type ValidationResult<T> = {
|
|
|
81
81
|
readonly issues: readonly ValidationIssue[];
|
|
82
82
|
};
|
|
83
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Validation step 1: coerce external input into a normalized dictionary shape
|
|
86
|
+
* (keys, locales, ICU args) against a `DictionarySpec`.
|
|
87
|
+
*/
|
|
84
88
|
declare function normalizeDictionary(input: unknown, spec: DictionarySpec): ValidationResult<NormalizedDictionary>;
|
|
85
89
|
|
|
86
90
|
type LocaleDictionary = Record<string, string>;
|