next-intl 3.14.1 → 3.15.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 (133) hide show
  1. package/dist/development/config.js +1 -1
  2. package/dist/development/middleware/config.js +17 -0
  3. package/dist/development/middleware/getAlternateLinksHeaderValue.js +8 -7
  4. package/dist/development/middleware/middleware.js +69 -83
  5. package/dist/development/middleware/resolveLocale.js +5 -6
  6. package/dist/development/middleware/syncCookie.js +19 -0
  7. package/dist/development/middleware/utils.js +58 -30
  8. package/dist/development/navigation/react-client/ClientLink.js +7 -2
  9. package/dist/development/navigation/react-client/createLocalizedPathnamesNavigation.js +18 -16
  10. package/dist/development/navigation/react-client/createSharedPathnamesNavigation.js +17 -12
  11. package/dist/development/navigation/react-client/redirects.js +32 -0
  12. package/dist/development/navigation/react-client/useBasePathname.js +12 -4
  13. package/dist/development/navigation/react-client/useBaseRouter.js +8 -3
  14. package/dist/development/navigation/react-server/ServerLink.js +7 -1
  15. package/dist/development/navigation/react-server/createLocalizedPathnamesNavigation.js +15 -19
  16. package/dist/development/navigation/react-server/createSharedPathnamesNavigation.js +11 -10
  17. package/dist/development/navigation/react-server/redirects.js +24 -0
  18. package/dist/development/navigation/shared/BaseLink.js +6 -5
  19. package/dist/development/navigation/shared/config.js +30 -0
  20. package/dist/development/navigation/shared/redirects.js +22 -0
  21. package/dist/development/navigation/shared/utils.js +2 -4
  22. package/dist/development/routing/config.js +18 -0
  23. package/dist/development/routing.js +2 -0
  24. package/dist/development/server/react-server/RequestLocale.js +1 -1
  25. package/dist/development/shared/utils.js +26 -14
  26. package/dist/esm/config.js +1 -1
  27. package/dist/esm/middleware/config.js +1 -0
  28. package/dist/esm/middleware/getAlternateLinksHeaderValue.js +1 -1
  29. package/dist/esm/middleware/middleware.js +1 -1
  30. package/dist/esm/middleware/resolveLocale.js +1 -1
  31. package/dist/esm/middleware/syncCookie.js +1 -0
  32. package/dist/esm/middleware/utils.js +1 -1
  33. package/dist/esm/navigation/react-client/ClientLink.js +1 -1
  34. package/dist/esm/navigation/react-client/createLocalizedPathnamesNavigation.js +1 -1
  35. package/dist/esm/navigation/react-client/createSharedPathnamesNavigation.js +1 -1
  36. package/dist/esm/navigation/react-client/redirects.js +1 -0
  37. package/dist/esm/navigation/react-client/useBasePathname.js +1 -1
  38. package/dist/esm/navigation/react-client/useBaseRouter.js +1 -1
  39. package/dist/esm/navigation/react-server/ServerLink.js +1 -1
  40. package/dist/esm/navigation/react-server/createLocalizedPathnamesNavigation.js +1 -1
  41. package/dist/esm/navigation/react-server/createSharedPathnamesNavigation.js +1 -1
  42. package/dist/esm/navigation/react-server/redirects.js +1 -0
  43. package/dist/esm/navigation/shared/BaseLink.js +1 -1
  44. package/dist/esm/navigation/shared/config.js +1 -0
  45. package/dist/esm/navigation/shared/redirects.js +1 -0
  46. package/dist/esm/navigation/shared/utils.js +1 -1
  47. package/dist/esm/routing/config.js +1 -0
  48. package/dist/esm/routing.js +1 -0
  49. package/dist/esm/server/react-server/RequestLocale.js +1 -1
  50. package/dist/esm/shared/utils.js +1 -1
  51. package/dist/production/config.js +1 -1
  52. package/dist/production/middleware/config.js +1 -0
  53. package/dist/production/middleware/getAlternateLinksHeaderValue.js +1 -1
  54. package/dist/production/middleware/middleware.js +1 -1
  55. package/dist/production/middleware/resolveLocale.js +1 -1
  56. package/dist/production/middleware/syncCookie.js +1 -0
  57. package/dist/production/middleware/utils.js +1 -1
  58. package/dist/production/navigation/react-client/ClientLink.js +1 -1
  59. package/dist/production/navigation/react-client/createLocalizedPathnamesNavigation.js +1 -1
  60. package/dist/production/navigation/react-client/createSharedPathnamesNavigation.js +1 -1
  61. package/dist/production/navigation/react-client/redirects.js +1 -0
  62. package/dist/production/navigation/react-client/useBasePathname.js +1 -1
  63. package/dist/production/navigation/react-client/useBaseRouter.js +1 -1
  64. package/dist/production/navigation/react-server/ServerLink.js +1 -1
  65. package/dist/production/navigation/react-server/createLocalizedPathnamesNavigation.js +1 -1
  66. package/dist/production/navigation/react-server/createSharedPathnamesNavigation.js +1 -1
  67. package/dist/production/navigation/react-server/redirects.js +1 -0
  68. package/dist/production/navigation/shared/BaseLink.js +1 -1
  69. package/dist/production/navigation/shared/config.js +1 -0
  70. package/dist/production/navigation/shared/redirects.js +1 -0
  71. package/dist/production/navigation/shared/utils.js +1 -1
  72. package/dist/production/routing/config.js +1 -0
  73. package/dist/production/routing.js +1 -0
  74. package/dist/production/server/react-server/RequestLocale.js +1 -1
  75. package/dist/production/shared/utils.js +1 -1
  76. package/dist/routing.js +7 -0
  77. package/dist/types/src/middleware/config.d.ts +18 -0
  78. package/dist/types/src/middleware/getAlternateLinksHeaderValue.d.ts +6 -6
  79. package/dist/types/src/middleware/middleware.d.ts +3 -3
  80. package/dist/types/src/middleware/resolveLocale.d.ts +6 -6
  81. package/dist/types/src/middleware/syncCookie.d.ts +2 -0
  82. package/dist/types/src/middleware/utils.d.ts +19 -12
  83. package/dist/types/src/navigation/react-client/ClientLink.d.ts +10 -7
  84. package/dist/types/src/navigation/react-client/createLocalizedPathnamesNavigation.d.ts +21 -22
  85. package/dist/types/src/navigation/react-client/createSharedPathnamesNavigation.d.ts +22 -10
  86. package/dist/types/src/navigation/react-client/index.d.ts +3 -1
  87. package/dist/types/src/navigation/react-client/redirects.d.ts +10 -0
  88. package/dist/types/src/navigation/react-client/useBasePathname.d.ts +2 -1
  89. package/dist/types/src/navigation/react-client/useBaseRouter.d.ts +7 -7
  90. package/dist/types/src/navigation/react-server/ServerLink.d.ts +5 -4
  91. package/dist/types/src/navigation/react-server/createLocalizedPathnamesNavigation.d.ts +14 -15
  92. package/dist/types/src/navigation/react-server/createSharedPathnamesNavigation.d.ts +4 -6
  93. package/dist/types/src/navigation/react-server/index.d.ts +1 -1
  94. package/dist/types/src/navigation/react-server/redirects.d.ts +10 -0
  95. package/dist/types/src/navigation/shared/BaseLink.d.ts +3 -2
  96. package/dist/types/src/navigation/shared/config.d.ts +24 -0
  97. package/dist/types/src/navigation/shared/redirects.d.ts +11 -0
  98. package/dist/types/src/navigation/shared/utils.d.ts +10 -10
  99. package/dist/types/src/routing/config.d.ts +14 -0
  100. package/dist/types/src/routing/index.d.ts +2 -0
  101. package/dist/types/src/routing/types.d.ts +23 -0
  102. package/dist/types/src/routing.d.ts +1 -0
  103. package/dist/types/src/shared/types.d.ts +0 -5
  104. package/dist/types/src/shared/utils.d.ts +10 -7
  105. package/package.json +16 -6
  106. package/routing.d.ts +1 -0
  107. package/dist/development/navigation/react-client/clientPermanentRedirect.js +0 -25
  108. package/dist/development/navigation/react-client/clientRedirect.js +0 -25
  109. package/dist/development/navigation/react-server/serverPermanentRedirect.js +0 -19
  110. package/dist/development/navigation/react-server/serverRedirect.js +0 -19
  111. package/dist/development/navigation/shared/basePermanentRedirect.js +0 -16
  112. package/dist/development/navigation/shared/baseRedirect.js +0 -16
  113. package/dist/esm/navigation/react-client/clientPermanentRedirect.js +0 -1
  114. package/dist/esm/navigation/react-client/clientRedirect.js +0 -1
  115. package/dist/esm/navigation/react-server/serverPermanentRedirect.js +0 -1
  116. package/dist/esm/navigation/react-server/serverRedirect.js +0 -1
  117. package/dist/esm/navigation/shared/basePermanentRedirect.js +0 -1
  118. package/dist/esm/navigation/shared/baseRedirect.js +0 -1
  119. package/dist/production/navigation/react-client/clientPermanentRedirect.js +0 -1
  120. package/dist/production/navigation/react-client/clientRedirect.js +0 -1
  121. package/dist/production/navigation/react-server/serverPermanentRedirect.js +0 -1
  122. package/dist/production/navigation/react-server/serverRedirect.js +0 -1
  123. package/dist/production/navigation/shared/basePermanentRedirect.js +0 -1
  124. package/dist/production/navigation/shared/baseRedirect.js +0 -1
  125. package/dist/types/src/middleware/NextIntlMiddlewareConfig.d.ts +0 -31
  126. package/dist/types/src/navigation/react-client/clientPermanentRedirect.d.ts +0 -6
  127. package/dist/types/src/navigation/react-client/clientRedirect.d.ts +0 -6
  128. package/dist/types/src/navigation/react-server/serverPermanentRedirect.d.ts +0 -6
  129. package/dist/types/src/navigation/react-server/serverRedirect.d.ts +0 -6
  130. package/dist/types/src/navigation/shared/basePermanentRedirect.d.ts +0 -7
  131. package/dist/types/src/navigation/shared/baseRedirect.d.ts +0 -7
  132. /package/dist/types/test/navigation/shared/{basePermanentRedirect.test.d.ts → redirects.test.d.ts} +0 -0
  133. /package/dist/types/test/{navigation/shared/baseRedirect.test.d.ts → routing/types.test.d.ts} +0 -0
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  function getConfig() {
6
- throw new Error("Couldn't find next-intl config file. Please follow the instructions at https://next-intl-docs.vercel.app/docs/getting-started/app-router-server-components");
6
+ throw new Error("Couldn't find next-intl config file. Please follow the instructions at https://next-intl-docs.vercel.app/docs/getting-started/app-router");
7
7
  }
