@xndrjs/i18n 0.8.0 → 0.8.2-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 (94) hide show
  1. package/README.md +1 -2
  2. package/dist/cli/audit.js +739 -0
  3. package/dist/cli/audit.js.map +1 -0
  4. package/dist/cli/codegen.js +1471 -0
  5. package/dist/cli/codegen.js.map +1 -0
  6. package/dist/cli/setup.js +148 -0
  7. package/dist/cli/setup.js.map +1 -0
  8. package/dist/codegen/index.js +43 -40
  9. package/dist/codegen/index.js.map +1 -1
  10. package/dist/index.d.ts +20 -1
  11. package/dist/index.js +56 -10
  12. package/dist/index.js.map +1 -1
  13. package/package.json +6 -9
  14. package/bin/audit.mjs +0 -14
  15. package/bin/codegen.mjs +0 -17
  16. package/bin/setup.mjs +0 -14
  17. package/src/IcuTranslationProviderMulti.test.ts +0 -215
  18. package/src/IcuTranslationProviderMulti.ts +0 -176
  19. package/src/audit/audit-dictionaries.test.ts +0 -134
  20. package/src/audit/audit-dictionaries.ts +0 -178
  21. package/src/audit/run-audit.test.ts +0 -169
  22. package/src/audit/run-audit.ts +0 -94
  23. package/src/builder-load-registry.ts +0 -39
  24. package/src/builder-loaders.ts +0 -15
  25. package/src/builder-types.test.ts +0 -49
  26. package/src/builder-types.ts +0 -24
  27. package/src/builder.test.ts +0 -260
  28. package/src/builder.ts +0 -10
  29. package/src/codegen/codegen-config-schema.ts +0 -156
  30. package/src/codegen/config.test.ts +0 -231
  31. package/src/codegen/config.ts +0 -42
  32. package/src/codegen/constants.ts +0 -9
  33. package/src/codegen/delivery-artifacts.test.ts +0 -167
  34. package/src/codegen/delivery-artifacts.ts +0 -154
  35. package/src/codegen/dictionary-spec-contract.test.ts +0 -28
  36. package/src/codegen/dictionary-spec-contract.ts +0 -138
  37. package/src/codegen/emit/dictionary-schema-file.ts +0 -113
  38. package/src/codegen/emit/instance-file.test.ts +0 -71
  39. package/src/codegen/emit/instance-file.ts +0 -257
  40. package/src/codegen/emit/namespace-loaders-file.test.ts +0 -251
  41. package/src/codegen/emit/namespace-loaders-file.ts +0 -229
  42. package/src/codegen/emit/types-file.test.ts +0 -96
  43. package/src/codegen/emit/types-file.ts +0 -142
  44. package/src/codegen/fixtures/billing-namespace.json +0 -6
  45. package/src/codegen/generate-i18n-types.test.ts +0 -1137
  46. package/src/codegen/generate-i18n-types.ts +0 -20
  47. package/src/codegen/icu-analysis.ts +0 -110
  48. package/src/codegen/locale-fallback.ts +0 -73
  49. package/src/codegen/locale-policy.test.ts +0 -35
  50. package/src/codegen/locale-policy.ts +0 -30
  51. package/src/codegen/paths.ts +0 -44
  52. package/src/codegen/project-locales-set-namespace.test.ts +0 -134
  53. package/src/codegen/read-dictionary.test.ts +0 -594
  54. package/src/codegen/read-dictionary.ts +0 -260
  55. package/src/codegen/regenerate-namespaces.ts +0 -180
  56. package/src/codegen/run-codegen.test.ts +0 -230
  57. package/src/codegen/run-codegen.ts +0 -252
  58. package/src/codegen/types.ts +0 -10
  59. package/src/codegen/write-file-if-changed.test.ts +0 -42
  60. package/src/codegen/write-file-if-changed.ts +0 -20
  61. package/src/codegen-config/build-config.ts +0 -15
  62. package/src/codegen-config/codegen-config.test.ts +0 -36
  63. package/src/codegen-config/index.ts +0 -37
  64. package/src/codegen-config/type-names.ts +0 -20
  65. package/src/codegen-config/write-config.ts +0 -8
  66. package/src/engine.ts +0 -47
  67. package/src/fetch-artifact.ts +0 -16
  68. package/src/format-core.ts +0 -91
  69. package/src/i18n-handle.ts +0 -202
  70. package/src/icu/extract-variables.test.ts +0 -199
  71. package/src/icu/extract-variables.ts +0 -227
  72. package/src/icu/parse-template.ts +0 -31
  73. package/src/index.ts +0 -58
  74. package/src/project-locales.test.ts +0 -280
  75. package/src/project-locales.ts +0 -211
  76. package/src/resolve-locale.test.ts +0 -91
  77. package/src/resolve-locale.ts +0 -88
  78. package/src/scope-multi.ts +0 -105
  79. package/src/scope-types.ts +0 -35
  80. package/src/scope.test.ts +0 -172
  81. package/src/serialized-state.test.ts +0 -114
  82. package/src/serialized-state.ts +0 -28
  83. package/src/setup/setup-i18n.test.ts +0 -85
  84. package/src/setup/setup-i18n.ts +0 -156
  85. package/src/types.ts +0 -65
  86. package/src/validation/create-args-schema.ts +0 -76
  87. package/src/validation/create-normalized-schema.ts +0 -52
  88. package/src/validation/errors.ts +0 -43
  89. package/src/validation/index.ts +0 -202
  90. package/src/validation/normalize.ts +0 -299
  91. package/src/validation/to-dictionary.ts +0 -67
  92. package/src/validation/types.ts +0 -82
  93. package/src/validation/validate-normalized.ts +0 -133
  94. package/src/validation/validation.test.ts +0 -562
