@bleedingdev/modern-js-plugin-i18n 3.5.0-ultramodern.4 → 3.5.0-ultramodern.41

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 (214) 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 +18 -82
  5. package/dist/cjs/runtime/contextHelpers.js +137 -0
  6. package/dist/cjs/runtime/core.js +29 -132
  7. package/dist/cjs/runtime/i18n/backend/defaults.node.js +7 -7
  8. package/dist/cjs/runtime/i18n/detection/cache.js +150 -0
  9. package/dist/cjs/runtime/i18n/detection/detector.js +100 -0
  10. package/dist/cjs/runtime/i18n/detection/index.js +8 -263
  11. package/dist/cjs/runtime/i18n/detection/initOptions.js +69 -0
  12. package/dist/cjs/runtime/i18n/detection/language.js +62 -0
  13. package/dist/cjs/runtime/i18n/detection/path.js +49 -0
  14. package/dist/cjs/runtime/i18n/detection/priority.js +66 -0
  15. package/dist/cjs/runtime/i18n/detection/ssr.js +70 -0
  16. package/dist/cjs/runtime/i18n/detection/types.js +18 -0
  17. package/dist/cjs/runtime/i18n/instance.js +7 -7
  18. package/dist/cjs/runtime/linkHelpers.js +148 -0
  19. package/dist/cjs/runtime/pluginSetup.js +102 -0
  20. package/dist/cjs/runtime/providerComposition.js +114 -0
  21. package/dist/cjs/runtime/reactI18next.js +43 -0
  22. package/dist/cjs/runtime/utils.js +1 -9
  23. package/dist/cjs/server/apiPrefix.js +72 -0
  24. package/dist/cjs/server/detectorOptions.js +97 -0
  25. package/dist/cjs/server/index.js +17 -144
  26. package/dist/cjs/server/redirectPolicy.js +96 -0
  27. package/dist/cjs/shared/detection.js +2 -104
  28. package/dist/cjs/shared/localisedUrls/config.js +49 -0
  29. package/dist/cjs/shared/localisedUrls/index.js +91 -0
  30. package/dist/cjs/shared/localisedUrls/normalise.js +87 -0
  31. package/dist/cjs/shared/localisedUrls/pathname.js +68 -0
  32. package/dist/cjs/shared/localisedUrls/patterns.js +130 -0
  33. package/dist/cjs/shared/localisedUrls/redirect.js +95 -0
  34. package/dist/cjs/shared/localisedUrls/resolve.js +88 -0
  35. package/dist/cjs/shared/localisedUrls/routes.js +129 -0
  36. package/dist/cjs/shared/localisedUrls/types.js +18 -0
  37. package/dist/cjs/shared/localisedUrls.js +28 -294
  38. package/dist/cjs/shared/utils.js +2 -8
  39. package/dist/esm/cli/index.mjs +2 -1
  40. package/dist/esm/cli/locales.mjs +13 -13
  41. package/dist/esm/runtime/Link.mjs +1 -82
  42. package/dist/esm/runtime/context.mjs +18 -82
  43. package/dist/esm/runtime/contextHelpers.mjs +84 -0
  44. package/dist/esm/runtime/core.mjs +30 -133
  45. package/dist/esm/runtime/i18n/backend/defaults.node.mjs +5 -5
  46. package/dist/esm/runtime/i18n/detection/cache.mjs +103 -0
  47. package/dist/esm/runtime/i18n/detection/detector.mjs +62 -0
  48. package/dist/esm/runtime/i18n/detection/index.mjs +4 -260
  49. package/dist/esm/runtime/i18n/detection/initOptions.mjs +28 -0
  50. package/dist/esm/runtime/i18n/detection/language.mjs +21 -0
  51. package/dist/esm/runtime/i18n/detection/path.mjs +11 -0
  52. package/dist/esm/runtime/i18n/detection/priority.mjs +28 -0
  53. package/dist/esm/runtime/i18n/detection/ssr.mjs +26 -0
  54. package/dist/esm/runtime/i18n/detection/types.mjs +0 -0
  55. package/dist/esm/runtime/i18n/instance.mjs +8 -5
  56. package/dist/esm/runtime/linkHelpers.mjs +98 -0
  57. package/dist/esm/runtime/pluginSetup.mjs +64 -0
  58. package/dist/esm/runtime/providerComposition.mjs +76 -0
  59. package/dist/esm/runtime/reactI18next.mjs +5 -0
  60. package/dist/esm/runtime/utils.mjs +2 -10
  61. package/dist/esm/server/apiPrefix.mjs +31 -0
  62. package/dist/esm/server/detectorOptions.mjs +59 -0
  63. package/dist/esm/server/index.mjs +8 -135
  64. package/dist/esm/server/redirectPolicy.mjs +46 -0
  65. package/dist/esm/shared/detection.mjs +1 -71
  66. package/dist/esm/shared/localisedUrls/config.mjs +11 -0
  67. package/dist/esm/shared/localisedUrls/index.mjs +7 -0
  68. package/dist/esm/shared/localisedUrls/normalise.mjs +37 -0
  69. package/dist/esm/shared/localisedUrls/pathname.mjs +24 -0
  70. package/dist/esm/shared/localisedUrls/patterns.mjs +86 -0
  71. package/dist/esm/shared/localisedUrls/redirect.mjs +48 -0
  72. package/dist/esm/shared/localisedUrls/resolve.mjs +47 -0
  73. package/dist/esm/shared/localisedUrls/routes.mjs +88 -0
  74. package/dist/esm/shared/localisedUrls/types.mjs +0 -0
  75. package/dist/esm/shared/localisedUrls.mjs +1 -283
  76. package/dist/esm/shared/utils.mjs +1 -1
  77. package/dist/esm-node/cli/index.mjs +2 -1
  78. package/dist/esm-node/cli/locales.mjs +13 -13
  79. package/dist/esm-node/runtime/Link.mjs +1 -82
  80. package/dist/esm-node/runtime/context.mjs +18 -82
  81. package/dist/esm-node/runtime/contextHelpers.mjs +85 -0
  82. package/dist/esm-node/runtime/core.mjs +30 -133
  83. package/dist/esm-node/runtime/i18n/backend/defaults.node.mjs +5 -5
  84. package/dist/esm-node/runtime/i18n/detection/cache.mjs +104 -0
  85. package/dist/esm-node/runtime/i18n/detection/detector.mjs +63 -0
  86. package/dist/esm-node/runtime/i18n/detection/index.mjs +4 -260
  87. package/dist/esm-node/runtime/i18n/detection/initOptions.mjs +29 -0
  88. package/dist/esm-node/runtime/i18n/detection/language.mjs +22 -0
  89. package/dist/esm-node/runtime/i18n/detection/path.mjs +12 -0
  90. package/dist/esm-node/runtime/i18n/detection/priority.mjs +29 -0
  91. package/dist/esm-node/runtime/i18n/detection/ssr.mjs +27 -0
  92. package/dist/esm-node/runtime/i18n/detection/types.mjs +1 -0
  93. package/dist/esm-node/runtime/i18n/instance.mjs +8 -5
  94. package/dist/esm-node/runtime/linkHelpers.mjs +99 -0
  95. package/dist/esm-node/runtime/pluginSetup.mjs +65 -0
  96. package/dist/esm-node/runtime/providerComposition.mjs +77 -0
  97. package/dist/esm-node/runtime/reactI18next.mjs +6 -0
  98. package/dist/esm-node/runtime/utils.mjs +2 -10
  99. package/dist/esm-node/server/apiPrefix.mjs +32 -0
  100. package/dist/esm-node/server/detectorOptions.mjs +60 -0
  101. package/dist/esm-node/server/index.mjs +8 -135
  102. package/dist/esm-node/server/redirectPolicy.mjs +47 -0
  103. package/dist/esm-node/shared/detection.mjs +1 -71
  104. package/dist/esm-node/shared/localisedUrls/config.mjs +12 -0
  105. package/dist/esm-node/shared/localisedUrls/index.mjs +8 -0
  106. package/dist/esm-node/shared/localisedUrls/normalise.mjs +38 -0
  107. package/dist/esm-node/shared/localisedUrls/pathname.mjs +25 -0
  108. package/dist/esm-node/shared/localisedUrls/patterns.mjs +87 -0
  109. package/dist/esm-node/shared/localisedUrls/redirect.mjs +49 -0
  110. package/dist/esm-node/shared/localisedUrls/resolve.mjs +48 -0
  111. package/dist/esm-node/shared/localisedUrls/routes.mjs +89 -0
  112. package/dist/esm-node/shared/localisedUrls/types.mjs +1 -0
  113. package/dist/esm-node/shared/localisedUrls.mjs +1 -283
  114. package/dist/esm-node/shared/utils.mjs +1 -1
  115. package/dist/types/cli/locales.d.ts +1 -1
  116. package/dist/types/runtime/Link.d.ts +3 -7
  117. package/dist/types/runtime/context.d.ts +6 -5
  118. package/dist/types/runtime/contextHelpers.d.ts +28 -0
  119. package/dist/types/runtime/core.d.ts +3 -7
  120. package/dist/types/runtime/hooks.d.ts +5 -0
  121. package/dist/types/runtime/i18n/backend/middleware.common.d.ts +2 -1
  122. package/dist/types/runtime/i18n/detection/cache.d.ts +14 -0
  123. package/dist/types/runtime/i18n/detection/detector.d.ts +8 -0
  124. package/dist/types/runtime/i18n/detection/index.d.ts +5 -50
  125. package/dist/types/runtime/i18n/detection/initOptions.d.ts +10 -0
  126. package/dist/types/runtime/i18n/detection/language.d.ts +11 -0
  127. package/dist/types/runtime/i18n/detection/middleware.d.ts +4 -4
  128. package/dist/types/runtime/i18n/detection/middleware.node.d.ts +4 -4
  129. package/dist/types/runtime/i18n/detection/path.d.ts +5 -0
  130. package/dist/types/runtime/i18n/detection/priority.d.ts +10 -0
  131. package/dist/types/runtime/i18n/detection/ssr.d.ts +9 -0
  132. package/dist/types/runtime/i18n/detection/types.d.ts +32 -0
  133. package/dist/types/runtime/i18n/instance.d.ts +28 -26
  134. package/dist/types/runtime/i18n/react-i18next.d.ts +1 -6
  135. package/dist/types/runtime/i18n/utils.d.ts +14 -5
  136. package/dist/types/runtime/linkHelpers.d.ts +17 -0
  137. package/dist/types/runtime/pluginSetup.d.ts +32 -0
  138. package/dist/types/runtime/providerComposition.d.ts +16 -0
  139. package/dist/types/runtime/reactI18next.d.ts +7 -0
  140. package/dist/types/runtime/routerAdapter.d.ts +7 -6
  141. package/dist/types/runtime/utils.d.ts +7 -2
  142. package/dist/types/server/apiPrefix.d.ts +7 -0
  143. package/dist/types/server/detectorOptions.d.ts +21 -0
  144. package/dist/types/server/index.d.ts +1 -6
  145. package/dist/types/server/redirectPolicy.d.ts +22 -0
  146. package/dist/types/shared/detection.d.ts +1 -11
  147. package/dist/types/shared/localisedUrls/config.d.ts +9 -0
  148. package/dist/types/shared/localisedUrls/index.d.ts +9 -0
  149. package/dist/types/shared/localisedUrls/normalise.d.ts +10 -0
  150. package/dist/types/shared/localisedUrls/pathname.d.ts +4 -0
  151. package/dist/types/shared/localisedUrls/patterns.d.ts +5 -0
  152. package/dist/types/shared/localisedUrls/redirect.d.ts +11 -0
  153. package/dist/types/shared/localisedUrls/resolve.d.ts +7 -0
  154. package/dist/types/shared/localisedUrls/routes.d.ts +3 -0
  155. package/dist/types/shared/localisedUrls/types.d.ts +14 -0
  156. package/dist/types/shared/localisedUrls.d.ts +2 -36
  157. package/dist/types/shared/utils.d.ts +0 -2
  158. package/package.json +16 -18
  159. package/rstest.config.mts +1 -0
  160. package/src/cli/index.ts +5 -4
  161. package/src/cli/locales.ts +3 -3
  162. package/src/runtime/Link.tsx +11 -138
  163. package/src/runtime/context.tsx +45 -199
  164. package/src/runtime/contextHelpers.ts +232 -0
  165. package/src/runtime/core.tsx +43 -274
  166. package/src/runtime/hooks.ts +13 -2
  167. package/src/runtime/i18n/backend/defaults.node.ts +2 -2
  168. package/src/runtime/i18n/backend/middleware.common.ts +5 -4
  169. package/src/runtime/i18n/detection/cache.ts +189 -0
  170. package/src/runtime/i18n/detection/detector.ts +166 -0
  171. package/src/runtime/i18n/detection/index.ts +10 -641
  172. package/src/runtime/i18n/detection/initOptions.ts +74 -0
  173. package/src/runtime/i18n/detection/language.ts +64 -0
  174. package/src/runtime/i18n/detection/middleware.node.ts +26 -7
  175. package/src/runtime/i18n/detection/middleware.ts +15 -7
  176. package/src/runtime/i18n/detection/path.ts +41 -0
  177. package/src/runtime/i18n/detection/priority.ts +82 -0
  178. package/src/runtime/i18n/detection/ssr.ts +47 -0
  179. package/src/runtime/i18n/detection/types.ts +41 -0
  180. package/src/runtime/i18n/instance.ts +56 -31
  181. package/src/runtime/i18n/react-i18next.ts +1 -6
  182. package/src/runtime/i18n/utils.ts +18 -9
  183. package/src/runtime/linkHelpers.ts +174 -0
  184. package/src/runtime/pluginSetup.ts +189 -0
  185. package/src/runtime/providerComposition.tsx +144 -0
  186. package/src/runtime/reactI18next.ts +20 -0
  187. package/src/runtime/routerAdapter.tsx +6 -6
  188. package/src/runtime/utils.ts +13 -35
  189. package/src/server/apiPrefix.ts +67 -0
  190. package/src/server/detectorOptions.ts +105 -0
  191. package/src/server/index.ts +14 -319
  192. package/src/server/redirectPolicy.ts +127 -0
  193. package/src/shared/detection.ts +1 -1
  194. package/src/shared/localisedUrls/config.ts +18 -0
  195. package/src/shared/localisedUrls/index.ts +24 -0
  196. package/src/shared/localisedUrls/normalise.ts +67 -0
  197. package/src/shared/localisedUrls/pathname.ts +60 -0
  198. package/src/shared/localisedUrls/patterns.ts +160 -0
  199. package/src/shared/localisedUrls/redirect.ts +91 -0
  200. package/src/shared/localisedUrls/resolve.ts +135 -0
  201. package/src/shared/localisedUrls/routes.ts +226 -0
  202. package/src/shared/localisedUrls/types.ts +18 -0
  203. package/src/shared/localisedUrls.ts +26 -623
  204. package/src/shared/utils.ts +2 -2
  205. package/tests/fixtures/localised-routes.golden.json +156 -0
  206. package/tests/link.test.tsx +111 -0
  207. package/tests/linkTypes.test.ts +15 -4
  208. package/tests/localisedUrlRewriteMatrix.fork.test.ts +147 -0
  209. package/tests/localisedUrls.test.ts +129 -2
  210. package/tests/reactI18nextRuntimeBoundary.test.ts +6 -3
  211. package/tests/redirectPolicy.test.ts +43 -0
  212. package/tests/routerAdapter.test.tsx +85 -0
  213. package/tests/type-fixture/fixture-globals.d.ts +11 -0
  214. package/tests/type-fixture/tsconfig.json +1 -0
