| title | Locale Detection |
|---|
The plugin supports multiple language detection methods, which can be combined to meet different business requirements.
When localePathRedirect is set to true, the plugin will detect the language from the URL path.
Examples:
/zh/about→ Detected language:zh/en/about→ Detected language:en/about→ If there's no language prefix, will redirect to the default language path
Configuration:
i18nPlugin({
localeDetection: {
localePathRedirect: true,
languages: ['zh', 'en'],
fallbackLanguage: 'en',
},
});Route Configuration (Convention-based Routing):
When using convention-based routing, you need to create a [lang] directory under the routes/ directory to represent the language parameter:
routes/
├── [lang]/
│ ├── layout.tsx # Layout component
│ ├── page.tsx # Home page
│ └── about/
│ └── page.tsx # About pageroutes/[lang]/layout.tsx:
import { Outlet } from '@modern-js/runtime/router';
export default function Layout() {
return <Outlet />;
}routes/[lang]/page.tsx:
export default function Home() {
return <div>Home</div>;
}routes/[lang]/about/page.tsx:
export default function About() {
return <div>About</div>;
}:::info
If using custom routing (modern.routes.ts), you need to add :lang dynamic parameter in the route configuration. Convention-based routing will automatically generate corresponding routes based on the file structure.
:::
When i18nextDetector is set to true, the i18next language detector will be enabled, supporting language detection from the following locations:
- Cookie: Read language settings from cookies
- LocalStorage: Read from browser LocalStorage
- Query Parameters: Read from URL query parameters (e.g.,
?lng=en) - Request Headers: Read from HTTP request headers (e.g.,
Accept-Language) - HTML Tag: Read from the
langattribute of HTML tags - Subdomain: Read from subdomain (e.g.,
en.example.com)
Configuration:
i18nPlugin({
localeDetection: {
i18nextDetector: true,
detection: {
order: ['cookie', 'querystring', 'header'],
lookupCookie: 'i18next',
lookupQuerystring: 'lng',
lookupHeader: 'accept-language',
caches: ['cookie'],
},
},
});You can customize detection behavior through the detection option:
i18nPlugin({
localeDetection: {
i18nextDetector: true,
detection: {
// Detection order
order: ['path', 'cookie', 'querystring', 'header'],
// Cookie related
lookupCookie: 'i18next',
cookieExpirationDate: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000), // Expires in 1 year
cookieDomain: '.example.com',
// Query parameter related
lookupQuerystring: 'lng',
// Request header related
lookupHeader: 'accept-language',
// Cache configuration
caches: ['cookie', 'localStorage'],
},
},
});The plugin's language detection follows the following priority order (from highest to lowest):
- SSR Data (highest priority): Read language from
window._SSR_DATAset during server-side rendering, applicable to both SSR and CSR projects - Path Detection: If
localePathRedirectistrue, detect language prefix from URL path - i18next Detector: Execute detection according to the order configured in
detection.order(Cookie, LocalStorage, query parameters, request headers, etc.) - User Configured Language: Use the language configured in
initOptions.lng - Fallback Language: Use
fallbackLanguageas the final fallback
:::info SSR data detection has the highest priority to ensure the client uses the language detected during server-side rendering, avoiding language flickering issues caused by client-side re-detection. :::
Example:
// Configured detection order (only affects priority within i18next detector)
detection: {
order: ['path', 'cookie', 'querystring', 'header'],
}
// Actual detection flow:
// 1. First check SSR data (window._SSR_DATA)
// 2. Then check URL path (if localePathRedirect is enabled)
// 3. Then check i18next detector according to order:
// - Cookie
// - Query parameters
// - Request headers
// 4. Then use initOptions.lng (if configured)
// 5. Finally use fallbackLanguageSpecifies the order of language detection, optional values:
path: Detect from URL pathquerystring: Detect from query parameterscookie: Detect from cookieslocalStorage: Detect from LocalStoragesessionStorage: Detect from SessionStoragenavigator: Detect from browser language settingshtmlTag: Detect from HTML tagsheader: Detect from HTTP request headerssubdomain: Detect from subdomain
:::warning
path detection requires localePathRedirect to be true. localStorage, sessionStorage, navigator, and htmlTag are only available in browser environments.
:::
Specifies where the detected language should be cached, optional values:
false: No caching['cookie']: Cache to Cookie['localStorage']: Cache to LocalStorage (browser only)['cookie', 'localStorage']: Cache to both Cookie and LocalStorage
Specifies the key name used when reading language from query parameters, cookies, LocalStorage, SessionStorage, or request headers:
lookupQuerystring: Default'lng', e.g.,?lng=enlookupCookie: Default'i18next'lookupLocalStorage: Default'i18nextLng'(browser only)lookupSession: SessionStorage key name (browser only)lookupHeader: Default'accept-language'
Specifies which position in the URL path to start detecting language (when 'path' is included in order):
lookupFromPathIndex: Path segment index, defaults to0(first path segment)
Example:
// URL: /api/v1/en/users
// If lookupFromPathIndex = 2, detection starts from the third path segment ('en')
detection: {
order: ['path'],
lookupFromPathIndex: 2,
}Controls Cookie expiration time:
cookieMinutes: Cookie expiration time (minutes), default525600(1 year)cookieExpirationDate: Cookie expiration date (Date object), takes precedence overcookieMinutes
Example:
detection: {
cookieMinutes: 60 * 24 * 7, // Expires in 7 days
// or
cookieExpirationDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // Expires in 7 days
}Specifies which routes should ignore automatic language redirection. This is very useful for API routes, static resources, and other paths that don't need language prefixes.
Configuration:
i18nPlugin({
localeDetection: {
localePathRedirect: true,
languages: ['zh', 'en'],
fallbackLanguage: 'en',
// String array: supports exact match and prefix match
ignoreRedirectRoutes: ['/api', '/admin', '/static'],
// Or use function for more flexible judgment
ignoreRedirectRoutes: pathname => {
return pathname.startsWith('/api') || pathname.startsWith('/admin');
},
},
});Matching Rules:
- String array: Supports exact match (
'/api') and prefix match ('/api'will match/apiand/api/users) - Function: Receives pathname (with language prefix removed), returns
trueto indicate ignoring redirection
Example:
// Ignore all API routes and static resources
ignoreRedirectRoutes: ['/api', '/static', '/assets'];
// Use function to ignore all paths starting with /api
ignoreRedirectRoutes: pathname => pathname.startsWith('/api');