intor 2.3.13 → 2.3.15

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.
Files changed (150) hide show
  1. package/dist/core/export/index.js +1 -2
  2. package/dist/core/src/config/define-intor-config.js +0 -3
  3. package/dist/core/src/config/resolvers/resolve-cookie-options.js +0 -1
  4. package/dist/core/src/config/resolvers/resolve-fallback-locales.js +1 -2
  5. package/dist/core/src/config/resolvers/resolve-routing-options.js +0 -2
  6. package/dist/core/src/config/validators/validate-default-locale.js +0 -1
  7. package/dist/core/src/config/validators/validate-id.js +0 -1
  8. package/dist/core/src/config/validators/validate-supported-locales.js +0 -1
  9. package/dist/core/src/core/messages/global-messages-pool.js +11 -17
  10. package/dist/core/src/core/messages/load-remote-messages/load-remote-messages.js +1 -40
  11. package/dist/core/src/core/messages/utils/is-valid-messages.js +23 -15
  12. package/dist/core/src/routing/pathname/get-unprefixed-pathname.js +0 -1
  13. package/dist/core/src/routing/pathname/locale-prefix-pathname.js +0 -1
  14. package/dist/core/src/routing/pathname/standardize-pathname.js +0 -1
  15. package/dist/core/src/server/helpers/get-translator.js +3 -2
  16. package/dist/core/src/server/helpers/local-messages-from-url.js +1 -1
  17. package/dist/core/src/server/intor/intor.js +0 -1
  18. package/dist/core/src/server/messages/load-local-messages/load-local-messages.js +11 -12
  19. package/dist/core/src/server/messages/load-local-messages/read-locale-messages/collect-file-entries/collect-file-entries.js +6 -6
  20. package/dist/core/src/server/messages/load-local-messages/read-locale-messages/parse-file-entries/parse-file-entries.js +14 -6
  21. package/dist/core/src/server/messages/load-local-messages/read-locale-messages/read-locale-messages.js +3 -3
  22. package/dist/core/src/server/messages/load-messages.js +8 -12
  23. package/dist/core/src/server/runtime/create-intor-runtime.js +12 -8
  24. package/dist/core/src/server/translator/create-translator.js +1 -0
  25. package/dist/express/src/adapters/express/helpers/get-translator.js +3 -4
  26. package/dist/express/src/adapters/express/middleware/create-intor.js +5 -5
  27. package/dist/express/src/core/messages/global-messages-pool.js +9 -3
  28. package/dist/express/src/core/messages/load-remote-messages/load-remote-messages.js +1 -40
  29. package/dist/express/src/core/messages/utils/is-valid-messages.js +23 -15
  30. package/dist/express/src/routing/inbound/resolve-inbound.js +5 -6
  31. package/dist/express/src/routing/inbound/resolve-locale/resolve-locale.js +13 -6
  32. package/dist/express/src/routing/locale/get-locale-from-accept-language.js +7 -17
  33. package/dist/express/src/routing/locale/get-locale-from-host.js +13 -15
  34. package/dist/express/src/routing/locale/get-locale-from-pathname.js +4 -14
  35. package/dist/express/src/routing/locale/get-locale-from-query.js +10 -17
  36. package/dist/express/src/routing/pathname/get-unprefixed-pathname.js +0 -1
  37. package/dist/express/src/routing/pathname/locale-prefix-pathname.js +0 -1
  38. package/dist/express/src/routing/pathname/standardize-pathname.js +0 -1
  39. package/dist/express/src/server/helpers/get-translator.js +3 -2
  40. package/dist/express/src/server/messages/load-local-messages/load-local-messages.js +11 -12
  41. package/dist/express/src/server/messages/load-local-messages/read-locale-messages/collect-file-entries/collect-file-entries.js +6 -6
  42. package/dist/express/src/server/messages/load-local-messages/read-locale-messages/parse-file-entries/parse-file-entries.js +14 -6
  43. package/dist/express/src/server/messages/load-local-messages/read-locale-messages/read-locale-messages.js +3 -3
  44. package/dist/express/src/server/messages/load-messages.js +8 -12
  45. package/dist/express/src/server/runtime/create-intor-runtime.js +12 -8
  46. package/dist/express/src/server/translator/create-translator.js +1 -0
  47. package/dist/next/src/adapters/next/navigation/redirect.js +0 -1
  48. package/dist/next/src/adapters/next/navigation/use-pathname.js +0 -1
  49. package/dist/next/src/adapters/next/proxy/intor-proxy.js +1 -2
  50. package/dist/next/src/adapters/next/server/get-locale.js +0 -1
  51. package/dist/next/src/adapters/next/server/get-pathname.js +0 -1
  52. package/dist/next/src/adapters/next/server/get-translator.js +3 -4
  53. package/dist/next/src/adapters/next/server/intor.js +2 -3
  54. package/dist/next/src/core/messages/global-messages-pool.js +9 -3
  55. package/dist/next/src/core/messages/load-remote-messages/load-remote-messages.js +1 -40
  56. package/dist/next/src/core/messages/utils/is-valid-messages.js +23 -15
  57. package/dist/next/src/policies/shoud-full-reload.js +0 -1
  58. package/dist/next/src/routing/inbound/resolve-inbound.js +5 -6
  59. package/dist/next/src/routing/inbound/resolve-locale/resolve-locale.js +13 -6
  60. package/dist/next/src/routing/locale/get-locale-from-accept-language.js +7 -17
  61. package/dist/next/src/routing/locale/get-locale-from-host.js +13 -15
  62. package/dist/next/src/routing/locale/get-locale-from-pathname.js +4 -14
  63. package/dist/next/src/routing/locale/get-locale-from-query.js +10 -17
  64. package/dist/next/src/routing/pathname/get-unprefixed-pathname.js +0 -1
  65. package/dist/next/src/routing/pathname/locale-prefix-pathname.js +0 -1
  66. package/dist/next/src/routing/pathname/standardize-pathname.js +0 -1
  67. package/dist/next/src/server/helpers/get-translator.js +3 -2
  68. package/dist/next/src/server/intor/intor.js +0 -1
  69. package/dist/next/src/server/messages/load-local-messages/load-local-messages.js +11 -12
  70. package/dist/next/src/server/messages/load-local-messages/read-locale-messages/collect-file-entries/collect-file-entries.js +6 -6
  71. package/dist/next/src/server/messages/load-local-messages/read-locale-messages/parse-file-entries/parse-file-entries.js +14 -6
  72. package/dist/next/src/server/messages/load-local-messages/read-locale-messages/read-locale-messages.js +3 -3
  73. package/dist/next/src/server/messages/load-messages.js +8 -12
  74. package/dist/next/src/server/runtime/create-intor-runtime.js +12 -8
  75. package/dist/next/src/server/translator/create-translator.js +1 -0
  76. package/dist/react/src/client/react/helpers/use-runtime-state.js +0 -1
  77. package/dist/react/src/client/react/navigation/use-execute-navigation.js +0 -1
  78. package/dist/react/src/client/react/navigation/use-resolve-navigation.js +0 -1
  79. package/dist/react/src/client/react/provider/effects/use-locale-effects.js +0 -1
  80. package/dist/react/src/client/react/translator/use-translator.js +1 -0
  81. package/dist/react/src/client/shared/helpers/get-client-locale.js +0 -1
  82. package/dist/react/src/client/shared/messages/create-refetch-messages.js +0 -3
  83. package/dist/react/src/core/messages/load-remote-messages/load-remote-messages.js +1 -40
  84. package/dist/react/src/core/messages/utils/is-valid-messages.js +23 -15
  85. package/dist/react/src/policies/shoud-full-reload.js +0 -1
  86. package/dist/react/src/routing/pathname/get-unprefixed-pathname.js +0 -1
  87. package/dist/react/src/routing/pathname/locale-prefix-pathname.js +0 -1
  88. package/dist/react/src/routing/pathname/standardize-pathname.js +0 -1
  89. package/dist/svelte/src/client/shared/helpers/get-client-locale.js +0 -1
  90. package/dist/svelte/src/client/shared/messages/create-refetch-messages.js +0 -3
  91. package/dist/svelte/src/client/svelte/helpers/create-runtime-state.js +0 -1
  92. package/dist/svelte/src/client/svelte/runtime/create-intor-api.js +4 -0
  93. package/dist/svelte/src/client/svelte/runtime/create-intor.js +2 -1
  94. package/dist/svelte/src/client/svelte/runtime/effects/locale-effects.js +0 -1
  95. package/dist/svelte/src/core/messages/load-remote-messages/load-remote-messages.js +1 -40
  96. package/dist/svelte/src/core/messages/utils/is-valid-messages.js +23 -15
  97. package/dist/types/export/index.d.ts +2 -2
  98. package/dist/types/src/adapters/express/global.d.ts +2 -1
  99. package/dist/types/src/adapters/express/helpers/get-translator.d.ts +1 -1
  100. package/dist/types/src/adapters/next/server/get-translator.d.ts +1 -1
  101. package/dist/types/src/adapters/next/server/intor.d.ts +2 -2
  102. package/dist/types/src/client/svelte/runtime/create-intor-api.d.ts +2 -0
  103. package/dist/types/src/client/svelte/runtime/types.d.ts +3 -1
  104. package/dist/types/src/client/vue/provider/resolver/resolve-runtime.d.ts +1 -1
  105. package/dist/types/src/config/constants/index.d.ts +0 -1
  106. package/dist/types/src/config/index.d.ts +2 -2
  107. package/dist/types/src/config/types/index.d.ts +0 -1
  108. package/dist/types/src/config/types/intor-config.d.ts +0 -4
  109. package/dist/types/src/core/index.d.ts +1 -1
  110. package/dist/types/src/core/messages/global-messages-pool.d.ts +15 -12
  111. package/dist/types/src/core/messages/index.d.ts +2 -2
  112. package/dist/types/src/core/messages/load-remote-messages/load-remote-messages.d.ts +1 -2
  113. package/dist/types/src/core/messages/load-remote-messages/types.d.ts +1 -6
  114. package/dist/types/src/core/messages/types.d.ts +14 -36
  115. package/dist/types/src/core/messages/utils/is-valid-messages.d.ts +5 -10
  116. package/dist/types/src/core/types/translator-instance.d.ts +3 -1
  117. package/dist/types/src/routing/inbound/resolve-locale/resolve-locale.d.ts +4 -3
  118. package/dist/types/src/routing/locale/get-locale-from-accept-language.d.ts +5 -7
  119. package/dist/types/src/routing/locale/get-locale-from-host.d.ts +12 -8
  120. package/dist/types/src/routing/locale/get-locale-from-pathname.d.ts +4 -13
  121. package/dist/types/src/routing/locale/get-locale-from-query.d.ts +9 -10
  122. package/dist/types/src/server/helpers/get-translator.d.ts +2 -3
  123. package/dist/types/src/server/messages/load-local-messages/load-local-messages.d.ts +2 -2
  124. package/dist/types/src/server/messages/load-local-messages/read-locale-messages/parse-file-entries/parse-file-entries.d.ts +2 -2
  125. package/dist/types/src/server/messages/load-local-messages/read-locale-messages/parse-file-entries/types.d.ts +4 -3
  126. package/dist/types/src/server/messages/load-local-messages/read-locale-messages/parse-file-entries/utils/json-reader.d.ts +2 -2
  127. package/dist/types/src/server/messages/load-local-messages/read-locale-messages/parse-file-entries/utils/nest-object-from-path.d.ts +2 -2
  128. package/dist/types/src/server/messages/load-local-messages/read-locale-messages/read-locale-messages.d.ts +1 -1
  129. package/dist/types/src/server/messages/load-local-messages/read-locale-messages/types.d.ts +2 -2
  130. package/dist/types/src/server/messages/load-local-messages/types.d.ts +2 -2
  131. package/dist/types/src/server/messages/load-messages.d.ts +1 -1
  132. package/dist/types/src/server/messages/types.d.ts +2 -2
  133. package/dist/types/src/server/runtime/types.d.ts +2 -2
  134. package/dist/types/src/server/translator/create-translator.d.ts +1 -0
  135. package/dist/vue/src/client/shared/helpers/get-client-locale.js +0 -1
  136. package/dist/vue/src/client/shared/messages/create-refetch-messages.js +0 -3
  137. package/dist/vue/src/client/vue/helpers/use-runtime-state.js +0 -1
  138. package/dist/vue/src/client/vue/provider/effects/use-locale-effects.js +0 -1
  139. package/dist/vue/src/client/vue/translator/use-translator.js +3 -1
  140. package/dist/vue/src/core/messages/load-remote-messages/load-remote-messages.js +1 -40
  141. package/dist/vue/src/core/messages/utils/is-valid-messages.js +23 -15
  142. package/package.json +3 -4
  143. package/dist/core/src/config/constants/cache.js +0 -7
  144. package/dist/core/src/config/resolvers/resolve-cache-options.js +0 -11
  145. package/dist/react/src/core/utils/normalizers/normalize-cache-key.js +0 -45
  146. package/dist/svelte/src/core/utils/normalizers/normalize-cache-key.js +0 -45
  147. package/dist/types/src/config/constants/cache.d.ts +0 -2
  148. package/dist/types/src/config/resolvers/resolve-cache-options.d.ts +0 -2
  149. package/dist/types/src/config/types/cache.d.ts +0 -7
  150. package/dist/vue/src/core/utils/normalizers/normalize-cache-key.js +0 -45
