Internationalization and translation management. Use when adding new translations, updating existing content, creating new language support, or working with locale routing.
CRITICAL: NEVER use the Edit tool on JSON locale files. Multi-byte UTF-8 characters (Japanese, etc.) cause crashes. ALWAYS use apply-inline command from the translation-helper.ts script to update translations.
i18n/
├── config.ts # Locale configuration, supported locales
└── (future files)
i18n.config.ts # next-intl request configuration
locales/
├── en/
│ └── common.json # English translations
└── es/
└── common.json # Spanish translations
app/[locale]/ # Locale-aware routes
├── layout.tsx # IntlProvider wrapper
├── page.tsx # Homepage
└── ... # Other pages
middleware.ts # Locale detection and routing
| File | Purpose |
|---|
i18n/config.ts | Defines SUPPORTED_LOCALES, DEFAULT_LOCALE, isValidLocale() |
i18n.config.ts | next-intl server config with getRequestConfig |
locales/{locale}/common.json | Translation strings organized by namespace |
middleware.ts | Detects locale from URL/cookie/header, handles routing |
Edit locales/en/common.json:
{
"namespace": {
"newKey": "English text here",
"anotherKey": "More text"
}
}
Edit locales/es/common.json (and any other supported locales):
{
"namespace": {
"newKey": "Texto en español aquí",
"anotherKey": "Más texto"
}
}
Client Component:
'use client';
import { useTranslations } from 'next-intl';
export function MyComponent() {
const t = useTranslations('namespace');
return <p>{t('newKey')}</p>;
}
Server Component:
import { getTranslations } from 'next-intl/server';
export default async function MyPage() {
const t = await getTranslations('namespace');
return <p>{t('newKey')}</p>;
}
Organize translations by feature/area:
| Namespace | Purpose | Example Keys |
|---|---|---|
common | Shared UI elements | loading, error, submit |
nav | Navigation items | features, pricing, signIn |
footer | Footer content | privacy, terms, copyright |
homepage | Landing page | heroTitle, ctaButton |
dashboard | Dashboard UI | credits, history, settings |
auth | Auth forms | email, password, forgotPassword |
Edit i18n/config.ts:
export const SUPPORTED_LOCALES = ['en', 'es', 'fr'] as const; // Add 'fr'
export const locales = {
en: { label: 'English', country: 'US' },
es: { label: 'Español', country: 'ES' },
fr: { label: 'Français', country: 'FR' }, // Add French
} as const;
Edit client/components/i18n/LocaleSwitcher.tsx:
import { US, ES, FR } from 'country-flag-icons/react/3x2';
const FlagComponents = {
US,
ES,
FR, // Add FR
} as const;
Create locales/fr/common.json:
{
"nav": {
"features": "Fonctionnalités",
"pricing": "Tarifs"
}
// Copy structure from en/common.json and translate
}
Edit app/[locale]/layout.tsx alternates: