intor 1.0.39 → 2.0.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 CHANGED
@@ -1,15 +1,28 @@
1
- import { logry } from 'logry';
2
- import { cookies, headers } from 'next/headers';
3
1
  import path from 'path';
4
2
  import { performance } from 'perf_hooks';
5
3
  import pLimit from 'p-limit';
6
4
  import fs from 'fs/promises';
7
- import { Translator } from 'intor-translator';
5
+ import { logry } from 'logry';
6
+ import Keyv from 'keyv';
8
7
  export { Translator } from 'intor-translator';
9
8
 
10
- // src/modules/intor/intor.ts
9
+ // src/modules/intor/utils/should-load-messages.ts
10
+ var shouldLoadMessages = (loader) => {
11
+ if (!loader) return false;
12
+ const { type, lazyLoad } = loader;
13
+ if (type === "import") return true;
14
+ if (lazyLoad) return false;
15
+ return true;
16
+ };
11
17
 
12
- // src/modules/intor-error/intor-error.ts
18
+ // src/modules/config/constants/cache.constants.ts
19
+ var DEFAULT_CACHE_OPTIONS = {
20
+ enabled: process.env.NODE_ENV === "production",
21
+ ttl: 60 * 60 * 1e3
22
+ // 1 hour
23
+ };
24
+
25
+ // src/shared/error/intor-error.ts
13
26
  var IntorError = class extends Error {
14
27
  constructor({ message, code, id }) {
15
28
  const fullMessage = id ? `[${id}] ${message}` : message;
@@ -21,218 +34,95 @@ var IntorError = class extends Error {
21
34
  }
22
35
  };
23
36
 
24
- // src/modules/intor-error/intor-error-types.ts
25
- var IntorErrorCode = /* @__PURE__ */ ((IntorErrorCode2) => {
26
- IntorErrorCode2["MISSING_DEFAULT_LOCALE"] = "INTOR_MISSING_DEFAULT_LOCALE";
27
- IntorErrorCode2["UNSUPPORTED_DEFAULT_LOCALE"] = "INTOR_UNSUPPORTED_DEFAULT_LOCALE";
28
- IntorErrorCode2["MISSING_SUPPORTED_LOCALES"] = "INTOR_MISSING_SUPPORTED_LOCALES";
29
- IntorErrorCode2["UNSUPPORTED_ADAPTER"] = "INTOR_UNSUPPORTED_ADAPTER";
30
- IntorErrorCode2["ADAPTER_RUNTIME_LOAD_FAILED"] = "INTOR_ADAPTER_RUNTIME_LOAD_FAILED";
31
- IntorErrorCode2["UNKNOWN_LOADER_TYPE"] = "INTOR_UNKNOWN_LOADER_TYPE";
32
- return IntorErrorCode2;
33
- })(IntorErrorCode || {});
34
-
35
- // src/adapters/next-client/constants/header-key-constants.ts
36
- var DEFAULT_PATHNAME_HEADER_NAME = "x-intor-pathname";
37
-
38
- // src/shared/utils/locale/normalize-locale.ts
39
- var normalizeLocale = (locale = "", supportedLocales = []) => {
40
- if (!locale || supportedLocales.length === 0) return void 0;
41
- const toCanonical = (input) => {
42
- try {
43
- return Intl.getCanonicalLocales(input)[0]?.toLowerCase();
44
- } catch {
45
- return void 0;
46
- }
47
- };
48
- const canonicalLocale = toCanonical(locale);
49
- if (!canonicalLocale) return void 0;
50
- const supportedCanonicalMap = /* @__PURE__ */ new Map();
51
- for (const l of supportedLocales) {
52
- const normalized = toCanonical(l);
53
- if (normalized) {
54
- supportedCanonicalMap.set(normalized, l);
55
- }
56
- }
57
- if (supportedCanonicalMap.has(canonicalLocale)) {
58
- return supportedCanonicalMap.get(canonicalLocale);
59
- }
60
- const baseLang = canonicalLocale.split("-")[0];
61
- for (const [key, original] of supportedCanonicalMap) {
62
- const supportedBase = key.split("-")[0];
63
- if (supportedBase === baseLang) {
64
- return original;
65
- }
66
- }
67
- return void 0;
68
- };
69
-
70
- // src/shared/utils/locale/resolve-preferred-locale.ts
71
- var resolvePreferredLocale = (acceptLanguageHeader, supportedLocales) => {
72
- if (!acceptLanguageHeader || !supportedLocales || supportedLocales.length === 0) {
73
- return;
74
- }
75
- const supportedLocalesSet = new Set(supportedLocales);
76
- const preferred = acceptLanguageHeader.split(",").map((part) => {
77
- const [lang, qValue] = part.split(";");
78
- const q = qValue ? parseFloat(qValue.split("=")[1]) : 1;
79
- if (isNaN(q)) {
80
- return { lang: lang.trim(), q: 0 };
81
- }
82
- return { lang: lang.trim(), q };
83
- }).sort((a, b) => b.q - a.q).find(({ lang }) => supportedLocalesSet.has(lang))?.lang;
84
- return preferred;
85
- };
86
-
87
- // src/adapters/next-client/next-client-runtime/next-client-runtime.ts
88
- var nextClientRuntime = async ({
89
- config
90
- }) => {
91
- const cookiesStore = await cookies();
92
- const headersStore = await headers();
93
- const logger = logry({ id: config.id, scope: "nextClientRuntime" });
94
- const { defaultLocale, supportedLocales = [], cookie, routing } = config;
95
- let locale;
96
- if (!cookie.disabled) {
97
- const localeFromCookie = cookiesStore.get(cookie.name)?.value;
98
- locale = normalizeLocale(localeFromCookie, supportedLocales);
99
- if (locale) {
100
- logger.debug("Get locale from cookie:", { locale });
101
- }
102
- }
103
- if (!locale && routing.firstVisit.localeSource === "browser") {
104
- const aLHeader = headersStore.get("accept-language") || void 0;
105
- const preferredLocale = resolvePreferredLocale(aLHeader, supportedLocales);
106
- locale = normalizeLocale(preferredLocale, supportedLocales);
107
- logger.debug("Get locale from browser:", { locale });
108
- }
109
- const pathname = headersStore.get(DEFAULT_PATHNAME_HEADER_NAME);
110
- if (pathname) {
111
- logger.debug("Get pathname from next headers:", { pathname });
112
- }
113
- return {
114
- locale: locale || defaultLocale,
115
- pathname: pathname || ""
116
- };
117
- };
118
- var nextServerRuntime = async ({
119
- config,
120
- request
121
- }) => {
122
- const cookiesStore = await cookies();
123
- const headersStore = await headers();
124
- const logger = logry({ id: config.id, scope: "nextServerRuntime" });
125
- const { defaultLocale, supportedLocales = [], cookie, routing } = config;
126
- let locale;
127
- if (!cookie.disabled) {
128
- const localeFromCookie = cookiesStore.get(cookie.name)?.value;
129
- locale = normalizeLocale(localeFromCookie, supportedLocales);
130
- if (locale) {
131
- logger.debug("Get locale from cookie:", { locale });
132
- }
133
- }
134
- if (!locale && routing.firstVisit.localeSource === "browser") {
135
- const aLHeader = headersStore.get("accept-language") || void 0;
136
- const preferredLocale = resolvePreferredLocale(aLHeader, supportedLocales);
137
- locale = normalizeLocale(preferredLocale, supportedLocales);
138
- logger.debug("Get locale from browser:", { locale });
139
- }
140
- let pathname = "";
141
- if (request && typeof request === "object" && "nextUrl" in request) {
142
- pathname = request.nextUrl.pathname;
143
- if (pathname) {
144
- logger.debug("Get pathname from next request:", { pathname });
145
- }
146
- }
147
- if (!pathname) {
148
- pathname = headersStore.get(DEFAULT_PATHNAME_HEADER_NAME);
149
- if (pathname) {
150
- logger.debug("Get pathname from next headers:", { pathname });
151
- }
152
- }
153
- if (!cookie.disabled && cookie.autoSetCookie) {
154
- cookiesStore.set({
155
- name: cookie.name,
156
- value: locale || defaultLocale,
157
- ...cookie.domain ? { domain: cookie.domain } : {},
158
- path: cookie.path,
159
- maxAge: cookie.maxAge,
160
- httpOnly: cookie.httpOnly,
161
- secure: cookie.secure,
162
- sameSite: cookie.sameSite
163
- });
164
- logger.debug("Set locale to cookie:", {
165
- cookie: { name: cookie.name, value: locale || defaultLocale }
166
- });
167
- }
168
- return {
169
- locale: locale || defaultLocale,
170
- pathname: pathname || ""
171
- };
172
- };
173
-
174
- // src/modules/intor-adapter/resolve-adapter-runtime-loader.ts
175
- var resolceAdapterRuntimeLoader = async ({
176
- config
177
- }) => {
178
- const { adapter } = config;
179
- let loadedRuntime;
180
- if (adapter === "next-client") {
181
- loadedRuntime = nextClientRuntime;
182
- } else if (adapter === "next-server") {
183
- loadedRuntime = nextServerRuntime;
184
- }
185
- return loadedRuntime;
186
- };
187
-
188
- // src/modules/intor-config/types/intor-adapter-types.ts
189
- var intorAdapters = ["next-client", "next-server"];
190
- var readMessageRecordFile = async (filePath) => {
37
+ // src/modules/messages/load-local-messages/utils/read-message-record-file.ts
38
+ var readMessageRecordFile = async (filePath, loggerOptions) => {
191
39
  const fileName = path.basename(filePath, ".json");
192
40
  const content = await fs.readFile(filePath, "utf-8");
193
41
  const parsed = JSON.parse(content);
194
42
  if (typeof parsed !== "object" || parsed === null) {
195
- throw new Error(`Invalid message format`);
43
+ throw new IntorError({
44
+ id: loggerOptions.id,
45
+ code: "INTOR_INVALID_MESSAGE_FORMAT" /* INVALID_MESSAGE_FORMAT */,
46
+ message: "Invalid message format"
47
+ });
196
48
  }
197
49
  return { fileName, content: parsed };
198
50
  };
199
51
 
200
- // src/modules/intor-messages-loader/load-local-messages/load-namespace-group/parse-message-file.ts
52
+ // src/shared/logger/global-logger-pool.ts
53
+ function getGlobalLoggerPool() {
54
+ if (!globalThis.__INTOR_LOGGER_POOL__) {
55
+ globalThis.__INTOR_LOGGER_POOL__ = /* @__PURE__ */ new Map();
56
+ }
57
+ return globalThis.__INTOR_LOGGER_POOL__;
58
+ }
59
+ function clearLoggerPool() {
60
+ const pool = getGlobalLoggerPool();
61
+ pool.clear();
62
+ }
63
+
64
+ // src/shared/logger/get-logger.ts
65
+ var DEFAULT_FORMATTER_CONFIG = {
66
+ node: { meta: { compact: true }, lineBreaksAfter: 1 }
67
+ };
68
+ function getLogger({
69
+ id,
70
+ formatterConfig = DEFAULT_FORMATTER_CONFIG,
71
+ ...options
72
+ }) {
73
+ const pool = getGlobalLoggerPool();
74
+ let logger = pool.get(id);
75
+ if (!logger) {
76
+ logger = logry({ id, formatterConfig, ...options });
77
+ pool.set(id, logger);
78
+ if (pool.size > 1e3) {
79
+ const keys = Array.from(pool.keys());
80
+ for (const key of keys.slice(0, 200)) pool.delete(key);
81
+ }
82
+ }
83
+ return logger;
84
+ }
85
+
86
+ // src/modules/messages/load-local-messages/load-namespace-group/parse-message-file.ts
201
87
  var MAX_PATH_LENGTH = 260;
202
- var parseMessageFile = async (filePath, loggerId) => {
203
- const logger = logry({ id: loggerId, scope: "parseMessageFile" });
88
+ var parseMessageFile = async (filePath, loggerOptions) => {
89
+ const baseLogger = getLogger({ ...loggerOptions });
90
+ const logger = baseLogger.child({ scope: "parse-message-file" });
204
91
  const trimmedPath = filePath.trim();
205
92
  if (!trimmedPath) {
206
- logger?.warn("Invalid file path provided.", { filePath: trimmedPath });
93
+ logger.warn("File path is empty.", { filePath: trimmedPath });
207
94
  return null;
208
95
  }
209
96
  if (trimmedPath.length > MAX_PATH_LENGTH) {
210
- logger?.warn("Invalid file path provided.", { filePath: trimmedPath });
97
+ logger.warn("File path exceeds maximum length.", { filePath: trimmedPath });
211
98
  return null;
212
99
  }
213
100
  const fileName = path.basename(trimmedPath);
214
101
  if (!fileName.toLowerCase().endsWith(".json")) {
215
- logger?.debug(`Skipped non-JSON file.`, { filePath: trimmedPath });
102
+ logger.trace("Skipped non-JSON file.", { filePath: trimmedPath });
216
103
  return null;
217
104
  }
218
105
  try {
219
- const { content } = await readMessageRecordFile(trimmedPath);
220
- logger?.debug(`Loaded a file.`, { filePath: trimmedPath });
106
+ const { content } = await readMessageRecordFile(trimmedPath, loggerOptions);
107
+ logger.trace(`Message file loaded.`, { filePath: trimmedPath });
221
108
  return content;
222
109
  } catch (error) {
223
- logger?.warn(`Failed to load file.`, { filePath: trimmedPath, error });
110
+ logger.warn("Failed to parse message file.", {
111
+ filePath: trimmedPath,
112
+ error
113
+ });
224
114
  return null;
225
115
  }
226
116
  };
227
117
 
228
- // src/modules/intor-messages-loader/load-local-messages/load-namespace-group/merge-namespace-messages.ts
229
- var mergeNamespaceMessages = async (filePaths, isAtRoot, loggerId) => {
118
+ // src/modules/messages/load-local-messages/load-namespace-group/merge-namespace-messages.ts
119
+ var mergeNamespaceMessages = async (filePaths, isAtRoot, loggerOptions) => {
230
120
  const baseContent = {};
231
121
  const subEntries = {};
232
122
  await Promise.all(
233
123
  filePaths.map(async (filePath) => {
234
124
  const fileName = path.basename(filePath);
235
- const content = await parseMessageFile(filePath, loggerId);
125
+ const content = await parseMessageFile(filePath, loggerOptions);
236
126
  if (!content) {
237
127
  return;
238
128
  }
@@ -247,20 +137,21 @@ var mergeNamespaceMessages = async (filePaths, isAtRoot, loggerId) => {
247
137
  return { base: baseContent, sub: subEntries };
248
138
  };
249
139
 
250
- // src/modules/intor-messages-loader/load-local-messages/load-namespace-group/load-namespace-group.ts
140
+ // src/modules/messages/load-local-messages/load-namespace-group/load-namespace-group.ts
251
141
  var loadNamespaceGroup = async ({
252
142
  locale,
253
143
  namespace,
254
144
  messages,
255
145
  namespaceGroupValue,
256
146
  limit,
257
- loggerId
147
+ logger: loggerOptions = { id: "default" }
258
148
  }) => {
259
- const logger = logry({ id: loggerId, scope: "loadNamespaceGroup" });
149
+ const baseLogger = getLogger({ ...loggerOptions });
150
+ const logger = baseLogger.child({ scope: "load-namespace-group" });
260
151
  const { isAtRoot, filePaths } = namespaceGroupValue;
261
152
  if (filePaths.length === 0) {
262
- logger?.debug?.(
263
- `Skipped merging [${locale}][${namespace}] because filePaths is empty`
153
+ logger.trace(
154
+ `Skipped merging ${locale}/${namespace} because filePaths is empty`
264
155
  );
265
156
  return;
266
157
  }
@@ -268,15 +159,19 @@ var loadNamespaceGroup = async ({
268
159
  const { base, sub } = await mergeNamespaceMessages(
269
160
  filePaths,
270
161
  isAtRoot,
271
- loggerId
162
+ loggerOptions
272
163
  );
273
164
  if (!messages[locale]) {
274
165
  messages[locale] = {};
275
166
  }
167
+ if (isAtRoot && filePaths.length === 1 && path.basename(filePaths[0]) === "index.json") {
168
+ messages[locale] = { ...messages[locale], ...base };
169
+ return;
170
+ }
276
171
  const finalContent = isAtRoot ? base : { ...base, ...sub };
277
172
  messages[locale][namespace] = finalContent;
278
173
  if (!isAtRoot && Object.keys(finalContent).length > 0) {
279
- logger?.debug(
174
+ logger.trace(
280
175
  `Merged ${locale}/${namespace} from ${filePaths.length} file(s)`,
281
176
  { namespace }
282
177
  );
@@ -309,15 +204,17 @@ var addToNamespaceGroup = ({
309
204
  }
310
205
  };
311
206
 
312
- // src/modules/intor-messages-loader/load-local-messages/prepare-namespace-groups/traverse-directory.ts
207
+ // src/modules/messages/load-local-messages/prepare-namespace-groups/traverse-directory.ts
313
208
  var traverseDirectory = async ({
314
209
  options,
315
210
  currentDirPath,
316
211
  namespaceGroups,
317
212
  namespacePathSegments
318
213
  }) => {
319
- const { limit, loggerId } = options;
320
- const logger = logry({ id: loggerId, scope: "traverseDirectory" });
214
+ const { limit } = options;
215
+ const loggerOptions = options.logger || { id: "default" };
216
+ const baseLogger = getLogger({ ...loggerOptions });
217
+ const logger = baseLogger.child({ scope: "traverse-directory" });
321
218
  try {
322
219
  const dirents = await fs.readdir(currentDirPath, { withFileTypes: true });
323
220
  const dirPromises = dirents.map(
@@ -353,7 +250,7 @@ var traverseDirectory = async ({
353
250
  }
354
251
  };
355
252
 
356
- // src/modules/intor-messages-loader/load-local-messages/prepare-namespace-groups/prepare-namespace-groups.ts
253
+ // src/modules/messages/load-local-messages/prepare-namespace-groups/prepare-namespace-groups.ts
357
254
  var prepareNamespaceGroups = async (options) => {
358
255
  const { basePath } = options;
359
256
  const namespaceGroups = /* @__PURE__ */ new Map();
@@ -366,16 +263,17 @@ var prepareNamespaceGroups = async (options) => {
366
263
  return namespaceGroups;
367
264
  };
368
265
 
369
- // src/modules/intor-messages-loader/load-local-messages/load-single-locale/load-single-locale.ts
266
+ // src/modules/messages/load-local-messages/load-single-locale/load-single-locale.ts
370
267
  var loadSingleLocale = async ({
371
268
  basePath,
372
269
  locale,
373
270
  namespaces,
374
271
  messages,
375
272
  limit,
376
- loggerId
273
+ logger: loggerOptions = { id: "default" }
377
274
  }) => {
378
- const logger = logry({ id: loggerId, scope: "loadSingleLocale" });
275
+ const baseLogger = getLogger({ ...loggerOptions });
276
+ const logger = baseLogger.child({ scope: "load-single-locale" });
379
277
  const localePath = path.join(basePath, locale);
380
278
  const validNamespaces = [];
381
279
  try {
@@ -388,14 +286,14 @@ var loadSingleLocale = async ({
388
286
  return;
389
287
  }
390
288
  } catch (error) {
391
- logger.warn("Error checking locale path:", { locale, error });
289
+ logger.warn("Error checking locale path.", { locale, error });
392
290
  return;
393
291
  }
394
292
  const namespaceGroups = await prepareNamespaceGroups({
395
293
  basePath: localePath,
396
294
  limit,
397
295
  namespaces: new Set(namespaces || []),
398
- loggerId
296
+ logger: loggerOptions
399
297
  });
400
298
  if (namespaceGroups.size === 0) {
401
299
  logger.warn("No namespace groups found.", {
@@ -405,7 +303,7 @@ var loadSingleLocale = async ({
405
303
  });
406
304
  return;
407
305
  }
408
- logger.debug("Prepared namespace groups from scanning local files:", {
306
+ logger.trace("Prepared namespace groups from scanning local files.", {
409
307
  namespaceGroups: [...namespaceGroups.entries()].map(([ns, val]) => ({
410
308
  namespace: ns,
411
309
  isAtRoot: val.isAtRoot,
@@ -421,14 +319,14 @@ var loadSingleLocale = async ({
421
319
  messages,
422
320
  namespaceGroupValue,
423
321
  limit,
424
- loggerId
322
+ logger: loggerOptions
425
323
  }).then(() => validNamespaces.push(namespace))
426
324
  );
427
325
  await Promise.all(namespaceGroupTasks);
428
326
  return validNamespaces;
429
327
  };
430
328
 
431
- // src/modules/intor-messages-loader/load-local-messages/load-locale-with-fallback/load-locale-with-fallback.ts
329
+ // src/modules/messages/load-local-messages/load-locale-with-fallback/load-locale-with-fallback.ts
432
330
  var loadLocaleWithFallback = async ({
433
331
  basePath,
434
332
  locale: targetLocale,
@@ -436,9 +334,10 @@ var loadLocaleWithFallback = async ({
436
334
  namespaces,
437
335
  messages,
438
336
  limit,
439
- loggerId
337
+ logger: loggerOptions = { id: "default" }
440
338
  }) => {
441
- const logger = logry({ id: loggerId, scope: "loadLocaleWithFallback" });
339
+ const baseLogger = getLogger({ ...loggerOptions });
340
+ const logger = baseLogger.child({ scope: "load-locale-with-fallback" });
442
341
  const localesToTry = [targetLocale, ...fallbackLocales];
443
342
  for (const locale of localesToTry) {
444
343
  try {
@@ -448,7 +347,7 @@ var loadLocaleWithFallback = async ({
448
347
  namespaces,
449
348
  messages,
450
349
  limit,
451
- loggerId
350
+ logger: loggerOptions
452
351
  });
453
352
  return validNamespaces;
454
353
  } catch (error) {
@@ -461,14 +360,155 @@ var loadLocaleWithFallback = async ({
461
360
  logger.warn("All fallback locales failed.", {
462
361
  attemptedLocales: localesToTry
463
362
  });
464
- return void 0;
363
+ return;
364
+ };
365
+ function getGlobalMessagesPool() {
366
+ if (!globalThis.__INTOR_MESSAGES_POOL__) {
367
+ globalThis.__INTOR_MESSAGES_POOL__ = new Keyv();
368
+ }
369
+ return globalThis.__INTOR_MESSAGES_POOL__;
370
+ }
371
+ function clearMessagesPool() {
372
+ const pool = getGlobalMessagesPool();
373
+ pool.clear();
374
+ }
375
+
376
+ // src/shared/utils/merge-messages.ts
377
+ var mergeMessages = (staticMessages = {}, loadedMessages = {}) => {
378
+ const result = Object.keys(staticMessages).length ? { ...staticMessages } : {};
379
+ for (const locale in loadedMessages) {
380
+ const loaded = loadedMessages[locale];
381
+ if (!result[locale]) {
382
+ result[locale] = loaded;
383
+ continue;
384
+ }
385
+ result[locale] = {
386
+ ...result[locale],
387
+ ...loaded
388
+ };
389
+ }
390
+ return result;
391
+ };
392
+
393
+ // src/shared/utils/normalize-cache-key.ts
394
+ var CACHE_KEY_DELIMITER = "|";
395
+ var sanitize = (k) => k.replaceAll(/[\u200B-\u200D\uFEFF]/g, "").replaceAll(/[\r\n]/g, "").trim();
396
+ var normalizeCacheKey = (key, delimiter = CACHE_KEY_DELIMITER) => {
397
+ if (!key) return null;
398
+ if (Array.isArray(key)) {
399
+ if (key.length === 0) return null;
400
+ const normalized = key.map((k) => {
401
+ if (k === null) return "__null";
402
+ if (k === void 0) return "__undefined";
403
+ if (typeof k === "boolean") return k ? "__true" : "__false";
404
+ return sanitize(String(k));
405
+ });
406
+ return normalized.join(delimiter);
407
+ }
408
+ if (typeof key === "boolean") return key ? "__true" : "__false";
409
+ return String(key);
410
+ };
411
+
412
+ // src/shared/constants/prefix-placeholder.ts
413
+ var PREFIX_PLACEHOLDER = "{locale}";
414
+
415
+ // src/shared/utils/resolve-namespaces.ts
416
+ var resolveNamespaces = ({
417
+ config,
418
+ pathname
419
+ }) => {
420
+ const { loader } = config;
421
+ const {
422
+ routeNamespaces = {},
423
+ namespaces: fallbackNamespaces
424
+ } = loader;
425
+ const { unprefixedPathname } = extractPathname({ config, pathname });
426
+ const standardizedPathname = standardizePathname({
427
+ config,
428
+ pathname: unprefixedPathname
429
+ });
430
+ const placeholderRemovedPathname = standardizedPathname.replace(
431
+ `/${PREFIX_PLACEHOLDER}`,
432
+ ""
433
+ );
434
+ const defaultNamespaces = routeNamespaces.default ?? [];
435
+ const exactMatchNamespaces = routeNamespaces[standardizedPathname] ?? routeNamespaces[placeholderRemovedPathname];
436
+ if (exactMatchNamespaces) {
437
+ return [...defaultNamespaces, ...exactMatchNamespaces];
438
+ }
439
+ let bestMatch = "";
440
+ let bestNamespaces;
441
+ const prefixPatterns = Object.keys(routeNamespaces).filter(
442
+ (pattern) => pattern.endsWith("/*")
443
+ );
444
+ for (const pattern of prefixPatterns) {
445
+ const basePath = pattern.replace(/\/\*$/, "");
446
+ if (standardizedPathname.startsWith(basePath)) {
447
+ if (basePath.length > bestMatch.length) {
448
+ bestMatch = basePath;
449
+ bestNamespaces = routeNamespaces[pattern];
450
+ }
451
+ }
452
+ }
453
+ const matchedNamespaces = bestNamespaces ?? routeNamespaces["/*"] ?? fallbackNamespaces ?? [];
454
+ if (matchedNamespaces.length > 0) {
455
+ return [...defaultNamespaces, ...matchedNamespaces];
456
+ } else {
457
+ return [...defaultNamespaces];
458
+ }
459
+ };
460
+
461
+ // src/shared/utils/locale/normalize-locale.ts
462
+ var normalizeLocale = (locale = "", supportedLocales = []) => {
463
+ if (!locale || supportedLocales.length === 0) return;
464
+ const toCanonical = (input) => {
465
+ try {
466
+ return Intl.getCanonicalLocales(input)[0]?.toLowerCase();
467
+ } catch {
468
+ return;
469
+ }
470
+ };
471
+ const canonicalLocale = toCanonical(locale);
472
+ if (!canonicalLocale) return;
473
+ const supportedCanonicalMap = /* @__PURE__ */ new Map();
474
+ for (const l of supportedLocales) {
475
+ const normalized = toCanonical(l);
476
+ if (normalized) {
477
+ supportedCanonicalMap.set(normalized, l);
478
+ }
479
+ }
480
+ if (supportedCanonicalMap.has(canonicalLocale)) {
481
+ return supportedCanonicalMap.get(canonicalLocale);
482
+ }
483
+ const baseLang = canonicalLocale.split("-")[0];
484
+ for (const [key, original] of supportedCanonicalMap) {
485
+ const supportedBase = key.split("-")[0];
486
+ if (supportedBase === baseLang) {
487
+ return original;
488
+ }
489
+ }
490
+ return;
491
+ };
492
+
493
+ // src/shared/utils/locale/resolve-preferred-locale.ts
494
+ var resolvePreferredLocale = (acceptLanguageHeader, supportedLocales) => {
495
+ if (!acceptLanguageHeader || !supportedLocales || supportedLocales.length === 0) {
496
+ return;
497
+ }
498
+ const supportedLocalesSet = new Set(supportedLocales);
499
+ const preferred = acceptLanguageHeader.split(",").map((part) => {
500
+ const [lang, qValue] = part.split(";");
501
+ const q = qValue ? parseFloat(qValue.split("=")[1]) : 1;
502
+ if (isNaN(q)) {
503
+ return { lang: lang.trim(), q: 0 };
504
+ }
505
+ return { lang: lang.trim(), q };
506
+ }).sort((a, b) => b.q - a.q).find(({ lang }) => supportedLocalesSet.has(lang))?.lang;
507
+ return preferred;
465
508
  };
466
509
 
467
510
  // src/shared/utils/pathname/normalize-pathname.ts
468
511
  var normalizePathname = (rawPathname, options = {}) => {
469
- if (typeof rawPathname !== "string") {
470
- throw new TypeError("Expected rawPathname to be a string");
471
- }
472
512
  const length = rawPathname.length;
473
513
  let start = 0;
474
514
  let end = length - 1;
@@ -498,33 +538,101 @@ var normalizePathname = (rawPathname, options = {}) => {
498
538
  return result || "/";
499
539
  };
500
540
 
501
- // src/modules/intor-messages-loader/load-local-messages/load-local-messages.ts
541
+ // src/shared/utils/pathname/extract-pathname.ts
542
+ var extractPathname = ({
543
+ config,
544
+ pathname: rawPathname
545
+ }) => {
546
+ const { routing, defaultLocale } = config;
547
+ const { basePath, prefix } = routing;
548
+ const normalizedPathname = normalizePathname(rawPathname);
549
+ let prefixedPathname = normalizedPathname;
550
+ if (basePath && normalizedPathname.startsWith(basePath + "/")) {
551
+ prefixedPathname = normalizedPathname.slice(basePath.length) || "/";
552
+ } else if (basePath && normalizedPathname === basePath) {
553
+ prefixedPathname = "/";
554
+ }
555
+ const pathParts = prefixedPathname.split("/").filter(Boolean);
556
+ const maybeLocale = pathParts[0] || "";
557
+ const isLocalePrefixed = config.supportedLocales?.includes(maybeLocale);
558
+ let unprefixedPathname = prefixedPathname;
559
+ if (prefix === "all") {
560
+ if (isLocalePrefixed) {
561
+ unprefixedPathname = prefixedPathname.slice(maybeLocale.length + 1) || "/";
562
+ }
563
+ } else if (prefix === "except-default") {
564
+ if (maybeLocale && maybeLocale !== defaultLocale && isLocalePrefixed) {
565
+ unprefixedPathname = prefixedPathname.slice(maybeLocale.length + 1) || "/";
566
+ }
567
+ }
568
+ return {
569
+ basePath,
570
+ prefixedPathname,
571
+ unprefixedPathname,
572
+ maybeLocale,
573
+ isLocalePrefixed: Boolean(isLocalePrefixed)
574
+ };
575
+ };
576
+
577
+ // src/shared/utils/pathname/standardize-pathname.ts
578
+ var standardizePathname = ({
579
+ config,
580
+ pathname
581
+ }) => {
582
+ const { routing } = config;
583
+ const { basePath } = routing;
584
+ const parts = [
585
+ normalizePathname(basePath),
586
+ PREFIX_PLACEHOLDER,
587
+ normalizePathname(pathname)
588
+ ];
589
+ const standardizedPathname = parts.join("/").replace(/\/{2,}/g, "/");
590
+ return normalizePathname(standardizedPathname);
591
+ };
592
+
593
+ // src/modules/messages/load-local-messages/load-local-messages.ts
502
594
  var loadLocalMessages = async ({
503
- basePath = "messages",
595
+ basePath,
504
596
  locale,
505
597
  fallbackLocales,
506
598
  namespaces,
507
599
  concurrency = 10,
508
- loggerId
600
+ cache = DEFAULT_CACHE_OPTIONS,
601
+ logger: loggerOptions = { id: "default" }
509
602
  }) => {
510
- if (!locale || locale.trim() === "") {
511
- return {};
512
- }
513
- const logger = logry({ id: loggerId, scope: "loadLocalMessages" });
603
+ basePath = basePath ?? "messages";
604
+ if (!locale || locale.trim() === "") return {};
605
+ const baseLogger = getLogger({ ...loggerOptions });
606
+ const logger = baseLogger.child({ scope: "load-locale-messages" });
607
+ const messages = {};
514
608
  const resolvedBasePath = path.resolve(
515
609
  process.cwd(),
516
610
  normalizePathname(basePath, { removeLeadingSlash: true })
517
611
  );
518
- const messages = {};
519
- const limit = pLimit(concurrency);
520
612
  const start = performance.now();
521
- logger.debug("Starting to load local messages with configuration:", {
613
+ logger.trace("Starting to load local messages with configuration.", {
522
614
  path: { basePath, resolvedBasePath },
523
615
  locale,
524
616
  fallbackLocales,
525
- namespaces: namespaces && namespaces.length > 0 ? { count: namespaces?.length, list: [...namespaces] } : "All",
617
+ namespaces: namespaces && namespaces.length > 0 ? { count: namespaces?.length, list: [...namespaces] } : "All Namespaces",
526
618
  concurrency
527
619
  });
620
+ const pool = getGlobalMessagesPool();
621
+ const key = normalizeCacheKey([
622
+ loggerOptions.id,
623
+ resolvedBasePath,
624
+ locale,
625
+ [...fallbackLocales ?? []].sort().join(","),
626
+ [...namespaces ?? []].sort().join(",")
627
+ ]);
628
+ if (cache.enabled && key) {
629
+ const cached = await pool.get(key);
630
+ if (cached) {
631
+ logger.debug("Messages cache hit.", { key });
632
+ return cached;
633
+ }
634
+ }
635
+ const limit = pLimit(concurrency);
528
636
  const validNamespaces = await loadLocaleWithFallback({
529
637
  basePath: resolvedBasePath,
530
638
  locale,
@@ -532,431 +640,261 @@ var loadLocalMessages = async ({
532
640
  namespaces,
533
641
  messages,
534
642
  limit,
535
- loggerId
643
+ logger: loggerOptions
536
644
  });
645
+ if (cache.enabled && key) {
646
+ await pool.set(key, messages, cache.ttl);
647
+ }
537
648
  const end = performance.now();
538
649
  const duration = Math.round(end - start);
539
- if (validNamespaces && validNamespaces?.length > 0) {
540
- logger.info("Finished loading local messages.", {
541
- locale,
542
- namespaces: validNamespaces,
543
- duration: `${duration} ms`
544
- });
545
- } else {
546
- logger.warn("No valid namespaces found for the locale.", {
547
- locale,
548
- namespaces: validNamespaces,
549
- duration: `${duration} ms`
550
- });
551
- }
650
+ logger.trace("Finished loading local messages.", {
651
+ locale,
652
+ validNamespaces,
653
+ duration: `${duration} ms`
654
+ });
552
655
  return messages;
553
656
  };
554
657
 
555
- // src/modules/intor-messages-loader/create-local-messages-loader/create-local-messages-loader.ts
556
- var createLocalMessagesLoader = (basePath) => {
658
+ // src/modules/messages/create-load-local-messages.ts
659
+ var createLoadLocalMessages = (basePath) => {
557
660
  return (options) => loadLocalMessages({ basePath, ...options });
558
661
  };
559
662
 
560
- // src/modules/intor-messages-loader/fetch-api-messages/build-search-params.ts
561
- var buildSearchParams = (params) => {
562
- const searchParams = new URLSearchParams();
563
- const appendParam = (key, value) => {
564
- if (value === void 0 || value === null) {
565
- return;
566
- }
567
- if (Array.isArray(value) && value.length > 0) {
568
- value.forEach((v) => v && searchParams.append(key, v));
569
- } else {
570
- searchParams.append(key, value);
571
- }
572
- };
573
- Object.entries(params).forEach(([key, value]) => {
574
- appendParam(key, value);
575
- });
576
- return searchParams;
577
- };
578
- var fetcher = async ({
663
+ // src/modules/messages/load-api-messages/fetch-messages.ts
664
+ var fetchMessages = async ({
579
665
  apiUrl,
666
+ apiHeaders,
580
667
  locale,
581
668
  searchParams,
582
- loggerId
669
+ logger: loggerOptions = { id: "default" }
583
670
  }) => {
584
- const logger = logry({ id: loggerId, scope: "fetcher" });
671
+ const baseLogger = getLogger({ ...loggerOptions });
672
+ const logger = baseLogger.child({ scope: "fetch-messages" });
585
673
  try {
586
674
  const params = new URLSearchParams(searchParams);
587
675
  params.append("locale", locale);
588
676
  const url = `${apiUrl}?${params.toString()}`;
677
+ const headers = {
678
+ "Content-Type": "application/json",
679
+ ...apiHeaders
680
+ };
589
681
  const response = await fetch(url, {
590
682
  method: "GET",
591
- headers: { "Content-Type": "application/json" },
683
+ headers,
592
684
  cache: "no-store"
593
685
  });
594
686
  if (!response.ok) {
595
- throw new Error(
596
- `Fetch failed for locale "${locale}" at URL: ${url} - ${response.status} ${response.statusText}`
597
- );
687
+ throw new Error(`Fetch failed: ${locale} (${response.status})`);
598
688
  }
599
689
  const data = await response.json();
600
690
  if (data == null || typeof data === "object" && Object.keys(data).length === 0) {
601
- throw new Error(
602
- `Missing or invalid messages for locale "${locale}" at URL: ${url}`
603
- );
691
+ throw new Error(`Invalid messages: ${locale}`);
604
692
  }
605
693
  return data;
606
- } catch {
694
+ } catch (error) {
607
695
  logger.warn(`Failed to fetch messages for locale "${locale}".`, {
608
696
  locale,
609
697
  apiUrl,
610
- searchParams: decodeURIComponent(searchParams.toString())
698
+ searchParams: decodeURIComponent(searchParams.toString()),
699
+ error
611
700
  });
612
- return void 0;
701
+ return;
613
702
  }
614
703
  };
615
704
 
616
- // src/modules/intor-messages-loader/fetch-api-messages/fetch-fallback-messages.ts
617
- var fetchFallbackMessages = async (apiUrl, searchParams, fallbackLocales, loggerId) => {
705
+ // src/modules/messages/load-api-messages/fetch-fallback-messages.ts
706
+ var fetchFallbackMessages = async ({
707
+ apiUrl,
708
+ apiHeaders,
709
+ searchParams,
710
+ fallbackLocales,
711
+ logger
712
+ }) => {
618
713
  for (const fallbackLocale of fallbackLocales) {
619
- const result = await fetcher({
714
+ const result = await fetchMessages({
620
715
  apiUrl,
621
716
  searchParams,
622
717
  locale: fallbackLocale,
623
- loggerId
718
+ apiHeaders,
719
+ logger
624
720
  });
625
721
  if (result) {
626
722
  return { locale: fallbackLocale, messages: result };
627
723
  }
628
724
  }
629
- return void 0;
725
+ return;
726
+ };
727
+
728
+ // src/modules/messages/load-api-messages/utils/build-search-params.ts
729
+ var buildSearchParams = (params) => {
730
+ const searchParams = new URLSearchParams();
731
+ const appendParam = (key, value) => {
732
+ if (value === void 0 || value === null) return;
733
+ if (Array.isArray(value) && value.length === 0) return;
734
+ if (Array.isArray(value)) {
735
+ value.forEach((v) => v && searchParams.append(key, v));
736
+ } else {
737
+ searchParams.append(key, value);
738
+ }
739
+ };
740
+ Object.entries(params).forEach(([key, value]) => {
741
+ appendParam(key, value);
742
+ });
743
+ return searchParams;
630
744
  };
631
745
 
632
- // src/modules/intor-messages-loader/fetch-api-messages/fetch-api-messages.ts
633
- var fetchApiMessages = async ({
746
+ // src/modules/messages/load-api-messages/load-api-messages.ts
747
+ var loadApiMessages = async ({
634
748
  apiUrl,
749
+ apiHeaders,
635
750
  basePath,
636
751
  locale,
637
752
  fallbackLocales = [],
638
753
  namespaces = [],
639
- loggerId
754
+ cache = DEFAULT_CACHE_OPTIONS,
755
+ logger: loggerOptions = { id: "default" }
640
756
  }) => {
641
- const logger = logry({ id: loggerId, scope: "fetchApiMessages" });
757
+ const baseLogger = getLogger({ ...loggerOptions });
758
+ const logger = baseLogger.child({ scope: "load-api-messages" });
642
759
  if (!apiUrl) {
643
- logger.warn("No apiUrl provided for fetchApiMessages. Skipping fetch.");
644
- return void 0;
760
+ logger.warn("No apiUrl provided. Skipping fetch.");
761
+ return;
645
762
  }
646
- const searchParams = buildSearchParams({
763
+ const pool = getGlobalMessagesPool();
764
+ const key = normalizeCacheKey([
765
+ loggerOptions.id,
647
766
  basePath,
648
- loggerId,
649
- namespaces
650
- });
651
- const messages = await fetcher({
767
+ locale,
768
+ [...fallbackLocales ?? []].sort().join(","),
769
+ [...namespaces ?? []].sort().join(",")
770
+ ]);
771
+ if (cache.enabled && key) {
772
+ const cached = await pool.get(key);
773
+ if (cached) {
774
+ logger.debug("Messages cache hit.", { key });
775
+ return cached;
776
+ }
777
+ }
778
+ const searchParams = buildSearchParams({ basePath, namespaces });
779
+ const messages = await fetchMessages({
652
780
  apiUrl,
781
+ apiHeaders,
653
782
  searchParams,
654
783
  locale,
655
- loggerId
784
+ logger: loggerOptions
656
785
  });
657
786
  if (messages) {
787
+ if (cache.enabled && key) {
788
+ await pool.set(key, messages, cache.ttl);
789
+ }
658
790
  return messages;
659
791
  }
660
- const fallbackResult = await fetchFallbackMessages(
792
+ const fallbackResult = await fetchFallbackMessages({
661
793
  apiUrl,
794
+ apiHeaders,
662
795
  searchParams,
663
796
  fallbackLocales,
664
- loggerId
665
- );
797
+ logger: loggerOptions
798
+ });
666
799
  if (fallbackResult) {
667
800
  logger.info("Fallback locale succeeded.", {
668
801
  usedLocale: fallbackResult.locale,
669
802
  apiUrl,
670
803
  searchParams: decodeURIComponent(searchParams.toString())
671
804
  });
805
+ if (cache.enabled && key) {
806
+ await pool.set(key, fallbackResult.messages, cache.ttl);
807
+ }
672
808
  return fallbackResult.messages;
673
809
  }
674
810
  logger.warn("Failed to fetch messages for all locales.", {
675
811
  locale,
676
812
  fallbackLocales
677
813
  });
678
- return void 0;
814
+ return;
679
815
  };
680
816
 
681
- // src/shared/utils/pathname/extract-pathname.ts
682
- var extractPathname = ({
683
- config,
684
- pathname: rawPathname
685
- }) => {
686
- const { routing, defaultLocale } = config;
687
- const { basePath, prefix } = routing;
688
- const normalizedPathname = normalizePathname(rawPathname);
689
- let prefixedPathname = normalizedPathname;
690
- if (basePath && normalizedPathname.startsWith(basePath + "/")) {
691
- prefixedPathname = normalizedPathname.slice(basePath.length) || "/";
692
- } else if (basePath && normalizedPathname === basePath) {
693
- prefixedPathname = "/";
694
- }
695
- const pathParts = prefixedPathname.split("/").filter(Boolean);
696
- const maybeLocale = pathParts[0] || "";
697
- const isLocalePrefixed = config.supportedLocales?.includes(maybeLocale);
698
- let unprefixedPathname = prefixedPathname;
699
- if (prefix === "all") {
700
- if (isLocalePrefixed) {
701
- unprefixedPathname = prefixedPathname.slice(maybeLocale.length + 1) || "/";
702
- }
703
- } else if (prefix === "except-default") {
704
- if (maybeLocale && maybeLocale !== defaultLocale && isLocalePrefixed) {
705
- unprefixedPathname = prefixedPathname.slice(maybeLocale.length + 1) || "/";
706
- }
707
- }
708
- return {
709
- basePath,
710
- prefixedPathname,
711
- unprefixedPathname,
712
- maybeLocale,
713
- isLocalePrefixed: Boolean(isLocalePrefixed)
714
- };
715
- };
716
-
717
- // src/shared/utils/pathname/standardize-pathname.ts
718
- var standardizePathname = ({
719
- config,
720
- pathname
721
- }) => {
722
- const { routing, prefixPlaceHolder } = config;
723
- const { basePath } = routing;
724
- const parts = [
725
- normalizePathname(basePath),
726
- normalizePathname(prefixPlaceHolder),
727
- normalizePathname(pathname)
728
- ];
729
- const standardizedPathname = parts.join("/").replace(/\/{2,}/g, "/");
730
- return normalizePathname(standardizedPathname);
731
- };
732
-
733
- // src/shared/utils/resolve-namespaces.ts
734
- var resolveNamespaces = ({
735
- config,
736
- pathname
737
- }) => {
738
- const { loaderOptions, prefixPlaceHolder } = config;
739
- const {
740
- routeNamespaces = {},
741
- namespaces: fallbackNamespaces
742
- } = loaderOptions;
743
- const { unprefixedPathname } = extractPathname({ config, pathname });
744
- const standardizedPathname = standardizePathname({
745
- config,
746
- pathname: unprefixedPathname
747
- });
748
- const placeholderRemovedPathname = standardizedPathname.replace(
749
- `/${prefixPlaceHolder}`,
750
- ""
751
- );
752
- const defaultNamespaces = routeNamespaces.default ?? [];
753
- const exactMatchNamespaces = routeNamespaces[standardizedPathname] ?? routeNamespaces[placeholderRemovedPathname];
754
- if (exactMatchNamespaces) {
755
- return [...defaultNamespaces, ...exactMatchNamespaces];
756
- }
757
- let bestMatch = "";
758
- let bestNamespaces;
759
- const prefixPatterns = Object.keys(routeNamespaces).filter(
760
- (pattern) => pattern.endsWith("/*")
761
- );
762
- for (const pattern of prefixPatterns) {
763
- const basePath = pattern.replace(/\/\*$/, "");
764
- if (standardizedPathname.startsWith(basePath)) {
765
- if (basePath.length > bestMatch.length) {
766
- bestMatch = basePath;
767
- bestNamespaces = routeNamespaces[pattern];
768
- }
769
- }
770
- }
771
- const matchedNamespaces = bestNamespaces ?? routeNamespaces["/*"] ?? fallbackNamespaces ?? [];
772
- if (matchedNamespaces.length > 0) {
773
- return [...defaultNamespaces, ...matchedNamespaces];
774
- } else {
775
- return [...defaultNamespaces];
776
- }
777
- };
778
-
779
- // src/modules/intor-messages-loader/intor-messages-loader.ts
780
- var intorMessagesLoader = async ({
817
+ // src/modules/messages/get-messages.ts
818
+ var getMessages = async ({
781
819
  config,
782
820
  locale,
783
821
  pathname
784
822
  }) => {
785
- const logger = logry({ id: config.id, scope: "intorMessagesLoader" });
786
- const loaderOptions = config.loaderOptions;
823
+ const baseLogger = getLogger({ id: config.id });
824
+ const logger = baseLogger.child({ scope: "messages-loader" });
825
+ const loaderOptions = config.loader;
787
826
  const fallbackLocales = config.fallbackLocales[locale] || [];
788
827
  const namespaces = resolveNamespaces({ config, pathname });
789
- let dynamicMessages;
790
- logger.info("Namespaces ready for loading:", {
791
- namespaces: namespaces.length > 0 ? { count: namespaces.length, list: [...namespaces] } : "All"
792
- });
793
- logger.debug("Loader type selected:", {
794
- loaderType: loaderOptions.type
828
+ logger.debug("Namespaces ready for loading.", {
829
+ namespaces: namespaces.length > 0 ? { count: namespaces.length, list: [...namespaces] } : "All Namespaces"
795
830
  });
831
+ logger.debug("Loader type selected.", { loaderType: loaderOptions.type });
832
+ let loadedMessages;
796
833
  if (loaderOptions.type === "import") {
797
- const loadLocalMessages2 = createLocalMessagesLoader(loaderOptions.basePath);
798
- dynamicMessages = await loadLocalMessages2({
834
+ const loadLocalMessages2 = createLoadLocalMessages(loaderOptions.basePath);
835
+ loadedMessages = await loadLocalMessages2({
799
836
  ...loaderOptions,
800
837
  locale,
801
838
  fallbackLocales,
802
839
  namespaces,
803
- loggerId: config.id
840
+ cache: config.cache,
841
+ logger: { id: config.id }
804
842
  });
805
843
  } else if (loaderOptions.type === "api") {
806
- dynamicMessages = await fetchApiMessages({
844
+ loadedMessages = await loadApiMessages({
807
845
  ...loaderOptions,
808
846
  locale,
809
847
  fallbackLocales,
810
848
  namespaces,
811
- loggerId: config.id
812
- });
813
- } else {
814
- logger.error("Unknown loader type.", {
815
- type: loaderOptions.type
816
- });
817
- throw new IntorError({
818
- id: config.id,
819
- code: "INTOR_UNKNOWN_LOADER_TYPE" /* UNKNOWN_LOADER_TYPE */,
820
- message: `Unknown loader type: ${loaderOptions.type}`
849
+ logger: { id: config.id }
821
850
  });
822
851
  }
823
- if (!dynamicMessages || Object.keys(dynamicMessages).length === 0) {
852
+ if (!loadedMessages || Object.keys(loadedMessages).length === 0) {
824
853
  logger.warn("No messages found.", { locale, namespaces });
825
854
  }
826
- return dynamicMessages;
827
- };
828
-
829
- // src/modules/intor-runtime/utils/should-load-dynamic-messages.ts
830
- var shouldLoadDynamicMessages = (loaderOptions, adapter) => {
831
- if (!loaderOptions) {
832
- return false;
833
- }
834
- const { type, lazyLoad } = loaderOptions;
835
- if (type === "import") {
836
- return true;
837
- }
838
- if (type === "api") {
839
- if (adapter === "next-client" && lazyLoad) {
840
- return false;
841
- }
842
- return true;
843
- }
844
- return false;
845
- };
846
-
847
- // src/shared/utils/merge-static-and-dynamic-messages.ts
848
- var mergeStaticAndDynamicMessages = (staticMessages = {}, dynamicMessages = {}) => {
849
- const result = Object.keys(staticMessages).length ? { ...staticMessages } : {};
850
- for (const locale in dynamicMessages) {
851
- const dynamic = dynamicMessages[locale];
852
- if (!result[locale]) {
853
- result[locale] = dynamic;
854
- continue;
855
- }
856
- result[locale] = {
857
- ...result[locale],
858
- ...dynamic
859
- };
860
- }
861
- return result;
855
+ return loadedMessages;
862
856
  };
863
857
 
864
- // src/modules/intor-runtime/intor-runtime.ts
865
- var intorRuntime = async ({
866
- request,
867
- config
858
+ // src/modules/intor/intor.ts
859
+ var intor = async ({
860
+ config,
861
+ adapter,
862
+ adapterRuntime
868
863
  }) => {
869
- const logger = logry({ id: config.id, scope: "intorRuntime" });
870
- const {
871
- messages: staticMessages,
872
- // Static messages defined from config
873
- loaderOptions,
874
- adapter
875
- } = config;
876
- if (!intorAdapters.includes(adapter)) {
877
- logger.error("Unsupported adapter:", { adapter });
878
- throw new IntorError({
879
- id: config.id,
880
- code: "INTOR_UNSUPPORTED_ADAPTER" /* UNSUPPORTED_ADAPTER */,
881
- message: `Unsupported adapter: ${adapter}`
882
- });
883
- }
884
- const adapterRuntime = await resolceAdapterRuntimeLoader({ config });
885
- const { locale, pathname } = await adapterRuntime({ config, request });
886
- logger.info("Initialized locale and pathname:", { locale, pathname });
887
- let dynamicMessages;
888
- if (shouldLoadDynamicMessages(loaderOptions, adapter)) {
889
- dynamicMessages = await intorMessagesLoader({ config, locale, pathname });
864
+ const baseLogger = getLogger({ id: config.id, ...config.logger });
865
+ const logger = baseLogger.child({ scope: "intor" });
866
+ logger.info("Start Intor initialization.");
867
+ const { messages, loader } = config;
868
+ let runtime;
869
+ if (adapter) {
870
+ runtime = await adapter(config);
871
+ } else {
872
+ runtime = {
873
+ locale: adapterRuntime?.locale || config.defaultLocale,
874
+ pathname: adapterRuntime?.pathname || ""
875
+ };
890
876
  }
891
- const messages = mergeStaticAndDynamicMessages(
892
- staticMessages,
893
- dynamicMessages
894
- );
895
- logger.info("Loaded messages:", {
896
- staticMessages: {
897
- fromConfig: !!staticMessages
877
+ const { locale, pathname } = runtime;
878
+ logger.debug("Runtime resolved via adapter/fallback", runtime);
879
+ let loadedMessages;
880
+ if (shouldLoadMessages(loader)) {
881
+ loadedMessages = await getMessages({ config, locale, pathname });
882
+ }
883
+ const mergedMessages = mergeMessages(messages, loadedMessages);
884
+ logger.info("Messages initialized.", {
885
+ staticMessages: { enabled: !!messages },
886
+ loadedMessages: {
887
+ enabled: !!loadedMessages,
888
+ ...loader ? { loaderType: loader.type, lazyLoad: !!loader.lazyLoad } : null
898
889
  },
899
- dynamicMessages: {
900
- fromLoader: !!dynamicMessages,
901
- ...loaderOptions ? {
902
- loaderType: loaderOptions.type,
903
- lazyLoad: !!loaderOptions.lazyLoad
904
- } : null
905
- },
906
- mergedMessages: messages
890
+ mergedMessages
907
891
  });
908
892
  return {
909
893
  config,
910
894
  initialLocale: locale,
911
895
  pathname,
912
- messages
913
- };
914
- };
915
-
916
- // src/modules/intor/intor.ts
917
- var intor = async ({
918
- request,
919
- config
920
- }) => {
921
- const logger = logry({
922
- id: config.id,
923
- scope: "intor",
924
- ...config.logger
925
- });
926
- logger.info("Starting Intor initialization:", {
927
- adapter: config.adapter
928
- });
929
- const runtime = await intorRuntime({ config, request });
930
- switch (config.adapter) {
931
- case "next-server": {
932
- return runtime;
933
- }
934
- case "next-client": {
935
- return runtime;
936
- }
937
- default: {
938
- logger.error("Unsupported adapter:", { adapter: config.adapter });
939
- throw new IntorError({
940
- id: config.id,
941
- code: "INTOR_UNSUPPORTED_ADAPTER" /* UNSUPPORTED_ADAPTER */,
942
- message: `Unsupported adapter: ${config.adapter}`
943
- });
944
- }
945
- }
946
- };
947
- var createIntor = (config, translateHandlers) => {
948
- return async (request) => {
949
- const { initialLocale, messages } = await intor({ config, request });
950
- const translator = new Translator({
951
- locale: initialLocale,
952
- messages,
953
- fallbackLocales: config.fallbackLocales,
954
- loadingMessage: config.translator?.loadingMessage,
955
- placeholder: config.translator?.placeholder,
956
- handlers: translateHandlers
957
- });
958
- return translator;
896
+ messages: mergedMessages
959
897
  };
960
898
  };
961
899
 
962
- export { IntorError, IntorErrorCode, createIntor, extractPathname, fetchApiMessages, intor, loadLocalMessages, mergeStaticAndDynamicMessages, normalizeLocale, normalizePathname, resolveNamespaces, resolvePreferredLocale, standardizePathname };
900
+ export { PREFIX_PLACEHOLDER, clearLoggerPool, clearMessagesPool, extractPathname, getMessages, intor, loadApiMessages, loadLocalMessages, mergeMessages, normalizeCacheKey, normalizeLocale, normalizePathname, resolveNamespaces, resolvePreferredLocale, standardizePathname };