Next.js
Internationalization in Next.js: Routing, Metadata, and SEO
Locale-based routing, translated metadata, and hreflang so internationalized Next.js sites are built and indexed correctly.

Internationalization in the App Router involves routing (e.g. /en/blog, /es/blog), translated content and metadata, and signals for search engines. Here’s a practical approach.
Locale in the URL
Two common patterns: prefix the locale (e.g. /en/about, /es/about) or use a domain/subdomain (e.g. en.example.com, es.example.com). Prefixing keeps one codebase and one deployment; use middleware or a route group to read the locale and serve the right content. Store the current locale in a cookie or accept-language so you can redirect or render accordingly. Next.js doesn’t ship a built-in i18n router in the App Router, so you implement the segment (e.g. [locale]) and middleware yourself.
// app/[locale]/layout.tsx
export default function LocaleLayout({
children,
params,
}: {
children: React.ReactNode;
params: Promise<{ locale: string }>;
}) {
const { locale } = await params;
// Validate locale; redirect if invalid
return (
<html lang={locale}>
<body>{children}</body>
</html>
);
}Use middleware to redirect / to a default locale (e.g. /en) or to set the locale from cookie/header and rewrite to the right segment.
Translating metadata
Each page’s title and description should be in the right language. Use generateMetadata and pass the locale (from params or context) so you can look up translated strings. Export a small dictionary or use a CMS for per-locale metadata. Set metadata.alternates.canonical to the current locale URL and add alternates.languages so search engines know about other language versions.
export async function generateMetadata({
params,
}: {
params: Promise<{ locale: string }>;
}) {
const { locale } = await params;
const t = await getTranslations(locale, "metadata");
const base = process.env.NEXT_PUBLIC_SITE_URL;
return {
title: t("home.title"),
description: t("home.description"),
alternates: {
canonical: `${base}/${locale}`,
languages: {
en: `${base}/en`,
es: `${base}/es`,
},
},
};
}That gives you correct titles and hreflang-style alternates for SEO.
Content and SEO
Serve translated content from your CMS or static files per locale. Use the same URL structure per locale (e.g. /en/blog/slug, /es/blog/slug) so you can map alternates. Add hreflang (via metadata or link elements) for each language version so search engines can show the right version to the right user. With routing, metadata, and hreflang in place, your i18n Next.js site is set up for SEO.
Summary
Put locale in the URL (e.g. [locale] segment), use middleware for redirects and locale detection, and translate metadata per locale. Set canonical and language alternates for each page. That covers routing, metadata, and SEO for internationalized Next.js.