@@ -0,0 +1,14 @@
1
+ export type LocalisedRoute = {
2
+ type: 'nested' | 'page';
3
+ path?: string;
4
+ id?: string;
5
+ children?: LocalisedRoute[];
6
+ [key: string]: any;
7
+ };
8
+ export type LocalisedUrlPathMap = Record<string, string>;
9
+ export type LocalisedUrlsMap = Record<string, LocalisedUrlPathMap>;
10
+ export type LocalisedUrlsOption = boolean | LocalisedUrlsMap;
11
+ export interface ResolvedLocalisedUrlsConfig {
12
+ enabled: boolean;
13
+ map: LocalisedUrlsMap;
14
+ }
@@ -1,36 +1,2 @@
1
- import type { NestedRouteForCli, PageRoute } from '@modern-js/types';
2
- export type LocalisedUrlPathMap = Record<string, string>;
3
- export type LocalisedUrlsMap = Record<string, LocalisedUrlPathMap>;
4
- export type LocalisedUrlsOption = boolean | LocalisedUrlsMap;
5
- export interface ResolvedLocalisedUrlsConfig {
6
- enabled: boolean;
7
- map: LocalisedUrlsMap;
8
- }
9
- export declare const normalisePathPattern: (path: string) => string;
10
- /**
11
- * Normalise a concrete request pathname: slash cleanup only. Unlike
12
- * {@link normalisePathPattern} it must not rewrite literal `[x]` segments to
13
- * `:x` params — pathnames are values, not patterns.
14
- */
15
- export declare const normalisePathname: (pathname: string) => string;
16
- /**
17
- * Localised URLs are strictly opt-in: only an explicit, non-empty map enables
18
- * route expansion and validation. `true`, `false`, an empty map and absence
19
- * all resolve to disabled, so upstream-style configs (`localePathRedirect` +
20
- * `languages` without a map) keep plain locale-prefix behavior instead of
21
- * failing the build for every route missing from a map they never wrote.
22
- */
23
- export declare const resolveLocalisedUrlsConfig: (option: LocalisedUrlsOption | undefined) => ResolvedLocalisedUrlsConfig;
24
- export declare const validateLocalisedUrls: (routes: (NestedRouteForCli | PageRoute)[], languages: string[], localisedUrls: LocalisedUrlsMap) => void;
25
- export declare const applyLocalisedUrlsToRoutes: (routes: (NestedRouteForCli | PageRoute)[], languages: string[], localisedUrls: LocalisedUrlsMap) => (NestedRouteForCli | PageRoute)[];
26
- export declare const matchPathPattern: (pathname: string, pattern: string) => Record<string, string> | null;
27
- export declare const buildPathFromPattern: (pattern: string, params: Record<string, string>) => string;
28
- export declare const resolveLocalisedPath: (pathname: string, targetLanguage: string, languages: string[], localisedUrls: LocalisedUrlsMap) => string;
29
- /**
30
- * Reverse-map a language-specific pathname (without language prefix) back to
31
- * the canonical, language-agnostic path: localized slug patterns are matched
32
- * against every language variant and rebuilt from the canonical map key.
33
- */
34
- export declare const resolveCanonicalLocalisedPath: (pathname: string, languages: string[], localisedUrls: LocalisedUrlsMap) => string;
35
- export declare const localiseTargetPathname: (pathname: string, language: string, languages: string[], localisedUrls?: LocalisedUrlsOption) => string;
36
- export declare const canonicalTargetPathname: (pathname: string, languages: string[], localisedUrls?: LocalisedUrlsOption) => string;
1
+ export type { LocaleRedirectSkipRule, LocalisedRoute, LocalisedUrlPathMap, LocalisedUrlsMap, LocalisedUrlsOption, ResolvedLocalisedUrlsConfig, } from './localisedUrls/index';
2
+ export { applyLocalisedUrlsToRoutes, buildPathFromPattern, canonicalTargetPathname, DEFAULT_LOCALE_REDIRECT_SKIP_RULES, isDefaultLocaleRedirectSkipPath, localiseTargetPathname, matchesPathPrefix, matchPathPattern, normalisePathname, normalisePathPattern, resolveCanonicalLocalisedPath, resolveLocalisedPath, resolveLocalisedUrlsConfig, shouldSkipLocaleRedirect, stripLanguagePrefix, validateLocalisedUrls, } from './localisedUrls/index';
@@ -1,5 +1,3 @@
1
1
  import type { BaseBackendOptions, BaseLocaleDetectionOptions } from './type';
