@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.
Files changed (57) hide show
  1. package/README.md +156 -29
  2. package/dist/codegen/index.d.ts +85 -0
  3. package/dist/codegen/index.js +181 -0
  4. package/dist/codegen/index.js.map +1 -0
  5. package/dist/index.d.ts +34 -5
  6. package/dist/index.js +175 -74
  7. package/dist/index.js.map +1 -1
  8. package/dist/validation/index.d.ts +4 -0
  9. package/dist/validation/index.js.map +1 -1
  10. package/package.json +6 -1
  11. package/src/IcuTranslationProviderMulti.test.ts +47 -0
  12. package/src/IcuTranslationProviderMulti.ts +41 -61
  13. package/src/IcuTranslationProviderSingle.test.ts +67 -0
  14. package/src/IcuTranslationProviderSingle.ts +27 -51
  15. package/src/audit/audit-dictionaries.ts +4 -1
  16. package/src/audit/run-audit.test.ts +35 -1
  17. package/src/audit/run-audit.ts +15 -7
  18. package/src/codegen/codegen-config-schema.ts +68 -1
  19. package/src/codegen/config.test.ts +174 -39
  20. package/src/codegen/config.ts +14 -5
  21. package/src/codegen/constants.ts +8 -0
  22. package/src/codegen/delivery-artifacts.test.ts +142 -0
  23. package/src/codegen/delivery-artifacts.ts +124 -0
  24. package/src/codegen/emit/dictionary-file.test.ts +190 -0
  25. package/src/codegen/emit/dictionary-file.ts +163 -0
  26. package/src/codegen/emit/dictionary-schema-file.ts +5 -0
  27. package/src/codegen/emit/instance-file.ts +114 -28
  28. package/src/codegen/emit/namespace-loaders-file.test.ts +176 -0
  29. package/src/codegen/emit/namespace-loaders-file.ts +114 -6
  30. package/src/codegen/emit/types-file.test.ts +114 -0
  31. package/src/codegen/emit/types-file.ts +48 -11
  32. package/src/codegen/generate-i18n-types.test.ts +754 -16
  33. package/src/codegen/generate-i18n-types.ts +111 -47
  34. package/src/codegen/icu-analysis.ts +9 -2
  35. package/src/codegen/locale-fallback.ts +19 -10
  36. package/src/codegen/locale-policy.ts +4 -0
  37. package/src/codegen/paths.ts +9 -5
  38. package/src/codegen/project-locales-set-namespace.test.ts +5 -5
  39. package/src/codegen/read-dictionary.test.ts +474 -2
  40. package/src/codegen/read-dictionary.ts +164 -15
  41. package/src/codegen/write-file-if-changed.test.ts +42 -0
  42. package/src/codegen/write-file-if-changed.ts +20 -0
  43. package/src/codegen-config/build-config.ts +34 -0
  44. package/src/codegen-config/codegen-config.test.ts +32 -0
  45. package/src/codegen-config/index.ts +21 -0
  46. package/src/codegen-config/write-config.ts +8 -0
  47. package/src/deep-freeze.test.ts +13 -0
  48. package/src/deep-freeze.ts +5 -0
  49. package/src/format-core.ts +91 -0
  50. package/src/index.ts +8 -2
  51. package/src/project-locales.test.ts +129 -10
  52. package/src/project-locales.ts +90 -3
  53. package/src/setup/setup-i18n.test.ts +1 -1
  54. package/src/setup/setup-i18n.ts +6 -30
  55. package/src/types.ts +19 -4
  56. package/src/validation/normalize.ts +4 -0
  57. /package/src/{setup → codegen-config}/type-names.ts +0 -0
@@ -1,6 +1,11 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
- import { loadConfig, resolveLoadOnInit, resolveNamespaces } from "./config.js";
3
+ import {
4
+ loadConfig,
5
+ resolveDeliveryOutputDir,
6
+ resolveLoadOnInit,
7
+ resolveNamespaces,
8
+ } from "./config.js";
4
9
  import { formatDictionaryFile } from "./emit/dictionary-file.js";
