@zachhandley/ez-i18n 0.1.8 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +81 -8
- package/dist/utils/index.d.ts +4 -2
- package/dist/utils/index.js +4 -2
- package/package.json +1 -1
- package/src/utils/translations.ts +44 -4
- package/src/vite-plugin.ts +77 -11
package/dist/index.js
CHANGED
|
@@ -152,8 +152,28 @@ function toRelativeImport(absolutePath, projectRoot) {
|
|
|
152
152
|
}
|
|
153
153
|
function toGlobPattern(baseDir, projectRoot) {
|
|
154
154
|
const relativePath = path.relative(projectRoot, baseDir).replace(/\\/g, "/");
|
|
155
|
-
|
|
156
|
-
|
|
155
|
+
if (relativePath.startsWith("public/") || relativePath === "public") {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
return `/${relativePath}/**/*.json`;
|
|
159
|
+
}
|
|
160
|
+
function isInPublicDir(filePath, projectRoot) {
|
|
161
|
+
const relativePath = path.relative(projectRoot, filePath).replace(/\\/g, "/");
|
|
162
|
+
return relativePath.startsWith("public/") || relativePath === "public";
|
|
163
|
+
}
|
|
164
|
+
function toPublicUrl(filePath, projectRoot) {
|
|
165
|
+
const relativePath = path.relative(projectRoot, filePath).replace(/\\/g, "/");
|
|
166
|
+
if (relativePath.startsWith("public/")) {
|
|
167
|
+
return "/" + relativePath.slice("public/".length);
|
|
168
|
+
}
|
|
169
|
+
return "/" + relativePath;
|
|
170
|
+
}
|
|
171
|
+
function getLocaleBaseDirForNamespace(localeBaseDir, projectRoot) {
|
|
172
|
+
const relativePath = path.relative(projectRoot, localeBaseDir).replace(/\\/g, "/");
|
|
173
|
+
if (relativePath.startsWith("public/")) {
|
|
174
|
+
return relativePath.slice("public/".length);
|
|
175
|
+
}
|
|
176
|
+
return relativePath;
|
|
157
177
|
}
|
|
158
178
|
function getNamespaceFromPath(filePath, localeDir) {
|
|
159
179
|
const relative2 = path.relative(localeDir, filePath);
|
|
@@ -262,12 +282,14 @@ function vitePlugin(config) {
|
|
|
262
282
|
};
|
|
263
283
|
for (const locale of finalLocales) {
|
|
264
284
|
const files = translations[locale] || [];
|
|
285
|
+
const filesInPublic = files.length > 0 && isInPublicDir(files[0], projectRoot);
|
|
265
286
|
const info = {
|
|
266
287
|
locale,
|
|
267
288
|
files,
|
|
268
|
-
localeBaseDir: localeBaseDirs[locale]
|
|
289
|
+
localeBaseDir: localeBaseDirs[locale],
|
|
290
|
+
isPublic: filesInPublic
|
|
269
291
|
};
|
|
270
|
-
if (isDev && config.translations) {
|
|
292
|
+
if (isDev && config.translations && !filesInPublic) {
|
|
271
293
|
const localeConfig = typeof config.translations === "string" ? path2.join(config.translations, locale) + "/" : config.translations[locale];
|
|
272
294
|
if (localeConfig && typeof localeConfig === "string") {
|
|
273
295
|
const pathType = detectPathType(localeConfig);
|
|
@@ -420,19 +442,43 @@ function generateDevTranslationsModule(translationInfo, projectRoot, pathBasedNa
|
|
|
420
442
|
for (const [locale, info] of translationInfo) {
|
|
421
443
|
if (info.files.length === 0) {
|
|
422
444
|
loaderEntries.push(` ${JSON.stringify(locale)}: async () => ({})`);
|
|
445
|
+
} else if (info.isPublic) {
|
|
446
|
+
if (pathBasedNamespacing && info.localeBaseDir) {
|
|
447
|
+
const localeBaseDirForNs = getLocaleBaseDirForNamespace(info.localeBaseDir, projectRoot);
|
|
448
|
+
const fileEntries = info.files.map((f) => {
|
|
449
|
+
const url = toPublicUrl(f, projectRoot);
|
|
450
|
+
const namespace = getNamespaceFromPath(f, info.localeBaseDir);
|
|
451
|
+
return `{ url: ${JSON.stringify(url)}, namespace: ${JSON.stringify(namespace)} }`;
|
|
452
|
+
});
|
|
453
|
+
loaderEntries.push(` ${JSON.stringify(locale)}: async () => {
|
|
454
|
+
const fileInfos = [${fileEntries.join(", ")}];
|
|
455
|
+
const responses = await Promise.all(fileInfos.map(f => fetch(f.url).then(r => r.json())));
|
|
456
|
+
const wrapped = responses.map((content, i) => __wrapWithNamespace(fileInfos[i].namespace, content));
|
|
457
|
+
return __deepMerge({}, ...wrapped);
|
|
458
|
+
}`);
|
|
459
|
+
} else {
|
|
460
|
+
const urls = info.files.map((f) => toPublicUrl(f, projectRoot));
|
|
461
|
+
loaderEntries.push(` ${JSON.stringify(locale)}: async () => {
|
|
462
|
+
const urls = ${JSON.stringify(urls)};
|
|
463
|
+
const responses = await Promise.all(urls.map(url => fetch(url).then(r => r.json())));
|
|
464
|
+
if (responses.length === 1) return responses[0];
|
|
465
|
+
return __deepMerge({}, ...responses);
|
|
466
|
+
}`);
|
|
467
|
+
}
|
|
423
468
|
} else if (info.globPattern && pathBasedNamespacing && info.localeBaseDir) {
|
|
424
469
|
const varName = `__${locale}Modules`;
|
|
425
|
-
const
|
|
470
|
+
const localeBaseDirForNs = getLocaleBaseDirForNamespace(info.localeBaseDir, projectRoot);
|
|
426
471
|
imports.push(
|
|
427
472
|
`const ${varName} = import.meta.glob(${JSON.stringify(info.globPattern)}, { eager: true, import: 'default' });`
|
|
428
473
|
);
|
|
429
474
|
loaderEntries.push(` ${JSON.stringify(locale)}: async () => {
|
|
430
475
|
const entries = Object.entries(${varName});
|
|
431
476
|
if (entries.length === 0) return {};
|
|
432
|
-
const localeBaseDir = ${JSON.stringify(
|
|
477
|
+
const localeBaseDir = ${JSON.stringify(localeBaseDirForNs)};
|
|
433
478
|
const wrapped = entries.map(([filePath, content]) => {
|
|
434
|
-
// Extract relative path from locale base dir
|
|
435
|
-
const
|
|
479
|
+
// Extract relative path from locale base dir - filePath starts with /
|
|
480
|
+
const normalizedPath = filePath.startsWith('/') ? filePath.slice(1) : filePath;
|
|
481
|
+
const relativePath = normalizedPath.replace(localeBaseDir + '/', '').replace(/\\.json$/i, '');
|
|
436
482
|
const namespace = relativePath.replace(/[\\/]/g, '.').replace(/\\.index$/, '');
|
|
437
483
|
return __wrapWithNamespace(namespace, content);
|
|
438
484
|
});
|
|
@@ -519,6 +565,33 @@ function generateBuildTranslationsModule(translationInfo, projectRoot, pathBased
|
|
|
519
565
|
for (const [locale, info] of translationInfo) {
|
|
520
566
|
if (info.files.length === 0) {
|
|
521
567
|
loaderEntries.push(` ${JSON.stringify(locale)}: async () => ({})`);
|
|
568
|
+
} else if (info.isPublic) {
|
|
569
|
+
needsDeepMerge = info.files.length > 1;
|
|
570
|
+
if (pathBasedNamespacing && info.localeBaseDir) {
|
|
571
|
+
needsNamespaceWrapper = true;
|
|
572
|
+
const fileEntries = info.files.map((f) => {
|
|
573
|
+
const url = toPublicUrl(f, projectRoot);
|
|
574
|
+
const namespace = getNamespaceFromPath(f, info.localeBaseDir);
|
|
575
|
+
return `{ url: ${JSON.stringify(url)}, namespace: ${JSON.stringify(namespace)} }`;
|
|
576
|
+
});
|
|
577
|
+
loaderEntries.push(` ${JSON.stringify(locale)}: async () => {
|
|
578
|
+
const fileInfos = [${fileEntries.join(", ")}];
|
|
579
|
+
const responses = await Promise.all(fileInfos.map(f => fetch(f.url).then(r => r.json())));
|
|
580
|
+
const wrapped = responses.map((content, i) => __wrapWithNamespace(fileInfos[i].namespace, content));
|
|
581
|
+
return __deepMerge({}, ...wrapped);
|
|
582
|
+
}`);
|
|
583
|
+
} else {
|
|
584
|
+
const urls = info.files.map((f) => toPublicUrl(f, projectRoot));
|
|
585
|
+
if (urls.length === 1) {
|
|
586
|
+
loaderEntries.push(` ${JSON.stringify(locale)}: () => fetch(${JSON.stringify(urls[0])}).then(r => r.json())`);
|
|
587
|
+
} else {
|
|
588
|
+
loaderEntries.push(` ${JSON.stringify(locale)}: async () => {
|
|
589
|
+
const urls = ${JSON.stringify(urls)};
|
|
590
|
+
const responses = await Promise.all(urls.map(url => fetch(url).then(r => r.json())));
|
|
591
|
+
return __deepMerge({}, ...responses);
|
|
592
|
+
}`);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
522
595
|
} else if (info.files.length === 1) {
|
|
523
596
|
const relativePath = toRelativeImport(info.files[0], projectRoot);
|
|
524
597
|
if (pathBasedNamespacing && info.localeBaseDir) {
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -52,9 +52,11 @@ declare function isCacheValid(cache: TranslationCache, projectRoot: string): boo
|
|
|
52
52
|
*/
|
|
53
53
|
declare function toRelativeImport(absolutePath: string, projectRoot: string): string;
|
|
54
54
|
/**
|
|
55
|
-
* Generate a glob pattern for import.meta.glob from a base directory
|
|
55
|
+
* Generate a glob pattern for import.meta.glob from a base directory.
|
|
56
|
+
* In virtual modules, globs must start with '/' (project root relative).
|
|
57
|
+
* Returns null if the path is in public/ (can't use import.meta.glob for public files).
|
|
56
58
|
*/
|
|
57
|
-
declare function toGlobPattern(baseDir: string, projectRoot: string): string;
|
|
59
|
+
declare function toGlobPattern(baseDir: string, projectRoot: string): string | null;
|
|
58
60
|
/**
|
|
59
61
|
* Get namespace from file path relative to locale base directory.
|
|
60
62
|
*
|
package/dist/utils/index.js
CHANGED
|
@@ -173,8 +173,10 @@ function toRelativeImport(absolutePath, projectRoot) {
|
|
|
173
173
|
}
|
|
174
174
|
function toGlobPattern(baseDir, projectRoot) {
|
|
175
175
|
const relativePath = path.relative(projectRoot, baseDir).replace(/\\/g, "/");
|
|
176
|
-
|
|
177
|
-
|
|
176
|
+
if (relativePath.startsWith("public/") || relativePath === "public") {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
return `/${relativePath}/**/*.json`;
|
|
178
180
|
}
|
|
179
181
|
function getNamespaceFromPath(filePath, localeDir) {
|
|
180
182
|
const relative2 = path.relative(localeDir, filePath);
|
package/package.json
CHANGED
|
@@ -302,12 +302,52 @@ export function toRelativeImport(absolutePath: string, projectRoot: string): str
|
|
|
302
302
|
}
|
|
303
303
|
|
|
304
304
|
/**
|
|
305
|
-
* Generate a glob pattern for import.meta.glob from a base directory
|
|
305
|
+
* Generate a glob pattern for import.meta.glob from a base directory.
|
|
306
|
+
* In virtual modules, globs must start with '/' (project root relative).
|
|
307
|
+
* Returns null if the path is in public/ (can't use import.meta.glob for public files).
|
|
306
308
|
*/
|
|
307
|
-
export function toGlobPattern(baseDir: string, projectRoot: string): string {
|
|
309
|
+
export function toGlobPattern(baseDir: string, projectRoot: string): string | null {
|
|
308
310
|
const relativePath = path.relative(projectRoot, baseDir).replace(/\\/g, '/');
|
|
309
|
-
|
|
310
|
-
|
|
311
|
+
// Can't use import.meta.glob for public directory files
|
|
312
|
+
if (relativePath.startsWith('public/') || relativePath === 'public') {
|
|
313
|
+
return null;
|
|
314
|
+
}
|
|
315
|
+
// Virtual modules require globs to start with '/' (project root relative)
|
|
316
|
+
return `/${relativePath}/**/*.json`;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Check if an absolute path is inside the public directory
|
|
321
|
+
*/
|
|
322
|
+
export function isInPublicDir(filePath: string, projectRoot: string): boolean {
|
|
323
|
+
const relativePath = path.relative(projectRoot, filePath).replace(/\\/g, '/');
|
|
324
|
+
return relativePath.startsWith('public/') || relativePath === 'public';
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Convert a public directory path to its served URL.
|
|
329
|
+
* public/i18n/en/common.json → /i18n/en/common.json
|
|
330
|
+
*/
|
|
331
|
+
export function toPublicUrl(filePath: string, projectRoot: string): string {
|
|
332
|
+
const relativePath = path.relative(projectRoot, filePath).replace(/\\/g, '/');
|
|
333
|
+
// Remove 'public/' prefix - files in public/ are served at root
|
|
334
|
+
if (relativePath.startsWith('public/')) {
|
|
335
|
+
return '/' + relativePath.slice('public/'.length);
|
|
336
|
+
}
|
|
337
|
+
return '/' + relativePath;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Get the locale base directory for namespace calculation.
|
|
342
|
+
* For public paths, strips the 'public/' prefix.
|
|
343
|
+
*/
|
|
344
|
+
export function getLocaleBaseDirForNamespace(localeBaseDir: string, projectRoot: string): string {
|
|
345
|
+
const relativePath = path.relative(projectRoot, localeBaseDir).replace(/\\/g, '/');
|
|
346
|
+
// For namespace calculation, we want the path without 'public/' prefix
|
|
347
|
+
if (relativePath.startsWith('public/')) {
|
|
348
|
+
return relativePath.slice('public/'.length);
|
|
349
|
+
}
|
|
350
|
+
return relativePath;
|
|
311
351
|
}
|
|
312
352
|
|
|
313
353
|
/**
|
package/src/vite-plugin.ts
CHANGED
|
@@ -10,6 +10,9 @@ import {
|
|
|
10
10
|
detectPathType,
|
|
11
11
|
getNamespaceFromPath,
|
|
12
12
|
generateNamespaceWrapperCode,
|
|
13
|
+
isInPublicDir,
|
|
14
|
+
toPublicUrl,
|
|
15
|
+
getLocaleBaseDirForNamespace,
|
|
13
16
|
} from './utils/translations';
|
|
14
17
|
import * as path from 'node:path';
|
|
15
18
|
|
|
@@ -21,10 +24,12 @@ const RESOLVED_PREFIX = '\0';
|
|
|
21
24
|
interface TranslationInfo {
|
|
22
25
|
locale: string;
|
|
23
26
|
files: string[];
|
|
24
|
-
/** Glob pattern for dev mode HMR (if applicable) */
|
|
25
|
-
globPattern?: string;
|
|
27
|
+
/** Glob pattern for dev mode HMR (if applicable, null for public files) */
|
|
28
|
+
globPattern?: string | null;
|
|
26
29
|
/** Base directory for this locale (used for namespace calculation) */
|
|
27
30
|
localeBaseDir?: string;
|
|
31
|
+
/** Whether files are in the public directory (use fetch instead of import) */
|
|
32
|
+
isPublic?: boolean;
|
|
28
33
|
}
|
|
29
34
|
|
|
30
35
|
/**
|
|
@@ -145,14 +150,18 @@ export function vitePlugin(config: EzI18nConfig): Plugin {
|
|
|
145
150
|
// Build translation info for each locale
|
|
146
151
|
for (const locale of finalLocales) {
|
|
147
152
|
const files = translations[locale] || [];
|
|
153
|
+
// Check if files are in public directory
|
|
154
|
+
const filesInPublic = files.length > 0 && isInPublicDir(files[0], projectRoot);
|
|
155
|
+
|
|
148
156
|
const info: TranslationInfo = {
|
|
149
157
|
locale,
|
|
150
158
|
files,
|
|
151
159
|
localeBaseDir: localeBaseDirs[locale],
|
|
160
|
+
isPublic: filesInPublic,
|
|
152
161
|
};
|
|
153
162
|
|
|
154
|
-
// For dev mode, determine if we can use import.meta.glob
|
|
155
|
-
if (isDev && config.translations) {
|
|
163
|
+
// For dev mode, determine if we can use import.meta.glob (not for public files)
|
|
164
|
+
if (isDev && config.translations && !filesInPublic) {
|
|
156
165
|
const localeConfig = typeof config.translations === 'string'
|
|
157
166
|
? path.join(config.translations, locale) + '/' // Trailing slash ensures detectPathType returns 'folder'
|
|
158
167
|
: config.translations[locale];
|
|
@@ -160,7 +169,7 @@ export function vitePlugin(config: EzI18nConfig): Plugin {
|
|
|
160
169
|
if (localeConfig && typeof localeConfig === 'string') {
|
|
161
170
|
const pathType = detectPathType(localeConfig);
|
|
162
171
|
if (pathType === 'folder' || pathType === 'glob') {
|
|
163
|
-
// Can use import.meta.glob for HMR
|
|
172
|
+
// Can use import.meta.glob for HMR (returns null for public files)
|
|
164
173
|
const basePath = pathType === 'glob'
|
|
165
174
|
? localeConfig
|
|
166
175
|
: toGlobPattern(path.resolve(projectRoot, localeConfig), projectRoot);
|
|
@@ -337,6 +346,7 @@ export function t(key, params) {
|
|
|
337
346
|
/**
|
|
338
347
|
* Generate the translations virtual module for dev mode.
|
|
339
348
|
* Uses import.meta.glob where possible for HMR support.
|
|
349
|
+
* Uses fetch() for files in public/ directory.
|
|
340
350
|
*/
|
|
341
351
|
function generateDevTranslationsModule(
|
|
342
352
|
translationInfo: Map<string, TranslationInfo>,
|
|
@@ -358,10 +368,35 @@ function generateDevTranslationsModule(
|
|
|
358
368
|
if (info.files.length === 0) {
|
|
359
369
|
// No files - return empty object
|
|
360
370
|
loaderEntries.push(` ${JSON.stringify(locale)}: async () => ({})`);
|
|
371
|
+
} else if (info.isPublic) {
|
|
372
|
+
// Public directory files - use fetch() instead of import
|
|
373
|
+
if (pathBasedNamespacing && info.localeBaseDir) {
|
|
374
|
+
const localeBaseDirForNs = getLocaleBaseDirForNamespace(info.localeBaseDir, projectRoot);
|
|
375
|
+
const fileEntries = info.files.map(f => {
|
|
376
|
+
const url = toPublicUrl(f, projectRoot);
|
|
377
|
+
const namespace = getNamespaceFromPath(f, info.localeBaseDir!);
|
|
378
|
+
return `{ url: ${JSON.stringify(url)}, namespace: ${JSON.stringify(namespace)} }`;
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
loaderEntries.push(` ${JSON.stringify(locale)}: async () => {
|
|
382
|
+
const fileInfos = [${fileEntries.join(', ')}];
|
|
383
|
+
const responses = await Promise.all(fileInfos.map(f => fetch(f.url).then(r => r.json())));
|
|
384
|
+
const wrapped = responses.map((content, i) => __wrapWithNamespace(fileInfos[i].namespace, content));
|
|
385
|
+
return __deepMerge({}, ...wrapped);
|
|
386
|
+
}`);
|
|
387
|
+
} else {
|
|
388
|
+
const urls = info.files.map(f => toPublicUrl(f, projectRoot));
|
|
389
|
+
loaderEntries.push(` ${JSON.stringify(locale)}: async () => {
|
|
390
|
+
const urls = ${JSON.stringify(urls)};
|
|
391
|
+
const responses = await Promise.all(urls.map(url => fetch(url).then(r => r.json())));
|
|
392
|
+
if (responses.length === 1) return responses[0];
|
|
393
|
+
return __deepMerge({}, ...responses);
|
|
394
|
+
}`);
|
|
395
|
+
}
|
|
361
396
|
} else if (info.globPattern && pathBasedNamespacing && info.localeBaseDir) {
|
|
362
397
|
// Use import.meta.glob with namespace wrapping
|
|
363
398
|
const varName = `__${locale}Modules`;
|
|
364
|
-
const
|
|
399
|
+
const localeBaseDirForNs = getLocaleBaseDirForNamespace(info.localeBaseDir, projectRoot);
|
|
365
400
|
imports.push(
|
|
366
401
|
`const ${varName} = import.meta.glob(${JSON.stringify(info.globPattern)}, { eager: true, import: 'default' });`
|
|
367
402
|
);
|
|
@@ -369,10 +404,11 @@ function generateDevTranslationsModule(
|
|
|
369
404
|
loaderEntries.push(` ${JSON.stringify(locale)}: async () => {
|
|
370
405
|
const entries = Object.entries(${varName});
|
|
371
406
|
if (entries.length === 0) return {};
|
|
372
|
-
const localeBaseDir = ${JSON.stringify(
|
|
407
|
+
const localeBaseDir = ${JSON.stringify(localeBaseDirForNs)};
|
|
373
408
|
const wrapped = entries.map(([filePath, content]) => {
|
|
374
|
-
// Extract relative path from locale base dir
|
|
375
|
-
const
|
|
409
|
+
// Extract relative path from locale base dir - filePath starts with /
|
|
410
|
+
const normalizedPath = filePath.startsWith('/') ? filePath.slice(1) : filePath;
|
|
411
|
+
const relativePath = normalizedPath.replace(localeBaseDir + '/', '').replace(/\\.json$/i, '');
|
|
376
412
|
const namespace = relativePath.replace(/[\\/]/g, '.').replace(/\\.index$/, '');
|
|
377
413
|
return __wrapWithNamespace(namespace, content);
|
|
378
414
|
});
|
|
@@ -392,7 +428,7 @@ function generateDevTranslationsModule(
|
|
|
392
428
|
return __deepMerge({}, ...modules);
|
|
393
429
|
}`);
|
|
394
430
|
} else if (info.files.length === 1) {
|
|
395
|
-
// Single file
|
|
431
|
+
// Single file - use import
|
|
396
432
|
const relativePath = toRelativeImport(info.files[0], projectRoot);
|
|
397
433
|
if (pathBasedNamespacing && info.localeBaseDir) {
|
|
398
434
|
const namespace = getNamespaceFromPath(info.files[0], info.localeBaseDir);
|
|
@@ -465,6 +501,7 @@ export async function loadTranslations(locale) {
|
|
|
465
501
|
/**
|
|
466
502
|
* Generate the translations virtual module for production builds.
|
|
467
503
|
* Pre-resolves all imports for optimal bundling.
|
|
504
|
+
* Uses fetch() for files in public/ directory.
|
|
468
505
|
*/
|
|
469
506
|
function generateBuildTranslationsModule(
|
|
470
507
|
translationInfo: Map<string, TranslationInfo>,
|
|
@@ -478,8 +515,37 @@ function generateBuildTranslationsModule(
|
|
|
478
515
|
for (const [locale, info] of translationInfo) {
|
|
479
516
|
if (info.files.length === 0) {
|
|
480
517
|
loaderEntries.push(` ${JSON.stringify(locale)}: async () => ({})`);
|
|
518
|
+
} else if (info.isPublic) {
|
|
519
|
+
// Public directory files - use fetch() instead of import
|
|
520
|
+
needsDeepMerge = info.files.length > 1;
|
|
521
|
+
if (pathBasedNamespacing && info.localeBaseDir) {
|
|
522
|
+
needsNamespaceWrapper = true;
|
|
523
|
+
const fileEntries = info.files.map(f => {
|
|
524
|
+
const url = toPublicUrl(f, projectRoot);
|
|
525
|
+
const namespace = getNamespaceFromPath(f, info.localeBaseDir!);
|
|
526
|
+
return `{ url: ${JSON.stringify(url)}, namespace: ${JSON.stringify(namespace)} }`;
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
loaderEntries.push(` ${JSON.stringify(locale)}: async () => {
|
|
530
|
+
const fileInfos = [${fileEntries.join(', ')}];
|
|
531
|
+
const responses = await Promise.all(fileInfos.map(f => fetch(f.url).then(r => r.json())));
|
|
532
|
+
const wrapped = responses.map((content, i) => __wrapWithNamespace(fileInfos[i].namespace, content));
|
|
533
|
+
return __deepMerge({}, ...wrapped);
|
|
534
|
+
}`);
|
|
535
|
+
} else {
|
|
536
|
+
const urls = info.files.map(f => toPublicUrl(f, projectRoot));
|
|
537
|
+
if (urls.length === 1) {
|
|
538
|
+
loaderEntries.push(` ${JSON.stringify(locale)}: () => fetch(${JSON.stringify(urls[0])}).then(r => r.json())`);
|
|
539
|
+
} else {
|
|
540
|
+
loaderEntries.push(` ${JSON.stringify(locale)}: async () => {
|
|
541
|
+
const urls = ${JSON.stringify(urls)};
|
|
542
|
+
const responses = await Promise.all(urls.map(url => fetch(url).then(r => r.json())));
|
|
543
|
+
return __deepMerge({}, ...responses);
|
|
544
|
+
}`);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
481
547
|
} else if (info.files.length === 1) {
|
|
482
|
-
// Single file
|
|
548
|
+
// Single file - use import
|
|
483
549
|
const relativePath = toRelativeImport(info.files[0], projectRoot);
|
|
484
550
|
if (pathBasedNamespacing && info.localeBaseDir) {
|
|
485
551
|
needsNamespaceWrapper = true;
|