2
- export declare function getEntryConfig<T extends Record<string, any>>(entryName: string, config: T, entryKey: string): T | undefined;
3
- export declare function removeEntryConfigKey<T extends Record<string, any>>(config: T, entryKey: string): Omit<T, typeof entryKey>;
4
2
  export declare function getLocaleDetectionOptions(entryName: string, localeDetection: BaseLocaleDetectionOptions): BaseLocaleDetectionOptions;
5
3
  export declare function getBackendOptions(entryName: string, backend: BaseBackendOptions): BaseBackendOptions;
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "modern",
18
18
  "modern.js"
19
19
  ],
20
- "version": "3.5.0-ultramodern.4",
20
+ "version": "3.5.0-ultramodern.41",
21
21
  "engines": {
22
22
  "node": ">=20"
23
23
  },
@@ -97,19 +97,18 @@
97
97
  "i18next-fs-backend": "^2.6.6",
98
98
  "i18next-http-backend": "^4.0.0",
99
99
  "i18next-http-middleware": "^3.9.7",
100
- "@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.5.0-ultramodern.4",
101
- "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.5.0-ultramodern.4",
102
- "@modern-js/server-runtime": "npm:@bleedingdev/modern-js-server-runtime@3.5.0-ultramodern.4",
103
- "@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.5.0-ultramodern.4",
104
- "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.5.0-ultramodern.4",
105
- "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.5.0-ultramodern.4"
100
+ "@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.5.0-ultramodern.41",
101
+ "@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.5.0-ultramodern.41",
102
+ "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.5.0-ultramodern.41",
103
+ "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.5.0-ultramodern.41",
104
+ "@modern-js/server-runtime": "npm:@bleedingdev/modern-js-server-runtime@3.5.0-ultramodern.41"
106
105
  },