@@ -1,229 +0,0 @@
1
- import path from "node:path";
2
- import type { DeliveryMode, LoaderStrategy } from "../codegen-config-schema.js";
3
- import { GENERATED_FILE_BANNER, toImportPath, toRelativeModuleImport } from "../paths.js";
4
- import type { ImportExtension, NamespaceEntry } from "../types.js";
5
-
6
- /**
7
- * Emits the generated `namespace-loaders.generated.ts` module: dynamic `import()`
8
- * or injectable `fetchImpl(resourceId)` loaders, shaped by delivery mode.
9
- */
10
- export interface NamespaceLoadersFileOptions {
11
- loadersOutputPath: string;
12
- lazyEntries: (NamespaceEntry & { absolutePath: string })[];
13
- schemaTypeName: string;
14
- localeTypeName: string;
15
- typesModule: string;
16
- importExtension: ImportExtension;
17
- projectRoot: string;
18
- delivery: DeliveryMode;
19
- splitPathsByNamespace?: Record<string, Record<string, string>>;
20
- requestLocales?: readonly string[];
21
- deliveryAreaTypeName?: string;
22
- deliveryAreaNames?: readonly string[];
23
- loaderStrategy?: LoaderStrategy;
24
- }
25
-
26
- interface PartitionedNamespaceLoadersParams {
27
- partitionKeys: readonly string[];
28
- paramName: string;
29
- paramTypeName: string;
30
- }
31
-
32
- function formatDefaultNamespacesLiteral(lazyEntries: NamespaceEntry[]): string {
33
- return [...lazyEntries]
34
- .map((entry) => entry.namespace)
35
- .sort()
36
- .map((namespace) => JSON.stringify(namespace))
37
- .join(", ");
38
- }
39
-
40
- function formatPartitionedTypesImport(
41
- options: NamespaceLoadersFileOptions,
42
- paramTypeName: string
43
- ): string {
44
- const { schemaTypeName, typesModule, importExtension } = options;
45
- return `import type { ${schemaTypeName}, LazyNamespace, ${paramTypeName} } from '${toRelativeModuleImport(typesModule, importExtension)}';\n\n`;
46
- }
47
-
48
- function formatImportCase(
49
- loadersOutputPath: string,
50
- projectRoot: string,
51
- splitRelativePath: string
52
- ): string {
53
- const importPath = toImportPath(loadersOutputPath, path.resolve(projectRoot, splitRelativePath));
54
- return `return import('${importPath}.json').then((m) => m.default);`;
55
- }
56
-
57
- function indentBlock(text: string, spaces: number): string {
58
- const pad = " ".repeat(spaces);
59
- return text
60
- .split("\n")
61
- .map((line) => (line.length === 0 ? line : `${pad}${line}`))
62
- .join("\n");
63
- }
64
-
65
- function formatImportNamespaceLoaderEntry(options: {
66
- namespace: string;
67
- paramName: string;
68
- partitionKeys: readonly string[];
69
- splitPathsByNamespace: Record<string, Record<string, string>>;
70
- loadersOutputPath: string;
71
- projectRoot: string;
72
- }): string {
73
- const {
74
- namespace,
75
- paramName,
76
- partitionKeys,
77
- splitPathsByNamespace,
78
- loadersOutputPath,
79
- projectRoot,
80
- } = options;
81
-
82
- const caseBodies = partitionKeys.map((partitionKey) => {
83
- const splitRelativePath = splitPathsByNamespace[namespace]?.[partitionKey];
84
- if (!splitRelativePath) {
85
- throw new Error(
86
- `[Codegen Error] Missing split path for namespace "${namespace}", ${paramName} "${partitionKey}".`
87
- );
88
- }
89
- const body = formatImportCase(loadersOutputPath, projectRoot, splitRelativePath);
90
- return [`case ${JSON.stringify(partitionKey)}:`, ` ${body}`].join("\n");
91
- });
92
-
93
- const switchBody = [
94
- ...caseBodies,
95
- `default:`,
96
- ` throw new Error(\`[i18n] No translation artifact for namespace ${JSON.stringify(namespace)} and ${paramName} "\${String(${paramName})}".\`);`,
97
- ].join("\n");
98
-
99
- const entry = [
100
- `${namespace}: (${paramName}) => {`,
101
- ` switch (${paramName}) {`,
102
- indentBlock(switchBody, 4),
103
- ` }`,
104
- `},`,
105
- ].join("\n");
106
-
107
- return indentBlock(entry, 2);
108
- }
109
-
110
- /** Fetch loaders forward a resource id; URL mapping is left to `fetchImpl`. */
111
- function formatFetchNamespaceLoaderEntry(options: {
112
- namespace: string;
113
- paramName: string;
114
- schemaTypeName: string;
115
- delivery: DeliveryMode;
116
- }): string {
117
- const { namespace, paramName, schemaTypeName, delivery } = options;
118
- const nsLiteral = JSON.stringify(namespace);
119
- const resourceId =
120
- delivery === "custom"
121
- ? `{ locale, namespace: ${nsLiteral}, area }`
122
- : `{ locale, namespace: ${nsLiteral} }`;
123
-
124
- // Custom: partition is area; locale comes from load() context.
125
- // Split-by-locale: partition is locale (second arg unused).
126
- const signature = delivery === "custom" ? `(${paramName}, { locale })` : `(${paramName})`;
127
-
128
- return indentBlock(
129
- `${namespace}: ${signature} =>\n` +
130
- ` fetchImpl(${resourceId}) as Promise<${schemaTypeName}[${nsLiteral}]>,`,
131
- 4
132
- );
133
- }
134
-
135
- function formatPartitionedNamespaceLoadersFile(
136
- options: NamespaceLoadersFileOptions,
137
- params: PartitionedNamespaceLoadersParams
138
- ): string {
139
- const { partitionKeys, paramName, paramTypeName } = params;
140
- const {
141
- loadersOutputPath,
142
- lazyEntries,
143
- schemaTypeName,
144
- projectRoot,
145
- delivery,
146
- splitPathsByNamespace = {},
147
- } = options;
148
- const loaderStrategy = options.loaderStrategy ?? "import";
149
-
150
- const loaderValueType = `${schemaTypeName}[K]`;
151
- const typesImport = formatPartitionedTypesImport(options, paramTypeName);
152
-
153
- if (loaderStrategy === "fetch") {
154
- // Fetch loaders ignore partition-key switches: the resource id is enough for the app.
155
- const fetchLoadersType = `{\n [K in LazyNamespace]: (${
156
- delivery === "custom"
157
- ? `${paramName}: ${paramTypeName}, context: { locale: string }`
158
- : `${paramName}: ${paramTypeName}`
159
- }) => Promise<${loaderValueType}>;\n}`;
160
-
161
- const loaderEntries = lazyEntries
162
- .map((entry) =>
163
- formatFetchNamespaceLoaderEntry({
164
- namespace: entry.namespace,
165
- paramName,
166
- schemaTypeName,
167
- delivery,
168
- })
169
- )
170
- .join("\n");
171
-
172
- return (
173
- `${GENERATED_FILE_BANNER}` +
174
- `import type { FetchArtifact } from '@xndrjs/i18n';\n` +
175
- typesImport +
176
- `export type NamespaceLoaders = ${fetchLoadersType};\n\n` +
177
- `/** Build loaders that resolve artifacts via the injected {@link FetchArtifact} (resource id only). */\n` +
178
- `export function createNamespaceLoaders(fetchImpl: FetchArtifact): NamespaceLoaders {\n` +
179
- ` return {\n${loaderEntries}\n };\n` +
180
- `}\n\n` +
181
- `export const defaultLazyNamespaces = [${formatDefaultNamespacesLiteral(lazyEntries)}] as const;\n`
182
- );
183
- }
184
-
185
- const loaderEntries = lazyEntries
186
- .map((entry) =>
187
- formatImportNamespaceLoaderEntry({
188
- namespace: entry.namespace,
189
- paramName,
190
- partitionKeys,
191
- splitPathsByNamespace,
192
- loadersOutputPath,
193
- projectRoot,
194
- })
195
- )
196
- .join("\n");
197
-
198
- // Import loaders only use the partition key; context is accepted for a uniform NamespaceLoader shape.
199
- const importLoadersType = `{\n [K in LazyNamespace]: (${paramName}: ${paramTypeName}) => Promise<${loaderValueType}>;\n}`;
200
-
201
- return (
202
- `${GENERATED_FILE_BANNER}` +
203
- typesImport +
204
- `export const namespaceLoaders: ${importLoadersType} = {\n${loaderEntries}\n};\n` +
205
- `\n` +
206
- `export const defaultLazyNamespaces = [${formatDefaultNamespacesLiteral(lazyEntries)}] as const;\n`
207
- );
208
- }
209
-
210
- /**
211
- * Builds `namespace-loaders.generated.ts` for split-by-locale or custom delivery areas.
212
- */
213
- export function formatNamespaceLoadersFile(options: NamespaceLoadersFileOptions): string {
214
- if (options.delivery === "split-by-locale") {
215
- return formatPartitionedNamespaceLoadersFile(options, {
216
- partitionKeys: options.requestLocales ?? [],
217
- paramName: "locale",
218
- paramTypeName: options.localeTypeName,
219
- });
220
- }
221
- if (!options.deliveryAreaTypeName) {
222
- throw new Error("[Codegen Error] deliveryAreaTypeName is required for custom delivery.");
223
- }
224
- return formatPartitionedNamespaceLoadersFile(options, {
225
- partitionKeys: options.deliveryAreaNames ?? [],
226
- paramName: "area",
227
- paramTypeName: options.deliveryAreaTypeName,
228
- });
229
- }
@@ -1,96 +0,0 @@
1
- import path from "node:path";
2
- import { describe, expect, it } from "vitest";
3
- import { formatTypesFile } from "./types-file.js";
4
-
5
- const projectRoot = "/project";
6
- const typesOutputPath = path.join(projectRoot, "src/i18n/generated/i18n-types.generated.ts");
7
-
8
- describe("formatTypesFile", () => {
9
- it("emits explicit Partial schema types and lazy aliases", () => {
10
- const output = formatTypesFile({
11
- entries: [
12
- { namespace: "default", filePath: "src/i18n/translations/default.json" },
13
- { namespace: "billing", filePath: "src/i18n/translations/billing.yaml" },
14
- ],
15
- projectRoot,
16
- typesOutputPath,
17
- paramsTypeName: "AppParams",
18
- schemaTypeName: "AppSchema",
19
- localeTypeName: "AppLocale",
20
- localeFallbackConstName: "LOCALE_FALLBACK",
21
- localeFallbackTypeName: "AppLocaleFallback",
22
- paramsByNamespace: {
23
- default: {
24
- login_button: "never",
25
- welcome: "{ name: string }",
26
- },
27
- billing: {
28
- invoice_summary: "{ count: number }",
29
- },
30
- },
31
- requestLocales: ["en", "it"],
32
- lazyEntries: [
33
- { namespace: "default", filePath: "src/i18n/translations/default.json" },
34
- { namespace: "billing", filePath: "src/i18n/translations/billing.yaml" },
35
- ],
36
- });
37
-
38
- expect(output).toContain("login_button: Partial<Record<AppLocale, string>>;");
39
- expect(output).toContain("invoice_summary: Partial<Record<AppLocale, string>>;");
40
- expect(output).toContain('export const AppLocales = ["en", "it"] as const;');
41
- expect(output).toContain("export type AppLocale = (typeof AppLocales)[number];");
42
- expect(output).toContain("export type LazyNamespace = 'default' | 'billing'");
43
- expect(output).toContain("export type InitialSchema = Record<string, never>");
44
- });
45
-
46
- it("emits delivery area type for custom delivery", () => {
47
- const output = formatTypesFile({
48
- entries: [
49
- { namespace: "default", filePath: "src/i18n/translations/default.json" },
50
- { namespace: "billing", filePath: "src/i18n/translations/billing.yaml" },
51
- ],
52
- projectRoot,
53
- typesOutputPath,
54
- paramsTypeName: "AppParams",
55
- schemaTypeName: "AppSchema",
56
- localeTypeName: "AppLocale",
57
- localeFallbackConstName: "LOCALE_FALLBACK",
58
- localeFallbackTypeName: "AppLocaleFallback",
59
- localeFallback: {
60
- "en-US": null,
61
- it: "en-US",
62
- fr: null,
63
- },
64
- paramsByNamespace: {
65
- default: { some_key: "never" },
66
- billing: { invoice_summary: "{ count: number }" },
67
- },
68
- requestLocales: ["en-US", "fr", "it"],
69
- deliveryAreaTypeName: "AppDeliveryArea",
70
- deliveryAreaNames: ["eu", "us"],
71
- deliveryArtifacts: {
72
- eu: ["it", "fr"],
73
- us: ["en-US"],
74
- },
75
- lazyEntries: [
76
- { namespace: "default", filePath: "src/i18n/translations/default.json" },
77
- { namespace: "billing", filePath: "src/i18n/translations/billing.yaml" },
78
- ],
79
- });
80
-
81
- expect(output).toContain('export const AppLocales = ["en-US", "fr", "it"] as const;');
82
- expect(output).toContain("export type AppLocale = (typeof AppLocales)[number];");
83
- expect(output).toContain('export const AppDeliveryAreas = ["eu", "us"] as const;');
84
- expect(output).toContain("export type AppDeliveryArea = (typeof AppDeliveryAreas)[number];");
85
- expect(output).toContain("export const DELIVERY_ARTIFACTS = {");
86
- expect(output).toContain('"eu": ["fr", "it"] as const');
87
- expect(output).toContain('"us": ["en-US"] as const');
88
- expect(output).toContain("} as const satisfies Record<AppDeliveryArea, readonly AppLocale[]>;");
89
- expect(output).toContain("export type AppDeliveryArtifacts = typeof DELIVERY_ARTIFACTS;");
90
- expect(output).toContain("export const LOCALE_DELIVERY_AREA = {");
91
- expect(output).toContain('"it": "eu"');
92
- expect(output).toContain('"en-US": "us"');
93
- expect(output).toContain("} as const satisfies Record<AppLocale, AppDeliveryArea>;");
94
- expect(output).toContain("some_key: Partial<Record<AppLocale, string>>;");
95
- });
96
- });
@@ -1,142 +0,0 @@
1
- import {
2
- formatDeliveryArtifactsBlock,
3
- formatLocaleDeliveryAreaBlock,
4
- type DeliveryArtifactsMap,
5
- } from "../delivery-artifacts.js";
6
- import { formatLocaleFallbackBlock } from "../locale-fallback.js";
7
- import { GENERATED_FILE_BANNER } from "../paths.js";
8
- import type { NamespaceEntry } from "../types.js";
9
-
10
- /**
11
- * Emits lazy-load type aliases. Every namespace is lazy; `InitialSchema` is empty
12
- * (cold start / hydrate via `resources` only).
13
- */
14
- export function formatLazyTypesBlock(lazyEntries: NamespaceEntry[]): string {
15
- const lazyUnion =
16
- lazyEntries.length > 0
17
- ? lazyEntries.map((entry) => `'${entry.namespace}'`).join(" | ")
18
- : "never";
19
-
20
- return (
21
- `export type LazyNamespace = ${lazyUnion};\n` +
22
- `/** Empty cold-start schema — namespaces arrive via \`namespaceLoaders\`. */\n` +
23
- `export type InitialSchema = Record<string, never>;\n\n`
24
- );
25
- }
26
-
27
- export function formatLocaleTemplateType(localeTypeName: string, hasLocaleUnion: boolean): string {
28
- if (!hasLocaleUnion) {
29
- return "Partial<Record<string, string>>";
30
- }
31
- return `Partial<Record<${localeTypeName}, string>>`;
32
- }
33
-
34
- export interface TypesFileOptions {
35
- entries: NamespaceEntry[];
36
- projectRoot: string;
37
- typesOutputPath: string;
38
- paramsTypeName: string;
39
- schemaTypeName: string;
40
- localeTypeName: string;
41
- localeFallbackConstName: string;
42
- localeFallbackTypeName: string;
43
- localeFallback?: Record<string, string | null> | undefined;
44
- paramsByNamespace: Record<string, Record<string, string>>;
45
- /** Sorted request locales — emits `ProjectLocales` const + `ProjectLocale` type. */
46
- requestLocales: readonly string[];
47
- deliveryAreaTypeName?: string;
48
- /** Sorted delivery area names — emits `ProjectDeliveryAreas` const + type. */
49
- deliveryAreaNames?: readonly string[];
50
- deliveryArtifacts?: DeliveryArtifactsMap;
51
- localeDeliveryAreaConstName?: string;
52
- lazyEntries: NamespaceEntry[];
53
- }
54
-
55
- export function formatTypesFile(options: TypesFileOptions): string {
56
- const {
57
- entries,
58
- paramsTypeName,
59
- schemaTypeName,
60
- localeTypeName,
61
- localeFallbackConstName,
62
- localeFallbackTypeName,
63
- localeFallback,
64
- paramsByNamespace,
65
- requestLocales,
66
- deliveryAreaTypeName,
67
- deliveryAreaNames,
68
- deliveryArtifacts,
69
- localeDeliveryAreaConstName = "LOCALE_DELIVERY_AREA",
70
- lazyEntries,
71
- } = options;
72
-
73
- const hasLocaleUnion = requestLocales.length > 0;
74
- const localeTemplateType = formatLocaleTemplateType(localeTypeName, hasLocaleUnion);
75
- const localesConstName = `${localeTypeName}s`;
76
-
77
- const localeBlock = hasLocaleUnion
78
- ? `${localeFallback ? formatLocaleFallbackBlock(localeFallback, localeFallbackConstName, localeFallbackTypeName) : ""}` +
79
- `export const ${localesConstName} = [${requestLocales.map((locale) => JSON.stringify(locale)).join(", ")}] as const;\n` +
80
- `export type ${localeTypeName} = (typeof ${localesConstName})[number];\n\n`
81
- : "";
82
-
83
- const deliveryAreasConstName = deliveryAreaTypeName ? `${deliveryAreaTypeName}s` : undefined;
84
- const deliveryAreaBlock =
85
- deliveryAreaTypeName &&
86
- deliveryAreasConstName &&
87
- deliveryAreaNames &&
88
- deliveryAreaNames.length > 0
89
- ? `export const ${deliveryAreasConstName} = [${deliveryAreaNames.map((area) => JSON.stringify(area)).join(", ")}] as const;\n` +
90
- `export type ${deliveryAreaTypeName} = (typeof ${deliveryAreasConstName})[number];\n\n` +
91
- (deliveryArtifacts
92
- ? formatDeliveryArtifactsBlock(
93
- deliveryArtifacts,
94
- "DELIVERY_ARTIFACTS",
95
- localeTypeName,
96
- deliveryAreaTypeName
97
- ) +
98
- formatLocaleDeliveryAreaBlock(
99
- deliveryArtifacts,
100
- localeDeliveryAreaConstName,
101
- localeTypeName,
102
- deliveryAreaTypeName
103
- )
104
- : "")
105
- : "";
106
-
107
- const namespaceBlocks = entries
108
- .map((entry) => {
109
- const keyTypes = paramsByNamespace[entry.namespace] ?? {};
110
- const lines = Object.entries(keyTypes)
111
- .map(([key, type]) => ` ${key}: ${type};`)
112
- .join("\n");
113
- return ` ${entry.namespace}: {\n${lines}\n };`;
114
- })
115
- .join("\n");
116
-
117
- const paramsBlock = `export type ${paramsTypeName} = {\n${namespaceBlocks}\n};`;
118
-
119
- const schemaLines = entries
120
- .map((entry) => {
121
- const keyTypes = paramsByNamespace[entry.namespace] ?? {};
122
- const lines = Object.keys(keyTypes)
123
- .map((key) => ` ${key}: ${localeTemplateType};`)
124
- .join("\n");
125
- return ` ${entry.namespace}: {\n${lines}\n };`;
126
- })
127
- .join("\n");
128
-
129
- const schemaBlock = `export type ${schemaTypeName} = {\n${schemaLines}\n};`;
130
-
131
- const lazyTypesBlock = formatLazyTypesBlock(lazyEntries);
132
-
133
- return (
134
- `${GENERATED_FILE_BANNER}` +
135
- `export const I18N_MODE = 'multi' as const;\n\n` +
136
- `${localeBlock}` +
137
- `${deliveryAreaBlock}` +
138
- `${paramsBlock}\n\n` +
139
- `${schemaBlock}\n` +
140
- `${lazyTypesBlock}`
141
- );
142
- }
@@ -1,6 +0,0 @@
1
- {
2
- "invoice_summary": {
3
- "en": "You have {count, plural, one {1 invoice} other {{count} invoices}}",
4
- "it": "Hai {count, plural, one {1 fattura} other {{count} fatture}}"
5
- }
6
- }