π Next.js Internationalization Using i18n

Table of contents
- π§ What is Internationalization (i18n)?
- π¦ Why Use Next.js for i18n?
- βοΈ Step 1: Next.js Configuration for i18n
- π Step 2: Project Folder Structure
- π οΈ Step 3: Install Required Dependencies
- π§© Step 4: Using Translations in Components
- π Step 5: Language Switcher Component
- π Handling Dates, Currency & Numbers
- π§ͺ Testing & Debugging
- β οΈ Common Pitfalls
- π Deployment Considerations
- π§ Best Practices
- β Conclusion
- π Resources

As digital products aim to reach a global audience, internationalization (i18n) emerges as an essential feature in contemporary web applications. Next.js, a robust React framework, provides comprehensive built-in support for internationalized routing. Coupled with tools like next-i18next
, managing translations becomes both elegant and efficient.
In this blog post, we'll dive deep into how to implement internationalization in a Next.js appβfrom setup to best practicesβwith a focus on SEO, routing, translation management, and language switching.
π§ What is Internationalization (i18n)?
Internationalization, abbreviated as i18n (because there are 18 letters between "i" and "n"), is the process of designing software that can be easily adapted to various languages and locales.
Examples of localized elements:
Static text (e.g., headings, buttons)
Dates and times
Currency formats
Number formats
Right-to-left (RTL) layout support for languages like Arabic or Hebrew
π¦ Why Use Next.js for i18n?
Next.js supports i18n out of the box with:
Localized routing (
/fr/about
vs/en/about
)Automatic locale detection
Support for Static Site Generation (SSG), Server-Side Rendering (SSR), and Client-Side Rendering (CSR)
With this built-in support combined with a library like next-i18next
, you get:
Namespaced translation files
Translation fallback support
TypeScript compatibility
Server and client translation sync
βοΈ Step 1: Next.js Configuration for i18n
Start by enabling internationalized routing in your Next.js config.
// next.config.js
const { i18n } = require('./next-i18next.config');
module.exports = {
i18n,
reactStrictMode: true,
};
// next-i18next.config.js
module.exports = {
i18n: {
defaultLocale: 'en',
locales: ['en', 'fr', 'de'],
localeDetection: true,
},
reloadOnPrerender: process.env.NODE_ENV === 'development',
};
π Step 2: Project Folder Structure
Organize your translations in the public/locales
directory.
public/
βββ locales/
βββ en/
β βββ common.json
βββ fr/
β βββ common.json
βββ de/
βββ common.json
Example common.json
:
{
"title": "Welcome to our i18n!",
"subtitle": "Experience internationalization with i18n in Next.js",
"button_label": "Hit me"
}
π οΈ Step 3: Install Required Dependencies
npm install next-i18next react-i18next i18next
# For TypeScript users:
npm install -D @types/react-i18next
π§© Step 4: Using Translations in Components
// pages/index.tsx
import { useTranslation } from 'next-i18next';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
export default function HomePage() {
const { t } = useTranslation('common');
return (
<main>
<h1>{t('title')}</h1>
<p>{t('subtitle')}</p>
<button>{t('button_label')}</button>
</main>
);
}
export async function getStaticProps({ locale }) {
return {
props: {
...(await serverSideTranslations(locale, ['common'])),
},
};
}
π Step 5: Language Switcher Component
import { useRouter } from 'next/router';
export default function LanguageSwitcher() {
const router = useRouter();
const { locale, locales, pathname, query, asPath } = router;
const switchTo = (lng: string) => {
router.push({ pathname, query }, asPath, { locale: lng });
};
return (
<div>
{locales?.map((lng) => (
<button key={lng} onClick={() => switchTo(lng)} disabled={lng === locale}>
{lng.toUpperCase()}
</button>
))}
</div>
);
}
π Handling Dates, Currency & Numbers
const formattedDate = new Intl.DateTimeFormat(locale, {
year: 'numeric', month: 'long', day: 'numeric'
}).format(new Date());
const formattedCurrency = new Intl.NumberFormat(locale, {
style: 'currency', currency: 'EUR'
}).format(499.99);
π§ͺ Testing & Debugging
Use browser dev tools to test
Accept-Language
headersLog
useRouter().locale
to verify current languageTry toggling between SSR, SSG, and CSR to see how translations load
β οΈ Common Pitfalls
Issue | Solution |
Translations not loading | Check namespace names in getStaticProps |
SSR hydration mismatch | Avoid hard-coded text outside t() |
Language switch causes full reload | Use router.push() with locale correctly |
Missing fallback strings | Set fallbackLng in i18next config |
π Deployment Considerations
Ensure the
public/locales
folder is included in your build.Use CDN caching headers that vary by language (e.g.,
Vary: Accept-Language
).If using middleware or edge functions, ensure locale headers are respected.
π§ Best Practices
Separate translation files by feature or route (e.g.,
home.json
,auth.json
)Use TypeScript +
react-i18next
for safer translation key usageKeep UI text and translations decoupled
Automate translation string extraction and management using tools like
locize
orphrase.com
β Conclusion
With built-in support for localized routing and seamless integration with translation libraries, Next.js makes internationalization straightforward and powerful. Whether you're building a multilingual marketing site or a global SaaS dashboard, i18n in Next.js ensures scalability and user-centric experiences.
π Resources
Subscribe to my newsletter
Read articles from Mukesh Bishnoi directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Mukesh Bishnoi
Mukesh Bishnoi
Passionate engineer who loves building, breaking and learning stuff. Looking for opportunities to work in a fast paced learning & growth environment. Currently focus on Frontend development,