@bleedingdev/modern-js-plugin-i18n 3.5.0-ultramodern.3 → 3.5.0-ultramodern.31
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/cjs/cli/index.js +2 -1
- package/dist/cjs/runtime/Link.js +8 -89
- package/dist/cjs/runtime/context.js +18 -82
- package/dist/cjs/runtime/contextHelpers.js +137 -0
- package/dist/cjs/runtime/core.js +29 -132
- package/dist/cjs/runtime/i18n/detection/cache.js +149 -0
- package/dist/cjs/runtime/i18n/detection/detector.js +100 -0
- package/dist/cjs/runtime/i18n/detection/index.js +8 -263
- package/dist/cjs/runtime/i18n/detection/initOptions.js +69 -0
- package/dist/cjs/runtime/i18n/detection/language.js +62 -0
- package/dist/cjs/runtime/i18n/detection/path.js +49 -0
- package/dist/cjs/runtime/i18n/detection/priority.js +66 -0
- package/dist/cjs/runtime/i18n/detection/ssr.js +70 -0
- package/dist/cjs/runtime/i18n/detection/types.js +18 -0
- package/dist/cjs/runtime/linkHelpers.js +148 -0
- package/dist/cjs/runtime/pluginSetup.js +102 -0
- package/dist/cjs/runtime/providerComposition.js +113 -0
- package/dist/cjs/runtime/reactI18next.js +43 -0
- package/dist/cjs/server/apiPrefix.js +72 -0
- package/dist/cjs/server/detectorOptions.js +97 -0
- package/dist/cjs/server/index.js +17 -144
- package/dist/cjs/server/redirectPolicy.js +102 -0
- package/dist/cjs/shared/localisedUrls/config.js +49 -0
- package/dist/cjs/shared/localisedUrls/index.js +75 -0
- package/dist/cjs/shared/localisedUrls/normalise.js +87 -0
- package/dist/cjs/shared/localisedUrls/pathname.js +65 -0
- package/dist/cjs/shared/localisedUrls/patterns.js +130 -0
- package/dist/cjs/shared/localisedUrls/resolve.js +91 -0
- package/dist/cjs/shared/localisedUrls/routes.js +129 -0
- package/dist/cjs/shared/localisedUrls/types.js +18 -0
- package/dist/cjs/shared/localisedUrls.js +13 -294
- package/dist/esm/cli/index.mjs +2 -1
- package/dist/esm/runtime/Link.mjs +1 -82
- package/dist/esm/runtime/context.mjs +18 -82
- package/dist/esm/runtime/contextHelpers.mjs +84 -0
- package/dist/esm/runtime/core.mjs +30 -133
- package/dist/esm/runtime/i18n/detection/cache.mjs +102 -0
- package/dist/esm/runtime/i18n/detection/detector.mjs +62 -0
- package/dist/esm/runtime/i18n/detection/index.mjs +4 -260
- package/dist/esm/runtime/i18n/detection/initOptions.mjs +28 -0
- package/dist/esm/runtime/i18n/detection/language.mjs +21 -0
- package/dist/esm/runtime/i18n/detection/path.mjs +11 -0
- package/dist/esm/runtime/i18n/detection/priority.mjs +28 -0
- package/dist/esm/runtime/i18n/detection/ssr.mjs +26 -0
- package/dist/esm/runtime/i18n/detection/types.mjs +0 -0
- package/dist/esm/runtime/linkHelpers.mjs +98 -0
- package/dist/esm/runtime/pluginSetup.mjs +64 -0
- package/dist/esm/runtime/providerComposition.mjs +75 -0
- package/dist/esm/runtime/reactI18next.mjs +5 -0
- package/dist/esm/server/apiPrefix.mjs +31 -0
- package/dist/esm/server/detectorOptions.mjs +59 -0
- package/dist/esm/server/index.mjs +6 -133
- package/dist/esm/server/redirectPolicy.mjs +52 -0
- package/dist/esm/shared/localisedUrls/config.mjs +11 -0
- package/dist/esm/shared/localisedUrls/index.mjs +6 -0
- package/dist/esm/shared/localisedUrls/normalise.mjs +37 -0
- package/dist/esm/shared/localisedUrls/pathname.mjs +24 -0
- package/dist/esm/shared/localisedUrls/patterns.mjs +86 -0
- package/dist/esm/shared/localisedUrls/resolve.mjs +50 -0
- package/dist/esm/shared/localisedUrls/routes.mjs +88 -0
- package/dist/esm/shared/localisedUrls/types.mjs +0 -0
- package/dist/esm/shared/localisedUrls.mjs +1 -283
- package/dist/esm-node/cli/index.mjs +2 -1
- package/dist/esm-node/runtime/Link.mjs +1 -82
- package/dist/esm-node/runtime/context.mjs +18 -82
- package/dist/esm-node/runtime/contextHelpers.mjs +85 -0
- package/dist/esm-node/runtime/core.mjs +30 -133
- package/dist/esm-node/runtime/i18n/detection/cache.mjs +103 -0
- package/dist/esm-node/runtime/i18n/detection/detector.mjs +63 -0
- package/dist/esm-node/runtime/i18n/detection/index.mjs +4 -260
- package/dist/esm-node/runtime/i18n/detection/initOptions.mjs +29 -0
- package/dist/esm-node/runtime/i18n/detection/language.mjs +22 -0
- package/dist/esm-node/runtime/i18n/detection/path.mjs +12 -0
- package/dist/esm-node/runtime/i18n/detection/priority.mjs +29 -0
- package/dist/esm-node/runtime/i18n/detection/ssr.mjs +27 -0
- package/dist/esm-node/runtime/i18n/detection/types.mjs +1 -0
- package/dist/esm-node/runtime/linkHelpers.mjs +99 -0
- package/dist/esm-node/runtime/pluginSetup.mjs +65 -0
- package/dist/esm-node/runtime/providerComposition.mjs +76 -0
- package/dist/esm-node/runtime/reactI18next.mjs +6 -0
- package/dist/esm-node/server/apiPrefix.mjs +32 -0
- package/dist/esm-node/server/detectorOptions.mjs +60 -0
- package/dist/esm-node/server/index.mjs +6 -133
- package/dist/esm-node/server/redirectPolicy.mjs +53 -0
- package/dist/esm-node/shared/localisedUrls/config.mjs +12 -0
- package/dist/esm-node/shared/localisedUrls/index.mjs +7 -0
- package/dist/esm-node/shared/localisedUrls/normalise.mjs +38 -0
- package/dist/esm-node/shared/localisedUrls/pathname.mjs +25 -0
- package/dist/esm-node/shared/localisedUrls/patterns.mjs +87 -0
- package/dist/esm-node/shared/localisedUrls/resolve.mjs +51 -0
- package/dist/esm-node/shared/localisedUrls/routes.mjs +89 -0
- package/dist/esm-node/shared/localisedUrls/types.mjs +1 -0
- package/dist/esm-node/shared/localisedUrls.mjs +1 -283
- package/dist/types/runtime/Link.d.ts +3 -7
- package/dist/types/runtime/context.d.ts +2 -2
- package/dist/types/runtime/contextHelpers.d.ts +28 -0
- package/dist/types/runtime/core.d.ts +3 -7
- package/dist/types/runtime/hooks.d.ts +5 -0
- package/dist/types/runtime/i18n/detection/cache.d.ts +14 -0
- package/dist/types/runtime/i18n/detection/detector.d.ts +8 -0
- package/dist/types/runtime/i18n/detection/index.d.ts +5 -50
- package/dist/types/runtime/i18n/detection/initOptions.d.ts +10 -0
- package/dist/types/runtime/i18n/detection/language.d.ts +11 -0
- package/dist/types/runtime/i18n/detection/path.d.ts +5 -0
- package/dist/types/runtime/i18n/detection/priority.d.ts +10 -0
- package/dist/types/runtime/i18n/detection/ssr.d.ts +9 -0
- package/dist/types/runtime/i18n/detection/types.d.ts +29 -0
- package/dist/types/runtime/i18n/react-i18next.d.ts +1 -6
- package/dist/types/runtime/linkHelpers.d.ts +17 -0
- package/dist/types/runtime/pluginSetup.d.ts +32 -0
- package/dist/types/runtime/providerComposition.d.ts +15 -0
- package/dist/types/runtime/reactI18next.d.ts +7 -0
- package/dist/types/runtime/utils.d.ts +7 -2
- package/dist/types/server/apiPrefix.d.ts +7 -0
- package/dist/types/server/detectorOptions.d.ts +21 -0
- package/dist/types/server/index.d.ts +1 -6
- package/dist/types/server/redirectPolicy.d.ts +16 -0
- package/dist/types/shared/localisedUrls/config.d.ts +9 -0
- package/dist/types/shared/localisedUrls/index.d.ts +7 -0
- package/dist/types/shared/localisedUrls/normalise.d.ts +10 -0
- package/dist/types/shared/localisedUrls/pathname.d.ts +3 -0
- package/dist/types/shared/localisedUrls/patterns.d.ts +5 -0
- package/dist/types/shared/localisedUrls/resolve.d.ts +8 -0
- package/dist/types/shared/localisedUrls/routes.d.ts +3 -0
- package/dist/types/shared/localisedUrls/types.d.ts +14 -0
- package/dist/types/shared/localisedUrls.d.ts +2 -36
- package/package.json +10 -10
- package/src/cli/index.ts +3 -2
- package/src/runtime/Link.tsx +11 -138
- package/src/runtime/context.tsx +42 -196
- package/src/runtime/contextHelpers.ts +232 -0
- package/src/runtime/core.tsx +43 -274
- package/src/runtime/hooks.ts +3 -0
- package/src/runtime/i18n/detection/cache.ts +175 -0
- package/src/runtime/i18n/detection/detector.ts +157 -0
- package/src/runtime/i18n/detection/index.ts +10 -641
- package/src/runtime/i18n/detection/initOptions.ts +74 -0
- package/src/runtime/i18n/detection/language.ts +64 -0
- package/src/runtime/i18n/detection/path.ts +41 -0
- package/src/runtime/i18n/detection/priority.ts +82 -0
- package/src/runtime/i18n/detection/ssr.ts +47 -0
- package/src/runtime/i18n/detection/types.ts +33 -0
- package/src/runtime/i18n/react-i18next.ts +1 -6
- package/src/runtime/linkHelpers.ts +174 -0
- package/src/runtime/pluginSetup.ts +189 -0
- package/src/runtime/providerComposition.tsx +142 -0
- package/src/runtime/reactI18next.ts +20 -0
- package/src/runtime/utils.ts +7 -5
- package/src/server/apiPrefix.ts +67 -0
- package/src/server/detectorOptions.ts +105 -0
- package/src/server/index.ts +14 -319
- package/src/server/redirectPolicy.ts +152 -0
- package/src/shared/localisedUrls/config.ts +18 -0
- package/src/shared/localisedUrls/index.ts +13 -0
- package/src/shared/localisedUrls/normalise.ts +67 -0
- package/src/shared/localisedUrls/pathname.ts +57 -0
- package/src/shared/localisedUrls/patterns.ts +160 -0
- package/src/shared/localisedUrls/resolve.ts +118 -0
- package/src/shared/localisedUrls/routes.ts +226 -0
- package/src/shared/localisedUrls/types.ts +18 -0
- package/src/shared/localisedUrls.ts +20 -623
- package/tests/link.test.tsx +111 -0
- package/tests/linkTypes.test.ts +15 -4
- package/tests/localisedUrls.test.ts +54 -2
- package/tests/reactI18nextRuntimeBoundary.test.ts +6 -3
- package/tests/routerAdapter.test.tsx +56 -0
- package/tests/type-fixture/fixture-globals.d.ts +11 -0
- package/tests/type-fixture/tsconfig.json +1 -0
|
@@ -1,31 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { merge } from "@modern-js/runtime-utils/merge";
|
|
5
|
-
import { useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
6
|
-
import { ModernI18nProvider, useModernI18n } from "./context.mjs";
|
|
7
|
-
import { createContextValue, useClientSideRedirect, useLanguageSync, useSdkResourcesLoader } from "./hooks.mjs";
|
|
8
|
-
import { getI18nInstance } from "./i18n/index.mjs";
|
|
9
|
-
import { mergeBackendOptions } from "./i18n/backend/index.mjs";
|
|
10
|
-
import { detectLanguageWithPriority, exportServerLngToWindow, mergeDetectionOptions } from "./i18n/detection/index.mjs";
|
|
11
|
-
import { useI18nextLanguageDetector } from "./i18n/detection/middleware.mjs";
|
|
12
|
-
import { getI18nextInstanceForProvider } from "./i18n/instance.mjs";
|
|
13
|
-
import { buildLocalizedUrl, getPathname, splitUrlTarget } from "./utils.mjs";
|
|
1
|
+
import { setupI18nBeforeRender } from "./pluginSetup.mjs";
|
|
2
|
+
import { createI18nRootWrapper } from "./providerComposition.mjs";
|
|
3
|
+
import { resolveReactI18nextIntegration } from "./reactI18next.mjs";
|
|
14
4
|
import "./types.mjs";
|
|
15
|
-
let i18nLifecycleHelpersPromise;
|
|
16
|
-
function loadI18nLifecycleHelpers() {
|
|
17
|
-
i18nLifecycleHelpersPromise ??= Promise.all([
|
|
18
|
-
import("./i18n/backend/middleware.mjs"),
|
|
19
|
-
import("./i18n/utils.mjs")
|
|
20
|
-
]).then(([backendMiddleware, utils])=>({
|
|
21
|
-
useI18nextBackend: backendMiddleware.useI18nextBackend,
|
|
22
|
-
changeI18nLanguage: utils.changeI18nLanguage,
|
|
23
|
-
ensureLanguageMatch: utils.ensureLanguageMatch,
|
|
24
|
-
initializeI18nInstance: utils.initializeI18nInstance,
|
|
25
|
-
setupClonedInstance: utils.setupClonedInstance
|
|
26
|
-
}));
|
|
27
|
-
return i18nLifecycleHelpersPromise;
|
|
28
|
-
}
|
|
29
5
|
const createI18nPlugin = (loadReactI18nextIntegration)=>(options)=>({
|
|
30
6
|
name: '@modern-js/plugin-i18n',
|
|
31
7
|
setup: (api)=>{
|
|
@@ -34,119 +10,40 @@ const createI18nPlugin = (loadReactI18nextIntegration)=>(options)=>({
|
|
|
34
10
|
const { enabled: backendEnabled = false } = backend || {};
|
|
35
11
|
let latestI18nInstance;
|
|
36
12
|
let I18nextProvider;
|
|
37
|
-
const resolveReactI18nextIntegration = async ()=>{
|
|
38
|
-
if (!reactI18next) return null;
|
|
39
|
-
return loadReactI18nextIntegration?.() ?? null;
|
|
40
|
-
};
|
|
41
13
|
api.onBeforeRender(async (context)=>{
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
I18nextProvider = reactI18nextIntegration?.I18nextProvider ?? null;
|
|
49
|
-
if (reactI18nextIntegration?.initReactI18next) i18nInstance.use(reactI18nextIntegration.initReactI18next);
|
|
50
|
-
const pathname = getPathname(context);
|
|
51
|
-
if (i18nextDetector) useI18nextLanguageDetector(i18nInstance);
|
|
52
|
-
const mergedDetection = mergeDetectionOptions(i18nextDetector, detection, localePathRedirect, userInitOptions);
|
|
53
|
-
const mergedBackend = mergeBackendOptions(backend, userInitOptions);
|
|
54
|
-
const hasSdkConfig = 'function' == typeof userInitOptions?.backend?.sdk || mergedBackend?.sdk && 'function' == typeof mergedBackend.sdk;
|
|
55
|
-
if (mergedBackend && (backendEnabled || hasSdkConfig)) useI18nextBackend(i18nInstance, mergedBackend);
|
|
56
|
-
const { finalLanguage } = await detectLanguageWithPriority(i18nInstance, {
|
|
57
|
-
languages,
|
|
58
|
-
fallbackLanguage,
|
|
59
|
-
localePathRedirect,
|
|
14
|
+
latestI18nInstance = await setupI18nBeforeRender(context, {
|
|
15
|
+
api,
|
|
16
|
+
userI18nInstance,
|
|
17
|
+
initOptions,
|
|
18
|
+
backend,
|
|
19
|
+
backendEnabled,
|
|
60
20
|
i18nextDetector,
|
|
61
21
|
detection,
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if (!isBrowser() && i18nInstance.cloneInstance) {
|
|
69
|
-
i18nInstance = i18nInstance.cloneInstance();
|
|
70
|
-
await setupClonedInstance(i18nInstance, finalLanguage, fallbackLanguage, languages, backendEnabled, backend, i18nextDetector, detection, localePathRedirect, userInitOptions);
|
|
71
|
-
}
|
|
72
|
-
if (localePathRedirect) await ensureLanguageMatch(i18nInstance, finalLanguage);
|
|
73
|
-
if (!isBrowser()) exportServerLngToWindow(context, finalLanguage);
|
|
74
|
-
context.i18nInstance = i18nInstance;
|
|
75
|
-
latestI18nInstance = i18nInstance;
|
|
76
|
-
context.changeLanguage = async (newLang)=>{
|
|
77
|
-
await changeI18nLanguage(i18nInstance, newLang, {
|
|
78
|
-
detectionOptions: mergedDetection
|
|
79
|
-
});
|
|
80
|
-
};
|
|
81
|
-
});
|
|
82
|
-
api.wrapRoot((App)=>(props)=>{
|
|
83
|
-
const runtimeContext = useContext(RuntimeContext);
|
|
84
|
-
const i18nInstance = runtimeContext.i18nInstance || latestI18nInstance;
|
|
85
|
-
const initialLang = useMemo(()=>i18nInstance?.language || (localeDetection?.fallbackLanguage ?? 'en'), [
|
|
86
|
-
i18nInstance?.language,
|
|
87
|
-
localeDetection?.fallbackLanguage
|
|
88
|
-
]);
|
|
89
|
-
const [lang, setLang] = useState(initialLang);
|
|
90
|
-
const [forceUpdate, setForceUpdate] = useState(0);
|
|
91
|
-
const prevLangRef = useRef(lang);
|
|
92
|
-
const runtimeContextRef = useRef(runtimeContext);
|
|
93
|
-
runtimeContextRef.current = runtimeContext;
|
|
94
|
-
useEffect(()=>{
|
|
95
|
-
if (i18nInstance?.language) {
|
|
96
|
-
const translator = i18nInstance.translator;
|
|
97
|
-
if (translator) translator.language = i18nInstance.language;
|
|
98
|
-
}
|
|
99
|
-
}, [
|
|
100
|
-
i18nInstance?.language
|
|
101
|
-
]);
|
|
102
|
-
useEffect(()=>{
|
|
103
|
-
prevLangRef.current = lang;
|
|
104
|
-
}, [
|
|
105
|
-
lang
|
|
106
|
-
]);
|
|
107
|
-
useSdkResourcesLoader(i18nInstance, setForceUpdate);
|
|
108
|
-
useLanguageSync(i18nInstance, localePathRedirect, languages, runtimeContextRef, prevLangRef, setLang);
|
|
109
|
-
useClientSideRedirect(i18nInstance, localePathRedirect, languages, fallbackLanguage, ignoreRedirectRoutes, localisedUrls);
|
|
110
|
-
const contextValue = useMemo(()=>createContextValue(lang, i18nInstance, entryName, languages, localePathRedirect, ignoreRedirectRoutes, localisedUrls, setLang), [
|
|
111
|
-
lang,
|
|
112
|
-
i18nInstance,
|
|
113
|
-
entryName,
|
|
114
|
-
languages,
|
|
115
|
-
localePathRedirect,
|
|
116
|
-
ignoreRedirectRoutes,
|
|
117
|
-
localisedUrls,
|
|
118
|
-
forceUpdate
|
|
119
|
-
]);
|
|
120
|
-
const children = props.children;
|
|
121
|
-
const appContent = /*#__PURE__*/ jsxs(Fragment, {
|
|
122
|
-
children: [
|
|
123
|
-
Boolean(htmlLangAttr) && /*#__PURE__*/ jsx(Helmet, {
|
|
124
|
-
htmlAttributes: {
|
|
125
|
-
lang
|
|
126
|
-
}
|
|
127
|
-
}),
|
|
128
|
-
/*#__PURE__*/ jsx(ModernI18nProvider, {
|
|
129
|
-
value: contextValue,
|
|
130
|
-
children: App ? /*#__PURE__*/ jsx(App, {
|
|
131
|
-
...props,
|
|
132
|
-
children: children
|
|
133
|
-
}) : children
|
|
134
|
-
})
|
|
135
|
-
]
|
|
136
|
-
});
|
|
137
|
-
if (!i18nInstance) return appContent;
|
|
138
|
-
if (I18nextProvider) {
|
|
139
|
-
const i18nextInstanceForProvider = getI18nextInstanceForProvider(i18nInstance);
|
|
140
|
-
return /*#__PURE__*/ jsx(I18nextProvider, {
|
|
141
|
-
i18n: i18nextInstanceForProvider,
|
|
142
|
-
children: appContent
|
|
143
|
-
});
|
|
22
|
+
localePathRedirect,
|
|
23
|
+
languages,
|
|
24
|
+
fallbackLanguage,
|
|
25
|
+
resolveReactI18nextIntegration: ()=>resolveReactI18nextIntegration(reactI18next, loadReactI18nextIntegration),
|
|
26
|
+
setI18nextProvider: (provider)=>{
|
|
27
|
+
I18nextProvider = provider;
|
|
144
28
|
}
|
|
145
|
-
return appContent;
|
|
146
29
|
});
|
|
30
|
+
});
|
|
31
|
+
api.wrapRoot(createI18nRootWrapper({
|
|
32
|
+
entryName,
|
|
33
|
+
htmlLangAttr,
|
|
34
|
+
localePathRedirect,
|
|
35
|
+
languages,
|
|
36
|
+
fallbackLanguage,
|
|
37
|
+
ignoreRedirectRoutes,
|
|
38
|
+
localisedUrls,
|
|
39
|
+
getLatestI18nInstance: ()=>latestI18nInstance,
|
|
40
|
+
getI18nextProvider: ()=>I18nextProvider
|
|
41
|
+
}));
|
|
147
42
|
}
|
|
148
43
|
});
|
|
44
|
+
export { useModernI18n } from "./context.mjs";
|
|
149
45
|
export { I18nLink } from "./I18nLink.mjs";
|
|
150
46
|
export { Link } from "./Link.mjs";
|
|
151
47
|
export { canonicalPath, localizePath, useLocalizedLocation, useLocalizedPaths } from "./localizedPaths.mjs";
|
|
152
|
-
export { buildLocalizedUrl,
|
|
48
|
+
export { buildLocalizedUrl, splitUrlTarget } from "./utils.mjs";
|
|
49
|
+
export { createI18nPlugin };
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
const detectorInstanceCache = new WeakMap();
|
|
2
|
+
const DETECTOR_SAFE_OPTION_KEYS = [
|
|
3
|
+
'lowerCaseLng',
|
|
4
|
+
'nonExplicitSupportedLngs',
|
|
5
|
+
'load',
|
|
6
|
+
'partialBundledLanguages',
|
|
7
|
+
'returnNull',
|
|
8
|
+
'returnEmptyString',
|
|
9
|
+
'returnObjects',
|
|
10
|
+
'joinArrays',
|
|
11
|
+
'keySeparator',
|
|
12
|
+
'nsSeparator',
|
|
13
|
+
'pluralSeparator',
|
|
14
|
+
'contextSeparator',
|
|
15
|
+
'fallbackNS',
|
|
16
|
+
'ns',
|
|
17
|
+
'defaultNS',
|
|
18
|
+
'debug'
|
|
19
|
+
];
|
|
20
|
+
const stableStringify = (value)=>{
|
|
21
|
+
if (null == value) return JSON.stringify(value);
|
|
22
|
+
if ('object' != typeof value) return JSON.stringify(value);
|
|
23
|
+
if (Array.isArray(value)) return `[${value.map((item)=>stableStringify(item)).join(',')}]`;
|
|
24
|
+
const sortedKeys = Object.keys(value).sort();
|
|
25
|
+
const sortedEntries = sortedKeys.map((key)=>{
|
|
26
|
+
const stringifiedValue = stableStringify(value[key]);
|
|
27
|
+
return `${JSON.stringify(key)}:${stringifiedValue}`;
|
|
28
|
+
});
|
|
29
|
+
return `{${sortedEntries.join(',')}}`;
|
|
30
|
+
};
|
|
31
|
+
const buildDetectorConfigKey = (languages, fallbackLanguage, mergedDetection)=>stableStringify({
|
|
32
|
+
languages,
|
|
33
|
+
fallbackLanguage,
|
|
34
|
+
detection: mergedDetection
|
|
35
|
+
});
|
|
36
|
+
const pickSafeDetectionOptions = (userInitOptions)=>{
|
|
37
|
+
if (!userInitOptions) return {};
|
|
38
|
+
const safeOptions = {};
|
|
39
|
+
for (const key of DETECTOR_SAFE_OPTION_KEYS){
|
|
40
|
+
const value = userInitOptions[key];
|
|
41
|
+
if (void 0 !== value) safeOptions[key] = value;
|
|
42
|
+
}
|
|
43
|
+
if (userInitOptions.interpolation) safeOptions.interpolation = {
|
|
44
|
+
...userInitOptions.interpolation
|
|
45
|
+
};
|
|
46
|
+
return safeOptions;
|
|
47
|
+
};
|
|
48
|
+
const cleanupDetectorCacheEntry = (entry)=>{
|
|
49
|
+
if (!entry || !entry.isTemporary) return;
|
|
50
|
+
const instance = entry.instance;
|
|
51
|
+
try {
|
|
52
|
+
instance?.removeAllListeners?.();
|
|
53
|
+
} catch (error) {}
|
|
54
|
+
try {
|
|
55
|
+
instance?.off?.('*');
|
|
56
|
+
} catch (error) {}
|
|
57
|
+
try {
|
|
58
|
+
instance?.services?.backendConnector?.backend?.stop?.();
|
|
59
|
+
} catch (error) {}
|
|
60
|
+
try {
|
|
61
|
+
instance?.services?.backendConnector?.backend?.close?.();
|
|
62
|
+
} catch (error) {}
|
|
63
|
+
};
|
|
64
|
+
const createDetectorInstance = (baseInstance, configKey)=>{
|
|
65
|
+
const cached = detectorInstanceCache.get(baseInstance);
|
|
66
|
+
if (cached && cached.configKey === configKey) return {
|
|
67
|
+
instance: cached.instance,
|
|
68
|
+
isTemporary: cached.isTemporary
|
|
69
|
+
};
|
|
70
|
+
if (cached) {
|
|
71
|
+
cleanupDetectorCacheEntry(cached);
|
|
72
|
+
detectorInstanceCache.delete(baseInstance);
|
|
73
|
+
}
|
|
74
|
+
const createNewInstance = ()=>{
|
|
75
|
+
if ('function' == typeof baseInstance.createInstance) try {
|
|
76
|
+
const created = baseInstance.createInstance();
|
|
77
|
+
if (created) return {
|
|
78
|
+
instance: created,
|
|
79
|
+
isTemporary: true
|
|
80
|
+
};
|
|
81
|
+
} catch (error) {}
|
|
82
|
+
if ('function' == typeof baseInstance.cloneInstance) try {
|
|
83
|
+
const cloned = baseInstance.cloneInstance();
|
|
84
|
+
if (cloned) return {
|
|
85
|
+
instance: cloned,
|
|
86
|
+
isTemporary: true
|
|
87
|
+
};
|
|
88
|
+
} catch (error) {}
|
|
89
|
+
return {
|
|
90
|
+
instance: baseInstance,
|
|
91
|
+
isTemporary: false
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
const created = createNewInstance();
|
|
95
|
+
if (created.isTemporary) detectorInstanceCache.set(baseInstance, {
|
|
96
|
+
instance: created.instance,
|
|
97
|
+
isTemporary: true,
|
|
98
|
+
configKey
|
|
99
|
+
});
|
|
100
|
+
return created;
|
|
101
|
+
};
|
|
102
|
+
export { buildDetectorConfigKey, createDetectorInstance, detectorInstanceCache, pickSafeDetectionOptions };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { isBrowser } from "@modern-js/runtime";
|
|
2
|
+
import { buildDetectorConfigKey, createDetectorInstance, detectorInstanceCache, pickSafeDetectionOptions } from "./cache.mjs";
|
|
3
|
+
import { mergeDetectionOptions } from "./initOptions.mjs";
|
|
4
|
+
import { getSupportedLanguage, isLanguageSupported } from "./language.mjs";
|
|
5
|
+
import { detectLanguage, useI18nextLanguageDetector } from "./middleware.mjs";
|
|
6
|
+
const initializeI18nForDetector = async (i18nInstance, options)=>{
|
|
7
|
+
const mergedDetection = mergeDetectionOptions(options.i18nextDetector, options.detection, options.localePathRedirect, options.userInitOptions);
|
|
8
|
+
const configKey = buildDetectorConfigKey(options.languages, options.fallbackLanguage, mergedDetection);
|
|
9
|
+
const { instance, isTemporary } = createDetectorInstance(i18nInstance, configKey);
|
|
10
|
+
const safeUserOptions = pickSafeDetectionOptions(options.userInitOptions);
|
|
11
|
+
const initOptions = {
|
|
12
|
+
...safeUserOptions,
|
|
13
|
+
fallbackLng: options.fallbackLanguage,
|
|
14
|
+
supportedLngs: options.languages,
|
|
15
|
+
detection: mergedDetection,
|
|
16
|
+
initImmediate: true,
|
|
17
|
+
interpolation: {
|
|
18
|
+
...safeUserOptions?.interpolation || {},
|
|
19
|
+
escapeValue: safeUserOptions?.interpolation?.escapeValue ?? false
|
|
20
|
+
},
|
|
21
|
+
react: {
|
|
22
|
+
useSuspense: false
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
useI18nextLanguageDetector(instance);
|
|
26
|
+
if (instance.isInitialized) {
|
|
27
|
+
if (isTemporary) await instance.init(initOptions);
|
|
28
|
+
} else await instance.init(initOptions);
|
|
29
|
+
return {
|
|
30
|
+
detectorInstance: instance,
|
|
31
|
+
isTemporary
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
const detectLanguageFromI18nextDetector = async (i18nInstance, options)=>{
|
|
35
|
+
if (!options.i18nextDetector) return;
|
|
36
|
+
const mergedDetection = mergeDetectionOptions(options.i18nextDetector, options.detection, options.localePathRedirect, options.userInitOptions);
|
|
37
|
+
const { detectorInstance, isTemporary } = await initializeI18nForDetector(i18nInstance, options);
|
|
38
|
+
try {
|
|
39
|
+
const request = options.ssrContext?.request;
|
|
40
|
+
if (!isBrowser() && !request) return;
|
|
41
|
+
const detectorLang = detectLanguage(detectorInstance, request, mergedDetection);
|
|
42
|
+
if (detectorLang) {
|
|
43
|
+
const supportedLang = getSupportedLanguage(detectorLang, options.languages);
|
|
44
|
+
if (supportedLang) return supportedLang;
|
|
45
|
+
}
|
|
46
|
+
if (detectorInstance.isInitialized && detectorInstance.language) {
|
|
47
|
+
const currentLang = detectorInstance.language;
|
|
48
|
+
if (isLanguageSupported(currentLang, options.languages)) return currentLang;
|
|
49
|
+
}
|
|
50
|
+
} catch (error) {} finally{
|
|
51
|
+
if (isTemporary && detectorInstance !== i18nInstance) detectorInstanceCache.set(i18nInstance, {
|
|
52
|
+
instance: detectorInstance,
|
|
53
|
+
isTemporary: true,
|
|
54
|
+
configKey: buildDetectorConfigKey(options.languages, options.fallbackLanguage, mergedDetection)
|
|
55
|
+
});
|
|
56
|
+
else if (detectorInstance === i18nInstance) {
|
|
57
|
+
i18nInstance.isInitialized = false;
|
|
58
|
+
delete i18nInstance.language;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
export { detectLanguageFromI18nextDetector };
|
|
@@ -1,260 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import { cacheUserLanguage, detectLanguage, readLanguageFromStorage, useI18nextLanguageDetector } from "./middleware.mjs";
|
|
6
|
-
const detectorInstanceCache = new WeakMap();
|
|
7
|
-
const DETECTOR_SAFE_OPTION_KEYS = [
|
|
8
|
-
'lowerCaseLng',
|
|
9
|
-
'nonExplicitSupportedLngs',
|
|
10
|
-
'load',
|
|
11
|
-
'partialBundledLanguages',
|
|
12
|
-
'returnNull',
|
|
13
|
-
'returnEmptyString',
|
|
14
|
-
'returnObjects',
|
|
15
|
-
'joinArrays',
|
|
16
|
-
'keySeparator',
|
|
17
|
-
'nsSeparator',
|
|
18
|
-
'pluralSeparator',
|
|
19
|
-
'contextSeparator',
|
|
20
|
-
'fallbackNS',
|
|
21
|
-
'ns',
|
|
22
|
-
'defaultNS',
|
|
23
|
-
'debug'
|
|
24
|
-
];
|
|
25
|
-
const stableStringify = (value)=>{
|
|
26
|
-
if (null == value) return JSON.stringify(value);
|
|
27
|
-
if ('object' != typeof value) return JSON.stringify(value);
|
|
28
|
-
if (Array.isArray(value)) return `[${value.map((item)=>stableStringify(item)).join(',')}]`;
|
|
29
|
-
const sortedKeys = Object.keys(value).sort();
|
|
30
|
-
const sortedEntries = sortedKeys.map((key)=>{
|
|
31
|
-
const stringifiedValue = stableStringify(value[key]);
|
|
32
|
-
return `${JSON.stringify(key)}:${stringifiedValue}`;
|
|
33
|
-
});
|
|
34
|
-
return `{${sortedEntries.join(',')}}`;
|
|
35
|
-
};
|
|
36
|
-
const buildDetectorConfigKey = (languages, fallbackLanguage, mergedDetection)=>stableStringify({
|
|
37
|
-
languages,
|
|
38
|
-
fallbackLanguage,
|
|
39
|
-
detection: mergedDetection
|
|
40
|
-
});
|
|
41
|
-
const pickSafeDetectionOptions = (userInitOptions)=>{
|
|
42
|
-
if (!userInitOptions) return {};
|
|
43
|
-
const safeOptions = {};
|
|
44
|
-
for (const key of DETECTOR_SAFE_OPTION_KEYS){
|
|
45
|
-
const value = userInitOptions[key];
|
|
46
|
-
if (void 0 !== value) safeOptions[key] = value;
|
|
47
|
-
}
|
|
48
|
-
if (userInitOptions.interpolation) safeOptions.interpolation = {
|
|
49
|
-
...userInitOptions.interpolation
|
|
50
|
-
};
|
|
51
|
-
return safeOptions;
|
|
52
|
-
};
|
|
53
|
-
const cleanupDetectorCacheEntry = (entry)=>{
|
|
54
|
-
if (!entry || !entry.isTemporary) return;
|
|
55
|
-
const instance = entry.instance;
|
|
56
|
-
try {
|
|
57
|
-
instance?.removeAllListeners?.();
|
|
58
|
-
} catch (error) {}
|
|
59
|
-
try {
|
|
60
|
-
instance?.off?.('*');
|
|
61
|
-
} catch (error) {}
|
|
62
|
-
try {
|
|
63
|
-
instance?.services?.backendConnector?.backend?.stop?.();
|
|
64
|
-
} catch (error) {}
|
|
65
|
-
try {
|
|
66
|
-
instance?.services?.backendConnector?.backend?.close?.();
|
|
67
|
-
} catch (error) {}
|
|
68
|
-
};
|
|
69
|
-
function exportServerLngToWindow(context, lng) {
|
|
70
|
-
context.__i18nData__ = {
|
|
71
|
-
lng
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
const getLanguageFromSSRData = (window1)=>{
|
|
75
|
-
try {
|
|
76
|
-
const ssrData = window1._SSR_DATA;
|
|
77
|
-
if (!ssrData || !ssrData.data || !ssrData.data.i18nData) return;
|
|
78
|
-
const lng = ssrData.data.i18nData.lng;
|
|
79
|
-
return 'string' == typeof lng && '' !== lng.trim() ? lng : void 0;
|
|
80
|
-
} catch (error) {
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
const normalizeLanguageCode = (language)=>{
|
|
85
|
-
if (!language) return language;
|
|
86
|
-
const baseLang = language.split('-')[0];
|
|
87
|
-
return baseLang;
|
|
88
|
-
};
|
|
89
|
-
const isLanguageSupported = (language, supportedLanguages)=>{
|
|
90
|
-
if (!language) return false;
|
|
91
|
-
if (0 === supportedLanguages.length) return true;
|
|
92
|
-
if (supportedLanguages.includes(language)) return true;
|
|
93
|
-
const baseLang = normalizeLanguageCode(language);
|
|
94
|
-
if (baseLang !== language && supportedLanguages.includes(baseLang)) return true;
|
|
95
|
-
return false;
|
|
96
|
-
};
|
|
97
|
-
const getSupportedLanguage = (language, supportedLanguages)=>{
|
|
98
|
-
if (!language) return;
|
|
99
|
-
if (0 === supportedLanguages.length) return language;
|
|
100
|
-
if (supportedLanguages.includes(language)) return language;
|
|
101
|
-
const baseLang = normalizeLanguageCode(language);
|
|
102
|
-
if (baseLang !== language && supportedLanguages.includes(baseLang)) return baseLang;
|
|
103
|
-
};
|
|
104
|
-
const detectLanguageFromSSR = (languages)=>{
|
|
105
|
-
if (!isBrowser()) return;
|
|
106
|
-
try {
|
|
107
|
-
const ssrLanguage = getLanguageFromSSRData(window);
|
|
108
|
-
if (ssrLanguage && isLanguageSupported(ssrLanguage, languages)) return ssrLanguage;
|
|
109
|
-
} catch (error) {}
|
|
110
|
-
};
|
|
111
|
-
const detectLanguageFromPathPriority = (pathname, languages, localePathRedirect)=>{
|
|
112
|
-
if (!localePathRedirect) return;
|
|
113
|
-
if (!languages || 0 === languages.length) return;
|
|
114
|
-
if (!pathname || '' === pathname.trim()) return;
|
|
115
|
-
try {
|
|
116
|
-
const pathDetection = detectLanguageFromPath(pathname, languages, localePathRedirect);
|
|
117
|
-
if (true === pathDetection.detected && pathDetection.language) return pathDetection.language;
|
|
118
|
-
} catch (error) {}
|
|
119
|
-
};
|
|
120
|
-
const createDetectorInstance = (baseInstance, configKey)=>{
|
|
121
|
-
const cached = detectorInstanceCache.get(baseInstance);
|
|
122
|
-
if (cached && cached.configKey === configKey) return {
|
|
123
|
-
instance: cached.instance,
|
|
124
|
-
isTemporary: cached.isTemporary
|
|
125
|
-
};
|
|
126
|
-
if (cached) {
|
|
127
|
-
cleanupDetectorCacheEntry(cached);
|
|
128
|
-
detectorInstanceCache.delete(baseInstance);
|
|
129
|
-
}
|
|
130
|
-
const createNewInstance = ()=>{
|
|
131
|
-
if ('function' == typeof baseInstance.createInstance) try {
|
|
132
|
-
const created = baseInstance.createInstance();
|
|
133
|
-
if (created) return {
|
|
134
|
-
instance: created,
|
|
135
|
-
isTemporary: true
|
|
136
|
-
};
|
|
137
|
-
} catch (error) {}
|
|
138
|
-
if ('function' == typeof baseInstance.cloneInstance) try {
|
|
139
|
-
const cloned = baseInstance.cloneInstance();
|
|
140
|
-
if (cloned) return {
|
|
141
|
-
instance: cloned,
|
|
142
|
-
isTemporary: true
|
|
143
|
-
};
|
|
144
|
-
} catch (error) {}
|
|
145
|
-
return {
|
|
146
|
-
instance: baseInstance,
|
|
147
|
-
isTemporary: false
|
|
148
|
-
};
|
|
149
|
-
};
|
|
150
|
-
const created = createNewInstance();
|
|
151
|
-
if (created.isTemporary) detectorInstanceCache.set(baseInstance, {
|
|
152
|
-
instance: created.instance,
|
|
153
|
-
isTemporary: true,
|
|
154
|
-
configKey
|
|
155
|
-
});
|
|
156
|
-
return created;
|
|
157
|
-
};
|
|
158
|
-
const initializeI18nForDetector = async (i18nInstance, options)=>{
|
|
159
|
-
const mergedDetection = detection_mergeDetectionOptions(options.i18nextDetector, options.detection, options.localePathRedirect, options.userInitOptions);
|
|
160
|
-
const configKey = buildDetectorConfigKey(options.languages, options.fallbackLanguage, mergedDetection);
|
|
161
|
-
const { instance, isTemporary } = createDetectorInstance(i18nInstance, configKey);
|
|
162
|
-
const safeUserOptions = pickSafeDetectionOptions(options.userInitOptions);
|
|
163
|
-
const initOptions = {
|
|
164
|
-
...safeUserOptions,
|
|
165
|
-
fallbackLng: options.fallbackLanguage,
|
|
166
|
-
supportedLngs: options.languages,
|
|
167
|
-
detection: mergedDetection,
|
|
168
|
-
initImmediate: true,
|
|
169
|
-
interpolation: {
|
|
170
|
-
...safeUserOptions?.interpolation || {},
|
|
171
|
-
escapeValue: safeUserOptions?.interpolation?.escapeValue ?? false
|
|
172
|
-
},
|
|
173
|
-
react: {
|
|
174
|
-
useSuspense: false
|
|
175
|
-
}
|
|
176
|
-
};
|
|
177
|
-
useI18nextLanguageDetector(instance);
|
|
178
|
-
if (instance.isInitialized) {
|
|
179
|
-
if (isTemporary) await instance.init(initOptions);
|
|
180
|
-
} else await instance.init(initOptions);
|
|
181
|
-
return {
|
|
182
|
-
detectorInstance: instance,
|
|
183
|
-
isTemporary
|
|
184
|
-
};
|
|
185
|
-
};
|
|
186
|
-
const detectLanguageFromI18nextDetector = async (i18nInstance, options)=>{
|
|
187
|
-
if (!options.i18nextDetector) return;
|
|
188
|
-
const mergedDetection = detection_mergeDetectionOptions(options.i18nextDetector, options.detection, options.localePathRedirect, options.userInitOptions);
|
|
189
|
-
const { detectorInstance, isTemporary } = await initializeI18nForDetector(i18nInstance, options);
|
|
190
|
-
try {
|
|
191
|
-
const request = options.ssrContext?.request;
|
|
192
|
-
if (!isBrowser() && !request) return;
|
|
193
|
-
const detectorLang = detectLanguage(detectorInstance, request, mergedDetection);
|
|
194
|
-
if (detectorLang) {
|
|
195
|
-
const supportedLang = getSupportedLanguage(detectorLang, options.languages);
|
|
196
|
-
if (supportedLang) return supportedLang;
|
|
197
|
-
}
|
|
198
|
-
if (detectorInstance.isInitialized && detectorInstance.language) {
|
|
199
|
-
const currentLang = detectorInstance.language;
|
|
200
|
-
if (isLanguageSupported(currentLang, options.languages)) return currentLang;
|
|
201
|
-
}
|
|
202
|
-
} catch (error) {} finally{
|
|
203
|
-
if (isTemporary && detectorInstance !== i18nInstance) detectorInstanceCache.set(i18nInstance, {
|
|
204
|
-
instance: detectorInstance,
|
|
205
|
-
isTemporary: true,
|
|
206
|
-
configKey: buildDetectorConfigKey(options.languages, options.fallbackLanguage, mergedDetection)
|
|
207
|
-
});
|
|
208
|
-
else if (detectorInstance === i18nInstance) {
|
|
209
|
-
i18nInstance.isInitialized = false;
|
|
210
|
-
delete i18nInstance.language;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
};
|
|
214
|
-
const detectLanguageWithPriority = async (i18nInstance, options)=>{
|
|
215
|
-
const { languages, fallbackLanguage, localePathRedirect, i18nextDetector, detection, userInitOptions, pathname, ssrContext } = options;
|
|
216
|
-
let detectedLanguage;
|
|
217
|
-
detectedLanguage = detectLanguageFromSSR(languages);
|
|
218
|
-
if (!detectedLanguage) detectedLanguage = detectLanguageFromPathPriority(pathname, languages, localePathRedirect);
|
|
219
|
-
if (!detectedLanguage && i18nextDetector) detectedLanguage = isI18nWrapperInstance(i18nInstance) ? readLanguageFromStorage(detection_mergeDetectionOptions(i18nextDetector, detection, localePathRedirect, userInitOptions)) : await detectLanguageFromI18nextDetector(i18nInstance, {
|
|
220
|
-
languages,
|
|
221
|
-
fallbackLanguage,
|
|
222
|
-
localePathRedirect,
|
|
223
|
-
i18nextDetector,
|
|
224
|
-
detection,
|
|
225
|
-
userInitOptions,
|
|
226
|
-
mergedBackend: options.mergedBackend,
|
|
227
|
-
ssrContext
|
|
228
|
-
});
|
|
229
|
-
const finalLanguage = detectedLanguage || userInitOptions?.lng || fallbackLanguage;
|
|
230
|
-
return {
|
|
231
|
-
detectedLanguage,
|
|
232
|
-
finalLanguage
|
|
233
|
-
};
|
|
234
|
-
};
|
|
235
|
-
const buildInitOptions = (params)=>{
|
|
236
|
-
const { finalLanguage, fallbackLanguage, languages, userInitOptions, mergedDetection, mergeBackend } = params;
|
|
237
|
-
return {
|
|
238
|
-
...userInitOptions || {},
|
|
239
|
-
lng: finalLanguage,
|
|
240
|
-
fallbackLng: fallbackLanguage,
|
|
241
|
-
supportedLngs: languages,
|
|
242
|
-
detection: mergedDetection,
|
|
243
|
-
backend: mergeBackend,
|
|
244
|
-
interpolation: {
|
|
245
|
-
...userInitOptions?.interpolation || {},
|
|
246
|
-
escapeValue: userInitOptions?.interpolation?.escapeValue ?? false
|
|
247
|
-
},
|
|
248
|
-
react: {
|
|
249
|
-
useSuspense: isBrowser()
|
|
250
|
-
}
|
|
251
|
-
};
|
|
252
|
-
};
|
|
253
|
-
const detection_mergeDetectionOptions = (i18nextDetector, detection, localePathRedirect, userInitOptions)=>{
|
|
254
|
-
let mergedDetection;
|
|
255
|
-
mergedDetection = i18nextDetector ? mergeDetectionOptions(detection, userInitOptions?.detection) : userInitOptions?.detection || {};
|
|
256
|
-
if (!mergedDetection || 'object' != typeof mergedDetection) mergedDetection = {};
|
|
257
|
-
if (localePathRedirect && mergedDetection.order) mergedDetection.order = mergedDetection.order.filter((item)=>'path' !== item);
|
|
258
|
-
return mergedDetection;
|
|
259
|
-
};
|
|
260
|
-
export { buildInitOptions, cacheUserLanguage, detectLanguageWithPriority, detection_mergeDetectionOptions as mergeDetectionOptions, exportServerLngToWindow, getLanguageFromSSRData };
|
|
1
|
+
export { buildInitOptions, mergeDetectionOptions } from "./initOptions.mjs";
|
|
2
|
+
export { cacheUserLanguage } from "./middleware.mjs";
|
|
3
|
+
export { detectLanguageWithPriority } from "./priority.mjs";
|
|
4
|
+
export { exportServerLngToWindow, getLanguageFromSSRData } from "./ssr.mjs";
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { isBrowser } from "@modern-js/runtime";
|
|
2
|
+
import { mergeDetectionOptions } from "./config.mjs";
|
|
3
|
+
const buildInitOptions = (params)=>{
|
|
4
|
+
const { finalLanguage, fallbackLanguage, languages, userInitOptions, mergedDetection, mergeBackend } = params;
|
|
5
|
+
return {
|
|
6
|
+
...userInitOptions || {},
|
|
7
|
+
lng: finalLanguage,
|
|
8
|
+
fallbackLng: fallbackLanguage,
|
|
9
|
+
supportedLngs: languages,
|
|
10
|
+
detection: mergedDetection,
|
|
11
|
+
backend: mergeBackend,
|
|
12
|
+
interpolation: {
|
|
13
|
+
...userInitOptions?.interpolation || {},
|
|
14
|
+
escapeValue: userInitOptions?.interpolation?.escapeValue ?? false
|
|
15
|
+
},
|
|
16
|
+
react: {
|
|
17
|
+
useSuspense: isBrowser()
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
const initOptions_mergeDetectionOptions = (i18nextDetector, detection, localePathRedirect, userInitOptions)=>{
|
|
22
|
+
let mergedDetection;
|
|
23
|
+
mergedDetection = i18nextDetector ? mergeDetectionOptions(detection, userInitOptions?.detection) : userInitOptions?.detection || {};
|
|
24
|
+
if (!mergedDetection || 'object' != typeof mergedDetection) mergedDetection = {};
|
|
25
|
+
if (localePathRedirect && mergedDetection.order) mergedDetection.order = mergedDetection.order.filter((item)=>'path' !== item);
|
|
26
|
+
return mergedDetection;
|
|
27
|
+
};
|
|
28
|
+
export { buildInitOptions, initOptions_mergeDetectionOptions as mergeDetectionOptions };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const normalizeLanguageCode = (language)=>{
|
|
2
|
+
if (!language) return language;
|
|
3
|
+
const baseLang = language.split('-')[0];
|
|
4
|
+
return baseLang;
|
|
5
|
+
};
|
|
6
|
+
const isLanguageSupported = (language, supportedLanguages)=>{
|
|
7
|
+
if (!language) return false;
|
|
8
|
+
if (0 === supportedLanguages.length) return true;
|
|
9
|
+
if (supportedLanguages.includes(language)) return true;
|
|
10
|
+
const baseLang = normalizeLanguageCode(language);
|
|
11
|
+
if (baseLang !== language && supportedLanguages.includes(baseLang)) return true;
|
|
12
|
+
return false;
|
|
13
|
+
};
|
|
14
|
+
const getSupportedLanguage = (language, supportedLanguages)=>{
|
|
15
|
+
if (!language) return;
|
|
16
|
+
if (0 === supportedLanguages.length) return language;
|
|
17
|
+
if (supportedLanguages.includes(language)) return language;
|
|
18
|
+
const baseLang = normalizeLanguageCode(language);
|
|
19
|
+
if (baseLang !== language && supportedLanguages.includes(baseLang)) return baseLang;
|
|
20
|
+
};
|
|
21
|
+
export { getSupportedLanguage, isLanguageSupported };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { detectLanguageFromPath } from "../../utils.mjs";
|
|
2
|
+
const detectLanguageFromPathPriority = (pathname, languages, localePathRedirect)=>{
|
|
3
|
+
if (!localePathRedirect) return;
|
|
4
|
+
if (!languages || 0 === languages.length) return;
|
|
5
|
+
if (!pathname || '' === pathname.trim()) return;
|
|
6
|
+
try {
|
|
7
|
+
const pathDetection = detectLanguageFromPath(pathname, languages, localePathRedirect);
|
|
8
|
+
if (true === pathDetection.detected && pathDetection.language) return pathDetection.language;
|
|
9
|
+
} catch (error) {}
|
|
10
|
+
};
|
|
11
|
+
export { detectLanguageFromPathPriority };
|