@bleedingdev/modern-js-plugin-i18n 3.4.0-ultramodern.1 → 3.4.0-ultramodern.2

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.
@@ -0,0 +1,139 @@
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 } from "./i18n/instance.mjs";
14
+ import { changeI18nLanguage, ensureLanguageMatch, initializeI18nInstance, setupClonedInstance } from "./i18n/utils.mjs";
15
+ import { buildLocalizedUrl, getPathname, splitUrlTarget } from "./utils.mjs";
16
+ import "./types.mjs";
17
+ const createI18nPlugin = (loadReactI18nextIntegration)=>(options)=>({
18
+ name: '@modern-js/plugin-i18n',
19
+ setup: (api)=>{
20
+ const { entryName, i18nInstance: userI18nInstance, initOptions, localeDetection, backend, htmlLangAttr = false, reactI18next = true } = options;
21
+ const { localePathRedirect = false, i18nextDetector = true, languages = [], fallbackLanguage = 'en', detection, ignoreRedirectRoutes, localisedUrls } = localeDetection || {};
22
+ const { enabled: backendEnabled = false } = backend || {};
23
+ let latestI18nInstance;
24
+ let I18nextProvider;
25
+ const resolveReactI18nextIntegration = async ()=>{
26
+ if (!reactI18next) return null;
27
+ return loadReactI18nextIntegration?.() ?? null;
28
+ };
29
+ api.onBeforeRender(async (context)=>{
30
+ let i18nInstance = await getI18nInstance(userI18nInstance);
31
+ const { i18n: otherConfig } = api.getRuntimeConfig();
32
+ const { initOptions: otherInitOptions } = otherConfig || {};
33
+ const userInitOptions = merge(otherInitOptions || {}, initOptions || {});
34
+ const reactI18nextIntegration = await resolveReactI18nextIntegration();
35
+ I18nextProvider = reactI18nextIntegration?.I18nextProvider ?? null;
36
+ if (reactI18nextIntegration?.initReactI18next) i18nInstance.use(reactI18nextIntegration.initReactI18next);
37
+ const pathname = getPathname(context);
38
+ if (i18nextDetector) useI18nextLanguageDetector(i18nInstance);
39
+ const mergedDetection = mergeDetectionOptions(i18nextDetector, detection, localePathRedirect, userInitOptions);
40
+ const mergedBackend = mergeBackendOptions(backend, userInitOptions);
41
+ const hasSdkConfig = 'function' == typeof userInitOptions?.backend?.sdk || mergedBackend?.sdk && 'function' == typeof mergedBackend.sdk;
42
+ if (mergedBackend && (backendEnabled || hasSdkConfig)) useI18nextBackend(i18nInstance, mergedBackend);
43
+ const { finalLanguage } = await detectLanguageWithPriority(i18nInstance, {
44
+ languages,
45
+ fallbackLanguage,
46
+ localePathRedirect,
47
+ i18nextDetector,
48
+ detection,
49
+ userInitOptions,
50
+ mergedBackend,
51
+ pathname,
52
+ ssrContext: context.ssrContext
53
+ });
54
+ await initializeI18nInstance(i18nInstance, finalLanguage, fallbackLanguage, languages, mergedDetection, mergedBackend, userInitOptions);
55
+ if (!isBrowser() && i18nInstance.cloneInstance) {
56
+ i18nInstance = i18nInstance.cloneInstance();
57
+ await setupClonedInstance(i18nInstance, finalLanguage, fallbackLanguage, languages, backendEnabled, backend, i18nextDetector, detection, localePathRedirect, userInitOptions);
58
+ }
59
+ if (localePathRedirect) await ensureLanguageMatch(i18nInstance, finalLanguage);
60
+ if (!isBrowser()) exportServerLngToWindow(context, finalLanguage);
61
+ context.i18nInstance = i18nInstance;
62
+ latestI18nInstance = i18nInstance;
63
+ context.changeLanguage = async (newLang)=>{
64
+ await changeI18nLanguage(i18nInstance, newLang, {
65
+ detectionOptions: mergedDetection
66
+ });
67
+ };
68
+ });
69
+ api.wrapRoot((App)=>(props)=>{
70
+ const runtimeContext = useContext(RuntimeContext);
71
+ const i18nInstance = runtimeContext.i18nInstance || latestI18nInstance;
72
+ const initialLang = useMemo(()=>i18nInstance?.language || (localeDetection?.fallbackLanguage ?? 'en'), [
73
+ i18nInstance?.language,
74
+ localeDetection?.fallbackLanguage
75
+ ]);
76
+ const [lang, setLang] = useState(initialLang);
77
+ const [forceUpdate, setForceUpdate] = useState(0);
78
+ const prevLangRef = useRef(lang);
79
+ const runtimeContextRef = useRef(runtimeContext);
80
+ runtimeContextRef.current = runtimeContext;
81
+ useEffect(()=>{
82
+ if (i18nInstance?.language) {
83
+ const translator = i18nInstance.translator;
84
+ if (translator) translator.language = i18nInstance.language;
85
+ }
86
+ }, [
87
+ i18nInstance?.language
88
+ ]);
89
+ useEffect(()=>{
90
+ prevLangRef.current = lang;
91
+ }, [
92
+ lang
93
+ ]);
94
+ useSdkResourcesLoader(i18nInstance, setForceUpdate);
95
+ useLanguageSync(i18nInstance, localePathRedirect, languages, runtimeContextRef, prevLangRef, setLang);
96
+ useClientSideRedirect(i18nInstance, localePathRedirect, languages, fallbackLanguage, ignoreRedirectRoutes, localisedUrls);
97
+ const contextValue = useMemo(()=>createContextValue(lang, i18nInstance, entryName, languages, localePathRedirect, ignoreRedirectRoutes, localisedUrls, setLang), [
98
+ lang,
99
+ i18nInstance,
100
+ entryName,
101
+ languages,
102
+ localePathRedirect,
103
+ ignoreRedirectRoutes,
104
+ localisedUrls,
105
+ forceUpdate
106
+ ]);
107
+ const children = props.children;
108
+ const appContent = /*#__PURE__*/ jsxs(Fragment, {
109
+ children: [
110
+ Boolean(htmlLangAttr) && /*#__PURE__*/ jsx(Helmet, {
111
+ htmlAttributes: {
112
+ lang
113
+ }
114
+ }),
115
+ /*#__PURE__*/ jsx(ModernI18nProvider, {
116
+ value: contextValue,
117
+ children: App ? /*#__PURE__*/ jsx(App, {
118
+ ...props,
119
+ children: children
120
+ }) : children
121
+ })
122
+ ]
123
+ });
124
+ if (!i18nInstance) return appContent;
125
+ if (I18nextProvider) {
126
+ const i18nextInstanceForProvider = getI18nextInstanceForProvider(i18nInstance);
127
+ return /*#__PURE__*/ jsx(I18nextProvider, {
128
+ i18n: i18nextInstanceForProvider,
129
+ children: appContent
130
+ });
131
+ }
132
+ return appContent;
133
+ });
134
+ }
135
+ });
136
+ export { I18nLink } from "./I18nLink.mjs";
137
+ export { Link } from "./Link.mjs";
138
+ export { canonicalPath, localizePath, useLocalizedLocation, useLocalizedPaths } from "./localizedPaths.mjs";
139
+ export { buildLocalizedUrl, createI18nPlugin, splitUrlTarget, useModernI18n };
@@ -1,142 +1,7 @@
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 } from "./i18n/instance.mjs";
14
- import { changeI18nLanguage, ensureLanguageMatch, initializeI18nInstance, setupClonedInstance } from "./i18n/utils.mjs";
15
- import { buildLocalizedUrl, getPathname, splitUrlTarget } 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, reactI18next = true } = options;
21
- const { localePathRedirect = false, i18nextDetector = true, languages = [], fallbackLanguage = 'en', detection, ignoreRedirectRoutes, localisedUrls } = localeDetection || {};
22
- const { enabled: backendEnabled = false } = backend || {};
23
- let latestI18nInstance;
24
- let I18nextProvider;
25
- const loadReactI18nextIntegration = async ()=>{
26
- if (!reactI18next) return null;
27
- const { getReactI18nextIntegration } = await import("./i18n/react-i18next.mjs");
28
- return getReactI18nextIntegration();
29
- };
30
- api.onBeforeRender(async (context)=>{
31
- let i18nInstance = await getI18nInstance(userI18nInstance);
32
- const { i18n: otherConfig } = api.getRuntimeConfig();
33
- const { initOptions: otherInitOptions } = otherConfig || {};
34
- const userInitOptions = merge(otherInitOptions || {}, initOptions || {});
35
- const reactI18nextIntegration = await loadReactI18nextIntegration();
36
- I18nextProvider = reactI18nextIntegration?.I18nextProvider ?? null;
37
- if (reactI18nextIntegration?.initReactI18next) i18nInstance.use(reactI18nextIntegration.initReactI18next);
38
- const pathname = getPathname(context);
39
- if (i18nextDetector) useI18nextLanguageDetector(i18nInstance);
40
- const mergedDetection = mergeDetectionOptions(i18nextDetector, detection, localePathRedirect, userInitOptions);
41
- const mergedBackend = mergeBackendOptions(backend, userInitOptions);
42
- const hasSdkConfig = 'function' == typeof userInitOptions?.backend?.sdk || mergedBackend?.sdk && 'function' == typeof mergedBackend.sdk;
43
- if (mergedBackend && (backendEnabled || hasSdkConfig)) useI18nextBackend(i18nInstance, mergedBackend);
44
- const { finalLanguage } = await detectLanguageWithPriority(i18nInstance, {
45
- languages,
46
- fallbackLanguage,
47
- localePathRedirect,
48
- i18nextDetector,
49
- detection,
50
- userInitOptions,
51
- mergedBackend,
52
- pathname,
53
- ssrContext: context.ssrContext
54
- });
55
- await initializeI18nInstance(i18nInstance, finalLanguage, fallbackLanguage, languages, mergedDetection, mergedBackend, userInitOptions);
56
- if (!isBrowser() && i18nInstance.cloneInstance) {
57
- i18nInstance = i18nInstance.cloneInstance();
58
- await setupClonedInstance(i18nInstance, finalLanguage, fallbackLanguage, languages, backendEnabled, backend, i18nextDetector, detection, localePathRedirect, userInitOptions);
59
- }
60
- if (localePathRedirect) await ensureLanguageMatch(i18nInstance, finalLanguage);
61
- if (!isBrowser()) exportServerLngToWindow(context, finalLanguage);
62
- context.i18nInstance = i18nInstance;
63
- latestI18nInstance = i18nInstance;
64
- context.changeLanguage = async (newLang)=>{
65
- await changeI18nLanguage(i18nInstance, newLang, {
66
- detectionOptions: mergedDetection
67
- });
68
- };
69
- });
70
- api.wrapRoot((App)=>(props)=>{
71
- const runtimeContext = useContext(RuntimeContext);
72
- const i18nInstance = runtimeContext.i18nInstance || latestI18nInstance;
73
- const initialLang = useMemo(()=>i18nInstance?.language || (localeDetection?.fallbackLanguage ?? 'en'), [
74
- i18nInstance?.language,
75
- localeDetection?.fallbackLanguage
76
- ]);
77
- const [lang, setLang] = useState(initialLang);
78
- const [forceUpdate, setForceUpdate] = useState(0);
79
- const prevLangRef = useRef(lang);
80
- const runtimeContextRef = useRef(runtimeContext);
81
- runtimeContextRef.current = runtimeContext;
82
- useEffect(()=>{
83
- if (i18nInstance?.language) {
84
- const translator = i18nInstance.translator;
85
- if (translator) translator.language = i18nInstance.language;
86
- }
87
- }, [
88
- i18nInstance?.language
89
- ]);
90
- useEffect(()=>{
91
- prevLangRef.current = lang;
92
- }, [
93
- lang
94
- ]);
95
- useSdkResourcesLoader(i18nInstance, setForceUpdate);
96
- useLanguageSync(i18nInstance, localePathRedirect, languages, runtimeContextRef, prevLangRef, setLang);
97
- useClientSideRedirect(i18nInstance, localePathRedirect, languages, fallbackLanguage, ignoreRedirectRoutes, localisedUrls);
98
- const contextValue = useMemo(()=>createContextValue(lang, i18nInstance, entryName, languages, localePathRedirect, ignoreRedirectRoutes, localisedUrls, setLang), [
99
- lang,
100
- i18nInstance,
101
- entryName,
102
- languages,
103
- localePathRedirect,
104
- ignoreRedirectRoutes,
105
- localisedUrls,
106
- forceUpdate
107
- ]);
108
- const children = props.children;
109
- const appContent = /*#__PURE__*/ jsxs(Fragment, {
110
- children: [
111
- Boolean(htmlLangAttr) && /*#__PURE__*/ jsx(Helmet, {
112
- htmlAttributes: {
113
- lang
114
- }
115
- }),
116
- /*#__PURE__*/ jsx(ModernI18nProvider, {
117
- value: contextValue,
118
- children: App ? /*#__PURE__*/ jsx(App, {
119
- ...props,
120
- children: children
121
- }) : children
122
- })
123
- ]
124
- });
125
- if (!i18nInstance) return appContent;
126
- if (I18nextProvider) {
127
- const i18nextInstanceForProvider = getI18nextInstanceForProvider(i18nInstance);
128
- return /*#__PURE__*/ jsx(I18nextProvider, {
129
- i18n: i18nextInstanceForProvider,
130
- children: appContent
131
- });
132
- }
133
- return appContent;
134
- });
135
- }
136
- });
1
+ import { createI18nPlugin } from "./core.mjs";
2
+ import { getReactI18nextIntegration } from "./i18n/react-i18next.mjs";
3
+ export * from "./core.mjs";
4
+ const i18nPlugin = createI18nPlugin(getReactI18nextIntegration);
137
5
  const runtime = i18nPlugin;
