Internationalization (i18n) in Next.js
April 5, 2025
Internationalization (i18n) in Next.js: The Ultimate Guide to Building Multi-Language Websites
Creating multilingual websites is no longer a luxury—it's a necessity. If you're building global applications or products, supporting multiple languages through internationalization (i18n) is crucial for reaching a broader audience and enhancing user experience.
In this ultimate guide, we'll explore how to build i18n-ready Next.js applications with:
- Built-in Next.js i18n routing
- Dynamic locale switching
- Integration with popular translation libraries
- Real-world use cases
- SEO and accessibility considerations
Table of Contents
- What is Internationalization (i18n)?
- Why i18n Matters in Next.js Projects
- Getting Started with i18n in Next.js
- Built-in i18n Routing in Next.js
- Locale Detection in Next.js
- Content Translation Strategies
- Using
next-intl
for i18n - Using
react-i18next
with Next.js - Creating a Language Switcher
- SEO Best Practices for Multilingual Sites
- Real-World Use Cases
- Common Pitfalls to Avoid
- Final Thoughts
What is Internationalization (i18n)?
Internationalization (abbreviated as i18n) is the process of designing your application to support multiple languages and regions without requiring engineering changes to the source code. It includes:
- Language translation
- Number and date formatting
- Currency localization
- Right-to-left (RTL) support
- Locale-specific routing
Why i18n Matters in Next.js Projects
Here’s why you should care about implementing i18n in your Next.js project:
- 📈 Reach a global audience
- ✅ Improve accessibility & user experience
- 🔍 Boost multilingual SEO rankings
- 💸 Increase conversion rates in local markets
Getting Started with i18n in Next.js
First, create a basic Next.js project (if you haven’t):
npx create-next-app@latest nextjs-i18n-site
cd nextjs-i18n-site
Enable i18n in next.config.js
module.exports = {
i18n: {
locales: ['en', 'fr', 'de'],
defaultLocale: 'en',
localeDetection: true,
},
}
This tells Next.js to:
- Support English, French, and German
- Default to English
- Detect user locale automatically
Built-in i18n Routing in Next.js
Next.js automatically prefixes routes with the locale:
| Locale | URL | Description |
| ------ | --- | ----------- |
| en | /about
| English version |
| fr | /fr/about
| French version |
| de | /de/about
| German version |
You can use useRouter()
to detect the current locale:
import { useRouter } from 'next/router'
const MyComponent = () => {
const { locale } = useRouter()
return <p>Current Locale: {locale}</p>
}
Locale Detection in Next.js
When localeDetection: true, Next.js uses the Accept-Language HTTP header to redirect users to the right locale.
You can also handle redirects manually via middleware (e.g. geolocation-based):
// middleware.ts
import { NextResponse } from 'next/server'
export function middleware(req) {
const { nextUrl } = req
const preferredLocale = req.headers.get('accept-language')?.split(',')[0] || 'en'
return NextResponse.redirect(new URL(`/${preferredLocale}${nextUrl.pathname}`, req.url))
}
Content Translation Strategies
There are two main approaches:
- Static JSON Files – good for smaller apps:
// /locales/en/common.json
{
"welcome": "Welcome",
"about": "About Us"
}
- Translation Platforms (e.g., Phrase, Lokalise, POEditor) – scalable for teams.
Using next-intl
for i18n
next-intl
is a powerful library that plays well with Next.js App Router.
Installation
npm install next-intl
Set Up the Provider
Wrap your app in <NextIntlProvider>
:
// app/[locale]/layout.tsx
import { NextIntlProvider } from 'next-intl'
export default function LocaleLayout({ children, params: { locale } }) {
const messages = require(`../../messages/${locale}.json`)
return (
<html lang={locale}>
<body>
<NextIntlProvider messages={messages}>
{children}
</NextIntlProvider>
</body>
</html>
)
}
Usage in Components
import { useTranslations } from 'next-intl'
const MyComponent = () => {
const t = useTranslations('Home')
return <h1>{t('welcome')}</h1>
}
Using react-i18next
with Next.js
react-i18next
is another excellent i18n library.
Installation
npm install react-i18next i18next
Use the appWithTranslation
HOC and translation JSON files in /public/locales
.
This method is more versatile if you’re migrating from a React SPA.
Creating a next.js language switcher
'use client'
import { usePathname, useRouter } from 'next/navigation'
export default function LanguageSwitcher() {
const pathname = usePathname()
const router = useRouter()
const switchTo = (locale: string) => {
const newPath = `/${locale}${pathname.replace(/^\/(en|fr|de)/, '')}`
router.push(newPath)
}
return (
<div className="space-x-4">
<button onClick={() => switchTo('en')}>🇺🇸 English</button>
<button onClick={() => switchTo('fr')}>🇫🇷 Français</button>
<button onClick={() => switchTo('de')}>🇩🇪 Deutsch</button>
</div>
)
}
SEO Best Practices for Multilingual Sites
- Set
lang
attributes:
<html lang="fr"> </html>
- Use
hreflang
in<head>
:
<link rel="alternate" href="https://example.com/" hreflang="en" />
<link rel="alternate" href="https://example.com/fr/" hreflang="fr" />
-
Separate URLs by locale: Avoid query params (
?lang=fr
). Use clean routes (/fr/page
). -
Translate meta tags: Dynamically render
<title>
,<meta name="description">
, etc., per locale.
Real-World Use Cases
- E-commerce: Sell globally with country-specific pricing, currencies, and languages.
- SaaS Platforms: Increase sign-ups with localized onboarding.
- Blogs & Media: Reach wider audiences by translating your content.
Common Pitfalls to Avoid
- Hardcoding language strings
- Ignoring SEO for alternate locales
- Not testing RTL layouts
- Forgetting to format numbers/dates/currency per locale
Final Thoughts
Next.js + i18n is a powerful combo that allows you to build global-ready web applications with ease. Whether you're using next-intl
, react-i18next
, or built-in routing, the key is to keep your app scalable, SEO-friendly, and user-first.
With this comprehensive guide, you’re now ready to ship multilingual Next.js applications like a pro.
Get in Touch
Want to collaborate or just say hi? Reach out!