diff --git a/docs/src/components/BlogVimeoVideo.tsx b/docs/src/components/BlogVimeoVideo.tsx
new file mode 100644
index 000000000..6798d9fd0
--- /dev/null
+++ b/docs/src/components/BlogVimeoVideo.tsx
@@ -0,0 +1,35 @@
+import clsx from 'clsx';
+import Script from 'next/script';
+
+type Props = {
+ className?: string;
+ src: string;
+ title: string;
+};
+
+export default function BlogVimeoVideo({className, src, title}: Props) {
+ return (
+ <>
+
+
+
+
+ >
+ );
+}
diff --git a/docs/src/components/CourseBanner/CourseBanner.tsx b/docs/src/components/CourseBanner/CourseBanner.tsx
index 8357d2794..15da8ce9f 100644
--- a/docs/src/components/CourseBanner/CourseBanner.tsx
+++ b/docs/src/components/CourseBanner/CourseBanner.tsx
@@ -6,9 +6,11 @@ import thumb from './thumb.jpg';
type Props = {
title: string;
+ description: string;
};
export default function CourseBanner({
+ description = 'Learn how to build delightful, multilingual apps with Next.js—from the basics to advanced patterns, all through a real-world project.',
title = "Internationalization isn't just translating words"
}: Props) {
const id = useId();
@@ -32,8 +34,7 @@ export default function CourseBanner({
{title}
- Learn how to build delightful, multilingual apps with Next.js—from the
- basics to advanced patterns, all through a real-world project.
+ {description}
Get started
diff --git a/docs/src/components/Steps.module.css b/docs/src/components/Steps.module.css
index a4653c77e..f8c8f4515 100644
--- a/docs/src/components/Steps.module.css
+++ b/docs/src/components/Steps.module.css
@@ -3,11 +3,13 @@
counter-reset: step;
}
-.root h3 {
+.root h3,
+.root h4 {
counter-increment: step;
@apply text-lg;
}
-.root h3:before {
+.root h3:before,
+.root h4:before {
content: counter(step);
@apply absolute mt-[-6px] ml-[-52px] inline-block h-10 w-10 rounded-full border-4 border-white bg-slate-100 pt-[4px] text-center text-base font-bold text-slate-500;
}
@@ -15,7 +17,8 @@
:global(.dark) .root {
@apply border-slate-800;
}
-:global(.dark) .root h3:before {
+:global(.dark) .root h3:before,
+:global(.dark) .root h4:before {
@apply bg-slate-800 text-white/75;
border-color: rgba(17, 17, 17, var(--tw-bg-opacity)); /* bg-dark */
}
diff --git a/docs/src/pages/blog/_meta.tsx b/docs/src/pages/blog/_meta.tsx
index dd417cb6c..85566b7f2 100644
--- a/docs/src/pages/blog/_meta.tsx
+++ b/docs/src/pages/blog/_meta.tsx
@@ -2,6 +2,10 @@ export default {
index: {
title: 'Overview'
},
+ 'nextjs-root-params': {
+ title: 'Using next/root-params in Next.js 16.2',
+ display: 'hidden'
+ },
'use-extracted': {
title: 'useExtracted: The Tailwind of i18n?',
display: 'hidden'
diff --git a/docs/src/pages/blog/index.mdx b/docs/src/pages/blog/index.mdx
index b0375422e..bfda214ba 100644
--- a/docs/src/pages/blog/index.mdx
+++ b/docs/src/pages/blog/index.mdx
@@ -4,6 +4,12 @@ import StayUpdated from '@/components/StayUpdated.mdx';
# next-intl blog
+
Mar 18, 2026 · by Jan Amann
+
+Next.js v16.3 was just released and comes with a new feature: `next/root-params`.
+
+This new API fills in the [missing piece](https://github.com/vercel/next.js/discussions/58862) that allows apps that use top-level dynamic segments like `[locale]` to read segment values deeply in Server Components:
+
+```tsx
+import {locale} from 'next/root-params';
+
+async function Component() {
+ // The ability to read params deeply in
+ // Server Components ... finally!
+ const locale = await locale();
+}
+```
+
+This addition is a game-changer for `next-intl`.
+
+While the library previously relied on workarounds to provide a locale to Server Components, this API now provides native support in Next.js for this use case, allowing the library to integrate much tighter with Next.js.
+
+Practically, for users of `next-intl` this means:
+
+1. Being able to support static rendering of apps with locale-based routing without `setRequestLocale`
+2. Improved integration with Next.js cache mechanisms like [`cacheComponents`](https://nextjs.org/docs/app/api-reference/config/next-config-js/cacheComponents)
+
+But first, let's have a look at how this API works in practice.
+
+## Introduction to root layouts
+
+
+
+ Prefer to watch a video?
+
+
+
+ → Continue reading at [static rendering](#static-rendering)
+
+
+
+Previously, Next.js required a [root layout](https://nextjs.org/docs/app/api-reference/file-conventions/layout#root-layouts) to be present at `app/layout.tsx`—the root of your app.
+
+Now, you can move a root layout to a nested segment, even if it's a dynamic one:
+
+```
+src
+└── app
+ └── [locale]
+ ├── layout.tsx (root layout)
+ └── page.tsx
+```
+
+In this extended definition, a root layout now is any layout that has **no other layouts located above it**.
+
+In contrast, layouts that do have other layout ancestors are regular layouts:
+
+```
+src
+└── app
+ └── [locale]
+ ├── layout.tsx (root layout)
+ ├── (...)
+ └── news
+ ├── layout.tsx (regular layout)
+ └── page.tsx
+```
+
+With the addition of `next/root-params`, you can now read param values of a root layout in all Server Components that render within it:
+
+```tsx filename=src/components/LocaleSwitcher.tsx
+import {locale} from 'next/root-params';
+
+export async function LocaleSwitcher() {
+ // Read the value of `[locale]`
+ const curLocale = await locale();
+
+ // ...
+}
+```
+
+## Multiple root layouts
+
+Here's where it gets interesting: With [route groups](https://nextjs.org/docs/app/building-your-application/routing/route-groups), you can provide another layout for pages that are not located in the `[locale]` segment:
+
+```
+src
+└── app
+ ├── [locale]
+ │ ├── layout.tsx
+ │ └── page.tsx
+ └── (unlocalized)
+ ├── layout.tsx
+ └── page.tsx
+```
+
+The layout at `[locale]/layout.tsx` as well as the layout at `(unlocalized)/layout.tsx` both have no other layouts located above them, therefore _both_ qualify as root layouts.
+
+Due to this, in this case the returned value of `next/root-params` will depend on where the component that calls the function is being rendered from.
+
+If you call `next/root-params` in shared code that is used by both layouts, this allows for a pattern like this:
+
+```tsx filename="src/utils/getLocale.tsx"
+import {locale} from 'next/root-params';
+
+export default async function getLocale() {
+ // Try to read the locale in case we're in `[locale]/layout.tsx`
+ let curLocale = await locale();
+
+ // If we're in `(unlocalized)/layout.tsx`, let's use a fallback
+ if (!curLocale) {
+ curLocale = 'en';
+ }
+
+ return curLocale;
+}
+```
+
+With this, you can use the `getLocale` function across your codebase to read the current locale without having to worry about where it's being called from.
+
+In an internationalized app, this can for example be useful to implement a country selection page at the root where you have to rely on a default locale. Once the user is within the `[locale]` segment, this param value can be used instead for localizing page content.
+
+## Static rendering
+
+In case we know all possible values for the `[locale]` segment ahead of time, we can provide them to Next.js by using the [`generateStaticParams`](https://nextjs.org/docs/app/api-reference/functions/generate-static-params) function to enable static rendering:
+
+```tsx filename="src/app/[locale]/layout.tsx"
+const locales = ['en', 'de'];
+
+// Pre-render all available locales at build time
+export function generateStaticParams() {
+ return locales.map((locale) => ({locale}));
+}
+
+// ...
+```
+
+Note that [`dynamicParams = false`](https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config/dynamicParams) doesn't work with Cache Components, therefore if you want to treat your `locales` array as exhaustive, you might be better off adding runtime validation for the `[locale]` segment and call `notFound()` to guard against unknown locales.
+
+## Leveraging `next/root-params` in `next-intl`
+
+So, how can you use this in `next-intl`?
+
+Similarly to how we've defined the `getLocale` function above, we do in fact already have a central place that is called by all server-side functions that require the current locale of the user: [`i18n/request.ts`](/docs/usage/configuration#server-client-components).
+
+So let's use `next/root-params` here:
+
+```tsx filename="src/i18n/request.ts" {1,8}
+import * as rootParams from 'next/root-params';
+import {getRequestConfig} from 'next-intl/server';
+import {hasLocale} from 'next-intl';
+import {routing} from './routing';
+import {notFound} from 'next/navigation';
+
+export default getRequestConfig(async () => {
+ const paramValue = await rootParams.locale();
+
+ let locale;
+ if (hasLocale(routing.locales, paramValue)) {
+ locale = paramValue;
+ } else {
+ // Runtime validation for unknown locales
+ notFound();
+ }
+
+ return {
+ locale
+ // ...
+ };
+});
+```
+
+That's it—with a single change to `i18n/request.ts` you can start using `next/root-params`!
+
+---
+
+**One caveat though**: `next/root-params` currently doesn't work in Route Handlers or Server Actions.
+
+You can work around that though by passing an explicit `locale` param at relevant call sites:
+
+```tsx {3}
+async function action(locale: string) {
+ 'use server';
+ const t = await getTranslations({locale, namespace: 'ContactForm'});
+ // ...
+}
+```
+
+… and then incorporate the override in `getRequestConfig`:
+
+```tsx filename="i18n/request.ts"
+// ...
+
+export default getRequestConfig(async ({locale}) => {
+ // Only read from `next/root-params` if no explicit
+ // override is provided by the caller
+ if (!locale) {
+ const paramValue = await rootParams.locale();
+ if (hasLocale(routing.locales, paramValue)) {
+ locale = paramValue;
+ } else {
+ notFound();
+ }
+ }
+
+ return {
+ locale
+ // ...
+ };
+});
+```
+
+## Time for spring cleaning
+
+With this change, you can now simplify your codebase in various ways:
+
+### Remove a pass-through root layout
+
+For certain patterns like global 404 pages, you might have used a pass-through root layout so far:
+
+```tsx filename="src/app/layout.tsx"
+export default function RootLayout({children}: LayoutProps<'/'>) {
+ return children;
+}
+```
+
+This needs to be removed now as otherwise this will qualify as a root layout instead of the one defined at `src/app/[locale]/layout.tsx`.
+
+Instead, you can use [`global-not-found`](/docs/environments/error-files#catching-non-localized-requests) for this now.
+
+### Avoid reading the `[locale]` segment
+
+Since `next-intl` provides the current locale via [`useLocale` and `getLocale`](/docs/usage/configuration#use-locale), you can seamlessly read the locale from these APIs instead of `params` now:
+
+```diff filename="src/app/[locale]/layout.tsx"
++ import {getLocale} from 'next-intl/server';
+
+export default async function RootLayout({
+ children,
+- params
+}: LayoutProps<'/[locale]'>) {
+- const {locale} = await params;
++ const locale = await getLocale();
+
+ return (
+
+ {children}
+
+ );
+}
+```
+
+If you've augmented the [`Locale` type](/docs/workflows/typescript#locale) you'll now also benefit from type safety here:
+
+```tsx
+// ✅ 'en' | 'de'
+const locale = await getLocale();
+```
+
+Behind the scenes, if you call `useLocale` or `getLocale` in a Server Component, your `i18n/request.ts` config will be consulted, potentially using a fallback that you have defined.
+
+### Remove manual locale overrides [#locale-override]
+
+If you're using async APIs like `getTranslations`, you might have previously passed the locale manually, typically to enable static rendering in the Metadata API.
+
+Now, you can remove this and rely on the locale that is returned from `i18n/request.ts`:
+
+```diff filename="src/app/[locale]/page.tsx"
+export async function generateMetadata(
+- {params}: PageProps<'/[locale]'>
+) {
+- const {locale} = await params;
+- const t = await getTranslations({locale, namespace: 'HomePage'});
++ const t = await getTranslations('HomePage');
+
+ // ...
+}
+```
+
+The cases where you still require a locale override are:
+
+1. When you're using functions from `next-intl` in **Route Handlers** or **Server Actions** (these are not supported by `next/root-params`)
+2. If your UI renders messages from **multiple locales** in parallel (uncommon)
+
+### Static rendering
+
+If you've previously used `setRequestLocale` to enable static rendering, you can now remove it:
+
+```diff filename="src/[locale]/page.tsx"
+- import {setRequestLocale} from 'next-intl/server';
+
+- export default function Page({params}: PageProps<'/[locale]'>) {
+- setRequestLocale(params.locale);
++ export default function Page() {
+ // ...
+}
+```
+
+Note that `generateStaticParams` is naturally still required though.
+
+### Custom routing setups
+
+`next-intl` provides mechanisms like [`localePrefix`](/docs/routing/configuration#localeprefix) (and esp. [`prefixes`](/docs/routing/configuration#locale-prefix-prefixes)) that allow you to customize your [routing configuration](/docs/routing). However, some apps might require further customization that goes beyond the capabilities that `next-intl` provides out of the box.
+
+With the introduction of `next/root-params`, it's now easier than ever to implement custom routing setups, while still being able to use core functionality from `next-intl` like `useTranslations`.
+
+**Example:**
+
+```
+app/
+└── [tenant]
+ ├── layout.tsx
+ └── page.tsx
+```
+
+```tsx filename="src/i18n/request.ts"
+import * as rootParams from 'next/root-params';
+import {getRequestConfig} from 'next-intl/server';
+import {fetchTenant} from '@/services/tenant';
+
+export default getRequestConfig(async () => {
+ const tenantId = await rootParams.tenant();
+ const tenant = await fetchTenant(tenantId);
+ const locale = tenant.locale;
+
+ return {
+ locale
+ // ...
+ };
+});
+```
+
+In this case, you can consider implementing your own [middleware](/docs/routing/middleware) and [navigation APIs](/docs/routing/navigation), if relevant.
+
+## Try `next/root-params` today!
+
+If you're giving `next/root-params` a go with `next-intl`, let me know how it works for you by joining the discussion here: [Experiences with `next/root-params`](https://github.com/amannn/next-intl/discussions/1627).
+
+I'm curious to hear how it simplifies your codebase!
+
+—Jan
+
+
+
+
diff --git a/docs/src/pages/docs/environments/actions-metadata-route-handlers.mdx b/docs/src/pages/docs/environments/actions-metadata-route-handlers.mdx
index dc8f2a1a2..0b7d6afa8 100644
--- a/docs/src/pages/docs/environments/actions-metadata-route-handlers.mdx
+++ b/docs/src/pages/docs/environments/actions-metadata-route-handlers.mdx
@@ -22,9 +22,8 @@ To internationalize metadata like the page title, you can use functionality from
```tsx filename="layout.tsx"
import {getTranslations} from 'next-intl/server';
-export async function generateMetadata({params}) {
- const {locale} = await params;
- const t = await getTranslations({locale, namespace: 'Metadata'});
+export async function generateMetadata() {
+ const t = await getTranslations('Metadata');
return {
title: t('title')
@@ -32,13 +31,6 @@ export async function generateMetadata({params}) {
}
```
-
- By passing an explicit `locale` to the awaitable functions from `next-intl`,
- you can make the metadata handler eligible for [static
- rendering](/docs/routing/setup#static-rendering) if you're using [locale-based
- routing](/docs/routing).
-
-
### Server Actions
[Server Actions](https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations) provide a mechanism to execute server-side code that is invoked by the client. In case you're returning user-facing messages, you can use `next-intl` to localize them based on the user's locale.
@@ -46,10 +38,10 @@ export async function generateMetadata({params}) {
```tsx
import {getTranslations} from 'next-intl/server';
-async function loginAction(data: FormData) {
+async function loginAction(locale: string, data: FormData) {
'use server';
- const t = await getTranslations('LoginForm');
+ const t = await getTranslations({namespace: 'LoginForm', locale});
const areCredentialsValid = /* ... */;
if (!areCredentialsValid) {
return {error: t('invalidCredentials')};
@@ -57,7 +49,9 @@ async function loginAction(data: FormData) {
}
```
-Note that when you're displaying messages generated in Server Actions to the user, you should consider the case if the user can switch the locale while the message is displayed to ensure that the UI is localized consistently. If you're using [a `[locale]` segment](/docs/routing) as part of your routing strategy then this is handled automatically. If you're not, you might want to clear the message manually, e.g. by [resetting the state](https://react.dev/learn/preserving-and-resetting-state#resetting-a-form-with-a-key) of the respective component via `key={locale}`.
+Note that when you're displaying messages generated in Server Actions to the user, you should consider the case if the user can switch the locale while the message is displayed to ensure that the UI is localized consistently.
+
+If you're using [a `[locale]` segment](/docs/routing) as part of your routing strategy then this is handled automatically. If you're not, you might want to clear the message manually, e.g. by [resetting the state](https://react.dev/learn/preserving-and-resetting-state#resetting-a-form-with-a-key) of the respective component via `key={locale}`.
When using Zod for validation, how can I localize error messages?
@@ -76,10 +70,10 @@ const loginFormSchema = z.object({
// ...
-async function loginAction(data: FormData) {
+async function loginAction(locale: string, data: FormData) {
'use server';
- const t = await getTranslations('LoginForm');
+ const t = await getTranslations({namespace: 'LoginForm', locale});
const values = Object.fromEntries(data);
const result = loginFormSchema.safeParse(values, {
diff --git a/docs/src/pages/docs/environments/error-files.mdx b/docs/src/pages/docs/environments/error-files.mdx
index 17d6afb78..bbcaa4a9f 100644
--- a/docs/src/pages/docs/environments/error-files.mdx
+++ b/docs/src/pages/docs/environments/error-files.mdx
@@ -49,14 +49,12 @@ After this change, all requests that are matched within the `[locale]` segment w
When the user requests a route that is not matched by the `next-intl` [middleware](/docs/routing/middleware), there's no locale associated with the request (depending on your [`matcher` config](/docs/routing/middleware#matcher-config), e.g. `/unknown.txt` might not be matched).
-You can add a root `not-found` page to handle these cases too.
-
-```tsx filename="app/not-found.tsx"
-'use client';
+You can add a [`global-not-found`](https://nextjs.org/docs/app/api-reference/file-conventions/not-found#global-not-foundjs-experimental) page to handle these cases too:
+```tsx filename="app/global-not-found.tsx"
import Error from 'next/error';
-export default function NotFound() {
+export default function GlobalNotFound() {
return (
@@ -67,32 +65,7 @@ export default function NotFound() {
}
```
-Note that the presence of `app/not-found.tsx` requires that a root layout is available, even if it's just passing `children` through.
-
-```tsx filename="app/layout.tsx"
-// Since we have a root `not-found.tsx` page, a layout file
-// is required, even if it's just passing children through.
-export default function RootLayout({children}) {
- return children;
-}
-```
-
-For the 404 page to render, we need to call the `notFound` function in the root layout when we detect an incoming `locale` param that isn't valid.
-
-```tsx filename="app/[locale]/layout.tsx"
-import {hasLocale} from 'next-intl';
-import {notFound} from 'next/navigation';
-import {routing} from '@/i18n/routing';
-
-export default function LocaleLayout({children, params}) {
- const {locale} = await params;
- if (!hasLocale(routing.locales, locale)) {
- notFound();
- }
-
- // ...
-}
-```
+For the 404 page to render, we need to call the `notFound` function when an unknown value for the `[locale]` segment is encountered—typically in [`i18n/request.ts`](/docs/routing/setup#i18n-request).
## `error.js`
diff --git a/docs/src/pages/docs/routing/setup.mdx b/docs/src/pages/docs/routing/setup.mdx
index 986660b2a..d57c45ba4 100644
--- a/docs/src/pages/docs/routing/setup.mdx
+++ b/docs/src/pages/docs/routing/setup.mdx
@@ -106,19 +106,24 @@ export const {Link, redirect, usePathname, useRouter, getPathname} =
### `src/i18n/request.ts` [#i18n-request]
-Now, we can read the matched locale in our request configuration:
+Now, we can read the matched locale from [`next/root-params`](/blog/nextjs-root-params) in our request configuration:
```tsx filename="src/i18n/request.ts"
+import * as rootParams from 'next/root-params';
+import {notFound} from 'next/navigation';
import {getRequestConfig} from 'next-intl/server';
import {hasLocale} from 'next-intl';
import {routing} from './routing';
-export default getRequestConfig(async ({requestLocale}) => {
- // Typically corresponds to the `[locale]` segment
- const requested = await requestLocale;
- const locale = hasLocale(routing.locales, requested)
- ? requested
- : routing.defaultLocale;
+export default getRequestConfig(async ({locale}) => {
+ if (!locale) {
+ const paramValue = await rootParams.locale();
+ if (hasLocale(routing.locales, paramValue)) {
+ locale = paramValue;
+ } else {
+ notFound();
+ }
+ }
return {
locale
@@ -127,6 +132,20 @@ export default getRequestConfig(async ({requestLocale}) => {
});
```
+The `locale` argument that is passed to `getRequestConfig` can be used for edge cases where you need to override the current locale.
+
+**Note:** `next/root-params` is currently experimental and needs to be enabled in your Next.js config:
+
+```tsx filename="next.config.tsx"
+const nextConfig = {
+ experimental: {
+ rootParams: true
+ }
+};
+
+// ...
+```
+
### `src/app/[locale]/layout.tsx` [#layout]
To complete our setup, we'll move all of our existing layouts and pages into the `[locale]` segment:
@@ -140,42 +159,68 @@ src
└── ...
```
-The `locale` that was matched is now available via the `[locale]` param:
+
-```tsx filename="app/[locale]/layout.tsx"
-import {NextIntlClientProvider, hasLocale} from 'next-intl';
-import {notFound} from 'next/navigation';
-import {routing} from '@/i18n/routing';
+That's all it takes!
-type Props = {
- children: React.ReactNode;
- params: Promise<{locale: string}>;
-};
+The `locale` that was matched is now correctly incorporated in all functionality from `next-intl`:
-export default async function LocaleLayout({children, params}: Props) {
- // Ensure that the incoming `locale` is valid
- const {locale} = await params;
- if (!hasLocale(routing.locales, locale)) {
- notFound();
- }
+```tsx filename="app/[locale]/layout.tsx"
+import {useTranslations} from 'next-intl';
+
+export default function Page() {
+ // ✅ Uses the locale from `i18n/request.ts`
+ const t = useTranslations();
// ...
}
```
-
-
-That's all it takes! From here, you can [configure your routing](/docs/routing/configuration) to cater to your specific needs.
+From here, you can [configure your routing](/docs/routing/configuration) to cater to your specific needs.
In case you ran into an issue, have a look at the [App Router example](/examples#app-router) to explore a working app.
## Static rendering
+### With `next/root-params`
+
+When you follow the setup instructions with `next/root-params` above, your app is automatically eligible for static rendering. Since we are using a dynamic route segment for the `[locale]` param, we need to use [`generateStaticParams`](https://nextjs.org/docs/app/api-reference/functions/generate-static-params) so that the routes can be rendered at build time.
+
+Depending on your needs, you can add `generateStaticParams` either to a layout or pages:
+
+1. **Layout**: Enables static rendering for all pages within this layout (e.g. `app/[locale]/layout.tsx`)
+2. **Individual pages**: Enables static rendering for a specific page (e.g. `app/[locale]/page.tsx`)
+
+**Example:**
+
+```tsx
+import {routing} from '@/i18n/routing';
+
+export function generateStaticParams() {
+ return routing.locales.map((locale) => ({locale}));
+}
+```
+
+
+Do I need to return all locales from `generateStaticParams`?
+
+If you prefer to only render certain locales at build time, or none at all, you can be selective about the ones you return from `generateStaticParams` (see [Static Rendering](https://nextjs.org/docs/app/api-reference/functions/generate-static-params#static-rendering) in the Next.js docs).
+
+
+
+### With `setRequestLocale` (legacy)
+
+
+
+`setRequestLocale` is a legacy API that was added until `next/root-params` was introduced. It is still supported for backwards compatibility, but it is recommended to use `next/root-params` instead.
+
+
+
When using locale-based routing, `next-intl` will currently opt into dynamic rendering when APIs like `useTranslations` are used in Server Components. This is a limitation that we aim to remove in the future, but as a stopgap solution, `next-intl` provides a temporary API that can be used to enable static rendering.
-### Add `generateStaticParams`
+#### Add `generateStaticParams`
Since we are using a dynamic route segment for the `[locale]` param, we need to use [`generateStaticParams`](https://nextjs.org/docs/app/api-reference/functions/generate-static-params) so that the routes can be rendered at build time.
@@ -201,7 +246,7 @@ If you prefer to only render certain locales at build time, or none at all, you
-### Add `setRequestLocale` to all relevant layouts and pages
+#### Add `setRequestLocale` to all relevant layouts and pages
`next-intl` provides an API that can be used to distribute the locale that is received via `params` in layouts and pages for usage in all Server Components that are rendered as part of the request.
@@ -280,7 +325,7 @@ By using `setRequestLocale`, you can provide the locale that is received in layo
-### Use the `locale` param in metadata
+#### Use the `locale` param in metadata
In addition to the rendering of your pages, also page metadata needs to qualify for static rendering.
diff --git a/docs/src/pages/docs/usage/configuration.mdx b/docs/src/pages/docs/usage/configuration.mdx
index 82153cc5a..d363eaaf1 100644
--- a/docs/src/pages/docs/usage/configuration.mdx
+++ b/docs/src/pages/docs/usage/configuration.mdx
@@ -13,13 +13,13 @@ Depending on if you handle internationalization in [Server- or Client Components
### `i18n/request.ts` & `getRequestConfig` [#i18n-request]
-`i18n/request.ts` can be used to provide configuration for **server-only** code, i.e. Server Components, Server Actions & friends. The configuration is provided via the `getRequestConfig` function and provides a `requestLocale` parameter in case you're using [locale-based routing](/docs/routing).
+`i18n/request.ts` can be used to provide configuration for **server-only** code, i.e. Server Components, Server Actions & friends. The configuration is provided via the `getRequestConfig` function and optionally provides a `locale` parameter in case you're overriding the `locale` at call sites.
```tsx filename="i18n/request.ts"
import {getRequestConfig} from 'next-intl/server';
import {routing} from '@/i18n/routing';
-export default getRequestConfig(async ({requestLocale}) => {
+export default getRequestConfig(async ({locale}) => {
// ...
return {
@@ -34,6 +34,23 @@ The configuration object is created once for each request by internally using Re
Since this function is executed during the Server Components render pass, you can call functions like [`cookies()`](https://nextjs.org/docs/app/api-reference/functions/cookies) and [`headers()`](https://nextjs.org/docs/app/api-reference/functions/headers) to return configuration that is request-specific.
+
+What is the `requestLocale` parameter?
+
+Before Next.js introduced `next/root-params`, the `requestLocale` parameter was used to read the `[locale]` segment from the middleware, optionally allowing to override it from [`setRequestLocale`](/docs/routing/setup#with-setrequestlocale-legacy).
+
+This is considered legacy and is no longer recommended.
+
+If you're still using `setRequestLocale`, the parameter typically corresponds to the `[locale]` segment that was matched by the middleware.
+
+However, there are three special cases to consider:
+
+1. **Overrides**: When an explicit `locale` is passed to [awaitable functions](/docs/environments/actions-metadata-route-handlers) like `getTranslations({locale: 'en'})`, then this value will be used instead of the segment.
+1. **`undefined`**: The value can be `undefined` when a page outside of the `[locale]` segment renders (e.g. a language selection page at `app/page.tsx`).
+1. **Invalid values**: Since the `[locale]` segment effectively acts like a catch-all for unknown routes (e.g. `/unknown.txt`), invalid values should be replaced with a valid locale. In addition to this, you might want to call `notFound()` in the [root layout](/docs/routing/setup#layout) to abort the render in this case.
+
+
+
### `NextIntlClientProvider`
`NextIntlClientProvider` can be used to provide configuration for **Client Components**.
@@ -141,27 +158,6 @@ The `locale` represents an identifier that contains the language and formatting
-Depending on if you're using [locale-based routing](/docs/routing), you can read the locale from the `requestLocale` parameter or provide a value on your own:
-
-**With locale-based routing:**
-
-```tsx filename="i18n/request.ts"
-export default getRequestConfig(async ({requestLocale}) => {
- // Typically corresponds to the `[locale]` segment
- const requested = await requestLocale;
- const locale = hasLocale(routing.locales, requested)
- ? requested
- : routing.defaultLocale;
-
- return {
- locale
- // ...
- };
-});
-```
-
-**Without locale-based routing:**
-
```tsx filename="i18n/request.ts"
export default getRequestConfig(async () => {
// Provide a static locale, fetch a user setting,
@@ -175,17 +171,6 @@ export default getRequestConfig(async () => {
});
```
-
-Which values can the `requestLocale` parameter hold?
-
-While the `requestLocale` parameter typically corresponds to the `[locale]` segment that was matched by the middleware, there are three special cases to consider:
-
-1. **Overrides**: When an explicit `locale` is passed to [awaitable functions](/docs/environments/actions-metadata-route-handlers) like `getTranslations({locale: 'en'})`, then this value will be used instead of the segment.
-1. **`undefined`**: The value can be `undefined` when a page outside of the `[locale]` segment renders (e.g. a language selection page at `app/page.tsx`).
-1. **Invalid values**: Since the `[locale]` segment effectively acts like a catch-all for unknown routes (e.g. `/unknown.txt`), invalid values should be replaced with a valid locale. In addition to this, you might want to call `notFound()` in the [root layout](/docs/routing/setup#layout) to abort the render in this case.
-
-
-
diff --git a/packages/next-intl/src/server/react-server/RequestLocaleCache.tsx b/packages/next-intl/src/server/react-server/RequestLocaleCache.tsx
index 98219f2b2..652c4f7eb 100644
--- a/packages/next-intl/src/server/react-server/RequestLocaleCache.tsx
+++ b/packages/next-intl/src/server/react-server/RequestLocaleCache.tsx
@@ -13,6 +13,9 @@ export function getCachedRequestLocale() {
return getCache().locale;
}
+/**
+ * @deprecated Please migrate to [`next/root-params`](https://next-intl.dev/blog/nextjs-root-params).
+ */
export function setCachedRequestLocale(locale: Locale) {
getCache().locale = locale;
}