@@ -2,7 +2,6 @@ import '../../core/error/intor-error.js';
2
2
  import { resolveLoaderOptions } from '../../core/utils/resolve-loader-options.js';
3
3
  import { getLogger } from '../../core/logger/get-logger.js';
4
4
  import { loadRemoteMessages } from '../../core/messages/load-remote-messages/load-remote-messages.js';
5
- import 'keyv';
6
5
  import { loadLocalMessages } from './load-local-messages/load-local-messages.js';
7
6
 
8
7
  /**
@@ -18,7 +17,7 @@ import { loadLocalMessages } from './load-local-messages/load-local-messages.js'
18
17
  * Message traversal, parsing, fallback resolution, and caching logic
19
18
  * are delegated to the selected loader.
20
19
  */
21
- const loadMessages = async ({ config, locale, readOptions, allowCacheWrite = false, }) => {
20
+ const loadMessages = async ({ config, locale, readers, allowCacheWrite = false, }) => {
22
21
  const baseLogger = getLogger(config.logger);
23
22
  const logger = baseLogger.child({ scope: "load-messages" });
24
23
  // ---------------------------------------------------------------------------
@@ -29,15 +28,15 @@ const loadMessages = async ({ config, locale, readOptions, allowCacheWrite = fal
29
28
  logger.warn("No loader options have been configured in the current config.");
30
29
  return;
31
30
  }
32
- const { type, namespaces } = loader;
31
+ const { type, namespaces, rootDir } = loader;
33
32
  const fallbackLocales = config.fallbackLocales[locale] || [];
34
33
  logger.info(`Loading messages for locale "${locale}".`);
35
34
  logger.trace("Starting to load messages with runtime context.", {
36
35
  loaderType: type,
36
+ rootDir,
37
37
  locale,
38
- fallbackLocales,
39
- namespaces: namespaces && namespaces.length > 0 ? [...namespaces] : ["*"],
40
- cache: config.cache,
38
+ fallbackLocales: fallbackLocales.join(", "),
39
+ namespaces: namespaces && namespaces.length > 0 ? [...namespaces] : "*",
41
40
  });
42
41
  // ---------------------------------------------------------------------------
43
42
  // Dispatch to loader implementation
@@ -49,24 +48,21 @@ const loadMessages = async ({ config, locale, readOptions, allowCacheWrite = fal
49
48
  locale,
50
49
  fallbackLocales,
51
50
  namespaces,
52
- rootDir: loader.rootDir,
51
+ rootDir,
53
52
  concurrency: loader.concurrency,
54
- readOptions,
53
+ readers,
55
54
  allowCacheWrite,
56
55
  loggerOptions: config.logger,
57
56
  });
58
57
  }
59
58
  else if (type === "remote") {
60
59
  loadedMessages = await loadRemoteMessages({
61
- id: config.id,
62
60
  locale,
63
61
  fallbackLocales,
64
62
  namespaces,
65
- rootDir: loader.rootDir,
63
+ rootDir,
66
64
  url: loader.url,
67
65
  headers: loader.headers,
68
- allowCacheWrite,
69
- cacheOptions: config.cache,
70
66
  loggerOptions: config.logger,
71
67
  });
72
68
  }
@@ -1,6 +1,6 @@
1
1
  import { IntorError, IntorErrorCode } from '../../core/error/intor-error.js';
2
+ import { resolveLoaderOptions } from '../../core/utils/resolve-loader-options.js';
2
3
  import 'logry';
3
- import 'keyv';
4
4
  import { loadMessages } from '../messages/load-messages.js';
5
5
  import { createTranslator } from '../translator/create-translator.js';
6
6
 
@@ -14,20 +14,24 @@ import { createTranslator } from '../translator/create-translator.js';
14
14
  * before a translator snapshot can be created.
15
15
  */
16
16
  function createIntorRuntime(config, options) {
17
+ const loader = resolveLoaderOptions(config);
17
18
  // Locale that has completed the ensureMessages() phase
18
19
  let ensuredLocale;
19
20
  // Messages prepared during ensureMessages(); may be empty
20
21
  let ensuredMessages;
21
22
  return {
22
23
  async ensureMessages(locale) {
23
- const messages = await loadMessages({
24
- config,
25
- locale,
26
- readOptions: options?.readOptions,
27
- allowCacheWrite: options?.allowCacheWrite ?? false,
28
- });
24
+ let messages;
25
+ if (loader) {
26
+ messages = await loadMessages({
27
+ config,
28
+ locale,
29
+ readers: options?.readers,
30
+ allowCacheWrite: options?.allowCacheWrite || false,
31
+ });
32
+ }
29
33
  ensuredLocale = locale;
30
- ensuredMessages = messages;
34
+ ensuredMessages = messages || {};
31
35
  },
32
36
  translator(locale, options) {
33
37
  // Guard: translator requires ensureMessages() to be completed for this locale
@@ -34,6 +34,7 @@ function createTranslator(params) {
34
34
  locale,
35
35
  hasKey: scoped ? scoped.hasKey : translator.hasKey,
36
36
  t: scoped ? scoped.t : translator.t,
37
+ tRaw: scoped ? scoped.tRaw : translator.tRaw,
37
38
  };
38
39
  }
39
40
 
@@ -1,7 +1,6 @@
1
1
  import { redirect as redirect$1 } from 'next/navigation';
2
2
  import '../../../core/error/intor-error.js';
3
3
  import 'logry';
4
- import 'keyv';
5
4
  import { resolveNavigation } from '../../../routing/navigation/resolve-navigation.js';
6
5
  import { getLocale } from '../server/get-locale.js';
7
6
 
@@ -2,7 +2,6 @@ import { usePathname as usePathname$1 } from 'next/navigation';
2
2
  import { useIntor } from 'intor/react';
3
3
  import '../../../core/error/intor-error.js';
4
4
  import 'logry';
5
- import 'keyv';
6
5
  import { localizePathname } from '../../../routing/pathname/localize-pathname.js';
7
6
 
8
7
  /**
@@ -3,7 +3,6 @@ import { INTOR_HEADERS } from '../../../core/constants/headers.js';
3
3
  import '../../../core/error/intor-error.js';
4
4
  import { normalizeQuery } from '../../../core/utils/normalizers/normalize-query.js';
5
5
  import 'logry';
6
- import 'keyv';
7
6
  import { resolveInbound } from '../../../routing/inbound/resolve-inbound.js';
8
7
  import { getLocaleFromAcceptLanguage } from '../../../routing/locale/get-locale-from-accept-language.js';
9
8
 
@@ -19,7 +18,7 @@ import { getLocaleFromAcceptLanguage } from '../../../routing/locale/get-locale-
19
18
  const intorProxy = async (config, request) => {
20
19
  // locale from accept-language header
21
20
  const acceptLanguageHeader = request.headers.get("accept-language");
22
- const localeFromAcceptLanguage = getLocaleFromAcceptLanguage(config, acceptLanguageHeader);
21
+ const localeFromAcceptLanguage = getLocaleFromAcceptLanguage(acceptLanguageHeader, config.supportedLocales);
23
22
  // Check whether this navigation flow has already redirected
24
23
  const hasRedirectedForLocale = request.headers.get("x-intor-redirected") === "1";
25
24
  // ----------------------------------------------------------
@@ -2,7 +2,6 @@ import { headers } from 'next/headers';
2
2
  import { INTOR_HEADERS } from '../../../core/constants/headers.js';
3
3
  import '../../../core/error/intor-error.js';
4
4
  import 'logry';
5
- import 'keyv';
6
5
 
7
6
  /**
8
7
  * Get the locale for the current execution context.
@@ -2,7 +2,6 @@ import { headers } from 'next/headers';
2
2
  import { INTOR_HEADERS } from '../../../core/constants/headers.js';
3
3
  import '../../../core/error/intor-error.js';
4
4
  import 'logry';
5
- import 'keyv';
6
5
  import { localizePathname } from '../../../routing/pathname/localize-pathname.js';
7
6
 
8
7
  /**
@@ -1,6 +1,5 @@
1
1
  import '../../../core/error/intor-error.js';
2
2
  import 'logry';
3
- import 'keyv';
4
3
  import 'node:path';
5
4
  import 'p-limit';
6
5
  import 'node:fs/promises';
@@ -10,14 +9,14 @@ import { getLocale } from './get-locale.js';
10
9
 
11
10
  // Implementation
12
11
  async function getTranslator(config, params) {
13
- const { preKey, handlers, plugins, readOptions } = params || {};
12
+ const { preKey, handlers, plugins, readers, allowCacheWrite } = params || {};
14
13
  return getTranslator$1(config, {
15
14
  locale: await getLocale(config),
16
15
  preKey,
17
16
  handlers,
18
17
  plugins,
19
- readOptions,
20
- allowCacheWrite: false,
18
+ readers,
19
+ allowCacheWrite,
21
20
  });
22
21
  }
23
22
 
@@ -1,6 +1,5 @@
1
1
  import '../../../core/error/intor-error.js';
2
2
  import 'logry';
3
- import 'keyv';
4
3
  import { intor as intor$1 } from '../../../server/intor/intor.js';
5
4
  import 'node:path';
6
5
  import 'p-limit';
@@ -15,9 +14,9 @@ import { getLocale } from './get-locale.js';
15
14
  * - Acts as the bootstrap entry where cache writes are permitted.
16
15
  * @platform Next.js
17
16
  */
18
- async function intor(config, readOptions) {
17
+ async function intor(config, readers) {
19
18
  return await intor$1(config, getLocale, {
20
- readOptions,
19
+ readers,
21
20
  allowCacheWrite: true,
22
21
  });
23
22
  }
@@ -1,8 +1,14 @@
1
- import Keyv from 'keyv';
2
-
1
+ /**
2
+ * Get the global messages pool.
3
+ *
4
+ * Lazily initialized to ensure:
5
+ * - Cross-module sharing
6
+ * - Dev / HMR safety
7
+ */
3
8
  function getGlobalMessagesPool() {
4
9
  if (!globalThis.__INTOR_MESSAGES_POOL__) {
5
- globalThis.__INTOR_MESSAGES_POOL__ = new Keyv();
10
+ const pool = new Map();
11
+ globalThis.__INTOR_MESSAGES_POOL__ = pool;
6
12
  }
7
13
  return globalThis.__INTOR_MESSAGES_POOL__;
8
14
  }
@@ -1,5 +1,4 @@
1
1
  import { getLogger } from '../../logger/get-logger.js';
2
- import { normalizeCacheKey } from '../../utils/normalizers/normalize-cache-key.js';
3
2
  import { fetchLocaleMessages } from './fetch-locale-messages/fetch-locale-messages.js';
4
3
 
5
4
  /**
@@ -9,12 +8,11 @@ import { fetchLocaleMessages } from './fetch-locale-messages/fetch-locale-messag
9
8
  * It coordinates:
10
9
  *
11
10
  * - Locale resolution with fallbacks
12
- * - Cache read / write behavior
13
11
  * - Respecting abort signals across the entire async flow
14
12
  *
15
13
  * Network fetching and data validation are delegated to lower-level utilities.
16
14
  */
17
- const loadRemoteMessages = async ({ id, locale, fallbackLocales, namespaces, rootDir, url, headers, signal, pool, cacheOptions, allowCacheWrite = false, loggerOptions, }) => {
15
+ const loadRemoteMessages = async ({ locale, fallbackLocales, namespaces, rootDir, url, headers, signal, loggerOptions, }) => {
18
16
  const baseLogger = getLogger(loggerOptions);
19
17
  const logger = baseLogger.child({ scope: "load-remote-messages" });
20
18
  // Abort early if the request has already been cancelled
@@ -25,31 +23,6 @@ const loadRemoteMessages = async ({ id, locale, fallbackLocales, namespaces, roo
25
23
  const start = performance.now();
26
24
  logger.debug("Loading remote messages.", { url });
27
25
  // ---------------------------------------------------------------------------
28
- // Cache key resolution
29
- // ---------------------------------------------------------------------------
30
- const cacheKey = normalizeCacheKey([
31
- id,
32
- "loaderType:remote",
33
- rootDir,
34
- locale,
35
- (fallbackLocales || []).toSorted().join(","),
36
- (namespaces || []).toSorted().join(","),
37
- ]);
38
- // ---------------------------------------------------------------------------
39
- // Cache read
40
- // ---------------------------------------------------------------------------
41
- if (cacheOptions.enabled && cacheKey) {
42
- const cached = await pool?.get(cacheKey);
43
- if (signal?.aborted) {
44
- logger.debug("Remote message loading aborted after cache read.");
45
- return;
46
- }
47
- if (cached) {
48
- logger.debug("Messages cache hit.", { key: cacheKey });
49
- return cached;
50
- }
51
- }
52
- // ---------------------------------------------------------------------------
53
26
  // Resolve locale messages with ordered fallback strategy
54
27
  // ---------------------------------------------------------------------------
55
28
  const candidateLocales = [locale, ...(fallbackLocales || [])];
@@ -93,18 +66,6 @@ const loadRemoteMessages = async ({ id, locale, fallbackLocales, namespaces, roo
93
66
  });
94
67
  }
95
68
  }
96
- // ---------------------------------------------------------------------------
97
- // Cache write (explicitly permitted)
98
- // ---------------------------------------------------------------------------
99
- if (cacheOptions.enabled && allowCacheWrite) {
100
- if (signal?.aborted) {
101
- logger.debug("Remote message loading aborted before cache write.");
102
- return;
103
- }
104
- if (cacheKey && messages) {
105
- await pool?.set(cacheKey, messages, cacheOptions.ttl);
106
- }
107
- }
108
69
  // Final success log with resolved locale and timing
109
70
  if (messages) {
110
71
  logger.trace("Finished loading remote messages.", {
@@ -3,15 +3,10 @@ function isPlainObject(value) {
3
3
  return typeof value === "object" && value !== null && !Array.isArray(value);
4
4
  }
5
5
  /**
6
- * Check if a value is a valid **Messages** object.
6
+ * Check if a value is a valid MessageObject.
7
7
  *
8
- * - Uses an iterative approach to avoid stack overflow with deeply nested objects.
9
- *
10
- * @example
11
- * ```ts
12
- * isValidMessages({ en: { hello: "Hello" } }) // true
13
- * isValidMessages({ en: { count: 5 } }) // false
14
- * ```
8
+ * - Supports all MessageValue variants (primitive, array, object).
9
+ * - Uses an iterative approach to avoid stack overflow.
15
10
  */
16
11
  function isValidMessages(value) {
17
12
  if (!isPlainObject(value))
@@ -19,16 +14,29 @@ function isValidMessages(value) {
19
14
  const stack = [value];
20
15
  while (stack.length > 0) {
21
16
  const current = stack.pop();
22
- for (const v of Object.values(current)) {
23
- if (typeof v === "string")
24
- continue;
25
- if (isPlainObject(v)) {
26
- stack.push(v);
17
+ // primitives are always valid
18
+ if (current === null ||
19
+ typeof current === "string" ||
20
+ typeof current === "number" ||
21
+ typeof current === "boolean") {
22
+ continue;
23
+ }
24
+ // array → validate each item
25
+ if (Array.isArray(current)) {
26
+ for (const item of current) {
27
+ stack.push(item);
27
28
  }
28
- else {
29
- return false;
29
+ continue;
30
+ }
31
+ // object → validate each value
32
+ if (isPlainObject(current)) {
33
+ for (const v of Object.values(current)) {
34
+ stack.push(v);
30
35
  }
36
+ continue;
31
37
  }
38
+ // everything else is invalid
39
+ return false;
32
40
  }
33
41
  return true;
34
42
  }
@@ -1,7 +1,6 @@
1
1
  import '../core/error/intor-error.js';
2
2
  import { resolveLoaderOptions } from '../core/utils/resolve-loader-options.js';
3
3
  import 'logry';
4
- import 'keyv';
5
4
 
6
5
  /**
7
6
  * Determine whether client-side navigation must be forced to reload.
@@ -1,6 +1,3 @@
1
- import '../../core/error/intor-error.js';
2
- import 'logry';
3
- import 'keyv';
4
1
  import { getLocaleFromPathname } from '../locale/get-locale-from-pathname.js';
5
2
  import { getLocaleFromHost } from '../locale/get-locale-from-host.js';
6
3
  import { getLocaleFromQuery } from '../locale/get-locale-from-query.js';
@@ -21,11 +18,13 @@ async function resolveInbound(config, rawPathname, hasRedirected, localeInputs)
21
18
  // ------------------------------------------------------
22
19
  // Resolve locale from inbound inputs
23
20
  // ------------------------------------------------------
24
- const pathLocale = getLocaleFromPathname(config, rawPathname);
21
+ const pathLocale = getLocaleFromPathname(rawPathname, config);
25
22
  const { locale, localeSource } = resolveLocale(config, {
26
23
  path: { locale: pathLocale },
27
- host: { locale: getLocaleFromHost(config, host) },
28
- query: { locale: getLocaleFromQuery(config, query) },
24
+ host: { locale: getLocaleFromHost(host) },
25
+ query: {
26
+ locale: getLocaleFromQuery(query, config.routing.inbound.queryKey),
27
+ },
29
28
  cookie: { locale: cookie },
30
29
  detected: { locale: detected },
31
30
  });
@@ -1,23 +1,30 @@
1
+ import '../../../core/error/intor-error.js';
2
+ import { normalizeLocale } from '../../../core/utils/normalizers/normalize-locale.js';
3
+ import 'logry';
4
+
1
5
  /**
2
- * Resolves the active locale from inbound routing configuration.
6
+ * Resolve the active locale from inbound routing configuration.
3
7
  *
4
- * The first matching locale from the configured sources is used,
5
- * with the detected locale as a guaranteed fallback.
8
+ * Iterates through configured locale sources and returns the first
9
+ * normalized, supported locale. Falls back to the detected locale
10
+ * or the default locale if none match.
6
11
  */
7
12
  function resolveLocale(config, context) {
8
13
  const { localeSources } = config.routing.inbound;
9
14
  for (const source of localeSources) {
10
15
  const locale = context[source]?.locale;
11
- if (!locale)
16
+ const normalized = normalizeLocale(locale, config.supportedLocales);
17
+ if (!normalized)
12
18
  continue;
13
19
  return {
14
- locale,
20
+ locale: normalized,
15
21
  localeSource: source,
16
22
  };
17
23
  }
18
24
  // Fallback: detected is always available
19
25
  return {
20
- locale: context.detected.locale,
26
+ locale: normalizeLocale(context.detected.locale, config.supportedLocales) ||
27
+ config.defaultLocale,
21
28
  localeSource: "detected",
22
29
  };
23
30
  }
@@ -1,30 +1,20 @@
1
- import '../../core/error/intor-error.js';
2
- import { normalizeLocale } from '../../core/utils/normalizers/normalize-locale.js';
3
- import 'logry';
4
- import 'keyv';
5
-
6
1
  /**
7
- * Resolve locale from the `Accept-Language` header.
8
- *
9
- * - Parses language priorities (`q` values) from the header.
10
- * - Selects the highest-priority language supported by the application.
11
- * - Normalizes the matched locale against `supportedLocales`.
2
+ * Get locale candidate from the `Accept-Language` header.
12
3
  *
13
- * If no supported locale can be resolved, `undefined` is returned.
4
+ * Parses language priorities and returns the highest-priority
5
+ * language present in `supportedLocales`, without normalization.
14
6
  *
15
7
  * @example
16
8
  * ```ts
17
9
  * getLocaleFromAcceptLanguage("en-US,en;q=0.8,zh-TW;q=0.9", ["en-US", "zh-TW"])
18
10
  * // => "en-US"
11
+ *
19
12
  * getLocaleFromAcceptLanguage("fr,ja;q=0.9", ["en", "zh-TW"])
20
13
  * // => undefined
21
14
  * ```
22
15
  */
23
- const getLocaleFromAcceptLanguage = (config, acceptLanguageHeader) => {
24
- const { supportedLocales } = config;
25
- if (!acceptLanguageHeader ||
26
- !supportedLocales ||
27
- supportedLocales.length === 0) {
16
+ const getLocaleFromAcceptLanguage = (acceptLanguageHeader, supportedLocales) => {
17
+ if (!acceptLanguageHeader || supportedLocales.length === 0) {
28
18
  return;
29
19
  }
30
20
  const supportedLocalesSet = new Set(supportedLocales);
@@ -42,7 +32,7 @@ const getLocaleFromAcceptLanguage = (config, acceptLanguageHeader) => {
42
32
  const sortedByPriority = parsedLanguages.toSorted((a, b) => b.q - a.q);
43
33
  // 3. Pick the first language explicitly supported
44
34
  const preferred = sortedByPriority.find(({ lang }) => supportedLocalesSet.has(lang))?.lang;
45
- return normalizeLocale(preferred, supportedLocales);
35
+ return preferred;
46
36
  };
47
37
 
48
38
  export { getLocaleFromAcceptLanguage };
@@ -1,34 +1,32 @@
1
- import '../../core/error/intor-error.js';
2
- import { normalizeLocale } from '../../core/utils/normalizers/normalize-locale.js';
3
- import 'logry';
4
- import 'keyv';
5
-
6
1
  /**
7
- * Extract locale from hostname.
2
+ * Get locale candidate from hostname.
8
3
  *
9
- * Only the left-most subdomain is considered as a locale candidate, if present.
4
+ * Returns the left-most hostname label, without validation or normalization.
10
5
  *
11
6
  * @example
12
7
  * ```ts
13
- * getLocaleFromHost(config, "en.example.com")
8
+ * getLocaleFromHost("en.example.com")
14
9
  * // => "en"
15
- * getLocaleFromHost(config, "example.com")
16
- * // => undefined
17
- * getLocaleFromHost(config, "api.jp.example.com")
10
+ *
11
+ * getLocaleFromHost("example.com")
12
+ * // => "example"
13
+ *
14
+ * getLocaleFromHost("api.jp.example.com")
15
+ * // => "api"
16
+ *
17
+ * getLocaleFromHost("localhost")
18
18
  * // => undefined
19
19
  * ```
20
20
  */
21
- function getLocaleFromHost(config, host) {
21
+ function getLocaleFromHost(host) {
22
22
  if (!host)
23
23
  return;
24
- const { supportedLocales } = config;
25
24
  // Remove port (e.g. localhost:3000)
26
25
  const hostname = host.split(":")[0];
27
26
  const parts = hostname.split(".");
28
27
  if (parts.length < 2)
29
28
  return;
30
- const candidate = parts[0];
31
- return normalizeLocale(candidate, supportedLocales);
29
+ return parts[0];
32
30
  }
33
31
 
34
32
  export { getLocaleFromHost };
@@ -1,22 +1,12 @@
1
1
  import '../../core/error/intor-error.js';
2
2
  import { normalizePathname } from '../../core/utils/normalizers/normalize-pathname.js';
3
3
  import 'logry';
4
- import 'keyv';
5
4
 
6
5
  /**
7
- * Extracts the locale from a pathname, if present.
6
+ * Get locale from pathname.
8
7
  *
9
- * - Normalizes the raw pathname.
10
- * - Strips the configured basePath.
11
- * - Inspects the first path segment to determine whether
12
- * it matches a supported locale.
13
- *
14
- * If no locale segment is found, `undefined` is returned.
15
- *
16
- * Note:
17
- * - The pathname is treated as a canonical source.
18
- * - Only exact matches against `supportedLocales` are accepted.
19
- * - ___Locale normalization is intentionally not applied here.___
8
+ * Extracts the first pathname segment (after basePath) as a locale
9
+ * if it exactly matches one of the supported locales.
20
10
  *
21
11
  * @example
22
12
  * ```ts
@@ -32,7 +22,7 @@ import 'keyv';
32
22
  * // => "en"
33
23
  * ```
34
24
  */
35
- function getLocaleFromPathname(config, pathname) {
25
+ function getLocaleFromPathname(pathname, config) {
36
26
  const { routing, supportedLocales } = config;
37
27
  const { basePath } = routing;
38
28
  // 1. Normalize pathname
@@ -1,36 +1,29 @@
1
- import '../../core/error/intor-error.js';
2
- import { normalizeLocale } from '../../core/utils/normalizers/normalize-locale.js';
3
- import 'logry';
4
- import 'keyv';
5
-
6
1
  /**
7
- * Extracts locale from URL query parameters.
8
- *
9
- * - Reads the configured locale query key.
10
- * - Normalizes the value against supported locales.
2
+ * Get locale candidate from URL query parameters.
11
3
  *
12
- * If no valid locale is found, `undefined` is returned.
4
+ * Extracts the value of the configured query key, without
5
+ * validation or normalization.
13
6
  *
14
7
  * @example
15
8
  * ```ts
16
- * getLocaleFromQuery(config, { locale: "en" })
9
+ * getLocaleFromQuery({ locale: "en" }, "locale")
17
10
  * // => "en"
18
- * getLocaleFromQuery(config, {})
11
+ *
12
+ * getLocaleFromQuery({}, "locale")
19
13
  * // => undefined
20
- * getLocaleFromQuery(config, { locale: ["zh-TW"] })
14
+ *
15
+ * getLocaleFromQuery({ locale: ["zh-TW"] }, "locale")
21
16
  * // => "zh-TW"
22
17
  * ```
23
18
  */
24
- function getLocaleFromQuery(config, query) {
19
+ function getLocaleFromQuery(query, queryKey) {
25
20
  if (!query)
26
21
  return;
27
- const { supportedLocales, routing } = config;
28
- const { queryKey } = routing.inbound;
29
22
  const raw = query[queryKey];
30
23
  if (!raw)
31
24
  return;
32
25
  const value = Array.isArray(raw) ? raw[0] : raw;
33
- return normalizeLocale(value, supportedLocales);
26
+ return value;
34
27
  }
35
28
 
36
29
  export { getLocaleFromQuery };
@@ -1,7 +1,6 @@
1
1
  import '../../core/error/intor-error.js';
2
2
  import { normalizePathname } from '../../core/utils/normalizers/normalize-pathname.js';
3
3
  import 'logry';
4
- import 'keyv';
5
4
 
6
5
  /**
7
6
  * Returns a canonical, locale-agnostic pathname.
@@ -2,7 +2,6 @@ import { PREFIX_PLACEHOLDER } from '../../core/constants/prefix-placeholder.js';
2
2
  import '../../core/error/intor-error.js';
3
3
  import { normalizePathname } from '../../core/utils/normalizers/normalize-pathname.js';
4
4
  import 'logry';
5
- import 'keyv';
6
5
 
7
6
  /**
8
7
  * Applies the configured locale prefix behavior to a standardized pathname.
@@ -2,7 +2,6 @@ import { PREFIX_PLACEHOLDER } from '../../core/constants/prefix-placeholder.js';
2
2
  import '../../core/error/intor-error.js';
3
3
  import { normalizePathname } from '../../core/utils/normalizers/normalize-pathname.js';
4
4
  import 'logry';
5
- import 'keyv';
6
5
 
7
6
  /**
8
7
  * Standardizes a canonical pathname by applying the base path