Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: next-intl@4 #1412

Draft
wants to merge 80 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
a8fb0e3
fix: Don't commit canary releases
amannn Jun 20, 2024
cf3f8b0
Improve docs [skip ci]
amannn Jun 20, 2024
4fd9b20
fix: Try out updated credits
amannn Jun 20, 2024
47239f9
v3.15.3-canary.0
amannn Jun 20, 2024
0d60a72
Revert "v3.15.3-canary.0"
amannn Jun 20, 2024
c459669
Merge remote-tracking branch 'origin/main' into canary
amannn Jun 20, 2024
8d3ab38
fix: Prefer more specific routes in `usePathname` when detecting the …
amannn Jun 26, 2024
605c9a6
Merge remote-tracking branch 'origin/main' into canary
amannn Jun 26, 2024
cb15046
Merge branch 'fix/sort-pathnames-usepathname' into canary
amannn Jun 26, 2024
11262b8
Merge remote-tracking branch 'origin/main' into canary
amannn Jul 11, 2024
7976376
feat: Support `trailingSlash: true` in Next.js config (#1188)
amannn Jul 11, 2024
b352c10
fix: Release please?
amannn Jul 11, 2024
cba448a
Merge remote-tracking branch 'origin/main' into canary
amannn Jul 11, 2024
0c670b2
Merge remote-tracking branch 'origin/main' into canary
amannn Jul 12, 2024
5dc7f53
Merge remote-tracking branch 'origin/main' into canary
amannn Jul 12, 2024
11dcbcc
Merge remote-tracking branch 'origin/main' into canary
amannn Jul 12, 2024
1b074da
Merge remote-tracking branch 'origin/main' into canary
amannn Jul 12, 2024
e98682b
Merge remote-tracking branch 'origin/main' into canary
amannn Jul 15, 2024
7c6f533
Merge branch 'main' into canary
amannn Aug 23, 2024
8b4c7c4
feat!: Automatically inherit `formats` when `NextIntlClientProvider` …
amannn Aug 26, 2024
d80d691
feat!: Inherit context between providers (#1413)
amannn Oct 9, 2024
8158de4
Merge remote-tracking branch 'origin/canary' into HEAD
amannn Oct 9, 2024
7dd54c1
Merge remote-tracking branch 'origin/canary' into v4
amannn Oct 24, 2024
ccaef97
fix lint
amannn Oct 24, 2024
25a0dc8
bump size
amannn Oct 24, 2024
9f4754c
feat!: Make package ESM-only, target modern browsers, use modern JSX …
amannn Oct 29, 2024
5b5f0e3
feat!: Remove deprecated APIs (#1479)
amannn Oct 29, 2024
eb5bf09
feat!: Bump minimum required `typescript` version to 5 for projects u…
amannn Oct 29, 2024
a6238f4
feat!: Remove deprecated APIs pt. 2 (#1482)
amannn Oct 29, 2024
829998e
feat!: Infer default `locale` for `NextIntlClientProvider` from `useP…
amannn Oct 29, 2024
a9c35db
add comment
amannn Oct 29, 2024
5402851
feat!: Require `locale` to be returned from `getRequestConfig` (#1486)
amannn Oct 29, 2024
b4e4d1d
feat!: Decrease cookie expiration to 5 hours, only set cookie when ne…
amannn Oct 30, 2024
d83abc2
feat: Return type-safe `IntlMessages` from `useMessages` & `getMessag…
amannn Oct 30, 2024
a7aaf56
feat!: Revamp augmented types and add support for typed `Locale` (#1495)
amannn Nov 1, 2024
2388c9b
remove unused file
amannn Nov 1, 2024
01268f6
feat: Type-safe ICU arguments (#1499)
amannn Nov 7, 2024
0bb75c5
decrease size by making plain message error handling dev-only
amannn Nov 7, 2024
dd28ac1
fix: Allow to merge inline formats with global formats in `t` (#1523)
amannn Nov 7, 2024
4675f7e
Merge remote-tracking branch 'origin/main' into v4
amannn Nov 8, 2024
c154409
move/rename file
amannn Nov 8, 2024
887034d
simplify signature
amannn Nov 8, 2024
ab22a92
temporarily disable exports that cause OOM
amannn Nov 8, 2024
b9c515e
simplify types for `createTranslator`
amannn Nov 8, 2024
8ac7206
fix: Fix recursion bug in typed ICU args (#1527)
amannn Nov 8, 2024
21f2dac
remove outdated constant
amannn Nov 12, 2024
2a92f17
feat!: Remove default of `now={new Date()}` from `NextIntlClientProvi…
amannn Nov 14, 2024
dc36097
feat!: Don't read a default for `useLocale` from `useParams.locale` o…
amannn Nov 14, 2024
3ff1923
decrease size, relax next.js peer dependency
amannn Nov 14, 2024
f44ae15
feat: Adopt shared ICU type parser (#1549)
amannn Nov 14, 2024
7d89d54
chore: Strict type imports with ESLint (#1524)
amannn Nov 14, 2024
c2a8984
Merge remote-tracking branch 'origin/main' into v4
amannn Nov 15, 2024
00a79d4
feat: publish v4 prerelease
amannn Nov 15, 2024
ba18078
rename canary workflow
amannn Nov 15, 2024
6f1a39d
unique workflow names [skip ci]
amannn Nov 15, 2024
486a7bd
docs: minor fixes
amannn Nov 15, 2024
dfa5ea0
docs: blog post draft
amannn Nov 18, 2024
9ea117c
fix: Disallow string dates, improve autocomplete (#1557)
amannn Nov 18, 2024
c8eb4ad
fix: Use `fs.watch` instead of `chokidar`
amannn Nov 19, 2024
5a7f7be
fix: Move locale validation to `defineRouting` (#1560)
amannn Nov 19, 2024
bfcd251
docs: Proofread blog post
amannn Nov 19, 2024
7b755e9
fix: update warning for now fallback in `createFormatter`
amannn Nov 19, 2024
18156c4
fix: use v4-beta tag instead
amannn Nov 19, 2024
0b2c951
docs: reference new tag
amannn Nov 19, 2024
6275030
feat!: Disallow passing `null`, `undefined` or `boolean` as an ICU ar…
amannn Nov 20, 2024
c323050
fix: release for "feat!: " as well
amannn Nov 20, 2024
8cce53e
docs: performance notes of messages augmentation
amannn Nov 20, 2024
6d94a9e
docs: fix toc, note in gdpr release notes [skip ci]
amannn Nov 28, 2024
db95243
docs: Update legacy example to use `next-intl` instead of `use-intl` …
amannn Nov 28, 2024
21b882a
docs: improve relative time formatting docs (also fix release conditi…
amannn Nov 28, 2024
cb6b998
Merge remote-tracking branch 'origin/main' into v4
amannn Nov 28, 2024
8f37883
fix: Change error messages to not mention provider (since there might…
amannn Dec 2, 2024
8b9a2fc
Merge remote-tracking branch 'origin/main' into v4
amannn Dec 18, 2024
7e7011d
fix: Fix hard reload when using `<Link />` in Next.js 15 (#1620)
amannn Dec 18, 2024
9f3a4b0
docs: Improve blog post wording
amannn Dec 19, 2024
dac018a
docs: blog post wording
amannn Dec 19, 2024
c224d1c
docs: Remove blog post
amannn Dec 20, 2024
0825f08
feat: Re-introduce `locale` argument for `getRequestConfig` to be use…
amannn Dec 20, 2024
56f59a7
docs: v4 banner
amannn Dec 20, 2024
e65f4f9
Merge remote-tracking branch 'origin/main' into v4
amannn Dec 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
jobs:
build:
name: Build, lint, and test
runs-on: ubuntu-latest
runs-on: macos-15
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: prerelease
name: prerelease (canary)

on:
push:
Expand Down Expand Up @@ -26,7 +26,7 @@ jobs:
- run: |
sed -i 's/"use-intl": "workspace:\^"/"use-intl": "workspace:"/' ./packages/next-intl/package.json && git commit -am "use fixed version"
- run: pnpm lerna publish 0.0.0-canary-${GITHUB_SHA::7} --no-git-reset --dist-tag canary --no-push --yes
if: "${{startsWith(github.event.head_commit.message, 'fix: ') || startsWith(github.event.head_commit.message, 'feat: ')}}"
if: "${{startsWith(github.event.head_commit.message, 'fix: ') || startsWith(github.event.head_commit.message, 'feat: ') || startsWith(github.event.head_commit.message, 'feat!: ')}}"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
Expand Down
33 changes: 33 additions & 0 deletions .github/workflows/prerelease-v4.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: prerelease (v4)

on:
push:
branches:
- v4

jobs:
main:
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
registry-url: 'https://registry.npmjs.org'
node-version: 20.x
cache: 'pnpm'
- run: pnpm install
- run: |
git config --global user.name "${{ github.actor }}"
git config --global user.email "${{ github.actor }}@users.noreply.github.com"
- run: |
sed -i 's/"use-intl": "workspace:\^"/"use-intl": "workspace:"/' ./packages/next-intl/package.json && git commit -am "use fixed version"
- run: pnpm lerna publish 4.0.0-beta-${GITHUB_SHA::7} --no-git-reset --dist-tag v4-beta --no-push --yes
if: "${{startsWith(github.event.head_commit.message, 'fix: ') || startsWith(github.event.head_commit.message, 'feat: ') || startsWith(github.event.head_commit.message, 'feat!: ')}}"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_CONFIG_PROVENANCE: true
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
git config --global user.name "${{ github.actor }}"
git config --global user.email "${{ github.actor }}@users.noreply.github.com"
- run: pnpm run publish
if: "${{startsWith(github.event.head_commit.message, 'fix: ') || startsWith(github.event.head_commit.message, 'feat: ')}}"
if: "${{startsWith(github.event.head_commit.message, 'fix: ') || startsWith(github.event.head_commit.message, 'feat: ') || startsWith(github.event.head_commit.message, 'feat!: ')}}"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
Expand Down
1 change: 0 additions & 1 deletion docs/src/components/StayUpdated.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@

**Let's keep in touch:**

- [GitHub releases](https://github.com/amannn/next-intl/releases)
- [Bluesky (Jan Amann)](https://bsky.app/profile/amann.work)
- [X (Jan Amann)](https://x.com/jamannnnnn)
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,9 @@ Note that by default, `next-intl` returns [the `link` response header](/docs/rou

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.

```tsx filename="app/sitemap.ts" {4-5,8-9}
```tsx filename="app/sitemap.ts" {5-6,9-10}
import {MetadataRoute} from 'next';
import {Locale} from 'next-intl';
import {routing, getPathname} from '@/i18n/routing';

// Adapt this as necessary
Expand All @@ -179,7 +180,7 @@ function getEntry(href: Href) {
};
}

function getUrl(href: Href, locale: (typeof routing.locales)[number]) {
function getUrl(href: Href, locale: Locale) {
const pathname = getPathname({locale, href});
return host + pathname;
}
Expand All @@ -206,12 +207,16 @@ You can use `next-intl` in [Route Handlers](https://nextjs.org/docs/app/building

```tsx filename="app/api/hello/route.tsx"
import {NextResponse} from 'next/server';
import {hasLocale} from 'next-intl';
import {getTranslations} from 'next-intl/server';

export async function GET(request) {
// Example: Receive the `locale` via a search param
const {searchParams} = new URL(request.url);
const locale = searchParams.get('locale');
if (!hasLocale(locales, locale)) {
return NextResponse.json({error: 'Invalid locale'}, {status: 400});
}

const t = await getTranslations({locale, namespace: 'Hello'});
return NextResponse.json({title: t('title')});
Expand Down
7 changes: 4 additions & 3 deletions docs/src/pages/docs/environments/error-files.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,15 @@ export default function RootLayout({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 a valid locale.
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: {locale}}) {
// Ensure that the incoming `locale` is valid
if (!routing.locales.includes(locale as any)) {
if (!hasLocale(routing.locales, locale)) {
notFound();
}

Expand Down
8 changes: 5 additions & 3 deletions docs/src/pages/docs/environments/server-client-components.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,17 @@ These functions are available:

Components that aren't declared with the `async` keyword and don't use interactive features like `useState`, are referred to as [shared components](https://github.com/reactjs/rfcs/blob/main/text/0188-server-components.md#sharing-code-between-server-and-client). These can render either as a Server or Client Component, depending on where they are imported from.

In Next.js, Server Components are the default, and therefore shared components will typically execute as Server Components.
In Next.js, Server Components are the default, and therefore shared components will typically execute as Server Components:

```tsx filename="UserDetails.tsx"
import {useTranslations} from 'next-intl';

export default function UserDetails({user}) {
const t = useTranslations('UserProfile');

// This component will execute as a Server Component by default.
// However, if it is imported from a Client Component, it will
// execute as a Client Component.
return (
<section>
<h2>{t('title')}</h2>
Expand Down Expand Up @@ -275,7 +278,7 @@ In particular, page and search params are often a great option because they offe

### Option 3: Providing individual messages

To reduce bundle size, `next-intl` doesn't automatically provide [messages](/docs/usage/configuration#messages) or [formats](/docs/usage/configuration#formats) to Client Components.
To reduce bundle size, `next-intl` doesn't automatically provide [messages](/docs/usage/configuration#messages) to Client Components.

If you need to incorporate dynamic state into components that can not be moved to the server side, you can wrap these components with `NextIntlClientProvider` and provide the relevant messages.

Expand Down Expand Up @@ -366,7 +369,6 @@ The component accepts the following props that are not serializable:

1. [`onError`](/docs/usage/configuration#error-handling)
2. [`getMessageFallback`](/docs/usage/configuration#error-handling)
3. Rich text elements for [`defaultTranslationValues`](/docs/usage/configuration#default-translation-values)

To configure these, you can wrap `NextIntlClientProvider` with another component that is marked with `'use client'` and defines the relevant props.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,16 +147,15 @@ When using features from `next-intl` in Server Components, the relevant configur

```tsx filename="src/i18n/request.ts"
import {getRequestConfig} from 'next-intl/server';
import {hasLocale} from 'next-intl';
import {routing} from './routing';

export default getRequestConfig(async ({requestLocale}) => {
// This typically corresponds to the `[locale]` segment
let locale = await requestLocale;

// Ensure that a valid locale is used
if (!locale || !routing.locales.includes(locale as any)) {
locale = routing.defaultLocale;
}
// Typically corresponds to the `[locale]` segment
const requested = await requestLocale;
const locale = hasLocale(routing.locales, requested)
? requested
: routing.defaultLocale;

return {
locale,
Expand Down Expand Up @@ -186,7 +185,7 @@ const withNextIntl = createNextIntlPlugin(
The `locale` that was matched by the middleware is available via the `locale` param and can be used to configure the document language. Additionally, we can use this place to pass configuration from `i18n/request.ts` to Client Components via `NextIntlClientProvider`.

```tsx filename="app/[locale]/layout.tsx"
import {NextIntlClientProvider} from 'next-intl';
import {NextIntlClientProvider, Locale, hasLocale} from 'next-intl';
import {getMessages} from 'next-intl/server';
import {notFound} from 'next/navigation';
import {routing} from '@/i18n/routing';
Expand All @@ -196,10 +195,9 @@ export default async function LocaleLayout({
params: {locale}
}: {
children: React.ReactNode;
params: {locale: string};
params: {locale: Locale};
}) {
// Ensure that the incoming `locale` is valid
if (!routing.locales.includes(locale as any)) {
if (!hasLocale(routing.locales, locale)) {
notFound();
}

Expand Down Expand Up @@ -297,12 +295,12 @@ export function generateStaticParams() {

```tsx filename="app/[locale]/layout.tsx"
import {setRequestLocale} from 'next-intl/server';
import {hasLocale} from 'next-intl';
import {notFound} from 'next/navigation';
import {routing} from '@/i18n/routing';

export default async function LocaleLayout({children, params: {locale}}) {
// Ensure that the incoming `locale` is valid
if (!routing.locales.includes(locale as any)) {
if (!hasLocale(routing.locales, locale)) {
notFound();
}

Expand Down
6 changes: 0 additions & 6 deletions docs/src/pages/docs/getting-started/pages-router.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,3 @@ export async function getStaticProps() {
</ul>

</Callout>

## Support for legacy Next.js versions

Next.js version 10, 11 and 12 are still supported. Note however that instead of installing `next-intl`, you'll have to import functionality like `useTranslations` from [`use-intl`](/docs/environments/core-library#react-apps).

See the [legacy example](https://github.com/amannn/next-intl/tree/main/examples/example-pages-router-legacy).
28 changes: 20 additions & 8 deletions docs/src/pages/docs/routing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ In this case, requests for all locales will be rewritten to have the locale only
**Note that:**

1. If you use this strategy, you should adapt your matcher to detect [unprefixed pathnames](/docs/routing/middleware#matcher-no-prefix).
2. If you don't use domain-based routing, the cookie is now the source of truth for determining the locale. Make sure that your hosting solution reliably returns the `set-cookie` header from the middleware (e.g. Vercel and Cloudflare are known to potentially [strip this header](https://developers.cloudflare.com/cache/concepts/cache-behavior/#interaction-of-set-cookie-response-header-with-cache) for cacheable requests).
3. [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`.
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`.
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.

#### Custom prefixes [#locale-prefix-custom]

Expand Down Expand Up @@ -297,11 +297,12 @@ In case you're using a system like a CMS to configure localized pathnames, you'l

```tsx filename="page.tsx"
import {notFound} from 'next';
import {Locale} from 'next-intl';
import {fetchContent} from './cms';

type Props = {
params: {
locale: string;
locale: Locale;
slug: Array<string>;
};
};
Expand Down Expand Up @@ -472,11 +473,11 @@ In this case, only the locale prefix and a potentially [matching domain](#domain

### Locale cookie [#locale-cookie]

By default, the middleware will set a cookie called `NEXT_LOCALE` that contains the most recently detected locale. This is used to [remember the user's locale](/docs/routing/middleware#locale-detection) preference for future requests.
If a user changes the locale to a value that doesn't match the `accept-language` header, `next-intl` will set a cookie called `NEXT_LOCALE` that contains the most recently detected locale. This is used to [remember the user's locale](/docs/routing/middleware#locale-detection) preference for future requests.

By default, the cookie will be configured with the following attributes:

1. [**`maxAge`**](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#max-agenumber): This value is set to 1 year so that the preference of the user is kept as long as possible.
1. [**`maxAge`**](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#max-agenumber): This value is set to 5 hours in order to be [GDPR-compliant](#locale-cookie-gdpr) out of the box.
2. [**`sameSite`**](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value): This value is set to `lax` so that the cookie can be set when coming from an external site.
3. [**`path`**](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value): This value is not set by default, but will use the value of your [`basePath`](#base-path) if configured.

Expand All @@ -492,8 +493,8 @@ export const routing = defineRouting({
localeCookie: {
// Custom cookie name
name: 'USER_LOCALE',
// Expire in one day
maxAge: 60 * 60 * 24
// Expire in one year
maxAge: 60 * 60 * 24 * 365
}
});
```
Expand All @@ -510,7 +511,18 @@ export const routing = defineRouting({
});
```

Note that the cookie is only set when the user switches the locale and is not updated on every request.
<Details id="locale-cookie-gdpr">
<summary>Which `maxAge` value should I consider for GDPR compliance?</summary>

The [Article 29 Working Party opinion 04/2012](https://ec.europa.eu/justice/article-29/documentation/opinion-recommendation/files/2012/wp194_en.pdf) provides a guideline for the expiration of cookies that are used to remember the user's language in section 3.6 "UI customization cookies".

In this policy, a language preference cookie set as a result of an explicit user action, such as using a language switcher, is allowed to remain active for "a few additional hours" after a browser session has ended. To be compliant out of the box, `next-intl` sets the `maxAge` value of the cookie to 5 hours.

However, the Working Party also states that if additional information about the use of cookies is provided in a prominent location (e.g. a "uses cookies" notice next to the language switcher), the cookie can be configured to remember the user's preference for "a longer duration". If you're providing such a notice, you can consider increasing `maxAge` accordingly.

Please note that legal requirements may vary by region, so it's advisable to verify them independently. While we strive to keep this information as up-to-date as possible, we cannot guarantee its accuracy.

</Details>

### Alternate links [#alternate-links]

Expand Down
7 changes: 4 additions & 3 deletions docs/src/pages/docs/routing/middleware.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const config = {

## Locale detection [#locale-detection]

The locale is negotiated based on your [`localePrefix`](/docs/routing#locale-prefix) and [`domains`](/docs/routing#domains) setting. Once a locale is detected, it will be remembered for future requests by being stored in the `NEXT_LOCALE` cookie.
The locale is negotiated based on your routing configuration, taking into account your settings for [`localePrefix`](/docs/routing#locale-prefix), [`domains`](/docs/routing#domains), [`localeDetection`](/docs/routing#locale-detection), and [`localeCookie`](/docs/routing#locale-cookie).

### Prefix-based routing (default) [#location-detection-prefix]

Expand All @@ -48,10 +48,11 @@ To change the locale, users can visit a prefixed route. This will take precedenc
**Example workflow:**

1. A user requests `/` and based on the `accept-language` header, the `en` locale is matched.
2. The `en` locale is saved in a cookie and the user is redirected to `/en`.
2. The user is redirected to `/en`.
3. The app renders `<Link locale="de" href="/">Switch to German</Link>` to allow the user to change the locale to `de`.
4. When the user clicks on the link, a request to `/de` is initiated.
5. The middleware will update the cookie value to `de`.
5. The middleware will add a cookie to remember the preference for the `de` locale.
6. The user later requests `/` again and the middleware will redirect to `/de` based on the cookie.

<Details id="accept-language-matching">
<summary>Which algorithm is used to match the accept-language header against the available locales?</summary>
Expand Down
11 changes: 0 additions & 11 deletions docs/src/pages/docs/routing/navigation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -374,14 +374,3 @@ const pathname = getPathname({
}
});
```

## Legacy APIs

`next-intl@3.0.0` brought the first release of the navigation APIs with these functions:

- `createSharedPathnamesNavigation`
- `createLocalizedPathnamesNavigation`

As part of `next-intl@3.22.0`, these functions have been replaced by a single `createNavigation` function, which unifies the API for both use cases and also fixes a few quirks in the previous APIs. Going forward, `createNavigation` is recommended and the previous functions are marked as deprecated.

While `createNavigation` is mostly API-compatible, there are some minor differences that should be noted. Please refer to the [3.22 announcement post](/blog/next-intl-3-22#create-navigation) for full details.
Loading
Loading