107
106
  "peerDependencies": {
108
- "@modern-js/runtime": "3.5.0-ultramodern.4",
107
+ "@modern-js/runtime": "3.5.0-ultramodern.41",
109
108
  "i18next": ">=26.3.1",
110
109
  "react": "^19.2.7",
111
110
  "react-dom": "^19.2.7",
112
- "react-i18next": "^17.0.8"
111
+ "react-i18next": "^17.0.9"
113
112
  },
114
113
  "peerDependenciesMeta": {
115
114
  "i18next": {
@@ -120,17 +119,16 @@
120
119
  }
121
120
  },
122
121
  "devDependencies": {
123
- "@rslib/core": "0.23.1",
124
- "@types/node": "^26.0.1",
125
- "@typescript/native-preview": "7.0.0-dev.20260628.1",
126
- "i18next": "26.3.3",
122
+ "@rslib/core": "0.23.2",
123
+ "@types/node": "^26.1.1",
124
+ "@typescript/native-preview": "7.0.0-dev.20260707.2",
125
+ "i18next": "26.3.6",
127
126
  "react": "^19.2.7",
128
127
  "react-dom": "^19.2.7",
129
- "react-i18next": "17.0.8",
130
- "ts-node": "^10.9.2",
131
- "typescript": "^6.0.3",
132
- "@modern-js/app-tools": "npm:@bleedingdev/modern-js-app-tools@3.5.0-ultramodern.4",
133
- "@modern-js/runtime": "npm:@bleedingdev/modern-js-runtime@3.5.0-ultramodern.4"
128
+ "react-i18next": "17.0.9",
129
+ "typescript": "^7.0.2",
130
+ "@modern-js/app-tools": "npm:@bleedingdev/modern-js-app-tools@3.5.0-ultramodern.41",
131
+ "@modern-js/runtime": "npm:@bleedingdev/modern-js-runtime@3.5.0-ultramodern.41"
134
132
  },
