Add a Locale
The app uses next-intl with locale-prefixed routes under src/app/[locale].
This guide shows where locale configuration lives, how to add a new message file, and what to verify so the new language works across public and authenticated routes.
Before adding a locale
Review Project Structure and First Customization first so you know where localized labels and config-driven copy already live in the project.
What this guide covers
Routing setup
How new locale codes join the existing next-intl routing system.
Message files
How to create and keep translation keys aligned with the current supported locales.
Route verification
How to confirm public and protected pages still resolve correctly under the new locale.
Main files and folders
| File | Propósito |
|---|---|
src/i18n/routing.ts | Supported locales and route-level i18n configuration. |
src/i18n/request.ts | Request-time locale message loading. |
src/middleware.ts | Locale-aware routing entry behavior. |
messages/en.json | English translation base. |
messages/es.json | Spanish translation file. |
messages/cn.json | Chinese translation file. |
Recommended sequence
Use this order when adding a new language.
Register the locale code
Add the new locale to the routing config so the app can recognize locale-prefixed URLs for that language.
Create the message file
Add a new locale JSON file and mirror the same keys used by the existing translations.
Translate config-driven content
Review marketing, auth, dashboard, pricing, and footer keys so the new locale is not partially translated.
Verify routing and rendering
Test the main public and protected routes under the new locale before considering the work finished.
Steps
1. Add the locale code
Add the new locale to the locales array in src/i18n/routing.ts.
2. Create the message file
Add a messages/<locale>/ directory with the same JSON files used by the existing languages (system.json, navbar.json, dashboard.json, auth.json).
3. Translate config-driven content
Review keys referenced by:
- dashboard labels
- auth forms
- marketing sections
- footer content
- pricing and FAQ
4. Verify route behavior
Because the app is locale-first, every user-facing route should continue to resolve correctly under the new locale.
Test:
- home
- sign-in
- sign-up
- forgot password
- dashboard
- payment result pages
Translation completeness matters
A locale can be technically registered and still feel broken if config-driven labels or message keys are missing in one part of the app.
Important note
The middleware matcher is locale-agnostic, so new locales added through src/i18n/routing.ts automatically participate in the routing system without needing a separate matcher update.