π Next.js Internationalization Using i18n

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,
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/aboutvs/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-LanguageheadersLog
useRouter().localeto 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/localesfolder 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-i18nextfor safer translation key usageKeep UI text and translations decoupled
Automate translation string extraction and management using tools like
locizeorphrase.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.


