@depup/next-intl 4.8.3-depup.0

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 (296) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +33 -0
  3. package/changes.json +18 -0
  4. package/config.d.ts +4 -0
  5. package/dist/cjs/development/ExtractorCodec-D9Tw618d.cjs +7 -0
  6. package/dist/cjs/development/JSONCodec-rhejs716.cjs +50 -0
  7. package/dist/cjs/development/POCodec-Cv3VdXQG.cjs +105 -0
  8. package/dist/cjs/development/plugin-YzBhQjAo.cjs +1457 -0
  9. package/dist/cjs/development/plugin.cjs +13 -0
  10. package/dist/esm/development/config.js +5 -0
  11. package/dist/esm/development/extractor/ExtractionCompiler.js +38 -0
  12. package/dist/esm/development/extractor/catalog/CatalogLocales.js +84 -0
  13. package/dist/esm/development/extractor/catalog/CatalogManager.js +370 -0
  14. package/dist/esm/development/extractor/catalog/CatalogPersister.js +63 -0
  15. package/dist/esm/development/extractor/catalog/SaveScheduler.js +85 -0
  16. package/dist/esm/development/extractor/catalogLoader.js +96 -0
  17. package/dist/esm/development/extractor/extractMessages.js +15 -0
  18. package/dist/esm/development/extractor/extractionLoader.js +26 -0
  19. package/dist/esm/development/extractor/extractor/LRUCache.js +30 -0
  20. package/dist/esm/development/extractor/extractor/MessageExtractor.js +66 -0
  21. package/dist/esm/development/extractor/format/ExtractorCodec.js +5 -0
  22. package/dist/esm/development/extractor/format/codecs/JSONCodec.js +42 -0
  23. package/dist/esm/development/extractor/format/codecs/POCodec.js +93 -0
  24. package/dist/esm/development/extractor/format/index.js +44 -0
  25. package/dist/esm/development/extractor/source/SourceFileFilter.js +29 -0
  26. package/dist/esm/development/extractor/source/SourceFileScanner.js +31 -0
  27. package/dist/esm/development/extractor/source/SourceFileWatcher.js +132 -0
  28. package/dist/esm/development/extractor/utils.js +46 -0
  29. package/dist/esm/development/extractor.js +2 -0
  30. package/dist/esm/development/index.react-client.js +4 -0
  31. package/dist/esm/development/index.react-server.js +9 -0
  32. package/dist/esm/development/middleware/getAlternateLinksHeaderValue.js +91 -0
  33. package/dist/esm/development/middleware/middleware.js +168 -0
  34. package/dist/esm/development/middleware/resolveLocale.js +129 -0
  35. package/dist/esm/development/middleware/syncCookie.js +27 -0
  36. package/dist/esm/development/middleware/utils.js +194 -0
  37. package/dist/esm/development/middleware.js +1 -0
  38. package/dist/esm/development/navigation/react-client/createNavigation.js +80 -0
  39. package/dist/esm/development/navigation/react-client/useBasePathname.js +36 -0
  40. package/dist/esm/development/navigation/react-server/createNavigation.js +22 -0
  41. package/dist/esm/development/navigation/react-server/getServerLocale.js +12 -0
  42. package/dist/esm/development/navigation/shared/BaseLink.js +51 -0
  43. package/dist/esm/development/navigation/shared/createSharedNavigationFns.js +105 -0
  44. package/dist/esm/development/navigation/shared/syncLocaleCookie.js +47 -0
  45. package/dist/esm/development/navigation/shared/utils.js +165 -0
  46. package/dist/esm/development/navigation.react-client.js +1 -0
  47. package/dist/esm/development/navigation.react-server.js +1 -0
  48. package/dist/esm/development/plugin/config.js +10 -0
  49. package/dist/esm/development/plugin/createNextIntlPlugin.js +26 -0
  50. package/dist/esm/development/plugin/declaration/createMessagesDeclaration.js +70 -0
  51. package/dist/esm/development/plugin/extractor/initExtractionCompiler.js +59 -0
  52. package/dist/esm/development/plugin/getNextConfig.js +267 -0
  53. package/dist/esm/development/plugin/nextFlags.js +32 -0
  54. package/dist/esm/development/plugin/utils.js +26 -0
  55. package/dist/esm/development/plugin/watchFile.js +21 -0
  56. package/dist/esm/development/plugin.js +1 -0
  57. package/dist/esm/development/react-client/index.js +34 -0
  58. package/dist/esm/development/react-server/NextIntlClientProviderServer.js +34 -0
  59. package/dist/esm/development/react-server/useConfig.js +21 -0
  60. package/dist/esm/development/react-server/useExtracted.js +9 -0
  61. package/dist/esm/development/react-server/useFormatter.js +9 -0
  62. package/dist/esm/development/react-server/useLocale.js +8 -0
  63. package/dist/esm/development/react-server/useMessages.js +9 -0
  64. package/dist/esm/development/react-server/useNow.js +12 -0
  65. package/dist/esm/development/react-server/useTimeZone.js +8 -0
  66. package/dist/esm/development/react-server/useTranslations.js +9 -0
  67. package/dist/esm/development/routing/config.js +26 -0
  68. package/dist/esm/development/routing/defineRouting.js +25 -0
  69. package/dist/esm/development/routing.js +1 -0
  70. package/dist/esm/development/server/react-client/index.js +32 -0
  71. package/dist/esm/development/server/react-server/RequestLocale.js +36 -0
  72. package/dist/esm/development/server/react-server/RequestLocaleCache.js +18 -0
  73. package/dist/esm/development/server/react-server/createRequestConfig.js +2 -0
  74. package/dist/esm/development/server/react-server/getConfig.js +59 -0
  75. package/dist/esm/development/server/react-server/getConfigNow.js +10 -0
  76. package/dist/esm/development/server/react-server/getDefaultNow.js +9 -0
  77. package/dist/esm/development/server/react-server/getExtracted.js +24 -0
  78. package/dist/esm/development/server/react-server/getFormats.js +10 -0
  79. package/dist/esm/development/server/react-server/getFormatter.js +21 -0
  80. package/dist/esm/development/server/react-server/getLocale.js +10 -0
  81. package/dist/esm/development/server/react-server/getMessages.js +19 -0
  82. package/dist/esm/development/server/react-server/getNow.js +8 -0
  83. package/dist/esm/development/server/react-server/getRequestConfig.js +8 -0
  84. package/dist/esm/development/server/react-server/getServerExtractor.js +38 -0
  85. package/dist/esm/development/server/react-server/getServerFormatter.js +17 -0
  86. package/dist/esm/development/server/react-server/getServerTranslator.js +12 -0
  87. package/dist/esm/development/server/react-server/getTimeZone.js +13 -0
  88. package/dist/esm/development/server/react-server/getTranslations.js +28 -0
  89. package/dist/esm/development/server/react-server/validateLocale.js +12 -0
  90. package/dist/esm/development/server.react-client.js +1 -0
  91. package/dist/esm/development/server.react-server.js +9 -0
  92. package/dist/esm/development/shared/NextIntlClientProvider.js +18 -0
  93. package/dist/esm/development/shared/constants.js +4 -0
  94. package/dist/esm/development/shared/use.js +13 -0
  95. package/dist/esm/development/shared/utils.js +140 -0
  96. package/dist/esm/production/config.js +1 -0
  97. package/dist/esm/production/extractor/ExtractionCompiler.js +1 -0
  98. package/dist/esm/production/extractor/catalog/CatalogLocales.js +1 -0
  99. package/dist/esm/production/extractor/catalog/CatalogManager.js +1 -0
  100. package/dist/esm/production/extractor/catalog/CatalogPersister.js +1 -0
  101. package/dist/esm/production/extractor/catalog/SaveScheduler.js +1 -0
  102. package/dist/esm/production/extractor/catalogLoader.js +1 -0
  103. package/dist/esm/production/extractor/extractMessages.js +1 -0
  104. package/dist/esm/production/extractor/extractionLoader.js +1 -0
  105. package/dist/esm/production/extractor/extractor/LRUCache.js +1 -0
  106. package/dist/esm/production/extractor/extractor/MessageExtractor.js +1 -0
  107. package/dist/esm/production/extractor/format/ExtractorCodec.js +1 -0
  108. package/dist/esm/production/extractor/format/codecs/JSONCodec.js +1 -0
  109. package/dist/esm/production/extractor/format/codecs/POCodec.js +1 -0
  110. package/dist/esm/production/extractor/format/index.js +1 -0
  111. package/dist/esm/production/extractor/source/SourceFileFilter.js +1 -0
  112. package/dist/esm/production/extractor/source/SourceFileScanner.js +1 -0
  113. package/dist/esm/production/extractor/source/SourceFileWatcher.js +1 -0
  114. package/dist/esm/production/extractor/utils.js +1 -0
  115. package/dist/esm/production/extractor.js +1 -0
  116. package/dist/esm/production/index.react-client.js +1 -0
  117. package/dist/esm/production/index.react-server.js +1 -0
  118. package/dist/esm/production/middleware/getAlternateLinksHeaderValue.js +1 -0
  119. package/dist/esm/production/middleware/middleware.js +1 -0
  120. package/dist/esm/production/middleware/resolveLocale.js +1 -0
  121. package/dist/esm/production/middleware/syncCookie.js +1 -0
  122. package/dist/esm/production/middleware/utils.js +1 -0
  123. package/dist/esm/production/middleware.js +1 -0
  124. package/dist/esm/production/navigation/react-client/createNavigation.js +1 -0
  125. package/dist/esm/production/navigation/react-client/useBasePathname.js +1 -0
  126. package/dist/esm/production/navigation/react-server/createNavigation.js +1 -0
  127. package/dist/esm/production/navigation/react-server/getServerLocale.js +1 -0
  128. package/dist/esm/production/navigation/shared/BaseLink.js +2 -0
  129. package/dist/esm/production/navigation/shared/createSharedNavigationFns.js +1 -0
  130. package/dist/esm/production/navigation/shared/syncLocaleCookie.js +1 -0
  131. package/dist/esm/production/navigation/shared/utils.js +1 -0
  132. package/dist/esm/production/navigation.react-client.js +1 -0
  133. package/dist/esm/production/navigation.react-server.js +1 -0
  134. package/dist/esm/production/plugin/config.js +1 -0
  135. package/dist/esm/production/plugin/createNextIntlPlugin.js +1 -0
  136. package/dist/esm/production/plugin/declaration/createMessagesDeclaration.js +1 -0
  137. package/dist/esm/production/plugin/extractor/initExtractionCompiler.js +1 -0
  138. package/dist/esm/production/plugin/getNextConfig.js +1 -0
  139. package/dist/esm/production/plugin/nextFlags.js +1 -0
  140. package/dist/esm/production/plugin/utils.js +1 -0
  141. package/dist/esm/production/plugin/watchFile.js +1 -0
  142. package/dist/esm/production/plugin.js +1 -0
  143. package/dist/esm/production/react-client/index.js +1 -0
  144. package/dist/esm/production/react-server/NextIntlClientProviderServer.js +1 -0
  145. package/dist/esm/production/react-server/useConfig.js +1 -0
  146. package/dist/esm/production/react-server/useExtracted.js +1 -0
  147. package/dist/esm/production/react-server/useFormatter.js +1 -0
  148. package/dist/esm/production/react-server/useLocale.js +1 -0
  149. package/dist/esm/production/react-server/useMessages.js +1 -0
  150. package/dist/esm/production/react-server/useNow.js +1 -0
  151. package/dist/esm/production/react-server/useTimeZone.js +1 -0
  152. package/dist/esm/production/react-server/useTranslations.js +1 -0
  153. package/dist/esm/production/routing/config.js +1 -0
  154. package/dist/esm/production/routing/defineRouting.js +1 -0
  155. package/dist/esm/production/routing.js +1 -0
  156. package/dist/esm/production/server/react-client/index.js +1 -0
  157. package/dist/esm/production/server/react-server/RequestLocale.js +1 -0
  158. package/dist/esm/production/server/react-server/RequestLocaleCache.js +1 -0
  159. package/dist/esm/production/server/react-server/createRequestConfig.js +1 -0
  160. package/dist/esm/production/server/react-server/getConfig.js +1 -0
  161. package/dist/esm/production/server/react-server/getConfigNow.js +1 -0
  162. package/dist/esm/production/server/react-server/getDefaultNow.js +1 -0
  163. package/dist/esm/production/server/react-server/getExtracted.js +1 -0
  164. package/dist/esm/production/server/react-server/getFormats.js +1 -0
  165. package/dist/esm/production/server/react-server/getFormatter.js +1 -0
  166. package/dist/esm/production/server/react-server/getLocale.js +1 -0
  167. package/dist/esm/production/server/react-server/getMessages.js +1 -0
  168. package/dist/esm/production/server/react-server/getNow.js +1 -0
  169. package/dist/esm/production/server/react-server/getRequestConfig.js +1 -0
  170. package/dist/esm/production/server/react-server/getServerExtractor.js +1 -0
  171. package/dist/esm/production/server/react-server/getServerFormatter.js +1 -0
  172. package/dist/esm/production/server/react-server/getServerTranslator.js +1 -0
  173. package/dist/esm/production/server/react-server/getTimeZone.js +1 -0
  174. package/dist/esm/production/server/react-server/getTranslations.js +1 -0
  175. package/dist/esm/production/server.react-client.js +1 -0
  176. package/dist/esm/production/server.react-server.js +1 -0
  177. package/dist/esm/production/shared/NextIntlClientProvider.js +2 -0
  178. package/dist/esm/production/shared/constants.js +1 -0
  179. package/dist/esm/production/shared/use.js +1 -0
  180. package/dist/esm/production/shared/utils.js +1 -0
  181. package/dist/types/config.d.ts +1 -0
  182. package/dist/types/extractor/ExtractionCompiler.d.ts +15 -0
  183. package/dist/types/extractor/catalog/CatalogLocales.d.ts +29 -0
  184. package/dist/types/extractor/catalog/CatalogManager.d.ts +59 -0
  185. package/dist/types/extractor/catalog/CatalogPersister.d.ts +20 -0
  186. package/dist/types/extractor/catalog/SaveScheduler.d.ts +18 -0
  187. package/dist/types/extractor/extractMessages.d.ts +2 -0
  188. package/dist/types/extractor/extractor/KeyGenerator.d.ts +3 -0
  189. package/dist/types/extractor/extractor/LRUCache.d.ts +7 -0
  190. package/dist/types/extractor/extractor/MessageExtractor.bench.d.ts +1 -0
  191. package/dist/types/extractor/extractor/MessageExtractor.d.ts +21 -0
  192. package/dist/types/extractor/format/ExtractorCodec.d.ts +33 -0
  193. package/dist/types/extractor/format/codecs/JSONCodec.d.ts +2 -0
  194. package/dist/types/extractor/format/codecs/POCodec.d.ts +2 -0
  195. package/dist/types/extractor/format/codecs/fixtures/JSONCodecStructured.d.ts +2 -0
  196. package/dist/types/extractor/format/codecs/fixtures/POCodecSourceMessageKey.d.ts +2 -0
  197. package/dist/types/extractor/format/index.d.ts +15 -0
  198. package/dist/types/extractor/format/types.d.ts +8 -0
  199. package/dist/types/extractor/index.d.ts +2 -0
  200. package/dist/types/extractor/source/SourceFileFilter.d.ts +8 -0
  201. package/dist/types/extractor/source/SourceFileScanner.d.ts +4 -0
  202. package/dist/types/extractor/source/SourceFileWatcher.d.ts +15 -0
  203. package/dist/types/extractor/types.d.ts +28 -0
  204. package/dist/types/extractor/utils.d.ts +7 -0
  205. package/dist/types/extractor.d.ts +1 -0
  206. package/dist/types/index.react-client.d.ts +8 -0
  207. package/dist/types/index.react-server.d.ts +1 -0
  208. package/dist/types/middleware/getAlternateLinksHeaderValue.d.ts +13 -0
  209. package/dist/types/middleware/index.d.ts +4 -0
  210. package/dist/types/middleware/middleware.d.ts +4 -0
  211. package/dist/types/middleware/resolveLocale.d.ts +9 -0
  212. package/dist/types/middleware/syncCookie.d.ts +7 -0
  213. package/dist/types/middleware/utils.d.ts +26 -0
  214. package/dist/types/middleware.d.ts +1 -0
  215. package/dist/types/navigation/react-client/createNavigation.d.ts +464 -0
  216. package/dist/types/navigation/react-client/index.d.ts +2 -0
  217. package/dist/types/navigation/react-client/useBasePathname.d.ts +5 -0
  218. package/dist/types/navigation/react-server/createNavigation.d.ts +384 -0
  219. package/dist/types/navigation/react-server/getServerLocale.d.ts +5 -0
  220. package/dist/types/navigation/react-server/index.d.ts +2 -0
  221. package/dist/types/navigation/shared/BaseLink.d.ts +11 -0
  222. package/dist/types/navigation/shared/StrictParams.d.ts +8 -0
  223. package/dist/types/navigation/shared/createSharedNavigationFns.d.ts +370 -0
  224. package/dist/types/navigation/shared/syncLocaleCookie.d.ts +8 -0
  225. package/dist/types/navigation/shared/utils.d.ts +53 -0
  226. package/dist/types/navigation.react-client.d.ts +1 -0
  227. package/dist/types/navigation.react-server.d.ts +1 -0
  228. package/dist/types/plugin/catalog/catalogLoader.d.ts +10 -0
  229. package/dist/types/plugin/config.d.ts +3 -0
  230. package/dist/types/plugin/createNextIntlPlugin.d.ts +3 -0
  231. package/dist/types/plugin/declaration/createMessagesDeclaration.d.ts +1 -0
  232. package/dist/types/plugin/declaration/index.d.ts +1 -0
  233. package/dist/types/plugin/extractor/extractionLoader.d.ts +3 -0
  234. package/dist/types/plugin/extractor/initExtractionCompiler.d.ts +2 -0
  235. package/dist/types/plugin/getNextConfig.d.ts +3 -0
  236. package/dist/types/plugin/index.d.ts +1 -0
  237. package/dist/types/plugin/nextFlags.d.ts +2 -0
  238. package/dist/types/plugin/types.d.ts +29 -0
  239. package/dist/types/plugin/utils.d.ts +8 -0
  240. package/dist/types/plugin/watchFile.d.ts +6 -0
  241. package/dist/types/plugin.d.ts +1 -0
  242. package/dist/types/react-client/index.d.ts +16 -0
  243. package/dist/types/react-server/NextIntlClientProviderServer.d.ts +5 -0
  244. package/dist/types/react-server/index.d.ts +16 -0
  245. package/dist/types/react-server/testUtils.d.ts +2 -0
  246. package/dist/types/react-server/useConfig.d.ts +2 -0
  247. package/dist/types/react-server/useExtracted.d.ts +2 -0
  248. package/dist/types/react-server/useFormatter.d.ts +2 -0
  249. package/dist/types/react-server/useLocale.d.ts +2 -0
  250. package/dist/types/react-server/useMessages.d.ts +2 -0
  251. package/dist/types/react-server/useNow.d.ts +2 -0
  252. package/dist/types/react-server/useTimeZone.d.ts +2 -0
  253. package/dist/types/react-server/useTranslations.d.ts +2 -0
  254. package/dist/types/routing/config.d.ts +73 -0
  255. package/dist/types/routing/defineRouting.d.ts +3 -0
  256. package/dist/types/routing/index.d.ts +3 -0
  257. package/dist/types/routing/types.d.ts +24 -0
  258. package/dist/types/routing.d.ts +1 -0
  259. package/dist/types/server/react-client/index.d.ts +10 -0
  260. package/dist/types/server/react-server/RequestLocale.d.ts +1 -0
  261. package/dist/types/server/react-server/RequestLocaleCache.d.ts +3 -0
  262. package/dist/types/server/react-server/createRequestConfig.d.ts +3 -0
  263. package/dist/types/server/react-server/getConfig.d.ts +13 -0
  264. package/dist/types/server/react-server/getConfigNow.d.ts +4 -0
  265. package/dist/types/server/react-server/getDefaultNow.d.ts +3 -0
  266. package/dist/types/server/react-server/getExtracted.d.ts +10 -0
  267. package/dist/types/server/react-server/getFormats.d.ts +3 -0
  268. package/dist/types/server/react-server/getFormatter.d.ts +10 -0
  269. package/dist/types/server/react-server/getLocale.d.ts +4 -0
  270. package/dist/types/server/react-server/getMessages.d.ts +6 -0
  271. package/dist/types/server/react-server/getNow.d.ts +4 -0
  272. package/dist/types/server/react-server/getRequestConfig.d.ts +35 -0
  273. package/dist/types/server/react-server/getServerExtractor.d.ts +5 -0
  274. package/dist/types/server/react-server/getServerFormatter.d.ts +25 -0
  275. package/dist/types/server/react-server/getServerTranslator.d.ts +4 -0
  276. package/dist/types/server/react-server/getTimeZone.d.ts +4 -0
  277. package/dist/types/server/react-server/getTranslations.d.ts +8 -0
  278. package/dist/types/server/react-server/index.d.ts +12 -0
  279. package/dist/types/server/react-server/validateLocale.d.ts +1 -0
  280. package/dist/types/server.react-client.d.ts +1 -0
  281. package/dist/types/server.react-server.d.ts +1 -0
  282. package/dist/types/shared/NextIntlClientProvider.d.ts +9 -0
  283. package/dist/types/shared/constants.d.ts +1 -0
  284. package/dist/types/shared/types.d.ts +5 -0
  285. package/dist/types/shared/use.d.ts +3 -0
  286. package/dist/types/shared/utils.d.ts +20 -0
  287. package/extractor/catalogLoader.d.ts +4 -0
  288. package/extractor/extractionLoader.d.ts +4 -0
  289. package/extractor.d.ts +2 -0
  290. package/middleware.d.ts +4 -0
  291. package/navigation.d.ts +2 -0
  292. package/package.json +175 -0
  293. package/plugin.d.cts +3 -0
  294. package/plugin.d.ts +4 -0
  295. package/routing.d.ts +2 -0
  296. package/server.d.ts +2 -0
