@zachhandley/ez-i18n 0.1.9 → 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 +80 -6
- package/dist/utils/index.d.ts +2 -1
- package/dist/utils/index.js +3 -0
- package/package.json +1 -1
- package/src/utils/translations.ts +40 -1
- package/src/vite-plugin.ts +77 -11
package/dist/index.js
CHANGED
|
@@ -152,8 +152,29 @@ function toRelativeImport(absolutePath, projectRoot) {
|
|
|
152
152
|
}
|
|
153
153
|
function toGlobPattern(baseDir, projectRoot) {
|
|
154
154
|
const relativePath = path.relative(projectRoot, baseDir).replace(/\\/g, "/");
|
|
155
|
+
if (relativePath.startsWith("public/") || relativePath === "public") {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
155
158
|
return `/${relativePath}/**/*.json`;
|
|
156
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;
|
|
177
|
+
}
|
|
157
178
|
function getNamespaceFromPath(filePath, localeDir) {
|
|
158
179
|
const relative2 = path.relative(localeDir, filePath);
|
|
159
180
|
const withoutExt = relative2.replace(/\.json$/i, "");
|
|
@@ -261,12 +282,14 @@ function vitePlugin(config) {
|
|
|
261
282
|
};
|
|
262
283
|
for (const locale of finalLocales) {
|
|
263
284
|
const files = translations[locale] || [];
|
|
285
|
+
const filesInPublic = files.length > 0 && isInPublicDir(files[0], projectRoot);
|
|
264
286
|
const info = {
|
|
265
287
|
locale,
|
|
266
288
|
files,
|
|
267
|
-
localeBaseDir: localeBaseDirs[locale]
|
|
289
|
+
localeBaseDir: localeBaseDirs[locale],
|
|
290
|
+
isPublic: filesInPublic
|
|
268
291
|
};
|
|
269
|
-
if (isDev && config.translations) {
|
|
292
|
+
if (isDev && config.translations && !filesInPublic) {
|
|
270
293
|
const localeConfig = typeof config.translations === "string" ? path2.join(config.translations, locale) + "/" : config.translations[locale];
|
|
271
294
|
if (localeConfig && typeof localeConfig === "string") {
|
|
272
295
|
const pathType = detectPathType(localeConfig);
|
|
@@ -419,19 +442,43 @@ function generateDevTranslationsModule(translationInfo, projectRoot, pathBasedNa
|
|
|
419
442
|
for (const [locale, info] of translationInfo) {
|
|
420
443
|
if (info.files.length === 0) {
|
|
421
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
|
+
}
|
|
422
468
|
} else if (info.globPattern && pathBasedNamespacing && info.localeBaseDir) {
|
|
423
469
|
const varName = `__${locale}Modules`;
|
|
424
|
-
const
|
|
470
|
+
const localeBaseDirForNs = getLocaleBaseDirForNamespace(info.localeBaseDir, projectRoot);
|
|
425
471
|
imports.push(
|
|
426
472
|
`const ${varName} = import.meta.glob(${JSON.stringify(info.globPattern)}, { eager: true, import: 'default' });`
|
|
427
473
|
);
|
|
428
474
|
loaderEntries.push(` ${JSON.stringify(locale)}: async () => {
|
|
429
475
|
const entries = Object.entries(${varName});
|
|
430
476
|
if (entries.length === 0) return {};
|
|
431
|
-
const localeBaseDir = ${JSON.stringify(
|
|
477
|
+
const localeBaseDir = ${JSON.stringify(localeBaseDirForNs)};
|
|
432
478
|
const wrapped = entries.map(([filePath, content]) => {
|
|
433
|
-
// Extract relative path from locale base dir
|
|
434
|
-
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, '');
|
|
435
482
|
const namespace = relativePath.replace(/[\\/]/g, '.').replace(/\\.index$/, '');
|
|
436
483
|
return __wrapWithNamespace(namespace, content);
|
|
437
484
|
});
|
|
@@ -518,6 +565,33 @@ function generateBuildTranslationsModule(translationInfo, projectRoot, pathBased
|
|
|
518
565
|
for (const [locale, info] of translationInfo) {
|
|
519
566
|
if (info.files.length === 0) {
|
|
520
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
|
+
}
|
|
521
595
|
} else if (info.files.length === 1) {
|
|
522
596
|
const relativePath = toRelativeImport(info.files[0], projectRoot);
|
|
523
597
|
if (pathBasedNamespacing && info.localeBaseDir) {
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -54,8 +54,9 @@ declare function toRelativeImport(absolutePath: string, projectRoot: string): st
|
|
|
54
54
|
/**
|
|
55
55
|
* Generate a glob pattern for import.meta.glob from a base directory.
|
|
56
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).
|
|
57
58
|
*/
|
|
58
|
-
declare function toGlobPattern(baseDir: string, projectRoot: string): string;
|
|
59
|
+
declare function toGlobPattern(baseDir: string, projectRoot: string): string | null;
|
|
59
60
|
/**
|
|
60
61
|
* Get namespace from file path relative to locale base directory.
|
|
61
62
|
*
|
package/dist/utils/index.js
CHANGED
|
@@ -173,6 +173,9 @@ function toRelativeImport(absolutePath, projectRoot) {
|
|
|
173
173
|
}
|
|
174
174
|
function toGlobPattern(baseDir, projectRoot) {
|
|
175
175
|
const relativePath = path.relative(projectRoot, baseDir).replace(/\\/g, "/");
|
|
176
|
+
if (relativePath.startsWith("public/") || relativePath === "public") {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
176
179
|
return `/${relativePath}/**/*.json`;
|
|
177
180
|
}
|
|
178
181
|
function getNamespaceFromPath(filePath, localeDir) {
|
package/package.json
CHANGED
|
@@ -304,13 +304,52 @@ export function toRelativeImport(absolutePath: string, projectRoot: string): str
|
|
|
304
304
|
/**
|
|
305
305
|
* Generate a glob pattern for import.meta.glob from a base directory.
|
|
306
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).
|
|
307
308
|
*/
|
|
308
|
-
export function toGlobPattern(baseDir: string, projectRoot: string): string {
|
|
309
|
+
export function toGlobPattern(baseDir: string, projectRoot: string): string | null {
|
|
309
310
|
const relativePath = path.relative(projectRoot, baseDir).replace(/\\/g, '/');
|
|
311
|
+
// Can't use import.meta.glob for public directory files
|
|
312
|
+
if (relativePath.startsWith('public/') || relativePath === 'public') {
|
|
313
|
+
return null;
|
|
314
|
+
}
|
|
310
315
|
// Virtual modules require globs to start with '/' (project root relative)
|
|
311
316
|
return `/${relativePath}/**/*.json`;
|
|
312
317
|
}
|
|
313
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;
|
|
351
|
+
}
|
|
352
|
+
|
|
314
353
|
/**
|
|
315
354
|
* Get namespace from file path relative to locale base directory.
|
|
316
355
|
*
|
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;
|