Internationalization in Next.js error files
The Next.js App Router's file convention provides two files that can be used for error handling:
This page provides practical guides for these cases.
Have a look at the App Router example to explore a working app with error handling.
not-found.js
Next.js renders the closest not-found
page when a route segment calls the notFound
function (opens in a new tab). We can use this mechanism to provide a localized 404 page by adding a not-found
file within the [locale]
folder.
import {useTranslations} from 'next-intl';
export default function NotFoundPage() {
const t = useTranslations('NotFoundPage');
return <h1>{t('title')}</h1>;
}
Note however that Next.js will only render this page when the notFound
function is called from within a route, not for all unknown routes in general.
Catching unknown routes
To catch unknown routes too, you can define a catch-all route that explicitly calls the notFound
function.
import {notFound} from 'next/navigation';
export default function CatchAllPage() {
notFound();
}
After this change, all requests that are matched within the [locale]
segment will render the not-found
page when an unknown route is encountered.
Catching non-localized requests
When the user requests a route that is not matched by the next-intl
middleware, there's no locale associated with the request (depending on your matcher
config, e.g. /unknown.txt
might not be matched).
You can add a root not-found
page to handle these cases too.
'use client';
import Error from 'next/error';
// Render the default Next.js 404 page when a route
// is requested that doesn't match the middleware and
// therefore doesn't have a locale associated with it.
export default function NotFound() {
return (
<html lang="en">
<body>
<Error statusCode={404} />
</body>
</html>
);
}
Note that the presence of app/not-found.tsx
requires that a root layout is available, even if it's just passing children
through.
// 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 within [locale]/layout.tsx
when we detect an incoming locale
param that isn't a valid locale.
import {useLocale} from 'next-intl';
import {notFound} from 'next/navigation';
const locales = ['en', 'de'];
export default function LocaleLayout({children, params}) {
// Validate that the incoming `locale` parameter is valid
if (!locales.includes(locale as any)) notFound();
return (
<html lang={locale}>
<body>{children}</body>
</html>
);
}
error.js
When an error
file is defined, Next.js creates an error boundary within your layout (opens in a new tab) that wraps pages accordingly to catch runtime errors:
Since the error
file must be defined as a Client Component, you have to use NextIntlClientProvider
to provide messages in case the error
file renders.
import pick from 'lodash/pick';
export default async function LocaleLayout({children}) {
// ...
const messages = useMessages();
return (
<html lang={locale}>
<body>
<NextIntlClientProvider
locale={locale}
messages={pick(messages, 'Error')}
>
{children}
</NextIntlClientProvider>
</body>
</html>
);
}
Once NextIntlClientProvider
is in place, you can use functionality from next-intl
in the error
file:
'use client';
import {useTranslations} from 'next-intl';
export default function Error({error, reset}) {
const t = useTranslations('Error');
return (
<div>
<h1>{t('title')}</h1>
<button onClick={reset}>{t('retry')}</button>
</div>
);
}
Note that NextIntlClientProvider
only provides the messages to your error page, but doesn't load any runtime code for processing translations on the client side. Only the error page will include this code, so the performance of other pages isn't affected.