8
8
 
9
9
  exports.default = getConfig;
@@ -0,0 +1,17 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var config = require('../routing/config.js');
6
+
7
+ function receiveConfig(input) {
8
+ var _input$alternateLinks, _input$localeDetectio;
9
+ return {
10
+ ...input,
11
+ alternateLinks: (_input$alternateLinks = input === null || input === void 0 ? void 0 : input.alternateLinks) !== null && _input$alternateLinks !== void 0 ? _input$alternateLinks : true,
12
+ localeDetection: (_input$localeDetectio = input === null || input === void 0 ? void 0 : input.localeDetection) !== null && _input$localeDetectio !== void 0 ? _input$localeDetectio : true,
13
+ localePrefix: config.receiveLocalePrefixConfig(input === null || input === void 0 ? void 0 : input.localePrefix)
14
+ };
15
+ }
16
+
17
+ exports.receiveConfig = receiveConfig;
@@ -22,7 +22,7 @@ function getAlternateLinksHeaderValue(_ref) {
22
22
  normalizedUrl.host = host;
23
23
  }
24
24
  normalizedUrl.protocol = (_request$headers$get = request.headers.get('x-forwarded-proto')) !== null && _request$headers$get !== void 0 ? _request$headers$get : normalizedUrl.protocol;
25
- normalizedUrl.pathname = utils.getNormalizedPathname(normalizedUrl.pathname, config.locales);
25
+ normalizedUrl.pathname = utils.getNormalizedPathname(normalizedUrl.pathname, config.locales, config.localePrefix);
26
26
  function getAlternateEntry(url, locale) {
27
27
  if (request.nextUrl.basePath) {
28
28
  url = new URL(url);
@@ -37,12 +37,13 @@ function getAlternateLinksHeaderValue(_ref) {
37
37
  return pathname;
38
38
  }
39
39
  }
40
- const links = config.locales.flatMap(locale => {
40
+ const links = utils.getLocalePrefixes(config.locales, config.localePrefix).flatMap(_ref2 => {
41
+ let [locale, prefix] = _ref2;
41
42
  function prefixPathname(pathname) {
42
43
  if (pathname === '/') {
43
- return "/".concat(locale);
44
+ return prefix;
44
45
  } else {
45
- return "/".concat(locale).concat(pathname);
46
+ return prefix + pathname;
46
47
  }
47
48
  }
48
49
  let url;
@@ -56,7 +57,7 @@ function getAlternateLinksHeaderValue(_ref) {
56
57
  // Important: Use `normalizedUrl` here, as `url` potentially uses
57
58
  // a `basePath` that automatically gets applied to the pathname
58
59
  url.pathname = getLocalizedPathname(normalizedUrl.pathname, locale);
59
- if (locale !== domainConfig.defaultLocale || config.localePrefix === 'always') {
60
+ if (locale !== domainConfig.defaultLocale || config.localePrefix.mode === 'always') {
60
61
  url.pathname = prefixPathname(url.pathname);
61
62
  }
62
63
  return getAlternateEntry(url, locale);
@@ -68,7 +69,7 @@ function getAlternateLinksHeaderValue(_ref) {
68
69
  } else {
69
70
  pathname = normalizedUrl.pathname;
70
71
  }
71
- if (locale !== config.defaultLocale || config.localePrefix === 'always') {
72
+ if (locale !== config.defaultLocale || config.localePrefix.mode === 'always') {
72
73
  pathname = prefixPathname(pathname);
73
74
  }
74
75
  url = new URL(pathname, normalizedUrl);
@@ -79,7 +80,7 @@ function getAlternateLinksHeaderValue(_ref) {
79
80
  // Add x-default entry
80
81
  const shouldAddXDefault =
81
82
  // For domain-based routing there is no reasonable x-default
82
- !config.domains && (config.localePrefix !== 'always' || normalizedUrl.pathname === '/');
83
+ !config.domains && (config.localePrefix.mode !== 'always' || normalizedUrl.pathname === '/');
83
84
  if (shouldAddXDefault) {
84
85
  const url = new URL(getLocalizedPathname(normalizedUrl.pathname, config.defaultLocale), normalizedUrl);
85
86
  links.push(getAlternateEntry(url, 'x-default'));
@@ -5,61 +5,46 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var server = require('next/server');
6
6
  var constants = require('../shared/constants.js');
7
7
  var utils$1 = require('../shared/utils.js');
8
+ var config = require('./config.js');
8
9
  var getAlternateLinksHeaderValue = require('./getAlternateLinksHeaderValue.js');
9
10
  var resolveLocale = require('./resolveLocale.js');
11
+ var syncCookie = require('./syncCookie.js');
10
12
  var utils = require('./utils.js');
11
13
 
12
- const ROOT_URL = '/';
13
- function receiveConfig(config) {
14
- var _config$alternateLink, _config$localePrefix, _config$localeDetecti;
15
- const result = {
16
- ...config,
17
- alternateLinks: (_config$alternateLink = config.alternateLinks) !== null && _config$alternateLink !== void 0 ? _config$alternateLink : true,
18
- localePrefix: (_config$localePrefix = config.localePrefix) !== null && _config$localePrefix !== void 0 ? _config$localePrefix : 'always',
19
- localeDetection: (_config$localeDetecti = config.localeDetection) !== null && _config$localeDetecti !== void 0 ? _config$localeDetecti : true
20
- };
21
- return result;
22
- }
23
- function createMiddleware(config) {
24
- const configWithDefaults = receiveConfig(config);
14
+ function createMiddleware(input) {
15
+ const config$1 = config.receiveConfig(input);
25
16
  return function middleware(request) {
26
- var _request$cookies$get, _configWithDefaults$d;
17
+ var _config$domains;
27
18
  // Resolve potential foreign symbols (e.g. /ja/%E7%B4%84 → /ja/約))
28
- const nextPathname = decodeURI(request.nextUrl.pathname);
19
+ const externalPathname = decodeURI(request.nextUrl.pathname);
29
20
  const {
30
21
  domain,
31
22
  locale
32
- } = resolveLocale.default(configWithDefaults, request.headers, request.cookies, nextPathname);
33
- const hasOutdatedCookie = configWithDefaults.localeDetection && ((_request$cookies$get = request.cookies.get(constants.COOKIE_LOCALE_NAME)) === null || _request$cookies$get === void 0 ? void 0 : _request$cookies$get.value) !== locale;
34
- const hasMatchedDefaultLocale = domain ? domain.defaultLocale === locale : locale === configWithDefaults.defaultLocale;
35
- const domainConfigs = ((_configWithDefaults$d = configWithDefaults.domains) === null || _configWithDefaults$d === void 0 ? void 0 : _configWithDefaults$d.filter(curDomain => utils.isLocaleSupportedOnDomain(locale, curDomain))) || [];
36
- const hasUnknownHost = configWithDefaults.domains != null && !domain;
37
- function getResponseInit() {
38
- const headers = new Headers(request.headers);
39
- headers.set(constants.HEADER_LOCALE_NAME, locale);
40
- return {
41
- request: {
42
- headers
43
- }
44
- };
45
- }
23
+ } = resolveLocale.default(config$1, request.headers, request.cookies, externalPathname);
24
+ const hasMatchedDefaultLocale = domain ? domain.defaultLocale === locale : locale === config$1.defaultLocale;
25
+ const domainConfigs = ((_config$domains = config$1.domains) === null || _config$domains === void 0 ? void 0 : _config$domains.filter(curDomain => utils.isLocaleSupportedOnDomain(locale, curDomain))) || [];
26
+ const hasUnknownHost = config$1.domains != null && !domain;
46
27
  function rewrite(url) {
47
28
  const urlObj = new URL(url, request.url);
48
29
  if (request.nextUrl.basePath) {
49
30
  urlObj.pathname = utils.applyBasePath(urlObj.pathname, request.nextUrl.basePath);
50
31
  }
51
- return server.NextResponse.rewrite(urlObj, getResponseInit());
32
+ const headers = new Headers(request.headers);
33
+ headers.set(constants.HEADER_LOCALE_NAME, locale);
34
+ return server.NextResponse.rewrite(urlObj, {
35
+ request: {
36
+ headers
37
+ }
38
+ });
52
39
  }
53
40
  function redirect(url, redirectDomain) {
54
- const urlObj = new URL(url, request.url);
55
- if (domainConfigs.length > 0) {
56
- if (!redirectDomain) {
57
- const bestMatchingDomain = utils.getBestMatchingDomain(domain, locale, domainConfigs);
58
- if (bestMatchingDomain) {
59
- redirectDomain = bestMatchingDomain.domain;
60
- if (bestMatchingDomain.defaultLocale === locale && configWithDefaults.localePrefix === 'as-needed' && urlObj.pathname.startsWith("/".concat(locale))) {
61
- urlObj.pathname = utils.getNormalizedPathname(urlObj.pathname, configWithDefaults.locales);
62
- }
41
+ const urlObj = new URL(utils.normalizeTrailingSlash(url), request.url);
42
+ if (domainConfigs.length > 0 && !redirectDomain) {
43
+ const bestMatchingDomain = utils.getBestMatchingDomain(domain, locale, domainConfigs);
44
+ if (bestMatchingDomain) {
45
+ redirectDomain = bestMatchingDomain.domain;
46
+ if (bestMatchingDomain.defaultLocale === locale && config$1.localePrefix.mode === 'as-needed') {
47
+ urlObj.pathname = utils.getNormalizedPathname(urlObj.pathname, config$1.locales, config$1.localePrefix);
63
48
  }
64
49
  }
65
50
  }
@@ -76,88 +61,89 @@ function createMiddleware(config) {
76
61
  }
77
62
  return server.NextResponse.redirect(urlObj.toString());
78
63
  }
79
- const normalizedPathname = utils.getNormalizedPathname(nextPathname, configWithDefaults.locales);
80
- const pathLocale = utils.getPathnameLocale(nextPathname, configWithDefaults.locales);
81
- const hasLocalePrefix = pathLocale != null;
64
+ const unprefixedExternalPathname = utils.getNormalizedPathname(externalPathname, config$1.locales, config$1.localePrefix);
65
+ const pathnameMatch = utils.getPathnameMatch(externalPathname, config$1.locales, config$1.localePrefix);
66
+ const hasLocalePrefix = pathnameMatch != null;
67
+ const isUnprefixedRouting = config$1.localePrefix.mode === 'never' || hasMatchedDefaultLocale && config$1.localePrefix.mode === 'as-needed';
82
68
  let response;
83
69
  let internalTemplateName;
84
- let pathname = nextPathname;
85
- if (configWithDefaults.pathnames) {
70
+ let unprefixedInternalPathname = unprefixedExternalPathname;
71
+ if (config$1.pathnames) {
86
72
  let resolvedTemplateLocale;
87
- [resolvedTemplateLocale, internalTemplateName] = utils.getInternalTemplate(configWithDefaults.pathnames, normalizedPathname, locale);
73
+ [resolvedTemplateLocale, internalTemplateName] = utils.getInternalTemplate(config$1.pathnames, unprefixedExternalPathname, locale);
88
74
  if (internalTemplateName) {
89
- const pathnameConfig = configWithDefaults.pathnames[internalTemplateName];
90
- const localeTemplate = typeof pathnameConfig === 'string' ? pathnameConfig : pathnameConfig[locale];
91
- if (utils$1.matchesPathname(localeTemplate, normalizedPathname)) {
92
- pathname = utils.formatTemplatePathname(normalizedPathname, localeTemplate, internalTemplateName, pathLocale);
75
+ const pathnameConfig = config$1.pathnames[internalTemplateName];
76
+ const localeTemplate = typeof pathnameConfig === 'string' ? pathnameConfig :
77
+ // @ts-expect-error This is ok
78
+ pathnameConfig[locale];
79
+ if (utils$1.matchesPathname(localeTemplate, unprefixedExternalPathname)) {
80
+ unprefixedInternalPathname = utils.formatTemplatePathname(unprefixedExternalPathname, localeTemplate, internalTemplateName);
93
81
  } else {
94
82
  let sourceTemplate;
95
83
  if (resolvedTemplateLocale) {
96
84
  // A localized pathname from another locale has matched
97
- sourceTemplate = typeof pathnameConfig === 'string' ? pathnameConfig : pathnameConfig[resolvedTemplateLocale];
85
+ sourceTemplate = typeof pathnameConfig === 'string' ? pathnameConfig :
86
+ // @ts-expect-error This is ok
87
+ pathnameConfig[resolvedTemplateLocale];
98
88
  } else {
99
89
  // An internal pathname has matched that
100
90
  // doesn't have a localized pathname
101
91
  sourceTemplate = internalTemplateName;
102
92
  }
103
- const localePrefix = (hasLocalePrefix || !hasMatchedDefaultLocale) && configWithDefaults.localePrefix !== 'never' ? locale : undefined;
104
- response = redirect(utils.getPathWithSearch(utils.formatTemplatePathname(normalizedPathname, sourceTemplate, localeTemplate, localePrefix), request.nextUrl.search));
93
+ const localePrefix = isUnprefixedRouting ? undefined : utils$1.getLocalePrefix(locale, config$1.localePrefix);
94
+ const template = utils.formatTemplatePathname(unprefixedExternalPathname, sourceTemplate, localeTemplate);
95
+ response = redirect(utils.formatPathname(template, localePrefix, request.nextUrl.search));
105
96
  }
106
97
  }
107
98
  }
108
99
  if (!response) {
109
- if (pathname === ROOT_URL) {
110
- const pathWithSearch = utils.getPathWithSearch("/".concat(locale), request.nextUrl.search);
111
- if (configWithDefaults.localePrefix === 'never' || hasMatchedDefaultLocale && configWithDefaults.localePrefix === 'as-needed') {
112
- response = rewrite(pathWithSearch);
100
+ if (unprefixedInternalPathname === '/' && !hasLocalePrefix) {
101
+ if (isUnprefixedRouting) {
102
+ response = rewrite(utils.formatPathname(unprefixedInternalPathname, utils.getLocaleAsPrefix(locale), request.nextUrl.search));
113
103
  } else {
114
- response = redirect(pathWithSearch);
104
+ response = redirect(utils.formatPathname(unprefixedExternalPathname, utils$1.getLocalePrefix(locale, config$1.localePrefix), request.nextUrl.search));
115
105
  }
116
106
  } else {
117
- const internalPathWithSearch = utils.getPathWithSearch(pathname, request.nextUrl.search);
107
+ const internalHref = utils.formatPathname(unprefixedInternalPathname, utils.getLocaleAsPrefix(locale), request.nextUrl.search);
118
108
  if (hasLocalePrefix) {
119
- const normalizedPathnameWithSearch = utils.getPathWithSearch(normalizedPathname, request.nextUrl.search);
120
- if (configWithDefaults.localePrefix === 'never') {
121
- response = redirect(normalizedPathnameWithSearch);
122
- } else if (pathLocale === locale) {
123
- if (hasMatchedDefaultLocale && configWithDefaults.localePrefix === 'as-needed') {
124
- response = redirect(normalizedPathnameWithSearch);
109
+ const externalHref = utils.formatPathname(unprefixedExternalPathname, pathnameMatch.prefix, request.nextUrl.search);
110
+ if (config$1.localePrefix.mode === 'never') {
111
+ response = redirect(utils.formatPathname(unprefixedExternalPathname, undefined, request.nextUrl.search));
112
+ } else if (pathnameMatch.exact) {
113
+ if (hasMatchedDefaultLocale && isUnprefixedRouting) {
114
+ response = redirect(utils.formatPathname(unprefixedExternalPathname, undefined, request.nextUrl.search));
125
115
  } else {
126
- if (configWithDefaults.domains) {
127
- const pathDomain = utils.getBestMatchingDomain(domain, pathLocale, domainConfigs);
116
+ if (config$1.domains) {
117
+ const pathDomain = utils.getBestMatchingDomain(domain, pathnameMatch.locale, domainConfigs);
128
118
  if ((domain === null || domain === void 0 ? void 0 : domain.domain) !== (pathDomain === null || pathDomain === void 0 ? void 0 : pathDomain.domain) && !hasUnknownHost) {
129
- response = redirect(normalizedPathnameWithSearch, pathDomain === null || pathDomain === void 0 ? void 0 : pathDomain.domain);
119
+ response = redirect(externalHref, pathDomain === null || pathDomain === void 0 ? void 0 : pathDomain.domain);
130
120
  } else {
131
- response = rewrite(internalPathWithSearch);
121
+ response = rewrite(internalHref);
132
122
  }
133
123
  } else {
134
- response = rewrite(internalPathWithSearch);
124
+ response = rewrite(internalHref);
135
125
  }
136
126
  }
137
127
  } else {
138
- response = redirect("/".concat(locale).concat(normalizedPathnameWithSearch));
128
+ response = redirect(externalHref);
139
129
  }
140
130
  } else {
141
- if (configWithDefaults.localePrefix === 'never' || hasMatchedDefaultLocale && (configWithDefaults.localePrefix === 'as-needed' || configWithDefaults.domains)) {
142
- response = rewrite("/".concat(locale).concat(internalPathWithSearch));
131
+ if (isUnprefixedRouting) {
132
+ response = rewrite(internalHref);
143
133
  } else {
144
- response = redirect("/".concat(locale).concat(internalPathWithSearch));
134
+ response = redirect(utils.formatPathname(unprefixedExternalPathname, utils$1.getLocalePrefix(locale, config$1.localePrefix), request.nextUrl.search));
145
135
  }
146
136
  }
147
137
  }
148
138
  }
149
- if (hasOutdatedCookie) {
150
- response.cookies.set(constants.COOKIE_LOCALE_NAME, locale, {
151
- path: request.nextUrl.basePath || undefined,
152
- sameSite: constants.COOKIE_SAME_SITE,
153
- maxAge: constants.COOKIE_MAX_AGE
154
- });
139
+ if (config$1.localeDetection) {
140
+ syncCookie.default(request, response, locale);
155
141
  }
156
- if (configWithDefaults.localePrefix !== 'never' && configWithDefaults.alternateLinks && configWithDefaults.locales.length > 1) {
157
- var _configWithDefaults$p;
142
+ if (config$1.localePrefix.mode !== 'never' && config$1.alternateLinks && config$1.locales.length > 1) {
143
+ var _config$pathnames;
158
144
  response.headers.set('Link', getAlternateLinksHeaderValue.default({
159
- config: configWithDefaults,
160
- localizedPathnames: internalTemplateName != null ? (_configWithDefaults$p = configWithDefaults.pathnames) === null || _configWithDefaults$p === void 0 ? void 0 : _configWithDefaults$p[internalTemplateName] : undefined,
145
+ config: config$1,
146
+ localizedPathnames: internalTemplateName != null ? (_config$pathnames = config$1.pathnames) === null || _config$pathnames === void 0 ? void 0 : _config$pathnames[internalTemplateName] : undefined,
161
147
  request,
162
148
  resolvedLocale: locale
163
149
  }));
@@ -36,10 +36,6 @@ function getAcceptLanguageLocale(requestHeaders, locales, defaultLocale) {
36
36
  }
37
37
  return locale;
38
38
  }
39
- function getLocaleFromPrefix(pathname, locales) {
40
- const pathLocaleCandidate = utils.getFirstPathnameSegment(pathname);
41
- return utils.findCaseInsensitiveLocale(pathLocaleCandidate, locales);
42
- }
43
39
  function getLocaleFromCookie(requestCookies, locales) {
44
40
  if (requestCookies.has(constants.COOKIE_LOCALE_NAME)) {
45
41
  var _requestCookies$get;
@@ -53,13 +49,15 @@ function resolveLocaleFromPrefix(_ref, requestHeaders, requestCookies, pathname)
53
49
  let {
54
50
  defaultLocale,
55
51
  localeDetection,
52
+ localePrefix,
56
53
  locales
57
54
  } = _ref;
58
55
  let locale;
59
56
 
60
57
  // Prio 1: Use route prefix
61
58
  if (pathname) {
62
- locale = getLocaleFromPrefix(pathname, locales);
59
+ var _getPathnameMatch;
60
+ locale = (_getPathnameMatch = utils.getPathnameMatch(pathname, locales, localePrefix)) === null || _getPathnameMatch === void 0 ? void 0 : _getPathnameMatch.locale;
63
61
  }
64
62
 
65
63
  // Prio 2: Use existing cookie
@@ -90,7 +88,8 @@ function resolveLocaleFromDomain(config, requestHeaders, requestCookies, pathnam
90
88
 
91
89
  // Prio 1: Use route prefix
92
90
  if (pathname) {
93
- const prefixLocale = getLocaleFromPrefix(pathname, config.locales);
91
+ var _getPathnameMatch2;
92
+ const prefixLocale = (_getPathnameMatch2 = utils.getPathnameMatch(pathname, config.locales, config.localePrefix)) === null || _getPathnameMatch2 === void 0 ? void 0 : _getPathnameMatch2.locale;
94
93
  if (prefixLocale) {
95
94
  if (utils.isLocaleSupportedOnDomain(prefixLocale, domain)) {
96
95
  locale = prefixLocale;
@@ -0,0 +1,19 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var constants = require('../shared/constants.js');
6
+
7
+ function syncCookie(request, response, locale) {
8
+ var _request$cookies$get;
9
+ const hasOutdatedCookie = ((_request$cookies$get = request.cookies.get(constants.COOKIE_LOCALE_NAME)) === null || _request$cookies$get === void 0 ? void 0 : _request$cookies$get.value) !== locale;
10
+ if (hasOutdatedCookie) {
11
+ response.cookies.set(constants.COOKIE_LOCALE_NAME, locale, {
12
+ path: request.nextUrl.basePath || undefined,
13
+ sameSite: constants.COOKIE_SAME_SITE,
14
+ maxAge: constants.COOKIE_MAX_AGE
15
+ });
16
+ }
17
+ }
18
+
19
+ exports.default = syncCookie;
@@ -4,9 +4,6 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var utils = require('../shared/utils.js');
6
6
 
7
- function getFirstPathnameSegment(pathname) {
8
- return pathname.split('/')[1];
9
- }
10
7
  function isOptionalCatchAllSegment(pathname) {
11
8
  return pathname.includes('[[...');
12
9
  }
@@ -94,40 +91,64 @@ function getInternalTemplate(pathnames, pathname, locale) {
94
91
  // No match
95
92
  return [undefined, undefined];
96
93
  }
97
- function formatTemplatePathname(sourcePathname, sourceTemplate, targetTemplate, localePrefix) {
94
+ function formatTemplatePathname(sourcePathname, sourceTemplate, targetTemplate, prefix) {
98
95
  const params = getRouteParams(sourceTemplate, sourcePathname);
99
96
  let targetPathname = '';
100
- if (localePrefix) {
101
- targetPathname = "/".concat(localePrefix);
97
+ if (prefix) {
98
+ targetPathname = "/".concat(prefix);
102
99
  }
103
- targetPathname += formatPathname(targetTemplate, params);
100
+ targetPathname += formatPathnameTemplate(targetTemplate, params);
104
101
  targetPathname = normalizeTrailingSlash(targetPathname);
105
102
  return targetPathname;
106
103
  }
107
104
 
108
105
  /**
109
- * Removes potential locales from the pathname.
106
+ * Removes potential prefixes from the pathname.
110
107
  */
111
- function getNormalizedPathname(pathname, locales) {
108
+ function getNormalizedPathname(pathname, locales, localePrefix) {
112
109
  // Add trailing slash for consistent handling
113
110
  // both for the root as well as nested paths
114
111
  if (!pathname.endsWith('/')) {
115
112
  pathname += '/';
116
113
  }
117
- const match = pathname.match(new RegExp("^/(".concat(locales.join('|'), ")/(.*)"), 'i'));
114
+ const localePrefixes = getLocalePrefixes(locales, localePrefix);
115
+ const regex = new RegExp("^(".concat(localePrefixes.map(_ref2 => {
116
+ let [, prefix] = _ref2;
117
+ return prefix.replaceAll('/', '\\/');
118
+ }).join('|'), ")/(.*)"), 'i');
119
+ const match = pathname.match(regex);
118
120
  let result = match ? '/' + match[2] : pathname;
119
121
  if (result !== '/') {
120
122
  result = normalizeTrailingSlash(result);
121
123
  }
122
124
  return result;
123
125
  }
124
- function findCaseInsensitiveLocale(candidate, locales) {
125
- return locales.find(locale => locale.toLowerCase() === candidate.toLowerCase());
126
+ function getLocalePrefixes(locales, localePrefix) {
127
+ return locales.map(locale => [locale, utils.getLocalePrefix(locale, localePrefix)]);
126
128
  }
127
- function getPathnameLocale(pathname, locales) {
128
- const pathLocaleCandidate = getFirstPathnameSegment(pathname);
129
- const pathLocale = findCaseInsensitiveLocale(pathLocaleCandidate, locales) ? pathLocaleCandidate : undefined;
130
- return pathLocale;
129
+ function getPathnameMatch(pathname, locales, localePrefix) {
130
+ const localePrefixes = getLocalePrefixes(locales, localePrefix);
131
+ for (const [locale, prefix] of localePrefixes) {
132
+ let exact, matches;
133
+ if (pathname === prefix || pathname.startsWith(prefix + '/')) {
134
+ exact = matches = true;
135
+ } else {
136
+ const normalizedPathname = pathname.toLowerCase();
137
+ const normalizedPrefix = prefix.toLowerCase();
138
+ if (normalizedPathname === normalizedPrefix || normalizedPathname.startsWith(normalizedPrefix + '/')) {
139
+ exact = false;
140
+ matches = true;
141
+ }
142
+ }
143
+ if (matches) {
144
+ return {
145
+ locale,
146
+ prefix,
147
+ matchedPrefix: pathname.slice(0, prefix.length),
148
+ exact
149
+ };
150
+ }
151
+ }
131
152
  }
132
153
  function getRouteParams(template, pathname) {
133
154
  const regex = utils.templateToRegex(template);
@@ -141,29 +162,32 @@ function getRouteParams(template, pathname) {
141
162
  }
142
163
  return params;
143
164
  }
144
- function formatPathname(template, params) {
165
+ function formatPathnameTemplate(template, params) {
145
166
  if (!params) return template;
146
167
 
147
168
  // Simplify syntax for optional catchall ('[[...slug]]') so
148
169
  // we can replace the value with simple interpolation
149
170
  template = template.replace(/\[\[/g, '[').replace(/\]\]/g, ']');
150
171
  let result = template;
151
- Object.entries(params).forEach(_ref2 => {
152
- let [key, value] = _ref2;
172
+ Object.entries(params).forEach(_ref3 => {
173
+ let [key, value] = _ref3;
153
174
  result = result.replace("[".concat(key, "]"), value);
154
175
  });
155
176
  return result;
156
177
  }
157
- function getPathWithSearch(pathname, search) {
158
- let pathWithSearch = pathname;
178
+ function formatPathname(pathname, prefix, search) {
179
+ let result = pathname;
180
+ if (prefix) {
181
+ result = utils.prefixPathname(prefix, result);
182
+ }
159
183
  if (search) {
160
- pathWithSearch += search;
184
+ result += search;
161
185
  }
162
- return pathWithSearch;
186
+ return result;
163
187
  }
164
188
  function getHost(requestHeaders) {
165
- var _ref3, _requestHeaders$get;
166
- return (_ref3 = (_requestHeaders$get = requestHeaders.get('x-forwarded-host')) !== null && _requestHeaders$get !== void 0 ? _requestHeaders$get : requestHeaders.get('host')) !== null && _ref3 !== void 0 ? _ref3 : undefined;
189
+ var _ref4, _requestHeaders$get;
190
+ return (_ref4 = (_requestHeaders$get = requestHeaders.get('x-forwarded-host')) !== null && _requestHeaders$get !== void 0 ? _requestHeaders$get : requestHeaders.get('host')) !== null && _ref4 !== void 0 ? _ref4 : undefined;
167
191
  }
168
192
  function isLocaleSupportedOnDomain(locale, domain) {
169
193
  return domain.defaultLocale === locale || !domain.locales || domain.locales.includes(locale);
@@ -201,24 +225,28 @@ function applyBasePath(pathname, basePath) {
201
225
  return normalizeTrailingSlash(basePath + pathname);
202
226
  }
203
227
  function normalizeTrailingSlash(pathname) {
204
- if (pathname.endsWith('/')) {
228
+ if (pathname !== '/' && pathname.endsWith('/')) {
205
229
  pathname = pathname.slice(0, -1);
206
230
  }
207
231
  return pathname;
208
232
  }
233
+ function getLocaleAsPrefix(locale) {
234
+ return "/".concat(locale);
235
+ }
209
236
 
210
237
  exports.applyBasePath = applyBasePath;
211
238
  exports.comparePathnamePairs = comparePathnamePairs;
212
- exports.findCaseInsensitiveLocale = findCaseInsensitiveLocale;
213
239
  exports.formatPathname = formatPathname;
240
+ exports.formatPathnameTemplate = formatPathnameTemplate;
214
241
  exports.formatTemplatePathname = formatTemplatePathname;
215
242
  exports.getBestMatchingDomain = getBestMatchingDomain;
216
- exports.getFirstPathnameSegment = getFirstPathnameSegment;
217
243
  exports.getHost = getHost;
218
244
  exports.getInternalTemplate = getInternalTemplate;
245
+ exports.getLocaleAsPrefix = getLocaleAsPrefix;
246
+ exports.getLocalePrefixes = getLocalePrefixes;
219
247
  exports.getNormalizedPathname = getNormalizedPathname;
220
- exports.getPathWithSearch = getPathWithSearch;
221
- exports.getPathnameLocale = getPathnameLocale;
248
+ exports.getPathnameMatch = getPathnameMatch;
222
249
  exports.getRouteParams = getRouteParams;
223
250
  exports.getSortedPathnames = getSortedPathnames;
224
251
  exports.isLocaleSupportedOnDomain = isLocaleSupportedOnDomain;
252
+ exports.normalizeTrailingSlash = normalizeTrailingSlash;
@@ -5,6 +5,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var _rollupPluginBabelHelpers = require('../../_virtual/_rollupPluginBabelHelpers.js');
6
6
  var React = require('react');
7
7
  var useLocale = require('../../react-client/useLocale.js');
8
+ var utils = require('../../shared/utils.js');
8
9
  var BaseLink = require('../shared/BaseLink.js');
9
10
 
10
11
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -14,13 +15,17 @@ var React__default = /*#__PURE__*/_interopDefault(React);
14
15
  function ClientLink(_ref, ref) {
15
16
  let {
16
17
  locale,
18
+ localePrefix,
17
19
  ...rest
18
20
  } = _ref;
19
21
  const defaultLocale = useLocale.default();
20
- const linkLocale = locale || defaultLocale;
22
+ const finalLocale = locale || defaultLocale;
23
+ const prefix = utils.getLocalePrefix(finalLocale, localePrefix);
21
24
  return /*#__PURE__*/React__default.default.createElement(BaseLink.default, _rollupPluginBabelHelpers.extends({
22
25
  ref: ref,
23
- locale: linkLocale
26
+ locale: finalLocale,
27
+ localePrefixMode: localePrefix.mode,
28
+ prefix: prefix
24
29
  }, rest));
25
30
  }
26
31
 
@@ -5,10 +5,10 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var _rollupPluginBabelHelpers = require('../../_virtual/_rollupPluginBabelHelpers.js');
6
6
  var React = require('react');
7
7
  var useLocale = require('../../react-client/useLocale.js');
8
+ var config = require('../shared/config.js');
8
9
  var utils = require('../shared/utils.js');
9
10
  var ClientLink = require('./ClientLink.js');
10
- var clientPermanentRedirect = require('./clientPermanentRedirect.js');
11
- var clientRedirect = require('./clientRedirect.js');
11
+ var redirects = require('./redirects.js');
12
12
  var useBasePathname = require('./useBasePathname.js');
13
13
  var useBaseRouter = require('./useBaseRouter.js');
14
14
 
@@ -16,10 +16,11 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
16
16
 
17
17
  var React__default = /*#__PURE__*/_interopDefault(React);
18
18
 
19
- function createLocalizedPathnamesNavigation(opts) {
19
+ function createLocalizedPathnamesNavigation(input) {
20
+ const config$1 = config.receiveLocalizedNavigationRoutingConfig(input);
20
21
  function useTypedLocale() {
21
22
  const locale = useLocale.default();
22
- const isValid = opts.locales.includes(locale);
23
+ const isValid = config$1.locales.includes(locale);
23
24
  if (!isValid) {
24
25
  throw new Error("Unknown locale encountered: \"".concat(locale, "\". Make sure to validate the locale in `i18n.ts`.") );
25
26
  }
@@ -41,10 +42,10 @@ function createLocalizedPathnamesNavigation(opts) {
41
42
  pathname: href,
42
43
  // @ts-expect-error -- This is ok
43
44
  params: typeof href === 'object' ? href.params : undefined,
44
- pathnames: opts.pathnames
45
+ pathnames: config$1.pathnames
45
46
  }),
46
47
  locale: locale,
47
- localePrefix: opts.localePrefix
48
+ localePrefix: config$1.localePrefix
48
49
  }, rest));
49
50
  }
50
51
  const LinkWithRef = /*#__PURE__*/React.forwardRef(Link);
@@ -59,9 +60,9 @@ function createLocalizedPathnamesNavigation(opts) {
59
60
  for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
60
61
  args[_key - 1] = arguments[_key];
61
62
  }
62
- return clientRedirect.default({
63
- ...opts,
64
- pathname: resolvedHref
63
+ return redirects.clientRedirect({
64
+ pathname: resolvedHref,
65
+ localePrefix: config$1.localePrefix
65
66
  }, ...args);
66
67
  }
67
68
  function permanentRedirect(href) {
@@ -74,13 +75,13 @@ function createLocalizedPathnamesNavigation(opts) {
74
75
  for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
75
76
  args[_key2 - 1] = arguments[_key2];
76
77
  }
77
- return clientPermanentRedirect.default({
78
- ...opts,
79
- pathname: resolvedHref
78
+ return redirects.clientPermanentRedirect({
79
+ pathname: resolvedHref,
80
+ localePrefix: config$1.localePrefix
80
81
  }, ...args);
81
82
  }
82
83
  function useRouter() {
83
- const baseRouter = useBaseRouter.default();
84
+ const baseRouter = useBaseRouter.default(config$1.localePrefix);
84
85
  const defaultLocale = useTypedLocale();
85
86
  return {
86
87
  ...baseRouter,
@@ -120,13 +121,14 @@ function createLocalizedPathnamesNavigation(opts) {
120
121
  };
121
122
  }
122
123
  function usePathname() {
123
- const pathname = useBasePathname.default();
124
+ const pathname = useBasePathname.default(config$1.localePrefix);
124
125
  const locale = useTypedLocale();
126
+
125
127
  // @ts-expect-error -- Mirror the behavior from Next.js, where `null` is returned when `usePathname` is used outside of Next, but the types indicate that a string is always returned.
126
128
  return pathname ? utils.getRoute({
127
129
  pathname,
128
130
  locale,
129
- pathnames: opts.pathnames
131
+ pathnames: config$1.pathnames
130
132
  }) : pathname;
131
133
  }
132
134
  function getPathname(_ref2) {
@@ -137,7 +139,7 @@ function createLocalizedPathnamesNavigation(opts) {
137
139
  return utils.compileLocalizedPathname({
138
140
  ...utils.normalizeNameOrNameWithParams(href),
139
141
  locale,
140
- pathnames: opts.pathnames
142
+ pathnames: config$1.pathnames
141
143
  });
142
144
  }
143
145
  return {