Skip to main content

Internationalization

Multi-language support using next-intl.

Off by default. When on, the site supports multiple languages with URL prefixes like /en/, /ru/, /es/.

Don't enable until you have translations

Turning i18n on with only en.json gives you every downside (extra routing, prefixed URLs) with zero benefit. Only flip it on when you have at least one real translation ready.

How it works

  • Translations live in messages/{locale}.json
  • Middleware (middleware.ts) detects the user's language and routes accordingly
  • Components use the useTranslations() hook to pull strings
  • A language switcher in the header lets users override detection

Language switcher in the site header

Setup

Two toggles, both required:

config/features.config.ts
export const featuresConfig = { /* ... */ i18n: true };
config/i18n.config.ts
export const i18nConfig = {
  enabled: true,
  defaultLocale: 'en',
  locales: ['en', 'ru', 'es'],
  localeCookie: 'NEXT_LOCALE',
  localeDetection: true,
};

Then create translation files:

messages/
├── en.json
├── ru.json
└── es.json

Using translations in components

Server components

import { getTranslations } from 'next-intl/server';
 
export default async function Page() {
  const t = await getTranslations('homepage');
  return <h1>{t('title')}</h1>;
}

Client components

'use client';
import { useTranslations } from 'next-intl';
 
export function Hero() {
  const t = useTranslations('homepage');
  return <h1>{t('title')}</h1>;
}

Always use next-intl's Link, not Next's — it auto-prefixes with the current locale:

import { Link } from '@/i18n/navigation';  // or next-intl equivalent
 
<Link href="/pricing">Pricing</Link>
// renders as /pricing for EN, /ru/pricing for RU, etc.

What's not auto-translated

  • User-generated content (project names, descriptions, comments) — stays in whatever language the user typed
  • Blog posts — write separate MDX files per locale, or use a translation service
  • Legal pages — translate the strings in messages/, the content lives there

See also