Internationalization
FR + EN with next-intl — architecture and preparation steps
Priority: growth — decide early
The marketplace is French-only today and that's fine. But retrofitting i18n is painful — the zero-cost preparation steps below are worth following now, and the architecture decision (next-intl, subdirectory URLs) is made so nobody re-litigates it later.
Stack decision
| Layer | Library | Why |
|---|---|---|
| Frontend | next-intl | Best Next.js App Router support, ICU message format |
| Backend | nestjs-i18n | API error messages, email templates |
| Content | Translation JSON files | Simple, version-controlled |
Frontend architecture
apps/web/
messages/
fr.json # French translations (default)
en.json # English translations
i18n/
request.ts # next-intl config
app/
[locale]/ # locale prefix in URL: /fr/deals, /en/deals
middleware.ts # locale detection from browser/cookie (extend existing)import { getRequestConfig } from "next-intl/server";
export default getRequestConfig(async ({ locale }) => ({
messages: (await import(`../messages/${locale}.json`)).default,
}));URL strategy: subdirectory (/fr/deals, /en/deals) over subdomains — simpler, better SEO, single deployment.
What to translate
✅ UI labels, buttons, placeholders · form validation messages · toasts · error messages · email templates · legal pages (separate content per locale) · SEO metadata.
❌ User-generated content (deal titles, descriptions, chat) · product names, specs, categories — FPV terminology is universally English in the community ("frame", "motor", "ESC", "VTX").
Scope: ~200–300 translation keys for V1 — manageable manually, no Crowdin/Lokalise needed yet.
Preparation steps (now, zero effort)
- No hardcoded language-specific date formats — use
Intl.DateTimeFormat/RelativeDate(already the convention). - No hardcoded currency formatting —
formatPrice()already usesIntl.NumberFormatcorrectly. - Extract user-visible strings from new features into
messages/fr.jsonas you build them — much cheaper than retroactive extraction.
Tasks
- Install
next-intl; createmessages/fr.json+messages/en.json - Middleware locale detection; restructure routes under
[locale]/ - Replace hardcoded strings with
useTranslations(); locale switcher (FR/EN) in header nestjs-i18nfor backend error messages; translate email templates- SEO: hreflang tags, localized metadata; legal pages per locale