Next.js
I. Next.js Fundamentals
1. Introduction to Next.js
2. Next.js vs React
3. Project Setup
4. Folder Structure
5. Pages and Routing
6. Link and Navigation
7. Static Assets
8. CSS and Styling
II. Routing, Data & Rendering
9. Dynamic Routing
10. API Routes
11. Data Fetching Basics
12. getStaticProps
13. getServerSideProps
14. Incremental Static Regeneration
15. Rendering Strategies
16. Image Optimization
III. Advanced Next.js & Performance
17. Middleware
18. Authentication Basics
19. Authorization
20. Environment Variables
21. Performance Optimization
22. SEO with Next.js
23. Internationalization
24. Error Handling
IV. Projects, Deployment & Best Practices
25. Next.js Best Practices
26. Folder and Code Organization
27. Testing Next.js Apps
28. Security in Next.js
29. Next.js Interview Questions
30. Mini Project – Blog
31. Mini Project – Dashboard
32. Mini Project – Ecommerce
33. Mini Project – API Integration
34. Next.js Case Study
35. Real-World Use Cases
36. Project Planning
37. Final Project
38. Deployment with Vercel
39. Course Review
40. Career Roadmap
Lesson 23
Internationalization
Build multi-language support for NewsWave using Next.js i18n features and routing strategies.
The web speaks many languages. Your users come from different countries, cultures, and linguistic backgrounds. Internationalization (often shortened to i18n — the "18" represents the 18 letters between "i" and "n") makes your application accessible to global audiences by supporting multiple languages, currencies, date formats, and cultural conventions. Unlike plain React where you'd need to manually handle language switching and route management, Next.js provides built-in internationalization features. These tools automatically detect user preferences, manage translated routes, and serve the correct content based on locale. The framework handles the complex parts — URL routing, language detection, and static generation for each locale — while you focus on organizing translations and user experience. Think of i18n like running a global newsroom. Just as BBC serves different content for BBC America versus BBC UK, NewsWave needs to serve articles in different languages while maintaining the same core functionality. The challenge isn't just translating text, but adapting the entire user experience for different cultures and reading patterns.Understanding Locales and Routing
A locale represents a specific language and region combination. English spoken in the United States (en-US) differs from English in the United Kingdom (en-GB) — not just in spelling, but in cultural references, date formats, and currency symbols. Spanish in Mexico (es-MX) uses different vocabulary than Spanish in Spain (es-ES). Next.js organizes internationalization around these locale codes. When you configure i18n, the framework automatically creates route prefixes for each supported language. A single page component serves multiple locales, with Next.js handling the routing complexity behind the scenes. The routing strategy determines how users access different language versions. Sub-path routing puts the locale in the URL path like/es/articles and /fr/articles. Sub-domain routing uses separate domains like es.newswave.com and fr.newswave.com. Domain routing assigns completely different domains to each language.
// next.config.js - Configure i18n routing
/** @type {import('next').NextConfig} */
const nextConfig = {
i18n: {
locales: ['en', 'es', 'fr', 'de'], // Supported languages
defaultLocale: 'en', // Fallback when no locale detected
localeDetection: true, // Auto-detect user's preferred language
},
}
module.exports = nextConfigTerminal
$ npm run dev
✓ Ready on http://localhost:3000
✓ i18n configured for 4 locales
✓ Routes: /en, /es, /fr, /de
What just happened?
Next.js created automatic routing for all four languages. Users visiting
/es/articles get Spanish content, while /fr/articles serves French. The framework detects browser language preferences and redirects appropriately. Try this: Visit your site and change your browser's preferred language to see automatic redirection.Translation Management
Translation management involves organizing, storing, and accessing translated content throughout your application. While you could scatter translation strings across components, this approach becomes unwieldy as your application grows. Professional i18n requires a structured system for managing thousands of translation keys across multiple languages. The most common approach uses JSON files to store translations for each locale. Each file contains key-value pairs where keys remain consistent across languages, but values change based on the target locale. This structure allows developers to reference translation keys in components while translators work independently on the content files. Translation libraries like react-i18next or next-i18next provide hooks and utilities for accessing these translation files. They handle complex scenarios like pluralization rules (English has two plural forms, Polish has five), variable interpolation, and nested translation objects. The library loads the appropriate translation file based on the current locale and provides fallback mechanisms when translations are missing.// Create translation files structure
// locales/en.json
{
"navigation": {
"home": "Home",
"articles": "Articles",
"about": "About"
},
"homepage": {
"title": "Breaking News & Analysis",
"subtitle": "Stay informed with NewsWave"
}
}// locales/es.json - Spanish translations
{
"navigation": {
"home": "Inicio",
"articles": "Artículos",
"about": "Acerca de"
},
"homepage": {
"title": "Noticias de Última Hora y Análisis",
"subtitle": "Mantente informado con NewsWave"
}
}# Install react-i18next for translation management
npm install react-i18next i18nextTerminal
$ npm install react-i18next i18next
+ react-i18next@12.0.0
+ i18next@22.0.0
✓ Translation libraries installed
What just happened?
You created a scalable translation structure using JSON files. Each language gets its own file with identical key structures but different values. The i18next library will load the appropriate file based on the current locale and provide translation utilities in your components. Try this: Create additional language files for French and German using the same key structure.
Using Translations in Components
Accessing translations in React components requires hooks and context providers that connect to your translation files. The useTranslation hook from react-i18next provides a t function that retrieves translated strings based on the current locale. This hook automatically re-renders components when the language changes, ensuring your interface updates immediately when users switch locales. Translation keys use dot notation to access nested objects within your JSON files. A key like "navigation.home" retrieves the "home" value from the "navigation" object. This hierarchical structure helps organize related translations and prevents naming conflicts as your translation files grow larger. The translation system also supports interpolation for dynamic content. Instead of concatenating strings, you embed placeholder variables within translations that get replaced at runtime. This approach respects different grammar structures across languages while maintaining clean, readable translation files.// lib/i18n.js - Configure i18next
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
// Import translation files
import enTranslations from '../locales/en.json';
import esTranslations from '../locales/es.json';// Initialize i18next with resources
i18n
.use(initReactI18next) // Connect to React
.init({
resources: {
en: { translation: enTranslations }, // English translations
es: { translation: esTranslations }, // Spanish translations
},
lng: 'en', // Default language
fallbackLng: 'en', // Fallback when translation missing
});
export default i18n;// components/Navigation.jsx - Use translations
import { useTranslation } from 'react-i18next';
export default function Navigation() {
const { t } = useTranslation(); // Get translation function
return (
<nav className="navigation">
<a href="/">{t('navigation.home')}</a>
<a href="/articles">{t('navigation.articles')}</a>
<a href="/about">{t('navigation.about')}</a>
</nav>
);
}localhost:3000 — NewsWave
What just happened?
The navigation component dynamically displays translated text based on the selected language. The t function retrieves the appropriate translation from your JSON files using dot notation. When users switch languages, all translated text updates immediately throughout the interface. Try this: Click the EN/ES buttons to see the navigation labels change between English and Spanish.
Dynamic Content Translation
Static navigation labels represent just the beginning of internationalization challenges. Dynamic content like article titles, user-generated comments, and real-time data requires more sophisticated translation strategies. Some content gets translated once and stored in multiple languages, while other content needs real-time translation or smart fallback mechanisms. Article content in NewsWave might come from multiple sources. Editorial content written by your team can be professionally translated and stored in multiple languages. Wire service articles might only be available in their original language, requiring automatic translation services or clear language indicators. User comments and community content present additional complexity since you can't pre-translate user-generated content. The solution involves combining pre-translated content with dynamic translation services and smart fallback mechanisms. Your application should gracefully handle missing translations, clearly indicate content language when it differs from the interface language, and provide users with options for automatic translation when needed.// components/ArticleCard.jsx - Handle multi-language articles
import { useTranslation } from 'react-i18next';
export default function ArticleCard({ article }) {
const { t, i18n } = useTranslation(); // Get current language
const currentLang = i18n.language; // Current interface language
// Use translated version if available, fallback to original
const title = article.translations?.[currentLang]?.title || article.title;
const excerpt = article.translations?.[currentLang]?.excerpt || article.excerpt; return (
<article className="article-card">
<h2>{title}</h2>
<p>{excerpt}</p>
{/* Show language indicator if content differs from interface */}
{article.originalLanguage !== currentLang && (
<span className="language-badge">
{t('content.originalLanguage', { lang: article.originalLanguage })}
</span>
)}
<div className="article-meta">
<span>{t('article.publishedOn', { date: article.publishedAt })}</span>
<span>{t('article.author')}: {article.author}</span>
</div>
</article>
);
}localhost:3000/es — NewsWave
What just happened?
The article card intelligently handles multilingual content by checking for translated versions before falling back to the original. When content is displayed in a different language than the interface, a language badge appears to inform users. The metadata (author, date) uses the interface language while respecting the content's original language. Try this: Switch between EN/ES to see how the article adapts and when the language indicator appears.
Locale-Specific Formatting
Different cultures format numbers, dates, currencies, and addresses in distinct ways. What Americans write as "12/31/2023" (MM/DD/YYYY), Europeans write as "31/12/2023" (DD/MM/YYYY), and ISO standard represents as "2023-12-31" (YYYY-MM-DD). Currency symbols, decimal separators, and number grouping follow regional conventions that your international users expect to see. JavaScript's built-in Internationalization API (Intl) provides powerful formatting utilities that respect locale-specific conventions. These APIs handle the complexity of cultural formatting rules while providing a consistent programming interface. The Intl.DateTimeFormat constructor creates locale-aware date formatters, while Intl.NumberFormat handles numbers, currencies, and percentages according to regional preferences. Next.js applications can leverage these APIs alongside translation systems to create truly localized user experiences. Rather than hardcoding formats or manually converting between conventions, you define formatters that automatically adapt based on the current locale. This approach scales naturally as you add new markets and ensures consistency across your application.// utils/formatters.js - Locale-aware formatting utilities
export function formatDate(date, locale = 'en') {
return new Intl.DateTimeFormat(locale, {
year: 'numeric', // Full year (2024)
month: 'long', // Full month name (January)
day: 'numeric', // Day of month (15)
}).format(new Date(date));
}export function formatNumber(number, locale = 'en') {
return new Intl.NumberFormat(locale, {
minimumFractionDigits: 0, // No unnecessary decimals
maximumFractionDigits: 2, // Max 2 decimal places
}).format(number);
}
export function formatCurrency(amount, locale = 'en', currency = 'USD') {
return new Intl.NumberFormat(locale, {
style: 'currency', // Enable currency formatting
currency: currency, // Currency code (USD, EUR, JPY)
}).format(amount);
}// components/ArticleStats.jsx - Use locale formatting
import { useTranslation } from 'react-i18next';
import { formatDate, formatNumber } from '../utils/formatters';
export default function ArticleStats({ article }) {
const { i18n } = useTranslation();
const currentLocale = i18n.language; // Current language/locale
return (
<div className="article-stats">
<span>
📅 {formatDate(article.publishedAt, currentLocale)}
</span>
<span>
👁️ {formatNumber(article.viewCount, currentLocale)} views
</span>
</div>
);
}localhost:3000 — NewsWave
What just happened?
The Intl API automatically formats dates, numbers, and currency according to each locale's conventions. Notice how German uses periods for thousands and commas for decimals, while Japanese yen displays without decimal places. The date format changes from "January 15, 2024" in English to "15. Januar 2024" in German. Try this: Click through different locales to see how the same data adapts to cultural expectations.
Language Switching and Detection
User-friendly language switching requires both automatic detection and manual override capabilities. Browser-based detection uses the Accept-Language header to determine user preferences, but users should always have the ability to manually select their preferred language. Some users browse with English browsers but prefer content in their native language, while others might be accessing your site from shared computers with different language settings. Next.js provides automatic locale detection that examines browser preferences and redirects users to the appropriate language version of your site. This detection happens server-side during the initial request, ensuring users see content in their preferred language from the first page load. The framework also handles locale persistence across navigation, maintaining the user's language choice as they browse different pages. Manual language switching involves updating both the current locale and the URL structure. When users select a new language, your application should update the interface immediately while navigating to the equivalent page in the new locale. This navigation preserves the user's current context — if they're reading an article in English and switch to Spanish, they should see the Spanish version of the same article rather than being redirected to the homepage.// components/LanguageSwitcher.jsx - Manual language selection
import { useRouter } from 'next/router';
import { useTranslation } from 'react-i18next';
const languages = [
{ code: 'en', name: 'English', flag: '🇺🇸' },
{ code: 'es', name: 'Español', flag: '🇪🇸' },
{ code: 'fr', name: 'Français', flag: '🇫🇷' },
{ code: 'de', name: 'Deutsch', flag: '🇩🇪' },
];export default function LanguageSwitcher() {
const router = useRouter();
const { i18n } = useTranslation();
const switchLanguage = (newLocale) => {
// Update i18n language
i18n.changeLanguage(newLocale);
// Navigate to same page in new locale
router.push(router.asPath, router.asPath, { locale: newLocale });
};
return (
<div className="language-switcher">
{languages.map(lang => (
<button
key={lang.code}
onClick={() => switchLanguage(lang.code)}
className={router.locale === lang.code ? 'active' : ''}
>
{lang.flag} {lang.name}
</button>
))}
</div>
);
}localhost:3000 — NewsWave
What just happened?
The language switcher provides manual override for automatic detection. Users can select their preferred language from flag-labeled buttons, with the active language clearly highlighted. When switched, the entire interface updates immediately while preserving the current page context. This pattern works alongside browser detection to give users full control over their language experience. Try this: Click different language buttons to see instant interface updates across all content.
Up Next: Error Handling
Learn to gracefully handle and recover from errors in production Next.js applications with custom error pages and boundaries.
Quiz
1. NewsWave needs to support Spanish and French versions. What does Next.js sub-path routing accomplish for internationalization?
2. NewsWave displays article view counts that need to format correctly for different locales (1,234 vs 1.234). Which approach handles locale-specific number formatting?
3. NewsWave receives breaking news articles in various languages, but not all articles are translated immediately. What's the best strategy for handling mixed-language content?