@xndrjs/i18n 0.2.0-alpha.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.
Files changed (50) hide show
  1. package/README.md +572 -0
  2. package/bin/codegen.mjs +17 -0
  3. package/bin/setup.mjs +14 -0
  4. package/dist/index.d.ts +124 -0
  5. package/dist/index.js +320 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/types-CFWVT2PP.d.ts +77 -0
  8. package/dist/validation/index.d.ts +44 -0
  9. package/dist/validation/index.js +490 -0
  10. package/dist/validation/index.js.map +1 -0
  11. package/package.json +65 -0
  12. package/src/IcuTranslationProviderMulti.test.ts +290 -0
  13. package/src/IcuTranslationProviderMulti.ts +195 -0
  14. package/src/IcuTranslationProviderSingle.test.ts +314 -0
  15. package/src/IcuTranslationProviderSingle.ts +155 -0
  16. package/src/codegen/config.ts +63 -0
  17. package/src/codegen/emit/dictionary-file.ts +73 -0
  18. package/src/codegen/emit/dictionary-schema-file.ts +129 -0
  19. package/src/codegen/emit/instance-file.ts +60 -0
  20. package/src/codegen/emit/namespace-loaders-file.ts +44 -0
  21. package/src/codegen/emit/types-file.ts +118 -0
  22. package/src/codegen/generate-i18n-types.test.ts +482 -0
  23. package/src/codegen/generate-i18n-types.ts +173 -0
  24. package/src/codegen/icu-analysis.ts +88 -0
  25. package/src/codegen/locale-fallback.ts +64 -0
  26. package/src/codegen/paths.ts +27 -0
  27. package/src/codegen/types.ts +30 -0
  28. package/src/deep-freeze.test.ts +27 -0
  29. package/src/deep-freeze.ts +17 -0
  30. package/src/ensure-namespace.integration.test.ts +66 -0
  31. package/src/ensure-namespace.test.ts +125 -0
  32. package/src/ensure-namespace.ts +70 -0
  33. package/src/icu/extract-variables.ts +87 -0
  34. package/src/icu/parse-template.ts +24 -0
  35. package/src/index.ts +32 -0
  36. package/src/resolve-locale.test.ts +91 -0
  37. package/src/resolve-locale.ts +88 -0
  38. package/src/setup/setup-i18n.test.ts +86 -0
  39. package/src/setup/setup-i18n.ts +179 -0
  40. package/src/setup/type-names.ts +20 -0
  41. package/src/types.ts +34 -0
  42. package/src/validation/create-args-schema.ts +76 -0
  43. package/src/validation/create-normalized-schema.ts +52 -0
  44. package/src/validation/errors.ts +41 -0
  45. package/src/validation/index.ts +90 -0
  46. package/src/validation/normalize.ts +158 -0
  47. package/src/validation/to-dictionary.ts +67 -0
  48. package/src/validation/types.ts +78 -0
  49. package/src/validation/validate-normalized.ts +91 -0
  50. package/src/validation/validation.test.ts +265 -0
