I18n Setup in Next.js with next-intl
Internationalization (i18n) is essential for applications targeting multiple languages. The next-intl library makes it easy to implement i18n in Next.js with support for both static and dynamic rendering.
In this article, we’ll walk through a clean and modular setup to localize your app URLs like:
/en/about
/az/about
1. Installation
npm install next-intl
2. Folder Structure
Create a file-based route structure like:
src/
├── app/
│ └── [locale]/
│ ├── layout.tsx
│ └── page.tsx
├── i18n/
│ ├── request.ts
│ └── routing.ts
└── locales/
├── az.json
└── en.json
3. Configure Routing
i18n/routing.ts:
import { defineRouting } from "next-intl/routing";
export const routing = defineRouting({
locales: ["en", "az"],
defaultLocale: "en",
localePrefix: {
mode: "always",
prefixes: {
en: "/en",
az: "/az",
},
},
pathnames: {
"/": "/",
"/about": {
en: "/about",
az: "/about",
},
},
});
4. Provide Translations
i18n/request.ts:
import { getRequestConfig } from "next-intl/server";
import { routing } from "@/i18n/routing";
import { notFound } from "next/navigation";
export default getRequestConfig(async ({ locale = "en" }) => {
if (!routing.locales.includes(locale)) notFound();
return {
locale,
messages: (await import(`../locales/${locale}.json`)).default,
};
});
5. Middleware Setup
middleware.ts:
import createMiddleware from "next-intl/middleware";
import { routing } from "@/i18n/routing";
export default createMiddleware({
locales: routing.locales,
defaultLocale: routing.defaultLocale,
});
export const config = {
matcher: ["/", "/(az|en)/:path*"],
};
6. Configure next.config.mjs
import createNextIntlPlugin from "next-intl/plugin";
const withNextIntl = createNextIntlPlugin();
/** @type {import('next').NextConfig} */
const nextConfig = {};
export default withNextIntl(nextConfig);
7. Add Provider in Layout
// layout.tsx
import { getMessages } from "next-intl/server";
import { NextIntlClientProvider } from "next-intl";
export default async function RootLayout({
children,
params: { locale },
}: {
children: React.ReactNode;
params: { locale: string };
}) {
const messages = await getMessages();
return (
<html lang={locale}>
<body>
<NextIntlClientProvider messages={messages} locale={locale}>
{children}
</NextIntlClientProvider>
</body>
</html>
);
}
8. Use useTranslations() in Components
import { useTranslations } from "next-intl";
export default function AboutPage() {
const t = useTranslations("about");
return <h1>{t("title")}</h1>;
}
9. Localized Routing with <Link />
import { usePathname, useRouter } from "next-intl/client";
import Link from "next-intl/link";
<Link href="/about">About</Link>;
✅ This automatically uses the active locale in URLs like /en/about or /az/about.
Summary
next-intlmakes i18n simple in Next.js 13+- URL-based language routing is supported
- Translations are dynamic and work with both SSR and SSG
Comments