@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.
Files changed (79) hide show
  1. package/dist/cjs/cli/index.js +0 -22
  2. package/dist/cjs/runtime/Link.js +19 -32
  3. package/dist/cjs/runtime/context.js +26 -61
  4. package/dist/cjs/runtime/contextHelpers.js +5 -5
  5. package/dist/cjs/runtime/core.js +17 -14
  6. package/dist/cjs/runtime/hooks.js +7 -8
  7. package/dist/cjs/runtime/localizedPaths.js +11 -9
  8. package/dist/cjs/runtime/providerComposition.js +37 -13
  9. package/dist/cjs/runtime/routerAdapter.js +35 -140
  10. package/dist/cjs/runtime/utils.js +17 -19
  11. package/dist/cjs/server/index.js +10 -7
  12. package/dist/cjs/server/redirectPolicy.js +36 -31
  13. package/dist/cjs/shared/urlStrategy.js +18 -0
  14. package/dist/esm/cli/index.mjs +0 -22
  15. package/dist/esm/runtime/Link.mjs +19 -32
  16. package/dist/esm/runtime/context.mjs +18 -62
  17. package/dist/esm/runtime/contextHelpers.mjs +5 -5
  18. package/dist/esm/runtime/core.mjs +8 -5
  19. package/dist/esm/runtime/hooks.mjs +7 -8
  20. package/dist/esm/runtime/localizedPaths.mjs +11 -9
  21. package/dist/esm/runtime/providerComposition.mjs +38 -14
  22. package/dist/esm/runtime/routerAdapter.mjs +30 -141
  23. package/dist/esm/runtime/utils.mjs +15 -17
  24. package/dist/esm/server/index.mjs +10 -7
  25. package/dist/esm/server/redirectPolicy.mjs +29 -24
  26. package/dist/esm/shared/urlStrategy.mjs +0 -0
  27. package/dist/esm-node/cli/index.mjs +0 -22
  28. package/dist/esm-node/runtime/Link.mjs +19 -32
  29. package/dist/esm-node/runtime/context.mjs +18 -62
  30. package/dist/esm-node/runtime/contextHelpers.mjs +5 -5
  31. package/dist/esm-node/runtime/core.mjs +8 -5
  32. package/dist/esm-node/runtime/hooks.mjs +7 -8
  33. package/dist/esm-node/runtime/localizedPaths.mjs +11 -9
  34. package/dist/esm-node/runtime/providerComposition.mjs +38 -14
  35. package/dist/esm-node/runtime/routerAdapter.mjs +30 -141
  36. package/dist/esm-node/runtime/utils.mjs +15 -17
  37. package/dist/esm-node/server/index.mjs +10 -7
  38. package/dist/esm-node/server/redirectPolicy.mjs +29 -24
  39. package/dist/esm-node/shared/urlStrategy.mjs +1 -0
  40. package/dist/types/runtime/context.d.ts +8 -11
  41. package/dist/types/runtime/contextHelpers.d.ts +2 -2
  42. package/dist/types/runtime/core.d.ts +11 -2
  43. package/dist/types/runtime/hooks.d.ts +4 -5
  44. package/dist/types/runtime/localizedPaths.d.ts +4 -4
  45. package/dist/types/runtime/providerComposition.d.ts +13 -1
  46. package/dist/types/runtime/routerAdapter.d.ts +23 -6
  47. package/dist/types/runtime/utils.d.ts +4 -12
  48. package/dist/types/server/index.d.ts +2 -0
  49. package/dist/types/server/redirectPolicy.d.ts +5 -13
  50. package/dist/types/shared/type.d.ts +0 -14
  51. package/dist/types/shared/urlStrategy.d.ts +7 -0
  52. package/package.json +21 -11
  53. package/rstest.config.mts +2 -8
  54. package/src/cli/index.ts +1 -43
  55. package/src/runtime/Link.tsx +20 -40
  56. package/src/runtime/context.tsx +34 -133
  57. package/src/runtime/contextHelpers.ts +7 -5
  58. package/src/runtime/core.tsx +26 -6
  59. package/src/runtime/hooks.ts +14 -9
  60. package/src/runtime/localizedPaths.ts +24 -19
  61. package/src/runtime/providerComposition.tsx +71 -23
  62. package/src/runtime/routerAdapter.tsx +73 -338
  63. package/src/runtime/utils.ts +40 -31
  64. package/src/server/index.ts +44 -9
  65. package/src/server/redirectPolicy.ts +70 -70
  66. package/src/shared/type.ts +0 -14
  67. package/src/shared/urlStrategy.ts +11 -0
  68. package/tests/federatedI18nBoundaryResolver.test.tsx +71 -0
  69. package/tests/i18nUtils.test.ts +31 -65
  70. package/tests/link.test.tsx +13 -511
  71. package/tests/linkTypes.test.ts +12 -3
  72. package/tests/localisedUrlRewriteMatrix.fork.test.ts +4 -96
  73. package/tests/localisedUrls.test.ts +7 -216
  74. package/tests/reactI18nextRuntimeBoundary.test.ts +1 -82
  75. package/tests/redirectPolicy.test.ts +39 -30
  76. package/tests/routerAdapter.test.tsx +95 -1055
  77. package/tests/federatedI18nBoundary.client.test.tsx +0 -129
  78. package/tests/federatedI18nBoundary.test.tsx +0 -132
  79. package/tests/peerCohort.test.ts +0 -25
@@ -31,7 +31,6 @@ __webpack_require__.d(__webpack_exports__, {
31
31
  default: ()=>cli,
32
32
  i18nPlugin: ()=>i18nPlugin
33
33
  });
