web-i18n-nextjs
v1.0.0Internationalization (i18n) guide for Next.js / Node.js web applications using the App Router. Covers translation file structure, locale routing, SEO metadata per locale, hreflang, structured JSON-LD data, UI component translations, and multi-language sitemap generation. Use when the user asks to: a...
Installation
i18n for Next.js — Implementation Guide
Core Principles
- All user-facing features must implement i18n — no hardcoded strings in components.
- Translations must be natural and idiomatic — never use scripts or machine translation; treat quality the same as English copywriting.
- SEO metadata, JSON-LD structured data, and sitemaps must all be locale-aware.
- Default locale (English) uses clean URLs with no prefix (
/products); other locales use a prefix (/es/products).
Supported Locales
Locale list lives in src/lib/i18n/locales.ts. Keep the sitemap script's locales array in sync with this file.
export const locales = ['en', 'es', 'fr', 'de', 'ja', 'zh-CN', /* ... add as needed */]
export const defaultLocale = 'en'
export type Locale = typeof locales[number]
Directory Structure
src/app/[lang]/
├── dictionaries/ ← One JSON file per locale
│ ├── en.json
│ ├── es.json
│ └── ...
├── dictionaries.ts ← getDictionary(locale) server helper
├── layout.tsx ← Root layout: generateMetadata + hreflang + JSON-LD
└── <page>/
└── page.tsx ← generateMetadata + page content
Translation Files
See references/translation-files.md for:
- JSON key hierarchy conventions (page.section.key)
- Server-side getDictionary() usage
- Client-side useDictionary() hook usage
- Template variable pattern ({count} substitution)
- Fallback pattern for missing keys
Routing & Middleware
See references/routing.md for:
- src/middleware.ts — locale detection, redirect /en/* → /*, rewrite for default locale
- LocalizedLink component — automatically prefixes non-default locales
- useLocale() hook — reads locale from URL params → pathname → localStorage → default
- getLocalizedPath() / removeLocalePrefix() utilities
SEO Metadata
See references/seo-metadata.md for:
- generateMetadata() pattern in layout/page files
- generateAlternatesMetadata() from src/lib/i18n/seo.ts
- Full hreflang alternates.languages output (all locales + x-default)
- OpenGraph locale / alternateLocale fields
- html lang attribute and LangSetter client component
Structured JSON-LD Data
See references/structured-data.md for:
- WebApplication schema with translated featureList, description
- BlogPosting schema with inLanguage field
- FAQ schema with translated acceptedAnswer
- BreadcrumbList schema with localized URLs
- Rendering via <Script> or <script> tags
Multi-language Sitemap
See references/sitemap.md for:
- Sitemap structure: one <url> entry per page with <xhtml:link> alternates for every locale
- <loc> uses the default-locale (clean) URL; x-default also points there
- Full XML example with static and dynamic pages
- Next.js App Router sitemap.ts implementation pattern
- What to include vs. exclude (admin/API routes excluded)
- Hreflang language code format rules
Quick Checklist — Adding a New Feature with i18n
- Add translation keys to all locale JSON files in
src/app/[lang]/dictionaries/ - Add English first, then translate to all other languages naturally
- Server components:
const dict = await getDictionary(locale)→dict?.page?.section?.key || 'fallback' - Client components:
const dict = useDictionary()→ same fallback pattern - Add
generateMetadata()to the page file, callinggenerateAlternatesMetadata() - Add JSON-LD structured data script tag with translated fields and
inLanguage - Update sitemap if the page is new: add it to the sitemap source (see references/sitemap.md)
- Use
<LocalizedLink>for internal links andgetLocalizedPath()for programmatic navigation
Quick Checklist — Adding a New Locale
- Add locale code to
localesarray insrc/lib/i18n/locales.ts - Add locale entry to
dictionaries/as<code>.json(full translation ofen.json) - Add entry in
src/app/[lang]/dictionaries.tsimport map - Add display name in
LanguageSwitcherlanguageNamesmap - Sync the sitemap locale list with the app's
localesarray - Regenerate / redeploy the sitemap