Skip to content

Commit 8868626

Browse files
committed
Merge remote-tracking branch 'origin/main' into v4
# Conflicts: # docs/src/pages/docs/usage/configuration.mdx # lerna.json
2 parents ca3fcd5 + 1f44136 commit 8868626

File tree

18 files changed

+399
-44
lines changed

18 files changed

+399
-44
lines changed

.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.

.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

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
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.3 (2024-12-20)
7+
8+
### Bug Fixes
9+
10+
* Add missing deprecation warnings for `next-intl@4.0` ([#1485](https://github.com/amannn/next-intl/issues/1485)) ([1d60d08](https://github.com/amannn/next-intl/commit/1d60d08c446d9eeac8bcc5bfbd0654113a737518)) – by @amannn
11+
612
## 3.26.2 (2024-12-18)
713

814
### Bug Fixes

docs/src/components/GetStartedBackground.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export default function GetStartedBackground() {
44
const size = 530;
55
const radius = 2;
66
const className =
7-
'absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-screen';
7+
'absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-full';
88
const patternSize = 19;
99

1010
return (

docs/src/pages/blog/_meta.tsx

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ export default {
22
index: {
33
title: 'Overview'
44
},
5+
'next-intl-4-0': {
6+
title: 'next-intl 4.0 beta',
7+
display: 'hidden'
8+
},
59
'next-intl-3-22': {
610
title: 'next-intl 3.22',
711
display: 'hidden'

docs/src/pages/blog/index.mdx

+6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ import StayUpdated from '@/components/StayUpdated.mdx';
44
# next-intl blog
55

66
<div className="flex flex-col gap-4 py-8">
7+
<BlogPostLink
8+
href="/blog/next-intl-4-0"
9+
title="next-intl 4.0 beta"
10+
date="Dec 23, 2024"
11+
author="By Jan Amann"
12+
/>
713
<BlogPostLink
814
href="/blog/next-intl-3-22"
915
title="next-intl 3.22: Incrementally moving forward"

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

+263
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
---
2+
title: next-intl 4.0 beta
3+
---
4+
5+
import PartnerContentLink from '@/components/PartnerContentLink';
6+
import StayUpdated from '@/components/StayUpdated.mdx';
7+
8+
# next-intl 4.0 beta
9+
10+
<small>Dec 23, 2024 · by Jan Amann</small>
11+
12+
After a year of feature development, this release focuses on streamlining the API surface while maintaining the core architecture of `next-intl`. With many improvements already released in [previous minor versions](/blog/next-intl-3-22), this update introduces several enhancements that will improve your development experience and make working with internationalization even more seamless.
13+
14+
Here's what's new in `next-intl@4.0`:
15+
16+
1. [**Revamped augmented types**](#revamped-augmented-types)
17+
2. [**Strictly-typed locale**](#strictly-typed-locale)
18+
3. [**Strictly-typed ICU arguments**](#strictly-typed-icu-arguments)
19+
4. [**GDPR compliance**](#gdpr-compliance)
20+
5. [**Modernized build output**](#modernized-build-output)
21+
6. [**Improved inheritance in `NextIntlClientProvider`**](#nextintlclientprovider-inheritance)
22+
7. [**Preparation for upcoming Next.js features**](#nextjs-future)
23+
24+
Please also have a look at the [other breaking changes](#other-breaking-changes) listed below before you upgrade.
25+
26+
## Revamped augmented types
27+
28+
After type-safe [`Formats`](/docs/usage/configuration#formats) was added in `next-intl@3.20`, it became clear that a new API was needed that centralizes the registration of augmented types.
29+
30+
With `next-intl@4.0`, both `Messages` as well as `Formats` can now be registered under a single type that is scoped to `next-intl` and no longer affects the global scope:
31+
32+
```tsx
33+
// global.d.ts
34+
35+
import {formats} from '@/i18n/request';
36+
import en from './messages/en.json';
37+
38+
declare module 'next-intl' {
39+
interface AppConfig {
40+
Messages: typeof en;
41+
Formats: typeof formats;
42+
}
43+
}
44+
```
45+
46+
See the updated [TypeScript augmentation](https://v4.next-intl.dev/docs/workflows/typescript) guide.
47+
48+
## Strictly-typed locale
49+
50+
Building on the new type augmentation mechanism, `next-intl@4.0` now allows you to strictly type locales across your app:
51+
52+
```tsx
53+
// global.d.ts
54+
55+
import {routing} from '@/i18n/routing';
56+
57+
declare module 'next-intl' {
58+
interface AppConfig {
59+
// ...
60+
Locale: (typeof routing.locales)[number];
61+
}
62+
}
63+
```
64+
65+
By doing so, APIs like `useLocale()` or `<Link />` that either return or receive a `locale` will now pick up your app-specific `Locale` type, improving type safety across your app.
66+
67+
To simplify narrowing of `string`-based locales, a `hasLocale` function has been added. This can for example be used in [`i18n/request.ts`](https://v4.next-intl.dev/docs/getting-started/app-router/with-i18n-routing#i18n-request) to return a valid locale:
68+
69+
```tsx
70+
import {getRequestConfig} from 'next-intl/server';
71+
import {hasLocale} from 'next-intl';
72+
import {routing} from './routing';
73+
74+
export default getRequestConfig(async ({requestLocale}) => {
75+
// Typically corresponds to the `[locale]` segment
76+
const requested = await requestLocale;
77+
const locale = hasLocale(routing.locales, requested)
78+
? requested
79+
: routing.defaultLocale;
80+
81+
return {
82+
locale,
83+
messages: (await import(`../../messages/${locale}.json`)).default
84+
};
85+
});
86+
```
87+
88+
Furthermore, the `Locale` type can be imported into your app code in case you're passing a locale to another function and want to ensure type safety:
89+
90+
```tsx
91+
import {Locale} from 'next-intl';
92+
93+
async function getPosts(locale: Locale) {
94+
// ...
95+
}
96+
```
97+
98+
Note that strictly-typing the `Locale` is optional and can be used as desired in case you wish to have additional guardrails in your app.
99+
100+
## Strictly-typed ICU arguments
101+
102+
How type-safe can your app be?
103+
104+
The quest to bring type safety to the last corner of `next-intl` has led me down a rabbit hole with the discovery of an ICU parser by [Marco Schumacher](https://github.com/schummar)—written entirely in types. Marco kindly published his implementation for usage in `next-intl`, with me only adding support for rich tags on top.
105+
106+
Check it out:
107+
108+
```tsx
109+
// "Hello {name}"
110+
t('message', {});
111+
// ^? {name: string}
112+
113+
// "It's {today, date, long}"
114+
t('message', {});
115+
// ^? {today: Date}
116+
117+
// "Page {page, number} out of {total, number}"
118+
t('message', {});
119+
// ^? {page: number, total: number}
120+
121+
// "You have {count, plural, =0 {no followers yet} =1 {one follower} other {# followers}}."
122+
t('message', {});
123+
// ^? {count: number}
124+
125+
// "Country: {country, select, US {United States} CA {Canada} other {Other}}"
126+
t('message', {});
127+
// ^? {country: 'US' | 'CA' | (string & {})}
128+
129+
// "Please refer to the <link>guidelines</link>."
130+
t('message', {});
131+
// ^? {link: (chunks: ReactNode) => ReactNode}
132+
```
133+
134+
With this type inference in place, you can now use autocompletion in your IDE to get suggestions for the available arguments of a given ICU message and catch potential errors early.
135+
136+
This also addresses one of my favorite pet peeves:
137+
138+
```tsx
139+
t('followers', {count: 30000});
140+
```
141+
142+
```json
143+
// ✖️ Would be: "30000 followers"
144+
"{count} followers"
145+
146+
// ✅ Valid: "30,000 followers"
147+
"{count, number} followers"
148+
```
149+
150+
Due to a current limitation in TypeScript, this feature is opt-in for now. Please refer to the [strict arguments](https://v4.next-intl.dev/docs/workflows/typescript#messages-arguments) docs to learn how to enable it.
151+
152+
## GDPR compliance [#gdpr-compliance]
153+
154+
In order to comply with the current GDPR regulations, the following changes have been made and are relevant to you if you're using the `next-intl` middleware for i18n routing:
155+
156+
1. The locale cookie has been changed to a session cookie that expires when a browser is closed.
157+
2. The locale cookie is now only set when a user switches to a locale that doesn't match the `accept-language` header.
158+
159+
If you want to increase the cookie expiration, e.g. because you're informing users about the usage of cookies or if GDPR doesn't apply to your app, you can use the `maxAge` attribute to do so:
160+
161+
```tsx
162+
// i18n/routing.tsx
163+
164+
import {defineRouting} from 'next-intl/routing';
165+
166+
export const routing = defineRouting({
167+
// ...
168+
169+
localeCookie: {
170+
// Expire in one year
171+
maxAge: 60 * 60 * 24 * 365
172+
}
173+
});
174+
```
175+
176+
Since the cookie is now only available after a locale switch, make sure to not rely on it always being present. E.g. if you need access to the user's locale in a [Route Handler](https://v4.next-intl.dev/docs/environments/actions-metadata-route-handlers#route-handlers), a reliable option is to provide the locale as a search param (e.g. `/api/posts/12?locale=en`).
177+
178+
As part of this change, disabling a cookie now requires you to set [`localeCookie: false`](https://v4.next-intl.dev/docs/routing#locale-cookie) in your routing configuration. Previously, `localeDetection: false` ambiguously also disabled the cookie from being set, but since a separate `localeCookie` option was introduced recently, this should now be used instead.
179+
180+
Learn more in the [locale cookie](https://v4.next-intl.dev/docs/routing#locale-cookie) docs.
181+
182+
## Modernized build output
183+
184+
The build output of `next-intl` has been modernized and now leverages the following optimizations:
185+
186+
1. **ESM-only:** To enable enhanced tree-shaking and align with the modern JavaScript ecosystem, `next-intl` is now ESM-only. The only exception is `next-intl/plugin` which is published both as CommonJS as well as ESM, due to `next.config.js` still being popular.
187+
2. **Modern JSX transform:** The peer dependency for React has been bumped to v17 in order to use the more efficient, modern JSX transform.
188+
3. **Modern syntax:** Syntax is now compiled down to the Browserslist `defaults` query, which is a shortcut for ">0.5%, last 2 versions, Firefox ESR, not dead"—a baseline that is considered a reasonable target for modern apps.
189+
190+
With these changes, the bundle size of `next-intl` has been reduced by ~7% ([all details](https://github.com/amannn/next-intl/pull/1470)).
191+
192+
## Improved inheritance of `NextIntlClientProvider` [#nextintlclientprovider-inheritance]
193+
194+
Previously, [`NextIntlClientProvider`](/docs/usage/configuration#nextintlclientprovider) would conservatively inherit only a subset from `i18n/request.ts`.
195+
196+
To improve the getting started experience, the provider now also inherits:
197+
198+
- `messages` ([PR #1682](https://github.com/amannn/next-intl/pull/1682))
199+
- `formats` ([PR #1191](https://github.com/amannn/next-intl/pull/1191))
200+
201+
Due to this, you can now remove these props from `NextIntlClientProvider` if you've previously passed them manually:
202+
203+
```diff
204+
<NextIntlClientProvider
205+
- messages={messages}
206+
- formats={formats}
207+
>
208+
{/* ... */}
209+
</NextIntlClientProvider>
210+
```
211+
212+
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.
213+
214+
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)).
215+
216+
## Preparation for upcoming Next.js features [#nextjs-future]
217+
218+
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`.
219+
220+
This led to three minor changes:
221+
222+
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).
223+
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).
224+
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).
225+
226+
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.
227+
228+
I'm particularly excited about the announcement of `rootParams`, as it seems like this will finally fill in the [missing piece](https://github.com/vercel/next.js/discussions/58862) that enables apps with i18n routing to support static rendering without workarounds like `setRequestLocale`. I hope to have more to share on this soon!
229+
230+
## Other breaking changes
231+
232+
1. Return type-safe messages from `useMessages` and `getMessages` (see [PR #1489](https://github.com/amannn/next-intl/pull/1489))
233+
2. Require locale to be returned from `getRequestConfig` (see [PR #1486](https://github.com/amannn/next-intl/pull/1486))
234+
3. Disallow passing `null`, `undefined` or `boolean` as an ICU argument (see [PR #1561](https://github.com/amannn/next-intl/pull/1561))
235+
4. Bump minimum required TypeScript version to 5 for projects using TypeScript (see [PR #1481](https://github.com/amannn/next-intl/pull/1481))
236+
5. Remove deprecated APIs (see [PR #1479](https://github.com/amannn/next-intl/pull/1479))
237+
6. Remove deprecated APIs pt. 2 (see [PR #1482](https://github.com/amannn/next-intl/pull/1482))
238+
239+
## Upgrade now
240+
241+
For a smooth upgrade, please initially upgrade to the latest v3.x version and check for deprecation warnings.
242+
243+
Afterwards, you can upgrade by running:
244+
245+
```
246+
npm install next-intl@v4-beta
247+
```
248+
249+
The beta docs are available here: [v4.next-intl.dev](https://v4.next-intl.dev)
250+
251+
I'd love to hear about your experiences with `next-intl@4.0`! Join the conversation in the [discussions](https://github.com/amannn/next-intl/discussions/1631).
252+
253+
## Thank you!
254+
255+
I want to sincerely thank everyone who has helped to make `next-intl` what it is today.
256+
257+
A special thank you goes to <PartnerContentLink href="https://crowdin.com/">Crowdin</PartnerContentLink>, the primary sponsor of `next-intl`, enabling me to regularly work on this project and provide it as a free and open-source library for everyone.
258+
259+
—Jan
260+
261+
PS: Have you heard that [learn.next-intl.dev](https://learn.next-intl.dev) is coming?
262+
263+
<StayUpdated />

0 commit comments

Comments
 (0)