34
- const i18n_runtime_extensions_namespaceObject = require("@modern-js/i18n-runtime-extensions");
35
34
  const server_core_namespaceObject = require("@modern-js/server-core");
36
35
  const utils_js_namespaceObject = require("../shared/utils.js");
37
36
  const external_locales_js_namespaceObject = require("./locales.js");
@@ -76,27 +75,6 @@ const i18nPlugin = (options = {})=>({
76
75
  plugins
77
76
  };
78
77
  });
79
- api.modifyFileSystemRoutes(({ entrypoint, routes })=>{
80
- if (!localeDetection) return {
81
- entrypoint,
82
- routes
83
- };
84
- const localeDetectionOptions = (0, utils_js_namespaceObject.getLocaleDetectionOptions)(entrypoint.entryName, localeDetection);
85
- const { localePathRedirect, languages = [], localisedUrls } = localeDetectionOptions;
86
- if (!localePathRedirect || 0 === languages.length) return {
87
- entrypoint,
88
- routes
89
- };
90
- const localisedUrlsConfig = (0, i18n_runtime_extensions_namespaceObject.resolveLocalisedUrlsConfig)(localisedUrls);
91
- if (!localisedUrlsConfig.enabled) return {
92
- entrypoint,
93
- routes
94
- };
95
- return {
96
- entrypoint,
97
- routes: (0, i18n_runtime_extensions_namespaceObject.applyLocalisedUrlsToRoutes)(routes, languages, localisedUrlsConfig.map)
98
- };
99
- });
100
78
  api._internalServerPlugins(({ plugins })=>{
101
79
  const { serverRoutes, metaName } = api.getAppContext();
102
80
  const normalizedConfig = api.getNormalizedConfig();
@@ -43,10 +43,10 @@ const EXTERNAL_TARGET_RE = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
43
43
  const Link = (props)=>{
44
44
  const { to, params, children, hash: hashProp, search: searchProp, hashScrollIntoView, activeOptions, activeProps, prefetch, preload, ...rest } = props;
45
45
  const adapter = (0, external_routerAdapter_js_namespaceObject.useI18nRouterAdapter)();
46
- const { language, supportedLanguages, localisedUrls } = (0, external_context_js_namespaceObject.useModernI18n)();
46
+ const { language, supportedLanguages, urlStrategy } = (0, external_context_js_namespaceObject.useModernI18n)();
47
47
  const config = {
48
48
  languages: supportedLanguages,
49
- localisedUrls
49
+ urlStrategy
50
50
  };
51
51
  const isExternal = EXTERNAL_TARGET_RE.test(to);
52
52
  const isBareHash = to.startsWith('#');
@@ -56,7 +56,7 @@ const Link = (props)=>{
56
56
  const interpolated = (0, external_linkHelpers_js_namespaceObject.interpolateRouteParams)(pathname || '/', params);
57
57
  const firstSegment = interpolated.split('/').filter(Boolean)[0];
58
58
  if (firstSegment && supportedLanguages.includes(firstSegment)) (0, external_linkHelpers_js_namespaceObject.warnOnce)(`lang-prefix:${to}`, `[plugin-i18n] <Link to="${to}"> starts with a language prefix. Write language-agnostic canonical paths; the Link localizes them automatically.`);
59
- const localizedPathname = (0, external_utils_js_namespaceObject.buildLocalizedUrl)(interpolated, language, supportedLanguages, localisedUrls);
59
+ const localizedPathname = (0, external_utils_js_namespaceObject.buildLocalizedUrl)(interpolated, language, supportedLanguages, urlStrategy);
60
60
  const hash = hashProp ?? (hashFromTo ? hashFromTo.slice(1) : '');
61
61
  const { searchString, searchObject } = (0, external_linkHelpers_js_namespaceObject.normalizeSearch)(searchProp, searchFromTo);
62
62
  return {
@@ -76,7 +76,7 @@ const Link = (props)=>{
76
76
  isBareHash,
77
77
  language,
78
78
  supportedLanguages,
79
- localisedUrls
79
+ urlStrategy
80
80
  ]);
81
81
  const isActive = (0, external_react_namespaceObject.useMemo)(()=>{
82
82
  if (!target || !adapter.location) return false;
@@ -91,7 +91,7 @@ const Link = (props)=>{
91
91
  adapter.location,
92
92
  activeOptions?.exact,
93
93
  supportedLanguages,
94
- localisedUrls
94
+ urlStrategy
95
95
  ]);
96
96
  const resolvedActiveProps = (0, external_linkHelpers_js_namespaceObject.splitActiveProps)(isActive, activeProps);
97
97
  const activeAttributes = isActive ? {
@@ -106,7 +106,7 @@ const Link = (props)=>{
106
106
  children: children
107
107
  });
108
108
  }
109
- const { Link: RouterLink, hasRouter, framework } = adapter;
109
+ const { Link: RouterLink, hasRouter } = adapter;
110
110
  if (!hasRouter || !RouterLink) {
111
111
  const { replace: _replace, ...anchorProps } = rest;
112
112
  const { className: activeClassName, style: activeStyle, ...activeRest } = resolvedActiveProps;
@@ -129,38 +129,25 @@ const Link = (props)=>{
129
129
  ...rest.style,
130
130
  ...activeStyle
131
131
  };
132
- if ('tanstack' === framework) {
133
- const tanstackPreload = void 0 !== preload ? preload : void 0 === prefetch ? void 0 : 'none' === prefetch ? false : prefetch;
134
- return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(RouterLink, {
135
- to: target.localizedPathname,
136
- ...target.searchObject ? {
137
- search: target.searchObject
138
- } : {},
139
- ...target.hash ? {
140
- hash: target.hash
141
- } : {},
142
- ...void 0 === hashScrollIntoView ? {} : {
143
- hashScrollIntoView
144
- },
145
- ...void 0 === tanstackPreload ? {} : {
146
- preload: tanstackPreload
147
- },
148
- ...rest,
149
- ...activeRest,
150
- ...activeAttributes,
151
- className: mergedClassName,
152
- style: mergedStyle,
153
- children: children
154
- });
155
- }
156
- return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(RouterLink, {
132
+ const routerProps = adapter.createLinkProps?.({
133
+ pathname: target.localizedPathname,
134
+ href: target.href,
135
+ search: target.searchObject,
136
+ hash: target.hash,
137
+ hashScrollIntoView,
138
+ prefetch,
139
+ preload
140
+ }) ?? {
157
141
  to: target.href,
158
142
  ...void 0 === prefetch ? {} : {
159
143
  prefetch
160
144
  },
161
145
  ...void 0 === preload ? {} : {
162
146
  preload
163
- },
147
+ }
148
+ };
149
+ return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(RouterLink, {
150
+ ...routerProps,
164
151
  ...rest,
165
152
  ...activeRest,
166
153
  ...activeAttributes,
@@ -29,14 +29,18 @@ var __webpack_exports__ = {};
29
29
  __webpack_require__.r(__webpack_exports__);
30
30
  __webpack_require__.d(__webpack_exports__, {
31
31
  FederatedI18nBoundary: ()=>FederatedI18nBoundary,
32
+ ModernI18nContext: ()=>ModernI18nContext,
32
33
  ModernI18nProvider: ()=>ModernI18nProvider,
34
+ ReactI18nextProviderContext: ()=>ReactI18nextProviderContext,
35
+ getActualI18nextInstance: ()=>instance_js_namespaceObject.getActualI18nextInstance,
33
36
  useModernI18n: ()=>useModernI18n
34
37
  });
35
38
  const jsx_runtime_namespaceObject = require("react/jsx-runtime");
39
+ const context_namespaceObject = require("@modern-js/runtime/context");
36
40
  const external_react_namespaceObject = require("react");
37
41
  const external_contextHelpers_js_namespaceObject = require("./contextHelpers.js");
38
- const instance_js_namespaceObject = require("./i18n/instance.js");
39
42
  const external_routerAdapter_js_namespaceObject = require("./routerAdapter.js");
43
+ const instance_js_namespaceObject = require("./i18n/instance.js");
40
44
  const modernI18nContextKey = Symbol.for('@modern-js/plugin-i18n/runtime/ModernI18nContext');
41
45
  const reactI18nextProviderContextKey = Symbol.for('@modern-js/plugin-i18n/runtime/ReactI18nextProviderContext');
42
46
  const getGlobalContext = (key, defaultValue)=>{
@@ -56,68 +60,23 @@ const ModernI18nProvider = ({ children, i18nextProvider, value })=>{
56
60
  children: content
57
61
  });
58
62
  };
59
- const FederatedI18nBoundary = ({ children, defaultNamespace, fallbackLanguage, resources, supportedLanguages })=>{
60
- const parent = (0, external_react_namespaceObject.useContext)(ModernI18nContext);
61
- const I18nextProvider = (0, external_react_namespaceObject.useContext)(ReactI18nextProviderContext);
62
- if (!parent) throw new Error('FederatedI18nBoundary must be used within ModernI18nProvider');
63
- const languages = supportedLanguages ?? parent.languages ?? Object.keys(resources);
64
- const scopedInstance = (0, external_react_namespaceObject.useMemo)(()=>{
65
- const parentInstance = (0, instance_js_namespaceObject.getActualI18nextInstance)(parent.i18nInstance);
66
- const clone = parentInstance.cloneInstance?.({
67
- defaultNS: defaultNamespace,
68
- fallbackLng: fallbackLanguage ?? languages[0] ?? parent.language,
69
- forkResourceStore: true,
70
- initImmediate: false,
71
- lng: parent.language,
72
- ns: [
73
- defaultNamespace
74
- ],
75
- resources,
76
- supportedLngs: languages
77
- });
78
- if (!clone) throw new Error('FederatedI18nBoundary requires an i18n instance with cloneInstance support');
79
- const resourceStore = clone.store;
80
- const parentResourceStore = parentInstance.store;
81
- const sharesNestedResourceState = Object.entries(resourceStore?.data ?? {}).some(([language, namespaces])=>{
82
- const parentNamespaces = parentResourceStore?.data?.[language];
83
- return namespaces === parentNamespaces || Object.entries(namespaces).some(([namespace, resource])=>null !== resource && 'object' == typeof resource && resource === parentNamespaces?.[namespace]);
84
- });
85
- if (clone === parentInstance || resourceStore === parentResourceStore || resourceStore?.data === parentResourceStore?.data || sharesNestedResourceState) throw new Error('FederatedI18nBoundary cloneInstance did not isolate the host resource store');
86
- if (!resourceStore?.addResourceBundle || !clone.removeResourceBundle || !resourceStore.data) throw new Error('FederatedI18nBoundary requires an isolated mutable i18n resource store');
87
- for (const [language, namespaces] of Object.entries(resourceStore.data))for (const namespace of Object.keys(namespaces))clone.removeResourceBundle(language, namespace);
88
- for (const [language, namespaces] of Object.entries(resources))for (const [namespace, resource] of Object.entries(namespaces))resourceStore.addResourceBundle(language, namespace, resource, true, true);
89
- return clone;
90
- }, [
91
- defaultNamespace,
92
- fallbackLanguage,
93
- languages,
94
- parent.i18nInstance,
95
- parent.language,
96
- resources
97
- ]);
98
- const value = (0, external_react_namespaceObject.useMemo)(()=>({
99
- ...parent,
100
- i18nInstance: scopedInstance,
101
- language: parent.language,
102
- languages
103
- }), [
104
- languages,
105
- parent,
106
- scopedInstance
107
- ]);
108
- const scopedContent = /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(ModernI18nProvider, {
109
- value: value,
110
- children: children
63
+ const MissingFederatedI18nBoundary = ()=>{
64
+ throw new Error('FederatedI18nBoundary requires the @modern-js/i18n-integration runtime plugin');
65
+ };
66
+ const FederatedI18nBoundary = (props)=>{
67
+ const resolveComponent = (0, external_react_namespaceObject.useContext)(context_namespaceObject.RuntimeComponentResolverContext);
68
+ const Boundary = resolveComponent?.(MissingFederatedI18nBoundary, {
69
+ name: 'i18n.FederatedI18nBoundary'
70
+ }) ?? MissingFederatedI18nBoundary;
71
+ if (Boundary === FederatedI18nBoundary) throw new Error('FederatedI18nBoundary resolver returned its own wrapper');
72
+ return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(Boundary, {
73
+ ...props
111
74
  });
112
- return I18nextProvider ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(I18nextProvider, {
113
- i18n: scopedInstance,
114
- children: scopedContent
115
- }) : scopedContent;
116
75
  };
117
76
  const useModernI18n = ()=>{
118
77
  const context = (0, external_react_namespaceObject.useContext)(ModernI18nContext);
119
78
  if (!context) throw new Error('useModernI18n must be used within ModernI18nProvider');
120
- const { language: contextLanguage, i18nInstance, languages, localePathRedirect, ignoreRedirectRoutes, localisedUrls, updateLanguage, synchronizeLanguage } = context;
79
+ const { language: contextLanguage, i18nInstance, languages, localePathRedirect, ignoreRedirectRoutes, urlStrategy, updateLanguage, synchronizeLanguage } = context;
121
80
  const { navigate, location, hasRouter } = (0, external_routerAdapter_js_namespaceObject.useI18nRouterAdapter)();
122
81
  const pathLanguage = (0, external_react_namespaceObject.useMemo)(()=>(0, external_contextHelpers_js_namespaceObject.getPathLanguage)(location?.pathname, languages, localePathRedirect), [
123
82
  languages,
@@ -136,7 +95,7 @@ const useModernI18n = ()=>{
136
95
  updateLanguage,
137
96
  localePathRedirect,
138
97
  ignoreRedirectRoutes,
139
- localisedUrls,
98
+ urlStrategy,
140
99
  languages,
141
100
  hasRouter,
142
101
  navigate,
@@ -146,7 +105,7 @@ const useModernI18n = ()=>{
146
105
  updateLanguage,
147
106
  localePathRedirect,
148
107
  ignoreRedirectRoutes,
149
- localisedUrls,
108
+ urlStrategy,
150
109
  languages,
151
110
  hasRouter,
152
111
  navigate,
@@ -169,17 +128,23 @@ const useModernI18n = ()=>{
169
128
  t,
170
129
  i18nInstance: i18nInstance,
171
130
  supportedLanguages: languages || [],
172
- localisedUrls,
131
+ urlStrategy,
173
132
  isLanguageSupported,
174
133
  isResourcesReady
175
134
  };
176
135
  };
177
136
  exports.FederatedI18nBoundary = __webpack_exports__.FederatedI18nBoundary;
137
+ exports.ModernI18nContext = __webpack_exports__.ModernI18nContext;
178
138
  exports.ModernI18nProvider = __webpack_exports__.ModernI18nProvider;
139
+ exports.ReactI18nextProviderContext = __webpack_exports__.ReactI18nextProviderContext;
140
+ exports.getActualI18nextInstance = __webpack_exports__.getActualI18nextInstance;
179
141
  exports.useModernI18n = __webpack_exports__.useModernI18n;
180
142
  for(var __rspack_i in __webpack_exports__)if (-1 === [
181
143
  "FederatedI18nBoundary",
144
+ "ModernI18nContext",
182
145
  "ModernI18nProvider",
146
+ "ReactI18nextProviderContext",
147
+ "getActualI18nextInstance",
183
148
  "useModernI18n"
184
149
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
185
150
  Object.defineProperty(exports, '__esModule', {
@@ -55,7 +55,7 @@ async function changeI18nInstanceLanguage(i18nInstance, language) {
55
55
  else await i18nInstance.changeLanguage?.(language);
56
56
  }
57
57
  async function changeModernI18nLanguage(newLang, options) {
58
- const { i18nInstance, updateLanguage, localePathRedirect, ignoreRedirectRoutes, localisedUrls, languages, hasRouter, navigate, location } = options;
58
+ const { i18nInstance, updateLanguage, localePathRedirect, ignoreRedirectRoutes, urlStrategy, languages, hasRouter, navigate, location } = options;
59
59
  try {
60
60
  if (!newLang || 'string' != typeof newLang) throw new Error('Language must be non-empty string');
61
61
  await changeI18nInstanceLanguage(i18nInstance, newLang);
@@ -66,8 +66,8 @@ async function changeModernI18nLanguage(newLang, options) {
66
66
  const relativePath = currentPath.replace(entryPath, '');
67
67
  const pathLanguage = (0, external_utils_js_namespaceObject.detectLanguageFromPath)(currentPath, languages || [], localePathRedirect);
68
68
  if (pathLanguage.detected && pathLanguage.language === newLang) return void updateLanguage?.(newLang);
69
- if (!(0, external_utils_js_namespaceObject.shouldIgnoreRedirect)(relativePath, languages || [], ignoreRedirectRoutes)) {
70
- const newPath = (0, external_utils_js_namespaceObject.buildLocalizedUrl)(relativePath, newLang, languages || [], localisedUrls);
69
+ if (!(0, external_utils_js_namespaceObject.shouldIgnoreRedirect)(relativePath, languages || [], ignoreRedirectRoutes, urlStrategy)) {
70
+ const newPath = (0, external_utils_js_namespaceObject.buildLocalizedUrl)(relativePath, newLang, languages || [], urlStrategy);
71
71
  const newUrl = entryPath + newPath + location.search + location.hash;
72
72
  await navigate(newUrl, {
73
73
  replace: true
@@ -79,8 +79,8 @@ async function changeModernI18nLanguage(newLang, options) {
79
79
  const relativePath = currentPath.replace(entryPath, '');
80
80
  const pathLanguage = (0, external_utils_js_namespaceObject.detectLanguageFromPath)(currentPath, languages || [], localePathRedirect);
81
81
  if (pathLanguage.detected && pathLanguage.language === newLang) return void updateLanguage?.(newLang);
82
- if (!(0, external_utils_js_namespaceObject.shouldIgnoreRedirect)(relativePath, languages || [], ignoreRedirectRoutes)) {
83
- const newPath = (0, external_utils_js_namespaceObject.buildLocalizedUrl)(relativePath, newLang, languages || [], localisedUrls);
82
+ if (!(0, external_utils_js_namespaceObject.shouldIgnoreRedirect)(relativePath, languages || [], ignoreRedirectRoutes, urlStrategy)) {
83
+ const newPath = (0, external_utils_js_namespaceObject.buildLocalizedUrl)(relativePath, newLang, languages || [], urlStrategy);
84
84
  const newUrl = entryPath + newPath + window.location.search + window.location.hash;
85
85
  window.history.pushState(null, '', newUrl);
86
86
  }
@@ -30,20 +30,21 @@ __webpack_require__.r(__webpack_exports__);
30
30
  __webpack_require__.d(__webpack_exports__, {
31
31
  FederatedI18nBoundary: ()=>external_context_js_namespaceObject.FederatedI18nBoundary,
32
32
  I18nLink: ()=>external_I18nLink_js_namespaceObject.I18nLink,
33
+ I18nNavigationProvider: ()=>external_routerAdapter_js_namespaceObject.I18nNavigationProvider,
33
34
  Link: ()=>external_Link_js_namespaceObject.Link,
34
- buildLocalizedUrl: ()=>external_utils_js_namespaceObject.buildLocalizedUrl,
35
- canonicalPath: ()=>external_localizedPaths_js_namespaceObject.canonicalPath,
36
35
  createI18nPlugin: ()=>createI18nPlugin,
37
- localizePath: ()=>external_localizedPaths_js_namespaceObject.localizePath,
38
36
  splitUrlTarget: ()=>external_utils_js_namespaceObject.splitUrlTarget,
37
+ useI18nRouterAdapter: ()=>external_routerAdapter_js_namespaceObject.useI18nRouterAdapter,
39
38
  useLocalizedLocation: ()=>external_localizedPaths_js_namespaceObject.useLocalizedLocation,
40
39
  useLocalizedPaths: ()=>external_localizedPaths_js_namespaceObject.useLocalizedPaths,
41
- useModernI18n: ()=>external_context_js_namespaceObject.useModernI18n
40
+ useModernI18n: ()=>external_context_js_namespaceObject.useModernI18n,
41
+ useNativeI18nRouterAdapter: ()=>external_routerAdapter_js_namespaceObject.useNativeI18nRouterAdapter
42
42
  });
43
43
  const external_pluginSetup_js_namespaceObject = require("./pluginSetup.js");
44
44
  const external_providerComposition_js_namespaceObject = require("./providerComposition.js");
45
45
  const external_reactI18next_js_namespaceObject = require("./reactI18next.js");
46
46
  require("./types.js");
47
+ const external_routerAdapter_js_namespaceObject = require("./routerAdapter.js");
47
48
  const external_context_js_namespaceObject = require("./context.js");
48
49
  const external_I18nLink_js_namespaceObject = require("./I18nLink.js");
49
50
  const external_Link_js_namespaceObject = require("./Link.js");
@@ -52,8 +53,8 @@ const external_utils_js_namespaceObject = require("./utils.js");
52
53
  const createI18nPlugin = (loadReactI18nextIntegration)=>(options)=>({
53
54
  name: '@modern-js/plugin-i18n',
54
55
  setup: (api)=>{
55
- const { entryName, i18nInstance: userI18nInstance, initOptions, localeDetection, backend, htmlLangAttr = false, reactI18next = true } = options;
56
- const { localePathRedirect = false, i18nextDetector = true, languages = [], fallbackLanguage = 'en', detection, ignoreRedirectRoutes, localisedUrls } = localeDetection || {};
56
+ const { entryName, i18nInstance: userI18nInstance, initOptions, localeDetection, backend, htmlLangAttr = false, reactI18next = true, urlStrategy, NavigationProvider, LanguageSynchronization } = options;
57
+ const { localePathRedirect = false, i18nextDetector = true, languages = [], fallbackLanguage = 'en', detection, ignoreRedirectRoutes } = localeDetection || {};
57
58
  const { enabled: backendEnabled = false } = backend || {};
58
59
  let latestI18nInstance;
59
60
  let I18nextProvider;
@@ -82,7 +83,9 @@ const createI18nPlugin = (loadReactI18nextIntegration)=>(options)=>({
82
83
  languages,
83
84
  fallbackLanguage,
84
85
  ignoreRedirectRoutes,
85
- localisedUrls,
86
+ urlStrategy,
87
+ NavigationProvider,
88
+ LanguageSynchronization,
86
89
  getLatestI18nInstance: ()=>latestI18nInstance,
87
90
  getI18nextProvider: ()=>I18nextProvider
88
91
  }));
@@ -90,27 +93,27 @@ const createI18nPlugin = (loadReactI18nextIntegration)=>(options)=>({
90
93
  });
91
94
  exports.FederatedI18nBoundary = __webpack_exports__.FederatedI18nBoundary;
92
95
  exports.I18nLink = __webpack_exports__.I18nLink;
96
+ exports.I18nNavigationProvider = __webpack_exports__.I18nNavigationProvider;
93
97
  exports.Link = __webpack_exports__.Link;
94
- exports.buildLocalizedUrl = __webpack_exports__.buildLocalizedUrl;
95
- exports.canonicalPath = __webpack_exports__.canonicalPath;
96
98
  exports.createI18nPlugin = __webpack_exports__.createI18nPlugin;
97
- exports.localizePath = __webpack_exports__.localizePath;
98
99
  exports.splitUrlTarget = __webpack_exports__.splitUrlTarget;
100
+ exports.useI18nRouterAdapter = __webpack_exports__.useI18nRouterAdapter;
99
101
  exports.useLocalizedLocation = __webpack_exports__.useLocalizedLocation;
100
102
  exports.useLocalizedPaths = __webpack_exports__.useLocalizedPaths;
101
103
  exports.useModernI18n = __webpack_exports__.useModernI18n;
104
+ exports.useNativeI18nRouterAdapter = __webpack_exports__.useNativeI18nRouterAdapter;
102
105
  for(var __rspack_i in __webpack_exports__)if (-1 === [
103
106
  "FederatedI18nBoundary",
104
107
  "I18nLink",
108
+ "I18nNavigationProvider",
105
109
  "Link",
106
- "buildLocalizedUrl",
107
- "canonicalPath",
108
110
  "createI18nPlugin",
109
- "localizePath",
110
111
  "splitUrlTarget",
112
+ "useI18nRouterAdapter",
111
113
  "useLocalizedLocation",
112
114
  "useLocalizedPaths",
113
- "useModernI18n"
115
+ "useModernI18n",
116
+ "useNativeI18nRouterAdapter"
114
117
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
115
118
  Object.defineProperty(exports, '__esModule', {
116
119
  value: true
@@ -53,7 +53,7 @@ function createMinimalI18nInstance(language) {
53
53
  };
54
54
  return minimalInstance;
55
55
  }
56
- function createContextValue(lang, i18nInstance, entryName, languages, localePathRedirect, ignoreRedirectRoutes, localisedUrls, setLang, synchronizeLanguage) {
56
+ function createContextValue(lang, i18nInstance, entryName, languages, localePathRedirect, ignoreRedirectRoutes, setLang, urlStrategy) {
57
57
  const instance = i18nInstance || createMinimalI18nInstance(lang);
58
58
  return {
59
59
  language: lang,
@@ -62,9 +62,8 @@ function createContextValue(lang, i18nInstance, entryName, languages, localePath
62
62
  languages,
63
63
  localePathRedirect,
64
64
  ignoreRedirectRoutes,
65
- localisedUrls,
66
- updateLanguage: setLang,
67
- synchronizeLanguage
65
+ urlStrategy,
66
+ updateLanguage: setLang
68
67
  };
69
68
  }
70
69
  function useSdkResourcesLoader(i18nInstance, setForceUpdate) {
@@ -113,7 +112,7 @@ function useSdkResourcesLoader(i18nInstance, setForceUpdate) {
113
112
  setForceUpdate
114
113
  ]);
115
114
  }
116
- function useClientSideRedirect(i18nInstance, localePathRedirect, languages, fallbackLanguage, ignoreRedirectRoutes, localisedUrls) {
115
+ function useClientSideRedirect(i18nInstance, localePathRedirect, languages, fallbackLanguage, ignoreRedirectRoutes, urlStrategy) {
117
116
  const urlRef = (0, external_react_namespaceObject.useRef)('');
118
117
  const { navigate, location, hasRouter } = (0, external_routerAdapter_js_namespaceObject.useI18nRouterAdapter)();
119
118
  (0, external_react_namespaceObject.useEffect)(()=>{
@@ -130,10 +129,10 @@ function useClientSideRedirect(i18nInstance, localePathRedirect, languages, fall
130
129
  const currentHash = hasRouter && location ? location.hash : window.location.hash;
131
130
  const entryPath = (0, external_utils_js_namespaceObject.getEntryPath)();
132
131
  const relativePath = currentPathname.replace(entryPath, '');
133
- if ((0, external_utils_js_namespaceObject.shouldIgnoreRedirect)(relativePath, languages, ignoreRedirectRoutes)) return;
132
+ if ((0, external_utils_js_namespaceObject.shouldIgnoreRedirect)(relativePath, languages, ignoreRedirectRoutes, urlStrategy)) return;
134
133
  const pathDetection = (0, external_utils_js_namespaceObject.detectLanguageFromPath)(currentPathname, languages, localePathRedirect);
135
134
  const targetLanguage = pathDetection.language || i18nInstance.language || fallbackLanguage || languages[0] || 'en';
136
- const newPath = (0, external_utils_js_namespaceObject.buildLocalizedUrl)(relativePath, targetLanguage, languages, localisedUrls);
135
+ const newPath = (0, external_utils_js_namespaceObject.buildLocalizedUrl)(relativePath, targetLanguage, languages, urlStrategy);
137
136
  const newUrl = entryPath + newPath + currentSearch + currentHash;
138
137
  urlRef.current = currentPathname;
139
138
  if (newUrl !== currentPathname + currentSearch + currentHash) if (hasRouter && navigate && location) navigate(newUrl, {
@@ -149,7 +148,7 @@ function useClientSideRedirect(i18nInstance, localePathRedirect, languages, fall
149
148
  languages,
150
149
  fallbackLanguage,
151
150
  ignoreRedirectRoutes,
152
- localisedUrls
151
+ urlStrategy
153
152
  ]);
154
153
  }
155
154
  function useLanguageSync(i18nInstance, localePathRedirect, languages, pathname, prevLangRef, setLang) {
@@ -33,23 +33,25 @@ __webpack_require__.d(__webpack_exports__, {
33
33
  useLocalizedLocation: ()=>useLocalizedLocation,
34
34
  useLocalizedPaths: ()=>useLocalizedPaths
35
35
  });
36
- const i18n_runtime_extensions_namespaceObject = require("@modern-js/i18n-runtime-extensions");
37
36
  const external_react_namespaceObject = require("react");
38
37
  const external_context_js_namespaceObject = require("./context.js");
39
38
  const external_routerAdapter_js_namespaceObject = require("./routerAdapter.js");
40
39
  const external_utils_js_namespaceObject = require("./utils.js");
41
- const localizePath = (pathname, language, config)=>(0, external_utils_js_namespaceObject.buildLocalizedUrl)(pathname, language, config.languages, config.localisedUrls);
40
+ const localizePath = (pathname, language, config)=>(0, external_utils_js_namespaceObject.buildLocalizedUrl)(pathname, language, config.languages, config.urlStrategy);
42
41
  const canonicalPath = (target, config)=>{
43
42
  const { pathname, search, hash } = (0, external_utils_js_namespaceObject.splitUrlTarget)(target);
44
- const resolvedPath = (0, i18n_runtime_extensions_namespaceObject.canonicalTargetPathname)(pathname, config.languages, config.localisedUrls);
43
+ if (config.urlStrategy) return `${config.urlStrategy.canonicalPathname(pathname, config.languages)}${search}${hash}`;
44
+ const segments = pathname.split('/').filter(Boolean);
45
+ if (segments[0] && config.languages.some((language)=>language.toLowerCase() === segments[0].toLowerCase())) segments.shift();
46
+ const resolvedPath = `/${segments.join('/')}`;
45
47
  return `${resolvedPath}${search}${hash}`;
46
48
  };
47
49
  const useLocalizedPaths = ()=>{
48
- const { supportedLanguages, localisedUrls } = (0, external_context_js_namespaceObject.useModernI18n)();
50
+ const { supportedLanguages, urlStrategy } = (0, external_context_js_namespaceObject.useModernI18n)();
49
51
  return (0, external_react_namespaceObject.useMemo)(()=>{
50
52
  const config = {
51
53
  languages: supportedLanguages,
52
- localisedUrls
54
+ urlStrategy
53
55
  };
54
56
  return {
55
57
  localizePath: (pathname, language)=>localizePath(pathname, language, config),
@@ -57,11 +59,11 @@ const useLocalizedPaths = ()=>{
57
59
  };
58
60
  }, [
59
61
  supportedLanguages,
60
- localisedUrls
62
+ urlStrategy
61
63
  ]);
62
64
  };
63
65
  const useLocalizedLocation = ()=>{
64
- const { language, supportedLanguages, localisedUrls } = (0, external_context_js_namespaceObject.useModernI18n)();
66
+ const { language, supportedLanguages, urlStrategy } = (0, external_context_js_namespaceObject.useModernI18n)();
65
67
  const { location } = (0, external_routerAdapter_js_namespaceObject.useI18nRouterAdapter)();
66
68
  const pathname = location?.pathname ?? '/';
67
69
  const search = location?.search ?? '';
@@ -69,7 +71,7 @@ const useLocalizedLocation = ()=>{
69
71
  return (0, external_react_namespaceObject.useMemo)(()=>{
70
72
  const config = {
71
73
  languages: supportedLanguages,
72
- localisedUrls
74
+ urlStrategy
73
75
  };
74
76
  const alternates = {};
75
77
  for (const supportedLanguage of supportedLanguages)alternates[supportedLanguage] = `${localizePath(pathname, supportedLanguage, config)}${search}${hash}`;
@@ -81,7 +83,7 @@ const useLocalizedLocation = ()=>{
81
83
  }, [
82
84
  language,
83
85
  supportedLanguages,
84
- localisedUrls,
86
+ urlStrategy,
85
87
  pathname,
86
88
  search,
87
89
  hash
@@ -31,7 +31,6 @@ __webpack_require__.d(__webpack_exports__, {
31
31
  createI18nRootWrapper: ()=>createI18nRootWrapper
32
32
  });
33
33
  const jsx_runtime_namespaceObject = require("react/jsx-runtime");
34
- const i18n_runtime_extensions_namespaceObject = require("@modern-js/i18n-runtime-extensions");
35
34
  const runtime_namespaceObject = require("@modern-js/runtime");
36
35
  const head_namespaceObject = require("@modern-js/runtime/head");
37
36
  const external_react_namespaceObject = require("react");
@@ -39,8 +38,14 @@ const external_context_js_namespaceObject = require("./context.js");
39
38
  const external_hooks_js_namespaceObject = require("./hooks.js");
40
39
  const instance_js_namespaceObject = require("./i18n/instance.js");
41
40
  const external_routerAdapter_js_namespaceObject = require("./routerAdapter.js");
42
- const createI18nRootWrapper = (options)=>(App)=>(props)=>{
43
- const { entryName, htmlLangAttr, localePathRedirect, languages, fallbackLanguage, ignoreRedirectRoutes, localisedUrls, getLatestI18nInstance, getI18nextProvider } = options;
41
+ const NativeLanguageSynchronization = ({ i18nInstance, localePathRedirect, languages, pathname, prevLangRef, setLang, children })=>{
42
+ const synchronizeLanguage = (0, external_hooks_js_namespaceObject.useLanguageSync)(i18nInstance, localePathRedirect, languages, pathname, prevLangRef, setLang);
43
+ return children(synchronizeLanguage);
44
+ };
45
+ const createI18nRootWrapper = (options)=>(App)=>{
46
+ const LanguageSynchronization = options.LanguageSynchronization ?? NativeLanguageSynchronization;
47
+ const I18nRoot = (props)=>{
48
+ const { entryName, htmlLangAttr, localePathRedirect, languages, fallbackLanguage, ignoreRedirectRoutes, urlStrategy, getLatestI18nInstance, getI18nextProvider } = options;
44
49
  const runtimeContext = (0, external_react_namespaceObject.useContext)(runtime_namespaceObject.RuntimeContext);
45
50
  const i18nInstance = runtimeContext.i18nInstance || getLatestI18nInstance();
46
51
  const initialLang = (0, external_react_namespaceObject.useMemo)(()=>i18nInstance?.language || fallbackLanguage, [
@@ -65,18 +70,16 @@ const createI18nRootWrapper = (options)=>(App)=>(props)=>{
65
70
  lang
66
71
  ]);
67
72
  (0, external_hooks_js_namespaceObject.useSdkResourcesLoader)(i18nInstance, setForceUpdate);
68
- const synchronizeLanguage = (0, i18n_runtime_extensions_namespaceObject.useLanguageSync)(i18nInstance, localePathRedirect, languages, location?.pathname, prevLangRef, setLang);
69
- (0, external_hooks_js_namespaceObject.useClientSideRedirect)(i18nInstance, localePathRedirect, languages, fallbackLanguage, ignoreRedirectRoutes, localisedUrls);
70
- const contextValue = (0, external_react_namespaceObject.useMemo)(()=>(0, external_hooks_js_namespaceObject.createContextValue)(lang, i18nInstance, entryName, languages, localePathRedirect, ignoreRedirectRoutes, localisedUrls, setLang, synchronizeLanguage), [
73
+ (0, external_hooks_js_namespaceObject.useClientSideRedirect)(i18nInstance, localePathRedirect, languages, fallbackLanguage, ignoreRedirectRoutes, urlStrategy);
74
+ const contextValue = (0, external_react_namespaceObject.useMemo)(()=>(0, external_hooks_js_namespaceObject.createContextValue)(lang, i18nInstance, entryName, languages, localePathRedirect, ignoreRedirectRoutes, setLang, urlStrategy), [
71
75
  lang,
72
76
  i18nInstance,
73
77
  entryName,
74
78
  languages,
75
79
  localePathRedirect,
76
80
  ignoreRedirectRoutes,
77
- localisedUrls,
78
- forceUpdate,
79
- synchronizeLanguage
81
+ urlStrategy,
82
+ forceUpdate
80
83
  ]);
81
84
  const I18nextProvider = getI18nextProvider();
82
85
  const i18nextInstanceForProvider = (0, external_react_namespaceObject.useMemo)(()=>i18nInstance ? (0, instance_js_namespaceObject.getI18nextInstanceForProvider)(i18nInstance, lang) : void 0, [
@@ -99,14 +102,35 @@ const createI18nRootWrapper = (options)=>(App)=>(props)=>{
99
102
  lang
100
103
  }
101
104
  }),
102
- /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_context_js_namespaceObject.ModernI18nProvider, {
103
- i18nextProvider: I18nextProvider,
104
- value: contextValue,
105
- children: appContent
105
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(LanguageSynchronization, {
106
+ i18nInstance: i18nInstance,
107
+ localePathRedirect: localePathRedirect,
108
+ languages: languages,
109
+ pathname: location?.pathname,
110
+ prevLangRef: prevLangRef,
111
+ setLang: setLang,
112
+ children: (synchronizeLanguage)=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_context_js_namespaceObject.ModernI18nProvider, {
113
+ i18nextProvider: I18nextProvider,
114
+ value: {
115
+ ...contextValue,
116
+ synchronizeLanguage
117
+ },
118
+ children: appContent
119
+ })
106
120
  })
107
121
  ]
108
122
  });
109
123
  };
124
+ const { NavigationProvider } = options;
125
+ if (!NavigationProvider) return I18nRoot;
126
+ return function(props) {
127
+ return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(NavigationProvider, {
128
+ children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(I18nRoot, {
129
+ ...props
130
+ })
131
+ });
132
+ };
133
+ };
110
134
  exports.createI18nRootWrapper = __webpack_exports__.createI18nRootWrapper;
111
135
  for(var __rspack_i in __webpack_exports__)if (-1 === [
112
136
  "createI18nRootWrapper"