Contents

Next.js App Router i18n: A Complete Guide to next-intl

With the growth of globalization, multi-language support (i18n) has become a standard requirement for modern web applications. For projects using the Next.js App Router, next-intl provides an efficient internationalization solution that is deeply integrated with the framework, compatible with Server-Side Rendering (SSR), and supports both Server and Client components. This article will guide you step-by-step through building a multi-language Next.js application from scratch.


🚀 I. Why Choose next-intl?

Compared to traditional i18n libraries, next-intl is deeply optimized for the Next.js App Router:

  • Automatic Route Handling: Automatically handles routes with language prefixes (e.g., /en/page, /zh/page).
  • Component Support: Perfectly supports both Server Components and Client Components.
  • SEO Friendly: Native support for SEO-compliant multi-language links.
  • On-demand Loading: Supports on-demand loading of language resources in Server Components, reducing initial bundle size.

📁 II. Project Directory Structure

Under the App Router, the recommended directory structure is as follows (where [locale] is used for dynamic language prefix routes):

src/
├── app/
│   ├── layout.tsx                    ← Root layout (non-locale specific)
│   ├── middleware.ts                 ← next-intl middleware
│   ├── i18n/                         ← Internationalization config
│   │   ├── routing.ts
│   │   ├── request.ts
│   │   └── navigation.ts
│   └── [locale]/                     ← Dynamic locale prefix
│       ├── layout.tsx                ← Locale layout + Intl Provider
│       ├── page.tsx                  ← Homepage
│       └── ...
├── components/
│   └── LocaleSwitcher.tsx            ← Language switcher component
└── messages/                         ← Translation resources
    ├── en.json
    └── zh.json

📌 III. Core Configuration Steps

1. Install Dependencies

npm install next-intl

2. Configure Language Routes (src/app/i18n/routing.ts)

import { defineRouting } from "next-intl/routing";

export const routing = defineRouting({
  locales: ["en", "zh"],        // Supported languages
  defaultLocale: "en",          // Default language
  localePrefix: "always"        // Always use prefix /en /zh
});

3. Load Language Resources (src/app/i18n/request.ts)

import { getRequestConfig } from "next-intl/server";

export default getRequestConfig(async ({ locale }) => {
  return {
    messages: (await import(`../../../messages/${locale}.json`)).default
  };
});

4. Configure Middleware (src/middleware.ts)

import createMiddleware from "next-intl/middleware";
import { routing } from "./app/i18n/routing";

export default createMiddleware(routing);

export const config = {
  // Match all paths except API or static assets
  matcher: ["/((?!api|_next|.*\\..*).*)"]
};

🎨 IV. Using in Pages and Components

Locale Layout Configuration (src/app/[locale]/layout.tsx)

import { NextIntlClientProvider } from "next-intl";
import { getMessages } from "next-intl/server";

export default async function LocaleLayout({ children, params: { locale } }) {
  const messages = await getMessages();
  return (
    <html lang={locale}>
      <body>
        <NextIntlClientProvider messages={messages}>
          {children}
        </NextIntlClientProvider>
      </body>
    </html>
  );
}

Translation Example

import { useTranslations } from "next-intl";

export default function Home() {
  const t = useTranslations("Index");
  return <h1>{t("title")}</h1>;
}

🎯 V. Summary

With next-intl, we can implement multi-language support in Next.js App Router very elegantly. It not only simplifies routing logic but also provides an excellent development experience and runtime performance. If your project needs to serve international users, next-intl is definitely the most recommended choice currently.