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.
- package/dist/core/export/index.js +1 -2
- package/dist/core/src/config/define-intor-config.js +0 -3
- package/dist/core/src/config/resolvers/resolve-cookie-options.js +0 -1
- package/dist/core/src/config/resolvers/resolve-fallback-locales.js +1 -2
- package/dist/core/src/config/resolvers/resolve-routing-options.js +0 -2
- package/dist/core/src/config/validators/validate-default-locale.js +0 -1
- package/dist/core/src/config/validators/validate-id.js +0 -1
- package/dist/core/src/config/validators/validate-supported-locales.js +0 -1
- package/dist/core/src/core/messages/global-messages-pool.js +11 -17
- package/dist/core/src/core/messages/load-remote-messages/load-remote-messages.js +1 -40
- package/dist/core/src/core/messages/utils/is-valid-messages.js +23 -15
- package/dist/core/src/routing/pathname/get-unprefixed-pathname.js +0 -1
- package/dist/core/src/routing/pathname/locale-prefix-pathname.js +0 -1
- package/dist/core/src/routing/pathname/standardize-pathname.js +0 -1
- package/dist/core/src/server/helpers/get-translator.js +3 -2
- package/dist/core/src/server/helpers/local-messages-from-url.js +1 -1
- package/dist/core/src/server/intor/intor.js +0 -1
- package/dist/core/src/server/messages/load-local-messages/load-local-messages.js +11 -12
- package/dist/core/src/server/messages/load-local-messages/read-locale-messages/collect-file-entries/collect-file-entries.js +6 -6
- package/dist/core/src/server/messages/load-local-messages/read-locale-messages/parse-file-entries/parse-file-entries.js +14 -6
- package/dist/core/src/server/messages/load-local-messages/read-locale-messages/read-locale-messages.js +3 -3
- package/dist/core/src/server/messages/load-messages.js +8 -12
- package/dist/core/src/server/runtime/create-intor-runtime.js +12 -8
- package/dist/core/src/server/translator/create-translator.js +1 -0
- package/dist/express/src/adapters/express/helpers/get-translator.js +3 -4
- package/dist/express/src/adapters/express/middleware/create-intor.js +5 -5
- package/dist/express/src/core/messages/global-messages-pool.js +9 -3
- package/dist/express/src/core/messages/load-remote-messages/load-remote-messages.js +1 -40
- package/dist/express/src/core/messages/utils/is-valid-messages.js +23 -15
- package/dist/express/src/routing/inbound/resolve-inbound.js +5 -6
- package/dist/express/src/routing/inbound/resolve-locale/resolve-locale.js +13 -6
- package/dist/express/src/routing/locale/get-locale-from-accept-language.js +7 -17
- package/dist/express/src/routing/locale/get-locale-from-host.js +13 -15
- package/dist/express/src/routing/locale/get-locale-from-pathname.js +4 -14
- package/dist/express/src/routing/locale/get-locale-from-query.js +10 -17
- package/dist/express/src/routing/pathname/get-unprefixed-pathname.js +0 -1
- package/dist/express/src/routing/pathname/locale-prefix-pathname.js +0 -1
- package/dist/express/src/routing/pathname/standardize-pathname.js +0 -1
- package/dist/express/src/server/helpers/get-translator.js +3 -2
- package/dist/express/src/server/messages/load-local-messages/load-local-messages.js +11 -12
- package/dist/express/src/server/messages/load-local-messages/read-locale-messages/collect-file-entries/collect-file-entries.js +6 -6
- package/dist/express/src/server/messages/load-local-messages/read-locale-messages/parse-file-entries/parse-file-entries.js +14 -6
- package/dist/express/src/server/messages/load-local-messages/read-locale-messages/read-locale-messages.js +3 -3
- package/dist/express/src/server/messages/load-messages.js +8 -12
- package/dist/express/src/server/runtime/create-intor-runtime.js +12 -8
- package/dist/express/src/server/translator/create-translator.js +1 -0
- package/dist/next/src/adapters/next/navigation/redirect.js +0 -1
- package/dist/next/src/adapters/next/navigation/use-pathname.js +0 -1
- package/dist/next/src/adapters/next/proxy/intor-proxy.js +1 -2
- package/dist/next/src/adapters/next/server/get-locale.js +0 -1
- package/dist/next/src/adapters/next/server/get-pathname.js +0 -1
- package/dist/next/src/adapters/next/server/get-translator.js +3 -4
- package/dist/next/src/adapters/next/server/intor.js +2 -3
- package/dist/next/src/core/messages/global-messages-pool.js +9 -3
- package/dist/next/src/core/messages/load-remote-messages/load-remote-messages.js +1 -40
- package/dist/next/src/core/messages/utils/is-valid-messages.js +23 -15
- package/dist/next/src/policies/shoud-full-reload.js +0 -1
- package/dist/next/src/routing/inbound/resolve-inbound.js +5 -6
- package/dist/next/src/routing/inbound/resolve-locale/resolve-locale.js +13 -6
- package/dist/next/src/routing/locale/get-locale-from-accept-language.js +7 -17
- package/dist/next/src/routing/locale/get-locale-from-host.js +13 -15
- package/dist/next/src/routing/locale/get-locale-from-pathname.js +4 -14
- package/dist/next/src/routing/locale/get-locale-from-query.js +10 -17
- package/dist/next/src/routing/pathname/get-unprefixed-pathname.js +0 -1
- package/dist/next/src/routing/pathname/locale-prefix-pathname.js +0 -1
- package/dist/next/src/routing/pathname/standardize-pathname.js +0 -1
- package/dist/next/src/server/helpers/get-translator.js +3 -2
- package/dist/next/src/server/intor/intor.js +0 -1
- package/dist/next/src/server/messages/load-local-messages/load-local-messages.js +11 -12
- package/dist/next/src/server/messages/load-local-messages/read-locale-messages/collect-file-entries/collect-file-entries.js +6 -6
- package/dist/next/src/server/messages/load-local-messages/read-locale-messages/parse-file-entries/parse-file-entries.js +14 -6
- package/dist/next/src/server/messages/load-local-messages/read-locale-messages/read-locale-messages.js +3 -3
- package/dist/next/src/server/messages/load-messages.js +8 -12
- package/dist/next/src/server/runtime/create-intor-runtime.js +12 -8
- package/dist/next/src/server/translator/create-translator.js +1 -0
- package/dist/react/src/client/react/helpers/use-runtime-state.js +0 -1
- package/dist/react/src/client/react/navigation/use-execute-navigation.js +0 -1
- package/dist/react/src/client/react/navigation/use-resolve-navigation.js +0 -1
- package/dist/react/src/client/react/provider/effects/use-locale-effects.js +0 -1
- package/dist/react/src/client/react/translator/use-translator.js +1 -0
- package/dist/react/src/client/shared/helpers/get-client-locale.js +0 -1
- package/dist/react/src/client/shared/messages/create-refetch-messages.js +0 -3
- package/dist/react/src/core/messages/load-remote-messages/load-remote-messages.js +1 -40
- package/dist/react/src/core/messages/utils/is-valid-messages.js +23 -15
- package/dist/react/src/policies/shoud-full-reload.js +0 -1
- package/dist/react/src/routing/pathname/get-unprefixed-pathname.js +0 -1
- package/dist/react/src/routing/pathname/locale-prefix-pathname.js +0 -1
- package/dist/react/src/routing/pathname/standardize-pathname.js +0 -1
- package/dist/svelte/src/client/shared/helpers/get-client-locale.js +0 -1
- package/dist/svelte/src/client/shared/messages/create-refetch-messages.js +0 -3
- package/dist/svelte/src/client/svelte/helpers/create-runtime-state.js +0 -1
- package/dist/svelte/src/client/svelte/runtime/create-intor-api.js +4 -0
- package/dist/svelte/src/client/svelte/runtime/create-intor.js +2 -1
- package/dist/svelte/src/client/svelte/runtime/effects/locale-effects.js +0 -1
- package/dist/svelte/src/core/messages/load-remote-messages/load-remote-messages.js +1 -40
- package/dist/svelte/src/core/messages/utils/is-valid-messages.js +23 -15
- package/dist/types/export/index.d.ts +2 -2
- package/dist/types/src/adapters/express/global.d.ts +2 -1
- package/dist/types/src/adapters/express/helpers/get-translator.d.ts +1 -1
- package/dist/types/src/adapters/next/server/get-translator.d.ts +1 -1
- package/dist/types/src/adapters/next/server/intor.d.ts +2 -2
- package/dist/types/src/client/svelte/runtime/create-intor-api.d.ts +2 -0
- package/dist/types/src/client/svelte/runtime/types.d.ts +3 -1
- package/dist/types/src/client/vue/provider/resolver/resolve-runtime.d.ts +1 -1
- package/dist/types/src/config/constants/index.d.ts +0 -1
- package/dist/types/src/config/index.d.ts +2 -2
- package/dist/types/src/config/types/index.d.ts +0 -1
- package/dist/types/src/config/types/intor-config.d.ts +0 -4
- package/dist/types/src/core/index.d.ts +1 -1
- package/dist/types/src/core/messages/global-messages-pool.d.ts +15 -12
- package/dist/types/src/core/messages/index.d.ts +2 -2
- package/dist/types/src/core/messages/load-remote-messages/load-remote-messages.d.ts +1 -2
- package/dist/types/src/core/messages/load-remote-messages/types.d.ts +1 -6
- package/dist/types/src/core/messages/types.d.ts +14 -36
- package/dist/types/src/core/messages/utils/is-valid-messages.d.ts +5 -10
- package/dist/types/src/core/types/translator-instance.d.ts +3 -1
- package/dist/types/src/routing/inbound/resolve-locale/resolve-locale.d.ts +4 -3
- package/dist/types/src/routing/locale/get-locale-from-accept-language.d.ts +5 -7
- package/dist/types/src/routing/locale/get-locale-from-host.d.ts +12 -8
- package/dist/types/src/routing/locale/get-locale-from-pathname.d.ts +4 -13
- package/dist/types/src/routing/locale/get-locale-from-query.d.ts +9 -10
- package/dist/types/src/server/helpers/get-translator.d.ts +2 -3
- package/dist/types/src/server/messages/load-local-messages/load-local-messages.d.ts +2 -2
- package/dist/types/src/server/messages/load-local-messages/read-locale-messages/parse-file-entries/parse-file-entries.d.ts +2 -2
- package/dist/types/src/server/messages/load-local-messages/read-locale-messages/parse-file-entries/types.d.ts +4 -3
- package/dist/types/src/server/messages/load-local-messages/read-locale-messages/parse-file-entries/utils/json-reader.d.ts +2 -2
- package/dist/types/src/server/messages/load-local-messages/read-locale-messages/parse-file-entries/utils/nest-object-from-path.d.ts +2 -2
- package/dist/types/src/server/messages/load-local-messages/read-locale-messages/read-locale-messages.d.ts +1 -1
- package/dist/types/src/server/messages/load-local-messages/read-locale-messages/types.d.ts +2 -2
- package/dist/types/src/server/messages/load-local-messages/types.d.ts +2 -2
- package/dist/types/src/server/messages/load-messages.d.ts +1 -1
- package/dist/types/src/server/messages/types.d.ts +2 -2
- package/dist/types/src/server/runtime/types.d.ts +2 -2
- package/dist/types/src/server/translator/create-translator.d.ts +1 -0
- package/dist/vue/src/client/shared/helpers/get-client-locale.js +0 -1
- package/dist/vue/src/client/shared/messages/create-refetch-messages.js +0 -3
- package/dist/vue/src/client/vue/helpers/use-runtime-state.js +0 -1
- package/dist/vue/src/client/vue/provider/effects/use-locale-effects.js +0 -1
- package/dist/vue/src/client/vue/translator/use-translator.js +3 -1
- package/dist/vue/src/core/messages/load-remote-messages/load-remote-messages.js +1 -40
- package/dist/vue/src/core/messages/utils/is-valid-messages.js +23 -15
- package/package.json +3 -4
- package/dist/core/src/config/constants/cache.js +0 -7
- package/dist/core/src/config/resolvers/resolve-cache-options.js +0 -11
- package/dist/react/src/core/utils/normalizers/normalize-cache-key.js +0 -45
- package/dist/svelte/src/core/utils/normalizers/normalize-cache-key.js +0 -45
- package/dist/types/src/config/constants/cache.d.ts +0 -2
- package/dist/types/src/config/resolvers/resolve-cache-options.d.ts +0 -2
- package/dist/types/src/config/types/cache.d.ts +0 -7
- 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,
|
|
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
|
|
51
|
+
rootDir,
|
|
53
52
|
concurrency: loader.concurrency,
|
|
54
|
-
|
|
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
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
|
@@ -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(
|
|
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
|
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,
|
|
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
|
-
|
|
20
|
-
allowCacheWrite
|
|
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,
|
|
17
|
+
async function intor(config, readers) {
|
|
19
18
|
return await intor$1(config, getLocale, {
|
|
20
|
-
|
|
19
|
+
readers,
|
|
21
20
|
allowCacheWrite: true,
|
|
22
21
|
});
|
|
23
22
|
}
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
|
|
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
|
-
|
|
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 ({
|
|
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
|
|
6
|
+
* Check if a value is a valid MessageObject.
|
|
7
7
|
*
|
|
8
|
-
* -
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
29
|
-
|
|
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,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(
|
|
21
|
+
const pathLocale = getLocaleFromPathname(rawPathname, config);
|
|
25
22
|
const { locale, localeSource } = resolveLocale(config, {
|
|
26
23
|
path: { locale: pathLocale },
|
|
27
|
-
host: { locale: getLocaleFromHost(
|
|
28
|
-
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
|
-
*
|
|
6
|
+
* Resolve the active locale from inbound routing configuration.
|
|
3
7
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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 = (
|
|
24
|
-
|
|
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
|
|
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
|
-
*
|
|
2
|
+
* Get locale candidate from hostname.
|
|
8
3
|
*
|
|
9
|
-
*
|
|
4
|
+
* Returns the left-most hostname label, without validation or normalization.
|
|
10
5
|
*
|
|
11
6
|
* @example
|
|
12
7
|
* ```ts
|
|
13
|
-
* getLocaleFromHost(
|
|
8
|
+
* getLocaleFromHost("en.example.com")
|
|
14
9
|
* // => "en"
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
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(
|
|
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
|
-
|
|
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
|
-
*
|
|
6
|
+
* Get locale from pathname.
|
|
8
7
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
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(
|
|
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
|
-
*
|
|
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
|
-
*
|
|
4
|
+
* Extracts the value of the configured query key, without
|
|
5
|
+
* validation or normalization.
|
|
13
6
|
*
|
|
14
7
|
* @example
|
|
15
8
|
* ```ts
|
|
16
|
-
* getLocaleFromQuery(
|
|
9
|
+
* getLocaleFromQuery({ locale: "en" }, "locale")
|
|
17
10
|
* // => "en"
|
|
18
|
-
*
|
|
11
|
+
*
|
|
12
|
+
* getLocaleFromQuery({}, "locale")
|
|
19
13
|
* // => undefined
|
|
20
|
-
*
|
|
14
|
+
*
|
|
15
|
+
* getLocaleFromQuery({ locale: ["zh-TW"] }, "locale")
|
|
21
16
|
* // => "zh-TW"
|
|
22
17
|
* ```
|
|
23
18
|
*/
|
|
24
|
-
function getLocaleFromQuery(
|
|
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
|
|
26
|
+
return value;
|
|
34
27
|
}
|
|
35
28
|
|
|
36
29
|
export { getLocaleFromQuery };
|
|
@@ -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
|