@bleedingdev/modern-js-plugin-i18n 3.5.0-ultramodern.9 → 3.5.0-ultramodern.90

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 (221) hide show
  1. package/dist/cjs/cli/index.js +2 -1
  2. package/dist/cjs/cli/locales.js +15 -15
  3. package/dist/cjs/runtime/Link.js +8 -89
  4. package/dist/cjs/runtime/context.js +78 -91
  5. package/dist/cjs/runtime/contextHelpers.js +143 -0
  6. package/dist/cjs/runtime/core.js +32 -132
  7. package/dist/cjs/runtime/hooks.js +54 -21
  8. package/dist/cjs/runtime/i18n/backend/defaults.node.js +7 -7
  9. package/dist/cjs/runtime/i18n/detection/cache.js +150 -0
  10. package/dist/cjs/runtime/i18n/detection/detector.js +100 -0
  11. package/dist/cjs/runtime/i18n/detection/index.js +8 -263
  12. package/dist/cjs/runtime/i18n/detection/initOptions.js +69 -0
  13. package/dist/cjs/runtime/i18n/detection/language.js +62 -0
  14. package/dist/cjs/runtime/i18n/detection/path.js +49 -0
  15. package/dist/cjs/runtime/i18n/detection/priority.js +66 -0
  16. package/dist/cjs/runtime/i18n/detection/ssr.js +70 -0
  17. package/dist/cjs/runtime/i18n/detection/types.js +18 -0
  18. package/dist/cjs/runtime/i18n/instance.js +34 -10
  19. package/dist/cjs/runtime/linkHelpers.js +148 -0
  20. package/dist/cjs/runtime/pluginSetup.js +102 -0
  21. package/dist/cjs/runtime/providerComposition.js +115 -0
  22. package/dist/cjs/runtime/reactI18next.js +43 -0
  23. package/dist/cjs/runtime/routerAdapter.js +16 -8
  24. package/dist/cjs/runtime/utils.js +1 -9
  25. package/dist/cjs/server/apiPrefix.js +72 -0
  26. package/dist/cjs/server/detectorOptions.js +97 -0
  27. package/dist/cjs/server/index.js +17 -144
  28. package/dist/cjs/server/redirectPolicy.js +96 -0
  29. package/dist/cjs/shared/detection.js +2 -104
  30. package/dist/cjs/shared/localisedUrls/config.js +49 -0
  31. package/dist/cjs/shared/localisedUrls/index.js +91 -0
  32. package/dist/cjs/shared/localisedUrls/normalise.js +87 -0
  33. package/dist/cjs/shared/localisedUrls/pathname.js +68 -0
  34. package/dist/cjs/shared/localisedUrls/patterns.js +130 -0
  35. package/dist/cjs/shared/localisedUrls/redirect.js +103 -0
  36. package/dist/cjs/shared/localisedUrls/resolve.js +88 -0
  37. package/dist/cjs/shared/localisedUrls/routes.js +130 -0
  38. package/dist/cjs/shared/localisedUrls/types.js +18 -0
  39. package/dist/cjs/shared/localisedUrls.js +28 -294
  40. package/dist/cjs/shared/utils.js +2 -8
  41. package/dist/esm/cli/index.mjs +2 -1
  42. package/dist/esm/cli/locales.mjs +13 -13
  43. package/dist/esm/runtime/Link.mjs +1 -82
  44. package/dist/esm/runtime/context.mjs +76 -92
  45. package/dist/esm/runtime/contextHelpers.mjs +87 -0
  46. package/dist/esm/runtime/core.mjs +30 -133
  47. package/dist/esm/runtime/hooks.mjs +56 -23
  48. package/dist/esm/runtime/i18n/backend/defaults.node.mjs +5 -5
  49. package/dist/esm/runtime/i18n/detection/cache.mjs +103 -0
  50. package/dist/esm/runtime/i18n/detection/detector.mjs +62 -0
  51. package/dist/esm/runtime/i18n/detection/index.mjs +4 -260
  52. package/dist/esm/runtime/i18n/detection/initOptions.mjs +28 -0
  53. package/dist/esm/runtime/i18n/detection/language.mjs +21 -0
  54. package/dist/esm/runtime/i18n/detection/path.mjs +11 -0
  55. package/dist/esm/runtime/i18n/detection/priority.mjs +28 -0
  56. package/dist/esm/runtime/i18n/detection/ssr.mjs +26 -0
  57. package/dist/esm/runtime/i18n/detection/types.mjs +0 -0
  58. package/dist/esm/runtime/i18n/instance.mjs +35 -8
  59. package/dist/esm/runtime/linkHelpers.mjs +98 -0
  60. package/dist/esm/runtime/pluginSetup.mjs +64 -0
  61. package/dist/esm/runtime/providerComposition.mjs +77 -0
  62. package/dist/esm/runtime/reactI18next.mjs +5 -0
  63. package/dist/esm/runtime/routerAdapter.mjs +16 -8
  64. package/dist/esm/runtime/utils.mjs +2 -10
  65. package/dist/esm/server/apiPrefix.mjs +31 -0
  66. package/dist/esm/server/detectorOptions.mjs +59 -0
  67. package/dist/esm/server/index.mjs +8 -135
  68. package/dist/esm/server/redirectPolicy.mjs +46 -0
  69. package/dist/esm/shared/detection.mjs +1 -71
  70. package/dist/esm/shared/localisedUrls/config.mjs +11 -0
  71. package/dist/esm/shared/localisedUrls/index.mjs +7 -0
  72. package/dist/esm/shared/localisedUrls/normalise.mjs +37 -0
  73. package/dist/esm/shared/localisedUrls/pathname.mjs +24 -0
  74. package/dist/esm/shared/localisedUrls/patterns.mjs +86 -0
  75. package/dist/esm/shared/localisedUrls/redirect.mjs +56 -0
  76. package/dist/esm/shared/localisedUrls/resolve.mjs +47 -0
  77. package/dist/esm/shared/localisedUrls/routes.mjs +89 -0
  78. package/dist/esm/shared/localisedUrls/types.mjs +0 -0
  79. package/dist/esm/shared/localisedUrls.mjs +1 -283
  80. package/dist/esm/shared/utils.mjs +1 -1
  81. package/dist/esm-node/cli/index.mjs +2 -1
  82. package/dist/esm-node/cli/locales.mjs +13 -13
  83. package/dist/esm-node/runtime/Link.mjs +1 -82
  84. package/dist/esm-node/runtime/context.mjs +76 -92
  85. package/dist/esm-node/runtime/contextHelpers.mjs +88 -0
  86. package/dist/esm-node/runtime/core.mjs +30 -133
  87. package/dist/esm-node/runtime/hooks.mjs +56 -23
  88. package/dist/esm-node/runtime/i18n/backend/defaults.node.mjs +5 -5
  89. package/dist/esm-node/runtime/i18n/detection/cache.mjs +104 -0
  90. package/dist/esm-node/runtime/i18n/detection/detector.mjs +63 -0
  91. package/dist/esm-node/runtime/i18n/detection/index.mjs +4 -260
  92. package/dist/esm-node/runtime/i18n/detection/initOptions.mjs +29 -0
  93. package/dist/esm-node/runtime/i18n/detection/language.mjs +22 -0
  94. package/dist/esm-node/runtime/i18n/detection/path.mjs +12 -0
  95. package/dist/esm-node/runtime/i18n/detection/priority.mjs +29 -0
  96. package/dist/esm-node/runtime/i18n/detection/ssr.mjs +27 -0
  97. package/dist/esm-node/runtime/i18n/detection/types.mjs +1 -0
  98. package/dist/esm-node/runtime/i18n/instance.mjs +35 -8
  99. package/dist/esm-node/runtime/linkHelpers.mjs +99 -0
  100. package/dist/esm-node/runtime/pluginSetup.mjs +65 -0
  101. package/dist/esm-node/runtime/providerComposition.mjs +78 -0
  102. package/dist/esm-node/runtime/reactI18next.mjs +6 -0
  103. package/dist/esm-node/runtime/routerAdapter.mjs +16 -8
  104. package/dist/esm-node/runtime/utils.mjs +2 -10
  105. package/dist/esm-node/server/apiPrefix.mjs +32 -0
  106. package/dist/esm-node/server/detectorOptions.mjs +60 -0
  107. package/dist/esm-node/server/index.mjs +8 -135
  108. package/dist/esm-node/server/redirectPolicy.mjs +47 -0
  109. package/dist/esm-node/shared/detection.mjs +1 -71
  110. package/dist/esm-node/shared/localisedUrls/config.mjs +12 -0
  111. package/dist/esm-node/shared/localisedUrls/index.mjs +8 -0
  112. package/dist/esm-node/shared/localisedUrls/normalise.mjs +38 -0
  113. package/dist/esm-node/shared/localisedUrls/pathname.mjs +25 -0
  114. package/dist/esm-node/shared/localisedUrls/patterns.mjs +87 -0
  115. package/dist/esm-node/shared/localisedUrls/redirect.mjs +57 -0
  116. package/dist/esm-node/shared/localisedUrls/resolve.mjs +48 -0
  117. package/dist/esm-node/shared/localisedUrls/routes.mjs +90 -0
  118. package/dist/esm-node/shared/localisedUrls/types.mjs +1 -0
  119. package/dist/esm-node/shared/localisedUrls.mjs +1 -283
  120. package/dist/esm-node/shared/utils.mjs +1 -1
  121. package/dist/types/cli/locales.d.ts +1 -1
  122. package/dist/types/runtime/Link.d.ts +3 -7
  123. package/dist/types/runtime/context.d.ts +21 -5
  124. package/dist/types/runtime/contextHelpers.d.ts +29 -0
  125. package/dist/types/runtime/core.d.ts +4 -8
  126. package/dist/types/runtime/hooks.d.ts +3 -7
  127. package/dist/types/runtime/i18n/backend/middleware.common.d.ts +2 -1
  128. package/dist/types/runtime/i18n/detection/cache.d.ts +14 -0
  129. package/dist/types/runtime/i18n/detection/detector.d.ts +8 -0
  130. package/dist/types/runtime/i18n/detection/index.d.ts +5 -50
  131. package/dist/types/runtime/i18n/detection/initOptions.d.ts +10 -0
  132. package/dist/types/runtime/i18n/detection/language.d.ts +11 -0
  133. package/dist/types/runtime/i18n/detection/middleware.d.ts +4 -4
  134. package/dist/types/runtime/i18n/detection/middleware.node.d.ts +4 -4
  135. package/dist/types/runtime/i18n/detection/path.d.ts +5 -0
  136. package/dist/types/runtime/i18n/detection/priority.d.ts +10 -0
  137. package/dist/types/runtime/i18n/detection/ssr.d.ts +9 -0
  138. package/dist/types/runtime/i18n/detection/types.d.ts +32 -0
  139. package/dist/types/runtime/i18n/instance.d.ts +31 -27
  140. package/dist/types/runtime/i18n/react-i18next.d.ts +1 -6
  141. package/dist/types/runtime/i18n/utils.d.ts +14 -5
  142. package/dist/types/runtime/linkHelpers.d.ts +17 -0
  143. package/dist/types/runtime/pluginSetup.d.ts +32 -0
  144. package/dist/types/runtime/providerComposition.d.ts +16 -0
  145. package/dist/types/runtime/reactI18next.d.ts +7 -0
  146. package/dist/types/runtime/routerAdapter.d.ts +7 -6
  147. package/dist/types/runtime/utils.d.ts +7 -2
  148. package/dist/types/server/apiPrefix.d.ts +7 -0
  149. package/dist/types/server/detectorOptions.d.ts +21 -0
  150. package/dist/types/server/index.d.ts +1 -6
  151. package/dist/types/server/redirectPolicy.d.ts +22 -0
  152. package/dist/types/shared/detection.d.ts +1 -11
  153. package/dist/types/shared/localisedUrls/config.d.ts +9 -0
  154. package/dist/types/shared/localisedUrls/index.d.ts +9 -0
  155. package/dist/types/shared/localisedUrls/normalise.d.ts +10 -0
  156. package/dist/types/shared/localisedUrls/pathname.d.ts +4 -0
  157. package/dist/types/shared/localisedUrls/patterns.d.ts +5 -0
  158. package/dist/types/shared/localisedUrls/redirect.d.ts +11 -0
  159. package/dist/types/shared/localisedUrls/resolve.d.ts +7 -0
  160. package/dist/types/shared/localisedUrls/routes.d.ts +3 -0
  161. package/dist/types/shared/localisedUrls/types.d.ts +14 -0
  162. package/dist/types/shared/localisedUrls.d.ts +2 -36
  163. package/dist/types/shared/utils.d.ts +0 -2
  164. package/package.json +17 -20
  165. package/rstest.config.mts +8 -1
  166. package/src/cli/index.ts +5 -4
  167. package/src/cli/locales.ts +3 -3
  168. package/src/runtime/Link.tsx +11 -138
  169. package/src/runtime/context.tsx +170 -207
  170. package/src/runtime/contextHelpers.ts +242 -0
  171. package/src/runtime/core.tsx +48 -275
  172. package/src/runtime/hooks.ts +86 -24
  173. package/src/runtime/i18n/backend/defaults.node.ts +2 -2
  174. package/src/runtime/i18n/backend/middleware.common.ts +5 -4
  175. package/src/runtime/i18n/detection/cache.ts +189 -0
  176. package/src/runtime/i18n/detection/detector.ts +166 -0
  177. package/src/runtime/i18n/detection/index.ts +10 -641
  178. package/src/runtime/i18n/detection/initOptions.ts +74 -0
  179. package/src/runtime/i18n/detection/language.ts +64 -0
  180. package/src/runtime/i18n/detection/middleware.node.ts +26 -7
  181. package/src/runtime/i18n/detection/middleware.ts +15 -7
  182. package/src/runtime/i18n/detection/path.ts +41 -0
  183. package/src/runtime/i18n/detection/priority.ts +82 -0
  184. package/src/runtime/i18n/detection/ssr.ts +47 -0
  185. package/src/runtime/i18n/detection/types.ts +41 -0
  186. package/src/runtime/i18n/instance.ts +98 -34
  187. package/src/runtime/i18n/react-i18next.ts +1 -6
  188. package/src/runtime/i18n/utils.ts +18 -9
  189. package/src/runtime/linkHelpers.ts +174 -0
  190. package/src/runtime/pluginSetup.ts +189 -0
  191. package/src/runtime/providerComposition.tsx +148 -0
  192. package/src/runtime/reactI18next.ts +20 -0
  193. package/src/runtime/routerAdapter.tsx +36 -15
  194. package/src/runtime/utils.ts +13 -35
  195. package/src/server/apiPrefix.ts +67 -0
  196. package/src/server/detectorOptions.ts +105 -0
  197. package/src/server/index.ts +14 -319
  198. package/src/server/redirectPolicy.ts +127 -0
  199. package/src/shared/detection.ts +1 -1
  200. package/src/shared/localisedUrls/config.ts +18 -0
  201. package/src/shared/localisedUrls/index.ts +24 -0
  202. package/src/shared/localisedUrls/normalise.ts +67 -0
  203. package/src/shared/localisedUrls/pathname.ts +60 -0
  204. package/src/shared/localisedUrls/patterns.ts +160 -0
  205. package/src/shared/localisedUrls/redirect.ts +93 -0
  206. package/src/shared/localisedUrls/resolve.ts +135 -0
  207. package/src/shared/localisedUrls/routes.ts +234 -0
  208. package/src/shared/localisedUrls/types.ts +18 -0
  209. package/src/shared/localisedUrls.ts +26 -623
  210. package/src/shared/utils.ts +2 -2
  211. package/tests/federatedI18nBoundary.client.test.tsx +112 -0
  212. package/tests/federatedI18nBoundary.test.tsx +120 -0
  213. package/tests/fixtures/localised-routes.golden.json +156 -0
  214. package/tests/link.test.tsx +111 -0
  215. package/tests/localisedUrlRewriteMatrix.fork.test.ts +147 -0
  216. package/tests/localisedUrls.test.ts +148 -2
  217. package/tests/reactI18nextRuntimeBoundary.test.ts +6 -3
  218. package/tests/redirectPolicy.test.ts +45 -0
  219. package/tests/routerAdapter.test.tsx +603 -0
  220. package/tests/type-fixture/fixture-globals.d.ts +11 -0
  221. package/tests/type-fixture/tsconfig.json +1 -0