138
- export { I18nLink } from "./I18nLink.mjs";
139
- export { Link } from "./Link.mjs";
140
- export { canonicalPath, localizePath, useLocalizedLocation, useLocalizedPaths } from "./localizedPaths.mjs";
141
6
  export default runtime;
142
- export { buildLocalizedUrl, i18nPlugin, splitUrlTarget, useModernI18n };
7
+ export { i18nPlugin };
@@ -0,0 +1,6 @@
1
+ import { createI18nPlugin } from "./core.mjs";
2
+ export * from "./core.mjs";
3
+ const i18nPlugin = createI18nPlugin();
4
+ const no_react_i18next = i18nPlugin;
5
+ export default no_react_i18next;
6
+ export { i18nPlugin };
@@ -32,9 +32,10 @@ const i18nPlugin = (options = {})=>({
32
32
  backend: backendOptions,
33
33
  ...extendedConfig
34
34
  };
35
+ const runtimePluginPath = customPlugin?.runtime?.path || (false === config.reactI18next ? `@${metaName}/plugin-i18n/runtime/no-react-i18next` : `@${metaName}/plugin-i18n/runtime`);
35
36
  plugins.push({
36
37
  name: customPlugin?.runtime?.name || 'i18n',
37
- path: customPlugin?.runtime?.path || `@${metaName}/plugin-i18n/runtime`,
38
+ path: runtimePluginPath,
38
39
  config
39
40
  });
40
41
  return {
@@ -0,0 +1,140 @@
1
+ import "node:module";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { RuntimeContext, isBrowser } from "@modern-js/runtime";
4
+ import { Helmet } from "@modern-js/runtime/head";
5
+ import { merge } from "@modern-js/runtime-utils/merge";
6
+ import { useContext, useEffect, useMemo, useRef, useState } from "react";
7
+ import { ModernI18nProvider, useModernI18n } from "./context.mjs";
8
+ import { createContextValue, useClientSideRedirect, useLanguageSync, useSdkResourcesLoader } from "./hooks.mjs";
9
+ import { getI18nInstance } from "./i18n/index.mjs";
10
+ import { mergeBackendOptions } from "./i18n/backend/index.mjs";
11
+ import { useI18nextBackend } from "./i18n/backend/middleware.mjs";
12
+ import { detectLanguageWithPriority, exportServerLngToWindow, mergeDetectionOptions } from "./i18n/detection/index.mjs";
13
+ import { useI18nextLanguageDetector } from "./i18n/detection/middleware.mjs";
14
+ import { getI18nextInstanceForProvider } from "./i18n/instance.mjs";
15
+ import { changeI18nLanguage, ensureLanguageMatch, initializeI18nInstance, setupClonedInstance } from "./i18n/utils.mjs";
16
+ import { buildLocalizedUrl, getPathname, splitUrlTarget } from "./utils.mjs";
17
+ import "./types.mjs";
18
+ const createI18nPlugin = (loadReactI18nextIntegration)=>(options)=>({
19
+ name: '@modern-js/plugin-i18n',
20
+ setup: (api)=>{
21
+ const { entryName, i18nInstance: userI18nInstance, initOptions, localeDetection, backend, htmlLangAttr = false, reactI18next = true } = options;
22
+ const { localePathRedirect = false, i18nextDetector = true, languages = [], fallbackLanguage = 'en', detection, ignoreRedirectRoutes, localisedUrls } = localeDetection || {};
23
+ const { enabled: backendEnabled = false } = backend || {};
24
+ let latestI18nInstance;
25
+ let I18nextProvider;
26
+ const resolveReactI18nextIntegration = async ()=>{
27
+ if (!reactI18next) return null;
28
+ return loadReactI18nextIntegration?.() ?? null;
29
+ };
30
+ api.onBeforeRender(async (context)=>{
31
+ let i18nInstance = await getI18nInstance(userI18nInstance);
32
+ const { i18n: otherConfig } = api.getRuntimeConfig();
33
+ const { initOptions: otherInitOptions } = otherConfig || {};
34
+ const userInitOptions = merge(otherInitOptions || {}, initOptions || {});
35
+ const reactI18nextIntegration = await resolveReactI18nextIntegration();
36
+ I18nextProvider = reactI18nextIntegration?.I18nextProvider ?? null;
37
+ if (reactI18nextIntegration?.initReactI18next) i18nInstance.use(reactI18nextIntegration.initReactI18next);
38
+ const pathname = getPathname(context);
39
+ if (i18nextDetector) useI18nextLanguageDetector(i18nInstance);
40
+ const mergedDetection = mergeDetectionOptions(i18nextDetector, detection, localePathRedirect, userInitOptions);
41
+ const mergedBackend = mergeBackendOptions(backend, userInitOptions);
42
+ const hasSdkConfig = 'function' == typeof userInitOptions?.backend?.sdk || mergedBackend?.sdk && 'function' == typeof mergedBackend.sdk;
43
+ if (mergedBackend && (backendEnabled || hasSdkConfig)) useI18nextBackend(i18nInstance, mergedBackend);
44
+ const { finalLanguage } = await detectLanguageWithPriority(i18nInstance, {
45
+ languages,
46
+ fallbackLanguage,
47
+ localePathRedirect,
48
+ i18nextDetector,
49
+ detection,
50
+ userInitOptions,
51
+ mergedBackend,
52
+ pathname,
53
+ ssrContext: context.ssrContext
54
+ });
55
+ await initializeI18nInstance(i18nInstance, finalLanguage, fallbackLanguage, languages, mergedDetection, mergedBackend, userInitOptions);
56
+ if (!isBrowser() && i18nInstance.cloneInstance) {
57
+ i18nInstance = i18nInstance.cloneInstance();
58
+ await setupClonedInstance(i18nInstance, finalLanguage, fallbackLanguage, languages, backendEnabled, backend, i18nextDetector, detection, localePathRedirect, userInitOptions);
59
+ }
60
+ if (localePathRedirect) await ensureLanguageMatch(i18nInstance, finalLanguage);
61
+ if (!isBrowser()) exportServerLngToWindow(context, finalLanguage);
62
+ context.i18nInstance = i18nInstance;
63
+ latestI18nInstance = i18nInstance;
64
+ context.changeLanguage = async (newLang)=>{
65
+ await changeI18nLanguage(i18nInstance, newLang, {
66
+ detectionOptions: mergedDetection
67
+ });
68
+ };
69
+ });
70
+ api.wrapRoot((App)=>(props)=>{
71
+ const runtimeContext = useContext(RuntimeContext);
72
+ const i18nInstance = runtimeContext.i18nInstance || latestI18nInstance;
73
+ const initialLang = useMemo(()=>i18nInstance?.language || (localeDetection?.fallbackLanguage ?? 'en'), [
74
+ i18nInstance?.language,
75
+ localeDetection?.fallbackLanguage
76
+ ]);
77
+ const [lang, setLang] = useState(initialLang);
78
+ const [forceUpdate, setForceUpdate] = useState(0);
79
+ const prevLangRef = useRef(lang);
80
+ const runtimeContextRef = useRef(runtimeContext);
81
+ runtimeContextRef.current = runtimeContext;
82
+ useEffect(()=>{
83
+ if (i18nInstance?.language) {
84
+ const translator = i18nInstance.translator;
85
+ if (translator) translator.language = i18nInstance.language;
86
+ }
87
+ }, [
88
+ i18nInstance?.language
89
+ ]);
90
+ useEffect(()=>{
91
+ prevLangRef.current = lang;
92
+ }, [
93
+ lang
94
+ ]);
95
+ useSdkResourcesLoader(i18nInstance, setForceUpdate);
96
+ useLanguageSync(i18nInstance, localePathRedirect, languages, runtimeContextRef, prevLangRef, setLang);
97
+ useClientSideRedirect(i18nInstance, localePathRedirect, languages, fallbackLanguage, ignoreRedirectRoutes, localisedUrls);
98
+ const contextValue = useMemo(()=>createContextValue(lang, i18nInstance, entryName, languages, localePathRedirect, ignoreRedirectRoutes, localisedUrls, setLang), [
99
+ lang,
100
+ i18nInstance,
101
+ entryName,
102
+ languages,
103
+ localePathRedirect,
104
+ ignoreRedirectRoutes,
105
+ localisedUrls,
106
+ forceUpdate
107
+ ]);
108
+ const children = props.children;
109
+ const appContent = /*#__PURE__*/ jsxs(Fragment, {
110
+ children: [
111
+ Boolean(htmlLangAttr) && /*#__PURE__*/ jsx(Helmet, {
112
+ htmlAttributes: {
113
+ lang
114
+ }
115
+ }),
116
+ /*#__PURE__*/ jsx(ModernI18nProvider, {
117
+ value: contextValue,
118
+ children: App ? /*#__PURE__*/ jsx(App, {
119
+ ...props,
120
+ children: children
121
+ }) : children
122
+ })
123
+ ]
124
+ });
125
+ if (!i18nInstance) return appContent;
126
+ if (I18nextProvider) {
127
+ const i18nextInstanceForProvider = getI18nextInstanceForProvider(i18nInstance);
128
+ return /*#__PURE__*/ jsx(I18nextProvider, {
129
+ i18n: i18nextInstanceForProvider,
130
+ children: appContent
131
+ });
132
+ }
133
+ return appContent;
134
+ });
135
+ }
136
+ });
137
+ export { I18nLink } from "./I18nLink.mjs";
138
+ export { Link } from "./Link.mjs";
139
+ export { canonicalPath, localizePath, useLocalizedLocation, useLocalizedPaths } from "./localizedPaths.mjs";
140
+ export { buildLocalizedUrl, createI18nPlugin, splitUrlTarget, useModernI18n };
@@ -1,143 +1,8 @@
1
1
  import "node:module";
2
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
- import { RuntimeContext, isBrowser } from "@modern-js/runtime";
4
- import { Helmet } from "@modern-js/runtime/head";
5
- import { merge } from "@modern-js/runtime-utils/merge";
6
- import { useContext, useEffect, useMemo, useRef, useState } from "react";
7
- import { ModernI18nProvider, useModernI18n } from "./context.mjs";
8
- import { createContextValue, useClientSideRedirect, useLanguageSync, useSdkResourcesLoader } from "./hooks.mjs";
9
- import { getI18nInstance } from "./i18n/index.mjs";
10
- import { mergeBackendOptions } from "./i18n/backend/index.mjs";
11
- import { useI18nextBackend } from "./i18n/backend/middleware.mjs";
12
- import { detectLanguageWithPriority, exportServerLngToWindow, mergeDetectionOptions } from "./i18n/detection/index.mjs";
13
- import { useI18nextLanguageDetector } from "./i18n/detection/middleware.mjs";
14
- import { getI18nextInstanceForProvider } from "./i18n/instance.mjs";
15
- import { changeI18nLanguage, ensureLanguageMatch, initializeI18nInstance, setupClonedInstance } from "./i18n/utils.mjs";
16
- import { buildLocalizedUrl, getPathname, splitUrlTarget } from "./utils.mjs";
17
- import "./types.mjs";
18
- const i18nPlugin = (options)=>({
19
- name: '@modern-js/plugin-i18n',
20
- setup: (api)=>{
21
- const { entryName, i18nInstance: userI18nInstance, initOptions, localeDetection, backend, htmlLangAttr = false, reactI18next = true } = options;
22
- const { localePathRedirect = false, i18nextDetector = true, languages = [], fallbackLanguage = 'en', detection, ignoreRedirectRoutes, localisedUrls } = localeDetection || {};
23
- const { enabled: backendEnabled = false } = backend || {};
24
- let latestI18nInstance;
25
- let I18nextProvider;
26
- const loadReactI18nextIntegration = async ()=>{
27
- if (!reactI18next) return null;
28
- const { getReactI18nextIntegration } = await import("./i18n/react-i18next.mjs");
29
- return getReactI18nextIntegration();
30
- };
31
- api.onBeforeRender(async (context)=>{
32
- let i18nInstance = await getI18nInstance(userI18nInstance);
33
- const { i18n: otherConfig } = api.getRuntimeConfig();
34
- const { initOptions: otherInitOptions } = otherConfig || {};
35
- const userInitOptions = merge(otherInitOptions || {}, initOptions || {});
36
- const reactI18nextIntegration = await loadReactI18nextIntegration();
37
- I18nextProvider = reactI18nextIntegration?.I18nextProvider ?? null;
38
- if (reactI18nextIntegration?.initReactI18next) i18nInstance.use(reactI18nextIntegration.initReactI18next);
39
- const pathname = getPathname(context);
40
- if (i18nextDetector) useI18nextLanguageDetector(i18nInstance);
41
- const mergedDetection = mergeDetectionOptions(i18nextDetector, detection, localePathRedirect, userInitOptions);
42
- const mergedBackend = mergeBackendOptions(backend, userInitOptions);
43
- const hasSdkConfig = 'function' == typeof userInitOptions?.backend?.sdk || mergedBackend?.sdk && 'function' == typeof mergedBackend.sdk;
44
- if (mergedBackend && (backendEnabled || hasSdkConfig)) useI18nextBackend(i18nInstance, mergedBackend);
45
- const { finalLanguage } = await detectLanguageWithPriority(i18nInstance, {
46
- languages,
47
- fallbackLanguage,
48
- localePathRedirect,
49
- i18nextDetector,
50
- detection,
51
- userInitOptions,
52
- mergedBackend,
53
- pathname,
54
- ssrContext: context.ssrContext
55
- });
56
- await initializeI18nInstance(i18nInstance, finalLanguage, fallbackLanguage, languages, mergedDetection, mergedBackend, userInitOptions);
57
- if (!isBrowser() && i18nInstance.cloneInstance) {
58
- i18nInstance = i18nInstance.cloneInstance();
59
- await setupClonedInstance(i18nInstance, finalLanguage, fallbackLanguage, languages, backendEnabled, backend, i18nextDetector, detection, localePathRedirect, userInitOptions);
60
- }
61
- if (localePathRedirect) await ensureLanguageMatch(i18nInstance, finalLanguage);
62
- if (!isBrowser()) exportServerLngToWindow(context, finalLanguage);
63
- context.i18nInstance = i18nInstance;
64
- latestI18nInstance = i18nInstance;
65
- context.changeLanguage = async (newLang)=>{
66
- await changeI18nLanguage(i18nInstance, newLang, {
67
- detectionOptions: mergedDetection
68
- });
69
- };
70
- });
71
- api.wrapRoot((App)=>(props)=>{
72
- const runtimeContext = useContext(RuntimeContext);
73
- const i18nInstance = runtimeContext.i18nInstance || latestI18nInstance;
74
- const initialLang = useMemo(()=>i18nInstance?.language || (localeDetection?.fallbackLanguage ?? 'en'), [
75
- i18nInstance?.language,
76
- localeDetection?.fallbackLanguage
77
- ]);
78
- const [lang, setLang] = useState(initialLang);
79
- const [forceUpdate, setForceUpdate] = useState(0);
80
- const prevLangRef = useRef(lang);
81
- const runtimeContextRef = useRef(runtimeContext);
82
- runtimeContextRef.current = runtimeContext;
83
- useEffect(()=>{
84
- if (i18nInstance?.language) {
85
- const translator = i18nInstance.translator;
86
- if (translator) translator.language = i18nInstance.language;
87
- }
88
- }, [
89
- i18nInstance?.language
90
- ]);
91
- useEffect(()=>{
92
- prevLangRef.current = lang;
93
- }, [
94
- lang
95
- ]);
96
- useSdkResourcesLoader(i18nInstance, setForceUpdate);
97
- useLanguageSync(i18nInstance, localePathRedirect, languages, runtimeContextRef, prevLangRef, setLang);
98
- useClientSideRedirect(i18nInstance, localePathRedirect, languages, fallbackLanguage, ignoreRedirectRoutes, localisedUrls);
99
- const contextValue = useMemo(()=>createContextValue(lang, i18nInstance, entryName, languages, localePathRedirect, ignoreRedirectRoutes, localisedUrls, setLang), [
100
- lang,
101
- i18nInstance,
102
- entryName,
103
- languages,
104
- localePathRedirect,
105
- ignoreRedirectRoutes,
106
- localisedUrls,
107
- forceUpdate
108
- ]);
109
- const children = props.children;
110
- const appContent = /*#__PURE__*/ jsxs(Fragment, {
111
- children: [
112
- Boolean(htmlLangAttr) && /*#__PURE__*/ jsx(Helmet, {
113
- htmlAttributes: {
114
- lang
115
- }
116
- }),
117
- /*#__PURE__*/ jsx(ModernI18nProvider, {
118
- value: contextValue,
119
- children: App ? /*#__PURE__*/ jsx(App, {
120
- ...props,
121
- children: children
122
- }) : children
123
- })
124
- ]
125
- });
126
- if (!i18nInstance) return appContent;
127
- if (I18nextProvider) {
128
- const i18nextInstanceForProvider = getI18nextInstanceForProvider(i18nInstance);
129
- return /*#__PURE__*/ jsx(I18nextProvider, {
130
- i18n: i18nextInstanceForProvider,
131
- children: appContent
132
- });
133
- }
134
- return appContent;
135
- });
136
- }
137
- });
2
+ import { createI18nPlugin } from "./core.mjs";
3
+ import { getReactI18nextIntegration } from "./i18n/react-i18next.mjs";
4
+ export * from "./core.mjs";
5
+ const i18nPlugin = createI18nPlugin(getReactI18nextIntegration);
138
6
  const runtime = i18nPlugin;
139
- export { I18nLink } from "./I18nLink.mjs";
140
- export { Link } from "./Link.mjs";
141
- export { canonicalPath, localizePath, useLocalizedLocation, useLocalizedPaths } from "./localizedPaths.mjs";
142
7
  export default runtime;
143
- export { buildLocalizedUrl, i18nPlugin, splitUrlTarget, useModernI18n };
8
+ export { i18nPlugin };
@@ -0,0 +1,7 @@
1
+ import "node:module";
2
+ import { createI18nPlugin } from "./core.mjs";
3
+ export * from "./core.mjs";
4
+ const i18nPlugin = createI18nPlugin();
5
+ const no_react_i18next = i18nPlugin;
6
+ export default no_react_i18next;
7
+ export { i18nPlugin };
@@ -0,0 +1,30 @@
1
+ import { type RuntimePlugin } from '@modern-js/runtime';
2
+ import type React from 'react';
3
+ import type { BaseBackendOptions, BaseLocaleDetectionOptions } from '../shared/type';
4
+ import type { I18nInitOptions, I18nInstance } from './i18n';
5
+ import './types';
6
+ export type { I18nSdkLoader, I18nSdkLoadOptions } from '../shared/type';
7
+ export type { Resources } from './i18n/instance';
8
+ export interface I18nPluginOptions {
9
+ entryName?: string;
10
+ localeDetection?: BaseLocaleDetectionOptions;
11
+ backend?: BaseBackendOptions;
12
+ i18nInstance?: I18nInstance;
13
+ changeLanguage?: (lang: string) => void;
14
+ initOptions?: I18nInitOptions;
15
+ htmlLangAttr?: boolean;
16
+ reactI18next?: boolean;
17
+ [key: string]: any;
18
+ }
19
+ export interface ReactI18nextIntegration {
20
+ I18nextProvider: React.ComponentType<any> | null;
21
+ initReactI18next: any | null;
22
+ }
23
+ export type LoadReactI18nextIntegration = () => Promise<ReactI18nextIntegration | null>;
24
+ export declare const createI18nPlugin: (loadReactI18nextIntegration?: LoadReactI18nextIntegration) => ((options: I18nPluginOptions) => RuntimePlugin);
25
+ export type { AllowedLinkTarget, CanonicalRoutePath, UltramodernCanonicalRoutes, } from './canonicalRoutes';
26
+ export { useModernI18n } from './context';
27
+ export { I18nLink, type I18nLinkProps } from './I18nLink';
28
+ export { Link, type LinkActiveOptions, type LinkBaseProps, type LinkParams, type LinkProps, } from './Link';
29
+ export { canonicalPath, type LocalizedPathsConfig, localizePath, type UseLocalizedLocationReturn, type UseLocalizedPathsReturn, useLocalizedLocation, useLocalizedPaths, } from './localizedPaths';
30
+ export { buildLocalizedUrl, splitUrlTarget } from './utils';