Language-based routing
Setting up language-based routing in Next.js (App Router)
Problem
A single URL, such as /about, is inherently ambiguous when an application supports multiple languages. Users visiting this URL receive content in a default language, but they have no way to link to or bookmark a version of that page in a different language. This ambiguity confuses search engines, which may not index all language versions or may mix them.
Solution
Incorporate a language identifier directly into the URL path, such as /en/about or /fr/about. This makes every path unique to a specific language, resolving the ambiguity for both users and search engines.
Steps
1. Create a dynamic language segment
In the Next.js App Router, you handle language routing by creating a dynamic segment folder at the root of your app directory. Create a new folder named [lang] inside app and move your main page.tsx file into it.
// app/[lang]/page.tsx
export default function Home({ params }: { params: { lang: string } }) {
return (
<div>
<h1>Home page</h1>
<p>Current language: {params.lang}</p>
</div>
);
}
This [lang] folder captures the first part of the URL (e.g., 'en' or 'fr') and passes it as a lang property inside the params object to your page component. You can now access your page at URLs like /en or /fr.
2. Update the root layout
Your root layout.tsx should also be moved inside the app/[lang] folder. It will also receive the lang param, which you should use to set the lang attribute on the <html> tag for accessibility and SEO.
// app/[lang]/layout.tsx
export default function RootLayout({
children,
params,
}: {
children: React.ReactNode;
params: { lang: string };
}) {
return (
<html lang={params.lang}>
<body>{children}</body>
</html>
);
}
This layout now wraps all pages within a specific language. Setting the lang attribute here informs browsers which language the page content is in.
3. Define supported languages
To tell Next.js which language segments are valid, you can export a generateStaticParams function from the root layout. This allows Next.js to statically generate these routes at build time.
// app/[lang]/layout.tsx
export async function generateStaticParams() {
return [{ lang: 'en' }, { lang: 'es' }, { lang: 'fr' }];
}
export default function RootLayout({
children,
params,
}: {
children: React.ReactNode;
params: { lang: string };
}) {
return (
<html lang={params.lang}>
<body>{children}</body>
</html>
);
}
This function informs Next.js that your app supports /en, /es, and /fr. Requests for other paths (like /de) will result in a 404 Not Found page.
4. Add nested routes
All other pages in your app are now created inside the [lang] folder. For example, to create an 'about' page, you would add app/[lang]/about/page.tsx.
// app/[lang]/about/page.tsx
export default function AboutPage({ params }: { params: { lang: string } }) {
return (
<div>
<h1>About page</h1>
<p>Current language: {params.lang}</p>
</div>
);
}
This file automatically creates routes that are accessible at /en/about, /es/about, and /fr/about. The lang parameter is available on all pages if you need it to fetch the correct translated content.