5
10
  import {
6
11
  formatDictionarySchemaFile,
@@ -10,11 +15,18 @@ import { formatInstanceFile } from "./emit/instance-file.js";
10
15
  import { formatNamespaceLoadersFile } from "./emit/namespace-loaders-file.js";
11
16
  import { formatTypesFile } from "./emit/types-file.js";
12
17
  import { analyzeDictionaries } from "./icu-analysis.js";
13
- import { collectRequestLocales, validateCodegenLocaleFallback } from "./locale-fallback.js";
18
+ import { getDeliveryArtifactsIssues } from "./delivery-artifacts.js";
19
+ import { collectRequestLocales, getCodegenLocaleFallbackIssues } from "./locale-fallback.js";
14
20
  import { enrichLocaleFallback } from "./locale-policy.js";
15
- import { fail, resolveImportExtension, toModuleBasename } from "./paths.js";
21
+ import { reportCodegenIssues, resolveImportExtension, toModuleBasename } from "./paths.js";
16
22
  import { prepareDictionaryEntries } from "./read-dictionary.js";
23
+ import { writeFileIfChanged } from "./write-file-if-changed.js";
17
24
 
25
+ /**
26
+ * Codegen CLI entry point. Pipeline:
27
+ * config → analyze (ICU + types input) → validate locale/delivery policy →
28
+ * prepare artifacts (YAML→JSON, split) → resolve lazy/eager → emit generated .ts files.
29
+ */
18
30
  function main() {
19
31
  const configArgIndex = process.argv.indexOf("--config");
20
32
  const configPath = path.resolve(
@@ -24,41 +36,29 @@ function main() {
24
36
  const projectRoot = path.dirname(configPath);
25
37
 
26
38
  if (!fs.existsSync(configPath)) {
27
- fail(`[Codegen Error] Config file not found: ${configPath}`);
39
+ throw new Error(`[Codegen Error] Config file not found: ${configPath}`);
28
40
  }
29
41
 
30
42
  const config = loadConfig(configPath);
31
43
  const sourceEntries = resolveNamespaces(config);
32
- const generatedDirRelative = path.dirname(config.typesOutput);
33
- let resolvedEntries;
34
- let compiledFiles: string[];
35
-
36
- try {
37
- const prepared = prepareDictionaryEntries(projectRoot, sourceEntries, generatedDirRelative);
38
- resolvedEntries = prepared.resolvedEntries;
39
- compiledFiles = prepared.compiledFiles;
40
- } catch (error) {
41
- const message = error instanceof Error ? error.message : String(error);
42
- fail(message);
43
- }
44
-
45
- const entries = resolvedEntries;
44
+ const deliveryOutputRelative = resolveDeliveryOutputDir(config);
45
+ const delivery = config.delivery ?? "canonical";
46
46
  const isSingle = Boolean(config.dictionary);
47
- const { loadOnInitSet, lazyEntries, hasLazy } = resolveLoadOnInit(config, entries, isSingle);
48
-
49
- const typesOutputPath = path.resolve(projectRoot, config.typesOutput);
50
- const dictionaryOutputPath = path.resolve(projectRoot, config.dictionaryOutput);
51
- const instanceOutputPath = path.resolve(projectRoot, config.instanceOutput);
52
47
 
53
- const analysisResult = analyzeDictionaries(projectRoot, entries);
48
+ const analysisResult = analyzeDictionaries(projectRoot, sourceEntries);
54
49
  if (!analysisResult.ok) {
55
50
  process.exit(1);
56
51
  }
57
52
 
58
- const { paramsByNamespace, argsSpecByNamespace, locales } = analysisResult.analysis;
53
+ const { paramsByNamespace, argsSpecByNamespace, locales, dictionariesByNamespace } =
54
+ analysisResult.analysis;
59
55
 
60
- if (config.localeFallback && validateCodegenLocaleFallback(config.localeFallback, locales)) {
61
- process.exit(1);
56
+ if (config.localeFallback) {
57
+ const localeFallbackIssues = getCodegenLocaleFallbackIssues(config.localeFallback, locales);
58
+ if (localeFallbackIssues.length > 0) {
59
+ reportCodegenIssues(localeFallbackIssues);
60
+ process.exit(1);
61
+ }
62
62
  }
63
63
 
64
64
  const paramsTypeName = config.paramsTypeName;
@@ -68,14 +68,55 @@ function main() {
68
68
  const localeFallbackTypeName = `${localeTypeName}Fallback`;
69
69
  const factoryName = config.factoryName ?? "createI18n";
70
70
  const importExtension = resolveImportExtension(config);
71
- const typesModule = toModuleBasename(typesOutputPath);
72
71
 
73
72
  const requestLocales = collectRequestLocales(locales, config.localeFallback);
74
- const requestLocaleUnion = [...requestLocales]
73
+ const requestLocalesList = [...requestLocales].sort();
74
+
75
+ if (delivery === "custom" && config.deliveryArtifacts) {
76
+ const deliveryArtifactsIssues = getDeliveryArtifactsIssues(
77
+ config.deliveryArtifacts,
78
+ requestLocales
79
+ );
80
+ if (deliveryArtifactsIssues.length > 0) {
81
+ reportCodegenIssues(deliveryArtifactsIssues);
82
+ process.exit(1);
83
+ }
84
+ }
85
+
86
+ const {
87
+ resolvedEntries: entries,
88
+ splitPathsByNamespace,
89
+ compiledFiles,
90
+ } = prepareDictionaryEntries(projectRoot, sourceEntries, deliveryOutputRelative, {
91
+ dictionariesByNamespace,
92
+ delivery,
93
+ localeFallback: config.localeFallback,
94
+ requestLocales: delivery === "split-by-locale" ? requestLocalesList : undefined,
95
+ deliveryArtifacts: delivery === "custom" ? config.deliveryArtifacts : undefined,
96
+ });
97
+
98
+ const { loadOnInitSet, lazyEntries, hasLazy } = resolveLoadOnInit(config, entries, isSingle);
99
+
100
+ const typesOutputPath = path.resolve(projectRoot, config.typesOutput);
101
+ const dictionaryOutputPath = path.resolve(projectRoot, config.dictionaryOutput);
102
+ const instanceOutputPath = path.resolve(projectRoot, config.instanceOutput);
103
+ const typesModule = toModuleBasename(typesOutputPath);
104
+
105
+ const requestLocaleUnion = requestLocalesList
75
106
  .sort()
76
107
  .map((locale) => `'${locale}'`)
77
108
  .join(" | ");
78
109
 
110
+ const deliveryAreaNames =
111
+ delivery === "custom" && config.deliveryArtifacts
112
+ ? Object.keys(config.deliveryArtifacts).sort()
113
+ : undefined;
114
+ const deliveryAreaTypeName =
115
+ delivery === "custom" ? schemaTypeName.replace(/Schema$/, "DeliveryArea") : undefined;
116
+ const deliveryAreaUnion = deliveryAreaNames
117
+ ? deliveryAreaNames.map((area) => `'${area}'`).join(" | ")
118
+ : undefined;
119
+
79
120
  const eagerEntries = hasLazy
80
121
  ? entries.filter((entry) => loadOnInitSet.has(entry.namespace))
81
122
  : entries;
@@ -97,6 +138,15 @@ function main() {
97
138
  localeFallback: localeFallbackForEmit,
98
139
  paramsByNamespace,
99
140
  requestLocaleUnion,
141
+ ...(deliveryAreaTypeName && deliveryAreaUnion
142
+ ? {
143
+ deliveryAreaTypeName,
144
+ deliveryAreaUnion,
145
+ ...(delivery === "custom" && config.deliveryArtifacts
146
+ ? { deliveryArtifacts: config.deliveryArtifacts }
147
+ : {}),
148
+ }
149
+ : {}),
100
150
  hasLazy,
101
151
  loadOnInitSet,
102
152
  lazyEntries,
@@ -111,7 +161,14 @@ function main() {
111
161
  dictionaryOutputPath,
112
162
  typesOutputPath,
113
163
  schemaTypeName,
164
+ localeTypeName,
114
165
  importExtension,
166
+ delivery,
167
+ splitPathsByNamespace,
168
+ ...(delivery === "split-by-locale" ? { requestLocales: requestLocalesList } : {}),
169
+ ...(delivery === "custom" && deliveryAreaTypeName && deliveryAreaNames
170
+ ? { deliveryAreaTypeName, deliveryAreaNames }
171
+ : {}),
115
172
  });
116
173
 
117
174
  const instanceContent = formatInstanceFile({
@@ -127,16 +184,12 @@ function main() {
127
184
  hasLocaleType: Boolean(requestLocaleUnion),
128
185
  namespaceNames: entries.map((entry) => entry.namespace),
129
186
  importExtension,
187
+ delivery,
130
188
  });
131
189
 
132
- fs.mkdirSync(path.dirname(typesOutputPath), { recursive: true });
133
- fs.writeFileSync(typesOutputPath, typesContent);
134
-
135
- fs.mkdirSync(path.dirname(dictionaryOutputPath), { recursive: true });
136
- fs.writeFileSync(dictionaryOutputPath, dictionaryContent);
137
-
138
- fs.mkdirSync(path.dirname(instanceOutputPath), { recursive: true });
139
- fs.writeFileSync(instanceOutputPath, instanceContent);
190
+ writeFileIfChanged(typesOutputPath, typesContent);
191
+ writeFileIfChanged(dictionaryOutputPath, dictionaryContent);
192
+ writeFileIfChanged(instanceOutputPath, instanceContent);
140
193
 
141
194
  const generatedFiles = [
142
195
  path.relative(projectRoot, typesOutputPath),
@@ -155,8 +208,7 @@ function main() {
155
208
  importExtension
156
209
  );
157
210
 
158
- fs.mkdirSync(path.dirname(dictionarySchemaOutputPath), { recursive: true });
159
- fs.writeFileSync(dictionarySchemaOutputPath, dictionarySchemaContent);
211
+ writeFileIfChanged(dictionarySchemaOutputPath, dictionarySchemaContent);
160
212
  generatedFiles.push(path.relative(projectRoot, dictionarySchemaOutputPath));
161
213
  }
162
214
 
@@ -170,16 +222,23 @@ function main() {
170
222
  ...entry,
171
223
  absolutePath: path.resolve(projectRoot, entry.filePath),
172
224
  }));
173
- const namespaceLoadersContent = formatNamespaceLoadersFile(
174
- namespaceLoadersOutputPath,
175
- lazyEntriesWithPaths,
225
+ const namespaceLoadersContent = formatNamespaceLoadersFile({
226
+ loadersOutputPath: namespaceLoadersOutputPath,
227
+ lazyEntries: lazyEntriesWithPaths,
176
228
  schemaTypeName,
229
+ localeTypeName,
177
230
  typesModule,
178
- importExtension
179
- );
231
+ importExtension,
232
+ projectRoot,
233
+ delivery,
234
+ splitPathsByNamespace,
235
+ ...(delivery === "split-by-locale" ? { requestLocales: requestLocalesList } : {}),
236
+ ...(delivery === "custom" && deliveryAreaTypeName && deliveryAreaNames
237
+ ? { deliveryAreaTypeName, deliveryAreaNames }
238
+ : {}),
239
+ });
180
240
 
181
- fs.mkdirSync(path.dirname(namespaceLoadersOutputPath), { recursive: true });
182
- fs.writeFileSync(namespaceLoadersOutputPath, namespaceLoadersContent);
241
+ writeFileIfChanged(namespaceLoadersOutputPath, namespaceLoadersContent);
183
242
  generatedFiles.push(path.relative(projectRoot, namespaceLoadersOutputPath));
184
243
  }
185
244
 
@@ -189,4 +248,9 @@ function main() {
189
248
  }
190
249
  }
191
250
 
192
- main();
251
+ try {
252
+ main();
253
+ } catch (error) {
254
+ console.error(error instanceof Error ? error.message : String(error));
255
+ process.exit(1);
256
+ }
@@ -6,7 +6,7 @@ import {
6
6
  mergeVariableMetaAcrossLocales,
7
7
  type VariableSpec,
8
8
  } from "../icu/extract-variables.js";
9
- import type { NamespaceEntry } from "./types.js";
9
+ import type { DictionaryJson, NamespaceEntry } from "./types.js";
10
10
  import { readDictionaryFile } from "./read-dictionary.js";
11
11
 
12
12
  export function paramsTypeForVariables(variables: VariableSpec): string {
@@ -26,8 +26,13 @@ export interface DictionaryAnalysis {
26
26
  paramsByNamespace: Record<string, Record<string, string>>;
27
27
  argsSpecByNamespace: Record<string, Record<string, VariableSpec>>;
28
28
  locales: Set<string>;
29
+ dictionariesByNamespace: Record<string, DictionaryJson>;
29
30
  }
30
31
 
32
+ /**
33
+ * Phase 1 of codegen: read source dictionaries, validate ICU syntax, infer param types.
34
+ * Output feeds type emission, optional `DICTIONARY_SPEC`, and `prepareDictionaryEntries`.
35
+ */
31
36
  export function analyzeDictionaries(
32
37
  projectRoot: string,
33
38
  entries: NamespaceEntry[]
@@ -35,6 +40,7 @@ export function analyzeDictionaries(
35
40
  const paramsByNamespace: Record<string, Record<string, string>> = {};
36
41
  const argsSpecByNamespace: Record<string, Record<string, VariableSpec>> = {};
37
42
  const locales = new Set<string>();
43
+ const dictionariesByNamespace: Record<string, DictionaryJson> = {};
38
44
  let hasErrors = false;
39
45
 
40
46
  for (const entry of entries) {
@@ -49,6 +55,7 @@ export function analyzeDictionaries(
49
55
  }
50
56
 
51
57
  const dictionary = readDictionaryFile(absolutePath);
58
+ dictionariesByNamespace[entry.namespace] = dictionary;
52
59
  paramsByNamespace[entry.namespace] = {};
53
60
  argsSpecByNamespace[entry.namespace] = {};
54
61
 
@@ -98,6 +105,6 @@ export function analyzeDictionaries(
98
105
 
99
106
  return {
100
107
  ok: true,
101
- analysis: { paramsByNamespace, argsSpecByNamespace, locales },
108
+ analysis: { paramsByNamespace, argsSpecByNamespace, locales, dictionariesByNamespace },
102
109
  };
103
110
  }
@@ -1,5 +1,9 @@
1
1
  import { validateLocaleFallback } from "../resolve-locale.js";
2
2
 
3
+ /**
4
+ * Union of locales found in dictionaries plus every locale referenced by `localeFallback`.
5
+ * Drives split-by-locale partitioning and the generated locale union type.
6
+ */
3
7
  export function collectRequestLocales(
4
8
  dictionaryLocales: Set<string>,
5
9
  fallback?: Record<string, string | null>
@@ -19,30 +23,35 @@ export function collectRequestLocales(
19
23
  return all;
20
24
  }
21
25
 
22
- export function validateCodegenLocaleFallback(
26
+ export type LocaleFallbackIssue = {
27
+ path: (string | number)[];
28
+ message: string;
29
+ };
30
+
31
+ /** Pre-emit validation gate for `localeFallback` config against discovered dictionary locales. */
32
+ export function getCodegenLocaleFallbackIssues(
23
33
  fallback: Record<string, string | null>,
24
34
  dictionaryLocales: Set<string>
25
- ): boolean {
26
- let hasErrors = false;
35
+ ): LocaleFallbackIssue[] {
36
+ const issues: LocaleFallbackIssue[] = [];
27
37
 
28
38
  try {
29
39
  validateLocaleFallback(fallback);
30
40
  } catch (error) {
31
41
  const message = error instanceof Error ? error.message : String(error);
32
- console.error(`[Codegen Error] ${message}`);
33
- hasErrors = true;
42
+ issues.push({ path: ["localeFallback"], message });
34
43
  }
35
44
 
36
45
  for (const [locale, target] of Object.entries(fallback)) {
37
46
  if (target !== null && !(target in fallback) && !dictionaryLocales.has(target)) {
38
- console.error(
39
- `[Codegen Error] localeFallback: "${locale}" points to "${target}" which is not defined in the fallback map or dictionary locales`
40
- );
41
- hasErrors = true;
47
+ issues.push({
48
+ path: ["localeFallback", locale],
49
+ message: `localeFallback: "${locale}" points to "${target}" which is not defined in the fallback map or dictionary locales`,
50
+ });
42
51
  }
43
52
  }
44
53
 
45
- return hasErrors;
54
+ return issues;
46
55
  }
47
56
 
48
57
  export function formatLocaleFallbackBlock(
@@ -7,6 +7,10 @@ export function buildRequiredLocales(
7
7
  return [...collectRequestLocales(dictionaryLocales, configFallback)].sort();
8
8
  }
9
9
 
10
+ /**
11
+ * Completes `localeFallback` with explicit `null` entries for every request locale,
12
+ * producing a stable map emitted into `i18n-types.generated.ts`.
13
+ */
10
14
  export function enrichLocaleFallback(
11
15
  dictionaryLocales: Set<string>,
12
16
  configFallback: Record<string, string | null>
@@ -6,10 +6,10 @@ import { CodegenConfig } from "./codegen-config-schema.js";
6
6
  export const GENERATED_FILE_BANNER = "// Automatically generated code. Do not edit manually.\n";
7
7
  export const DEFAULT_IMPORT_EXTENSION: ImportExtension = "none";
8
8
 
9
- export function fail(message: string): never {
10
- console.error(message);
11
- process.exit(1);
12
- throw new Error(message);
9
+ export function reportCodegenIssues(issues: readonly { message: string }[]): void {
10
+ for (const issue of issues) {
11
+ console.error(`[Codegen Error] ${issue.message}`);
12
+ }
13
13
  }
14
14
 
15
15
  export function toImportPath(fromFile: string, toFile: string): string {
@@ -27,7 +27,7 @@ export function resolveImportExtension(
27
27
  ): ImportExtension {
28
28
  const extension = config.importExtension ?? DEFAULT_IMPORT_EXTENSION;
29
29
  if (!SUPPORTED_IMPORT_EXTENSIONS.includes(extension)) {
30
- fail(
30
+ throw new Error(
31
31
  `[Codegen Error] importExtension must be "none", ".ts", or ".js", got ${JSON.stringify(extension)}.`
32
32
  );
33
33
  }
@@ -52,3 +52,7 @@ export function toImportIdentifier(namespace: string): string {
52
52
  }
53
53
  return `${safe}Ns`;
54
54
  }
55
+
56
+ export function toLocaleObjectKey(locale: string): string {
57
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(locale) ? locale : JSON.stringify(locale);
58
+ }
@@ -95,7 +95,7 @@ function writeTscProject(tempDir: string) {
95
95
  );
96
96
  }
97
97
 
98
- describe("codegen projectLocales + setNamespace", () => {
98
+ describe("codegen projectDictionaryLocales + setNamespace", () => {
99
99
  describe("generated instance output", () => {
100
100
  let tempDir: string;
101
101
 
@@ -112,7 +112,7 @@ describe("codegen projectLocales + setNamespace", () => {
112
112
  const factory = readFileSync(join(tempDir, "src/i18n/instance.generated.ts"), "utf8");
113
113
  expect(factory).toContain('dictionary: AppSchema["billing"]');
114
114
  expect(factory).toContain(
115
- "projectNamespacesLocalesCore(dictionary, locales, LOCALE_FALLBACK)"
115
+ "projectDictionaryLocalesCore(dictionary, locales, LOCALE_FALLBACK)"
116
116
  );
117
117
  });
118
118
 
@@ -138,14 +138,14 @@ describe("codegen projectLocales + setNamespace", () => {
138
138
  expect(tsc.status, `${tsc.stdout}\n${tsc.stderr}`).toBe(0);
139
139
  });
140
140
 
141
- it("passes tsc when replacing the full schema with projectLocales before setAll", () => {
141
+ it("passes tsc when replacing the full schema with projectDictionaryLocales before setAll", () => {
142
142
  tempDir = mkdtempSync(join(tmpdir(), "xndrjs-i18n-project-locales-"));
143
143
  setupMultiCodegenFixture(tempDir);
144
144
 
145
145
  writeFileSync(
146
146
  join(tempDir, "src/hydrate-all.ts"),
147
147
  [
148
- `import { createI18n, projectLocales } from "./i18n/instance.generated.js";`,
148
+ `import { createI18n, projectDictionaryLocales } from "./i18n/instance.generated.js";`,
149
149
  `import { defaultDictionary } from "./i18n/dictionary.generated.js";`,
150
150
  `import type { AppSchema } from "./i18n/i18n-types.generated.js";`,
151
151
  `import billingDictionary from "./i18n/translations/billing.json";`,
@@ -157,7 +157,7 @@ describe("codegen projectLocales + setNamespace", () => {
157
157
  `} satisfies AppSchema;`,
158
158
  ``,
159
159
  `const i18n = createI18n(defaultDictionary);`,
160
- `i18n.setAll(projectLocales(fullDictionary, ["en"]));`,
160
+ `i18n.setAll(projectDictionaryLocales(fullDictionary, ["en"]));`,
161
161
  ].join("\n")
162
162
  );
163
163