Skip to content

Commit 7b21386

Browse files
committed
Merge remote-tracking branch 'origin/main' into chore/next-15
2 parents 2213185 + 3491eb3 commit 7b21386

File tree

23 files changed

+263
-70
lines changed

23 files changed

+263
-70
lines changed

Diff for: .github/ISSUE_TEMPLATE/02_feature_request.yml

+10-2
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,18 @@ labels:
66
body:
77
- type: markdown
88
attributes:
9-
value: Thanks for taking the time to file a feature request! Please fill out this form completely.
9+
value: Thanks for taking the time to improve next-intl!
1010
- type: markdown
1111
attributes:
12-
value: Please keep in mind that if something doesn't work as expected, you might want to [create a bug report](https://github.com/amannn/next-intl/issues/new/choose) instead. Bug reports disguised as feature requests will be closed.
12+
value: |
13+
Please keep in mind:
14+
15+
- If you're looking for specific support with your project, you can consider [asking for community support](https://github.com/amannn/next-intl/issues/new/choose) instead.
16+
- If something doesn't work as expected, you might want to [create a bug report](https://github.com/amannn/next-intl/issues/new/choose) instead.
17+
- Please double check the [docs](https://next-intl.dev) to see if your feature request is already supported.
18+
- Please also check the [existing issues](https://github.com/amannn/next-intl/issues) to see if your feature request was already discussed.
19+
20+
If you have a feature request that has not been discussed yet, please fill out this form completely.
1321
- type: textarea
1422
attributes:
1523
label: Is your feature request related to a problem? Please describe.

Diff for: .github/ISSUE_TEMPLATE/config.yml

+8-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,15 @@ contact_links:
33
- name: View documentation
44
url: https://next-intl.dev
55
about: Check out the official docs for answers to common questions
6-
- name: Get community support
6+
- name: Get community support on the Next.js Discord
7+
url: https://discord.com/invite/nextjs
8+
about: Join the Next.js community on Discord to get real-time help and connect with other developers
9+
- name: Get community support on Stack Overflow
710
url: https://stackoverflow.com/questions/ask
8-
about: Ask questions and discuss with other community members
11+
about: Post your technical questions on Stack Overflow where experienced developers can help
12+
- name: Get community support on GitHub Discussions
13+
url: https://github.com/amannn/next-intl/discussions
14+
about: Start a discussion to share ideas and ask questions
915
- name: Get maintainer support
1016
url: https://github.com/sponsors/amannn?frequency=one-time
1117
about: Book a consulting session to get help with your specific project

Diff for: CHANGELOG.md

+12
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,18 @@
33
All notable changes to this project will be documented in this file.
44
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
55

6+
## 3.26.5 (2025-02-21)
7+
8+
### Bug Fixes
9+
10+
* Handle `query` in `<Link />` correctly when using `localePrefix: 'as-needed'` with `domains` ([#1732](https://github.com/amannn/next-intl/issues/1732)) ([ec8776e](https://github.com/amannn/next-intl/commit/ec8776e8f0344f78fea4f71284c48312484a7059)), closes [#1731](https://github.com/amannn/next-intl/issues/1731) – by @amannn
11+
12+
## 3.26.4 (2025-02-18)
13+
14+
### Bug Fixes
15+
16+
* Add workaround for OpenTelemetry/Zone.js ([#1719](https://github.com/amannn/next-intl/issues/1719)) ([1cac9a6](https://github.com/amannn/next-intl/commit/1cac9a65d2aefe20ff7fcf734e70f1fe85cac19d)), closes [#1711](https://github.com/amannn/next-intl/issues/1711) – by @amannn
17+
618
## 3.26.3 (2024-12-20)
719

820
### Bug Fixes

Diff for: docs/src/components/HeroCode.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ const files = [
164164
<span data-token="text">:</span>
165165
<span data-token="text"> </span>
166166
<span data-token="string">
167-
"{'{'}firstname{'}'}'s profile"
167+
"{'{'}firstName{'}'}'s profile"
168168
</span>
169169
<span data-token="text">,</span>
170170
</span>

Diff for: docs/src/pages/blog/next-intl-4-0.mdx

+86-9
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ Here's what's new in `next-intl@4.0`:
1818
3. [**Strictly-typed ICU arguments**](#strictly-typed-icu-arguments)
1919
4. [**GDPR compliance**](#gdpr-compliance)
2020
5. [**Modernized build output**](#modernized-build-output)
21-
6. [**Preparation for upcoming Next.js features**](#nextjs-future)
21+
6. [**Improved inheritance in `NextIntlClientProvider`**](#nextintlclientprovider-inheritance)
22+
7. [**Stricter config for `domains`**](#domains-config)
23+
8. [**Preparation for upcoming Next.js features**](#nextjs-future)
2224

2325
Please also have a look at the [other breaking changes](#other-breaking-changes) listed below before you upgrade.
2426

@@ -188,6 +190,82 @@ The build output of `next-intl` has been modernized and now leverages the follow
188190

189191
With these changes, the bundle size of `next-intl` has been reduced by ~7% ([all details](https://github.com/amannn/next-intl/pull/1470)).
190192

193+
## Improved inheritance of `NextIntlClientProvider` [#nextintlclientprovider-inheritance]
194+
195+
Previously, [`NextIntlClientProvider`](/docs/usage/configuration#nextintlclientprovider) would conservatively inherit only a subset from `i18n/request.ts`.
196+
197+
To improve the getting started experience, the provider now also inherits:
198+
199+
- `messages` ([PR #1682](https://github.com/amannn/next-intl/pull/1682))
200+
- `formats` ([PR #1191](https://github.com/amannn/next-intl/pull/1191))
201+
202+
Due to this, you can now remove these props from `NextIntlClientProvider` if you've previously passed them manually:
203+
204+
```diff
205+
<NextIntlClientProvider
206+
- messages={messages}
207+
- formats={formats}
208+
>
209+
{/* ... */}
210+
</NextIntlClientProvider>
211+
```
212+
213+
With this, `NextIntlClientProvider` now inherits all of your configuration, with the minor exception of [error handling functions](/docs/usage/configuration#error-handling). Since functions are not serializable, they cannot be passed across the server/client boundary. However, [an alternative](https://github.com/amannn/next-intl/issues/1285) for this is also on the horizon.
214+
215+
To make it easier to work with error handling functions on the client side, `NextIntlClientProvider` can now also be used in a nested fashion and will inherit the configuration from a parent provider ([PR #1413](https://github.com/amannn/next-intl/pull/1413)).
216+
217+
## Stricter config for `domains` [#domains-config]
218+
219+
So far, when using [`domains`](/docs/routing#domains) in combination with [`localePrefix: 'as-needed'`](/docs/routing#locale-prefix-as-needed), `next-intl` had to make some [tradeoffs](https://next-intl-docs-6wwcmwb9a-next-intl.vercel.app/docs/routing#domains-localeprefix-asneeded) to avoid reading the current host of the incoming request in components.
220+
221+
Now, by introducing two new constraints, `next-intl` can avoid these tradeoffs altogether:
222+
223+
1. A locale can now only be used for a single domain
224+
2. Each domain now must specify its `locales`
225+
226+
The result is a simplified, more intuitive model that works as expected for this popular use case.
227+
228+
If you previously used locales across multiple domains, you now have to be more specific—typically by introducing a regional variant for a base language. You can additionally customize the prefixes if desired.
229+
230+
**Example:**
231+
232+
```tsx
233+
import {defineRouting} from 'next-intl/routing';
234+
235+
export const routing = defineRouting({
236+
locales: ['sv-SE', 'en-SE', 'no-NO', 'en-NO'],
237+
defaultLocale: 'en-SE',
238+
localePrefix: {
239+
mode: 'as-needed',
240+
prefixes: {
241+
'en-SE': '/en',
242+
'en-NO': '/en'
243+
}
244+
},
245+
domains: [
246+
{
247+
domain: 'example.se',
248+
defaultLocale: 'sv-SE',
249+
locales: ['sv-SE', 'en-SE']
250+
},
251+
{
252+
domain: 'example.no',
253+
defaultLocale: 'no-NO',
254+
locales: ['no-NO', 'en-NO']
255+
}
256+
]
257+
});
258+
```
259+
260+
This will create the following structure:
261+
262+
- `example.se`: `sv-SE`
263+
- `example.se/en`: `en-SE`
264+
- `example.no`: `no-NO`
265+
- `example.no/en`: `en-NO`
266+
267+
Learn more in the updated docs for [`domains`](https://v4.next-intl.dev/docs/routing#domains).
268+
191269
## Preparation for upcoming Next.js features [#nextjs-future]
192270

193271
To ensure that the sails of `next-intl` are set for a steady course in the upcoming future, I've investigated the implications of upcoming Next.js features like [`ppr`](https://nextjs.org/docs/app/api-reference/next-config-js/ppr), [`dynamicIO`](https://nextjs.org/docs/canary/app/api-reference/config/next-config-js/dynamicIO) and [`rootParams`](https://github.com/vercel/next.js/pull/72837) for `next-intl`.
@@ -196,7 +274,7 @@ This led to three minor changes:
196274

197275
1. If you don't already have a `NextIntlClientProvider` in your app that wraps all Client Components that use `next-intl`, you now have to add one (see [PR #1541](https://github.com/amannn/next-intl/pull/1541) for details).
198276
2. If you're using `format.relativeTime` in Client Components, you may need to provide the `now` argument explicitly now (see [PR #1536](https://github.com/amannn/next-intl/pull/1536) for details).
199-
3. If you're using i18n routing, make sure you've updated to [`await requestLocale`](https://next-intl.dev/blog/next-intl-3-22#await-request-locale) that was introduced in `next-intl@3.22`. The previously deprecated `locale` argument will serve an edge case in the future once `rootParams` is a thing (see [PR #1625](https://github.com/amannn/next-intl/pull/1625/) for details).
277+
3. If you're using i18n routing, make sure you've updated to [`await requestLocale`](/blog/next-intl-3-22#await-request-locale) that was introduced in `next-intl@3.22`. The previously deprecated `locale` argument will serve an edge case in the future once `rootParams` is a thing (see [PR #1625](https://github.com/amannn/next-intl/pull/1625/) for details).
200278

201279
While the mentioned Next.js features are still under development and may change, these changes seem reasonable to me in any case—and ideally will be all that's necessary to adapt for `next-intl` to get the most out of these upcoming capabilities.
202280

@@ -205,13 +283,12 @@ I'm particularly excited about the announcement of `rootParams`, as it seems lik
205283
## Other breaking changes
206284

207285
1. Return type-safe messages from `useMessages` and `getMessages` (see [PR #1489](https://github.com/amannn/next-intl/pull/1489))
208-
2. Inherit context in case nested `NextIntlClientProvider` instances are present (see [PR #1413](https://github.com/amannn/next-intl/pull/1413))
209-
3. Automatically inherit formats when `NextIntlClientProvider` is rendered from a Server Component (see [PR #1191](https://github.com/amannn/next-intl/pull/1191))
210-
4. Require locale to be returned from `getRequestConfig` (see [PR #1486](https://github.com/amannn/next-intl/pull/1486))
211-
5. Disallow passing `null`, `undefined` or `boolean` as an ICU argument (see [PR #1561](https://github.com/amannn/next-intl/pull/1561))
212-
6. Bump minimum required TypeScript version to 5 for projects using TypeScript (see [PR #1481](https://github.com/amannn/next-intl/pull/1481))
213-
7. Remove deprecated APIs (see [PR #1479](https://github.com/amannn/next-intl/pull/1479))
214-
8. Remove deprecated APIs pt. 2 (see [PR #1482](https://github.com/amannn/next-intl/pull/1482))
286+
2. Require locale to be returned from `getRequestConfig` (see [PR #1486](https://github.com/amannn/next-intl/pull/1486))
287+
3. Disallow passing `null`, `undefined` or `boolean` as an ICU argument (see [PR #1561](https://github.com/amannn/next-intl/pull/1561))
288+
4. Bump minimum required TypeScript version to 5 for projects using TypeScript (see [PR #1481](https://github.com/amannn/next-intl/pull/1481))
289+
5. Return `x-default` alternate link also for sub pages when using `localePrefix: 'always'` and update middleware matcher suggestion in docs (see [PR #1720](https://github.com/amannn/next-intl/pull/1720))
290+
6. Remove deprecated APIs (see [PR #1479](https://github.com/amannn/next-intl/pull/1479))
291+
7. Remove deprecated APIs pt. 2 (see [PR #1482](https://github.com/amannn/next-intl/pull/1482))
215292

216293
## Upgrade now
217294

Diff for: docs/src/pages/docs/environments/actions-metadata-route-handlers.mdx

+26-25
Original file line numberDiff line numberDiff line change
@@ -81,22 +81,18 @@ async function loginAction(data: FormData) {
8181
const t = await getTranslations('LoginForm');
8282
const values = Object.fromEntries(data);
8383

84-
const result = await loginFormSchema
85-
.refine(async (credentials) => loginUser(credentials), {
86-
message: t('invalidCredentials')
87-
})
88-
.safeParseAsync(values, {
89-
errorMap(issue, ctx) {
90-
const path = issue.path.join('.');
91-
92-
const message = {
93-
email: t('invalidEmail')
94-
password: t('invalidPassword')
95-
}[path];
96-
97-
return {message: message || ctx.defaultError};
98-
}
99-
});
84+
const result = loginFormSchema.safeParse(values, {
85+
errorMap(issue, ctx) {
86+
const path = issue.path.join('.');
87+
88+
const message = {
89+
email: t('invalidEmail')
90+
password: t('invalidPassword')
91+
}[path];
92+
93+
return {message: message || ctx.defaultError};
94+
}
95+
});
10096

10197
// ...
10298
}
@@ -175,7 +171,7 @@ If you're using a sitemap to inform search engines about all pages of your site,
175171

176172
Note that by default, `next-intl` returns [the `link` response header](/docs/routing#alternate-links) to instruct search engines that a page is available in multiple languages. While this sufficiently links localized pages for search engines, you may choose to provide this information in a sitemap in case you have more specific requirements.
177173

178-
Next.js supports providing alternate URLs per language via the [`alternates` entry](https://nextjs.org/docs/app/api-reference/file-conventions/metadata/sitemap#generate-a-localized-sitemap) as of version 14.2. You can use your default locale for the main URL and provide alternate URLs based on all locales that your app supports. Keep in mind that also the default locale should be included in the `alternates` object.
174+
Next.js supports providing alternate URLs per language via the [`alternates` entry](https://nextjs.org/docs/app/api-reference/file-conventions/metadata/sitemap#generate-a-localized-sitemap). You can construct a list of entries for each pathname and locale as follows:
179175

180176
```tsx filename="app/sitemap.ts" {4-5,8-9}
181177
import {MetadataRoute} from 'next';
@@ -186,20 +182,20 @@ const host = 'https://acme.com';
186182

187183
export default function sitemap(): MetadataRoute.Sitemap {
188184
// Adapt this as necessary
189-
return [getEntry('/'), getEntry('/users')];
185+
return [...getEntries('/'), ...getEntries('/users')];
190186
}
191187

192188
type Href = Parameters<typeof getPathname>[0]['href'];
193189

194-
function getEntry(href: Href) {
195-
return {
196-
url: getUrl(href, routing.defaultLocale),
190+
function getEntries(href: Href) {
191+
return routing.locales.map((locale) => ({
192+
url: getUrl(href, locale),
197193
alternates: {
198194
languages: Object.fromEntries(
199-
routing.locales.map((locale) => [locale, getUrl(href, locale)])
195+
routing.locales.map((cur) => [cur, getUrl(href, cur)])
200196
)
201197
}
202-
};
198+
}));
203199
}
204200

205201
function getUrl(href: Href, locale: (typeof routing.locales)[number]) {
@@ -212,15 +208,20 @@ Depending on if you're using the [`pathnames`](/docs/routing#pathnames) setting,
212208

213209
```tsx
214210
// 1. A final string (when not using `pathnames`)
215-
getEntry('/users/1');
211+
getEntries('/users/1');
216212

217213
// 2. An object (when using `pathnames`)
218-
getEntry({
214+
getEntries({
219215
pathname: '/users/[id]',
220216
params: {id: '1'}
221217
});
222218
```
223219

220+
**Keep in mind**:
221+
222+
- Each pathname should have a separate entry for every locale that your app supports.
223+
- Also the locale of a given pathname should be included in the `alternates` object.
224+
224225
([working implementation](https://github.com/amannn/next-intl/blob/main/examples/example-app-router/src/app/sitemap.ts))
225226

226227
### Route Handlers

Diff for: docs/src/pages/docs/usage/configuration.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ export default async function RootLayout({children}) {
190190
messages={messages}
191191
>
192192
{children}
193-
</NextIntlClientProvider>
193+
</IntlProvider>
194194
</body>
195195
</html>
196196
);

Diff for: examples/example-app-router/src/app/sitemap.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,20 @@ import {routing, Locale} from '@/i18n/routing';
44
import {getPathname} from '@/i18n/navigation';
55

66
export default function sitemap(): MetadataRoute.Sitemap {
7-
return [getEntry('/'), getEntry('/pathnames')];
7+
return [...getEntries('/'), ...getEntries('/pathnames')];
88
}
99

1010
type Href = Parameters<typeof getPathname>[0]['href'];
1111

12-
function getEntry(href: Href) {
13-
return {
14-
url: getUrl(href, routing.defaultLocale),
12+
function getEntries(href: Href) {
13+
return routing.locales.map((locale) => ({
14+
url: getUrl(href, locale),
1515
alternates: {
1616
languages: Object.fromEntries(
17-
routing.locales.map((locale) => [locale, getUrl(href, locale)])
17+
routing.locales.map((cur) => [cur, getUrl(href, cur)])
1818
)
1919
}
20-
};
20+
}));
2121
}
2222

2323
function getUrl(href: Href, locale: Locale) {

Diff for: examples/example-app-router/tests/main.spec.ts

+10
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,20 @@ it('serves a sitemap.xml', async ({page}) => {
111111
<xhtml:link rel="alternate" hreflang="de" href="http://localhost:3000/de" />
112112
</url>
113113
<url>
114+
<loc>http://localhost:3000/de</loc>
115+
<xhtml:link rel="alternate" hreflang="en" href="http://localhost:3000/en" />
116+
<xhtml:link rel="alternate" hreflang="de" href="http://localhost:3000/de" />
117+
</url>
118+
<url>
114119
<loc>http://localhost:3000/en/pathnames</loc>
115120
<xhtml:link rel="alternate" hreflang="en" href="http://localhost:3000/en/pathnames" />
116121
<xhtml:link rel="alternate" hreflang="de" href="http://localhost:3000/de/pfadnamen" />
117122
</url>
123+
<url>
124+
<loc>http://localhost:3000/de/pfadnamen</loc>
125+
<xhtml:link rel="alternate" hreflang="en" href="http://localhost:3000/en/pathnames" />
126+
<xhtml:link rel="alternate" hreflang="de" href="http://localhost:3000/de/pfadnamen" />
127+
</url>
118128
</urlset>
119129
`
120130
);

Diff for: lerna.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"$schema": "node_modules/@lerna-lite/cli/schemas/lerna-schema.json",
3-
"version": "3.26.3",
3+
"version": "3.26.5",
44
"packages": [
55
"packages/*"
66
],

Diff for: media/assets.sketch

32.9 KB
Binary file not shown.

0 commit comments

Comments
 (0)