135
133
  "sideEffects": false,
136
134
  "publishConfig": {
package/rstest.config.mts CHANGED
@@ -29,6 +29,7 @@ export default {
29
29
  include: [
30
30
  'tests/i18nUtils.test.ts',
31
31
  'tests/localisedUrls.test.ts',
32
+ 'tests/localisedUrlRewriteMatrix.fork.test.ts',
32
33
  'tests/linkTypes.test.ts',
33
34
  'tests/backendDefaults.test.ts',
34
35
  'tests/reactI18nextRuntimeBoundary.test.ts',
package/src/cli/index.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
1
3
  import type { AppTools, CliPlugin } from '@modern-js/app-tools';
2
4
  import { getPublicDirRoutePrefixes } from '@modern-js/server-core';
3
5
  import type {
@@ -5,8 +7,6 @@ import type {
5
7
  NestedRouteForCli,
6
8
  PageRoute,
7
9
  } from '@modern-js/types';
8
- import fs from 'fs';
9
- import path from 'path';
10
10
  import {
11
11
  applyLocalisedUrlsToRoutes,
12
12
  resolveLocalisedUrlsConfig,
@@ -126,9 +126,10 @@ export const i18nPlugin = (
126
126
  backend: backendOptions,
127
127
  ...extendedConfig,
128
128
  };
129
+ const { reactI18next } = extendedConfig as { reactI18next?: boolean };
129
130
  const runtimePluginPath =
130
131
  customPlugin?.runtime?.path ||
131
- (config.reactI18next === false
132
+ (reactI18next === false
132
133
  ? `@${metaName}/plugin-i18n/runtime/no-react-i18next`
133
134
  : `@${metaName}/plugin-i18n/runtime`);
134
135
 
@@ -173,7 +174,7 @@ export const i18nPlugin = (
173
174
  routes as (NestedRouteForCli | PageRoute)[],
174
175
  languages,
175
176
  localisedUrlsConfig.map,
176
- ),
177
+ ) as (NestedRouteForCli | PageRoute)[],
177
178
  };
178
179
  });
179
180
 
@@ -1,10 +1,10 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
1
3
  import {
2
4
  getPublicDirRoutePrefixes,
3
5
  normalizePublicDir,
4
6
  normalizePublicDirPath,
5
7
  } from '@modern-js/server-core';
6
- import fs from 'fs';
7
- import path from 'path';
8
8
  import type { BackendOptions } from '../shared/type';
9
9
 
10
10
  interface NormalizedConfigForLocales {
@@ -13,7 +13,7 @@ interface NormalizedConfigForLocales {
13
13
  };
14
14
  }
15
15
 
16
- export interface DetectedLocalesDirectory {
16
+ interface DetectedLocalesDirectory {
17
17
  loadPath: string;
18
18
  addPath: string;
19
19
  serverLoadPath: string;
@@ -6,96 +6,22 @@ import type {
6
6
  ValidateLinkTo,
7
7
  } from './canonicalRoutes';
8
8
  import { useModernI18n } from './context';
9
+ import {
10
+ interpolateRouteParams,
11
+ type LinkParams,
12
+ mergeClassNames,
13
+ normalizeSearch,
14
+ splitActiveProps,
15
+ warnOnce,
16
+ } from './linkHelpers';
9
17
  import { canonicalPath, type LocalizedPathsConfig } from './localizedPaths';
10
18
  import { useI18nRouterAdapter } from './routerAdapter';
11
19
  import { buildLocalizedUrl, splitUrlTarget } from './utils';
12
20
 
13
- const EXTERNAL_TARGET_RE = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
14
-
15
- const warnedTargets = new Set<string>();
16
-
17
- const warnOnce = (key: string, message: string) => {
18
- if (process.env.NODE_ENV !== 'development' || warnedTargets.has(key)) {
19
- return;
20
- }
21
- warnedTargets.add(key);
22
- console.warn(message);
23
- };
24
-
25
- export type LinkParams = Record<string, string | number | undefined>;
26
-
27
- /**
28
- * Interpolate `$param`, `:param`, optional (`{-$param}` / `:param?`) and splat
29
- * (`$` / `*`) segments with concrete values before localization, so
30
- * pattern-mapped slugs localize correctly.
31
- */
32
- export const interpolateRouteParams = (
33
- pathname: string,
34
- params?: LinkParams,
35
- ): string => {
36
- if (!/[$:*{]/.test(pathname)) {
37
- return pathname;
38
- }
39
-
40
- const resolveParam = (name: string): string | undefined => {
41
- const value = params?.[name];
42
- return value === undefined ? undefined : String(value);
43
- };
44
-
45
- const segments = pathname
46
- .split('/')
47
- .map(segment => {
48
- if (!segment) {
49
- return segment;
50
- }
51
-
52
- if (segment.startsWith('{-$') && segment.endsWith('}')) {
53
- const value = resolveParam(segment.slice(3, -1));
54
- return value === undefined ? null : encodeURIComponent(value);
55
- }
56
-
57
- if (segment === '$' || segment === '*') {
58
- const value = resolveParam('_splat') ?? resolveParam('*');
59
- return value === undefined
60
- ? null
61
- : value.split('/').map(encodeURIComponent).join('/');
62
- }
63
-
64
- if (segment.startsWith('$')) {
65
- const value = resolveParam(segment.slice(1));
66
- if (value === undefined) {
67
- warnOnce(
68
- `missing-param:${pathname}:${segment}`,
69
- `[plugin-i18n] <Link to="${pathname}"> is missing required param "${segment.slice(1)}".`,
70
- );
71
- return segment;
72
- }
73
- return encodeURIComponent(value);
74
- }
75
-
76
- if (segment.startsWith(':')) {
77
- const optional = segment.endsWith('?');
78
- const name = segment.slice(1, optional ? -1 : undefined);
79
- const value = resolveParam(name);
80
- if (value === undefined) {
81
- if (optional) {
82
- return null;
83
- }
84
- warnOnce(
85
- `missing-param:${pathname}:${segment}`,
86
- `[plugin-i18n] <Link to="${pathname}"> is missing required param "${name}".`,
87
- );
88
- return segment;
89
- }
90
- return encodeURIComponent(value);
91
- }
21
+ export type { LinkParams };
22
+ export { interpolateRouteParams };
92
23
 
93
- return segment;
94
- })
95
- .filter(segment => segment !== null);
96
-
97
- return segments.join('/') || '/';
98
- };
24
+ const EXTERNAL_TARGET_RE = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
99
25
 
100
26
  export interface LinkActiveOptions {
101
27
  /**
@@ -142,59 +68,6 @@ export type LinkProps<TTo extends string = string> = LinkBaseProps & {
142
68
  } & ValidateLinkTo<TTo> &
143
69
  LinkParamsProp<LinkTargetPathname<TTo>>;
144
70
 
145
- const normalizeSearch = (
146
- search: string | Record<string, unknown> | undefined,
147
- searchFromTo: string,
148
- ): {
149
- searchString: string;
150
- searchObject: Record<string, string> | undefined;
151
- } => {
152
- if (search && typeof search === 'object') {
153
- const entries = Object.entries(search).filter(
154
- ([, value]) => value !== undefined && value !== null,
155
- );
156
- const searchObject = Object.fromEntries(
157
- entries.map(([key, value]) => [key, String(value)]),
158
- );
159
- const params = new URLSearchParams(searchObject);
160
- const serialized = params.toString();
161
- return {
162
- searchString: serialized ? `?${serialized}` : '',
163
- searchObject,
164
- };
165
- }
166
-
167
- const raw = typeof search === 'string' && search ? search : searchFromTo;
168
- if (!raw) {
169
- return { searchString: '', searchObject: undefined };
170
- }
171
-
172
- const searchString = raw.startsWith('?') ? raw : `?${raw}`;
173
- const searchObject: Record<string, string> = {};
174
- new URLSearchParams(searchString).forEach((value, key) => {
175
- searchObject[key] = value;
176
- });
177
-
178
- return { searchString, searchObject };
179
- };
180
-
181
- const splitActiveProps = (
182
- active: boolean,
183
- activeProps?: LinkBaseProps['activeProps'],
184
- ) => {
185
- if (!active || !activeProps) {
186
- return {};
187
- }
188
- return activeProps;
189
- };
190
-
191
- const mergeClassNames = (...values: Array<unknown>): string | undefined => {
192
- const classNames = values.filter(
193
- (value): value is string => typeof value === 'string' && value.length > 0,
194
- );
195
- return classNames.length > 0 ? classNames.join(' ') : undefined;
196
- };
197
-
198
71
  /**
199
72
  * The standard UltraModern link: a vanilla link in every respect except that
200
73
  * it localizes canonical, language-agnostic paths automatically.