@@ -1,9 +1,8 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
- import { isBrowser } from "@modern-js/runtime";
3
2
  import { createContext, useCallback, useContext, useEffect, useMemo } from "react";
4
- import { cacheUserLanguage } from "./i18n/detection/index.mjs";
3
+ import { changeModernI18nLanguage, getPathLanguage, isI18nLanguageSupported, isI18nResourcesReady, translateI18n } from "./contextHelpers.mjs";
4
+ import { getActualI18nextInstance } from "./i18n/instance.mjs";
5
5
  import { useI18nRouterAdapter } from "./routerAdapter.mjs";
6
- import { buildLocalizedUrl, detectLanguageFromPath, getEntryPath, shouldIgnoreRedirect } from "./utils.mjs";
7
6
  const modernI18nContextKey = Symbol.for('@modern-js/plugin-i18n/runtime/ModernI18nContext');
8
7
  const getModernI18nContext = ()=>{
9
8
  const globalStore = globalThis;
@@ -15,76 +14,87 @@ const ModernI18nProvider = ({ children, value })=>/*#__PURE__*/ jsx(ModernI18nCo
15
14
  value: value,
16
15
  children: children
17
16
  });
17
+ const FederatedI18nBoundary = ({ children, defaultNamespace, fallbackLanguage, resources, supportedLanguages })=>{
18
+ const parent = useContext(ModernI18nContext);
19
+ if (!parent) throw new Error('FederatedI18nBoundary must be used within ModernI18nProvider');
20
+ const languages = supportedLanguages ?? parent.languages ?? Object.keys(resources);
21
+ const scopedInstance = useMemo(()=>{
22
+ const parentInstance = getActualI18nextInstance(parent.i18nInstance);
23
+ const clone = parentInstance.cloneInstance?.({
24
+ defaultNS: defaultNamespace,
25
+ fallbackLng: fallbackLanguage ?? languages[0] ?? parent.language,
26
+ forkResourceStore: true,
27
+ initImmediate: false,
28
+ lng: parent.language,
29
+ ns: [
30
+ defaultNamespace
31
+ ],
32
+ resources,
33
+ supportedLngs: languages
34
+ });
35
+ if (!clone) throw new Error('FederatedI18nBoundary requires an i18n instance with cloneInstance support');
36
+ const resourceStore = clone.store;
37
+ const parentResourceStore = parentInstance.store;
38
+ const sharesNestedResourceState = Object.entries(resourceStore?.data ?? {}).some(([language, namespaces])=>{
39
+ const parentNamespaces = parentResourceStore?.data?.[language];
40
+ return namespaces === parentNamespaces || Object.entries(namespaces).some(([namespace, resource])=>null !== resource && 'object' == typeof resource && resource === parentNamespaces?.[namespace]);
41
+ });
42
+ if (clone === parentInstance || resourceStore === parentResourceStore || resourceStore?.data === parentResourceStore?.data || sharesNestedResourceState) throw new Error('FederatedI18nBoundary cloneInstance did not isolate the host resource store');
43
+ if (!resourceStore?.addResourceBundle || !clone.removeResourceBundle || !resourceStore.data) throw new Error('FederatedI18nBoundary requires an isolated mutable i18n resource store');
44
+ for (const [language, namespaces] of Object.entries(resourceStore.data))for (const namespace of Object.keys(namespaces))clone.removeResourceBundle(language, namespace);
45
+ for (const [language, namespaces] of Object.entries(resources))for (const [namespace, resource] of Object.entries(namespaces))resourceStore.addResourceBundle(language, namespace, resource, true, true);
46
+ return clone;
47
+ }, [
48
+ defaultNamespace,
49
+ fallbackLanguage,
50
+ languages,
51
+ parent.i18nInstance,
52
+ parent.language,
53
+ resources
54
+ ]);
55
+ const value = useMemo(()=>({
56
+ ...parent,
57
+ i18nInstance: scopedInstance,
58
+ language: parent.language,
59
+ languages
60
+ }), [
61
+ languages,
62
+ parent,
63
+ scopedInstance
64
+ ]);
65
+ return /*#__PURE__*/ jsx(ModernI18nProvider, {
66
+ value: value,
67
+ children: children
68
+ });
69
+ };
18
70
  const useModernI18n = ()=>{
19
71
  const context = useContext(ModernI18nContext);
20
- if (!context) throw new Error('useModernI18n must be used within a ModernI18nProvider');
21
- const { language: contextLanguage, i18nInstance, languages, localePathRedirect, ignoreRedirectRoutes, localisedUrls, updateLanguage } = context;
72
+ if (!context) throw new Error('useModernI18n must be used within ModernI18nProvider');
73
+ const { language: contextLanguage, i18nInstance, languages, localePathRedirect, ignoreRedirectRoutes, localisedUrls, updateLanguage, synchronizeLanguage } = context;
22
74
  const { navigate, location, hasRouter } = useI18nRouterAdapter();
23
- const pathLanguage = useMemo(()=>{
24
- if (!localePathRedirect || !location?.pathname) return;
25
- const detected = detectLanguageFromPath(location.pathname, languages || [], localePathRedirect);
26
- return detected.detected ? detected.language : void 0;
27
- }, [
75
+ const pathLanguage = useMemo(()=>getPathLanguage(location?.pathname, languages, localePathRedirect), [
28
76
  languages,
29
77
  localePathRedirect,
30
78
  location?.pathname
31
79
  ]);
32
- const currentLanguage = pathLanguage || contextLanguage;
33
80
  useEffect(()=>{
34
- if (!pathLanguage || pathLanguage === contextLanguage) return;
35
- updateLanguage?.(pathLanguage);
36
- i18nInstance?.setLang?.(pathLanguage);
37
- i18nInstance?.changeLanguage?.(pathLanguage);
38
- if (isBrowser()) {
39
- const detectionOptions = i18nInstance.options?.detection;
40
- cacheUserLanguage(i18nInstance, pathLanguage, detectionOptions);
41
- }
81
+ if (pathLanguage) synchronizeLanguage?.(pathLanguage);
42
82
  }, [
43
- contextLanguage,
44
- i18nInstance,
45
83
  pathLanguage,
46
- updateLanguage
84
+ synchronizeLanguage
47
85
  ]);
48
- const changeLanguage = useCallback(async (newLang)=>{
49
- try {
50
- if (!newLang || 'string' != typeof newLang) throw new Error('Language must be a non-empty string');
51
- await i18nInstance?.setLang?.(newLang);
52
- await i18nInstance?.changeLanguage?.(newLang);
53
- if (isBrowser()) {
54
- const detectionOptions = i18nInstance.options?.detection;
55
- cacheUserLanguage(i18nInstance, newLang, detectionOptions);
56
- }
57
- if (localePathRedirect && isBrowser() && hasRouter && navigate && location) {
58
- const currentPath = location.pathname;
59
- const entryPath = getEntryPath();
60
- const relativePath = currentPath.replace(entryPath, '');
61
- const pathLanguage = detectLanguageFromPath(currentPath, languages || [], localePathRedirect);
62
- if (pathLanguage.detected && pathLanguage.language === newLang) return;
63
- if (!shouldIgnoreRedirect(relativePath, languages || [], ignoreRedirectRoutes)) {
64
- const newPath = buildLocalizedUrl(relativePath, newLang, languages || [], localisedUrls);
65
- const newUrl = entryPath + newPath + location.search + location.hash;
66
- await navigate(newUrl, {
67
- replace: true
68
- });
69
- }
70
- } else if (localePathRedirect && isBrowser() && !hasRouter) {
71
- const currentPath = window.location.pathname;
72
- const entryPath = getEntryPath();
73
- const relativePath = currentPath.replace(entryPath, '');
74
- const pathLanguage = detectLanguageFromPath(currentPath, languages || [], localePathRedirect);
75
- if (pathLanguage.detected && pathLanguage.language === newLang) return;
76
- if (!shouldIgnoreRedirect(relativePath, languages || [], ignoreRedirectRoutes)) {
77
- const newPath = buildLocalizedUrl(relativePath, newLang, languages || [], localisedUrls);
78
- const newUrl = entryPath + newPath + window.location.search + window.location.hash;
79
- window.history.pushState(null, '', newUrl);
80
- }
81
- }
82
- if (updateLanguage) updateLanguage(newLang);
83
- } catch (error) {
84
- console.error('Failed to change language:', error);
85
- throw error;
86
- }
87
- }, [
86
+ const currentLanguage = contextLanguage;
87
+ const changeLanguage = useCallback((newLang)=>changeModernI18nLanguage(newLang, {
88
+ i18nInstance,
89
+ updateLanguage,
90
+ localePathRedirect,
91
+ ignoreRedirectRoutes,
92
+ localisedUrls,
93
+ languages,
94
+ hasRouter,
95
+ navigate,
96
+ location
97
+ }), [
88
98
  i18nInstance,
89
99
  updateLanguage,
90
100
  localePathRedirect,
@@ -95,40 +105,14 @@ const useModernI18n = ()=>{
95
105
  navigate,
96
106
  location
97
107
  ]);
98
- const t = useCallback((key, ...args)=>{
99
- if ('function' != typeof i18nInstance.t) throw new Error('i18nInstance.t is required');
100
- return i18nInstance.t(key, ...args);
101
- }, [
108
+ const t = useCallback((key, ...args)=>translateI18n(i18nInstance, key, ...args), [
102
109
  currentLanguage,
103
110
  i18nInstance
104
111
  ]);
105
- const isLanguageSupported = useCallback((lang)=>languages?.includes(lang) || false, [
112
+ const isLanguageSupported = useCallback((lang)=>isI18nLanguageSupported(languages, lang), [
106
113
  languages
107
114
  ]);
108
- const isResourcesReady = useMemo(()=>{
109
- if (!i18nInstance?.isInitialized) return false;
110
- const backend = i18nInstance?.services?.backend;
111
- if (backend && 'function' == typeof backend.isLoading) {
112
- const loadingResources = backend.getLoadingResources();
113
- const isCurrentLanguageLoading = loadingResources.some(({ language })=>language === currentLanguage);
114
- if (isCurrentLanguageLoading) return false;
115
- }
116
- const store = i18nInstance.store;
117
- if (!store?.data) return false;
118
- const langData = store.data[currentLanguage];
119
- if (!langData || 'object' != typeof langData) return false;
120
- const options = i18nInstance.options;
121
- const namespaces = options?.ns || options?.defaultNS || [
122
- 'translation'
123
- ];
124
- const requiredNamespaces = Array.isArray(namespaces) ? namespaces : [
125
- namespaces
126
- ];
127
- return requiredNamespaces.every((ns)=>{
128
- const nsData = langData[ns];
129
- return nsData && 'object' == typeof nsData && Object.keys(nsData).length > 0;
130
- });
131
- }, [
115
+ const isResourcesReady = useMemo(()=>isI18nResourcesReady(i18nInstance, currentLanguage), [
132
116
  currentLanguage,
133
117
  i18nInstance
134
118
  ]);
@@ -143,4 +127,4 @@ const useModernI18n = ()=>{
143
127
  isResourcesReady
144
128
  };
145
129
  };
146
- export { ModernI18nProvider, useModernI18n };
130
+ export { FederatedI18nBoundary, ModernI18nProvider, useModernI18n };
@@ -0,0 +1,87 @@
1
+ import { isBrowser } from "@modern-js/runtime";
2
+ import { cacheUserLanguage } from "./i18n/detection/index.mjs";
3
+ import { buildLocalizedUrl, detectLanguageFromPath, getEntryPath, shouldIgnoreRedirect } from "./utils.mjs";
4
+ function getPathLanguage(pathname, languages, localePathRedirect) {
5
+ if (!localePathRedirect || !pathname) return;
6
+ const detected = detectLanguageFromPath(pathname, languages || [], localePathRedirect);
7
+ return detected.detected ? detected.language : void 0;
8
+ }
9
+ function cacheI18nLanguage(i18nInstance, language) {
10
+ if (isBrowser()) {
11
+ const detectionOptions = i18nInstance.options?.detection;
12
+ cacheUserLanguage(i18nInstance, language, detectionOptions);
13
+ }
14
+ }
15
+ async function changeI18nInstanceLanguage(i18nInstance, language) {
16
+ if (i18nInstance.setLang) await i18nInstance.setLang(language);
17
+ else await i18nInstance.changeLanguage?.(language);
18
+ }
19
+ async function changeModernI18nLanguage(newLang, options) {
20
+ const { i18nInstance, updateLanguage, localePathRedirect, ignoreRedirectRoutes, localisedUrls, languages, hasRouter, navigate, location } = options;
21
+ try {
22
+ if (!newLang || 'string' != typeof newLang) throw new Error('Language must be non-empty string');
23
+ await changeI18nInstanceLanguage(i18nInstance, newLang);
24
+ cacheI18nLanguage(i18nInstance, newLang);
25
+ if (localePathRedirect && isBrowser() && hasRouter && navigate && location) {
26
+ const currentPath = location.pathname;
27
+ const entryPath = getEntryPath();
28
+ const relativePath = currentPath.replace(entryPath, '');
29
+ const pathLanguage = detectLanguageFromPath(currentPath, languages || [], localePathRedirect);
30
+ if (pathLanguage.detected && pathLanguage.language === newLang) return void updateLanguage?.(newLang);
31
+ if (!shouldIgnoreRedirect(relativePath, languages || [], ignoreRedirectRoutes)) {
32
+ const newPath = buildLocalizedUrl(relativePath, newLang, languages || [], localisedUrls);
33
+ const newUrl = entryPath + newPath + location.search + location.hash;
34
+ await navigate(newUrl, {
35
+ replace: true
36
+ });
37
+ }
38
+ } else if (localePathRedirect && isBrowser() && !hasRouter) {
39
+ const currentPath = window.location.pathname;
40
+ const entryPath = getEntryPath();
41
+ const relativePath = currentPath.replace(entryPath, '');
42
+ const pathLanguage = detectLanguageFromPath(currentPath, languages || [], localePathRedirect);
43
+ if (pathLanguage.detected && pathLanguage.language === newLang) return void updateLanguage?.(newLang);
44
+ if (!shouldIgnoreRedirect(relativePath, languages || [], ignoreRedirectRoutes)) {
45
+ const newPath = buildLocalizedUrl(relativePath, newLang, languages || [], localisedUrls);
46
+ const newUrl = entryPath + newPath + window.location.search + window.location.hash;
47
+ window.history.pushState(null, '', newUrl);
48
+ }
49
+ }
50
+ if (updateLanguage) updateLanguage(newLang);
51
+ } catch (error) {
52
+ console.error('Failed change language:', error);
53
+ throw error;
54
+ }
55
+ }
56
+ function translateI18n(i18nInstance, key, ...args) {
57
+ if ('function' != typeof i18nInstance.t) throw new Error('i18nInstance.t required');
58
+ return i18nInstance.t(key, ...args);
59
+ }
60
+ function isI18nLanguageSupported(languages, lang) {
61
+ return languages?.includes(lang) || false;
62
+ }
63
+ function isI18nResourcesReady(i18nInstance, currentLanguage) {
64
+ if (!i18nInstance?.isInitialized) return false;
65
+ const backend = i18nInstance?.services?.backend;
66
+ if (backend && 'function' == typeof backend.isLoading) {
67
+ const loadingResources = backend.getLoadingResources();
68
+ const isCurrentLanguageLoading = loadingResources.some(({ language })=>language === currentLanguage);
69
+ if (isCurrentLanguageLoading) return false;
70
+ }
71
+ const store = i18nInstance.store;
72
+ if (!store?.data) return false;
73
+ const langData = store.data[currentLanguage];
74
+ if (!langData || 'object' != typeof langData) return false;
75
+ const options = i18nInstance.options;
76
+ const namespaces = options?.ns || options?.defaultNS || [
77
+ 'translation'
78
+ ];
79
+ const requiredNamespaces = Array.isArray(namespaces) ? namespaces : [
80
+ namespaces
81
+ ];
82
+ return requiredNamespaces.every((ns)=>{
83
+ const nsData = langData[ns];
84
+ return nsData && 'object' == typeof nsData && Object.keys(nsData).length > 0;
85
+ });
86
+ }
87
+ export { cacheI18nLanguage, changeI18nInstanceLanguage, changeModernI18nLanguage, getPathLanguage, isI18nLanguageSupported, isI18nResourcesReady, translateI18n };
@@ -1,31 +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 { detectLanguageWithPriority, exportServerLngToWindow, mergeDetectionOptions } from "./i18n/detection/index.mjs";
11
- import { useI18nextLanguageDetector } from "./i18n/detection/middleware.mjs";
12
- import { getI18nextInstanceForProvider } from "./i18n/instance.mjs";
13
- import { buildLocalizedUrl, getPathname, splitUrlTarget } from "./utils.mjs";
1
+ import { setupI18nBeforeRender } from "./pluginSetup.mjs";
2
+ import { createI18nRootWrapper } from "./providerComposition.mjs";
3
+ import { resolveReactI18nextIntegration } from "./reactI18next.mjs";
14
4
  import "./types.mjs";
15
- let i18nLifecycleHelpersPromise;
16
- function loadI18nLifecycleHelpers() {
17
- i18nLifecycleHelpersPromise ??= Promise.all([
18
- import("./i18n/backend/middleware.mjs"),
19
- import("./i18n/utils.mjs")
20
- ]).then(([backendMiddleware, utils])=>({
21
- useI18nextBackend: backendMiddleware.useI18nextBackend,
22
- changeI18nLanguage: utils.changeI18nLanguage,
23
- ensureLanguageMatch: utils.ensureLanguageMatch,
24
- initializeI18nInstance: utils.initializeI18nInstance,
25
- setupClonedInstance: utils.setupClonedInstance
26
- }));
27
- return i18nLifecycleHelpersPromise;
28
- }
29
5
  const createI18nPlugin = (loadReactI18nextIntegration)=>(options)=>({
30
6
  name: '@modern-js/plugin-i18n',
31
7
  setup: (api)=>{
@@ -34,119 +10,40 @@ const createI18nPlugin = (loadReactI18nextIntegration)=>(options)=>({
34
10
  const { enabled: backendEnabled = false } = backend || {};
35
11
  let latestI18nInstance;
36
12
  let I18nextProvider;
37
- const resolveReactI18nextIntegration = async ()=>{
38
- if (!reactI18next) return null;
39
- return loadReactI18nextIntegration?.() ?? null;
40
- };
41
13
  api.onBeforeRender(async (context)=>{
42
- const { useI18nextBackend, changeI18nLanguage, ensureLanguageMatch, initializeI18nInstance, setupClonedInstance } = await loadI18nLifecycleHelpers();
43
- let i18nInstance = await getI18nInstance(userI18nInstance);
44
- const { i18n: otherConfig } = api.getRuntimeConfig();
45
- const { initOptions: otherInitOptions } = otherConfig || {};
46
- const userInitOptions = merge(otherInitOptions || {}, initOptions || {});
47
- const reactI18nextIntegration = await resolveReactI18nextIntegration();
48
- I18nextProvider = reactI18nextIntegration?.I18nextProvider ?? null;
49
- if (reactI18nextIntegration?.initReactI18next) i18nInstance.use(reactI18nextIntegration.initReactI18next);
50
- const pathname = getPathname(context);
51
- if (i18nextDetector) useI18nextLanguageDetector(i18nInstance);
52
- const mergedDetection = mergeDetectionOptions(i18nextDetector, detection, localePathRedirect, userInitOptions);
53
- const mergedBackend = mergeBackendOptions(backend, userInitOptions);
54
- const hasSdkConfig = 'function' == typeof userInitOptions?.backend?.sdk || mergedBackend?.sdk && 'function' == typeof mergedBackend.sdk;
55
- if (mergedBackend && (backendEnabled || hasSdkConfig)) useI18nextBackend(i18nInstance, mergedBackend);
56
- const { finalLanguage } = await detectLanguageWithPriority(i18nInstance, {
57
- languages,
58
- fallbackLanguage,
59
- localePathRedirect,
14
+ latestI18nInstance = await setupI18nBeforeRender(context, {
15
+ api,
16
+ userI18nInstance,
17
+ initOptions,
18
+ backend,
19
+ backendEnabled,
60
20
  i18nextDetector,
61
21
  detection,
62
- userInitOptions,
63
- mergedBackend,
64
- pathname,
65
- ssrContext: context.ssrContext
66
- });
67
- await initializeI18nInstance(i18nInstance, finalLanguage, fallbackLanguage, languages, mergedDetection, mergedBackend, userInitOptions);
68
- if (!isBrowser() && i18nInstance.cloneInstance) {
69
- i18nInstance = i18nInstance.cloneInstance();
70
- await setupClonedInstance(i18nInstance, finalLanguage, fallbackLanguage, languages, backendEnabled, backend, i18nextDetector, detection, localePathRedirect, userInitOptions);
71
- }
72
- if (localePathRedirect) await ensureLanguageMatch(i18nInstance, finalLanguage);
73
- if (!isBrowser()) exportServerLngToWindow(context, finalLanguage);
74
- context.i18nInstance = i18nInstance;
75
- latestI18nInstance = i18nInstance;
76
- context.changeLanguage = async (newLang)=>{
77
- await changeI18nLanguage(i18nInstance, newLang, {
78
- detectionOptions: mergedDetection
79
- });
80
- };
81
- });
82
- api.wrapRoot((App)=>(props)=>{
83
- const runtimeContext = useContext(RuntimeContext);
84
- const i18nInstance = runtimeContext.i18nInstance || latestI18nInstance;
85
- const initialLang = useMemo(()=>i18nInstance?.language || (localeDetection?.fallbackLanguage ?? 'en'), [
86
- i18nInstance?.language,
87
- localeDetection?.fallbackLanguage
88
- ]);
89
- const [lang, setLang] = useState(initialLang);
90
- const [forceUpdate, setForceUpdate] = useState(0);
91
- const prevLangRef = useRef(lang);
92
- const runtimeContextRef = useRef(runtimeContext);
93
- runtimeContextRef.current = runtimeContext;
94
- useEffect(()=>{
95
- if (i18nInstance?.language) {
96
- const translator = i18nInstance.translator;
97
- if (translator) translator.language = i18nInstance.language;
98
- }
99
- }, [
100
- i18nInstance?.language
101
- ]);
102
- useEffect(()=>{
103
- prevLangRef.current = lang;
104
- }, [
105
- lang
106
- ]);
107
- useSdkResourcesLoader(i18nInstance, setForceUpdate);
108
- useLanguageSync(i18nInstance, localePathRedirect, languages, runtimeContextRef, prevLangRef, setLang);
109
- useClientSideRedirect(i18nInstance, localePathRedirect, languages, fallbackLanguage, ignoreRedirectRoutes, localisedUrls);
110
- const contextValue = useMemo(()=>createContextValue(lang, i18nInstance, entryName, languages, localePathRedirect, ignoreRedirectRoutes, localisedUrls, setLang), [
111
- lang,
112
- i18nInstance,
113
- entryName,
114
- languages,
115
- localePathRedirect,
116
- ignoreRedirectRoutes,
117
- localisedUrls,
118
- forceUpdate
119
- ]);
120
- const children = props.children;
121
- const appContent = /*#__PURE__*/ jsxs(Fragment, {
122
- children: [
123
- Boolean(htmlLangAttr) && /*#__PURE__*/ jsx(Helmet, {
124
- htmlAttributes: {
125
- lang
126
- }
127
- }),
128
- /*#__PURE__*/ jsx(ModernI18nProvider, {
129
- value: contextValue,
130
- children: App ? /*#__PURE__*/ jsx(App, {
131
- ...props,
132
- children: children
133
- }) : children
134
- })
135
- ]
136
- });
137
- if (!i18nInstance) return appContent;
138
- if (I18nextProvider) {
139
- const i18nextInstanceForProvider = getI18nextInstanceForProvider(i18nInstance);
140
- return /*#__PURE__*/ jsx(I18nextProvider, {
141
- i18n: i18nextInstanceForProvider,
142
- children: appContent
143
- });
22
+ localePathRedirect,
23
+ languages,
24
+ fallbackLanguage,
25
+ resolveReactI18nextIntegration: ()=>resolveReactI18nextIntegration(reactI18next, loadReactI18nextIntegration),
26
+ setI18nextProvider: (provider)=>{
27
+ I18nextProvider = provider;
144
28
  }
145
- return appContent;
146
29
  });
30
+ });
31
+ api.wrapRoot(createI18nRootWrapper({
32
+ entryName,
33
+ htmlLangAttr,
34
+ localePathRedirect,
35
+ languages,
36
+ fallbackLanguage,
37
+ ignoreRedirectRoutes,
38
+ localisedUrls,
39
+ getLatestI18nInstance: ()=>latestI18nInstance,
40
+ getI18nextProvider: ()=>I18nextProvider
41
+ }));
147
42
  }
148
43
  });
44
+ export { FederatedI18nBoundary, useModernI18n } from "./context.mjs";
149
45
  export { I18nLink } from "./I18nLink.mjs";
150
46
  export { Link } from "./Link.mjs";
151
47
  export { canonicalPath, localizePath, useLocalizedLocation, useLocalizedPaths } from "./localizedPaths.mjs";
152
- export { buildLocalizedUrl, createI18nPlugin, splitUrlTarget, useModernI18n };
48
+ export { buildLocalizedUrl, splitUrlTarget } from "./utils.mjs";
49
+ export { createI18nPlugin };
@@ -1,9 +1,9 @@
1
1
  import { isBrowser } from "@modern-js/runtime";
2
- import { useEffect, useRef } from "react";
2
+ import { useCallback, useEffect, useRef } from "react";
3
+ import { cacheI18nLanguage, changeI18nInstanceLanguage } from "./contextHelpers.mjs";
3
4
  import { I18N_SDK_RESOURCES_LOADED_EVENT, getI18nSdkBackendId } from "./i18n/backend/sdk-event.mjs";
4
- import { cacheUserLanguage } from "./i18n/detection/index.mjs";
5
5
  import { useI18nRouterAdapter } from "./routerAdapter.mjs";
6
- import { buildLocalizedUrl, detectLanguageFromPath, getEntryPath, getPathname, shouldIgnoreRedirect } from "./utils.mjs";
6
+ import { buildLocalizedUrl, detectLanguageFromPath, getEntryPath, shouldIgnoreRedirect } from "./utils.mjs";
7
7
  function createMinimalI18nInstance(language) {
8
8
  const minimalInstance = {
9
9
  language,
@@ -15,7 +15,7 @@ function createMinimalI18nInstance(language) {
15
15
  };
16
16
  return minimalInstance;
17
17
  }
18
- function createContextValue(lang, i18nInstance, entryName, languages, localePathRedirect, ignoreRedirectRoutes, localisedUrls, setLang) {
18
+ function createContextValue(lang, i18nInstance, entryName, languages, localePathRedirect, ignoreRedirectRoutes, localisedUrls, setLang, synchronizeLanguage) {
19
19
  const instance = i18nInstance || createMinimalI18nInstance(lang);
20
20
  return {
21
21
  language: lang,
@@ -25,7 +25,8 @@ function createContextValue(lang, i18nInstance, entryName, languages, localePath
25
25
  localePathRedirect,
26
26
  ignoreRedirectRoutes,
27
27
  localisedUrls,
28
- updateLanguage: setLang
28
+ updateLanguage: setLang,
29
+ synchronizeLanguage
29
30
  };
30
31
  }
31
32
  function useSdkResourcesLoader(i18nInstance, setForceUpdate) {
@@ -116,26 +117,56 @@ function useClientSideRedirect(i18nInstance, localePathRedirect, languages, fall
116
117
  localisedUrls
117
118
  ]);
118
119
  }
119
- function useLanguageSync(i18nInstance, localePathRedirect, languages, runtimeContextRef, prevLangRef, setLang) {
120
+ function useLanguageSync(i18nInstance, localePathRedirect, languages, pathname, prevLangRef, setLang) {
121
+ const latestRequestRef = useRef(0);
122
+ const syncQueueRef = useRef(Promise.resolve());
123
+ const isMountedRef = useRef(false);
124
+ const desiredLanguageRef = useRef(void 0);
120
125
  useEffect(()=>{
121
- if (!i18nInstance) return;
122
- if (localePathRedirect) {
123
- const currentPathname = getPathname(runtimeContextRef.current);
124
- const pathDetection = detectLanguageFromPath(currentPathname, languages, localePathRedirect);
125
- if (pathDetection.detected && pathDetection.language) {
126
- const currentLang = pathDetection.language;
127
- if (currentLang !== prevLangRef.current) {
128
- prevLangRef.current = currentLang;
129
- setLang(currentLang);
130
- i18nInstance.setLang?.(currentLang);
131
- i18nInstance.changeLanguage?.(currentLang);
132
- if (isBrowser()) {
133
- const detectionOptions = i18nInstance.options?.detection;
134
- cacheUserLanguage(i18nInstance, currentLang, detectionOptions);
135
- }
126
+ isMountedRef.current = true;
127
+ return ()=>{
128
+ isMountedRef.current = false;
129
+ latestRequestRef.current += 1;
130
+ };
131
+ }, []);
132
+ useEffect(()=>{
133
+ desiredLanguageRef.current = void 0;
134
+ latestRequestRef.current += 1;
135
+ syncQueueRef.current = Promise.resolve();
136
+ }, [
137
+ i18nInstance
138
+ ]);
139
+ const synchronizeLanguage = useCallback((currentLang)=>{
140
+ if (!i18nInstance || !currentLang || desiredLanguageRef.current === currentLang) return;
141
+ desiredLanguageRef.current = currentLang;
142
+ const requestId = ++latestRequestRef.current;
143
+ syncQueueRef.current = syncQueueRef.current.then(async ()=>{
144
+ if (requestId !== latestRequestRef.current || !isMountedRef.current) return;
145
+ try {
146
+ if (i18nInstance.language !== currentLang) await changeI18nInstanceLanguage(i18nInstance, currentLang);
147
+ if (requestId !== latestRequestRef.current || !isMountedRef.current) return;
148
+ prevLangRef.current = currentLang;
149
+ setLang(currentLang);
150
+ cacheI18nLanguage(i18nInstance, currentLang);
151
+ } catch (error) {
152
+ if (requestId === latestRequestRef.current && isMountedRef.current) {
153
+ desiredLanguageRef.current = void 0;
154
+ console.error(`Failed to synchronize i18n language "${currentLang}".`, error);
136
155
  }
137
156
  }
157
+ });
158
+ }, [
159
+ i18nInstance,
160
+ prevLangRef,
161
+ setLang
162
+ ]);
163
+ useEffect(()=>{
164
+ if (!i18nInstance) return;
165
+ if (localePathRedirect) {
166
+ const pathDetection = detectLanguageFromPath(pathname || '', languages, localePathRedirect);
167
+ if (pathDetection.detected && pathDetection.language) synchronizeLanguage(pathDetection.language);
138
168
  } else {
169
+ latestRequestRef.current += 1;
139
170
  const instanceLang = i18nInstance.language;
140
171
  if (instanceLang && instanceLang !== prevLangRef.current) {
141
172
  prevLangRef.current = instanceLang;
@@ -146,9 +177,11 @@ function useLanguageSync(i18nInstance, localePathRedirect, languages, runtimeCon
146
177
  i18nInstance,
147
178
  localePathRedirect,
148
179
  languages,
149
- runtimeContextRef,
180
+ pathname,
150
181
  prevLangRef,
151
- setLang
182
+ setLang,
183
+ synchronizeLanguage
152
184
  ]);
185
+ return synchronizeLanguage;
153
186
  }
154
187
  export { createContextValue, useClientSideRedirect, useLanguageSync, useSdkResourcesLoader };
@@ -1,18 +1,18 @@
1
- import fs from "fs";
2
- import path_0 from "path";
1
+ import node_fs from "node:fs";
2
+ import node_path from "node:path";
3
3
  const CONVENTIONAL_LOCALES_DIRS = [
4
4
  './locales',
5
5
  './config/public/locales'
6
6
  ];
7
7
  const isDirectory = (dirPath)=>{
8
8
  try {
9
- return fs.statSync(dirPath).isDirectory();
9
+ return node_fs.statSync(dirPath).isDirectory();
10
10
  } catch {
11
11
  return false;
12
12
  }
13
13
  };
14
14
  const resolveDefaultLocalesDir = (cwd = process.cwd())=>{
15
- for (const dir of CONVENTIONAL_LOCALES_DIRS)if (isDirectory(path_0.resolve(cwd, dir))) return dir;
15
+ for (const dir of CONVENTIONAL_LOCALES_DIRS)if (isDirectory(node_path.resolve(cwd, dir))) return dir;
16
16
  return CONVENTIONAL_LOCALES_DIRS[0];
17
17
  };
18
18
  const DEFAULT_I18NEXT_BACKEND_OPTIONS = {
@@ -38,7 +38,7 @@ function getResourceBasePath(resourcePath) {
38
38
  }
39
39
  function pathExists(resourcePath) {
40
40
  try {
41
- return fs.existsSync(getResourceBasePath(resourcePath));
41
+ return node_fs.existsSync(getResourceBasePath(resourcePath));
42
42
  } catch {
43
43
  return false;
44
44
  }