@xndrjs/i18n 0.5.0 → 0.6.0-alpha.1
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 +67 -35
- package/dist/codegen/index.d.ts +5 -3
- package/dist/codegen/index.js +15 -2
- package/dist/codegen/index.js.map +1 -1
- package/package.json +1 -1
- package/src/codegen/codegen-config-schema.ts +27 -1
- package/src/codegen/config.test.ts +79 -1
- package/src/codegen/config.ts +10 -1
- package/src/codegen/delivery-artifacts.test.ts +24 -0
- package/src/codegen/delivery-artifacts.ts +29 -0
- package/src/codegen/emit/dictionary-file.test.ts +32 -0
- package/src/codegen/emit/dictionary-file.ts +6 -2
- package/src/codegen/emit/dictionary-schema-file.ts +2 -2
- package/src/codegen/emit/namespace-loaders-file.test.ts +53 -1
- package/src/codegen/emit/namespace-loaders-file.ts +95 -7
- package/src/codegen/emit/types-file.test.ts +5 -0
- package/src/codegen/emit/types-file.ts +19 -6
- package/src/codegen/generate-i18n-types.test.ts +82 -56
- package/src/codegen/generate-i18n-types.ts +15 -4
- package/src/codegen-config/index.ts +1 -0
|
@@ -30,6 +30,38 @@ describe("formatDictionaryFile", () => {
|
|
|
30
30
|
expect(output).not.toContain("defaultDictionaryFor");
|
|
31
31
|
});
|
|
32
32
|
|
|
33
|
+
it("emits an empty module when all namespaces are lazy in split mode (multi)", () => {
|
|
34
|
+
const output = formatDictionaryFile({
|
|
35
|
+
isSingle: false,
|
|
36
|
+
hasLazy: true,
|
|
37
|
+
entries: [
|
|
38
|
+
{ namespace: "default", filePath: "src/i18n/translations/default.json" },
|
|
39
|
+
{ namespace: "billing", filePath: "src/i18n/translations/billing.json" },
|
|
40
|
+
],
|
|
41
|
+
eagerEntries: [],
|
|
42
|
+
projectRoot,
|
|
43
|
+
dictionaryOutputPath,
|
|
44
|
+
typesOutputPath,
|
|
45
|
+
schemaTypeName: "AppSchema",
|
|
46
|
+
localeTypeName: "AppLocale",
|
|
47
|
+
importExtension: "none",
|
|
48
|
+
delivery: "split-by-locale",
|
|
49
|
+
requestLocales: ["en", "it"],
|
|
50
|
+
splitPathsByNamespace: {
|
|
51
|
+
default: {
|
|
52
|
+
en: "src/i18n/generated/translations/default.en.json",
|
|
53
|
+
it: "src/i18n/generated/translations/default.it.json",
|
|
54
|
+
},
|
|
55
|
+
billing: {
|
|
56
|
+
en: "src/i18n/generated/translations/billing.en.json",
|
|
57
|
+
it: "src/i18n/generated/translations/billing.it.json",
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
expect(output).toBeNull();
|
|
63
|
+
});
|
|
64
|
+
|
|
33
65
|
it("emits defaultDictionaryFor with per-locale imports in split mode (multi)", () => {
|
|
34
66
|
const output = formatDictionaryFile({
|
|
35
67
|
isSingle: false,
|
|
@@ -67,7 +67,7 @@ function toPartitionSuffix(paramName: string): string {
|
|
|
67
67
|
function formatPartitionedDictionaryFile(
|
|
68
68
|
options: DictionaryFileOptions,
|
|
69
69
|
{ partitionKeys, paramName, paramTypeName }: PartitionedDictionaryParams
|
|
70
|
-
): string {
|
|
70
|
+
): string | null {
|
|
71
71
|
const {
|
|
72
72
|
isSingle,
|
|
73
73
|
hasLazy,
|
|
@@ -86,6 +86,10 @@ function formatPartitionedDictionaryFile(
|
|
|
86
86
|
const dictionaryTypeName = hasLazy ? "InitialSchema" : schemaTypeName;
|
|
87
87
|
const schemaTypeImport = hasLazy ? `, ${schemaTypeName}` : "";
|
|
88
88
|
|
|
89
|
+
if (eagerEntries.length === 0) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
|
|
89
93
|
const imports = eagerEntries
|
|
90
94
|
.flatMap((entry) =>
|
|
91
95
|
partitionKeys.map((partitionKey) => {
|
|
@@ -164,7 +168,7 @@ function formatPartitionedDictionaryFile(
|
|
|
164
168
|
* Builds `dictionary.generated.ts` for the configured delivery mode:
|
|
165
169
|
* canonical (single bundled JSON per namespace), split-by-locale, or custom areas.
|
|
166
170
|
*/
|
|
167
|
-
export function formatDictionaryFile(options: DictionaryFileOptions): string {
|
|
171
|
+
export function formatDictionaryFile(options: DictionaryFileOptions): string | null {
|
|
168
172
|
const delivery = options.delivery ?? "canonical";
|
|
169
173
|
if (delivery === "split-by-locale") {
|
|
170
174
|
return formatPartitionedDictionaryFile(options, {
|
|
@@ -81,14 +81,14 @@ export function formatDictionarySchemaFile(
|
|
|
81
81
|
const typesImport = toRelativeModuleImport(typesModule, importExtension);
|
|
82
82
|
const namespaceImport = isSingle
|
|
83
83
|
? ""
|
|
84
|
-
: ` validateExternalNamespace as
|
|
84
|
+
: ` validateExternalNamespace as validateExternalNamespaceCore,\n`;
|
|
85
85
|
const namespaceValidator = isSingle
|
|
86
86
|
? ""
|
|
87
87
|
: `export function validateExternalNamespace<NS extends keyof ${schemaTypeName}>(\n` +
|
|
88
88
|
` namespace: NS,\n` +
|
|
89
89
|
` input: unknown,\n` +
|
|
90
90
|
`) {\n` +
|
|
91
|
-
` return
|
|
91
|
+
` return validateExternalNamespaceCore<${schemaTypeName}[NS]>(\n` +
|
|
92
92
|
` namespace as string,\n` +
|
|
93
93
|
` input,\n` +
|
|
94
94
|
` DICTIONARY_SPEC,\n` +
|
|
@@ -17,7 +17,10 @@ describe("formatNamespaceLoadersFile", () => {
|
|
|
17
17
|
},
|
|
18
18
|
],
|
|
19
19
|
schemaTypeName: "AppSchema",
|
|
20
|
+
paramsTypeName: "AppParams",
|
|
20
21
|
localeTypeName: "AppLocale",
|
|
22
|
+
localeFallbackConstName: "LOCALE_FALLBACK",
|
|
23
|
+
hasLocaleFallback: false,
|
|
21
24
|
typesModule: "i18n-types.generated",
|
|
22
25
|
importExtension: "none",
|
|
23
26
|
projectRoot,
|
|
@@ -29,6 +32,7 @@ describe("formatNamespaceLoadersFile", () => {
|
|
|
29
32
|
"billing: () => import('./translations/billing.json').then((m) => m.default),"
|
|
30
33
|
);
|
|
31
34
|
expect(output).not.toContain("AppLocale");
|
|
35
|
+
expect(output).not.toContain("ensureNamespacesLoadedForLocale");
|
|
32
36
|
});
|
|
33
37
|
|
|
34
38
|
it("emits ns(locale) loaders in split mode", () => {
|
|
@@ -40,6 +44,11 @@ describe("formatNamespaceLoadersFile", () => {
|
|
|
40
44
|
filePath: "src/i18n/translations/billing.json",
|
|
41
45
|
absolutePath: path.join(projectRoot, "src/i18n/translations/billing.json"),
|
|
42
46
|
},
|
|
47
|
+
{
|
|
48
|
+
namespace: "default",
|
|
49
|
+
filePath: "src/i18n/translations/default.json",
|
|
50
|
+
absolutePath: path.join(projectRoot, "src/i18n/translations/default.json"),
|
|
51
|
+
},
|
|
43
52
|
{
|
|
44
53
|
namespace: "user",
|
|
45
54
|
filePath: "src/i18n/translations/user.json",
|
|
@@ -47,10 +56,14 @@ describe("formatNamespaceLoadersFile", () => {
|
|
|
47
56
|
},
|
|
48
57
|
],
|
|
49
58
|
schemaTypeName: "AppSchema",
|
|
59
|
+
paramsTypeName: "AppParams",
|
|
50
60
|
localeTypeName: "AppLocale",
|
|
61
|
+
localeFallbackConstName: "LOCALE_FALLBACK",
|
|
62
|
+
hasLocaleFallback: true,
|
|
51
63
|
typesModule: "i18n-types.generated",
|
|
52
64
|
importExtension: "none",
|
|
53
65
|
projectRoot,
|
|
66
|
+
isSingle: false,
|
|
54
67
|
delivery: "split-by-locale",
|
|
55
68
|
requestLocales: ["en", "it", "de-CH"],
|
|
56
69
|
splitPathsByNamespace: {
|
|
@@ -59,6 +72,11 @@ describe("formatNamespaceLoadersFile", () => {
|
|
|
59
72
|
it: "src/i18n/generated/translations/billing.it.json",
|
|
60
73
|
"de-CH": "src/i18n/generated/translations/billing.de-CH.json",
|
|
61
74
|
},
|
|
75
|
+
default: {
|
|
76
|
+
en: "src/i18n/generated/translations/default.en.json",
|
|
77
|
+
it: "src/i18n/generated/translations/default.it.json",
|
|
78
|
+
"de-CH": "src/i18n/generated/translations/default.de-CH.json",
|
|
79
|
+
},
|
|
62
80
|
user: {
|
|
63
81
|
en: "src/i18n/generated/translations/user.en.json",
|
|
64
82
|
it: "src/i18n/generated/translations/user.it.json",
|
|
@@ -72,12 +90,21 @@ describe("formatNamespaceLoadersFile", () => {
|
|
|
72
90
|
expect(output).toContain('case "en":');
|
|
73
91
|
expect(output).toContain('case "it":');
|
|
74
92
|
expect(output).toContain('case "de-CH":');
|
|
93
|
+
expect(output).toContain(
|
|
94
|
+
'throw new Error(`[i18n] No translation artifact for namespace "billing" and locale "${String(locale)}".`);'
|
|
95
|
+
);
|
|
75
96
|
expect(output).toContain(
|
|
76
97
|
"return import('./generated/translations/billing.en.json').then((m) => m.default);"
|
|
77
98
|
);
|
|
78
99
|
expect(output).toContain("user: (locale) => {");
|
|
79
100
|
expect(output).not.toContain("billing: {");
|
|
80
101
|
expect(output).not.toContain("import('./translations/billing.json')");
|
|
102
|
+
expect(output).toContain("export async function ensureNamespacesLoadedForLocale(");
|
|
103
|
+
expect(output).toContain("i18n: I18nMultiInstance,");
|
|
104
|
+
expect(output).toContain(
|
|
105
|
+
'namespaces: readonly LazyNamespace[] = ["billing", "default", "user"] as const,'
|
|
106
|
+
);
|
|
107
|
+
expect(output.match(/from '\.\/i18n-types\.generated'/g)?.length).toBe(1);
|
|
81
108
|
});
|
|
82
109
|
|
|
83
110
|
it("throws when a split path is missing", () => {
|
|
@@ -92,7 +119,10 @@ describe("formatNamespaceLoadersFile", () => {
|
|
|
92
119
|
},
|
|
93
120
|
],
|
|
94
121
|
schemaTypeName: "AppSchema",
|
|
122
|
+
paramsTypeName: "AppParams",
|
|
95
123
|
localeTypeName: "AppLocale",
|
|
124
|
+
localeFallbackConstName: "LOCALE_FALLBACK",
|
|
125
|
+
hasLocaleFallback: false,
|
|
96
126
|
typesModule: "i18n-types.generated",
|
|
97
127
|
importExtension: "none",
|
|
98
128
|
projectRoot,
|
|
@@ -116,12 +146,21 @@ describe("formatNamespaceLoadersFile", () => {
|
|
|
116
146
|
filePath: "src/i18n/translations/billing.json",
|
|
117
147
|
absolutePath: path.join(projectRoot, "src/i18n/translations/billing.json"),
|
|
118
148
|
},
|
|
149
|
+
{
|
|
150
|
+
namespace: "default",
|
|
151
|
+
filePath: "src/i18n/translations/default.json",
|
|
152
|
+
absolutePath: path.join(projectRoot, "src/i18n/translations/default.json"),
|
|
153
|
+
},
|
|
119
154
|
],
|
|
120
155
|
schemaTypeName: "AppSchema",
|
|
156
|
+
paramsTypeName: "AppParams",
|
|
121
157
|
localeTypeName: "AppLocale",
|
|
158
|
+
localeFallbackConstName: "LOCALE_FALLBACK",
|
|
159
|
+
hasLocaleFallback: true,
|
|
122
160
|
typesModule: "i18n-types.generated",
|
|
123
161
|
importExtension: "none",
|
|
124
162
|
projectRoot,
|
|
163
|
+
isSingle: false,
|
|
125
164
|
delivery: "custom",
|
|
126
165
|
deliveryAreaTypeName: "AppDeliveryArea",
|
|
127
166
|
deliveryAreaNames: ["eu", "us"],
|
|
@@ -130,6 +169,10 @@ describe("formatNamespaceLoadersFile", () => {
|
|
|
130
169
|
eu: "src/i18n/generated/translations/billing.eu.json",
|
|
131
170
|
us: "src/i18n/generated/translations/billing.us.json",
|
|
132
171
|
},
|
|
172
|
+
default: {
|
|
173
|
+
eu: "src/i18n/generated/translations/default.eu.json",
|
|
174
|
+
us: "src/i18n/generated/translations/default.us.json",
|
|
175
|
+
},
|
|
133
176
|
},
|
|
134
177
|
});
|
|
135
178
|
|
|
@@ -139,11 +182,17 @@ describe("formatNamespaceLoadersFile", () => {
|
|
|
139
182
|
expect(output).toContain("billing: (area) => {");
|
|
140
183
|
expect(output).toContain('case "eu":');
|
|
141
184
|
expect(output).toContain('case "us":');
|
|
185
|
+
expect(output).toContain(
|
|
186
|
+
'throw new Error(`[i18n] No translation artifact for namespace "billing" and area "${String(area)}".`);'
|
|
187
|
+
);
|
|
142
188
|
expect(output).toContain(
|
|
143
189
|
"return import('./generated/translations/billing.eu.json').then((m) => m.default);"
|
|
144
190
|
);
|
|
145
|
-
expect(output).not.toContain("AppLocale");
|
|
146
191
|
expect(output).not.toContain("import('./translations/billing.json')");
|
|
192
|
+
expect(output).toContain("export async function ensureNamespacesLoadedForArea(");
|
|
193
|
+
expect(output).toContain(
|
|
194
|
+
'namespaces: readonly LazyNamespace[] = ["billing", "default"] as const,'
|
|
195
|
+
);
|
|
147
196
|
});
|
|
148
197
|
|
|
149
198
|
it("throws when a custom delivery split path is missing", () => {
|
|
@@ -158,7 +207,10 @@ describe("formatNamespaceLoadersFile", () => {
|
|
|
158
207
|
},
|
|
159
208
|
],
|
|
160
209
|
schemaTypeName: "AppSchema",
|
|
210
|
+
paramsTypeName: "AppParams",
|
|
161
211
|
localeTypeName: "AppLocale",
|
|
212
|
+
localeFallbackConstName: "LOCALE_FALLBACK",
|
|
213
|
+
hasLocaleFallback: false,
|
|
162
214
|
typesModule: "i18n-types.generated",
|
|
163
215
|
importExtension: "none",
|
|
164
216
|
projectRoot,
|
|
@@ -11,10 +11,14 @@ export interface NamespaceLoadersFileOptions {
|
|
|
11
11
|
loadersOutputPath: string;
|
|
12
12
|
lazyEntries: (NamespaceEntry & { absolutePath: string })[];
|
|
13
13
|
schemaTypeName: string;
|
|
14
|
+
paramsTypeName: string;
|
|
14
15
|
localeTypeName: string;
|
|
16
|
+
localeFallbackConstName: string;
|
|
17
|
+
hasLocaleFallback: boolean;
|
|
15
18
|
typesModule: string;
|
|
16
19
|
importExtension: ImportExtension;
|
|
17
20
|
projectRoot: string;
|
|
21
|
+
isSingle?: boolean;
|
|
18
22
|
delivery?: DeliveryMode;
|
|
19
23
|
splitPathsByNamespace?: Record<string, Record<string, string>>;
|
|
20
24
|
requestLocales?: readonly string[];
|
|
@@ -26,28 +30,108 @@ interface PartitionedNamespaceLoadersParams {
|
|
|
26
30
|
partitionKeys: readonly string[];
|
|
27
31
|
paramName: string;
|
|
28
32
|
paramTypeName: string;
|
|
33
|
+
loadNamespacesFunctionName: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function formatI18nMultiInstanceType(options: NamespaceLoadersFileOptions): string {
|
|
37
|
+
const {
|
|
38
|
+
schemaTypeName,
|
|
39
|
+
paramsTypeName,
|
|
40
|
+
localeTypeName,
|
|
41
|
+
localeFallbackConstName,
|
|
42
|
+
hasLocaleFallback,
|
|
43
|
+
} = options;
|
|
44
|
+
|
|
45
|
+
const typeArgs = hasLocaleFallback
|
|
46
|
+
? `${schemaTypeName}, ${paramsTypeName}, ${localeTypeName}, typeof ${localeFallbackConstName}`
|
|
47
|
+
: `${schemaTypeName}, ${paramsTypeName}`;
|
|
48
|
+
|
|
49
|
+
return `IcuTranslationProviderMulti<${typeArgs}>`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function formatDefaultNamespacesLiteral(lazyEntries: NamespaceEntry[]): string {
|
|
53
|
+
return [...lazyEntries]
|
|
54
|
+
.map((entry) => entry.namespace)
|
|
55
|
+
.sort()
|
|
56
|
+
.map((namespace) => JSON.stringify(namespace))
|
|
57
|
+
.join(", ");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function formatLoadNamespacesHelper(
|
|
61
|
+
options: NamespaceLoadersFileOptions,
|
|
62
|
+
{ paramName, paramTypeName, loadNamespacesFunctionName }: PartitionedNamespaceLoadersParams
|
|
63
|
+
): string {
|
|
64
|
+
const { lazyEntries } = options;
|
|
65
|
+
const defaultNamespaces = formatDefaultNamespacesLiteral(lazyEntries);
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
`\ntype I18nMultiInstance = ${formatI18nMultiInstanceType(options)};\n\n` +
|
|
69
|
+
`export async function ${loadNamespacesFunctionName}(\n` +
|
|
70
|
+
` i18n: I18nMultiInstance,\n` +
|
|
71
|
+
` ${paramName}: ${paramTypeName},\n` +
|
|
72
|
+
` namespaces: readonly LazyNamespace[] = [${defaultNamespaces}] as const,\n` +
|
|
73
|
+
`): Promise<void> {\n` +
|
|
74
|
+
` await Promise.all(\n` +
|
|
75
|
+
` namespaces.map(async (namespace) => {\n` +
|
|
76
|
+
` i18n.setNamespace(namespace, await namespaceLoaders[namespace](${paramName}));\n` +
|
|
77
|
+
` }),\n` +
|
|
78
|
+
` );\n` +
|
|
79
|
+
`}\n`
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function formatPartitionedTypesImport(
|
|
84
|
+
options: NamespaceLoadersFileOptions,
|
|
85
|
+
paramTypeName: string
|
|
86
|
+
): string {
|
|
87
|
+
const {
|
|
88
|
+
schemaTypeName,
|
|
89
|
+
paramsTypeName,
|
|
90
|
+
localeTypeName,
|
|
91
|
+
localeFallbackConstName,
|
|
92
|
+
hasLocaleFallback,
|
|
93
|
+
typesModule,
|
|
94
|
+
importExtension,
|
|
95
|
+
isSingle,
|
|
96
|
+
} = options;
|
|
97
|
+
|
|
98
|
+
if (isSingle) {
|
|
99
|
+
return `import type { ${schemaTypeName}, LazyNamespace, ${paramTypeName} } from '${toRelativeModuleImport(typesModule, importExtension)}';\n\n`;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const fallbackImport = hasLocaleFallback ? `${localeFallbackConstName}, ` : "";
|
|
103
|
+
const paramTypeImport = paramTypeName === localeTypeName ? "" : `, type ${paramTypeName}`;
|
|
104
|
+
return (
|
|
105
|
+
`import { IcuTranslationProviderMulti } from '@xndrjs/i18n';\n` +
|
|
106
|
+
`import { ${fallbackImport}type ${localeTypeName}, type ${paramsTypeName}, type ${schemaTypeName}, type LazyNamespace${paramTypeImport} } from '${toRelativeModuleImport(typesModule, importExtension)}';\n\n`
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function formatSwitchDefaultCase(namespace: string, paramName: string): string {
|
|
111
|
+
return (
|
|
112
|
+
` default:\n` +
|
|
113
|
+
` throw new Error(\`[i18n] No translation artifact for namespace ${JSON.stringify(namespace)} and ${paramName} "\${String(${paramName})}".\`);\n`
|
|
114
|
+
);
|
|
29
115
|
}
|
|
30
116
|
|
|
31
117
|
/**
|
|
32
|
-
* Emits lazy loaders for split-by-locale and custom delivery.
|
|
33
118
|
* Each namespace gets a function that dynamic-imports the JSON for the given
|
|
34
119
|
* partition key (locale or area) via a switch.
|
|
35
120
|
*/
|
|
36
121
|
function formatPartitionedNamespaceLoadersFile(
|
|
37
122
|
options: NamespaceLoadersFileOptions,
|
|
38
|
-
|
|
123
|
+
params: PartitionedNamespaceLoadersParams
|
|
39
124
|
): string {
|
|
125
|
+
const { partitionKeys, paramName, paramTypeName } = params;
|
|
40
126
|
const {
|
|
41
127
|
loadersOutputPath,
|
|
42
128
|
lazyEntries,
|
|
43
129
|
schemaTypeName,
|
|
44
|
-
typesModule,
|
|
45
|
-
importExtension,
|
|
46
130
|
projectRoot,
|
|
47
131
|
splitPathsByNamespace = {},
|
|
48
132
|
} = options;
|
|
49
133
|
|
|
50
|
-
const typesImport =
|
|
134
|
+
const typesImport = formatPartitionedTypesImport(options, paramTypeName);
|
|
51
135
|
const loaderEntries = lazyEntries
|
|
52
136
|
.map((entry) => {
|
|
53
137
|
const switchCases = partitionKeys
|
|
@@ -72,6 +156,7 @@ function formatPartitionedNamespaceLoadersFile(
|
|
|
72
156
|
return (
|
|
73
157
|
` ${entry.namespace}: (${paramName}) => {\n` +
|
|
74
158
|
` switch (${paramName}) {\n${switchCases}\n` +
|
|
159
|
+
`${formatSwitchDefaultCase(entry.namespace, paramName)}` +
|
|
75
160
|
` }\n` +
|
|
76
161
|
` },`
|
|
77
162
|
);
|
|
@@ -80,10 +165,11 @@ function formatPartitionedNamespaceLoadersFile(
|
|
|
80
165
|
|
|
81
166
|
return (
|
|
82
167
|
`${GENERATED_FILE_BANNER}` +
|
|
83
|
-
|
|
168
|
+
typesImport +
|
|
84
169
|
`export const namespaceLoaders: {\n` +
|
|
85
170
|
` [K in LazyNamespace]: (${paramName}: ${paramTypeName}) => Promise<${schemaTypeName}[K]>;\n` +
|
|
86
|
-
`} = {\n${loaderEntries}\n};\n`
|
|
171
|
+
`} = {\n${loaderEntries}\n};\n` +
|
|
172
|
+
(options.isSingle ? "" : formatLoadNamespacesHelper(options, params))
|
|
87
173
|
);
|
|
88
174
|
}
|
|
89
175
|
|
|
@@ -118,6 +204,7 @@ export function formatNamespaceLoadersFile(options: NamespaceLoadersFileOptions)
|
|
|
118
204
|
partitionKeys: options.requestLocales ?? [],
|
|
119
205
|
paramName: "locale",
|
|
120
206
|
paramTypeName: options.localeTypeName,
|
|
207
|
+
loadNamespacesFunctionName: "ensureNamespacesLoadedForLocale",
|
|
121
208
|
});
|
|
122
209
|
}
|
|
123
210
|
if (delivery === "custom") {
|
|
@@ -128,6 +215,7 @@ export function formatNamespaceLoadersFile(options: NamespaceLoadersFileOptions)
|
|
|
128
215
|
partitionKeys: options.deliveryAreaNames ?? [],
|
|
129
216
|
paramName: "area",
|
|
130
217
|
paramTypeName: options.deliveryAreaTypeName,
|
|
218
|
+
loadNamespacesFunctionName: "ensureNamespacesLoadedForArea",
|
|
131
219
|
});
|
|
132
220
|
}
|
|
133
221
|
return formatCanonicalNamespaceLoadersFile(options);
|
|
@@ -105,6 +105,11 @@ describe("formatTypesFile", () => {
|
|
|
105
105
|
|
|
106
106
|
expect(output).toContain("export type AppLocale = 'en-US' | 'fr' | 'it';");
|
|
107
107
|
expect(output).toContain("export type AppDeliveryArea = 'eu' | 'us';");
|
|
108
|
+
expect(output).toContain("export const DELIVERY_ARTIFACTS = {");
|
|
109
|
+
expect(output).toContain('"eu": ["fr", "it"] as const');
|
|
110
|
+
expect(output).toContain('"us": ["en-US"] as const');
|
|
111
|
+
expect(output).toContain("} as const satisfies Record<AppDeliveryArea, readonly AppLocale[]>;");
|
|
112
|
+
expect(output).toContain("export type AppDeliveryArtifacts = typeof DELIVERY_ARTIFACTS;");
|
|
108
113
|
expect(output).toContain("export const LOCALE_DELIVERY_AREA = {");
|
|
109
114
|
expect(output).toContain('"it": "eu"');
|
|
110
115
|
expect(output).toContain('"en-US": "us"');
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
formatDeliveryArtifactsBlock,
|
|
3
|
+
formatLocaleDeliveryAreaBlock,
|
|
4
|
+
type DeliveryArtifactsMap,
|
|
5
|
+
} from "../delivery-artifacts.js";
|
|
2
6
|
import { formatLocaleFallbackBlock } from "../locale-fallback.js";
|
|
3
7
|
import { GENERATED_FILE_BANNER } from "../paths.js";
|
|
4
8
|
import type { NamespaceEntry } from "../types.js";
|
|
@@ -12,10 +16,13 @@ export function formatLazyTypesBlock(
|
|
|
12
16
|
lazyEntries: NamespaceEntry[],
|
|
13
17
|
schemaTypeName: string
|
|
14
18
|
): string {
|
|
15
|
-
const loadOnInitUnion =
|
|
16
|
-
.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
const loadOnInitUnion =
|
|
20
|
+
loadOnInitSet.size > 0
|
|
21
|
+
? [...loadOnInitSet]
|
|
22
|
+
.sort()
|
|
23
|
+
.map((namespace) => `'${namespace}'`)
|
|
24
|
+
.join(" | ")
|
|
25
|
+
: "never";
|
|
19
26
|
const lazyUnion = lazyEntries.map((entry) => `'${entry.namespace}'`).join(" | ");
|
|
20
27
|
|
|
21
28
|
return (
|
|
@@ -87,7 +94,13 @@ export function formatTypesFile(options: TypesFileOptions): string {
|
|
|
87
94
|
deliveryAreaTypeName && deliveryAreaUnion
|
|
88
95
|
? `export type ${deliveryAreaTypeName} = ${deliveryAreaUnion};\n\n` +
|
|
89
96
|
(deliveryArtifacts
|
|
90
|
-
?
|
|
97
|
+
? formatDeliveryArtifactsBlock(
|
|
98
|
+
deliveryArtifacts,
|
|
99
|
+
"DELIVERY_ARTIFACTS",
|
|
100
|
+
localeTypeName,
|
|
101
|
+
deliveryAreaTypeName
|
|
102
|
+
) +
|
|
103
|
+
formatLocaleDeliveryAreaBlock(
|
|
91
104
|
deliveryArtifacts,
|
|
92
105
|
localeDeliveryAreaConstName,
|
|
93
106
|
localeTypeName,
|