Internationalization
Multi-language support architecture using next-intl in your SaaS application.
This SaaS Starter kit uses next-intl for internationalization, providing a robust system for multi-language support with server-side rendering, namespace-based organization, and automatic locale detection.
Architecture Overview
The i18n system is split between a shared package and app-specific configuration:
packages/i18n/ # Shared i18n package├── src/│ ├── routing.ts # Locale configuration│ ├── navigation.ts # Locale-aware navigation utilities│ └── client-provider.tsx # Client-side providerapps/web/i18n/ # App-specific configuration├── request.ts # Namespace definitions and loading└── messages/ └── en/ # English translations ├── common.json ├── auth.json ├── account.json ├── organizations.json ├── billing.json ├── marketing.json ├── settings.json ├── goodbye.json └── errors.jsonConfiguration Files
Locale Configuration
The locale configuration is defined in packages/i18n/src/routing.ts:
import { defineRouting } from 'next-intl/routing';const defaultLanguage = process.env.NEXT_PUBLIC_DEFAULT_LOCALE ?? 'en';export const languages: string[] = [ defaultLanguage, // Add other languages here: // 'es', // Spanish // 'fr', // French];export const routing = defineRouting({ locales: languages, defaultLocale: defaultLanguage, localePrefix: 'as-needed', localeDetection: true,});export type Locale = (typeof routing.locales)[number];Key settings:
locales: Array of supported language codesdefaultLocale: The default language (fromNEXT_PUBLIC_DEFAULT_LOCALEenv variable)localePrefix: 'as-needed': Default locale has no URL prefix, other locales dolocaleDetection: true: Automatically detect locale from browser headers/cookies
URL Structure
With localePrefix: 'as-needed':
| URL | Locale |
|---|---|
/about | English (default) |
/es/about | Spanish |
/fr/about | French |
Namespace Configuration
Namespaces are defined in apps/web/i18n/request.ts:
const namespaces = [ 'common', 'auth', 'account', 'organizations', 'billing', 'marketing', 'settings', 'goodbye', 'errors',] as const;Each namespace corresponds to a JSON file in apps/web/i18n/messages/{locale}/.
Package Exports
The @kit/i18n package provides several entry points:
@kit/i18n/routing
Locale configuration and type definitions:
import { routing, languages, type Locale } from '@kit/i18n/routing';@kit/i18n/navigation
Locale-aware navigation utilities:
import { Link, redirect, useRouter, usePathname } from '@kit/i18n/navigation';These work like their Next.js counterparts but automatically handle locale prefixes.
@kit/i18n/server
Server-side utilities for React Server Components:
import { getTranslations, getLocale, getMessages, getNow, getTimeZone} from '@kit/i18n/server';@kit/i18n/provider
Client-side provider for client components:
import { I18nClientProvider } from '@kit/i18n/provider';Supported Namespaces
| Namespace | Purpose |
|---|---|
common | Shared UI labels, routes, roles, OTP, cookie banner |
auth | Sign up, sign in, password reset, MFA |
account | Profile updates, email/password management |
organizations | Team management, invitations, member actions |
billing | Subscriptions, plans, billing portal |
marketing | Landing page, blog, FAQ, contact |
settings | Personal and organization settings |
goodbye | Account deletion confirmation |
errors | Error messages and codes |
Next: Using Translations →