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 pathConfiguration:
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>;
}
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:
?lng=en)Accept-Language)lang attribute of HTML tagsen.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):
window._SSR_DATA set during server-side rendering, applicable to both SSR and CSR projectslocalePathRedirect is true, detect language prefix from URL pathdetection.order (Cookie, LocalStorage, query parameters, request headers, etc.)initOptions.lngfallbackLanguage as the final fallbackSSR 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
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 LocalStorageSpecifies 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 to 0 (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), default 525600 (1 year)cookieExpirationDate: Cookie expiration date (Date object), takes precedence over cookieMinutesExample:
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:
'/api') and prefix match ('/api' will match /api and /api/users)true to indicate ignoring redirectionExample:
// 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');