@bleedingdev/modern-js-plugin-i18n 3.2.0-ultramodern.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +32 -0
- package/dist/cjs/cli/index.js +154 -0
- package/dist/cjs/runtime/I18nLink.js +68 -0
- package/dist/cjs/runtime/context.js +142 -0
- package/dist/cjs/runtime/hooks.js +194 -0
- package/dist/cjs/runtime/i18n/backend/config.js +39 -0
- package/dist/cjs/runtime/i18n/backend/defaults.js +56 -0
- package/dist/cjs/runtime/i18n/backend/defaults.node.js +56 -0
- package/dist/cjs/runtime/i18n/backend/index.js +108 -0
- package/dist/cjs/runtime/i18n/backend/middleware.common.js +105 -0
- package/dist/cjs/runtime/i18n/backend/middleware.js +54 -0
- package/dist/cjs/runtime/i18n/backend/middleware.node.js +58 -0
- package/dist/cjs/runtime/i18n/backend/sdk-backend.js +175 -0
- package/dist/cjs/runtime/i18n/backend/sdk-event.js +64 -0
- package/dist/cjs/runtime/i18n/detection/config.js +63 -0
- package/dist/cjs/runtime/i18n/detection/index.js +309 -0
- package/dist/cjs/runtime/i18n/detection/middleware.js +185 -0
- package/dist/cjs/runtime/i18n/detection/middleware.node.js +74 -0
- package/dist/cjs/runtime/i18n/index.js +43 -0
- package/dist/cjs/runtime/i18n/instance.js +132 -0
- package/dist/cjs/runtime/i18n/utils.js +189 -0
- package/dist/cjs/runtime/index.js +174 -0
- package/dist/cjs/runtime/types.js +18 -0
- package/dist/cjs/runtime/utils.js +136 -0
- package/dist/cjs/server/index.js +218 -0
- package/dist/cjs/shared/deepMerge.js +54 -0
- package/dist/cjs/shared/detection.js +105 -0
- package/dist/cjs/shared/type.js +18 -0
- package/dist/cjs/shared/utils.js +78 -0
- package/dist/esm/cli/index.mjs +107 -0
- package/dist/esm/rslib-runtime.mjs +18 -0
- package/dist/esm/runtime/I18nLink.mjs +32 -0
- package/dist/esm/runtime/context.mjs +105 -0
- package/dist/esm/runtime/hooks.mjs +151 -0
- package/dist/esm/runtime/i18n/backend/config.mjs +5 -0
- package/dist/esm/runtime/i18n/backend/defaults.mjs +19 -0
- package/dist/esm/runtime/i18n/backend/defaults.node.mjs +19 -0
- package/dist/esm/runtime/i18n/backend/index.mjs +74 -0
- package/dist/esm/runtime/i18n/backend/middleware.common.mjs +61 -0
- package/dist/esm/runtime/i18n/backend/middleware.mjs +7 -0
- package/dist/esm/runtime/i18n/backend/middleware.node.mjs +8 -0
- package/dist/esm/runtime/i18n/backend/sdk-backend.mjs +141 -0
- package/dist/esm/runtime/i18n/backend/sdk-event.mjs +21 -0
- package/dist/esm/runtime/i18n/detection/config.mjs +26 -0
- package/dist/esm/runtime/i18n/detection/index.mjs +260 -0
- package/dist/esm/runtime/i18n/detection/middleware.mjs +132 -0
- package/dist/esm/runtime/i18n/detection/middleware.node.mjs +31 -0
- package/dist/esm/runtime/i18n/index.mjs +2 -0
- package/dist/esm/runtime/i18n/instance.mjs +77 -0
- package/dist/esm/runtime/i18n/utils.mjs +140 -0
- package/dist/esm/runtime/index.mjs +132 -0
- package/dist/esm/runtime/types.mjs +0 -0
- package/dist/esm/runtime/utils.mjs +75 -0
- package/dist/esm/server/index.mjs +182 -0
- package/dist/esm/shared/deepMerge.mjs +20 -0
- package/dist/esm/shared/detection.mjs +71 -0
- package/dist/esm/shared/type.mjs +0 -0
- package/dist/esm/shared/utils.mjs +35 -0
- package/dist/esm-node/cli/index.mjs +108 -0
- package/dist/esm-node/rslib-runtime.mjs +19 -0
- package/dist/esm-node/runtime/I18nLink.mjs +33 -0
- package/dist/esm-node/runtime/context.mjs +106 -0
- package/dist/esm-node/runtime/hooks.mjs +152 -0
- package/dist/esm-node/runtime/i18n/backend/config.mjs +6 -0
- package/dist/esm-node/runtime/i18n/backend/defaults.mjs +20 -0
- package/dist/esm-node/runtime/i18n/backend/defaults.node.mjs +20 -0
- package/dist/esm-node/runtime/i18n/backend/index.mjs +75 -0
- package/dist/esm-node/runtime/i18n/backend/middleware.common.mjs +62 -0
- package/dist/esm-node/runtime/i18n/backend/middleware.mjs +8 -0
- package/dist/esm-node/runtime/i18n/backend/middleware.node.mjs +9 -0
- package/dist/esm-node/runtime/i18n/backend/sdk-backend.mjs +142 -0
- package/dist/esm-node/runtime/i18n/backend/sdk-event.mjs +22 -0
- package/dist/esm-node/runtime/i18n/detection/config.mjs +27 -0
- package/dist/esm-node/runtime/i18n/detection/index.mjs +261 -0
- package/dist/esm-node/runtime/i18n/detection/middleware.mjs +133 -0
- package/dist/esm-node/runtime/i18n/detection/middleware.node.mjs +32 -0
- package/dist/esm-node/runtime/i18n/index.mjs +3 -0
- package/dist/esm-node/runtime/i18n/instance.mjs +78 -0
- package/dist/esm-node/runtime/i18n/utils.mjs +141 -0
- package/dist/esm-node/runtime/index.mjs +133 -0
- package/dist/esm-node/runtime/types.mjs +1 -0
- package/dist/esm-node/runtime/utils.mjs +76 -0
- package/dist/esm-node/server/index.mjs +183 -0
- package/dist/esm-node/shared/deepMerge.mjs +21 -0
- package/dist/esm-node/shared/detection.mjs +72 -0
- package/dist/esm-node/shared/type.mjs +1 -0
- package/dist/esm-node/shared/utils.mjs +36 -0
- package/dist/types/cli/index.d.ts +21 -0
- package/dist/types/runtime/I18nLink.d.ts +8 -0
- package/dist/types/runtime/context.d.ts +38 -0
- package/dist/types/runtime/hooks.d.ts +28 -0
- package/dist/types/runtime/i18n/backend/config.d.ts +2 -0
- package/dist/types/runtime/i18n/backend/defaults.d.ts +13 -0
- package/dist/types/runtime/i18n/backend/defaults.node.d.ts +8 -0
- package/dist/types/runtime/i18n/backend/index.d.ts +3 -0
- package/dist/types/runtime/i18n/backend/middleware.common.d.ts +14 -0
- package/dist/types/runtime/i18n/backend/middleware.d.ts +12 -0
- package/dist/types/runtime/i18n/backend/middleware.node.d.ts +13 -0
- package/dist/types/runtime/i18n/backend/sdk-backend.d.ts +53 -0
- package/dist/types/runtime/i18n/backend/sdk-event.d.ts +9 -0
- package/dist/types/runtime/i18n/detection/config.d.ts +11 -0
- package/dist/types/runtime/i18n/detection/index.d.ts +50 -0
- package/dist/types/runtime/i18n/detection/middleware.d.ts +24 -0
- package/dist/types/runtime/i18n/detection/middleware.node.d.ts +17 -0
- package/dist/types/runtime/i18n/index.d.ts +3 -0
- package/dist/types/runtime/i18n/instance.d.ts +93 -0
- package/dist/types/runtime/i18n/utils.d.ts +29 -0
- package/dist/types/runtime/index.d.ts +20 -0
- package/dist/types/runtime/types.d.ts +15 -0
- package/dist/types/runtime/utils.d.ts +33 -0
- package/dist/types/server/index.d.ts +8 -0
- package/dist/types/shared/deepMerge.d.ts +1 -0
- package/dist/types/shared/detection.d.ts +11 -0
- package/dist/types/shared/type.d.ts +156 -0
- package/dist/types/shared/utils.d.ts +5 -0
- package/package.json +136 -0
- package/rslib.config.mts +4 -0
- package/src/cli/index.ts +245 -0
- package/src/runtime/I18nLink.tsx +76 -0
- package/src/runtime/context.tsx +281 -0
- package/src/runtime/hooks.ts +298 -0
- package/src/runtime/i18n/backend/config.ts +10 -0
- package/src/runtime/i18n/backend/defaults.node.ts +31 -0
- package/src/runtime/i18n/backend/defaults.ts +37 -0
- package/src/runtime/i18n/backend/index.ts +181 -0
- package/src/runtime/i18n/backend/middleware.common.ts +116 -0
- package/src/runtime/i18n/backend/middleware.node.ts +32 -0
- package/src/runtime/i18n/backend/middleware.ts +28 -0
- package/src/runtime/i18n/backend/sdk-backend.ts +306 -0
- package/src/runtime/i18n/backend/sdk-event.ts +39 -0
- package/src/runtime/i18n/detection/config.ts +32 -0
- package/src/runtime/i18n/detection/index.ts +641 -0
- package/src/runtime/i18n/detection/middleware.node.ts +84 -0
- package/src/runtime/i18n/detection/middleware.ts +251 -0
- package/src/runtime/i18n/index.ts +8 -0
- package/src/runtime/i18n/instance.ts +227 -0
- package/src/runtime/i18n/utils.ts +351 -0
- package/src/runtime/index.tsx +285 -0
- package/src/runtime/types.ts +17 -0
- package/src/runtime/utils.ts +163 -0
- package/src/server/index.ts +406 -0
- package/src/shared/deepMerge.ts +38 -0
- package/src/shared/detection.ts +131 -0
- package/src/shared/type.ts +170 -0
- package/src/shared/utils.ts +82 -0
- package/tsconfig.json +13 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { RuntimeContext, isBrowser } from "@modern-js/runtime";
|
|
3
|
+
import { Helmet } from "@modern-js/runtime/head";
|
|
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 { useI18nextBackend } from "./i18n/backend/middleware.mjs";
|
|
11
|
+
import { detectLanguageWithPriority, exportServerLngToWindow, mergeDetectionOptions } from "./i18n/detection/index.mjs";
|
|
12
|
+
import { useI18nextLanguageDetector } from "./i18n/detection/middleware.mjs";
|
|
13
|
+
import { getI18nextInstanceForProvider, getI18nextProvider, getInitReactI18next } from "./i18n/instance.mjs";
|
|
14
|
+
import { changeI18nLanguage, ensureLanguageMatch, initializeI18nInstance, setupClonedInstance } from "./i18n/utils.mjs";
|
|
15
|
+
import { getPathname } from "./utils.mjs";
|
|
16
|
+
import "./types.mjs";
|
|
17
|
+
const i18nPlugin = (options)=>({
|
|
18
|
+
name: '@modern-js/plugin-i18n',
|
|
19
|
+
setup: (api)=>{
|
|
20
|
+
const { entryName, i18nInstance: userI18nInstance, initOptions, localeDetection, backend, htmlLangAttr = false } = options;
|
|
21
|
+
const { localePathRedirect = false, i18nextDetector = true, languages = [], fallbackLanguage = 'en', detection, ignoreRedirectRoutes } = localeDetection || {};
|
|
22
|
+
const { enabled: backendEnabled = false } = backend || {};
|
|
23
|
+
let latestI18nInstance;
|
|
24
|
+
let I18nextProvider;
|
|
25
|
+
api.onBeforeRender(async (context)=>{
|
|
26
|
+
let i18nInstance = await getI18nInstance(userI18nInstance);
|
|
27
|
+
const { i18n: otherConfig } = api.getRuntimeConfig();
|
|
28
|
+
const { initOptions: otherInitOptions } = otherConfig || {};
|
|
29
|
+
const userInitOptions = merge(otherInitOptions || {}, initOptions || {});
|
|
30
|
+
const initReactI18next = await getInitReactI18next();
|
|
31
|
+
I18nextProvider = await getI18nextProvider();
|
|
32
|
+
if (initReactI18next) i18nInstance.use(initReactI18next);
|
|
33
|
+
const pathname = getPathname(context);
|
|
34
|
+
if (i18nextDetector) useI18nextLanguageDetector(i18nInstance);
|
|
35
|
+
const mergedDetection = mergeDetectionOptions(i18nextDetector, detection, localePathRedirect, userInitOptions);
|
|
36
|
+
const mergedBackend = mergeBackendOptions(backend, userInitOptions);
|
|
37
|
+
const hasSdkConfig = 'function' == typeof userInitOptions?.backend?.sdk || mergedBackend?.sdk && 'function' == typeof mergedBackend.sdk;
|
|
38
|
+
if (mergedBackend && (backendEnabled || hasSdkConfig)) useI18nextBackend(i18nInstance, mergedBackend);
|
|
39
|
+
const { finalLanguage } = await detectLanguageWithPriority(i18nInstance, {
|
|
40
|
+
languages,
|
|
41
|
+
fallbackLanguage,
|
|
42
|
+
localePathRedirect,
|
|
43
|
+
i18nextDetector,
|
|
44
|
+
detection,
|
|
45
|
+
userInitOptions,
|
|
46
|
+
mergedBackend,
|
|
47
|
+
pathname,
|
|
48
|
+
ssrContext: context.ssrContext
|
|
49
|
+
});
|
|
50
|
+
await initializeI18nInstance(i18nInstance, finalLanguage, fallbackLanguage, languages, mergedDetection, mergedBackend, userInitOptions);
|
|
51
|
+
if (!isBrowser() && i18nInstance.cloneInstance) {
|
|
52
|
+
i18nInstance = i18nInstance.cloneInstance();
|
|
53
|
+
await setupClonedInstance(i18nInstance, finalLanguage, fallbackLanguage, languages, backendEnabled, backend, i18nextDetector, detection, localePathRedirect, userInitOptions);
|
|
54
|
+
}
|
|
55
|
+
if (localePathRedirect) await ensureLanguageMatch(i18nInstance, finalLanguage);
|
|
56
|
+
if (!isBrowser()) exportServerLngToWindow(context, finalLanguage);
|
|
57
|
+
context.i18nInstance = i18nInstance;
|
|
58
|
+
latestI18nInstance = i18nInstance;
|
|
59
|
+
context.changeLanguage = async (newLang)=>{
|
|
60
|
+
await changeI18nLanguage(i18nInstance, newLang, {
|
|
61
|
+
detectionOptions: mergedDetection
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
api.wrapRoot((App)=>(props)=>{
|
|
66
|
+
const runtimeContext = useContext(RuntimeContext);
|
|
67
|
+
const i18nInstance = runtimeContext.i18nInstance || latestI18nInstance;
|
|
68
|
+
const initialLang = useMemo(()=>i18nInstance?.language || (localeDetection?.fallbackLanguage ?? 'en'), [
|
|
69
|
+
i18nInstance?.language,
|
|
70
|
+
localeDetection?.fallbackLanguage
|
|
71
|
+
]);
|
|
72
|
+
const [lang, setLang] = useState(initialLang);
|
|
73
|
+
const [forceUpdate, setForceUpdate] = useState(0);
|
|
74
|
+
const prevLangRef = useRef(lang);
|
|
75
|
+
const runtimeContextRef = useRef(runtimeContext);
|
|
76
|
+
runtimeContextRef.current = runtimeContext;
|
|
77
|
+
useEffect(()=>{
|
|
78
|
+
if (i18nInstance?.language) {
|
|
79
|
+
const translator = i18nInstance.translator;
|
|
80
|
+
if (translator) translator.language = i18nInstance.language;
|
|
81
|
+
}
|
|
82
|
+
}, [
|
|
83
|
+
i18nInstance?.language
|
|
84
|
+
]);
|
|
85
|
+
useEffect(()=>{
|
|
86
|
+
prevLangRef.current = lang;
|
|
87
|
+
}, [
|
|
88
|
+
lang
|
|
89
|
+
]);
|
|
90
|
+
useSdkResourcesLoader(i18nInstance, setForceUpdate);
|
|
91
|
+
useLanguageSync(i18nInstance, localePathRedirect, languages, runtimeContextRef, prevLangRef, setLang);
|
|
92
|
+
useClientSideRedirect(i18nInstance, localePathRedirect, languages, fallbackLanguage, ignoreRedirectRoutes);
|
|
93
|
+
const contextValue = useMemo(()=>createContextValue(lang, i18nInstance, entryName, languages, localePathRedirect, ignoreRedirectRoutes, setLang), [
|
|
94
|
+
lang,
|
|
95
|
+
i18nInstance,
|
|
96
|
+
entryName,
|
|
97
|
+
languages,
|
|
98
|
+
localePathRedirect,
|
|
99
|
+
ignoreRedirectRoutes,
|
|
100
|
+
forceUpdate
|
|
101
|
+
]);
|
|
102
|
+
const appContent = /*#__PURE__*/ jsxs(Fragment, {
|
|
103
|
+
children: [
|
|
104
|
+
Boolean(htmlLangAttr) && /*#__PURE__*/ jsx(Helmet, {
|
|
105
|
+
htmlAttributes: {
|
|
106
|
+
lang
|
|
107
|
+
}
|
|
108
|
+
}),
|
|
109
|
+
/*#__PURE__*/ jsx(ModernI18nProvider, {
|
|
110
|
+
value: contextValue,
|
|
111
|
+
children: /*#__PURE__*/ jsx(App, {
|
|
112
|
+
...props
|
|
113
|
+
})
|
|
114
|
+
})
|
|
115
|
+
]
|
|
116
|
+
});
|
|
117
|
+
if (!i18nInstance) return appContent;
|
|
118
|
+
if (I18nextProvider) {
|
|
119
|
+
const i18nextInstanceForProvider = getI18nextInstanceForProvider(i18nInstance);
|
|
120
|
+
return /*#__PURE__*/ jsx(I18nextProvider, {
|
|
121
|
+
i18n: i18nextInstanceForProvider,
|
|
122
|
+
children: appContent
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
return appContent;
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
const runtime = i18nPlugin;
|
|
130
|
+
export { I18nLink } from "./I18nLink.mjs";
|
|
131
|
+
export default runtime;
|
|
132
|
+
export { i18nPlugin, useModernI18n };
|
|
File without changes
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { isBrowser } from "@modern-js/runtime";
|
|
2
|
+
import { getGlobalBasename } from "@modern-js/runtime/context";
|
|
3
|
+
import { __webpack_require__ } from "../rslib-runtime.mjs";
|
|
4
|
+
import * as __rspack_external__modern_js_runtime_router_2dfd0c78 from "@modern-js/runtime/router";
|
|
5
|
+
__webpack_require__.add({
|
|
6
|
+
"@modern-js/runtime/router?f1fa" (module) {
|
|
7
|
+
module.exports = __rspack_external__modern_js_runtime_router_2dfd0c78;
|
|
8
|
+
}
|
|
9
|
+
});
|
|
10
|
+
const getPathname = (context)=>{
|
|
11
|
+
if (isBrowser()) return window.location.pathname;
|
|
12
|
+
return context.ssrContext?.request?.pathname || '/';
|
|
13
|
+
};
|
|
14
|
+
const getEntryPath = ()=>{
|
|
15
|
+
const basename = getGlobalBasename();
|
|
16
|
+
if (basename) return '/' === basename ? '' : basename;
|
|
17
|
+
return '';
|
|
18
|
+
};
|
|
19
|
+
const getLanguageFromPath = (pathname, languages, fallbackLanguage)=>{
|
|
20
|
+
const segments = pathname.split('/').filter(Boolean);
|
|
21
|
+
const firstSegment = segments[0];
|
|
22
|
+
if (languages.includes(firstSegment)) return firstSegment;
|
|
23
|
+
return fallbackLanguage;
|
|
24
|
+
};
|
|
25
|
+
const buildLocalizedUrl = (pathname, language, languages)=>{
|
|
26
|
+
const segments = pathname.split('/').filter(Boolean);
|
|
27
|
+
if (segments.length > 0 && languages.includes(segments[0])) segments[0] = language;
|
|
28
|
+
else segments.unshift(language);
|
|
29
|
+
return `/${segments.join('/')}`;
|
|
30
|
+
};
|
|
31
|
+
const detectLanguageFromPath = (pathname, languages, localePathRedirect)=>{
|
|
32
|
+
if (!localePathRedirect) return {
|
|
33
|
+
detected: false
|
|
34
|
+
};
|
|
35
|
+
const entryPath = getEntryPath();
|
|
36
|
+
const relativePath = pathname.replace(entryPath, '');
|
|
37
|
+
const segments = relativePath.split('/').filter(Boolean);
|
|
38
|
+
const segmentsToCheck = !entryPath && segments.length > 1 && segments[0] && !languages.includes(segments[0]) ? segments.slice(1) : segments;
|
|
39
|
+
const firstSegment = segmentsToCheck[0];
|
|
40
|
+
if (firstSegment && languages.includes(firstSegment)) return {
|
|
41
|
+
detected: true,
|
|
42
|
+
language: firstSegment
|
|
43
|
+
};
|
|
44
|
+
return {
|
|
45
|
+
detected: false
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
const shouldIgnoreRedirect = (pathname, languages, ignoreRedirectRoutes)=>{
|
|
49
|
+
if (!ignoreRedirectRoutes) return false;
|
|
50
|
+
const segments = pathname.split('/').filter(Boolean);
|
|
51
|
+
let pathWithoutLang = pathname;
|
|
52
|
+
if (segments.length > 0 && languages.includes(segments[0])) pathWithoutLang = `/${segments.slice(1).join('/')}`;
|
|
53
|
+
const normalizedPath = pathWithoutLang.startsWith('/') ? pathWithoutLang : `/${pathWithoutLang}`;
|
|
54
|
+
if ('function' == typeof ignoreRedirectRoutes) return ignoreRedirectRoutes(normalizedPath);
|
|
55
|
+
return ignoreRedirectRoutes.some((pattern)=>normalizedPath === pattern || normalizedPath.startsWith(`${pattern}/`));
|
|
56
|
+
};
|
|
57
|
+
const useRouterHooks = ()=>{
|
|
58
|
+
try {
|
|
59
|
+
const { useLocation, useNavigate, useParams } = __webpack_require__("@modern-js/runtime/router?f1fa");
|
|
60
|
+
return {
|
|
61
|
+
navigate: useNavigate(),
|
|
62
|
+
location: useLocation(),
|
|
63
|
+
params: useParams(),
|
|
64
|
+
hasRouter: true
|
|
65
|
+
};
|
|
66
|
+
} catch (error) {
|
|
67
|
+
return {
|
|
68
|
+
navigate: null,
|
|
69
|
+
location: null,
|
|
70
|
+
params: {},
|
|
71
|
+
hasRouter: false
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
export { buildLocalizedUrl, detectLanguageFromPath, getEntryPath, getLanguageFromPath, getPathname, shouldIgnoreRedirect, useRouterHooks };
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { DEFAULT_I18NEXT_DETECTION_OPTIONS, mergeDetectionOptions } from "../runtime/i18n/detection/config.mjs";
|
|
2
|
+
import { getLocaleDetectionOptions } from "../shared/utils.mjs";
|
|
3
|
+
import * as __rspack_external__modern_js_server_core_hono_a76ca254 from "@modern-js/server-core/hono";
|
|
4
|
+
const { languageDetector: languageDetector } = __rspack_external__modern_js_server_core_hono_a76ca254;
|
|
5
|
+
const convertToHonoLanguageDetectorOptions = (languages, fallbackLanguage, detectionOptions)=>{
|
|
6
|
+
const mergedDetection = detectionOptions ? mergeDetectionOptions(detectionOptions) : DEFAULT_I18NEXT_DETECTION_OPTIONS;
|
|
7
|
+
const order = (mergedDetection.order || []).filter((item)=>![
|
|
8
|
+
'path',
|
|
9
|
+
'localStorage',
|
|
10
|
+
'navigator',
|
|
11
|
+
'htmlTag',
|
|
12
|
+
'subdomain'
|
|
13
|
+
].includes(item));
|
|
14
|
+
const detectionOrder = order.length > 0 ? order : [
|
|
15
|
+
'querystring',
|
|
16
|
+
'cookie',
|
|
17
|
+
'header'
|
|
18
|
+
];
|
|
19
|
+
const honoOrder = detectionOrder.map((item)=>{
|
|
20
|
+
if ('querystring' === item) return 'querystring';
|
|
21
|
+
if ('cookie' === item) return 'cookie';
|
|
22
|
+
if ('header' === item) return 'header';
|
|
23
|
+
return item;
|
|
24
|
+
});
|
|
25
|
+
const caches = false === mergedDetection.caches ? false : Array.isArray(mergedDetection.caches) && !mergedDetection.caches.includes('cookie') ? false : [
|
|
26
|
+
'cookie'
|
|
27
|
+
];
|
|
28
|
+
const cookieMinutes = mergedDetection.cookieMinutes;
|
|
29
|
+
const cookieMaxAge = 'number' == typeof cookieMinutes && Number.isFinite(cookieMinutes) ? Math.max(0, Math.floor(60 * cookieMinutes)) : 60 * DEFAULT_I18NEXT_DETECTION_OPTIONS.cookieMinutes;
|
|
30
|
+
const cookieDomain = mergedDetection.cookieDomain;
|
|
31
|
+
const cookieSecure = mergedDetection.cookieSecure;
|
|
32
|
+
const cookieHttpOnly = mergedDetection.cookieHttpOnly;
|
|
33
|
+
const cookieSameSite = mergedDetection.cookieSameSite;
|
|
34
|
+
const normalizedCookieDomain = 'string' == typeof cookieDomain ? cookieDomain : void 0;
|
|
35
|
+
const cookieOptions = {
|
|
36
|
+
maxAge: cookieMaxAge,
|
|
37
|
+
sameSite: 'None' === cookieSameSite || 'none' === cookieSameSite ? 'None' : 'Lax' === cookieSameSite || 'lax' === cookieSameSite ? 'Lax' : 'Strict',
|
|
38
|
+
secure: 'boolean' == typeof cookieSecure ? cookieSecure : false,
|
|
39
|
+
httpOnly: 'boolean' == typeof cookieHttpOnly ? cookieHttpOnly : false,
|
|
40
|
+
...normalizedCookieDomain ? {
|
|
41
|
+
domain: normalizedCookieDomain
|
|
42
|
+
} : {}
|
|
43
|
+
};
|
|
44
|
+
return {
|
|
45
|
+
supportedLanguages: languages.length > 0 ? languages : [
|
|
46
|
+
fallbackLanguage
|
|
47
|
+
],
|
|
48
|
+
fallbackLanguage,
|
|
49
|
+
order: honoOrder,
|
|
50
|
+
lookupQueryString: mergedDetection.lookupQuerystring || DEFAULT_I18NEXT_DETECTION_OPTIONS.lookupQuerystring || 'lng',
|
|
51
|
+
lookupCookie: mergedDetection.lookupCookie || DEFAULT_I18NEXT_DETECTION_OPTIONS.lookupCookie || 'i18next',
|
|
52
|
+
lookupFromHeaderKey: mergedDetection.lookupHeader || DEFAULT_I18NEXT_DETECTION_OPTIONS.lookupHeader || 'accept-language',
|
|
53
|
+
...void 0 !== caches && {
|
|
54
|
+
caches
|
|
55
|
+
},
|
|
56
|
+
...false !== caches && {
|
|
57
|
+
cookieOptions
|
|
58
|
+
},
|
|
59
|
+
ignoreCase: true
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
const shouldIgnoreRedirect = (pathname, urlPath, ignoreRedirectRoutes)=>{
|
|
63
|
+
if (!ignoreRedirectRoutes) return false;
|
|
64
|
+
const basePath = urlPath.replace('/*', '');
|
|
65
|
+
const remainingPath = pathname.startsWith(basePath) ? pathname.slice(basePath.length) : pathname;
|
|
66
|
+
const normalizedPath = remainingPath.startsWith('/') ? remainingPath : `/${remainingPath}`;
|
|
67
|
+
if ('function' == typeof ignoreRedirectRoutes) return ignoreRedirectRoutes(normalizedPath);
|
|
68
|
+
return ignoreRedirectRoutes.some((pattern)=>normalizedPath === pattern || normalizedPath.startsWith(`${pattern}/`));
|
|
69
|
+
};
|
|
70
|
+
const isStaticResourceRequest = (pathname, staticRoutePrefixes, languages = [])=>{
|
|
71
|
+
if (staticRoutePrefixes.some((prefix)=>pathname.startsWith(`${prefix}/`) || pathname === prefix)) return true;
|
|
72
|
+
const standardStaticPrefixes = [
|
|
73
|
+
'/static/',
|
|
74
|
+
'/upload/'
|
|
75
|
+
];
|
|
76
|
+
if (standardStaticPrefixes.some((prefix)=>pathname.startsWith(prefix))) return true;
|
|
77
|
+
const pathSegments = pathname.split('/').filter(Boolean);
|
|
78
|
+
if (pathSegments.length > 0 && languages.includes(pathSegments[0])) {
|
|
79
|
+
const pathWithoutLang = '/' + pathSegments.slice(1).join('/');
|
|
80
|
+
if (standardStaticPrefixes.some((prefix)=>pathWithoutLang.startsWith(prefix)) || staticRoutePrefixes.some((prefix)=>pathWithoutLang.startsWith(`${prefix}/`) || pathWithoutLang === prefix)) return true;
|
|
81
|
+
}
|
|
82
|
+
return false;
|
|
83
|
+
};
|
|
84
|
+
const getLanguageFromPath = (req, urlPath, languages)=>{
|
|
85
|
+
const url = new URL(req.url, `http://${req.header().host}`);
|
|
86
|
+
const pathname = url.pathname;
|
|
87
|
+
const basePath = urlPath.replace('/*', '');
|
|
88
|
+
const remainingPath = pathname.startsWith(basePath) ? pathname.slice(basePath.length) : pathname;
|
|
89
|
+
const segments = remainingPath.split('/').filter(Boolean);
|
|
90
|
+
const firstSegment = segments[0];
|
|
91
|
+
if (languages.includes(firstSegment)) return firstSegment;
|
|
92
|
+
return null;
|
|
93
|
+
};
|
|
94
|
+
const buildLocalizedUrl = (req, urlPath, language, languages)=>{
|
|
95
|
+
const url = new URL(req.url);
|
|
96
|
+
const pathname = url.pathname;
|
|
97
|
+
const basePath = urlPath.replace('/*', '');
|
|
98
|
+
const remainingPath = pathname.startsWith(basePath) ? pathname.slice(basePath.length) : pathname;
|
|
99
|
+
const segments = remainingPath.split('/').filter(Boolean);
|
|
100
|
+
if (segments.length > 0 && languages.includes(segments[0])) segments[0] = language;
|
|
101
|
+
else segments.unshift(language);
|
|
102
|
+
const newPathname = `/${segments.join('/')}`;
|
|
103
|
+
const suffix = `${url.search}${url.hash}`;
|
|
104
|
+
const localizedUrl = '/' === basePath ? newPathname + suffix : basePath + newPathname + suffix;
|
|
105
|
+
return localizedUrl;
|
|
106
|
+
};
|
|
107
|
+
const i18nServerPlugin = (options)=>({
|
|
108
|
+
name: '@modern-js/plugin-i18n/server',
|
|
109
|
+
setup: (api)=>{
|
|
110
|
+
api.onPrepare(()=>{
|
|
111
|
+
const { middlewares, routes } = api.getServerContext();
|
|
112
|
+
const entryPaths = new Set();
|
|
113
|
+
routes.forEach((route)=>{
|
|
114
|
+
if (route.entryName && route.urlPath && '/' !== route.urlPath) {
|
|
115
|
+
const pathSegments = route.urlPath.split('/').filter(Boolean);
|
|
116
|
+
if (pathSegments.length > 0) entryPaths.add(`/${pathSegments[0]}`);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
routes.map((route)=>{
|
|
120
|
+
const { entryName } = route;
|
|
121
|
+
if (!entryName) return;
|
|
122
|
+
if (!options.localeDetection) return;
|
|
123
|
+
const { localePathRedirect, i18nextDetector = true, languages = [], fallbackLanguage = 'en', detection, ignoreRedirectRoutes } = getLocaleDetectionOptions(entryName, options.localeDetection);
|
|
124
|
+
const staticRoutePrefixes = options.staticRoutePrefixes;
|
|
125
|
+
const originUrlPath = route.urlPath;
|
|
126
|
+
const urlPath = originUrlPath.endsWith('/') ? `${originUrlPath}*` : `${originUrlPath}/*`;
|
|
127
|
+
if (localePathRedirect) {
|
|
128
|
+
if (i18nextDetector) {
|
|
129
|
+
const detectorOptions = convertToHonoLanguageDetectorOptions(languages, fallbackLanguage, detection);
|
|
130
|
+
const detectorHandler = languageDetector(detectorOptions);
|
|
131
|
+
middlewares.push({
|
|
132
|
+
name: 'i18n-language-detector',
|
|
133
|
+
path: urlPath,
|
|
134
|
+
handler: async (c, next)=>{
|
|
135
|
+
const url = new URL(c.req.url);
|
|
136
|
+
const pathname = url.pathname;
|
|
137
|
+
if (isStaticResourceRequest(pathname, staticRoutePrefixes, languages)) return await next();
|
|
138
|
+
if ('/' === originUrlPath) {
|
|
139
|
+
const pathSegments = pathname.split('/').filter(Boolean);
|
|
140
|
+
if (pathSegments.length > 0) {
|
|
141
|
+
const firstSegment = `/${pathSegments[0]}`;
|
|
142
|
+
if (entryPaths.has(firstSegment)) return await next();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return detectorHandler(c, next);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
middlewares.push({
|
|
150
|
+
name: 'i18n-server-middleware',
|
|
151
|
+
path: urlPath,
|
|
152
|
+
handler: async (c, next)=>{
|
|
153
|
+
const url = new URL(c.req.url);
|
|
154
|
+
const pathname = url.pathname;
|
|
155
|
+
if (isStaticResourceRequest(pathname, staticRoutePrefixes, languages)) return await next();
|
|
156
|
+
if (shouldIgnoreRedirect(pathname, urlPath, ignoreRedirectRoutes)) return await next();
|
|
157
|
+
if ('/' === originUrlPath) {
|
|
158
|
+
const pathSegments = pathname.split('/').filter(Boolean);
|
|
159
|
+
if (pathSegments.length > 0) {
|
|
160
|
+
const firstSegment = `/${pathSegments[0]}`;
|
|
161
|
+
if (entryPaths.has(firstSegment)) return await next();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const language = getLanguageFromPath(c.req, urlPath, languages);
|
|
165
|
+
if (!language) {
|
|
166
|
+
let detectedLanguage = null;
|
|
167
|
+
if (i18nextDetector) detectedLanguage = c.get('language') || null;
|
|
168
|
+
const targetLanguage = detectedLanguage || fallbackLanguage;
|
|
169
|
+
const localizedUrl = buildLocalizedUrl(c.req, originUrlPath, targetLanguage, languages);
|
|
170
|
+
return c.redirect(localizedUrl);
|
|
171
|
+
}
|
|
172
|
+
await next();
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
const server = i18nServerPlugin;
|
|
181
|
+
export default server;
|
|
182
|
+
export { i18nServerPlugin };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
function isPlainObject(value) {
|
|
2
|
+
return null !== value && 'object' == typeof value && !Array.isArray(value) && !(value instanceof Date);
|
|
3
|
+
}
|
|
4
|
+
function deepMerge(defaultOptions, userOptions) {
|
|
5
|
+
if (!userOptions) return defaultOptions;
|
|
6
|
+
const merged = {
|
|
7
|
+
...defaultOptions
|
|
8
|
+
};
|
|
9
|
+
for(const key in userOptions){
|
|
10
|
+
const userValue = userOptions[key];
|
|
11
|
+
if (void 0 === userValue) continue;
|
|
12
|
+
const defaultValue = merged[key];
|
|
13
|
+
const isUserValueObject = isPlainObject(userValue);
|
|
14
|
+
const isDefaultValueObject = isPlainObject(defaultValue);
|
|
15
|
+
if (isUserValueObject && isDefaultValueObject) merged[key] = deepMerge(defaultValue, userValue);
|
|
16
|
+
else merged[key] = userValue;
|
|
17
|
+
}
|
|
18
|
+
return merged;
|
|
19
|
+
}
|
|
20
|
+
export { deepMerge };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { DEFAULT_I18NEXT_DETECTION_OPTIONS, mergeDetectionOptions } from "../runtime/i18n/detection/config.mjs";
|
|
2
|
+
function detectLanguageFromRequest(req, languages, detectionOptions) {
|
|
3
|
+
try {
|
|
4
|
+
const mergedDetection = detectionOptions ? mergeDetectionOptions(detectionOptions) : DEFAULT_I18NEXT_DETECTION_OPTIONS;
|
|
5
|
+
const order = (mergedDetection.order || []).filter((item)=>![
|
|
6
|
+
'path',
|
|
7
|
+
'localStorage',
|
|
8
|
+
'navigator',
|
|
9
|
+
'htmlTag',
|
|
10
|
+
'subdomain'
|
|
11
|
+
].includes(item));
|
|
12
|
+
const detectionOrder = order.length > 0 ? order : [
|
|
13
|
+
'querystring',
|
|
14
|
+
'cookie',
|
|
15
|
+
'header'
|
|
16
|
+
];
|
|
17
|
+
const getHeader = (name)=>{
|
|
18
|
+
req.headers, Headers;
|
|
19
|
+
return req.headers.get(name);
|
|
20
|
+
};
|
|
21
|
+
for (const method of detectionOrder){
|
|
22
|
+
let detectedLang = null;
|
|
23
|
+
switch(method){
|
|
24
|
+
case 'querystring':
|
|
25
|
+
{
|
|
26
|
+
const lookupKey = mergedDetection.lookupQuerystring || DEFAULT_I18NEXT_DETECTION_OPTIONS.lookupQuerystring || 'lng';
|
|
27
|
+
const host = getHeader('host') || 'localhost';
|
|
28
|
+
const url = new URL(req.url, `http://${host}`);
|
|
29
|
+
detectedLang = url.searchParams.get(lookupKey);
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
case 'cookie':
|
|
33
|
+
{
|
|
34
|
+
const lookupKey = mergedDetection.lookupCookie || DEFAULT_I18NEXT_DETECTION_OPTIONS.lookupCookie || 'i18next';
|
|
35
|
+
const cookieHeader = getHeader('Cookie');
|
|
36
|
+
if (cookieHeader) {
|
|
37
|
+
const cookies = cookieHeader.split(';').reduce((acc, item)=>{
|
|
38
|
+
const [key, value] = item.trim().split('=');
|
|
39
|
+
if (key && value) acc[key] = value;
|
|
40
|
+
return acc;
|
|
41
|
+
}, {});
|
|
42
|
+
detectedLang = cookies[lookupKey] || null;
|
|
43
|
+
}
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
case 'header':
|
|
47
|
+
{
|
|
48
|
+
const lookupKey = mergedDetection.lookupHeader || DEFAULT_I18NEXT_DETECTION_OPTIONS.lookupHeader || 'accept-language';
|
|
49
|
+
const acceptLanguage = getHeader(lookupKey);
|
|
50
|
+
if (acceptLanguage) {
|
|
51
|
+
const languagesList = acceptLanguage.split(',').map((lang)=>{
|
|
52
|
+
const [code, q] = lang.trim().split(';');
|
|
53
|
+
return {
|
|
54
|
+
code: code.split('-')[0],
|
|
55
|
+
quality: q ? parseFloat(q.split('=')[1]) : 1.0
|
|
56
|
+
};
|
|
57
|
+
}).sort((a, b)=>b.quality - a.quality);
|
|
58
|
+
for (const lang of languagesList)if (0 === languages.length || languages.includes(lang.code)) {
|
|
59
|
+
detectedLang = lang.code;
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (detectedLang && (0 === languages.length || languages.includes(detectedLang))) return detectedLang;
|
|
67
|
+
}
|
|
68
|
+
} catch (error) {}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
export { detectLanguageFromRequest };
|
|
File without changes
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
function getEntryConfig(entryName, config, entryKey) {
|
|
2
|
+
const entryConfigMap = config[entryKey];
|
|
3
|
+
return entryConfigMap?.[entryName];
|
|
4
|
+
}
|
|
5
|
+
function removeEntryConfigKey(config, entryKey) {
|
|
6
|
+
const { [entryKey]: _, ...rest } = config;
|
|
7
|
+
return rest;
|
|
8
|
+
}
|
|
9
|
+
function getLocaleDetectionOptions(entryName, localeDetection) {
|
|
10
|
+
const fullConfig = localeDetection;
|
|
11
|
+
const entryConfig = getEntryConfig(entryName, fullConfig, 'localeDetectionByEntry');
|
|
12
|
+
if (entryConfig) {
|
|
13
|
+
const globalConfig = removeEntryConfigKey(fullConfig, 'localeDetectionByEntry');
|
|
14
|
+
return {
|
|
15
|
+
...globalConfig,
|
|
16
|
+
...entryConfig
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
if ('localeDetectionByEntry' in fullConfig) return removeEntryConfigKey(fullConfig, 'localeDetectionByEntry');
|
|
20
|
+
return localeDetection;
|
|
21
|
+
}
|
|
22
|
+
function getBackendOptions(entryName, backend) {
|
|
23
|
+
const fullConfig = backend;
|
|
24
|
+
const entryConfig = getEntryConfig(entryName, fullConfig, 'backendOptionsByEntry');
|
|
25
|
+
if (entryConfig) {
|
|
26
|
+
const globalConfig = removeEntryConfigKey(fullConfig, 'backendOptionsByEntry');
|
|
27
|
+
return {
|
|
28
|
+
...globalConfig,
|
|
29
|
+
...entryConfig
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
if ('backendOptionsByEntry' in fullConfig) return removeEntryConfigKey(fullConfig, 'backendOptionsByEntry');
|
|
33
|
+
return backend;
|
|
34
|
+
}
|
|
35
|
+
export { getBackendOptions, getEntryConfig, getLocaleDetectionOptions, removeEntryConfigKey };
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import { getPublicDirRoutePrefixes } from "@modern-js/server-core";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { getBackendOptions, getLocaleDetectionOptions } from "../shared/utils.mjs";
|
|
6
|
+
function hasJsonFiles(dirPath) {
|
|
7
|
+
try {
|
|
8
|
+
if (!fs.existsSync(dirPath) || !fs.statSync(dirPath).isDirectory()) return false;
|
|
9
|
+
const entries = fs.readdirSync(dirPath);
|
|
10
|
+
for (const entry of entries){
|
|
11
|
+
const entryPath = path.join(dirPath, entry);
|
|
12
|
+
const stat = fs.statSync(entryPath);
|
|
13
|
+
if (stat.isFile() && entry.endsWith('.json')) return true;
|
|
14
|
+
if (stat.isDirectory()) {
|
|
15
|
+
if (hasJsonFiles(entryPath)) return true;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return false;
|
|
19
|
+
} catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function detectLocalesDirectory(appDirectory, normalizedConfig) {
|
|
24
|
+
const rootLocalesPath = path.join(appDirectory, 'locales');
|
|
25
|
+
if (hasJsonFiles(rootLocalesPath)) return true;
|
|
26
|
+
const configPublicPath = path.join(appDirectory, 'config', 'public', 'locales');
|
|
27
|
+
if (hasJsonFiles(configPublicPath)) return true;
|
|
28
|
+
const publicDir = normalizedConfig?.server?.publicDir;
|
|
29
|
+
if (publicDir) {
|
|
30
|
+
const publicDirPath = Array.isArray(publicDir) ? publicDir[0] : publicDir;
|
|
31
|
+
const localesPath = path.isAbsolute(publicDirPath) ? path.join(publicDirPath, 'locales') : path.join(appDirectory, publicDirPath, 'locales');
|
|
32
|
+
if (hasJsonFiles(localesPath)) return true;
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
const i18nPlugin = (options = {})=>({
|
|
37
|
+
name: '@modern-js/plugin-i18n',
|
|
38
|
+
setup: (api)=>{
|
|
39
|
+
const { localeDetection, backend, transformRuntimeConfig, customPlugin, ...restOptions } = options;
|
|
40
|
+
api._internalRuntimePlugins(({ entrypoint, plugins })=>{
|
|
41
|
+
const localeDetectionOptions = localeDetection ? getLocaleDetectionOptions(entrypoint.entryName, localeDetection) : void 0;
|
|
42
|
+
let backendOptions;
|
|
43
|
+
const { appDirectory } = api.getAppContext();
|
|
44
|
+
const normalizedConfig = api.getNormalizedConfig();
|
|
45
|
+
if (backend) {
|
|
46
|
+
const entryBackendOptions = getBackendOptions(entrypoint.entryName, backend);
|
|
47
|
+
if (entryBackendOptions?.enabled === false) backendOptions = entryBackendOptions;
|
|
48
|
+
else if (entryBackendOptions?.loadPath || entryBackendOptions?.addPath) backendOptions = {
|
|
49
|
+
...entryBackendOptions,
|
|
50
|
+
enabled: true
|
|
51
|
+
};
|
|
52
|
+
else if (entryBackendOptions?.enabled !== true) {
|
|
53
|
+
const hasLocales = detectLocalesDirectory(appDirectory, normalizedConfig);
|
|
54
|
+
backendOptions = hasLocales ? {
|
|
55
|
+
...entryBackendOptions,
|
|
56
|
+
enabled: true
|
|
57
|
+
} : entryBackendOptions;
|
|
58
|
+
} else backendOptions = entryBackendOptions;
|
|
59
|
+
} else {
|
|
60
|
+
const hasLocales = detectLocalesDirectory(appDirectory, normalizedConfig);
|
|
61
|
+
if (hasLocales) backendOptions = getBackendOptions(entrypoint.entryName, {
|
|
62
|
+
enabled: true
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
const { metaName } = api.getAppContext();
|
|
66
|
+
let extendedConfig = restOptions;
|
|
67
|
+
if (transformRuntimeConfig) extendedConfig = transformRuntimeConfig(restOptions, entrypoint);
|
|
68
|
+
const config = {
|
|
69
|
+
entryName: entrypoint.entryName,
|
|
70
|
+
localeDetection: localeDetectionOptions,
|
|
71
|
+
backend: backendOptions,
|
|
72
|
+
...extendedConfig
|
|
73
|
+
};
|
|
74
|
+
plugins.push({
|
|
75
|
+
name: customPlugin?.runtime?.name || 'i18n',
|
|
76
|
+
path: customPlugin?.runtime?.path || `@${metaName}/plugin-i18n/runtime`,
|
|
77
|
+
config
|
|
78
|
+
});
|
|
79
|
+
return {
|
|
80
|
+
entrypoint,
|
|
81
|
+
plugins
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
api._internalServerPlugins(({ plugins })=>{
|
|
85
|
+
const { serverRoutes, metaName } = api.getAppContext();
|
|
86
|
+
const normalizedConfig = api.getNormalizedConfig();
|
|
87
|
+
let staticRoutePrefixes = [];
|
|
88
|
+
if (serverRoutes && Array.isArray(serverRoutes)) staticRoutePrefixes = serverRoutes.filter((route)=>!route.entryName && route.entryPath.startsWith('public')).map((route)=>route.urlPath).filter(Boolean);
|
|
89
|
+
const publicDirPrefixes = getPublicDirRoutePrefixes(normalizedConfig?.server?.publicDir);
|
|
90
|
+
publicDirPrefixes.forEach((prefix)=>{
|
|
91
|
+
if (!staticRoutePrefixes.includes(prefix)) staticRoutePrefixes.push(prefix);
|
|
92
|
+
});
|
|
93
|
+
plugins.push({
|
|
94
|
+
name: customPlugin?.server?.name || `@${metaName}/plugin-i18n/server`,
|
|
95
|
+
options: {
|
|
96
|
+
localeDetection,
|
|
97
|
+
staticRoutePrefixes
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
return {
|
|
101
|
+
plugins
|
|
102
|
+
};
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
const cli = i18nPlugin;
|
|
107
|
+
export default cli;
|
|
108
|
+
export { i18nPlugin };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
var __webpack_modules__ = {};
|
|
3
|
+
var __webpack_module_cache__ = {};
|
|
4
|
+
function __webpack_require__(moduleId) {
|
|
5
|
+
var cachedModule = __webpack_module_cache__[moduleId];
|
|
6
|
+
if (void 0 !== cachedModule) return cachedModule.exports;
|
|
7
|
+
var module = __webpack_module_cache__[moduleId] = {
|
|
8
|
+
exports: {}
|
|
9
|
+
};
|
|
10
|
+
__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
|
|
11
|
+
return module.exports;
|
|
12
|
+
}
|
|
13
|
+
__webpack_require__.m = __webpack_modules__;
|
|
14
|
+
(()=>{
|
|
15
|
+
__webpack_require__.add = function(modules) {
|
|
16
|
+
Object.assign(__webpack_require__.m, modules);
|
|
17
|
+
};
|
|
18
|
+
})();
|
|
19
|
+
export { __webpack_require__ };
|