@@ -0,0 +1,91 @@
1
+ import { normalizeTrailingSlash } from '../shared/utils.js';
2
+ import { getHost, getNormalizedPathname, getLocalePrefixes, isLocaleSupportedOnDomain, applyBasePath, formatTemplatePathname } from './utils.js';
3
+
4
+ /**
5
+ * See https://developers.google.com/search/docs/specialty/international/localized-versions
6
+ */
7
+ function getAlternateLinksHeaderValue({
8
+ internalTemplateName,
9
+ localizedPathnames,
10
+ request,
11
+ resolvedLocale,
12
+ routing
13
+ }) {
14
+ const normalizedUrl = request.nextUrl.clone();
15
+ const host = getHost(request.headers);
16
+ if (host) {
17
+ normalizedUrl.port = '';
18
+ normalizedUrl.host = host;
19
+ }
20
+ normalizedUrl.protocol = request.headers.get('x-forwarded-proto') ?? normalizedUrl.protocol;
21
+ normalizedUrl.pathname = getNormalizedPathname(normalizedUrl.pathname, routing.locales, routing.localePrefix);
22
+ function getAlternateEntry(url, locale) {
23
+ url.pathname = normalizeTrailingSlash(url.pathname);
24
+ if (request.nextUrl.basePath) {
25
+ url = new URL(url);
26
+ url.pathname = applyBasePath(url.pathname, request.nextUrl.basePath);
27
+ }
28
+ return `<${url.toString()}>; rel="alternate"; hreflang="${locale}"`;
29
+ }
30
+ function getLocalizedPathname(pathname, locale) {
31
+ if (localizedPathnames && typeof localizedPathnames === 'object') {
32
+ const sourceTemplate = localizedPathnames[resolvedLocale];
33
+ return formatTemplatePathname(pathname, sourceTemplate ?? internalTemplateName, localizedPathnames[locale] ?? internalTemplateName);
34
+ } else {
35
+ return pathname;
36
+ }
37
+ }
38
+ const links = getLocalePrefixes(routing.locales, routing.localePrefix, false).flatMap(([locale, prefix]) => {
39
+ function prefixPathname(pathname) {
40
+ if (pathname === '/') {
41
+ return prefix;
42
+ } else {
43
+ return prefix + pathname;
44
+ }
45
+ }
46
+ let url;
47
+ if (routing.domains) {
48
+ const domainConfigs = routing.domains.filter(cur => isLocaleSupportedOnDomain(locale, cur));
49
+ return domainConfigs.map(domainConfig => {
50
+ url = new URL(normalizedUrl);
51
+ url.port = '';
52
+ url.host = domainConfig.domain;
53
+
54
+ // Important: Use `normalizedUrl` here, as `url` potentially uses
55
+ // a `basePath` that automatically gets applied to the pathname
56
+ url.pathname = getLocalizedPathname(normalizedUrl.pathname, locale);
57
+ if (locale !== domainConfig.defaultLocale || routing.localePrefix.mode === 'always') {
58
+ url.pathname = prefixPathname(url.pathname);
59
+ }
60
+ return getAlternateEntry(url, locale);
61
+ });
62
+ } else {
63
+ let pathname;
64
+ if (localizedPathnames && typeof localizedPathnames === 'object') {
65
+ pathname = getLocalizedPathname(normalizedUrl.pathname, locale);
66
+ } else {
67
+ pathname = normalizedUrl.pathname;
68
+ }
69
+ if (locale !== routing.defaultLocale || routing.localePrefix.mode === 'always') {
70
+ pathname = prefixPathname(pathname);
71
+ }
72
+ url = new URL(pathname, normalizedUrl);
73
+ }
74
+ return getAlternateEntry(url, locale);
75
+ });
76
+
77
+ // Add x-default entry
78
+ const shouldAddXDefault =
79
+ // For domain-based routing there is no reasonable x-default
80
+ !routing.domains || routing.domains.length === 0;
81
+ if (shouldAddXDefault) {
82
+ const localizedPathname = getLocalizedPathname(normalizedUrl.pathname, routing.defaultLocale);
83
+ if (localizedPathname) {
84
+ const url = new URL(localizedPathname, normalizedUrl);
85
+ links.push(getAlternateEntry(url, 'x-default'));
86
+ }
87
+ }
88
+ return links.join(', ');
89
+ }
90
+
91
+ export { getAlternateLinksHeaderValue as default };
@@ -0,0 +1,168 @@
1
+ import { NextResponse } from 'next/server';
2
+ import { receiveRoutingConfig } from '../routing/config.js';
3
+ import { HEADER_LOCALE_NAME } from '../shared/constants.js';
4
+ import { matchesPathname, normalizeTrailingSlash, getLocalePrefix, getLocalizedTemplate } from '../shared/utils.js';
5
+ import getAlternateLinksHeaderValue from './getAlternateLinksHeaderValue.js';
6
+ import resolveLocale from './resolveLocale.js';
7
+ import syncCookie from './syncCookie.js';
8
+ import { sanitizePathname, isLocaleSupportedOnDomain, getNormalizedPathname, getPathnameMatch, getInternalTemplate, formatTemplatePathname, formatPathname, getBestMatchingDomain, applyBasePath, getLocaleAsPrefix } from './utils.js';
9
+
10
+ function createMiddleware(routing) {
11
+ const resolvedRouting = receiveRoutingConfig(routing);
12
+ return function middleware(request) {
13
+ let unsafeExternalPathname;
14
+ try {
15
+ // Resolve potential foreign symbols (e.g. /ja/%E7%B4%84 → /ja/約))
16
+ unsafeExternalPathname = decodeURI(request.nextUrl.pathname);
17
+ } catch {
18
+ // In case an invalid pathname is encountered, forward
19
+ // it to Next.js which in turn responds with a 400
20
+ return NextResponse.next();
21
+ }
22
+
23
+ // Sanitize malicious URIs to prevent open redirect attacks due to
24
+ // decodeURI doesn't escape encoded backslashes ('%5C' & '%5c')
25
+ const externalPathname = sanitizePathname(unsafeExternalPathname);
26
+ const {
27
+ domain,
28
+ locale
29
+ } = resolveLocale(resolvedRouting, request.headers, request.cookies, externalPathname);
30
+ const hasMatchedDefaultLocale = domain ? domain.defaultLocale === locale : locale === resolvedRouting.defaultLocale;
31
+ const domainsConfig = resolvedRouting.domains?.filter(curDomain => isLocaleSupportedOnDomain(locale, curDomain)) || [];
32
+ const hasUnknownHost = resolvedRouting.domains != null && !domain;
33
+ function next(url) {
34
+ const urlObj = new URL(url, request.url);
35
+ if (request.nextUrl.basePath) {
36
+ urlObj.pathname = applyBasePath(urlObj.pathname, request.nextUrl.basePath);
37
+ }
38
+ const headers = new Headers(request.headers);
39
+ headers.set(HEADER_LOCALE_NAME, locale);
40
+ const isRewriteNecessary = normalizeTrailingSlash(request.nextUrl.pathname) !== normalizeTrailingSlash(urlObj.pathname);
41
+ if (isRewriteNecessary) {
42
+ return NextResponse.rewrite(urlObj, {
43
+ request: {
44
+ headers
45
+ }
46
+ });
47
+ } else {
48
+ return NextResponse.next({
49
+ request: {
50
+ headers
51
+ }
52
+ });
53
+ }
54
+ }
55
+ function redirect(url, redirectDomain) {
56
+ const urlObj = new URL(url, request.url);
57
+ urlObj.pathname = normalizeTrailingSlash(urlObj.pathname);
58
+ if (domainsConfig.length > 0 && !redirectDomain && domain) {
59
+ const bestMatchingDomain = getBestMatchingDomain(domain, locale, domainsConfig);
60
+ if (bestMatchingDomain) {
61
+ redirectDomain = bestMatchingDomain.domain;
62
+ if (bestMatchingDomain.defaultLocale === locale && resolvedRouting.localePrefix.mode === 'as-needed') {
63
+ urlObj.pathname = getNormalizedPathname(urlObj.pathname, resolvedRouting.locales, resolvedRouting.localePrefix);
64
+ }
65
+ }
66
+ }
67
+ if (redirectDomain) {
68
+ urlObj.host = redirectDomain;
69
+ if (request.headers.get('x-forwarded-host')) {
70
+ urlObj.protocol = request.headers.get('x-forwarded-proto') ?? request.nextUrl.protocol;
71
+ const redirectDomainPort = redirectDomain.split(':')[1];
72
+ urlObj.port = redirectDomainPort ?? request.headers.get('x-forwarded-port') ?? '';
73
+ }
74
+ }
75
+ if (request.nextUrl.basePath) {
76
+ urlObj.pathname = applyBasePath(urlObj.pathname, request.nextUrl.basePath);
77
+ }
78
+ hasRedirected = true;
79
+ return NextResponse.redirect(urlObj.toString());
80
+ }
81
+ const unprefixedExternalPathname = getNormalizedPathname(externalPathname, resolvedRouting.locales, resolvedRouting.localePrefix);
82
+ const pathnameMatch = getPathnameMatch(externalPathname, resolvedRouting.locales, resolvedRouting.localePrefix, domain);
83
+ const hasLocalePrefix = pathnameMatch != null;
84
+ const isUnprefixedRouting = resolvedRouting.localePrefix.mode === 'never' || hasMatchedDefaultLocale && resolvedRouting.localePrefix.mode === 'as-needed';
85
+ let response;
86
+ let internalTemplateName;
87
+ let hasRedirected;
88
+ let unprefixedInternalPathname = unprefixedExternalPathname;
89
+ const pathnames = resolvedRouting.pathnames;
90
+ if (pathnames) {
91
+ let resolvedTemplateLocale;
92
+ [resolvedTemplateLocale, internalTemplateName] = getInternalTemplate(pathnames, unprefixedExternalPathname, locale);
93
+ if (internalTemplateName) {
94
+ const pathnameConfig = pathnames[internalTemplateName];
95
+ const localeTemplate = getLocalizedTemplate(pathnameConfig, locale, internalTemplateName);
96
+ if (matchesPathname(localeTemplate, unprefixedExternalPathname)) {
97
+ unprefixedInternalPathname = formatTemplatePathname(unprefixedExternalPathname, localeTemplate, internalTemplateName);
98
+ } else {
99
+ let sourceTemplate;
100
+ if (resolvedTemplateLocale) {
101
+ // A localized pathname from another locale has matched
102
+ sourceTemplate = getLocalizedTemplate(pathnameConfig, resolvedTemplateLocale, internalTemplateName);
103
+ } else {
104
+ // An internal pathname has matched that
105
+ // doesn't have a localized pathname
106
+ sourceTemplate = internalTemplateName;
107
+ }
108
+ const localePrefix = isUnprefixedRouting ? undefined : getLocalePrefix(locale, resolvedRouting.localePrefix);
109
+ const template = formatTemplatePathname(unprefixedExternalPathname, sourceTemplate, localeTemplate);
110
+ response = redirect(formatPathname(template, localePrefix, request.nextUrl.search));
111
+ }
112
+ }
113
+ }
114
+ if (!response) {
115
+ if (unprefixedInternalPathname === '/' && !hasLocalePrefix) {
116
+ if (isUnprefixedRouting) {
117
+ response = next(formatPathname(unprefixedInternalPathname, getLocaleAsPrefix(locale), request.nextUrl.search));
118
+ } else {
119
+ response = redirect(formatPathname(unprefixedExternalPathname, getLocalePrefix(locale, resolvedRouting.localePrefix), request.nextUrl.search));
120
+ }
121
+ } else {
122
+ const internalHref = formatPathname(unprefixedInternalPathname, getLocaleAsPrefix(locale), request.nextUrl.search);
123
+ if (hasLocalePrefix) {
124
+ const externalHref = formatPathname(unprefixedExternalPathname, pathnameMatch.prefix, request.nextUrl.search);
125
+ if (resolvedRouting.localePrefix.mode === 'never') {
126
+ response = redirect(formatPathname(unprefixedExternalPathname, undefined, request.nextUrl.search));
127
+ } else if (pathnameMatch.exact) {
128
+ if (hasMatchedDefaultLocale && isUnprefixedRouting) {
129
+ response = redirect(formatPathname(unprefixedExternalPathname, undefined, request.nextUrl.search));
130
+ } else {
131
+ if (resolvedRouting.domains) {
132
+ const pathDomain = getBestMatchingDomain(domain, pathnameMatch.locale, domainsConfig);
133
+ if (domain?.domain !== pathDomain?.domain && !hasUnknownHost) {
134
+ response = redirect(externalHref, pathDomain?.domain);
135
+ } else {
136
+ response = next(internalHref);
137
+ }
138
+ } else {
139
+ response = next(internalHref);
140
+ }
141
+ }
142
+ } else {
143
+ response = redirect(externalHref);
144
+ }
145
+ } else {
146
+ if (isUnprefixedRouting) {
147
+ response = next(internalHref);
148
+ } else {
149
+ response = redirect(formatPathname(unprefixedExternalPathname, getLocalePrefix(locale, resolvedRouting.localePrefix), request.nextUrl.search));
150
+ }
151
+ }
152
+ }
153
+ }
154
+ syncCookie(request, response, locale, resolvedRouting, domain);
155
+ if (!hasRedirected && resolvedRouting.localePrefix.mode !== 'never' && resolvedRouting.alternateLinks && resolvedRouting.locales.length > 1) {
156
+ response.headers.set('Link', getAlternateLinksHeaderValue({
157
+ routing: resolvedRouting,
158
+ internalTemplateName,
159
+ localizedPathnames: internalTemplateName != null && pathnames ? pathnames[internalTemplateName] : undefined,
160
+ request,
161
+ resolvedLocale: locale
162
+ }));
163
+ }
164
+ return response;
165
+ };
166
+ }
167
+
168
+ export { createMiddleware as default };
@@ -0,0 +1,129 @@
1
+ import { match } from '@formatjs/intl-localematcher';
2
+ import Negotiator from 'negotiator';
3
+ import { getPathnameMatch, isLocaleSupportedOnDomain, getHost } from './utils.js';
4
+
5
+ function findDomainFromHost(requestHeaders, domains) {
6
+ const host = getHost(requestHeaders);
7
+ if (host) {
8
+ return domains.find(cur => cur.domain === host);
9
+ }
10
+ return undefined;
11
+ }
12
+ function orderLocales(locales) {
13
+ // Workaround for https://github.com/formatjs/formatjs/issues/4469
14
+ return locales.slice().sort((a, b) => b.length - a.length);
15
+ }
16
+ function mapToProvidedLocale(locales, locale) {
17
+ return locales.find(cur => cur.toLowerCase() === locale.toLowerCase());
18
+ }
19
+ function getAcceptLanguageLocale(requestHeaders, locales, defaultLocale) {
20
+ let locale;
21
+ const languages = new Negotiator({
22
+ headers: {
23
+ 'accept-language': requestHeaders.get('accept-language') || undefined
24
+ }
25
+ }).languages();
26
+ try {
27
+ const orderedLocales = orderLocales(locales);
28
+ locale = mapToProvidedLocale(locales, match(languages, orderedLocales, defaultLocale));
29
+ } catch {
30
+ // Invalid language
31
+ }
32
+ return locale;
33
+ }
34
+ function getLocaleFromCookie(routing, requestCookies) {
35
+ if (routing.localeCookie && requestCookies.has(routing.localeCookie.name)) {
36
+ const value = requestCookies.get(routing.localeCookie.name)?.value;
37
+ if (value && routing.locales.includes(value)) {
38
+ return value;
39
+ }
40
+ }
41
+ }
42
+ function resolveLocaleFromPrefix(routing, requestHeaders, requestCookies, pathname) {
43
+ let locale;
44
+
45
+ // Prio 1: Use route prefix
46
+ if (pathname) {
47
+ locale = getPathnameMatch(pathname, routing.locales, routing.localePrefix)?.locale;
48
+ }
49
+
50
+ // Prio 2: Use existing cookie
51
+ if (!locale && routing.localeDetection) {
52
+ locale = getLocaleFromCookie(routing, requestCookies);
53
+ }
54
+
55
+ // Prio 3: Use the `accept-language` header
56
+ if (!locale && routing.localeDetection) {
57
+ locale = getAcceptLanguageLocale(requestHeaders, routing.locales, routing.defaultLocale);
58
+ }
59
+
60
+ // Prio 4: Use default locale
61
+ if (!locale) {
62
+ locale = routing.defaultLocale;
63
+ }
64
+ return locale;
65
+ }
66
+ function resolveLocaleFromDomain(routing, requestHeaders, requestCookies, pathname) {
67
+ const domains = routing.domains;
68
+ const domain = findDomainFromHost(requestHeaders, domains);
69
+ if (!domain) {
70
+ return {
71
+ locale: resolveLocaleFromPrefix(routing, requestHeaders, requestCookies, pathname)
72
+ };
73
+ }
74
+ let locale;
75
+
76
+ // Prio 1: Use route prefix
77
+ if (pathname) {
78
+ const prefixLocale = getPathnameMatch(pathname, routing.locales, routing.localePrefix, domain)?.locale;
79
+ if (prefixLocale) {
80
+ if (isLocaleSupportedOnDomain(prefixLocale, domain)) {
81
+ locale = prefixLocale;
82
+ } else {
83
+ // Causes a redirect to a domain that supports the locale
84
+ return {
85
+ locale: prefixLocale,
86
+ domain
87
+ };
88
+ }
89
+ }
90
+ }
91
+
92
+ // Prio 2: Use existing cookie
93
+ if (!locale && routing.localeDetection) {
94
+ const cookieLocale = getLocaleFromCookie(routing, requestCookies);
95
+ if (cookieLocale) {
96
+ if (isLocaleSupportedOnDomain(cookieLocale, domain)) {
97
+ locale = cookieLocale;
98
+ }
99
+ }
100
+ }
101
+
102
+ // Prio 3: Use the `accept-language` header
103
+ if (!locale && routing.localeDetection) {
104
+ const headerLocale = getAcceptLanguageLocale(requestHeaders, domain.locales, domain.defaultLocale);
105
+ if (headerLocale) {
106
+ locale = headerLocale;
107
+ }
108
+ }
109
+
110
+ // Prio 4: Use default locale
111
+ if (!locale) {
112
+ locale = domain.defaultLocale;
113
+ }
114
+ return {
115
+ locale,
116
+ domain
117
+ };
118
+ }
119
+ function resolveLocale(routing, requestHeaders, requestCookies, pathname) {
120
+ if (routing.domains) {
121
+ return resolveLocaleFromDomain(routing, requestHeaders, requestCookies, pathname);
122
+ } else {
123
+ return {
124
+ locale: resolveLocaleFromPrefix(routing, requestHeaders, requestCookies, pathname)
125
+ };
126
+ }
127
+ }
128
+
129
+ export { resolveLocale as default, getAcceptLanguageLocale };
@@ -0,0 +1,27 @@
1
+ import { getAcceptLanguageLocale } from './resolveLocale.js';
2
+
3
+ function syncCookie(request, response, locale, routing, domain) {
4
+ if (!routing.localeCookie) return;
5
+ const {
6
+ name,
7
+ ...rest
8
+ } = routing.localeCookie;
9
+ const hasLocaleCookie = request.cookies.has(name);
10
+ const hasOutdatedCookie = hasLocaleCookie && request.cookies.get(name)?.value !== locale;
11
+ if (hasOutdatedCookie) {
12
+ response.cookies.set(name, locale, {
13
+ path: request.nextUrl.basePath || undefined,
14
+ ...rest
15
+ });
16
+ } else if (!hasLocaleCookie) {
17
+ const acceptLanguageLocale = getAcceptLanguageLocale(request.headers, domain?.locales || routing.locales, routing.defaultLocale);
18
+ if (acceptLanguageLocale !== locale) {
19
+ response.cookies.set(name, locale, {
20
+ path: request.nextUrl.basePath || undefined,
21
+ ...rest
22
+ });
23
+ }
24
+ }
25
+ }
26
+
27
+ export { syncCookie as default };
@@ -0,0 +1,194 @@
1
+ import { normalizeTrailingSlash, getSortedPathnames, matchesPathname, prefixPathname, getLocalePrefix, templateToRegex, getLocalizedTemplate } from '../shared/utils.js';
2
+
3
+ function getInternalTemplate(pathnames, pathname, locale) {
4
+ const sortedPathnames = getSortedPathnames(Object.keys(pathnames));
5
+
6
+ // Try to find a localized pathname that matches
7
+ for (const internalPathname of sortedPathnames) {
8
+ const localizedPathnamesOrPathname = pathnames[internalPathname];
9
+ if (typeof localizedPathnamesOrPathname === 'string') {
10
+ const localizedPathname = localizedPathnamesOrPathname;
11
+ if (matchesPathname(localizedPathname, pathname)) {
12
+ return [undefined, internalPathname];
13
+ }
14
+ } else {
15
+ // Prefer the entry with the current locale in case multiple
16
+ // localized pathnames match the current pathname
17
+ const sortedEntries = Object.entries(localizedPathnamesOrPathname);
18
+ const curLocaleIndex = sortedEntries.findIndex(([entryLocale]) => entryLocale === locale);
19
+ if (curLocaleIndex > 0) {
20
+ sortedEntries.unshift(sortedEntries.splice(curLocaleIndex, 1)[0]);
21
+ }
22
+ for (const [entryLocale] of sortedEntries) {
23
+ const localizedTemplate = getLocalizedTemplate(pathnames[internalPathname], entryLocale, internalPathname);
24
+ if (matchesPathname(localizedTemplate, pathname)) {
25
+ return [entryLocale, internalPathname];
26
+ }
27
+ }
28
+ }
29
+ }
30
+
31
+ // Try to find an internal pathname that matches (this can be the case
32
+ // if all localized pathnames are different from the internal pathnames)
33
+ for (const internalPathname of Object.keys(pathnames)) {
34
+ if (matchesPathname(internalPathname, pathname)) {
35
+ return [undefined, internalPathname];
36
+ }
37
+ }
38
+
39
+ // No match
40
+ return [undefined, undefined];
41
+ }
42
+ function formatTemplatePathname(sourcePathname, sourceTemplate, targetTemplate, prefix) {
43
+ const params = getRouteParams(sourceTemplate, sourcePathname);
44
+ let targetPathname = '';
45
+ targetPathname += formatPathnameTemplate(targetTemplate, params);
46
+
47
+ // A pathname with an optional catchall like `/categories/[[...slug]]`
48
+ // should be normalized to `/categories` if the catchall is not present
49
+ // and no trailing slash is configured
50
+ targetPathname = normalizeTrailingSlash(targetPathname);
51
+ return targetPathname;
52
+ }
53
+
54
+ /**
55
+ * Removes potential prefixes from the pathname.
56
+ */
57
+ function getNormalizedPathname(pathname, locales, localePrefix) {
58
+ // Add trailing slash for consistent handling
59
+ // both for the root as well as nested paths
60
+ if (!pathname.endsWith('/')) {
61
+ pathname += '/';
62
+ }
63
+ const localePrefixes = getLocalePrefixes(locales, localePrefix);
64
+ const regex = new RegExp(`^(${localePrefixes.map(([, prefix]) => prefix.replaceAll('/', '\\/')).join('|')})/(.*)`, 'i');
65
+ const match = pathname.match(regex);
66
+ let result = match ? '/' + match[2] : pathname;
67
+ if (result !== '/') {
68
+ result = normalizeTrailingSlash(result);
69
+ }
70
+ return result;
71
+ }
72
+ function getLocalePrefixes(locales, localePrefix, sort = true) {
73
+ const prefixes = locales.map(locale => [locale, getLocalePrefix(locale, localePrefix)]);
74
+ if (sort) {
75
+ // More specific ones first
76
+ prefixes.sort((a, b) => b[1].length - a[1].length);
77
+ }
78
+ return prefixes;
79
+ }
80
+ function getPathnameMatch(pathname, locales, localePrefix, domain) {
81
+ const localePrefixes = getLocalePrefixes(locales, localePrefix);
82
+
83
+ // Sort to prioritize domain locales
84
+ if (domain) {
85
+ localePrefixes.sort(([localeA], [localeB]) => {
86
+ if (localeA === domain.defaultLocale) return -1;
87
+ if (localeB === domain.defaultLocale) return 1;
88
+ const isLocaleAInDomain = domain.locales.includes(localeA);
89
+ const isLocaleBInDomain = domain.locales.includes(localeB);
90
+ if (isLocaleAInDomain && !isLocaleBInDomain) return -1;
91
+ if (!isLocaleAInDomain && isLocaleBInDomain) return 1;
92
+ return 0;
93
+ });
94
+ }
95
+ for (const [locale, prefix] of localePrefixes) {
96
+ let exact, matches;
97
+ if (pathname === prefix || pathname.startsWith(prefix + '/')) {
98
+ exact = matches = true;
99
+ } else {
100
+ const normalizedPathname = pathname.toLowerCase();
101
+ const normalizedPrefix = prefix.toLowerCase();
102
+ if (normalizedPathname === normalizedPrefix || normalizedPathname.startsWith(normalizedPrefix + '/')) {
103
+ exact = false;
104
+ matches = true;
105
+ }
106
+ }
107
+ if (matches) {
108
+ return {
109
+ locale,
110
+ prefix,
111
+ matchedPrefix: pathname.slice(0, prefix.length),
112
+ exact
113
+ };
114
+ }
115
+ }
116
+ }
117
+ function getRouteParams(template, pathname) {
118
+ const normalizedPathname = normalizeTrailingSlash(pathname);
119
+ const normalizedTemplate = normalizeTrailingSlash(template);
120
+ const regex = templateToRegex(normalizedTemplate);
121
+ const match = regex.exec(normalizedPathname);
122
+ if (!match) return undefined;
123
+ const params = {};
124
+ const keys = normalizedTemplate.match(/\[([^\]]+)\]/g) ?? [];
125
+ for (let i = 1; i < match.length; i++) {
126
+ const rawKey = keys[i - 1];
127
+ if (!rawKey) continue;
128
+ const key = rawKey.replace(/[[\]]/g, '');
129
+ const value = match[i] ?? '';
130
+ params[key] = value;
131
+ }
132
+ return params;
133
+ }
134
+ function formatPathnameTemplate(template, params) {
135
+ if (!params) return template;
136
+
137
+ // Simplify syntax for optional catchall ('[[...slug]]') so
138
+ // we can replace the value with simple interpolation
139
+ template = template.replace(/\[\[/g, '[').replace(/\]\]/g, ']');
140
+ let result = template;
141
+ Object.entries(params).forEach(([key, value]) => {
142
+ result = result.replace(`[${key}]`, value);
143
+ });
144
+ return result;
145
+ }
146
+ function formatPathname(pathname, prefix, search) {
147
+ let result = pathname;
148
+ if (prefix) {
149
+ result = prefixPathname(prefix, result);
150
+ }
151
+ if (search) {
152
+ result += search;
153
+ }
154
+ return result;
155
+ }
156
+ function getHost(requestHeaders) {
157
+ return requestHeaders.get('x-forwarded-host') ?? requestHeaders.get('host') ?? undefined;
158
+ }
159
+ function isLocaleSupportedOnDomain(locale, domain) {
160
+ return domain.defaultLocale === locale || domain.locales.includes(locale);
161
+ }
162
+ function getBestMatchingDomain(curHostDomain, locale, domainsConfig) {
163
+ let domainConfig;
164
+
165
+ // Prio 1: Stay on current domain
166
+ if (curHostDomain && isLocaleSupportedOnDomain(locale, curHostDomain)) {
167
+ domainConfig = curHostDomain;
168
+ }
169
+
170
+ // Prio 2: Use alternative domain with matching default locale
171
+ if (!domainConfig) {
172
+ domainConfig = domainsConfig.find(cur => cur.defaultLocale === locale);
173
+ }
174
+
175
+ // Prio 3: Use alternative domain that supports the locale
176
+ if (!domainConfig) {
177
+ domainConfig = domainsConfig.find(cur => cur.locales.includes(locale));
178
+ }
179
+ return domainConfig;
180
+ }
181
+ function applyBasePath(pathname, basePath) {
182
+ return normalizeTrailingSlash(basePath + pathname);
183
+ }
184
+ function getLocaleAsPrefix(locale) {
185
+ return `/${locale}`;
186
+ }
187
+ function sanitizePathname(pathname) {
188
+ // Sanitize malicious URIs, e.g.:
189
+ // '/en/\\example.org → /en/%5C%5Cexample.org'
190
+ // '/en////example.org → /en/example.org'
191
+ return pathname.replace(/\\/g, '%5C').replace(/\/+/g, '/');
192
+ }
193
+
194
+ export { applyBasePath, formatPathname, formatPathnameTemplate, formatTemplatePathname, getBestMatchingDomain, getHost, getInternalTemplate, getLocaleAsPrefix, getLocalePrefixes, getNormalizedPathname, getPathnameMatch, getRouteParams, isLocaleSupportedOnDomain, sanitizePathname };
@@ -0,0 +1 @@
1
+ export { default } from './middleware/middleware.js';