@@ -0,0 +1,490 @@
1
+ import { parse } from '@formatjs/icu-messageformat-parser';
2
+ import { z } from 'zod';
3
+
4
+ // src/icu/extract-variables.ts
5
+ function isNumericIcuNode(node) {
6
+ if (node.type === 2) {
7
+ return true;
8
+ }
9
+ if (node.type === 6 && "pluralType" in node && node.pluralType) {
10
+ return true;
11
+ }
12
+ return false;
13
+ }
14
+ function hasVariableName(node) {
15
+ return "value" in node && typeof node.value === "string";
16
+ }
17
+ function extractVariables(nodes) {
18
+ const variables = {};
19
+ const walk = (walkNodes) => {
20
+ for (const node of walkNodes) {
21
+ if (node.type === 1) {
22
+ variables[node.value] = variables[node.value] ?? "string";
23
+ } else if (isNumericIcuNode(node) && hasVariableName(node)) {
24
+ variables[node.value] = "number";
25
+ } else if ((node.type === 3 || node.type === 4) && hasVariableName(node)) {
26
+ variables[node.value] = "date";
27
+ } else if (node.type === 5 && hasVariableName(node)) {
28
+ variables[node.value] = variables[node.value] ?? "string";
29
+ } else if (node.type === 6 && hasVariableName(node)) {
30
+ variables[node.value] = variables[node.value] ?? "string";
31
+ }
32
+ if ("options" in node && node.options) {
33
+ for (const option of Object.values(node.options)) {
34
+ walk(option.value);
35
+ }
36
+ }
37
+ if ("children" in node && Array.isArray(node.children)) {
38
+ walk(node.children);
39
+ }
40
+ }
41
+ };
42
+ walk(nodes);
43
+ return variables;
44
+ }
45
+ function mergeVariableSpecs(target, source) {
46
+ const merged = { ...target };
47
+ for (const [varName, varType] of Object.entries(source)) {
48
+ const existing = merged[varName];
49
+ if (existing && existing !== varType) {
50
+ merged[varName] = "number";
51
+ } else {
52
+ merged[varName] = varType;
53
+ }
54
+ }
55
+ return merged;
56
+ }
57
+ function variableSpecsEqual(a, b) {
58
+ const aKeys = Object.keys(a).sort();
59
+ const bKeys = Object.keys(b).sort();
60
+ if (aKeys.length !== bKeys.length) {
61
+ return false;
62
+ }
63
+ return aKeys.every((key, index) => {
64
+ if (key !== bKeys[index]) {
65
+ return false;
66
+ }
67
+ return a[key] === b[key];
68
+ });
69
+ }
70
+ function parseTemplate(template) {
71
+ try {
72
+ const ast = parse(template);
73
+ return { ok: true, args: extractVariables(ast) };
74
+ } catch (error) {
75
+ const message = error instanceof Error ? error.message : String(error);
76
+ return { ok: false, message };
77
+ }
78
+ }
79
+
80
+ // src/validation/normalize.ts
81
+ function failure(issues) {
82
+ return { ok: false, issues };
83
+ }
84
+ function success(data) {
85
+ return { ok: true, data };
86
+ }
87
+ function isPlainObject(value) {
88
+ return typeof value === "object" && value !== null && !Array.isArray(value);
89
+ }
90
+ function normalizeKeyDictionary(input, requiredKeys, keyPathPrefix) {
91
+ const issues = [];
92
+ const keys = {};
93
+ for (const key of requiredKeys) {
94
+ if (!(key in input)) {
95
+ issues.push({ kind: "missing_key", path: [...keyPathPrefix, key] });
96
+ continue;
97
+ }
98
+ const keyValue = input[key];
99
+ if (!isPlainObject(keyValue)) {
100
+ issues.push({
101
+ kind: "invalid_input",
102
+ message: `Expected object for key "${key}", got ${typeof keyValue}`
103
+ });
104
+ continue;
105
+ }
106
+ const locales = {};
107
+ let mergedArgs = {};
108
+ let hasLocaleArgs = false;
109
+ for (const [locale, template] of Object.entries(keyValue)) {
110
+ const localePath = [...keyPathPrefix, key, locale];
111
+ if (typeof template !== "string") {
112
+ issues.push({
113
+ kind: "invalid_locale_value",
114
+ path: localePath,
115
+ message: `expected string, got ${typeof template}`
116
+ });
117
+ continue;
118
+ }
119
+ const parsed = parseTemplate(template);
120
+ if (!parsed.ok) {
121
+ issues.push({
122
+ kind: "icu_syntax_error",
123
+ path: localePath,
124
+ message: parsed.message
125
+ });
126
+ continue;
127
+ }
128
+ locales[locale] = { template, args: parsed.args };
129
+ if (!hasLocaleArgs) {
130
+ mergedArgs = { ...parsed.args };
131
+ hasLocaleArgs = true;
132
+ } else if (!variableSpecsEqual(mergedArgs, parsed.args)) {
133
+ const localeArgs = {};
134
+ for (const [loc, entry] of Object.entries(locales)) {
135
+ localeArgs[loc] = entry.args;
136
+ }
137
+ issues.push({
138
+ kind: "locale_args_mismatch",
139
+ path: [...keyPathPrefix, key],
140
+ locales: localeArgs,
141
+ message: `Inconsistent ICU variables across locales for key "${key}"`
142
+ });
143
+ break;
144
+ }
145
+ }
146
+ keys[key] = { locales, mergedArgs };
147
+ }
148
+ if (issues.length > 0) {
149
+ return { ok: false, issues };
150
+ }
151
+ return { ok: true, data: keys };
152
+ }
153
+ function normalizeDictionary(input, spec) {
154
+ if (!isPlainObject(input)) {
155
+ return failure([
156
+ {
157
+ kind: "invalid_input",
158
+ message: `Expected object, got ${input === null ? "null" : typeof input}`
159
+ }
160
+ ]);
161
+ }
162
+ if (spec.mode === "single") {
163
+ const result = normalizeKeyDictionary(input, spec.requiredKeys, []);
164
+ if (!result.ok) {
165
+ return result;
166
+ }
167
+ return success({ mode: "single", keys: result.data });
168
+ }
169
+ const issues = [];
170
+ const namespaces = {};
171
+ for (const [namespace, requiredKeys] of Object.entries(spec.requiredKeys)) {
172
+ if (!(namespace in input)) {
173
+ for (const key of requiredKeys) {
174
+ issues.push({ kind: "missing_key", path: [namespace, key] });
175
+ }
176
+ continue;
177
+ }
178
+ const namespaceValue = input[namespace];
179
+ if (!isPlainObject(namespaceValue)) {
180
+ issues.push({
181
+ kind: "invalid_input",
182
+ message: `Expected object for namespace "${namespace}", got ${typeof namespaceValue}`
183
+ });
184
+ continue;
185
+ }
186
+ const result = normalizeKeyDictionary(namespaceValue, requiredKeys, [namespace]);
187
+ if (!result.ok) {
188
+ issues.push(...result.issues);
189
+ } else {
190
+ namespaces[namespace] = result.data;
191
+ }
192
+ }
193
+ if (issues.length > 0) {
194
+ return failure(issues);
195
+ }
196
+ return success({ mode: "multi", namespaces });
197
+ }
198
+
199
+ // src/validation/to-dictionary.ts
200
+ function toDictionary(normalized) {
201
+ if (normalized.mode === "single") {
202
+ const dictionary2 = {};
203
+ for (const [key, entry] of Object.entries(normalized.keys)) {
204
+ const locales = {};
205
+ for (const [locale, localeEntry] of Object.entries(entry.locales)) {
206
+ locales[locale] = localeEntry.template;
207
+ }
208
+ dictionary2[key] = locales;
209
+ }
210
+ return dictionary2;
211
+ }
212
+ const dictionary = {};
213
+ for (const [namespace, keys] of Object.entries(normalized.namespaces)) {
214
+ const namespaceDictionary = {};
215
+ for (const [key, entry] of Object.entries(keys)) {
216
+ const locales = {};
217
+ for (const [locale, localeEntry] of Object.entries(entry.locales)) {
218
+ locales[locale] = localeEntry.template;
219
+ }
220
+ namespaceDictionary[key] = locales;
221
+ }
222
+ dictionary[namespace] = namespaceDictionary;
223
+ }
224
+ return dictionary;
225
+ }
226
+ function toNamespaceDictionary(normalized, namespace) {
227
+ if (normalized.mode !== "multi") {
228
+ throw new Error(
229
+ `[i18n] toNamespaceDictionary requires multi-mode normalized dictionary, got "${normalized.mode}"`
230
+ );
231
+ }
232
+ const keys = normalized.namespaces[namespace];
233
+ if (!keys) {
234
+ return {};
235
+ }
236
+ const dictionary = {};
237
+ for (const [key, entry] of Object.entries(keys)) {
238
+ const locales = {};
239
+ for (const [locale, localeEntry] of Object.entries(entry.locales)) {
240
+ locales[locale] = localeEntry.template;
241
+ }
242
+ dictionary[key] = locales;
243
+ }
244
+ return dictionary;
245
+ }
246
+ var variableTypeSchema = z.enum(["string", "number", "date"]);
247
+ function formatVariableMismatch(expected, found) {
248
+ const expectedKeys = Object.keys(expected).sort();
249
+ const foundKeys = Object.keys(found).sort();
250
+ return `Expected variables [${expectedKeys.join(", ")}], found [${foundKeys.join(", ")}]`;
251
+ }
252
+ function createArgsSchema(expected) {
253
+ return z.record(z.string(), variableTypeSchema).superRefine((found, ctx) => {
254
+ const expectedKeys = Object.keys(expected).sort();
255
+ const foundKeys = Object.keys(found).sort();
256
+ if (expectedKeys.join() !== foundKeys.join()) {
257
+ ctx.addIssue({
258
+ code: "custom",
259
+ message: formatVariableMismatch(expected, found)
260
+ });
261
+ return;
262
+ }
263
+ for (const [name, type] of Object.entries(expected)) {
264
+ if (found[name] !== type) {
265
+ ctx.addIssue({
266
+ code: "custom",
267
+ message: `Variable "${name}": expected ${type}, found ${found[name]}`
268
+ });
269
+ }
270
+ }
271
+ });
272
+ }
273
+ function mapArgsSchemaError(expected, found, message, path) {
274
+ const expectedKeys = Object.keys(expected).sort();
275
+ const foundKeys = Object.keys(found).sort();
276
+ if (expectedKeys.join() !== foundKeys.join()) {
277
+ return {
278
+ kind: "variable_mismatch",
279
+ path,
280
+ expected,
281
+ found,
282
+ message
283
+ };
284
+ }
285
+ for (const [name, type] of Object.entries(expected)) {
286
+ const foundType = found[name];
287
+ if (foundType !== void 0 && foundType !== type) {
288
+ return {
289
+ kind: "variable_type_mismatch",
290
+ path,
291
+ variable: name,
292
+ expected: type,
293
+ found: foundType,
294
+ message
295
+ };
296
+ }
297
+ }
298
+ return {
299
+ kind: "variable_mismatch",
300
+ path,
301
+ expected,
302
+ found,
303
+ message
304
+ };
305
+ }
306
+ var parsedLocaleEntrySchema = z.object({
307
+ template: z.string(),
308
+ args: z.record(z.string(), variableTypeSchema)
309
+ });
310
+ var parsedKeyEntrySchema = z.object({
311
+ locales: z.record(z.string(), parsedLocaleEntrySchema),
312
+ mergedArgs: z.record(z.string(), variableTypeSchema)
313
+ });
314
+ function createKeyDictionarySchema(argsByKey) {
315
+ const keySchemas = Object.fromEntries(
316
+ Object.entries(argsByKey).map(([key, expectedArgs]) => [
317
+ key,
318
+ parsedKeyEntrySchema.extend({
319
+ mergedArgs: createArgsSchema(expectedArgs)
320
+ })
321
+ ])
322
+ );
323
+ return z.object(keySchemas);
324
+ }
325
+ function createNormalizedDictionarySchema(spec) {
326
+ if (spec.mode === "single") {
327
+ return z.object({
328
+ mode: z.literal("single"),
329
+ keys: createKeyDictionarySchema(spec.argsByKey)
330
+ });
331
+ }
332
+ const namespaceSchemas = Object.fromEntries(
333
+ Object.entries(spec.argsByKey).map(([namespace, argsByKey]) => [
334
+ namespace,
335
+ createKeyDictionarySchema(argsByKey)
336
+ ])
337
+ );
338
+ return z.object({
339
+ mode: z.literal("multi"),
340
+ namespaces: z.object(namespaceSchemas)
341
+ });
342
+ }
343
+
344
+ // src/validation/validate-normalized.ts
345
+ function getExpectedArgs(spec, path) {
346
+ if (spec.mode === "single") {
347
+ const key2 = path[path.length - 1];
348
+ if (typeof key2 !== "string") {
349
+ return void 0;
350
+ }
351
+ return spec.argsByKey[key2];
352
+ }
353
+ const namespace = path[0];
354
+ const key = path[path.length - 1];
355
+ if (typeof namespace !== "string" || typeof key !== "string") {
356
+ return void 0;
357
+ }
358
+ return spec.argsByKey[namespace]?.[key];
359
+ }
360
+ function getFoundArgs(normalized, path) {
361
+ if (normalized.mode === "single") {
362
+ const key2 = path[path.length - 1];
363
+ if (typeof key2 !== "string") {
364
+ return void 0;
365
+ }
366
+ return normalized.keys[key2]?.mergedArgs;
367
+ }
368
+ const namespace = path[0];
369
+ const key = path[path.length - 1];
370
+ if (typeof namespace !== "string" || typeof key !== "string") {
371
+ return void 0;
372
+ }
373
+ return normalized.namespaces[namespace]?.[key]?.mergedArgs;
374
+ }
375
+ function mapZodError(error, spec, normalized) {
376
+ return error.issues.map((issue) => {
377
+ const path = issue.path.map(String);
378
+ if (path.includes("mergedArgs")) {
379
+ const keyPath = path.slice(0, path.indexOf("mergedArgs"));
380
+ const expected = getExpectedArgs(spec, keyPath);
381
+ const found = getFoundArgs(normalized, keyPath);
382
+ if (expected && found) {
383
+ return mapArgsSchemaError(expected, found, issue.message, keyPath);
384
+ }
385
+ }
386
+ return {
387
+ kind: "invalid_input",
388
+ message: path.length > 0 ? `${path.join(".")}: ${issue.message}` : issue.message
389
+ };
390
+ });
391
+ }
392
+ function validateNormalizedDictionary(normalized, spec) {
393
+ const schema = createNormalizedDictionarySchema(spec);
394
+ const result = schema.safeParse(normalized);
395
+ if (result.success) {
396
+ return { ok: true, data: result.data };
397
+ }
398
+ return {
399
+ ok: false,
400
+ issues: mapZodError(result.error, spec, normalized)
401
+ };
402
+ }
403
+
404
+ // src/validation/errors.ts
405
+ function issueMessage(issue) {
406
+ switch (issue.kind) {
407
+ case "missing_key":
408
+ return `Missing required key at ${issue.path.join(".")}`;
409
+ case "invalid_input":
410
+ case "invalid_locale_value":
411
+ case "icu_syntax_error":
412
+ case "locale_args_mismatch":
413
+ case "variable_mismatch":
414
+ case "variable_type_mismatch":
415
+ return issue.message;
416
+ }
417
+ }
418
+ function formatIssues(issues) {
419
+ return issues.map((issue) => {
420
+ if ("path" in issue && issue.path.length > 0) {
421
+ return `[${issue.path.join(".")}] ${issue.kind}: ${issueMessage(issue)}`;
422
+ }
423
+ return `${issue.kind}: ${issueMessage(issue)}`;
424
+ }).join("\n");
425
+ }
426
+ var DictionaryValidationError = class extends Error {
427
+ constructor(issues) {
428
+ super(formatIssues(issues));
429
+ this.issues = issues;
430
+ this.name = "DictionaryValidationError";
431
+ }
432
+ issues;
433
+ };
434
+ function assertValidDictionary(result) {
435
+ if (!result.ok) {
436
+ throw new DictionaryValidationError(result.issues);
437
+ }
438
+ }
439
+
440
+ // src/validation/index.ts
441
+ function validateExternalDictionary(input, spec) {
442
+ const step1 = normalizeDictionary(input, spec);
443
+ if (!step1.ok) {
444
+ return step1;
445
+ }
446
+ const step2 = validateNormalizedDictionary(step1.data, spec);
447
+ if (!step2.ok) {
448
+ return step2;
449
+ }
450
+ return { ok: true, data: toDictionary(step2.data) };
451
+ }
452
+ function validateExternalNamespace(namespace, input, spec) {
453
+ if (spec.mode !== "multi") {
454
+ return {
455
+ ok: false,
456
+ issues: [
457
+ {
458
+ kind: "invalid_input",
459
+ message: "validateExternalNamespace requires multi-mode dictionary spec"
460
+ }
461
+ ]
462
+ };
463
+ }
464
+ const wrapped = { [namespace]: input };
465
+ const namespaceSpec = {
466
+ mode: "multi",
467
+ requiredKeys: {
468
+ [namespace]: spec.requiredKeys[namespace] ?? []
469
+ },
470
+ argsByKey: {
471
+ [namespace]: spec.argsByKey[namespace] ?? {}
472
+ }
473
+ };
474
+ const step1 = normalizeDictionary(wrapped, namespaceSpec);
475
+ if (!step1.ok) {
476
+ return step1;
477
+ }
478
+ const step2 = validateNormalizedDictionary(step1.data, namespaceSpec);
479
+ if (!step2.ok) {
480
+ return step2;
481
+ }
482
+ return {
483
+ ok: true,
484
+ data: toNamespaceDictionary(step2.data, namespace)
485
+ };
486
+ }
487
+
488
+ export { DictionaryValidationError, assertValidDictionary, createArgsSchema, createNormalizedDictionarySchema, extractVariables, formatIssues, mergeVariableSpecs, normalizeDictionary, parseTemplate, toDictionary, toNamespaceDictionary, validateExternalDictionary, validateExternalNamespace, validateNormalizedDictionary, variableSpecsEqual };
489
+ //# sourceMappingURL=index.js.map
490
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/icu/extract-variables.ts","../../src/icu/parse-template.ts","../../src/validation/normalize.ts","../../src/validation/to-dictionary.ts","../../src/validation/create-args-schema.ts","../../src/validation/create-normalized-schema.ts","../../src/validation/validate-normalized.ts","../../src/validation/errors.ts","../../src/validation/index.ts"],"names":["dictionary","z","key"],"mappings":"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","file":"index.js","sourcesContent":["import type { parse } from \"@formatjs/icu-messageformat-parser\";\n\nexport type VariableType = \"string\" | \"number\" | \"date\";\nexport type VariableSpec = Record<string, VariableType>;\n\ntype IcuAst = ReturnType<typeof parse>;\ntype IcuNode = IcuAst[number];\n\nfunction isNumericIcuNode(node: IcuNode): boolean {\n if (node.type === 2) {\n return true;\n }\n\n if (node.type === 6 && \"pluralType\" in node && node.pluralType) {\n return true;\n }\n\n return false;\n}\n\nfunction hasVariableName(node: IcuNode): node is Extract<IcuNode, { value: string }> {\n return \"value\" in node && typeof node.value === \"string\";\n}\n\nexport function extractVariables(nodes: IcuAst): VariableSpec {\n const variables: VariableSpec = {};\n\n const walk = (walkNodes: IcuAst) => {\n for (const node of walkNodes) {\n if (node.type === 1) {\n variables[node.value] = variables[node.value] ?? \"string\";\n } else if (isNumericIcuNode(node) && hasVariableName(node)) {\n variables[node.value] = \"number\";\n } else if ((node.type === 3 || node.type === 4) && hasVariableName(node)) {\n variables[node.value] = \"date\";\n } else if (node.type === 5 && hasVariableName(node)) {\n variables[node.value] = variables[node.value] ?? \"string\";\n } else if (node.type === 6 && hasVariableName(node)) {\n variables[node.value] = variables[node.value] ?? \"string\";\n }\n\n if (\"options\" in node && node.options) {\n for (const option of Object.values(node.options)) {\n walk(option.value);\n }\n }\n\n if (\"children\" in node && Array.isArray(node.children)) {\n walk(node.children);\n }\n }\n };\n\n walk(nodes);\n return variables;\n}\n\nexport function mergeVariableSpecs(target: VariableSpec, source: VariableSpec): VariableSpec {\n const merged = { ...target };\n\n for (const [varName, varType] of Object.entries(source)) {\n const existing = merged[varName];\n if (existing && existing !== varType) {\n merged[varName] = \"number\";\n } else {\n merged[varName] = varType;\n }\n }\n\n return merged;\n}\n\nexport function variableSpecsEqual(a: VariableSpec, b: VariableSpec): boolean {\n const aKeys = Object.keys(a).sort();\n const bKeys = Object.keys(b).sort();\n\n if (aKeys.length !== bKeys.length) {\n return false;\n }\n\n return aKeys.every((key, index) => {\n if (key !== bKeys[index]) {\n return false;\n }\n return a[key] === b[key];\n });\n}\n","import { parse } from \"@formatjs/icu-messageformat-parser\";\nimport { extractVariables, type VariableSpec } from \"./extract-variables.js\";\n\nexport type ParseTemplateSuccess = {\n readonly ok: true;\n readonly args: VariableSpec;\n};\n\nexport type ParseTemplateFailure = {\n readonly ok: false;\n readonly message: string;\n};\n\nexport type ParseTemplateResult = ParseTemplateSuccess | ParseTemplateFailure;\n\nexport function parseTemplate(template: string): ParseTemplateResult {\n try {\n const ast = parse(template);\n return { ok: true, args: extractVariables(ast) };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return { ok: false, message };\n }\n}\n","import { variableSpecsEqual } from \"../icu/extract-variables.js\";\nimport { parseTemplate } from \"../icu/parse-template.js\";\nimport type {\n DictionarySpec,\n NormalizedDictionary,\n NormalizedKeyDictionary,\n ParsedKeyEntry,\n ValidationIssue,\n ValidationResult,\n} from \"./types.js\";\n\nfunction failure(issues: ValidationIssue[]): ValidationResult<NormalizedDictionary> {\n return { ok: false, issues };\n}\n\nfunction success(data: NormalizedDictionary): ValidationResult<NormalizedDictionary> {\n return { ok: true, data };\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction normalizeKeyDictionary(\n input: Record<string, unknown>,\n requiredKeys: readonly string[],\n keyPathPrefix: readonly string[]\n): ValidationResult<NormalizedKeyDictionary> {\n const issues: ValidationIssue[] = [];\n const keys: Record<string, ParsedKeyEntry> = {};\n\n for (const key of requiredKeys) {\n if (!(key in input)) {\n issues.push({ kind: \"missing_key\", path: [...keyPathPrefix, key] });\n continue;\n }\n\n const keyValue = input[key];\n if (!isPlainObject(keyValue)) {\n issues.push({\n kind: \"invalid_input\",\n message: `Expected object for key \"${key}\", got ${typeof keyValue}`,\n });\n continue;\n }\n\n const locales: Record<string, ParsedKeyEntry[\"locales\"][string]> = {};\n let mergedArgs: ParsedKeyEntry[\"mergedArgs\"] = {};\n let hasLocaleArgs = false;\n\n for (const [locale, template] of Object.entries(keyValue)) {\n const localePath = [...keyPathPrefix, key, locale];\n\n if (typeof template !== \"string\") {\n issues.push({\n kind: \"invalid_locale_value\",\n path: localePath,\n message: `expected string, got ${typeof template}`,\n });\n continue;\n }\n\n const parsed = parseTemplate(template);\n if (!parsed.ok) {\n issues.push({\n kind: \"icu_syntax_error\",\n path: localePath,\n message: parsed.message,\n });\n continue;\n }\n\n locales[locale] = { template, args: parsed.args };\n\n if (!hasLocaleArgs) {\n mergedArgs = { ...parsed.args };\n hasLocaleArgs = true;\n } else if (!variableSpecsEqual(mergedArgs, parsed.args)) {\n const localeArgs: Record<string, ParsedKeyEntry[\"mergedArgs\"]> = {};\n for (const [loc, entry] of Object.entries(locales)) {\n localeArgs[loc] = entry.args;\n }\n issues.push({\n kind: \"locale_args_mismatch\",\n path: [...keyPathPrefix, key],\n locales: localeArgs,\n message: `Inconsistent ICU variables across locales for key \"${key}\"`,\n });\n break;\n }\n }\n\n keys[key] = { locales, mergedArgs };\n }\n\n if (issues.length > 0) {\n return { ok: false, issues };\n }\n\n return { ok: true, data: keys };\n}\n\nexport function normalizeDictionary(\n input: unknown,\n spec: DictionarySpec\n): ValidationResult<NormalizedDictionary> {\n if (!isPlainObject(input)) {\n return failure([\n {\n kind: \"invalid_input\",\n message: `Expected object, got ${input === null ? \"null\" : typeof input}`,\n },\n ]);\n }\n\n if (spec.mode === \"single\") {\n const result = normalizeKeyDictionary(input, spec.requiredKeys, []);\n if (!result.ok) {\n return result;\n }\n\n return success({ mode: \"single\", keys: result.data });\n }\n\n const issues: ValidationIssue[] = [];\n const namespaces: Record<string, NormalizedKeyDictionary> = {};\n\n for (const [namespace, requiredKeys] of Object.entries(spec.requiredKeys)) {\n if (!(namespace in input)) {\n for (const key of requiredKeys) {\n issues.push({ kind: \"missing_key\", path: [namespace, key] });\n }\n continue;\n }\n\n const namespaceValue = input[namespace];\n if (!isPlainObject(namespaceValue)) {\n issues.push({\n kind: \"invalid_input\",\n message: `Expected object for namespace \"${namespace}\", got ${typeof namespaceValue}`,\n });\n continue;\n }\n\n const result = normalizeKeyDictionary(namespaceValue, requiredKeys, [namespace]);\n if (!result.ok) {\n issues.push(...result.issues);\n } else {\n namespaces[namespace] = result.data;\n }\n }\n\n if (issues.length > 0) {\n return failure(issues);\n }\n\n return success({ mode: \"multi\", namespaces });\n}\n","import type { NormalizedDictionary } from \"./types.js\";\n\ntype LocaleDictionary = Record<string, string>;\ntype KeyDictionary = Record<string, LocaleDictionary>;\ntype MultiDictionary = Record<string, KeyDictionary>;\n\nexport function toDictionary(normalized: NormalizedDictionary): KeyDictionary | MultiDictionary {\n if (normalized.mode === \"single\") {\n const dictionary: KeyDictionary = {};\n\n for (const [key, entry] of Object.entries(normalized.keys)) {\n const locales: LocaleDictionary = {};\n for (const [locale, localeEntry] of Object.entries(entry.locales)) {\n locales[locale] = localeEntry.template;\n }\n dictionary[key] = locales;\n }\n\n return dictionary;\n }\n\n const dictionary: MultiDictionary = {};\n\n for (const [namespace, keys] of Object.entries(normalized.namespaces)) {\n const namespaceDictionary: KeyDictionary = {};\n\n for (const [key, entry] of Object.entries(keys)) {\n const locales: LocaleDictionary = {};\n for (const [locale, localeEntry] of Object.entries(entry.locales)) {\n locales[locale] = localeEntry.template;\n }\n namespaceDictionary[key] = locales;\n }\n\n dictionary[namespace] = namespaceDictionary;\n }\n\n return dictionary;\n}\n\nexport function toNamespaceDictionary(\n normalized: NormalizedDictionary,\n namespace: string\n): KeyDictionary {\n if (normalized.mode !== \"multi\") {\n throw new Error(\n `[i18n] toNamespaceDictionary requires multi-mode normalized dictionary, got \"${normalized.mode}\"`\n );\n }\n\n const keys = normalized.namespaces[namespace];\n if (!keys) {\n return {};\n }\n\n const dictionary: KeyDictionary = {};\n\n for (const [key, entry] of Object.entries(keys)) {\n const locales: LocaleDictionary = {};\n for (const [locale, localeEntry] of Object.entries(entry.locales)) {\n locales[locale] = localeEntry.template;\n }\n dictionary[key] = locales;\n }\n\n return dictionary;\n}\n","import { z } from \"zod\";\nimport type { VariableSpec, VariableType } from \"../icu/extract-variables.js\";\n\nexport const variableTypeSchema = z.enum([\"string\", \"number\", \"date\"]);\n\nfunction formatVariableMismatch(expected: VariableSpec, found: VariableSpec): string {\n const expectedKeys = Object.keys(expected).sort();\n const foundKeys = Object.keys(found).sort();\n return `Expected variables [${expectedKeys.join(\", \")}], found [${foundKeys.join(\", \")}]`;\n}\n\nexport function createArgsSchema(expected: VariableSpec): z.ZodType<VariableSpec> {\n return z.record(z.string(), variableTypeSchema).superRefine((found, ctx) => {\n const expectedKeys = Object.keys(expected).sort();\n const foundKeys = Object.keys(found).sort();\n\n if (expectedKeys.join() !== foundKeys.join()) {\n ctx.addIssue({\n code: \"custom\",\n message: formatVariableMismatch(expected, found),\n });\n return;\n }\n\n for (const [name, type] of Object.entries(expected)) {\n if (found[name] !== type) {\n ctx.addIssue({\n code: \"custom\",\n message: `Variable \"${name}\": expected ${type}, found ${found[name]}`,\n });\n }\n }\n });\n}\n\nexport function mapArgsSchemaError(\n expected: VariableSpec,\n found: VariableSpec,\n message: string,\n path: readonly string[]\n) {\n const expectedKeys = Object.keys(expected).sort();\n const foundKeys = Object.keys(found).sort();\n\n if (expectedKeys.join() !== foundKeys.join()) {\n return {\n kind: \"variable_mismatch\" as const,\n path,\n expected,\n found,\n message,\n };\n }\n\n for (const [name, type] of Object.entries(expected)) {\n const foundType = found[name];\n if (foundType !== undefined && foundType !== type) {\n return {\n kind: \"variable_type_mismatch\" as const,\n path,\n variable: name,\n expected: type,\n found: foundType as VariableType,\n message,\n };\n }\n }\n\n return {\n kind: \"variable_mismatch\" as const,\n path,\n expected,\n found,\n message,\n };\n}\n","import { z } from \"zod\";\nimport type { VariableSpec } from \"../icu/extract-variables.js\";\nimport { createArgsSchema, variableTypeSchema } from \"./create-args-schema.js\";\nimport type { DictionarySpec, NormalizedDictionary, ParsedKeyEntry } from \"./types.js\";\n\nconst parsedLocaleEntrySchema = z.object({\n template: z.string(),\n args: z.record(z.string(), variableTypeSchema),\n});\n\nconst parsedKeyEntrySchema = z.object({\n locales: z.record(z.string(), parsedLocaleEntrySchema),\n mergedArgs: z.record(z.string(), variableTypeSchema),\n});\n\nfunction createKeyDictionarySchema(\n argsByKey: Readonly<Record<string, VariableSpec>>\n): z.ZodType<Record<string, ParsedKeyEntry>> {\n const keySchemas = Object.fromEntries(\n Object.entries(argsByKey).map(([key, expectedArgs]) => [\n key,\n parsedKeyEntrySchema.extend({\n mergedArgs: createArgsSchema(expectedArgs),\n }),\n ])\n );\n\n return z.object(keySchemas);\n}\n\nexport function createNormalizedDictionarySchema(\n spec: DictionarySpec\n): z.ZodType<NormalizedDictionary> {\n if (spec.mode === \"single\") {\n return z.object({\n mode: z.literal(\"single\"),\n keys: createKeyDictionarySchema(spec.argsByKey),\n }) as z.ZodType<NormalizedDictionary>;\n }\n\n const namespaceSchemas = Object.fromEntries(\n Object.entries(spec.argsByKey).map(([namespace, argsByKey]) => [\n namespace,\n createKeyDictionarySchema(argsByKey),\n ])\n );\n\n return z.object({\n mode: z.literal(\"multi\"),\n namespaces: z.object(namespaceSchemas),\n }) as z.ZodType<NormalizedDictionary>;\n}\n","import type { ZodError } from \"zod\";\nimport { mapArgsSchemaError } from \"./create-args-schema.js\";\nimport { createNormalizedDictionarySchema } from \"./create-normalized-schema.js\";\nimport type {\n DictionarySpec,\n NormalizedDictionary,\n ValidationIssue,\n ValidationResult,\n VariableSpec,\n} from \"./types.js\";\n\nfunction getExpectedArgs(spec: DictionarySpec, path: readonly string[]): VariableSpec | undefined {\n if (spec.mode === \"single\") {\n const key = path[path.length - 1];\n if (typeof key !== \"string\") {\n return undefined;\n }\n return spec.argsByKey[key];\n }\n\n const namespace = path[0];\n const key = path[path.length - 1];\n if (typeof namespace !== \"string\" || typeof key !== \"string\") {\n return undefined;\n }\n\n return spec.argsByKey[namespace]?.[key];\n}\n\nfunction getFoundArgs(\n normalized: NormalizedDictionary,\n path: readonly string[]\n): VariableSpec | undefined {\n if (normalized.mode === \"single\") {\n const key = path[path.length - 1];\n if (typeof key !== \"string\") {\n return undefined;\n }\n return normalized.keys[key]?.mergedArgs;\n }\n\n const namespace = path[0];\n const key = path[path.length - 1];\n if (typeof namespace !== \"string\" || typeof key !== \"string\") {\n return undefined;\n }\n\n return normalized.namespaces[namespace]?.[key]?.mergedArgs;\n}\n\nfunction mapZodError(\n error: ZodError,\n spec: DictionarySpec,\n normalized: NormalizedDictionary\n): ValidationIssue[] {\n return error.issues.map((issue) => {\n const path = issue.path.map(String);\n\n if (path.includes(\"mergedArgs\")) {\n const keyPath = path.slice(0, path.indexOf(\"mergedArgs\"));\n const expected = getExpectedArgs(spec, keyPath);\n const found = getFoundArgs(normalized, keyPath);\n\n if (expected && found) {\n return mapArgsSchemaError(expected, found, issue.message, keyPath);\n }\n }\n\n return {\n kind: \"invalid_input\" as const,\n message: path.length > 0 ? `${path.join(\".\")}: ${issue.message}` : issue.message,\n };\n });\n}\n\nexport function validateNormalizedDictionary(\n normalized: NormalizedDictionary,\n spec: DictionarySpec\n): ValidationResult<NormalizedDictionary> {\n const schema = createNormalizedDictionarySchema(spec);\n const result = schema.safeParse(normalized);\n\n if (result.success) {\n return { ok: true, data: result.data };\n }\n\n return {\n ok: false,\n issues: mapZodError(result.error, spec, normalized),\n };\n}\n","import type { ValidationIssue, ValidationResult } from \"./types.js\";\n\nfunction issueMessage(issue: ValidationIssue): string {\n switch (issue.kind) {\n case \"missing_key\":\n return `Missing required key at ${issue.path.join(\".\")}`;\n case \"invalid_input\":\n case \"invalid_locale_value\":\n case \"icu_syntax_error\":\n case \"locale_args_mismatch\":\n case \"variable_mismatch\":\n case \"variable_type_mismatch\":\n return issue.message;\n }\n}\n\nexport function formatIssues(issues: readonly ValidationIssue[]): string {\n return issues\n .map((issue) => {\n if (\"path\" in issue && issue.path.length > 0) {\n return `[${issue.path.join(\".\")}] ${issue.kind}: ${issueMessage(issue)}`;\n }\n return `${issue.kind}: ${issueMessage(issue)}`;\n })\n .join(\"\\n\");\n}\n\nexport class DictionaryValidationError extends Error {\n constructor(public readonly issues: readonly ValidationIssue[]) {\n super(formatIssues(issues));\n this.name = \"DictionaryValidationError\";\n }\n}\n\nexport function assertValidDictionary<T>(\n result: ValidationResult<T>\n): asserts result is { ok: true; data: T } {\n if (!result.ok) {\n throw new DictionaryValidationError(result.issues);\n }\n}\n","import { normalizeDictionary } from \"./normalize.js\";\nimport { toDictionary, toNamespaceDictionary } from \"./to-dictionary.js\";\nimport type { DictionarySpec, NormalizedDictionary, ValidationResult } from \"./types.js\";\nimport { validateNormalizedDictionary } from \"./validate-normalized.js\";\n\nexport function validateExternalDictionary<TSchema>(\n input: unknown,\n spec: DictionarySpec\n): ValidationResult<TSchema> {\n const step1 = normalizeDictionary(input, spec);\n if (!step1.ok) {\n return step1;\n }\n\n const step2 = validateNormalizedDictionary(step1.data, spec);\n if (!step2.ok) {\n return step2;\n }\n\n return { ok: true, data: toDictionary(step2.data) as TSchema };\n}\n\nexport function validateExternalNamespace<TNamespaceSchema>(\n namespace: string,\n input: unknown,\n spec: DictionarySpec\n): ValidationResult<TNamespaceSchema> {\n if (spec.mode !== \"multi\") {\n return {\n ok: false,\n issues: [\n {\n kind: \"invalid_input\",\n message: \"validateExternalNamespace requires multi-mode dictionary spec\",\n },\n ],\n };\n }\n\n const wrapped = { [namespace]: input };\n const namespaceSpec: DictionarySpec = {\n mode: \"multi\",\n requiredKeys: {\n [namespace]: spec.requiredKeys[namespace] ?? [],\n },\n argsByKey: {\n [namespace]: spec.argsByKey[namespace] ?? {},\n },\n };\n\n const step1 = normalizeDictionary(wrapped, namespaceSpec);\n if (!step1.ok) {\n return step1;\n }\n\n const step2 = validateNormalizedDictionary(step1.data, namespaceSpec);\n if (!step2.ok) {\n return step2;\n }\n\n return {\n ok: true,\n data: toNamespaceDictionary(step2.data, namespace) as TNamespaceSchema,\n };\n}\n\nexport { normalizeDictionary, validateNormalizedDictionary, toDictionary, toNamespaceDictionary };\nexport { createArgsSchema } from \"./create-args-schema.js\";\nexport { createNormalizedDictionarySchema } from \"./create-normalized-schema.js\";\nexport { DictionaryValidationError, assertValidDictionary, formatIssues } from \"./errors.js\";\nexport type {\n DictionarySpec,\n NormalizedDictionary,\n NormalizedKeyDictionary,\n NormalizedMultiDictionary,\n ParsedKeyEntry,\n ParsedLocaleEntry,\n ValidationIssue,\n ValidationResult,\n VariableSpec,\n VariableType,\n} from \"./types.js\";\n\nexport type { ParseTemplateResult } from \"../icu/parse-template.js\";\nexport { parseTemplate } from \"../icu/parse-template.js\";\nexport {\n extractVariables,\n mergeVariableSpecs,\n variableSpecsEqual,\n} from \"../icu/extract-variables.js\";\n"]}
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "@xndrjs/i18n",
3
+ "version": "0.2.0-alpha.0",
4
+ "description": "Compiler-first, type-safe ICU MessageFormat i18n with runtime dictionary override from external sources.",
5
+ "private": false,
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/xndrjs/toolkit.git",
10
+ "directory": "packages/i18n"
11
+ },
12
+ "type": "module",
13
+ "bin": {
14
+ "xndrjs-i18n-codegen": "./bin/codegen.mjs",
15
+ "xndrjs-i18n-setup": "./bin/setup.mjs"
16
+ },
17
+ "types": "./dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js",
22
+ "default": "./dist/index.js"
23
+ },
24
+ "./validation": {
25
+ "types": "./dist/validation/index.d.ts",
26
+ "import": "./dist/validation/index.js",
27
+ "default": "./dist/validation/index.js"
28
+ }
29
+ },
30
+ "files": [
31
+ "dist",
32
+ "bin",
33
+ "src"
34
+ ],
35
+ "engines": {
36
+ "node": ">=18"
37
+ },
38
+ "dependencies": {
39
+ "@formatjs/icu-messageformat-parser": "^3.5.12",
40
+ "intl-messageformat": "^11.2.9"
41
+ },
42
+ "peerDependencies": {
43
+ "tsx": ">=4",
44
+ "zod": "^4.0.0"
45
+ },
46
+ "peerDependenciesMeta": {
47
+ "zod": {
48
+ "optional": true
49
+ }
50
+ },
51
+ "devDependencies": {
52
+ "tsup": "^8.5.1",
53
+ "tsx": "^4.22.4",
54
+ "vitest": "^4.1.0",
55
+ "zod": "^4.3.6"
56
+ },
57
+ "scripts": {
58
+ "build": "tsup",
59
+ "pack": "pnpm run build && mkdir -p artifacts && npm pack --pack-destination artifacts",
60
+ "lint": "eslint .",
61
+ "lint:fix": "eslint . --fix",
62
+ "test": "vitest run",
63
+ "typecheck": "tsc --noEmit"
64
+ }
65
+ }