next-intl is an internationalization (i18n) library designed specifically for the Next.js App Router. It is lightweight, easy to use, and deeply integrated with the App Router.
1. Installation
Install next-intl using pnpm.
2. Configuration Overview
Recommended Directory Structure
messages/: Stores translation files such asen.jsonandzh.jsonsrc/i18n/: Contains language-related configuration and helper functions
Steps to Set Up Multilingual Support
-
Integrate the
next-intlplugin innext.config.jsimport type { NextConfig } from "next"; import createNextIntlPlugin from "next-intl/plugin"; const nextConfig: NextConfig = {}; const withNextIntl = createNextIntlPlugin(); export default withNextIntl(nextConfig); -
Use TypeScript files like
en.tsandzh.tsinstead of JSON for translation content to improve flexibility -
Create a
getI18nfunction to dynamically load translation objects// src/i18n/index.ts import { en } from "./en"; import { zh } from "./zh"; const locales = { zh, en }; export function getI18n(locale: string) { return locales[locale as keyof typeof locales] || locales["en"]; } -
Define supported locales and routing settings in
routing.ts// src/i18n/routing.ts import { defineRouting } from "next-intl/routing"; export const routing = defineRouting({ // A list of all locales that are supported locales: ["en", "zh"], // Used when no locale matches defaultLocale: "en", localeDetection: false, }); -
Load language messages dynamically in
request.tsbased on the incoming locale// src/i18n/request.ts import { hasLocale } from "next-intl"; import { getRequestConfig } from "next-intl/server"; 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; return { locale, messages: (await import(`../../messages/${locale}.json`)).default, }; }); -
Wrap navigation methods like
Linkinnavigation.tsto automatically handle locale prefixes// src/i18n/navigation.ts import { createNavigation } from "next-intl/navigation"; import { routing } from "./routing"; // Lightweight wrappers around Next.js' navigation // APIs that consider the routing configuration export const { Link, redirect, usePathname, useRouter, getPathname } = createNavigation(routing);
Locale-Aware Layout
In src/app/[locale]/layout.tsx, set the <html lang="xx"> attribute according to the current locale and wrap the app with NextIntlClientProvider.
// src/app/[locale]/layout.tsx
import { routing } from "@/i18n/routing";
import { NextIntlClientProvider, hasLocale } from "next-intl";
import { notFound } from "next/navigation";
export default async function LocaleLayout({
children,
params,
}: {
children: React.ReactNode;
params: Promise<{ locale: string }>;
}) {
const { locale } = await params;
if (!hasLocale(routing.locales, locale)) {
notFound();
}
return (
<html lang={locale}>
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
<NextIntlClientProvider>{children}</NextIntlClientProvider>
</body>
</html>
);
}
3. Using Translations
-
Use
useTranslationsin components to access localized stringsimport {useTranslations} from 'next-intl'; function About() { const t = useTranslations('About'); return <h1>{t('title')}</h1>; } -
For complex content structures, use
getI18n(locale)to load translation objectsimport { useLocale } from "next-intl"; export default function Header() { const locale = useLocale(); const t = getI18n(locale); } return ( <div> {t.services.items.map((service, index) => ( <Card key={index}> {service.description} </Card> ))} </div> ) -
The custom
Linkcomponent automatically handles language-prefixed routesimport { Link } from "@/i18n/navigation"; <Link href={posts[0].url} className="inline-flex items-center px-6 py-3 rounded-lg bg-blue-600 text-white font-medium hover:bg-blue-700 transition-colors" > Read More → </Link>
With this setup, next-intl provides a clean and scalable solution for adding multilingual support to Next.js applications.