intor 2.2.1 → 2.2.2
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/config/index.d.cts +9 -9
- package/dist/config/index.d.ts +9 -9
- package/dist/index.cjs +306 -453
- package/dist/index.d.cts +76 -54
- package/dist/index.d.ts +76 -54
- package/dist/index.js +309 -457
- package/dist/next/index.cjs +141 -148
- package/dist/next/index.d.cts +9 -9
- package/dist/next/index.d.ts +9 -9
- package/dist/next/index.js +139 -147
- package/dist/next/middleware/index.d.cts +9 -9
- package/dist/next/middleware/index.d.ts +9 -9
- package/dist/next/server/index.cjs +286 -430
- package/dist/next/server/index.d.cts +9 -9
- package/dist/next/server/index.d.ts +9 -9
- package/dist/next/server/index.js +289 -434
- package/package.json +4 -12
|
@@ -7,6 +7,7 @@ var path = require('path');
|
|
|
7
7
|
var perf_hooks = require('perf_hooks');
|
|
8
8
|
var pLimit = require('p-limit');
|
|
9
9
|
var fs = require('fs/promises');
|
|
10
|
+
var merge = require('lodash.merge');
|
|
10
11
|
var Keyv = require('keyv');
|
|
11
12
|
|
|
12
13
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -14,6 +15,7 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
|
14
15
|
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
15
16
|
var pLimit__default = /*#__PURE__*/_interopDefault(pLimit);
|
|
16
17
|
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
18
|
+
var merge__default = /*#__PURE__*/_interopDefault(merge);
|
|
17
19
|
var Keyv__default = /*#__PURE__*/_interopDefault(Keyv);
|
|
18
20
|
|
|
19
21
|
// src/adapters/next/server/get-i18n-context.ts
|
|
@@ -34,17 +36,18 @@ var DEFAULT_FORMATTER_CONFIG = {
|
|
|
34
36
|
node: { meta: { compact: true }, lineBreaksAfter: 1 }
|
|
35
37
|
};
|
|
36
38
|
function getLogger({
|
|
37
|
-
id,
|
|
39
|
+
id = "default",
|
|
38
40
|
formatterConfig,
|
|
39
41
|
preset,
|
|
40
42
|
...options
|
|
41
43
|
}) {
|
|
42
44
|
const pool = getGlobalLoggerPool();
|
|
43
45
|
let logger = pool.get(id);
|
|
46
|
+
const useDefault = !formatterConfig && !preset;
|
|
44
47
|
if (!logger) {
|
|
45
48
|
logger = logry.logry({
|
|
46
49
|
id,
|
|
47
|
-
formatterConfig:
|
|
50
|
+
formatterConfig: useDefault ? DEFAULT_FORMATTER_CONFIG : formatterConfig,
|
|
48
51
|
preset,
|
|
49
52
|
...options
|
|
50
53
|
});
|
|
@@ -86,6 +89,8 @@ var resolveNamespaces = ({
|
|
|
86
89
|
}) => {
|
|
87
90
|
const { loader } = config;
|
|
88
91
|
const { routeNamespaces = {}, namespaces } = loader || {};
|
|
92
|
+
if (Object.keys(routeNamespaces).length === 0 && !namespaces)
|
|
93
|
+
return void 0;
|
|
89
94
|
const standardizedPathname = standardizePathname({ config, pathname });
|
|
90
95
|
const placeholderRemovedPathname = standardizedPathname.replace(
|
|
91
96
|
`/${PREFIX_PLACEHOLDER}`,
|
|
@@ -242,307 +247,171 @@ var DEFAULT_CACHE_OPTIONS = {
|
|
|
242
247
|
ttl: 60 * 60 * 1e3
|
|
243
248
|
// 1 hour
|
|
244
249
|
};
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
this.id = id;
|
|
253
|
-
this.code = code;
|
|
254
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
255
|
-
}
|
|
256
|
-
};
|
|
257
|
-
|
|
258
|
-
// src/modules/messages/load-local-messages/load-namespace-group/parse-message-file.ts
|
|
259
|
-
var MAX_PATH_LENGTH = 260;
|
|
260
|
-
var parseMessageFile = async (filePath, loggerOptions) => {
|
|
250
|
+
async function collectFileEntries({
|
|
251
|
+
readdir = fs__default.default.readdir,
|
|
252
|
+
limit,
|
|
253
|
+
rootDir,
|
|
254
|
+
namespaces,
|
|
255
|
+
extraOptions: { exts = [".json"], loggerOptions } = {}
|
|
256
|
+
}) {
|
|
261
257
|
const baseLogger = getLogger({ ...loggerOptions });
|
|
262
|
-
const logger = baseLogger.child({ scope: "
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
}
|
|
272
|
-
const fileName = path__default.default.basename(trimmedPath);
|
|
273
|
-
if (!fileName.toLowerCase().endsWith(".json")) {
|
|
274
|
-
logger.trace("Skipped non-JSON file.", { filePath: trimmedPath });
|
|
275
|
-
return null;
|
|
276
|
-
}
|
|
277
|
-
try {
|
|
278
|
-
const content = await fs__default.default.readFile(trimmedPath, "utf8");
|
|
279
|
-
const parsed = JSON.parse(content);
|
|
280
|
-
if (typeof parsed !== "object" || parsed === null) {
|
|
281
|
-
throw new IntorError({
|
|
282
|
-
id: loggerOptions.id,
|
|
283
|
-
code: "INTOR_INVALID_MESSAGE_FORMAT" /* INVALID_MESSAGE_FORMAT */,
|
|
284
|
-
message: "Invalid message format"
|
|
285
|
-
});
|
|
258
|
+
const logger = baseLogger.child({ scope: "collect-file-entries" });
|
|
259
|
+
const results = [];
|
|
260
|
+
const walk = async (currentDir) => {
|
|
261
|
+
let entries = [];
|
|
262
|
+
try {
|
|
263
|
+
entries = await readdir(currentDir, { withFileTypes: true });
|
|
264
|
+
} catch (error) {
|
|
265
|
+
logger.error(`Error reading directory: ${currentDir}`, { error });
|
|
266
|
+
return;
|
|
286
267
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
268
|
+
const tasks = entries.map(
|
|
269
|
+
(entry) => limit(async () => {
|
|
270
|
+
const fullPath = path__default.default.join(currentDir, entry.name);
|
|
271
|
+
if (entry.isDirectory()) {
|
|
272
|
+
await walk(fullPath);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
if (!exts.some((ext2) => entry.name.endsWith(ext2))) return;
|
|
276
|
+
const relativePath = path__default.default.relative(rootDir, fullPath);
|
|
277
|
+
const ext = path__default.default.extname(relativePath);
|
|
278
|
+
const withoutExt = relativePath.slice(0, -ext.length);
|
|
279
|
+
const segments = withoutExt.split(path__default.default.sep).filter(Boolean);
|
|
280
|
+
const namespace = segments.at(0);
|
|
281
|
+
if (!namespace) return;
|
|
282
|
+
if (namespaces && namespace !== "index") {
|
|
283
|
+
if (!namespaces.includes(namespace)) return;
|
|
284
|
+
}
|
|
285
|
+
results.push({
|
|
286
|
+
namespace,
|
|
287
|
+
fullPath,
|
|
288
|
+
relativePath,
|
|
289
|
+
segments,
|
|
290
|
+
basename: path__default.default.basename(entry.name, ext)
|
|
291
|
+
});
|
|
292
|
+
})
|
|
293
|
+
);
|
|
294
|
+
await Promise.all(tasks);
|
|
295
|
+
};
|
|
296
|
+
await walk(rootDir);
|
|
297
|
+
if (logger.core.level === "debug") {
|
|
298
|
+
logger.debug("Local message files collected.", {
|
|
299
|
+
count: results.length
|
|
293
300
|
});
|
|
294
|
-
return null;
|
|
295
301
|
}
|
|
296
|
-
|
|
302
|
+
logger.trace("Local message files collected.", {
|
|
303
|
+
count: results.length,
|
|
304
|
+
fileEntries: results.map(({ namespace, relativePath }) => ({
|
|
305
|
+
namespace: namespace === "index" ? null : namespace,
|
|
306
|
+
relativePath
|
|
307
|
+
}))
|
|
308
|
+
});
|
|
309
|
+
return results;
|
|
310
|
+
}
|
|
297
311
|
|
|
298
|
-
// src/modules/messages/
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
if (
|
|
310
|
-
|
|
312
|
+
// src/modules/messages/shared/utils/is-namespace-messages.ts
|
|
313
|
+
function isPlainObject(value) {
|
|
314
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
315
|
+
}
|
|
316
|
+
function isNamespaceMessages(value) {
|
|
317
|
+
if (!isPlainObject(value)) return false;
|
|
318
|
+
const stack = [value];
|
|
319
|
+
while (stack.length > 0) {
|
|
320
|
+
const current = stack.pop();
|
|
321
|
+
for (const v of Object.values(current)) {
|
|
322
|
+
if (typeof v === "string") continue;
|
|
323
|
+
if (isPlainObject(v)) {
|
|
324
|
+
stack.push(v);
|
|
311
325
|
} else {
|
|
312
|
-
|
|
313
|
-
subEntries[name] = content;
|
|
326
|
+
return false;
|
|
314
327
|
}
|
|
315
|
-
})
|
|
316
|
-
);
|
|
317
|
-
return { base: baseContent, sub: subEntries };
|
|
318
|
-
};
|
|
319
|
-
|
|
320
|
-
// src/modules/messages/load-local-messages/load-namespace-group/load-namespace-group.ts
|
|
321
|
-
var loadNamespaceGroup = async ({
|
|
322
|
-
locale,
|
|
323
|
-
namespace,
|
|
324
|
-
messages,
|
|
325
|
-
namespaceGroupValue,
|
|
326
|
-
limit,
|
|
327
|
-
logger: loggerOptions = { id: "default" }
|
|
328
|
-
}) => {
|
|
329
|
-
const baseLogger = getLogger({ ...loggerOptions });
|
|
330
|
-
const logger = baseLogger.child({ scope: "load-namespace-group" });
|
|
331
|
-
const { isAtRoot, filePaths } = namespaceGroupValue;
|
|
332
|
-
if (filePaths.length === 0) {
|
|
333
|
-
logger.trace(
|
|
334
|
-
`Skipped merging ${locale}/${namespace} because filePaths is empty`
|
|
335
|
-
);
|
|
336
|
-
return;
|
|
337
|
-
}
|
|
338
|
-
return limit(async () => {
|
|
339
|
-
const { base, sub } = await mergeNamespaceMessages(
|
|
340
|
-
filePaths,
|
|
341
|
-
isAtRoot,
|
|
342
|
-
loggerOptions
|
|
343
|
-
);
|
|
344
|
-
if (!messages[locale]) {
|
|
345
|
-
messages[locale] = {};
|
|
346
|
-
}
|
|
347
|
-
if (isAtRoot && filePaths.length === 1 && path__default.default.basename(filePaths[0]) === "index.json") {
|
|
348
|
-
messages[locale] = { ...messages[locale], ...base };
|
|
349
|
-
return;
|
|
350
|
-
}
|
|
351
|
-
const finalContent = isAtRoot ? base : { ...base, ...sub };
|
|
352
|
-
messages[locale][namespace] = finalContent;
|
|
353
|
-
if (!isAtRoot && Object.keys(finalContent).length > 0) {
|
|
354
|
-
logger.trace(
|
|
355
|
-
`Merged ${locale}/${namespace} from ${filePaths.length} file(s)`,
|
|
356
|
-
{ namespace }
|
|
357
|
-
);
|
|
358
328
|
}
|
|
359
|
-
});
|
|
360
|
-
};
|
|
361
|
-
var addToNamespaceGroup = ({
|
|
362
|
-
options: { namespaces },
|
|
363
|
-
filePath,
|
|
364
|
-
namespaceGroups,
|
|
365
|
-
namespacePathSegments
|
|
366
|
-
}) => {
|
|
367
|
-
if (!filePath) {
|
|
368
|
-
return;
|
|
369
329
|
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
330
|
+
return true;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// src/modules/messages/load-local-messages/read-locale-messages/parse-file-entries/utils/json-reader.ts
|
|
334
|
+
async function jsonReader(filePath, readFile = fs__default.default.readFile) {
|
|
335
|
+
const raw = await readFile(filePath, "utf8");
|
|
336
|
+
const parsed = JSON.parse(raw);
|
|
337
|
+
if (!isNamespaceMessages(parsed)) {
|
|
338
|
+
throw new Error("JSON file does not match NamespaceMessages structure");
|
|
374
339
|
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
namespaceGroups.set(nsKey, group);
|
|
340
|
+
return parsed;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// src/modules/messages/load-local-messages/read-locale-messages/parse-file-entries/utils/nest-object-from-path.ts
|
|
344
|
+
function nestObjectFromPath(path4, value) {
|
|
345
|
+
let obj = value;
|
|
346
|
+
for (let i = path4.length - 1; i >= 0; i--) {
|
|
347
|
+
obj = { [path4[i]]: obj };
|
|
384
348
|
}
|
|
385
|
-
|
|
349
|
+
return obj;
|
|
350
|
+
}
|
|
386
351
|
|
|
387
|
-
// src/modules/messages/load-local-messages/
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
readdir = fs__default.default.readdir
|
|
394
|
-
}) => {
|
|
395
|
-
const { limit } = options;
|
|
396
|
-
const loggerOptions = options.logger || { id: "default" };
|
|
352
|
+
// src/modules/messages/load-local-messages/read-locale-messages/parse-file-entries/parse-file-entries.ts
|
|
353
|
+
async function parseFileEntries({
|
|
354
|
+
fileEntries,
|
|
355
|
+
limit,
|
|
356
|
+
extraOptions: { messageFileReader, loggerOptions } = {}
|
|
357
|
+
}) {
|
|
397
358
|
const baseLogger = getLogger({ ...loggerOptions });
|
|
398
|
-
const logger = baseLogger.child({ scope: "
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
const
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
namespaceGroups,
|
|
414
|
-
currentDirPath: filePath,
|
|
415
|
-
namespacePathSegments: [...namespacePathSegments, dirent.name],
|
|
416
|
-
options,
|
|
417
|
-
readdir
|
|
418
|
-
});
|
|
419
|
-
}
|
|
420
|
-
}).catch((error) => {
|
|
421
|
-
logger.warn("Failed to process a locale file or directory.", {
|
|
422
|
-
name: dirent.name,
|
|
423
|
-
type: dirent.isFile() ? "file" : "directory",
|
|
424
|
-
path: currentDirPath,
|
|
359
|
+
const logger = baseLogger.child({ scope: "parse-file-entries" });
|
|
360
|
+
const parsedFileEntries = [];
|
|
361
|
+
const tasks = fileEntries.map(
|
|
362
|
+
({ namespace, segments, basename, fullPath }) => limit(async () => {
|
|
363
|
+
try {
|
|
364
|
+
const segsWithoutNs = segments.slice(1);
|
|
365
|
+
const json = await (messageFileReader ? messageFileReader(fullPath) : jsonReader(fullPath));
|
|
366
|
+
const isIndex = basename === "index";
|
|
367
|
+
const keyPath = isIndex ? segsWithoutNs.slice(0, -1) : segsWithoutNs;
|
|
368
|
+
const namespaceMessages = nestObjectFromPath(keyPath, json);
|
|
369
|
+
parsedFileEntries.push({ namespace, namespaceMessages });
|
|
370
|
+
logger.trace("Parsed file.", { path: fullPath });
|
|
371
|
+
} catch (error) {
|
|
372
|
+
logger.error("Failed to read or parse file.", {
|
|
373
|
+
path: fullPath,
|
|
425
374
|
error
|
|
426
375
|
});
|
|
427
|
-
}
|
|
428
|
-
)
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
376
|
+
}
|
|
377
|
+
})
|
|
378
|
+
);
|
|
379
|
+
await Promise.all(tasks);
|
|
380
|
+
const result = {};
|
|
381
|
+
for (const { namespace, namespaceMessages } of parsedFileEntries) {
|
|
382
|
+
if (namespace === "index") {
|
|
383
|
+
merge__default.default(result, namespaceMessages);
|
|
384
|
+
} else {
|
|
385
|
+
result[namespace] = merge__default.default(
|
|
386
|
+
result[namespace] ?? {},
|
|
387
|
+
namespaceMessages
|
|
388
|
+
);
|
|
389
|
+
}
|
|
432
390
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
// src/modules/messages/load-local-messages/prepare-namespace-groups/prepare-namespace-groups.ts
|
|
436
|
-
var prepareNamespaceGroups = async (options) => {
|
|
437
|
-
const { basePath } = options;
|
|
438
|
-
const namespaceGroups = /* @__PURE__ */ new Map();
|
|
439
|
-
await traverseDirectory({
|
|
440
|
-
options,
|
|
441
|
-
currentDirPath: basePath,
|
|
442
|
-
namespaceGroups,
|
|
443
|
-
namespacePathSegments: []
|
|
444
|
-
});
|
|
445
|
-
return namespaceGroups;
|
|
446
|
-
};
|
|
391
|
+
return result;
|
|
392
|
+
}
|
|
447
393
|
|
|
448
|
-
// src/modules/messages/load-local-messages/
|
|
449
|
-
var
|
|
450
|
-
|
|
394
|
+
// src/modules/messages/load-local-messages/read-locale-messages/read-locale-messages.ts
|
|
395
|
+
var readLocaleMessages = async ({
|
|
396
|
+
limit,
|
|
397
|
+
rootDir = "messages",
|
|
451
398
|
locale,
|
|
452
399
|
namespaces,
|
|
453
|
-
|
|
454
|
-
limit,
|
|
455
|
-
logger: loggerOptions = { id: "default" }
|
|
400
|
+
extraOptions: { exts, messageFileReader, loggerOptions } = {}
|
|
456
401
|
}) => {
|
|
457
|
-
const
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
const validNamespaces = [];
|
|
461
|
-
try {
|
|
462
|
-
const stat = await fs__default.default.stat(localePath);
|
|
463
|
-
if (!stat.isDirectory()) {
|
|
464
|
-
logger.warn("Locale path is not a directory.", {
|
|
465
|
-
locale,
|
|
466
|
-
path: localePath
|
|
467
|
-
});
|
|
468
|
-
return;
|
|
469
|
-
}
|
|
470
|
-
} catch (error) {
|
|
471
|
-
logger.warn("Error checking locale path.", { locale, error });
|
|
472
|
-
return;
|
|
473
|
-
}
|
|
474
|
-
const namespaceGroups = await prepareNamespaceGroups({
|
|
475
|
-
basePath: localePath,
|
|
402
|
+
const fileEntries = await collectFileEntries({
|
|
403
|
+
rootDir: path__default.default.resolve(process.cwd(), rootDir, locale),
|
|
404
|
+
namespaces,
|
|
476
405
|
limit,
|
|
477
|
-
|
|
478
|
-
logger: loggerOptions
|
|
406
|
+
extraOptions: { exts, loggerOptions }
|
|
479
407
|
});
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
namespaces
|
|
485
|
-
});
|
|
486
|
-
return;
|
|
487
|
-
}
|
|
488
|
-
logger.trace("Prepared namespace groups from scanning local files.", {
|
|
489
|
-
namespaceGroups: [...namespaceGroups.entries()].map(([ns, val]) => ({
|
|
490
|
-
namespace: ns,
|
|
491
|
-
isAtRoot: val.isAtRoot,
|
|
492
|
-
fileCount: val.filePaths.length
|
|
493
|
-
}))
|
|
494
|
-
});
|
|
495
|
-
const namespaceGroupTasks = [...namespaceGroups.entries()].filter(
|
|
496
|
-
([ns]) => !namespaces || namespaces.length === 0 || namespaces.includes(ns)
|
|
497
|
-
).map(
|
|
498
|
-
([namespace, namespaceGroupValue]) => loadNamespaceGroup({
|
|
499
|
-
locale,
|
|
500
|
-
namespace,
|
|
501
|
-
messages,
|
|
502
|
-
namespaceGroupValue,
|
|
503
|
-
limit,
|
|
504
|
-
logger: loggerOptions
|
|
505
|
-
}).then(() => validNamespaces.push(namespace))
|
|
506
|
-
);
|
|
507
|
-
await Promise.all(namespaceGroupTasks);
|
|
508
|
-
return validNamespaces;
|
|
509
|
-
};
|
|
510
|
-
|
|
511
|
-
// src/modules/messages/load-local-messages/load-locale-with-fallback/load-locale-with-fallback.ts
|
|
512
|
-
var loadLocaleWithFallback = async ({
|
|
513
|
-
basePath,
|
|
514
|
-
locale: targetLocale,
|
|
515
|
-
fallbackLocales = [],
|
|
516
|
-
namespaces,
|
|
517
|
-
messages,
|
|
518
|
-
limit,
|
|
519
|
-
logger: loggerOptions = { id: "default" }
|
|
520
|
-
}) => {
|
|
521
|
-
const baseLogger = getLogger({ ...loggerOptions });
|
|
522
|
-
const logger = baseLogger.child({ scope: "load-locale-with-fallback" });
|
|
523
|
-
const candidateLocales = [targetLocale, ...fallbackLocales];
|
|
524
|
-
for (const locale of candidateLocales) {
|
|
525
|
-
try {
|
|
526
|
-
const validNamespaces = await loadSingleLocale({
|
|
527
|
-
basePath,
|
|
528
|
-
locale,
|
|
529
|
-
namespaces,
|
|
530
|
-
messages,
|
|
531
|
-
limit,
|
|
532
|
-
logger: loggerOptions
|
|
533
|
-
});
|
|
534
|
-
return validNamespaces;
|
|
535
|
-
} catch (error) {
|
|
536
|
-
logger.warn("Error occurred while processing the locale.", {
|
|
537
|
-
locale,
|
|
538
|
-
error
|
|
539
|
-
});
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
logger.warn("All fallback locales failed.", {
|
|
543
|
-
attemptedLocales: candidateLocales
|
|
408
|
+
const namespaceMessages = await parseFileEntries({
|
|
409
|
+
fileEntries,
|
|
410
|
+
limit,
|
|
411
|
+
extraOptions: { messageFileReader, loggerOptions }
|
|
544
412
|
});
|
|
545
|
-
|
|
413
|
+
const localeMessages = { [locale]: namespaceMessages };
|
|
414
|
+
return localeMessages;
|
|
546
415
|
};
|
|
547
416
|
function getGlobalMessagesPool() {
|
|
548
417
|
if (!globalThis.__INTOR_MESSAGES_POOL__) {
|
|
@@ -553,43 +422,35 @@ function getGlobalMessagesPool() {
|
|
|
553
422
|
|
|
554
423
|
// src/modules/messages/load-local-messages/load-local-messages.ts
|
|
555
424
|
var loadLocalMessages = async ({
|
|
556
|
-
|
|
425
|
+
pool = getGlobalMessagesPool(),
|
|
426
|
+
rootDir = "messages",
|
|
557
427
|
locale,
|
|
558
428
|
fallbackLocales,
|
|
559
429
|
namespaces,
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
430
|
+
extraOptions: {
|
|
431
|
+
concurrency = 10,
|
|
432
|
+
cacheOptions = DEFAULT_CACHE_OPTIONS,
|
|
433
|
+
loggerOptions = { id: "default" },
|
|
434
|
+
exts,
|
|
435
|
+
messageFileReader
|
|
436
|
+
} = {}
|
|
563
437
|
}) => {
|
|
564
|
-
basePath = basePath ?? "messages";
|
|
565
|
-
if (!locale || locale.trim() === "") return {};
|
|
566
438
|
const baseLogger = getLogger({ ...loggerOptions });
|
|
567
|
-
const logger = baseLogger.child({ scope: "load-
|
|
568
|
-
const messages = {};
|
|
569
|
-
const resolvedBasePath = path__default.default.resolve(
|
|
570
|
-
process.cwd(),
|
|
571
|
-
normalizePathname(basePath, { removeLeadingSlash: true })
|
|
572
|
-
);
|
|
439
|
+
const logger = baseLogger.child({ scope: "load-local-messages" });
|
|
573
440
|
const start = perf_hooks.performance.now();
|
|
574
|
-
logger.
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
fallbackLocales,
|
|
578
|
-
namespaces: namespaces && namespaces.length > 0 ? { count: namespaces?.length, list: [...namespaces] } : "All Namespaces",
|
|
579
|
-
concurrency
|
|
441
|
+
logger.debug("Loading local messages from directory.", {
|
|
442
|
+
rootDir,
|
|
443
|
+
resolvedRootDir: path__default.default.resolve(process.cwd(), rootDir)
|
|
580
444
|
});
|
|
581
|
-
let pool;
|
|
582
|
-
if (cache.enabled) {
|
|
583
|
-
pool = getGlobalMessagesPool();
|
|
584
|
-
}
|
|
585
445
|
const key = normalizeCacheKey([
|
|
586
446
|
loggerOptions.id,
|
|
587
|
-
|
|
447
|
+
"loaderType:local",
|
|
448
|
+
rootDir,
|
|
588
449
|
locale,
|
|
589
|
-
(fallbackLocales
|
|
590
|
-
(namespaces
|
|
450
|
+
(fallbackLocales || []).toSorted().join(","),
|
|
451
|
+
(namespaces || []).toSorted().join(",")
|
|
591
452
|
]);
|
|
592
|
-
if (
|
|
453
|
+
if (cacheOptions.enabled && key) {
|
|
593
454
|
const cached = await pool?.get(key);
|
|
594
455
|
if (cached) {
|
|
595
456
|
logger.debug("Messages cache hit.", { key });
|
|
@@ -597,50 +458,57 @@ var loadLocalMessages = async ({
|
|
|
597
458
|
}
|
|
598
459
|
}
|
|
599
460
|
const limit = pLimit__default.default(concurrency);
|
|
600
|
-
const
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
461
|
+
const candidateLocales = [locale, ...fallbackLocales || []];
|
|
462
|
+
let messages;
|
|
463
|
+
for (const candidateLocale of candidateLocales) {
|
|
464
|
+
try {
|
|
465
|
+
const result = await readLocaleMessages({
|
|
466
|
+
limit,
|
|
467
|
+
rootDir,
|
|
468
|
+
locale: candidateLocale,
|
|
469
|
+
namespaces,
|
|
470
|
+
extraOptions: { loggerOptions, exts, messageFileReader }
|
|
471
|
+
});
|
|
472
|
+
if (result && Object.values(result[candidateLocale] || {}).length > 0) {
|
|
473
|
+
messages = result;
|
|
474
|
+
break;
|
|
475
|
+
}
|
|
476
|
+
} catch (error) {
|
|
477
|
+
logger.error("Failed to read locale messages", {
|
|
478
|
+
locale: candidateLocale,
|
|
479
|
+
error
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
if (cacheOptions.enabled && key && messages) {
|
|
484
|
+
await pool?.set(key, messages, cacheOptions.ttl);
|
|
611
485
|
}
|
|
612
486
|
const end = perf_hooks.performance.now();
|
|
613
487
|
const duration = Math.round(end - start);
|
|
614
488
|
logger.trace("Finished loading local messages.", {
|
|
615
|
-
|
|
616
|
-
validNamespaces,
|
|
489
|
+
loadedLocale: messages ? Object.keys(messages)[0] : void 0,
|
|
617
490
|
duration: `${duration} ms`
|
|
618
491
|
});
|
|
619
492
|
return messages;
|
|
620
493
|
};
|
|
621
494
|
|
|
622
|
-
// src/modules/messages/
|
|
623
|
-
var
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
// src/modules/messages/load-api-messages/fetch-messages.ts
|
|
628
|
-
var fetchMessages = async ({
|
|
629
|
-
apiUrl,
|
|
630
|
-
apiHeaders,
|
|
631
|
-
locale,
|
|
495
|
+
// src/modules/messages/load-remote-messages/fetch-locale-messages/fetch-locale-messages.ts
|
|
496
|
+
var fetchLocaleMessages = async ({
|
|
497
|
+
remoteUrl,
|
|
498
|
+
remoteHeaders,
|
|
632
499
|
searchParams,
|
|
633
|
-
|
|
500
|
+
locale,
|
|
501
|
+
extraOptions: { loggerOptions } = {}
|
|
634
502
|
}) => {
|
|
635
503
|
const baseLogger = getLogger({ ...loggerOptions });
|
|
636
|
-
const logger = baseLogger.child({ scope: "fetch-messages" });
|
|
504
|
+
const logger = baseLogger.child({ scope: "fetch-locale-messages" });
|
|
637
505
|
try {
|
|
638
506
|
const params = new URLSearchParams(searchParams);
|
|
639
507
|
params.append("locale", locale);
|
|
640
|
-
const url = `${
|
|
508
|
+
const url = `${remoteUrl}?${params.toString()}`;
|
|
641
509
|
const headers2 = {
|
|
642
510
|
"Content-Type": "application/json",
|
|
643
|
-
...
|
|
511
|
+
...remoteHeaders
|
|
644
512
|
};
|
|
645
513
|
const response = await fetch(url, {
|
|
646
514
|
method: "GET",
|
|
@@ -648,17 +516,17 @@ var fetchMessages = async ({
|
|
|
648
516
|
cache: "no-store"
|
|
649
517
|
});
|
|
650
518
|
if (!response.ok) {
|
|
651
|
-
throw new Error(`
|
|
519
|
+
throw new Error(`HTTP error ${response.status} ${response.statusText}`);
|
|
652
520
|
}
|
|
653
521
|
const data = await response.json();
|
|
654
|
-
if (
|
|
655
|
-
throw new Error(
|
|
522
|
+
if (!isNamespaceMessages(data[locale])) {
|
|
523
|
+
throw new Error("JSON file does not match NamespaceMessages structure");
|
|
656
524
|
}
|
|
657
525
|
return data;
|
|
658
526
|
} catch (error) {
|
|
659
|
-
logger.warn(
|
|
527
|
+
logger.warn("Fetching locale messages failed.", {
|
|
660
528
|
locale,
|
|
661
|
-
|
|
529
|
+
remoteUrl,
|
|
662
530
|
searchParams: decodeURIComponent(searchParams.toString()),
|
|
663
531
|
error
|
|
664
532
|
});
|
|
@@ -666,30 +534,7 @@ var fetchMessages = async ({
|
|
|
666
534
|
}
|
|
667
535
|
};
|
|
668
536
|
|
|
669
|
-
// src/modules/messages/load-
|
|
670
|
-
var fetchFallbackMessages = async ({
|
|
671
|
-
apiUrl,
|
|
672
|
-
apiHeaders,
|
|
673
|
-
searchParams,
|
|
674
|
-
fallbackLocales,
|
|
675
|
-
logger
|
|
676
|
-
}) => {
|
|
677
|
-
for (const fallbackLocale of fallbackLocales) {
|
|
678
|
-
const result = await fetchMessages({
|
|
679
|
-
apiUrl,
|
|
680
|
-
searchParams,
|
|
681
|
-
locale: fallbackLocale,
|
|
682
|
-
apiHeaders,
|
|
683
|
-
logger
|
|
684
|
-
});
|
|
685
|
-
if (result) {
|
|
686
|
-
return { locale: fallbackLocale, messages: result };
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
return;
|
|
690
|
-
};
|
|
691
|
-
|
|
692
|
-
// src/modules/messages/load-api-messages/utils/build-search-params.ts
|
|
537
|
+
// src/modules/messages/load-remote-messages/fetch-locale-messages/utils/build-search-params.ts
|
|
693
538
|
var buildSearchParams = (params) => {
|
|
694
539
|
const searchParams = new URLSearchParams();
|
|
695
540
|
const appendParam = (key, value) => {
|
|
@@ -707,119 +552,130 @@ var buildSearchParams = (params) => {
|
|
|
707
552
|
return searchParams;
|
|
708
553
|
};
|
|
709
554
|
|
|
710
|
-
// src/modules/messages/load-
|
|
711
|
-
var
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
555
|
+
// src/modules/messages/load-remote-messages/load-remote-messages.ts
|
|
556
|
+
var loadRemoteMessages = async ({
|
|
557
|
+
pool = getGlobalMessagesPool(),
|
|
558
|
+
rootDir,
|
|
559
|
+
remoteUrl,
|
|
560
|
+
remoteHeaders,
|
|
715
561
|
locale,
|
|
716
562
|
fallbackLocales = [],
|
|
717
563
|
namespaces = [],
|
|
718
|
-
|
|
719
|
-
|
|
564
|
+
extraOptions: {
|
|
565
|
+
cacheOptions = DEFAULT_CACHE_OPTIONS,
|
|
566
|
+
loggerOptions = { id: "default" }
|
|
567
|
+
} = {}
|
|
720
568
|
}) => {
|
|
721
569
|
const baseLogger = getLogger({ ...loggerOptions });
|
|
722
|
-
const logger = baseLogger.child({ scope: "load-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
return;
|
|
726
|
-
}
|
|
727
|
-
let pool;
|
|
728
|
-
if (cache.enabled) {
|
|
729
|
-
pool = getGlobalMessagesPool();
|
|
730
|
-
}
|
|
570
|
+
const logger = baseLogger.child({ scope: "load-remote-messages" });
|
|
571
|
+
const start = performance.now();
|
|
572
|
+
logger.debug("Loading remote messages from api.", { remoteUrl });
|
|
731
573
|
const key = normalizeCacheKey([
|
|
732
574
|
loggerOptions.id,
|
|
733
|
-
|
|
575
|
+
"loaderType:remote",
|
|
576
|
+
rootDir,
|
|
734
577
|
locale,
|
|
735
578
|
(fallbackLocales ?? []).toSorted().join(","),
|
|
736
579
|
(namespaces ?? []).toSorted().join(",")
|
|
737
580
|
]);
|
|
738
|
-
if (
|
|
581
|
+
if (cacheOptions.enabled && key) {
|
|
739
582
|
const cached = await pool?.get(key);
|
|
740
583
|
if (cached) {
|
|
741
584
|
logger.debug("Messages cache hit.", { key });
|
|
742
585
|
return cached;
|
|
743
586
|
}
|
|
744
587
|
}
|
|
745
|
-
const searchParams = buildSearchParams({
|
|
746
|
-
const
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
588
|
+
const searchParams = buildSearchParams({ rootDir, namespaces });
|
|
589
|
+
const candidateLocales = [locale, ...fallbackLocales || []];
|
|
590
|
+
let messages;
|
|
591
|
+
for (const candidateLocale of candidateLocales) {
|
|
592
|
+
try {
|
|
593
|
+
const result = await fetchLocaleMessages({
|
|
594
|
+
remoteUrl,
|
|
595
|
+
remoteHeaders,
|
|
596
|
+
searchParams,
|
|
597
|
+
locale: candidateLocale,
|
|
598
|
+
extraOptions: { loggerOptions }
|
|
599
|
+
});
|
|
600
|
+
if (result && Object.values(result[candidateLocale] || {}).length > 0) {
|
|
601
|
+
messages = result;
|
|
602
|
+
break;
|
|
603
|
+
}
|
|
604
|
+
} catch (error) {
|
|
605
|
+
logger.error("Failed to fetch locale messages.", {
|
|
606
|
+
locale: candidateLocale,
|
|
607
|
+
error
|
|
608
|
+
});
|
|
756
609
|
}
|
|
757
|
-
return messages;
|
|
758
610
|
}
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
apiHeaders,
|
|
762
|
-
searchParams,
|
|
763
|
-
fallbackLocales,
|
|
764
|
-
logger: loggerOptions
|
|
765
|
-
});
|
|
766
|
-
if (fallbackResult) {
|
|
767
|
-
logger.info("Fallback locale succeeded.", {
|
|
768
|
-
usedLocale: fallbackResult.locale,
|
|
769
|
-
apiUrl,
|
|
770
|
-
searchParams: decodeURIComponent(searchParams.toString())
|
|
771
|
-
});
|
|
772
|
-
if (cache.enabled && key) {
|
|
773
|
-
await pool?.set(key, fallbackResult.messages, cache.ttl);
|
|
774
|
-
}
|
|
775
|
-
return fallbackResult.messages;
|
|
611
|
+
if (cacheOptions.enabled && key && messages) {
|
|
612
|
+
await pool?.set(key, messages, cacheOptions.ttl);
|
|
776
613
|
}
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
614
|
+
const end = performance.now();
|
|
615
|
+
const duration = Math.round(end - start);
|
|
616
|
+
logger.trace("Finished loading remote messages.", {
|
|
617
|
+
loadedLocale: messages ? Object.keys(messages)[0] : void 0,
|
|
618
|
+
duration: `${duration} ms`
|
|
780
619
|
});
|
|
781
|
-
return;
|
|
620
|
+
return messages;
|
|
782
621
|
};
|
|
783
622
|
|
|
784
623
|
// src/modules/messages/load-messages.ts
|
|
785
624
|
var loadMessages = async ({
|
|
786
625
|
config,
|
|
787
626
|
locale,
|
|
788
|
-
pathname
|
|
627
|
+
pathname = "",
|
|
628
|
+
extraOptions: { exts, messageFileReader } = {}
|
|
789
629
|
}) => {
|
|
790
630
|
const baseLogger = getLogger({ id: config.id, ...config.logger });
|
|
791
|
-
const logger = baseLogger.child({ scope: "messages
|
|
631
|
+
const logger = baseLogger.child({ scope: "load-messages" });
|
|
792
632
|
if (!config.loader) {
|
|
793
633
|
logger.warn(
|
|
794
634
|
"No loader options have been configured in the current config."
|
|
795
635
|
);
|
|
796
636
|
return;
|
|
797
637
|
}
|
|
798
|
-
const {
|
|
638
|
+
const { type, concurrency, rootDir } = config.loader;
|
|
799
639
|
const fallbackLocales = config.fallbackLocales[locale] || [];
|
|
800
640
|
const namespaces = resolveNamespaces({ config, pathname });
|
|
801
|
-
logger.
|
|
802
|
-
|
|
641
|
+
if (logger.core.level === "debug") {
|
|
642
|
+
logger.debug("Starting to load messages.", { locale });
|
|
643
|
+
}
|
|
644
|
+
logger.trace("Starting to load messages with runtime context.", {
|
|
645
|
+
loaderType: type,
|
|
646
|
+
locale,
|
|
647
|
+
fallbackLocales,
|
|
648
|
+
namespaces: namespaces && namespaces.length > 0 ? [...namespaces] : "[ALL]",
|
|
649
|
+
cache: config.cache,
|
|
650
|
+
concurrency: concurrency ?? 10
|
|
803
651
|
});
|
|
804
|
-
logger.debug("Loader type selected.", { loaderType: loader.type });
|
|
805
652
|
let loadedMessages;
|
|
806
|
-
if (
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
...loader,
|
|
653
|
+
if (type === "local") {
|
|
654
|
+
loadedMessages = await loadLocalMessages({
|
|
655
|
+
rootDir,
|
|
810
656
|
locale,
|
|
811
657
|
fallbackLocales,
|
|
812
658
|
namespaces,
|
|
813
|
-
|
|
814
|
-
|
|
659
|
+
extraOptions: {
|
|
660
|
+
concurrency,
|
|
661
|
+
cacheOptions: config.cache,
|
|
662
|
+
loggerOptions: { id: config.id, ...config.logger },
|
|
663
|
+
exts,
|
|
664
|
+
messageFileReader
|
|
665
|
+
}
|
|
815
666
|
});
|
|
816
|
-
} else if (
|
|
817
|
-
loadedMessages = await
|
|
818
|
-
|
|
667
|
+
} else if (type === "remote") {
|
|
668
|
+
loadedMessages = await loadRemoteMessages({
|
|
669
|
+
rootDir,
|
|
670
|
+
remoteUrl: config.loader.remoteUrl,
|
|
671
|
+
remoteHeaders: config.loader.remoteHeaders,
|
|
819
672
|
locale,
|
|
820
673
|
fallbackLocales,
|
|
821
674
|
namespaces,
|
|
822
|
-
|
|
675
|
+
extraOptions: {
|
|
676
|
+
cacheOptions: config.cache,
|
|
677
|
+
loggerOptions: { id: config.id, ...config.logger }
|
|
678
|
+
}
|
|
823
679
|
});
|
|
824
680
|
}
|
|
825
681
|
if (!loadedMessages || Object.keys(loadedMessages).length === 0) {
|
|
@@ -828,7 +684,7 @@ var loadMessages = async ({
|
|
|
828
684
|
return loadedMessages;
|
|
829
685
|
};
|
|
830
686
|
|
|
831
|
-
// src/modules/
|
|
687
|
+
// src/modules/translator/get-translator.ts
|
|
832
688
|
async function getTranslator(opts) {
|
|
833
689
|
const { config, locale, pathname = "", preKey, handlers } = opts;
|
|
834
690
|
const messages = await loadMessages({ config, locale, pathname });
|