~2 min read • Updated Oct 28, 2025
Terminology
- Locale: An identifier for language and regional formatting preferences
- en-US: English (United States)
- nl-NL: Dutch (Netherlands)
- nl: Dutch (generic)
Internationalized Routing
To select the correct locale, use the browser’s Accept-Language header. Libraries like @formatjs/intl-localematcher and Negotiator help determine the preferred language:
let headers = { 'accept-language': 'en-US,en;q=0.5' }
let languages = new Negotiator({ headers }).languages()
let locales = ['en-US', 'nl-NL', 'nl']
let defaultLocale = 'en-US'
match(languages, locales, defaultLocale) // -> 'en-US'Locale-Based Redirects
In proxy.js, redirect users based on their locale:
export function proxy(request) {
const { pathname } = request.nextUrl
const pathnameHasLocale = locales.some(
(locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`
)
if (pathnameHasLocale) return
const locale = getLocale(request)
request.nextUrl.pathname = `/${locale}${pathname}`
return NextResponse.redirect(request.nextUrl)
}Folder Structure in app/
To support multiple languages, nest files under app/[lang]. This allows the router to pass the lang parameter to layouts and pages:
export default async function Page({ params }) {
const { lang } = await params
return ...
}Loading Translations
Use separate dictionaries for each language:
// dictionaries/en.json
{ "products": { "cart": "Add to Cart" } }
// dictionaries/nl.json
{ "products": { "cart": "Toevoegen aan Winkelwagen" } }Define a getDictionary function to load translations:
export const getDictionary = async (locale: 'en' | 'nl') =>
dictionaries[locale]()In your page:
const dict = await getDictionary(lang)
return <button>{dict.products.cart}</button>Static Rendering for Locales
Use generateStaticParams to generate static pages for each language:
export async function generateStaticParams() {
return [{ lang: 'en-US' }, { lang: 'de' }]
}In the layout:
<html lang={(await params).lang}>
<body>{children}</body>
</html>Conclusion
Internationalization in Next.js enables multilingual experiences through dynamic routing, translation loading, and static generation. With proper folder structure and locale detection, you can build scalable, global-ready applications.
Written & researched by Dr. Shahin Siami