Always build a multilingual interface using i18n
Build a multilingual interface where:
- language is selected deterministically (URL, user setting, or browser preference),
- all user-facing text comes from translation files,
- navigation, metadata, and SEO stay correct for each locale.
Mandatory baseline for all projects:
- every project must ship with these locales:
ru,en,es,pt.
- Keep locale configuration in one place:
locales(supported language codes),defaultLocale,- locale strategy (
always in URL,as-needed, etc.), - locale detection policy.
- required baseline locales in every project:
ru,en,es,pt.
- Use URL-based locales for web apps:
- Example:
/en/...,/es/.... - This is best for SEO, sharing, analytics segmentation, and reproducibility.
- Separate translation resources from UI logic:
- Store messages in per-locale files (
ru.json,en.json,es.json,pt.json, etc.). - Group keys by namespaces (
common,auth,checkout,profile, etc.).
- Load translations close to render time:
- Server-side for server-rendered pages and metadata.
- Client-side hooks for interactive components.
app/
[locale]/
layout.tsx
page.tsx
...feature pages
sitemap.ts
i18n/
routing.ts
request.ts
middleware.ts
messages/
ru.json
en.json
es.json
pt.json
Use any equivalent structure in your stack, but keep responsibilities split:
- routing config,
- request/locale resolution,
- middleware,
- translation dictionaries,
- locale-aware pages/layout.
- Never hardcode visible UI text in components.
- Use stable key names and semantic namespaces.
- Keep all locale files key-identical.
- Use placeholders for dynamic values (
{count},{name}) instead of string concatenation. - Add pluralization/format rules through your i18n library, not manual
ifblocks where possible.
- Use locale-aware link/router helpers everywhere for internal navigation.
- Keep locale when changing routes.
- Validate locale from URL and fallback to
defaultLocalewhen invalid. - Exclude API/static/internal assets from locale middleware.
- Client components: use i18n hooks (
useTranslationsor equivalent). - Server components/pages: use server translation API (
getTranslationsor equivalent). - Keep locale-dependent logic explicit (for example currency, support links, date formatting).
- Localize metadata (
title,description, OpenGraph, Twitter cards, JSON-LD where needed). - Provide
hreflangalternates for each locale andx-default. - Generate locale-specific sitemap entries.
- Keep canonical and alternate URLs consistent with your locale strategy.
- Add a CI check that compares translation key trees across all locale files.
- Add lint/static checks for forbidden hardcoded strings in UI layers.
- Fail build when required translation keys are missing.
- Keep a PR checklist item: "new UI text added to all locales".
- Track untranslated strings explicitly (for example marker values) and block release if present.
next-intlis a strong default for routing + server/client translation APIs.
i18next+react-i18nextFormatJS(react-intl)LinguiJS
Pick one stack and standardize it project-wide.
- Define locales and fallback rules.
Minimum required locales:
ru,en,es,pt. - Set up locale-aware routing.
- Add translation provider and request-level locale loading.
- Migrate all visible strings to translation keys.
- Localize metadata and sitemap.
- Add CI checks for translation completeness.
- Test all locales for navigation, SEO tags, and runtime behavior.