@bleedingdev/modern-js-plugin-i18n 3.5.0-ultramodern.98 → 3.8.1-ultramodern.1
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/runtime/context.js +1 -1
- package/dist/cjs/runtime/contextHelpers.js +2 -1
- package/dist/cjs/runtime/hooks.js +3 -0
- package/dist/cjs/runtime/providerComposition.js +9 -10
- package/dist/cjs/runtime/routerAdapter.js +23 -10
- package/dist/esm/runtime/context.mjs +1 -1
- package/dist/esm/runtime/contextHelpers.mjs +2 -1
- package/dist/esm/runtime/hooks.mjs +3 -0
- package/dist/esm/runtime/providerComposition.mjs +9 -10
- package/dist/esm/runtime/routerAdapter.mjs +24 -11
- package/dist/esm-node/runtime/context.mjs +1 -1
- package/dist/esm-node/runtime/contextHelpers.mjs +2 -1
- package/dist/esm-node/runtime/hooks.mjs +3 -0
- package/dist/esm-node/runtime/providerComposition.mjs +9 -10
- package/dist/esm-node/runtime/routerAdapter.mjs +24 -11
- package/dist/types/runtime/context.d.ts +9 -3
- package/dist/types/runtime/core.d.ts +2 -2
- package/dist/types/runtime/i18n/backend/middleware.common.d.ts +1 -1
- package/dist/types/runtime/i18n/backend/middleware.d.ts +1 -1
- package/dist/types/runtime/i18n/backend/middleware.node.d.ts +1 -1
- package/dist/types/runtime/i18n/detection/middleware.d.ts +1 -1
- package/dist/types/runtime/i18n/detection/middleware.node.d.ts +1 -1
- package/dist/types/runtime/i18n/instance.d.ts +28 -19
- package/package.json +19 -16
- package/src/runtime/context.tsx +16 -4
- package/src/runtime/contextHelpers.ts +10 -1
- package/src/runtime/core.tsx +7 -1
- package/src/runtime/hooks.ts +7 -0
- package/src/runtime/i18n/instance.ts +84 -30
- package/src/runtime/providerComposition.tsx +14 -13
- package/src/runtime/routerAdapter.tsx +81 -58
- package/tests/i18nUtils.test.ts +1 -0
- package/tests/link.test.tsx +1 -0
- package/tests/localisedUrls.test.ts +44 -25
- package/tests/reactI18nextRuntimeBoundary.test.ts +181 -31
- package/tests/routerAdapter.test.tsx +185 -0
- package/tests/type-fixture/i18nInstanceTypes.fixture.ts +29 -0
- package/tsconfig.json +3 -1
- package/tests/fixtures/localised-routes.golden.json +0 -156
|
@@ -93,7 +93,8 @@ async function changeModernI18nLanguage(newLang, options) {
|
|
|
93
93
|
}
|
|
94
94
|
function translateI18n(i18nInstance, key, ...args) {
|
|
95
95
|
if ('function' != typeof i18nInstance.t) throw new Error('i18nInstance.t required');
|
|
96
|
-
|
|
96
|
+
const translate = i18nInstance.t;
|
|
97
|
+
return translate.call(i18nInstance, key, ...args);
|
|
97
98
|
}
|
|
98
99
|
function isI18nLanguageSupported(languages, lang) {
|
|
99
100
|
return languages?.includes(lang) || false;
|
|
@@ -44,6 +44,9 @@ function createMinimalI18nInstance(language) {
|
|
|
44
44
|
language,
|
|
45
45
|
isInitialized: false,
|
|
46
46
|
init: ()=>Promise.resolve(void 0),
|
|
47
|
+
t: ()=>{
|
|
48
|
+
throw new Error('i18nInstance.t required');
|
|
49
|
+
},
|
|
47
50
|
use: ()=>{},
|
|
48
51
|
createInstance: ()=>minimalInstance,
|
|
49
52
|
services: {}
|
|
@@ -77,21 +77,20 @@ const createI18nRootWrapper = (options)=>(App)=>(props)=>{
|
|
|
77
77
|
forceUpdate,
|
|
78
78
|
synchronizeLanguage
|
|
79
79
|
]);
|
|
80
|
+
const I18nextProvider = getI18nextProvider();
|
|
81
|
+
const i18nextInstanceForProvider = (0, external_react_namespaceObject.useMemo)(()=>i18nInstance ? (0, instance_js_namespaceObject.getI18nextInstanceForProvider)(i18nInstance, lang) : void 0, [
|
|
82
|
+
i18nInstance,
|
|
83
|
+
lang
|
|
84
|
+
]);
|
|
80
85
|
const children = props.children;
|
|
81
86
|
let appContent = App ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(App, {
|
|
82
87
|
...props,
|
|
83
88
|
children: children
|
|
84
89
|
}) : children;
|
|
85
|
-
if (
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
appContent = /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(I18nextProvider, {
|
|
90
|
-
i18n: i18nextInstanceForProvider,
|
|
91
|
-
children: appContent
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
}
|
|
90
|
+
if (I18nextProvider && i18nextInstanceForProvider) appContent = /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(I18nextProvider, {
|
|
91
|
+
i18n: i18nextInstanceForProvider,
|
|
92
|
+
children: appContent
|
|
93
|
+
});
|
|
95
94
|
return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(jsx_runtime_namespaceObject.Fragment, {
|
|
96
95
|
children: [
|
|
97
96
|
Boolean(htmlLangAttr) && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(head_namespaceObject.Helmet, {
|
|
@@ -32,7 +32,6 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
32
32
|
});
|
|
33
33
|
const runtime_namespaceObject = require("@modern-js/runtime");
|
|
34
34
|
const context_namespaceObject = require("@modern-js/runtime/context");
|
|
35
|
-
const router_namespaceObject = require("@modern-js/runtime/router");
|
|
36
35
|
const external_react_namespaceObject = require("react");
|
|
37
36
|
const normalizeUrlPart = (value, prefix)=>{
|
|
38
37
|
if ('string' != typeof value || !value) return '';
|
|
@@ -82,24 +81,33 @@ const getRouterParams = (internalContext, contextRouter)=>{
|
|
|
82
81
|
return params;
|
|
83
82
|
}, {});
|
|
84
83
|
};
|
|
84
|
+
const getRouterSnapshot = (internalContext, contextRouter)=>{
|
|
85
|
+
const location = getRouterStateLocation(internalContext, contextRouter);
|
|
86
|
+
const params = getRouterParams(internalContext, contextRouter);
|
|
87
|
+
return JSON.stringify([
|
|
88
|
+
location?.pathname ?? '',
|
|
89
|
+
location?.search ?? '',
|
|
90
|
+
location?.hash ?? '',
|
|
91
|
+
Object.entries(params).sort(([left], [right])=>left.localeCompare(right))
|
|
92
|
+
]);
|
|
93
|
+
};
|
|
85
94
|
const useI18nRouterAdapter = ()=>{
|
|
86
95
|
const runtimeContext = (0, external_react_namespaceObject.useContext)(runtime_namespaceObject.RuntimeContext);
|
|
87
96
|
const internalContext = (0, external_react_namespaceObject.useContext)(context_namespaceObject.InternalRuntimeContext);
|
|
88
|
-
const
|
|
89
|
-
const
|
|
90
|
-
const
|
|
91
|
-
const
|
|
97
|
+
const routerApi = internalContext.router || runtimeContext.router;
|
|
98
|
+
const inReactRouter = routerApi?.useInRouterContext?.() ?? false;
|
|
99
|
+
const reactRouterNavigate = inReactRouter ? routerApi?.useNavigate?.() ?? null : null;
|
|
100
|
+
const reactRouterLocation = inReactRouter ? routerApi?.useLocation?.() ?? null : null;
|
|
101
|
+
const reactRouterParams = inReactRouter ? routerApi?.useParams?.() ?? {} : {};
|
|
92
102
|
const framework = getRouterFramework(runtimeContext, internalContext, inReactRouter);
|
|
93
103
|
const contextUseRouter = inReactRouter || 'tanstack' !== framework ? void 0 : internalContext.router?.useRouter || runtimeContext.router?.useRouter;
|
|
94
104
|
const contextRouter = contextUseRouter ? contextUseRouter({
|
|
95
105
|
warn: false
|
|
96
106
|
}) : null;
|
|
97
|
-
const [, setRouterVersion] = (0, external_react_namespaceObject.useState)(0);
|
|
98
107
|
const hasRouter = 'tanstack' === framework || 'react-router' === framework || Boolean(reactRouterNavigate);
|
|
99
|
-
(0, external_react_namespaceObject.
|
|
108
|
+
const subscribeToRouter = (0, external_react_namespaceObject.useCallback)((update)=>{
|
|
100
109
|
const router = getRouterInstance(internalContext, contextRouter);
|
|
101
|
-
if (!router) return;
|
|
102
|
-
const update = ()=>setRouterVersion((version)=>version + 1);
|
|
110
|
+
if (!router) return ()=>void 0;
|
|
103
111
|
const unsubscribers = [];
|
|
104
112
|
if ('react-router' === framework && !inReactRouter && 'function' == typeof router.subscribe) {
|
|
105
113
|
const subscribe = router.subscribe;
|
|
@@ -129,6 +137,11 @@ const useI18nRouterAdapter = ()=>{
|
|
|
129
137
|
inReactRouter,
|
|
130
138
|
internalContext
|
|
131
139
|
]);
|
|
140
|
+
const getSnapshot = (0, external_react_namespaceObject.useCallback)(()=>getRouterSnapshot(internalContext, contextRouter), [
|
|
141
|
+
contextRouter,
|
|
142
|
+
internalContext
|
|
143
|
+
]);
|
|
144
|
+
(0, external_react_namespaceObject.useSyncExternalStore)(subscribeToRouter, getSnapshot, getSnapshot);
|
|
132
145
|
const navigate = (0, external_react_namespaceObject.useCallback)((href, options)=>{
|
|
133
146
|
const router = getRouterInstance(internalContext, contextRouter);
|
|
134
147
|
const activeFramework = getRouterFramework(runtimeContext, internalContext, inReactRouter);
|
|
@@ -156,7 +169,7 @@ const useI18nRouterAdapter = ()=>{
|
|
|
156
169
|
]);
|
|
157
170
|
const location = (reactRouterLocation ? normalizeLocation(reactRouterLocation) : getRouterStateLocation(internalContext, contextRouter)) || getWindowLocation();
|
|
158
171
|
const params = inReactRouter ? reactRouterParams : getRouterParams(internalContext, contextRouter);
|
|
159
|
-
const Link = 'tanstack' === framework ? internalContext.router?.Link || runtimeContext.router?.Link || null : 'react-router' === framework || inReactRouter ?
|
|
172
|
+
const Link = 'tanstack' === framework ? internalContext.router?.Link || runtimeContext.router?.Link || null : 'react-router' === framework || inReactRouter ? routerApi?.Link ?? null : null;
|
|
160
173
|
return {
|
|
161
174
|
framework,
|
|
162
175
|
hasRouter,
|
|
@@ -55,7 +55,8 @@ async function changeModernI18nLanguage(newLang, options) {
|
|
|
55
55
|
}
|
|
56
56
|
function translateI18n(i18nInstance, key, ...args) {
|
|
57
57
|
if ('function' != typeof i18nInstance.t) throw new Error('i18nInstance.t required');
|
|
58
|
-
|
|
58
|
+
const translate = i18nInstance.t;
|
|
59
|
+
return translate.call(i18nInstance, key, ...args);
|
|
59
60
|
}
|
|
60
61
|
function isI18nLanguageSupported(languages, lang) {
|
|
61
62
|
return languages?.includes(lang) || false;
|
|
@@ -45,21 +45,20 @@ const createI18nRootWrapper = (options)=>(App)=>(props)=>{
|
|
|
45
45
|
forceUpdate,
|
|
46
46
|
synchronizeLanguage
|
|
47
47
|
]);
|
|
48
|
+
const I18nextProvider = getI18nextProvider();
|
|
49
|
+
const i18nextInstanceForProvider = useMemo(()=>i18nInstance ? getI18nextInstanceForProvider(i18nInstance, lang) : void 0, [
|
|
50
|
+
i18nInstance,
|
|
51
|
+
lang
|
|
52
|
+
]);
|
|
48
53
|
const children = props.children;
|
|
49
54
|
let appContent = App ? /*#__PURE__*/ jsx(App, {
|
|
50
55
|
...props,
|
|
51
56
|
children: children
|
|
52
57
|
}) : children;
|
|
53
|
-
if (
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
appContent = /*#__PURE__*/ jsx(I18nextProvider, {
|
|
58
|
-
i18n: i18nextInstanceForProvider,
|
|
59
|
-
children: appContent
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
}
|
|
58
|
+
if (I18nextProvider && i18nextInstanceForProvider) appContent = /*#__PURE__*/ jsx(I18nextProvider, {
|
|
59
|
+
i18n: i18nextInstanceForProvider,
|
|
60
|
+
children: appContent
|
|
61
|
+
});
|
|
63
62
|
return /*#__PURE__*/ jsxs(Fragment, {
|
|
64
63
|
children: [
|
|
65
64
|
Boolean(htmlLangAttr) && /*#__PURE__*/ jsx(Helmet, {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { RuntimeContext, isBrowser } from "@modern-js/runtime";
|
|
2
2
|
import { InternalRuntimeContext, getRouterRuntimeState } from "@modern-js/runtime/context";
|
|
3
|
-
import {
|
|
4
|
-
import { useCallback, useContext, useEffect, useState } from "react";
|
|
3
|
+
import { useCallback, useContext, useSyncExternalStore } from "react";
|
|
5
4
|
const normalizeUrlPart = (value, prefix)=>{
|
|
6
5
|
if ('string' != typeof value || !value) return '';
|
|
7
6
|
return value.startsWith(prefix) ? value : `${prefix}${value}`;
|
|
@@ -50,24 +49,33 @@ const getRouterParams = (internalContext, contextRouter)=>{
|
|
|
50
49
|
return params;
|
|
51
50
|
}, {});
|
|
52
51
|
};
|
|
52
|
+
const getRouterSnapshot = (internalContext, contextRouter)=>{
|
|
53
|
+
const location = getRouterStateLocation(internalContext, contextRouter);
|
|
54
|
+
const params = getRouterParams(internalContext, contextRouter);
|
|
55
|
+
return JSON.stringify([
|
|
56
|
+
location?.pathname ?? '',
|
|
57
|
+
location?.search ?? '',
|
|
58
|
+
location?.hash ?? '',
|
|
59
|
+
Object.entries(params).sort(([left], [right])=>left.localeCompare(right))
|
|
60
|
+
]);
|
|
61
|
+
};
|
|
53
62
|
const useI18nRouterAdapter = ()=>{
|
|
54
63
|
const runtimeContext = useContext(RuntimeContext);
|
|
55
64
|
const internalContext = useContext(InternalRuntimeContext);
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
const
|
|
65
|
+
const routerApi = internalContext.router || runtimeContext.router;
|
|
66
|
+
const inReactRouter = routerApi?.useInRouterContext?.() ?? false;
|
|
67
|
+
const reactRouterNavigate = inReactRouter ? routerApi?.useNavigate?.() ?? null : null;
|
|
68
|
+
const reactRouterLocation = inReactRouter ? routerApi?.useLocation?.() ?? null : null;
|
|
69
|
+
const reactRouterParams = inReactRouter ? routerApi?.useParams?.() ?? {} : {};
|
|
60
70
|
const framework = getRouterFramework(runtimeContext, internalContext, inReactRouter);
|
|
61
71
|
const contextUseRouter = inReactRouter || 'tanstack' !== framework ? void 0 : internalContext.router?.useRouter || runtimeContext.router?.useRouter;
|
|
62
72
|
const contextRouter = contextUseRouter ? contextUseRouter({
|
|
63
73
|
warn: false
|
|
64
74
|
}) : null;
|
|
65
|
-
const [, setRouterVersion] = useState(0);
|
|
66
75
|
const hasRouter = 'tanstack' === framework || 'react-router' === framework || Boolean(reactRouterNavigate);
|
|
67
|
-
|
|
76
|
+
const subscribeToRouter = useCallback((update)=>{
|
|
68
77
|
const router = getRouterInstance(internalContext, contextRouter);
|
|
69
|
-
if (!router) return;
|
|
70
|
-
const update = ()=>setRouterVersion((version)=>version + 1);
|
|
78
|
+
if (!router) return ()=>void 0;
|
|
71
79
|
const unsubscribers = [];
|
|
72
80
|
if ('react-router' === framework && !inReactRouter && 'function' == typeof router.subscribe) {
|
|
73
81
|
const subscribe = router.subscribe;
|
|
@@ -97,6 +105,11 @@ const useI18nRouterAdapter = ()=>{
|
|
|
97
105
|
inReactRouter,
|
|
98
106
|
internalContext
|
|
99
107
|
]);
|
|
108
|
+
const getSnapshot = useCallback(()=>getRouterSnapshot(internalContext, contextRouter), [
|
|
109
|
+
contextRouter,
|
|
110
|
+
internalContext
|
|
111
|
+
]);
|
|
112
|
+
useSyncExternalStore(subscribeToRouter, getSnapshot, getSnapshot);
|
|
100
113
|
const navigate = useCallback((href, options)=>{
|
|
101
114
|
const router = getRouterInstance(internalContext, contextRouter);
|
|
102
115
|
const activeFramework = getRouterFramework(runtimeContext, internalContext, inReactRouter);
|
|
@@ -124,7 +137,7 @@ const useI18nRouterAdapter = ()=>{
|
|
|
124
137
|
]);
|
|
125
138
|
const location = (reactRouterLocation ? normalizeLocation(reactRouterLocation) : getRouterStateLocation(internalContext, contextRouter)) || getWindowLocation();
|
|
126
139
|
const params = inReactRouter ? reactRouterParams : getRouterParams(internalContext, contextRouter);
|
|
127
|
-
const Link = 'tanstack' === framework ? internalContext.router?.Link || runtimeContext.router?.Link || null : 'react-router' === framework || inReactRouter ?
|
|
140
|
+
const Link = 'tanstack' === framework ? internalContext.router?.Link || runtimeContext.router?.Link || null : 'react-router' === framework || inReactRouter ? routerApi?.Link ?? null : null;
|
|
128
141
|
return {
|
|
129
142
|
framework,
|
|
130
143
|
hasRouter,
|
|
@@ -56,7 +56,8 @@ async function changeModernI18nLanguage(newLang, options) {
|
|
|
56
56
|
}
|
|
57
57
|
function translateI18n(i18nInstance, key, ...args) {
|
|
58
58
|
if ('function' != typeof i18nInstance.t) throw new Error('i18nInstance.t required');
|
|
59
|
-
|
|
59
|
+
const translate = i18nInstance.t;
|
|
60
|
+
return translate.call(i18nInstance, key, ...args);
|
|
60
61
|
}
|
|
61
62
|
function isI18nLanguageSupported(languages, lang) {
|
|
62
63
|
return languages?.includes(lang) || false;
|
|
@@ -10,6 +10,9 @@ function createMinimalI18nInstance(language) {
|
|
|
10
10
|
language,
|
|
11
11
|
isInitialized: false,
|
|
12
12
|
init: ()=>Promise.resolve(void 0),
|
|
13
|
+
t: ()=>{
|
|
14
|
+
throw new Error('i18nInstance.t required');
|
|
15
|
+
},
|
|
13
16
|
use: ()=>{},
|
|
14
17
|
createInstance: ()=>minimalInstance,
|
|
15
18
|
services: {}
|
|
@@ -46,21 +46,20 @@ const createI18nRootWrapper = (options)=>(App)=>(props)=>{
|
|
|
46
46
|
forceUpdate,
|
|
47
47
|
synchronizeLanguage
|
|
48
48
|
]);
|
|
49
|
+
const I18nextProvider = getI18nextProvider();
|
|
50
|
+
const i18nextInstanceForProvider = useMemo(()=>i18nInstance ? getI18nextInstanceForProvider(i18nInstance, lang) : void 0, [
|
|
51
|
+
i18nInstance,
|
|
52
|
+
lang
|
|
53
|
+
]);
|
|
49
54
|
const children = props.children;
|
|
50
55
|
let appContent = App ? /*#__PURE__*/ jsx(App, {
|
|
51
56
|
...props,
|
|
52
57
|
children: children
|
|
53
58
|
}) : children;
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
appContent = /*#__PURE__*/ jsx(I18nextProvider, {
|
|
59
|
-
i18n: i18nextInstanceForProvider,
|
|
60
|
-
children: appContent
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
}
|
|
59
|
+
if (I18nextProvider && i18nextInstanceForProvider) appContent = /*#__PURE__*/ jsx(I18nextProvider, {
|
|
60
|
+
i18n: i18nextInstanceForProvider,
|
|
61
|
+
children: appContent
|
|
62
|
+
});
|
|
64
63
|
return /*#__PURE__*/ jsxs(Fragment, {
|
|
65
64
|
children: [
|
|
66
65
|
Boolean(htmlLangAttr) && /*#__PURE__*/ jsx(Helmet, {
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import "node:module";
|
|
2
2
|
import { RuntimeContext, isBrowser } from "@modern-js/runtime";
|
|
3
3
|
import { InternalRuntimeContext, getRouterRuntimeState } from "@modern-js/runtime/context";
|
|
4
|
-
import {
|
|
5
|
-
import { useCallback, useContext, useEffect, useState } from "react";
|
|
4
|
+
import { useCallback, useContext, useSyncExternalStore } from "react";
|
|
6
5
|
const normalizeUrlPart = (value, prefix)=>{
|
|
7
6
|
if ('string' != typeof value || !value) return '';
|
|
8
7
|
return value.startsWith(prefix) ? value : `${prefix}${value}`;
|
|
@@ -51,24 +50,33 @@ const getRouterParams = (internalContext, contextRouter)=>{
|
|
|
51
50
|
return params;
|
|
52
51
|
}, {});
|
|
53
52
|
};
|
|
53
|
+
const getRouterSnapshot = (internalContext, contextRouter)=>{
|
|
54
|
+
const location = getRouterStateLocation(internalContext, contextRouter);
|
|
55
|
+
const params = getRouterParams(internalContext, contextRouter);
|
|
56
|
+
return JSON.stringify([
|
|
57
|
+
location?.pathname ?? '',
|
|
58
|
+
location?.search ?? '',
|
|
59
|
+
location?.hash ?? '',
|
|
60
|
+
Object.entries(params).sort(([left], [right])=>left.localeCompare(right))
|
|
61
|
+
]);
|
|
62
|
+
};
|
|
54
63
|
const useI18nRouterAdapter = ()=>{
|
|
55
64
|
const runtimeContext = useContext(RuntimeContext);
|
|
56
65
|
const internalContext = useContext(InternalRuntimeContext);
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
const
|
|
60
|
-
const
|
|
66
|
+
const routerApi = internalContext.router || runtimeContext.router;
|
|
67
|
+
const inReactRouter = routerApi?.useInRouterContext?.() ?? false;
|
|
68
|
+
const reactRouterNavigate = inReactRouter ? routerApi?.useNavigate?.() ?? null : null;
|
|
69
|
+
const reactRouterLocation = inReactRouter ? routerApi?.useLocation?.() ?? null : null;
|
|
70
|
+
const reactRouterParams = inReactRouter ? routerApi?.useParams?.() ?? {} : {};
|
|
61
71
|
const framework = getRouterFramework(runtimeContext, internalContext, inReactRouter);
|
|
62
72
|
const contextUseRouter = inReactRouter || 'tanstack' !== framework ? void 0 : internalContext.router?.useRouter || runtimeContext.router?.useRouter;
|
|
63
73
|
const contextRouter = contextUseRouter ? contextUseRouter({
|
|
64
74
|
warn: false
|
|
65
75
|
}) : null;
|
|
66
|
-
const [, setRouterVersion] = useState(0);
|
|
67
76
|
const hasRouter = 'tanstack' === framework || 'react-router' === framework || Boolean(reactRouterNavigate);
|
|
68
|
-
|
|
77
|
+
const subscribeToRouter = useCallback((update)=>{
|
|
69
78
|
const router = getRouterInstance(internalContext, contextRouter);
|
|
70
|
-
if (!router) return;
|
|
71
|
-
const update = ()=>setRouterVersion((version)=>version + 1);
|
|
79
|
+
if (!router) return ()=>void 0;
|
|
72
80
|
const unsubscribers = [];
|
|
73
81
|
if ('react-router' === framework && !inReactRouter && 'function' == typeof router.subscribe) {
|
|
74
82
|
const subscribe = router.subscribe;
|
|
@@ -98,6 +106,11 @@ const useI18nRouterAdapter = ()=>{
|
|
|
98
106
|
inReactRouter,
|
|
99
107
|
internalContext
|
|
100
108
|
]);
|
|
109
|
+
const getSnapshot = useCallback(()=>getRouterSnapshot(internalContext, contextRouter), [
|
|
110
|
+
contextRouter,
|
|
111
|
+
internalContext
|
|
112
|
+
]);
|
|
113
|
+
useSyncExternalStore(subscribeToRouter, getSnapshot, getSnapshot);
|
|
101
114
|
const navigate = useCallback((href, options)=>{
|
|
102
115
|
const router = getRouterInstance(internalContext, contextRouter);
|
|
103
116
|
const activeFramework = getRouterFramework(runtimeContext, internalContext, inReactRouter);
|
|
@@ -125,7 +138,7 @@ const useI18nRouterAdapter = ()=>{
|
|
|
125
138
|
]);
|
|
126
139
|
const location = (reactRouterLocation ? normalizeLocation(reactRouterLocation) : getRouterStateLocation(internalContext, contextRouter)) || getWindowLocation();
|
|
127
140
|
const params = inReactRouter ? reactRouterParams : getRouterParams(internalContext, contextRouter);
|
|
128
|
-
const Link = 'tanstack' === framework ? internalContext.router?.Link || runtimeContext.router?.Link || null : 'react-router' === framework || inReactRouter ?
|
|
141
|
+
const Link = 'tanstack' === framework ? internalContext.router?.Link || runtimeContext.router?.Link || null : 'react-router' === framework || inReactRouter ? routerApi?.Link ?? null : null;
|
|
129
142
|
return {
|
|
130
143
|
framework,
|
|
131
144
|
hasRouter,
|
|
@@ -31,11 +31,11 @@ export interface FederatedI18nBoundaryProps {
|
|
|
31
31
|
* resources used below this boundary.
|
|
32
32
|
*/
|
|
33
33
|
export declare const FederatedI18nBoundary: FC<FederatedI18nBoundaryProps>;
|
|
34
|
-
interface UseModernI18nReturn {
|
|
34
|
+
export interface UseModernI18nReturn<TInstance extends I18nInstance = I18nInstance> {
|
|
35
35
|
language: string;
|
|
36
36
|
changeLanguage: (newLang: string) => Promise<void>;
|
|
37
37
|
t: (key: string | string[], ...args: any[]) => string;
|
|
38
|
-
i18nInstance:
|
|
38
|
+
i18nInstance: TInstance;
|
|
39
39
|
supportedLanguages: string[];
|
|
40
40
|
localisedUrls?: LocalisedUrlsOption;
|
|
41
41
|
isLanguageSupported: (lang: string) => boolean;
|
|
@@ -51,8 +51,14 @@ interface UseModernI18nReturn {
|
|
|
51
51
|
* - List of supported languages
|
|
52
52
|
* - Helper function to check if language is supported
|
|
53
53
|
*
|
|
54
|
+
* @typeParam TInstance - The concrete shape of the i18n instance held by the
|
|
55
|
+
* provider (e.g. i18next's `i18n`, or a wrapper type). Constrained to
|
|
56
|
+
* `I18nInstance`, so a nonsense argument is rejected; within that constraint it
|
|
57
|
+
* is still a caller assertion — the provider stores the base type and the
|
|
58
|
+
* narrowing is not verified at runtime. Pass it only when you know which
|
|
59
|
+
* instance the provider was given.
|
|
54
60
|
* @param options - Optional configuration to override context settings
|
|
55
61
|
* @returns Object containing i18n functionality and utilities
|
|
56
62
|
*/
|
|
57
|
-
export declare const useModernI18n: () => UseModernI18nReturn
|
|
63
|
+
export declare const useModernI18n: <TInstance extends I18nInstance = I18nInstance>() => UseModernI18nReturn<TInstance>;
|
|
58
64
|
export {};
|
|
@@ -4,7 +4,7 @@ import type { I18nInitOptions, I18nInstance } from './i18n';
|
|
|
4
4
|
import { type LoadReactI18nextIntegration } from './reactI18next';
|
|
5
5
|
import './types';
|
|
6
6
|
export type { I18nSdkLoader, I18nSdkLoadOptions } from '../shared/type';
|
|
7
|
-
export type { Resources } from './i18n/instance';
|
|
7
|
+
export type { I18nInitOptions, I18nInstance, Resources, TranslateFn, } from './i18n/instance';
|
|
8
8
|
export type { LoadReactI18nextIntegration, ReactI18nextIntegration, } from './reactI18next';
|
|
9
9
|
export interface I18nPluginOptions {
|
|
10
10
|
entryName?: string;
|
|
@@ -19,7 +19,7 @@ export interface I18nPluginOptions {
|
|
|
19
19
|
}
|
|
20
20
|
export declare const createI18nPlugin: (loadReactI18nextIntegration?: LoadReactI18nextIntegration) => ((options: I18nPluginOptions) => RuntimePlugin);
|
|
21
21
|
export type { AllowedLinkTarget, CanonicalRoutePath, UltramodernCanonicalRoutes, } from './canonicalRoutes';
|
|
22
|
-
export { FederatedI18nBoundary, type FederatedI18nBoundaryProps, useModernI18n, } from './context';
|
|
22
|
+
export { FederatedI18nBoundary, type FederatedI18nBoundaryProps, type UseModernI18nReturn, useModernI18n, } from './context';
|
|
23
23
|
export { I18nLink, type I18nLinkProps } from './I18nLink';
|
|
24
24
|
export { Link, type LinkActiveOptions, type LinkBaseProps, type LinkParams, type LinkProps, } from './Link';
|
|
25
25
|
export { canonicalPath, type LocalizedPathsConfig, localizePath, type UseLocalizedLocationReturn, type UseLocalizedPathsReturn, useLocalizedLocation, useLocalizedPaths, } from './localizedPaths';
|
|
@@ -11,5 +11,5 @@ type BackendConstructor = new (...args: never[]) => unknown;
|
|
|
11
11
|
* @param BackendBase - The base backend class (for non-chained use)
|
|
12
12
|
* @param backend - Optional backend configuration
|
|
13
13
|
*/
|
|
14
|
-
export declare function useI18nextBackendCommon(i18nInstance: I18nInstance, BackendWithSave: BackendConstructor, BackendBase: BackendConstructor, backend?: BackendConfigWithChained):
|
|
14
|
+
export declare function useI18nextBackendCommon(i18nInstance: I18nInstance, BackendWithSave: BackendConstructor, BackendBase: BackendConstructor, backend?: BackendConfigWithChained): unknown;
|
|
15
15
|
export {};
|
|
@@ -9,4 +9,4 @@ import type { I18nInstance } from '../instance';
|
|
|
9
9
|
export declare class HttpBackendWithSave extends Backend {
|
|
10
10
|
save(_language: string, _namespace: string, _data: unknown): void;
|
|
11
11
|
}
|
|
12
|
-
export declare const useI18nextBackend: (i18nInstance: I18nInstance, backend?: ExtendedBackendOptions) =>
|
|
12
|
+
export declare const useI18nextBackend: (i18nInstance: I18nInstance, backend?: ExtendedBackendOptions) => unknown;
|
|
@@ -12,5 +12,5 @@ export declare class FsBackendWithSave extends Backend {
|
|
|
12
12
|
save(_language: string, _namespace: string, _data: unknown): void;
|
|
13
13
|
}
|
|
14
14
|
export declare const HttpBackendWithSave: typeof FsBackendWithSave;
|
|
15
|
-
export declare const useI18nextBackend: (i18nInstance: I18nInstance, backend?: ExtendedBackendOptions) =>
|
|
15
|
+
export declare const useI18nextBackend: (i18nInstance: I18nInstance, backend?: ExtendedBackendOptions) => unknown;
|
|
16
16
|
export {};
|
|
@@ -4,7 +4,7 @@ import type { I18nInstance, LanguageDetectorOptions } from '../instance';
|
|
|
4
4
|
* Must be called before init() to properly register the detector
|
|
5
5
|
* For wrapper instances, ensure detector is registered on the underlying i18next instance
|
|
6
6
|
*/
|
|
7
|
-
export declare const useI18nextLanguageDetector: (i18nInstance: I18nInstance) =>
|
|
7
|
+
export declare const useI18nextLanguageDetector: (i18nInstance: I18nInstance) => unknown;
|
|
8
8
|
/**
|
|
9
9
|
* Read language directly from localStorage/cookie
|
|
10
10
|
* Fallback when detector is not available in services
|
|
@@ -9,7 +9,7 @@ export declare const readLanguageFromStorage: (_detectionOptions?: LanguageDetec
|
|
|
9
9
|
* Register LanguageDetector plugin to i18n instance
|
|
10
10
|
* Must be called before init() to properly register the detector
|
|
11
11
|
*/
|
|
12
|
-
export declare const useI18nextLanguageDetector: (i18nInstance: I18nInstance) =>
|
|
12
|
+
export declare const useI18nextLanguageDetector: (i18nInstance: I18nInstance) => unknown;
|
|
13
13
|
/**
|
|
14
14
|
* Detect language using i18next-http-middleware LanguageDetector
|
|
15
15
|
* For initialized instances without detector in services, manually create a detector instance
|
|
@@ -14,36 +14,45 @@ type I18nWrapperInstance = I18nInstance & {
|
|
|
14
14
|
};
|
|
15
15
|
export declare function isI18nWrapperInstance(obj: unknown): obj is I18nWrapperInstance;
|
|
16
16
|
export declare function getActualI18nextInstance(instance: I18nInstance): I18nInstance;
|
|
17
|
+
export type TranslateFn = (key: string | string[], options?: Record<string, unknown>) => string;
|
|
17
18
|
export interface I18nInstance {
|
|
18
19
|
language: string;
|
|
19
20
|
isInitialized?: boolean;
|
|
20
|
-
init:
|
|
21
|
-
|
|
22
|
-
(options: I18nInitOptions, callback?: (error: unknown, t: unknown) => void): Promise<unknown>;
|
|
23
|
-
};
|
|
24
|
-
changeLanguage?: (lng?: string, callback?: (error: unknown, t: unknown) => void) => Promise<unknown>;
|
|
21
|
+
init(options?: any, callback?: any): Promise<any>;
|
|
22
|
+
changeLanguage?(lng?: string, callback?: any): Promise<any>;
|
|
25
23
|
setLang?: (lang: string) => void | Promise<void>;
|
|
26
|
-
use
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
use(plugin: any): unknown;
|
|
25
|
+
t: TranslateFn;
|
|
26
|
+
exists?: (key: string | string[], options?: Record<string, unknown>) => boolean;
|
|
27
|
+
getFixedT?: (lng: string | readonly string[] | null, ns?: string | readonly string[] | null, keyPrefix?: string) => TranslateFn;
|
|
28
|
+
hasLoadedNamespace?: (ns: string | readonly string[], options?: Record<string, unknown>) => boolean;
|
|
29
|
+
dir?: (lng?: string) => string;
|
|
30
|
+
format?: (value: unknown, format?: string, lng?: string, options?: Record<string, unknown>) => string;
|
|
31
|
+
languages?: readonly string[];
|
|
32
|
+
resolvedLanguage?: string;
|
|
33
|
+
loadNamespaces?: (ns: string | readonly string[], callback?: (...args: any[]) => void) => Promise<void>;
|
|
34
|
+
loadLanguages?: (lngs: string | readonly string[], callback?: (...args: any[]) => void) => Promise<void>;
|
|
35
|
+
addResourceBundle?: (lng: string, ns: string, resources: Record<string, unknown>, deep?: boolean, overwrite?: boolean) => unknown;
|
|
36
|
+
getResourceBundle?: (lng: string, ns: string) => unknown;
|
|
37
|
+
getDataByLanguage?: (lng: string) => Record<string, Record<string, string>> | undefined;
|
|
38
|
+
createInstance?(options?: any, callback?: any): I18nInstance;
|
|
39
|
+
cloneInstance?(options?: any, callback?: any): I18nInstance;
|
|
29
40
|
store?: I18nResourceStore;
|
|
30
|
-
emit
|
|
31
|
-
reloadResources
|
|
32
|
-
removeResourceBundle
|
|
41
|
+
emit?(event: string, ...args: any[]): unknown;
|
|
42
|
+
reloadResources?(language?: any, namespace?: any, callback?: any): Promise<void>;
|
|
43
|
+
removeResourceBundle?(language: string, namespace: string): I18nInstance;
|
|
33
44
|
services?: {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
[key: string]: unknown;
|
|
37
|
-
};
|
|
45
|
+
store?: unknown;
|
|
46
|
+
languageDetector?: any;
|
|
38
47
|
resourceStore?: I18nResourceStore;
|
|
39
48
|
backend?: unknown;
|
|
40
|
-
[key: string]: unknown;
|
|
41
49
|
};
|
|
42
50
|
options?: {
|
|
43
|
-
|
|
44
|
-
|
|
51
|
+
detection?: any;
|
|
52
|
+
backend?: any;
|
|
53
|
+
ns?: any;
|
|
54
|
+
defaultNS?: any;
|
|
45
55
|
};
|
|
46
|
-
[key: string]: unknown;
|
|
47
56
|
}
|
|
48
57
|
type LanguageDetectorOrder = string[];
|
|
49
58
|
type LanguageDetectorCaches = boolean | string[];
|