@bleedingdev/modern-js-plugin-i18n 3.9.0-ultramodern.4 → 3.9.0-ultramodern.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/cli/index.js +0 -22
- package/dist/cjs/runtime/Link.js +19 -32
- package/dist/cjs/runtime/context.js +26 -61
- package/dist/cjs/runtime/contextHelpers.js +5 -5
- package/dist/cjs/runtime/core.js +17 -14
- package/dist/cjs/runtime/hooks.js +7 -8
- package/dist/cjs/runtime/localizedPaths.js +11 -9
- package/dist/cjs/runtime/providerComposition.js +37 -13
- package/dist/cjs/runtime/routerAdapter.js +35 -140
- package/dist/cjs/runtime/utils.js +17 -19
- package/dist/cjs/server/index.js +10 -7
- package/dist/cjs/server/redirectPolicy.js +36 -31
- package/dist/cjs/shared/urlStrategy.js +18 -0
- package/dist/esm/cli/index.mjs +0 -22
- package/dist/esm/runtime/Link.mjs +19 -32
- package/dist/esm/runtime/context.mjs +18 -62
- package/dist/esm/runtime/contextHelpers.mjs +5 -5
- package/dist/esm/runtime/core.mjs +8 -5
- package/dist/esm/runtime/hooks.mjs +7 -8
- package/dist/esm/runtime/localizedPaths.mjs +11 -9
- package/dist/esm/runtime/providerComposition.mjs +38 -14
- package/dist/esm/runtime/routerAdapter.mjs +30 -141
- package/dist/esm/runtime/utils.mjs +15 -17
- package/dist/esm/server/index.mjs +10 -7
- package/dist/esm/server/redirectPolicy.mjs +29 -24
- package/dist/esm/shared/urlStrategy.mjs +0 -0
- package/dist/esm-node/cli/index.mjs +0 -22
- package/dist/esm-node/runtime/Link.mjs +19 -32
- package/dist/esm-node/runtime/context.mjs +18 -62
- package/dist/esm-node/runtime/contextHelpers.mjs +5 -5
- package/dist/esm-node/runtime/core.mjs +8 -5
- package/dist/esm-node/runtime/hooks.mjs +7 -8
- package/dist/esm-node/runtime/localizedPaths.mjs +11 -9
- package/dist/esm-node/runtime/providerComposition.mjs +38 -14
- package/dist/esm-node/runtime/routerAdapter.mjs +30 -141
- package/dist/esm-node/runtime/utils.mjs +15 -17
- package/dist/esm-node/server/index.mjs +10 -7
- package/dist/esm-node/server/redirectPolicy.mjs +29 -24
- package/dist/esm-node/shared/urlStrategy.mjs +1 -0
- package/dist/types/runtime/context.d.ts +8 -11
- package/dist/types/runtime/contextHelpers.d.ts +2 -2
- package/dist/types/runtime/core.d.ts +11 -2
- package/dist/types/runtime/hooks.d.ts +4 -5
- package/dist/types/runtime/localizedPaths.d.ts +4 -4
- package/dist/types/runtime/providerComposition.d.ts +13 -1
- package/dist/types/runtime/routerAdapter.d.ts +23 -6
- package/dist/types/runtime/utils.d.ts +4 -12
- package/dist/types/server/index.d.ts +2 -0
- package/dist/types/server/redirectPolicy.d.ts +5 -13
- package/dist/types/shared/type.d.ts +0 -14
- package/dist/types/shared/urlStrategy.d.ts +7 -0
- package/package.json +21 -11
- package/rstest.config.mts +2 -8
- package/src/cli/index.ts +1 -43
- package/src/runtime/Link.tsx +20 -40
- package/src/runtime/context.tsx +34 -133
- package/src/runtime/contextHelpers.ts +7 -5
- package/src/runtime/core.tsx +26 -6
- package/src/runtime/hooks.ts +14 -9
- package/src/runtime/localizedPaths.ts +24 -19
- package/src/runtime/providerComposition.tsx +71 -23
- package/src/runtime/routerAdapter.tsx +73 -338
- package/src/runtime/utils.ts +40 -31
- package/src/server/index.ts +44 -9
- package/src/server/redirectPolicy.ts +70 -70
- package/src/shared/type.ts +0 -14
- package/src/shared/urlStrategy.ts +11 -0
- package/tests/federatedI18nBoundaryResolver.test.tsx +71 -0
- package/tests/i18nUtils.test.ts +31 -65
- package/tests/link.test.tsx +13 -511
- package/tests/linkTypes.test.ts +12 -3
- package/tests/localisedUrlRewriteMatrix.fork.test.ts +4 -96
- package/tests/localisedUrls.test.ts +7 -216
- package/tests/reactI18nextRuntimeBoundary.test.ts +1 -82
- package/tests/redirectPolicy.test.ts +39 -30
- package/tests/routerAdapter.test.tsx +95 -1055
- package/tests/federatedI18nBoundary.client.test.tsx +0 -129
- package/tests/federatedI18nBoundary.test.tsx +0 -132
- package/tests/peerCohort.test.ts +0 -25
package/src/runtime/core.tsx
CHANGED
|
@@ -4,12 +4,19 @@ import type {
|
|
|
4
4
|
BaseBackendOptions,
|
|
5
5
|
BaseLocaleDetectionOptions,
|
|
6
6
|
} from '../shared/type';
|
|
7
|
+
import type { I18nUrlStrategy } from '../shared/urlStrategy';
|
|
7
8
|
import type { I18nInitOptions, I18nInstance } from './i18n';
|
|
8
9
|
import {
|
|
9
10
|
type RuntimeContextWithI18n,
|
|
10
11
|
setupI18nBeforeRender,
|
|
11
12
|
} from './pluginSetup';
|
|
12
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
createI18nRootWrapper,
|
|
15
|
+
type I18nLanguageSynchronizationProps,
|
|
16
|
+
} from './providerComposition';
|
|
17
|
+
|
|
18
|
+
export type { I18nLanguageSynchronizationProps } from './providerComposition';
|
|
19
|
+
|
|
13
20
|
import {
|
|
14
21
|
type LoadReactI18nextIntegration,
|
|
15
22
|
resolveReactI18nextIntegration,
|
|
@@ -17,6 +24,7 @@ import {
|
|
|
17
24
|
import './types';
|
|
18
25
|
|
|
19
26
|
export type { I18nSdkLoader, I18nSdkLoadOptions } from '../shared/type';
|
|
27
|
+
export type { I18nUrlStrategy } from '../shared/urlStrategy';
|
|
20
28
|
export type {
|
|
21
29
|
I18nInitOptions,
|
|
22
30
|
I18nInstance,
|
|
@@ -27,6 +35,13 @@ export type {
|
|
|
27
35
|
LoadReactI18nextIntegration,
|
|
28
36
|
ReactI18nextIntegration,
|
|
29
37
|
} from './reactI18next';
|
|
38
|
+
export {
|
|
39
|
+
I18nNavigationProvider,
|
|
40
|
+
type I18nRouterAdapter,
|
|
41
|
+
type I18nRouterLinkTarget,
|
|
42
|
+
useI18nRouterAdapter,
|
|
43
|
+
useNativeI18nRouterAdapter,
|
|
44
|
+
} from './routerAdapter';
|
|
30
45
|
|
|
31
46
|
export interface I18nPluginOptions {
|
|
32
47
|
entryName?: string;
|
|
@@ -37,6 +52,9 @@ export interface I18nPluginOptions {
|
|
|
37
52
|
initOptions?: I18nInitOptions;
|
|
38
53
|
htmlLangAttr?: boolean;
|
|
39
54
|
reactI18next?: boolean;
|
|
55
|
+
urlStrategy?: I18nUrlStrategy;
|
|
56
|
+
NavigationProvider?: React.ComponentType<React.PropsWithChildren>;
|
|
57
|
+
LanguageSynchronization?: React.ComponentType<I18nLanguageSynchronizationProps>;
|
|
40
58
|
[key: string]: any;
|
|
41
59
|
}
|
|
42
60
|
|
|
@@ -55,6 +73,9 @@ export const createI18nPlugin =
|
|
|
55
73
|
backend,
|
|
56
74
|
htmlLangAttr = false,
|
|
57
75
|
reactI18next = true,
|
|
76
|
+
urlStrategy,
|
|
77
|
+
NavigationProvider,
|
|
78
|
+
LanguageSynchronization,
|
|
58
79
|
} = options;
|
|
59
80
|
const {
|
|
60
81
|
localePathRedirect = false,
|
|
@@ -63,7 +84,6 @@ export const createI18nPlugin =
|
|
|
63
84
|
fallbackLanguage = 'en',
|
|
64
85
|
detection,
|
|
65
86
|
ignoreRedirectRoutes,
|
|
66
|
-
localisedUrls,
|
|
67
87
|
} = localeDetection || {};
|
|
68
88
|
const { enabled: backendEnabled = false } = backend || {};
|
|
69
89
|
let latestI18nInstance: I18nInstance | undefined;
|
|
@@ -100,7 +120,9 @@ export const createI18nPlugin =
|
|
|
100
120
|
languages,
|
|
101
121
|
fallbackLanguage,
|
|
102
122
|
ignoreRedirectRoutes,
|
|
103
|
-
|
|
123
|
+
urlStrategy,
|
|
124
|
+
NavigationProvider,
|
|
125
|
+
LanguageSynchronization,
|
|
104
126
|
getLatestI18nInstance: () => latestI18nInstance,
|
|
105
127
|
getI18nextProvider: () => I18nextProvider,
|
|
106
128
|
}),
|
|
@@ -128,12 +150,10 @@ export {
|
|
|
128
150
|
type LinkProps,
|
|
129
151
|
} from './Link';
|
|
130
152
|
export {
|
|
131
|
-
canonicalPath,
|
|
132
153
|
type LocalizedPathsConfig,
|
|
133
|
-
localizePath,
|
|
134
154
|
type UseLocalizedLocationReturn,
|
|
135
155
|
type UseLocalizedPathsReturn,
|
|
136
156
|
useLocalizedLocation,
|
|
137
157
|
useLocalizedPaths,
|
|
138
158
|
} from './localizedPaths';
|
|
139
|
-
export {
|
|
159
|
+
export { splitUrlTarget } from './utils';
|
package/src/runtime/hooks.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { LocalisedUrlsOption } from '@modern-js/i18n-runtime-extensions';
|
|
2
1
|
import { isBrowser } from '@modern-js/runtime';
|
|
3
2
|
import type React from 'react';
|
|
4
3
|
import { useCallback, useEffect, useRef } from 'react';
|
|
4
|
+
import type { I18nUrlStrategy } from '../shared/urlStrategy';
|
|
5
5
|
import {
|
|
6
6
|
cacheI18nLanguage,
|
|
7
7
|
changeI18nInstanceLanguage,
|
|
@@ -54,9 +54,8 @@ export function createContextValue(
|
|
|
54
54
|
languages: string[],
|
|
55
55
|
localePathRedirect: boolean,
|
|
56
56
|
ignoreRedirectRoutes: string[] | ((pathname: string) => boolean) | undefined,
|
|
57
|
-
localisedUrls: LocalisedUrlsOption | undefined,
|
|
58
57
|
setLang: (lang: string) => void,
|
|
59
|
-
|
|
58
|
+
urlStrategy?: I18nUrlStrategy,
|
|
60
59
|
) {
|
|
61
60
|
const instance = i18nInstance || createMinimalI18nInstance(lang);
|
|
62
61
|
return {
|
|
@@ -66,9 +65,8 @@ export function createContextValue(
|
|
|
66
65
|
languages,
|
|
67
66
|
localePathRedirect,
|
|
68
67
|
ignoreRedirectRoutes,
|
|
69
|
-
|
|
68
|
+
urlStrategy,
|
|
70
69
|
updateLanguage: setLang,
|
|
71
|
-
synchronizeLanguage,
|
|
72
70
|
};
|
|
73
71
|
}
|
|
74
72
|
|
|
@@ -179,7 +177,7 @@ export function useClientSideRedirect(
|
|
|
179
177
|
languages: string[],
|
|
180
178
|
fallbackLanguage: string,
|
|
181
179
|
ignoreRedirectRoutes?: string[] | ((pathname: string) => boolean),
|
|
182
|
-
|
|
180
|
+
urlStrategy?: I18nUrlStrategy,
|
|
183
181
|
) {
|
|
184
182
|
const urlRef = useRef('');
|
|
185
183
|
const { navigate, location, hasRouter } = useI18nRouterAdapter();
|
|
@@ -220,7 +218,14 @@ export function useClientSideRedirect(
|
|
|
220
218
|
const entryPath = getEntryPath();
|
|
221
219
|
const relativePath = currentPathname.replace(entryPath, '');
|
|
222
220
|
|
|
223
|
-
if (
|
|
221
|
+
if (
|
|
222
|
+
shouldIgnoreRedirect(
|
|
223
|
+
relativePath,
|
|
224
|
+
languages,
|
|
225
|
+
ignoreRedirectRoutes,
|
|
226
|
+
urlStrategy,
|
|
227
|
+
)
|
|
228
|
+
) {
|
|
224
229
|
return;
|
|
225
230
|
}
|
|
226
231
|
|
|
@@ -241,7 +246,7 @@ export function useClientSideRedirect(
|
|
|
241
246
|
relativePath,
|
|
242
247
|
targetLanguage,
|
|
243
248
|
languages,
|
|
244
|
-
|
|
249
|
+
urlStrategy,
|
|
245
250
|
);
|
|
246
251
|
const newUrl = entryPath + newPath + currentSearch + currentHash;
|
|
247
252
|
|
|
@@ -265,7 +270,7 @@ export function useClientSideRedirect(
|
|
|
265
270
|
languages,
|
|
266
271
|
fallbackLanguage,
|
|
267
272
|
ignoreRedirectRoutes,
|
|
268
|
-
|
|
273
|
+
urlStrategy,
|
|
269
274
|
]);
|
|
270
275
|
}
|
|
271
276
|
|
|
@@ -1,20 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
canonicalTargetPathname,
|
|
3
|
-
type LocalisedUrlsOption,
|
|
4
|
-
} from '@modern-js/i18n-runtime-extensions';
|
|
5
1
|
import { useMemo } from 'react';
|
|
2
|
+
import type { I18nUrlStrategy } from '../shared/urlStrategy';
|
|
6
3
|
import { useModernI18n } from './context';
|
|
7
4
|
import { useI18nRouterAdapter } from './routerAdapter';
|
|
8
5
|
import { buildLocalizedUrl, splitUrlTarget } from './utils';
|
|
9
6
|
|
|
10
7
|
export interface LocalizedPathsConfig {
|
|
11
8
|
languages: string[];
|
|
12
|
-
|
|
9
|
+
urlStrategy?: I18nUrlStrategy;
|
|
13
10
|
}
|
|
14
11
|
|
|
15
12
|
/**
|
|
16
13
|
* Localize a canonical, language-agnostic target for the given language:
|
|
17
|
-
* adds the language prefix and applies
|
|
14
|
+
* adds the language prefix and applies the configured URL strategy.
|
|
18
15
|
* `?search`/`#hash` suffixes are preserved verbatim.
|
|
19
16
|
*/
|
|
20
17
|
export const localizePath = (
|
|
@@ -22,7 +19,7 @@ export const localizePath = (
|
|
|
22
19
|
language: string,
|
|
23
20
|
config: LocalizedPathsConfig,
|
|
24
21
|
): string =>
|
|
25
|
-
buildLocalizedUrl(pathname, language, config.languages, config.
|
|
22
|
+
buildLocalizedUrl(pathname, language, config.languages, config.urlStrategy);
|
|
26
23
|
|
|
27
24
|
/**
|
|
28
25
|
* Reverse of {@link localizePath}: strip the language prefix and map localized
|
|
@@ -34,11 +31,19 @@ export const canonicalPath = (
|
|
|
34
31
|
config: LocalizedPathsConfig,
|
|
35
32
|
): string => {
|
|
36
33
|
const { pathname, search, hash } = splitUrlTarget(target);
|
|
37
|
-
|
|
38
|
-
pathname,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
34
|
+
if (config.urlStrategy) {
|
|
35
|
+
return `${config.urlStrategy.canonicalPathname(pathname, config.languages)}${search}${hash}`;
|
|
36
|
+
}
|
|
37
|
+
const segments = pathname.split('/').filter(Boolean);
|
|
38
|
+
if (
|
|
39
|
+
segments[0] &&
|
|
40
|
+
config.languages.some(
|
|
41
|
+
language => language.toLowerCase() === segments[0].toLowerCase(),
|
|
42
|
+
)
|
|
43
|
+
) {
|
|
44
|
+
segments.shift();
|
|
45
|
+
}
|
|
46
|
+
const resolvedPath = `/${segments.join('/')}`;
|
|
42
47
|
|
|
43
48
|
return `${resolvedPath}${search}${hash}`;
|
|
44
49
|
};
|
|
@@ -50,16 +55,16 @@ export interface UseLocalizedPathsReturn {
|
|
|
50
55
|
|
|
51
56
|
/**
|
|
52
57
|
* Context-bound versions of {@link localizePath} and {@link canonicalPath} —
|
|
53
|
-
* the
|
|
58
|
+
* the languages and URL strategy are read from the i18n
|
|
54
59
|
* provider, so apps never copy pattern-matching helpers again.
|
|
55
60
|
*/
|
|
56
61
|
export const useLocalizedPaths = (): UseLocalizedPathsReturn => {
|
|
57
|
-
const { supportedLanguages,
|
|
62
|
+
const { supportedLanguages, urlStrategy } = useModernI18n();
|
|
58
63
|
|
|
59
64
|
return useMemo(() => {
|
|
60
65
|
const config: LocalizedPathsConfig = {
|
|
61
66
|
languages: supportedLanguages,
|
|
62
|
-
|
|
67
|
+
urlStrategy,
|
|
63
68
|
};
|
|
64
69
|
|
|
65
70
|
return {
|
|
@@ -67,7 +72,7 @@ export const useLocalizedPaths = (): UseLocalizedPathsReturn => {
|
|
|
67
72
|
localizePath(pathname, language, config),
|
|
68
73
|
canonicalPath: (pathname: string) => canonicalPath(pathname, config),
|
|
69
74
|
};
|
|
70
|
-
}, [supportedLanguages,
|
|
75
|
+
}, [supportedLanguages, urlStrategy]);
|
|
71
76
|
};
|
|
72
77
|
|
|
73
78
|
export interface UseLocalizedLocationReturn {
|
|
@@ -83,7 +88,7 @@ export interface UseLocalizedLocationReturn {
|
|
|
83
88
|
* language switchers. SSR-safe: the location comes from the router adapter.
|
|
84
89
|
*/
|
|
85
90
|
export const useLocalizedLocation = (): UseLocalizedLocationReturn => {
|
|
86
|
-
const { language, supportedLanguages,
|
|
91
|
+
const { language, supportedLanguages, urlStrategy } = useModernI18n();
|
|
87
92
|
const { location } = useI18nRouterAdapter();
|
|
88
93
|
const pathname = location?.pathname ?? '/';
|
|
89
94
|
const search = location?.search ?? '';
|
|
@@ -92,7 +97,7 @@ export const useLocalizedLocation = (): UseLocalizedLocationReturn => {
|
|
|
92
97
|
return useMemo(() => {
|
|
93
98
|
const config: LocalizedPathsConfig = {
|
|
94
99
|
languages: supportedLanguages,
|
|
95
|
-
|
|
100
|
+
urlStrategy,
|
|
96
101
|
};
|
|
97
102
|
const alternates: Record<string, string> = {};
|
|
98
103
|
for (const supportedLanguage of supportedLanguages) {
|
|
@@ -105,5 +110,5 @@ export const useLocalizedLocation = (): UseLocalizedLocationReturn => {
|
|
|
105
110
|
canonical: canonicalPath(pathname, config),
|
|
106
111
|
alternates,
|
|
107
112
|
};
|
|
108
|
-
}, [language, supportedLanguages,
|
|
113
|
+
}, [language, supportedLanguages, urlStrategy, pathname, search, hash]);
|
|
109
114
|
};
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { useLanguageSync } from '@modern-js/i18n-runtime-extensions';
|
|
2
1
|
import { RuntimeContext } from '@modern-js/runtime';
|
|
3
2
|
import { Helmet } from '@modern-js/runtime/head';
|
|
4
3
|
import type React from 'react';
|
|
5
4
|
import { useContext, useEffect, useMemo, useRef, useState } from 'react';
|
|
6
5
|
import type { BaseLocaleDetectionOptions } from '../shared/type';
|
|
6
|
+
import type { I18nUrlStrategy } from '../shared/urlStrategy';
|
|
7
7
|
import { ModernI18nProvider } from './context';
|
|
8
8
|
import {
|
|
9
9
|
createContextValue,
|
|
10
10
|
useClientSideRedirect,
|
|
11
|
+
useLanguageSync,
|
|
11
12
|
useSdkResourcesLoader,
|
|
12
13
|
} from './hooks';
|
|
13
14
|
import type { I18nInstance } from './i18n';
|
|
@@ -15,6 +16,38 @@ import { getI18nextInstanceForProvider } from './i18n/instance';
|
|
|
15
16
|
import type { RuntimeContextWithI18n } from './pluginSetup';
|
|
16
17
|
import { useI18nRouterAdapter } from './routerAdapter';
|
|
17
18
|
|
|
19
|
+
export interface I18nLanguageSynchronizationProps {
|
|
20
|
+
i18nInstance: I18nInstance | undefined;
|
|
21
|
+
localePathRedirect: boolean;
|
|
22
|
+
languages: string[];
|
|
23
|
+
pathname: string | undefined;
|
|
24
|
+
prevLangRef: React.MutableRefObject<string>;
|
|
25
|
+
setLang: (language: string) => void;
|
|
26
|
+
children: (
|
|
27
|
+
synchronizeLanguage: (language: string) => void,
|
|
28
|
+
) => React.ReactNode;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const NativeLanguageSynchronization = ({
|
|
32
|
+
i18nInstance,
|
|
33
|
+
localePathRedirect,
|
|
34
|
+
languages,
|
|
35
|
+
pathname,
|
|
36
|
+
prevLangRef,
|
|
37
|
+
setLang,
|
|
38
|
+
children,
|
|
39
|
+
}: I18nLanguageSynchronizationProps) => {
|
|
40
|
+
const synchronizeLanguage = useLanguageSync(
|
|
41
|
+
i18nInstance,
|
|
42
|
+
localePathRedirect,
|
|
43
|
+
languages,
|
|
44
|
+
pathname,
|
|
45
|
+
prevLangRef,
|
|
46
|
+
setLang,
|
|
47
|
+
);
|
|
48
|
+
return children(synchronizeLanguage);
|
|
49
|
+
};
|
|
50
|
+
|
|
18
51
|
interface I18nRootWrapperOptions {
|
|
19
52
|
entryName?: string;
|
|
20
53
|
htmlLangAttr: boolean;
|
|
@@ -22,14 +55,18 @@ interface I18nRootWrapperOptions {
|
|
|
22
55
|
languages: string[];
|
|
23
56
|
fallbackLanguage: string;
|
|
24
57
|
ignoreRedirectRoutes?: BaseLocaleDetectionOptions['ignoreRedirectRoutes'];
|
|
25
|
-
|
|
58
|
+
urlStrategy?: I18nUrlStrategy;
|
|
59
|
+
NavigationProvider?: React.ComponentType<React.PropsWithChildren>;
|
|
60
|
+
LanguageSynchronization?: React.ComponentType<I18nLanguageSynchronizationProps>;
|
|
26
61
|
getLatestI18nInstance: () => I18nInstance | undefined;
|
|
27
62
|
getI18nextProvider: () => React.ComponentType<any> | null | undefined;
|
|
28
63
|
}
|
|
29
64
|
|
|
30
65
|
export const createI18nRootWrapper =
|
|
31
66
|
(options: I18nRootWrapperOptions) => (App: React.ComponentType<any>) => {
|
|
32
|
-
|
|
67
|
+
const LanguageSynchronization =
|
|
68
|
+
options.LanguageSynchronization ?? NativeLanguageSynchronization;
|
|
69
|
+
const I18nRoot = (props: Record<string, unknown>) => {
|
|
33
70
|
const {
|
|
34
71
|
entryName,
|
|
35
72
|
htmlLangAttr,
|
|
@@ -37,7 +74,7 @@ export const createI18nRootWrapper =
|
|
|
37
74
|
languages,
|
|
38
75
|
fallbackLanguage,
|
|
39
76
|
ignoreRedirectRoutes,
|
|
40
|
-
|
|
77
|
+
urlStrategy,
|
|
41
78
|
getLatestI18nInstance,
|
|
42
79
|
getI18nextProvider,
|
|
43
80
|
} = options;
|
|
@@ -69,15 +106,6 @@ export const createI18nRootWrapper =
|
|
|
69
106
|
}, [lang]);
|
|
70
107
|
|
|
71
108
|
useSdkResourcesLoader(i18nInstance, setForceUpdate);
|
|
72
|
-
const synchronizeLanguage = useLanguageSync(
|
|
73
|
-
i18nInstance,
|
|
74
|
-
localePathRedirect,
|
|
75
|
-
languages,
|
|
76
|
-
location?.pathname,
|
|
77
|
-
prevLangRef,
|
|
78
|
-
setLang,
|
|
79
|
-
);
|
|
80
|
-
|
|
81
109
|
// Handle client-side redirect for static deployments.
|
|
82
110
|
useClientSideRedirect(
|
|
83
111
|
i18nInstance,
|
|
@@ -85,7 +113,7 @@ export const createI18nRootWrapper =
|
|
|
85
113
|
languages,
|
|
86
114
|
fallbackLanguage,
|
|
87
115
|
ignoreRedirectRoutes,
|
|
88
|
-
|
|
116
|
+
urlStrategy,
|
|
89
117
|
);
|
|
90
118
|
|
|
91
119
|
const contextValue = useMemo(
|
|
@@ -97,9 +125,8 @@ export const createI18nRootWrapper =
|
|
|
97
125
|
languages,
|
|
98
126
|
localePathRedirect,
|
|
99
127
|
ignoreRedirectRoutes,
|
|
100
|
-
localisedUrls,
|
|
101
128
|
setLang,
|
|
102
|
-
|
|
129
|
+
urlStrategy,
|
|
103
130
|
),
|
|
104
131
|
[
|
|
105
132
|
lang,
|
|
@@ -108,9 +135,8 @@ export const createI18nRootWrapper =
|
|
|
108
135
|
languages,
|
|
109
136
|
localePathRedirect,
|
|
110
137
|
ignoreRedirectRoutes,
|
|
111
|
-
|
|
138
|
+
urlStrategy,
|
|
112
139
|
forceUpdate,
|
|
113
|
-
synchronizeLanguage,
|
|
114
140
|
],
|
|
115
141
|
);
|
|
116
142
|
const I18nextProvider = getI18nextProvider();
|
|
@@ -140,13 +166,35 @@ export const createI18nRootWrapper =
|
|
|
140
166
|
return (
|
|
141
167
|
<>
|
|
142
168
|
{Boolean(htmlLangAttr) && <Helmet htmlAttributes={{ lang }} />}
|
|
143
|
-
<
|
|
144
|
-
|
|
145
|
-
|
|
169
|
+
<LanguageSynchronization
|
|
170
|
+
i18nInstance={i18nInstance}
|
|
171
|
+
localePathRedirect={localePathRedirect}
|
|
172
|
+
languages={languages}
|
|
173
|
+
pathname={location?.pathname}
|
|
174
|
+
prevLangRef={prevLangRef}
|
|
175
|
+
setLang={setLang}
|
|
146
176
|
>
|
|
147
|
-
{
|
|
148
|
-
|
|
177
|
+
{synchronizeLanguage => (
|
|
178
|
+
<ModernI18nProvider
|
|
179
|
+
i18nextProvider={I18nextProvider}
|
|
180
|
+
value={{ ...contextValue, synchronizeLanguage }}
|
|
181
|
+
>
|
|
182
|
+
{appContent}
|
|
183
|
+
</ModernI18nProvider>
|
|
184
|
+
)}
|
|
185
|
+
</LanguageSynchronization>
|
|
149
186
|
</>
|
|
150
187
|
);
|
|
151
188
|
};
|
|
189
|
+
const { NavigationProvider } = options;
|
|
190
|
+
if (!NavigationProvider) {
|
|
191
|
+
return I18nRoot;
|
|
192
|
+
}
|
|
193
|
+
return function I18nRootWithNavigation(props: Record<string, unknown>) {
|
|
194
|
+
return (
|
|
195
|
+
<NavigationProvider>
|
|
196
|
+
<I18nRoot {...props} />
|
|
197
|
+
</NavigationProvider>
|
|
198
|
+
);
|
|
199
|
+
};
|
|
152
200
|
};
|