Skip to main content
Practice Problems

Internationalization (i18n) in Next.js

Internationalization in Next.js

Internationalization (i18n) is the process of designing your app to support multiple languages and regions. Next.js App Router supports i18n through routing patterns and translation libraries.


Routing Strategy: Locale in URL

app/ [locale]/ page.tsx → /en, /ua, /de about/page.tsx → /en/about, /ua/about blog/ [slug]/page.tsx → /en/blog/hello, /ua/blog/hello layout.tsx

Middleware for Locale Detection

tsx
// middleware.ts import { NextResponse } from "next/server"; import type { NextRequest } from "next/server"; const locales = ["en", "ua"]; const defaultLocale = "en"; function getLocale(request: NextRequest): string { // Check cookie const cookieLocale = request.cookies.get("locale")?.value; if (cookieLocale && locales.includes(cookieLocale)) return cookieLocale; // Check Accept-Language header const acceptLanguage = request.headers.get("accept-language") || ""; for (const locale of locales) { if (acceptLanguage.includes(locale)) return locale; } return defaultLocale; } export function middleware(request: NextRequest) { const { pathname } = request.nextUrl; // Check if pathname already has a locale const hasLocale = locales.some( locale => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}` ); if (hasLocale) return NextResponse.next(); // Redirect to localized path const locale = getLocale(request); return NextResponse.redirect( new URL(`/${locale}${pathname}`, request.url) ); } export const config = { matcher: ["/((?!api|_next|favicon.ico).*)"], };

Translation Files (JSON)

json
// messages/en.json { "nav": { "home": "Home", "about": "About Us", "contact": "Contact" }, "hero": { "title": "Welcome to our platform", "description": "The best tool for developers" } } // messages/ua.json { "nav": { "home": "Головна", "about": "Про нас", "contact": "Контакти" }, "hero": { "title": "Ласкаво просимо на нашу платформу", "description": "Найкращий інструмент для розробників" } }
tsx
// app/[locale]/layout.tsx import { NextIntlClientProvider } from "next-intl"; import { getMessages } from "next-intl/server"; export default async function LocaleLayout({ children, params, }: { children: React.ReactNode; params: Promise<{ locale: string }>; }) { const { locale } = await params; const messages = await getMessages(); return ( <html lang={locale}> <body> <NextIntlClientProvider messages={messages}> {children} </NextIntlClientProvider> </body> </html> ); }

In Server Components

tsx
import { useTranslations } from "next-intl"; export default function HomePage() { const t = useTranslations("hero"); return ( <div> <h1>{t("title")}</h1> <p>{t("description")}</p> </div> ); }

In Client Components

tsx
"use client"; import { useTranslations } from "next-intl"; export function Navbar() { const t = useTranslations("nav"); return ( <nav> <a href="/">{t("home")}</a> <a href="/about">{t("about")}</a> <a href="/contact">{t("contact")}</a> </nav> ); }

Language Switcher

tsx
"use client"; import { usePathname, useRouter } from "next/navigation"; export function LanguageSwitcher() { const pathname = usePathname(); const router = useRouter(); const switchLocale = (newLocale: string) => { // Replace current locale in path const segments = pathname.split("/"); segments[1] = newLocale; router.push(segments.join("/")); }; return ( <div> <button onClick={() => switchLocale("en")}>EN</button> <button onClick={() => switchLocale("ua")}>UA</button> </div> ); }

Key Considerations

AspectApproach
Routing[locale] dynamic segment
DetectionMiddleware (cookie, Accept-Language header)
TranslationsJSON files + library (next-intl, react-i18next)
SEO<html lang>, alternate hreflang tags
Date/Number formattingIntl API or library
RTL supportCSS logical properties, dir attribute

Important:

Next.js i18n with App Router uses a [locale] segment in the URL, Middleware for automatic locale detection and redirection, and translation libraries like next-intl. Store translations in JSON files, use useTranslations() in components, and ensure proper SEO with lang attributes and hreflang tags.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Finished reading?
Practice Problems