You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix!: Return x-default alternate link also for sub pages when using localePrefix: 'always' and update middleware matcher suggestion in docs (#1720)
Previously, we suggested a middleware matcher that looked like this:
```tsx
// middleware.ts
export const config = {
// Match only internationalized pathnames
matcher: ['/', '/(de|en)/:path*']
};
```
Even though the hardcoded locales need to be updated when new locales
are added, this was suggested in light of providing an error-free
getting started experience.
However, based on the apps I've seen over time, it seems like this
choice was unpopular and users typically go for a matcher that looks
like this:
```tsx
export const config = {
// Match all pathnames except for
// - … if they start with `/api`, `/_next` or `/_vercel`
// - … the ones containing a dot (e.g. `favicon.ico`)
matcher: '/((?!api|_next|_vercel|.*\\..*).*)'
};
```
While this avoids hardcoding locales, it requires extra care to [match
pathnames that contain a
dot](https://next-intl.dev/docs/routing/middleware#matcher-config) (e.g.
`/users/jane.doe`).
To align better with user expectations, we now suggest the negative
lookahead in the getting started docs and point out the case with
pathnames containing dots. As an extra benefit, it makes it
significantly easier to switch between routing strategies and add custom
prefixes.
With the new matcher in place, the middleware now also returns an
`x-default` [alternate
link](https://next-intl.dev/docs/routing#alternate-links-details) for
non-root pathnames (previously only one for `/` was returned when using
`localePrefix: 'always'`). Due to this, please update your middleware
matcher as shown in the [getting started
docs](https://next-intl.dev/docs/getting-started/app-router/with-i18n-routing#middleware)
if you're using alternate links.
**Related discussions:**
- #1136
- #505
- #504
Copy file name to clipboardexpand all lines: docs/src/pages/docs/getting-started/app-router/with-i18n-routing.mdx
+32-5
Original file line number
Diff line number
Diff line change
@@ -61,7 +61,7 @@ The simplest option is to add JSON files in your local project folder:
61
61
62
62
### `next.config.mjs`[#next-config]
63
63
64
-
Now, set up the plugin which creates an alias to provide a request-specific i18n configuration to Server Components—more on this in the following steps.
64
+
Now, set up the plugin which creates an alias to provide a request-specific i18n configuration like your messages to Server Components—more on this in the following steps.
<summary>How can I match pathnames that contain dots like `/users/jane.doe`?</summary>
148
+
149
+
If you have pathnames where dots are expected, you can match them with explicit entries:
150
+
151
+
```tsx filename="src/middleware.ts" {10,11}
152
+
// ...
153
+
154
+
exportconst config = {
155
+
matcher: [
156
+
// Match all pathnames except for
157
+
// - … if they start with `/api`, `/trpc`, `/_next` or `/_vercel`
158
+
// - … the ones containing a dot (e.g. `favicon.ico`)
159
+
'/((?!api|trpc|_next|_vercel|.*\\..*).*)'
160
+
161
+
// Match all pathnames within `{/:locale}/users`
162
+
'/([\\w-]+)?/users/(.+)'
163
+
];
164
+
}
165
+
```
166
+
167
+
This will match e.g. `/users/jane.doe`, also optionally with a locale prefix.
168
+
169
+
</Details>
170
+
144
171
### `src/i18n/request.ts`[#i18n-request]
145
172
146
173
When using features from `next-intl` in Server Components, the relevant configuration is read from a central module that is located at `i18n/request.ts` by convention. This configuration is scoped to the current request and can be used to provide messages and other options based on the user's locale.
<summary>How can I redirect unprefixed pathnames?</summary>
68
-
69
-
If you want to redirect unprefixed pathnames like `/about` to a prefixed alternative like `/en/about`, you can adjust your middleware matcher to [match unprefixed pathnames](/docs/routing/middleware#matcher-no-prefix) too.
70
-
71
-
</Details>
72
-
73
66
#### Don't use a locale prefix for the default locale [#locale-prefix-as-needed]
74
67
75
68
If you want to use no prefix for the default locale (e.g. `/about`), you can configure your routing accordingly:
**Important**: For this routing strategy to work as expected, you should additionally adapt your middleware matcher to detect [unprefixed pathnames](/docs/routing/middleware#matcher-no-prefix).
79
+
**Note that:**
87
80
88
-
Note that if a superfluous locale prefix like `/en/about` is requested, the middleware will automatically redirect to the unprefixed version `/about`. This can be helpful in case you're redirecting from another locale and you want to update a potential cookie value first (e.g. [`<Link />`](/docs/routing/navigation#link) relies on this mechanism).
81
+
1. If you use this routing strategy, make sure that your [middleware matcher](/docs/routing/middleware#matcher-config) detects unprefixed pathnames.
82
+
2. If a superfluous locale prefix like `/en/about` is requested, the middleware will automatically redirect to the unprefixed version `/about`. This can be helpful in case you're redirecting from another locale and you want to update a potential cookie value first (e.g. [`<Link />`](/docs/routing/navigation#link) relies on this mechanism).
89
83
90
84
#### Never use a locale prefix [#locale-prefix-never]
91
85
@@ -109,7 +103,7 @@ In this case, requests for all locales will be rewritten to have the locale only
109
103
110
104
**Note that:**
111
105
112
-
1. If you use this strategy, you should adapt your matcher to detect [unprefixed pathnames](/docs/routing/middleware#matcher-no-prefix).
106
+
1. If you use this routing strategy, make sure that your [middleware matcher](/docs/routing/middleware#matcher-config) detects unprefixed pathnames.
113
107
2.[Alternate links](#alternate-links) are disabled in this mode since URLs might not be unique per locale. Due to this, consider including these yourself, or set up a [sitemap](/docs/environments/actions-metadata-route-handlers#sitemap) that links localized pages via `alternates`.
114
108
3. You can consider increasing the [`maxAge`](#locale-cookie) attribute of the locale cookie to a longer duration to remember the user's preference across sessions.
The [`x-default`](https://developers.google.com/search/docs/specialty/international/localized-versions#xdefault) entry is included to point to a variant that can be used if no other language matches the user's browser setting. This special entry is reserved for language selection & detection, in our case issuing a 307 redirect to the best matching locale.
563
557
564
-
Note that middleware configuration is automatically incorporated with the following special cases:
565
-
566
-
1.**`localePrefix: 'always'` (default)**: The `x-default` entry is only included for `/`, not for nested pathnames like `/about`. The reason is that the default [matcher](#matcher-config) doesn't handle unprefixed pathnames apart from `/`, therefore these URLs could be 404s. Note that this only applies to the optional `x-default` entry, locale-specific URLs are always included.
567
-
2.**`localePrefix: 'never'`**: Alternate links are entirely turned off since there might not be unique URLs per locale.
568
-
569
-
Other configuration options like `domains`, `pathnames` and `basePath` are automatically considered.
558
+
Your middleware configuration, including options like `domains`, `pathnames` and `basePath`, is automatically incorporated.
@@ -106,58 +108,6 @@ The bestmatching domain is detected based on these priorities:
106
108
107
109
The middleware is intended to only run on pages, not on arbitrary files that you serve independently of the user locale (e.g. `/favicon.ico`).
108
110
109
-
Because of this, the following config is generally recommended:
110
-
111
-
```tsx filename="middleware.ts"
112
-
exportconst config = {
113
-
// Match only internationalized pathnames
114
-
matcher: ['/', '/(de|en)/:path*']
115
-
};
116
-
```
117
-
118
-
This enables:
119
-
120
-
1. A redirect at `/` to a suitable locale
121
-
2. Internationalization of all pathnames starting with a locale (e.g. `/en/about`)
122
-
123
-
<Detailsid="matcher-avoid-hardcoding">
124
-
<summary>Can I avoid hardcoding the locales in the `matcher` config?</summary>
125
-
126
-
A [Next.js `matcher`](https://nextjs.org/docs/app/building-your-application/routing/middleware#matcher) needs to be statically analyzable, therefore you can't use variables to generate this value. However, you can alternatively implement a programmatic condition in the middleware:
### Pathnames without a locale prefix [#matcher-no-prefix]
153
-
154
-
There are two use cases where you might want to match pathnames without a locale prefix:
155
-
156
-
1. You're using a config for [`localePrefix`](/docs/routing#locale-prefix) other than [`always`](/docs/routing#locale-prefix-always)
157
-
2. You want to enable redirects that add a locale for unprefixed pathnames (e.g. `/about` → `/en/about`)
158
-
159
-
For these cases, the middleware should run on requests for pathnames without a locale prefix as well.
160
-
161
111
A popular strategy is to match all routes that don't start with certain segments (e.g. `/_next`) and also none that include a dot (`.`) since these typically indicate static files. However, if you have some routes where a dot is expected (e.g. `/users/jane.doe`), you should explicitly provide a matcher for these.
162
112
163
113
```tsx filename="middleware.ts"
@@ -169,6 +119,7 @@ export const config = {
169
119
// - … if they start with `/api`, `/_next` or `/_vercel`
170
120
// - … the ones containing a dot (e.g. `favicon.ico`)
171
121
'/((?!api|_next|_vercel|.*\\..*).*)',
122
+
172
123
// However, match all pathnames within `/users`, optionally with a locale prefix
0 commit comments