From efbcf124d581ebae07927abe5eecec4ed9a4cc01 Mon Sep 17 00:00:00 2001 From: caohuilin Date: Mon, 1 Dec 2025 11:19:38 +0800 Subject: [PATCH 1/3] docs: update i18n docs --- .../advanced-features/international/api.mdx | 27 +++- .../international/configuration.mdx | 14 ++ .../international/locale-detection.mdx | 106 +++++++++++-- .../international/routing.mdx | 24 +++ .../advanced-features/international/api.mdx | 28 +++- .../international/configuration.mdx | 14 ++ .../international/locale-detection.mdx | 145 +++++++++++++++--- .../international/quick-start.mdx | 6 +- .../international/routing.mdx | 24 +++ 9 files changed, 339 insertions(+), 49 deletions(-) diff --git a/packages/document/docs/en/guides/advanced-features/international/api.mdx b/packages/document/docs/en/guides/advanced-features/international/api.mdx index efb92ab9af6b..7b3bb81825df 100644 --- a/packages/document/docs/en/guides/advanced-features/international/api.mdx +++ b/packages/document/docs/en/guides/advanced-features/international/api.mdx @@ -38,12 +38,8 @@ interface UseModernI18nReturn { import { useModernI18n } from '@modern-js/plugin-i18n/runtime'; function LanguageSwitcher() { - const { - language, - changeLanguage, - supportedLanguages, - isLanguageSupported, - } = useModernI18n(); + const { language, changeLanguage, supportedLanguages, isLanguageSupported } = + useModernI18n(); return (
@@ -134,10 +130,11 @@ function MyComponent() { :::info `isResourcesReady` automatically checks: + - If i18n instance is initialized - If any resources for the current language are currently loading (SDK backend only) - If all required namespaces for the current language are loaded in the store -::: + ::: ## I18nLink Component @@ -267,14 +264,27 @@ interface I18nInitOptions { ```ts interface LanguageDetectorOptions { + /** Detection order */ order?: string[]; + /** Query parameter key name, default 'lng' */ lookupQuerystring?: string; + /** Cookie key name, default 'i18next' */ lookupCookie?: string; + /** LocalStorage key name, default 'i18nextLng' (browser only) */ + lookupLocalStorage?: string; + /** SessionStorage key name (browser only) */ lookupSession?: string; + /** Starting index in path for language detection, default 0 */ lookupFromPathIndex?: number; + /** Cache method, can be false or string array (e.g., ['cookie', 'localStorage']) */ caches?: boolean | string[]; + /** Cookie expiration time (minutes) */ + cookieMinutes?: number; + /** Cookie expiration date (Date object, takes precedence over cookieMinutes) */ cookieExpirationDate?: Date; + /** Cookie domain */ cookieDomain?: string; + /** Request header key name, default 'accept-language' */ lookupHeader?: string; } ``` @@ -289,3 +299,6 @@ type Resources = { }; ``` +:::info +The namespace value can be a string (for simple key-value pairs) or an object (for nested translation structures). +::: diff --git a/packages/document/docs/en/guides/advanced-features/international/configuration.mdx b/packages/document/docs/en/guides/advanced-features/international/configuration.mdx index 02f90ff4a086..3dc8482dd3e0 100644 --- a/packages/document/docs/en/guides/advanced-features/international/configuration.mdx +++ b/packages/document/docs/en/guides/advanced-features/international/configuration.mdx @@ -55,6 +55,20 @@ interface BaseLocaleDetectionOptions { /** Custom detection configuration */ detection?: LanguageDetectorOptions; + + /** Routes to ignore automatic redirection (array of path patterns or function) + * + * Can be a string array (path patterns) or a function to determine if redirection should be ignored. + * Supports exact match and prefix match (e.g., '/api' will match '/api' and '/api/users'). + * + * @example + * // String array + * ignoreRedirectRoutes: ['/api', '/admin'] + * + * // Function + * ignoreRedirectRoutes: (pathname) => pathname.startsWith('/api') + */ + ignoreRedirectRoutes?: string[] | ((pathname: string) => boolean); } interface LocaleDetectionOptions extends BaseLocaleDetectionOptions { diff --git a/packages/document/docs/en/guides/advanced-features/international/locale-detection.mdx b/packages/document/docs/en/guides/advanced-features/international/locale-detection.mdx index 332894c1b5f4..8aa207d857ff 100644 --- a/packages/document/docs/en/guides/advanced-features/international/locale-detection.mdx +++ b/packages/document/docs/en/guides/advanced-features/international/locale-detection.mdx @@ -133,25 +133,34 @@ i18nPlugin({ ## Detection Priority -When multiple detection methods are enabled, the detection priority follows the order configured in `detection.order`: +The plugin's language detection follows the following priority order (from highest to lowest): -1. **Path Detection** (if `localePathRedirect` is `true`) -2. **i18next Detector** (following the order configured in `order`) -3. **Fallback Language** (`fallbackLanguage`) +1. **SSR Data** (highest priority): Read language from `window._SSR_DATA` set during server-side rendering, applicable to both SSR and CSR projects +2. **Path Detection**: If `localePathRedirect` is `true`, detect language prefix from URL path +3. **i18next Detector**: Execute detection according to the order configured in `detection.order` (Cookie, LocalStorage, query parameters, request headers, etc.) +4. **User Configured Language**: Use the language configured in `initOptions.lng` +5. **Fallback Language**: Use `fallbackLanguage` as 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**: ```ts -// Configured detection order +// Configured detection order (only affects priority within i18next detector) detection: { order: ['path', 'cookie', 'querystring', 'header'], } // Actual detection flow: -// 1. First check URL path (if localePathRedirect is enabled) -// 2. Then check Cookie -// 3. Then check query parameters -// 4. Then check request headers +// 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 fallbackLanguage ``` @@ -172,7 +181,7 @@ Specifies the order of language detection, optional values: - `subdomain`: Detect from subdomain :::warning -`path` detection requires `localePathRedirect` to be `true`. `localStorage`, `navigator`, and `htmlTag` are only available in browser environments. +`path` detection requires `localePathRedirect` to be `true`. `localStorage`, `sessionStorage`, `navigator`, and `htmlTag` are only available in browser environments. ::: ### caches (Cache Method) @@ -184,11 +193,84 @@ Specifies where the detected language should be cached, optional values: - `['localStorage']`: Cache to LocalStorage (browser only) - `['cookie', 'localStorage']`: Cache to both Cookie and LocalStorage -### lookupQuerystring, lookupCookie, lookupHeader +### lookupQuerystring, lookupCookie, lookupLocalStorage, lookupSession, lookupHeader -Specifies the key name used when reading language from query parameters, cookies, or request headers: +Specifies the key name used when reading language from query parameters, cookies, LocalStorage, SessionStorage, or request headers: - `lookupQuerystring`: Default `'lng'`, e.g., `?lng=en` - `lookupCookie`: Default `'i18next'` +- `lookupLocalStorage`: Default `'i18nextLng'` (browser only) +- `lookupSession`: SessionStorage key name (browser only) - `lookupHeader`: Default `'accept-language'` +### lookupFromPathIndex + +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**: + +```ts +// URL: /api/v1/en/users +// If lookupFromPathIndex = 2, detection starts from the third path segment ('en') +detection: { + order: ['path'], + lookupFromPathIndex: 2, +} +``` + +### cookieMinutes, cookieExpirationDate + +Controls Cookie expiration time: + +- `cookieMinutes`: Cookie expiration time (minutes), default `525600` (1 year) +- `cookieExpirationDate`: Cookie expiration date (Date object), takes precedence over `cookieMinutes` + +**Example**: + +```ts +detection: { + cookieMinutes: 60 * 24 * 7, // Expires in 7 days + // or + cookieExpirationDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // Expires in 7 days +} +``` + +### ignoreRedirectRoutes + +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**: + +```ts +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 `/api` and `/api/users`) +- Function: Receives pathname (with language prefix removed), returns `true` to indicate ignoring redirection + +**Example**: + +```ts +// 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'); +``` + diff --git a/packages/document/docs/en/guides/advanced-features/international/routing.mdx b/packages/document/docs/en/guides/advanced-features/international/routing.mdx index 3b7791312b3c..e8fbe1d0f287 100644 --- a/packages/document/docs/en/guides/advanced-features/international/routing.mdx +++ b/packages/document/docs/en/guides/advanced-features/international/routing.mdx @@ -18,10 +18,34 @@ i18nPlugin({ localePathRedirect: true, languages: ['zh', 'en'], fallbackLanguage: 'en', + // Optional: ignore automatic redirection for certain routes + ignoreRedirectRoutes: ['/api', '/admin'], }, }); ``` +### Ignore Redirection Routes + +Some routes (such as API routes, static resources, etc.) don't need language prefixes. You can use the `ignoreRedirectRoutes` configuration to ignore automatic redirection for these routes: + +```ts +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'); + }, + }, +}); +``` + +For more details, please refer to the `ignoreRedirectRoutes` configuration in the [Locale Detection documentation](./locale-detection#ignoreredirectroutes). + ## Route Configuration After enabling path redirection, you need to add `:lang` dynamic parameter to the route configuration. diff --git a/packages/document/docs/zh/guides/advanced-features/international/api.mdx b/packages/document/docs/zh/guides/advanced-features/international/api.mdx index c3b87de73753..e33345eaac9d 100644 --- a/packages/document/docs/zh/guides/advanced-features/international/api.mdx +++ b/packages/document/docs/zh/guides/advanced-features/international/api.mdx @@ -38,12 +38,8 @@ interface UseModernI18nReturn { import { useModernI18n } from '@modern-js/plugin-i18n/runtime'; function LanguageSwitcher() { - const { - language, - changeLanguage, - supportedLanguages, - isLanguageSupported, - } = useModernI18n(); + const { language, changeLanguage, supportedLanguages, isLanguageSupported } = + useModernI18n(); return (
@@ -90,6 +86,7 @@ await changeLanguage('zh'); :::info `changeLanguage` 是异步函数,返回 Promise。 + ::: ### 语言支持检查 @@ -134,9 +131,11 @@ function MyComponent() { :::info `isResourcesReady` 会自动检查: + - i18n 实例是否已初始化 - 当前语言是否有资源正在加载中(仅 SDK 后端) - 当前语言的所有必需命名空间是否已在 store 中加载完成 + ::: ## I18nLink 组件 @@ -267,14 +266,27 @@ interface I18nInitOptions { ```ts interface LanguageDetectorOptions { + /** 检测顺序 */ order?: string[]; + /** 查询参数的键名,默认 'lng' */ lookupQuerystring?: string; + /** Cookie 的键名,默认 'i18next' */ lookupCookie?: string; + /** LocalStorage 的键名,默认 'i18nextLng'(仅浏览器环境) */ + lookupLocalStorage?: string; + /** SessionStorage 的键名(仅浏览器环境) */ lookupSession?: string; + /** 从路径的哪个位置开始检测语言,默认 0 */ lookupFromPathIndex?: number; + /** 缓存方式,可以是 false、字符串数组(如 ['cookie', 'localStorage']) */ caches?: boolean | string[]; + /** Cookie 过期时间(分钟) */ + cookieMinutes?: number; + /** Cookie 过期日期(Date 对象,优先级高于 cookieMinutes) */ cookieExpirationDate?: Date; + /** Cookie 域名 */ cookieDomain?: string; + /** 请求头的键名,默认 'accept-language' */ lookupHeader?: string; } ``` @@ -289,3 +301,7 @@ type Resources = { }; ``` +:::info +命名空间的值可以是字符串(用于简单的键值对)或对象(用于嵌套的翻译结构)。 + +::: diff --git a/packages/document/docs/zh/guides/advanced-features/international/configuration.mdx b/packages/document/docs/zh/guides/advanced-features/international/configuration.mdx index e50d58f6b71a..e81cd670e7df 100644 --- a/packages/document/docs/zh/guides/advanced-features/international/configuration.mdx +++ b/packages/document/docs/zh/guides/advanced-features/international/configuration.mdx @@ -55,6 +55,20 @@ interface BaseLocaleDetectionOptions { /** 自定义检测配置 */ detection?: LanguageDetectorOptions; + + /** 忽略自动重定向的路由列表或函数 + * + * 可以是一个字符串数组(路径模式),或一个函数来判断是否应该忽略重定向。 + * 支持精确匹配和前缀匹配(如 '/api' 会匹配 '/api' 和 '/api/users')。 + * + * @example + * // 字符串数组 + * ignoreRedirectRoutes: ['/api', '/admin'] + * + * // 函数 + * ignoreRedirectRoutes: (pathname) => pathname.startsWith('/api') + */ + ignoreRedirectRoutes?: string[] | ((pathname: string) => boolean); } interface LocaleDetectionOptions extends BaseLocaleDetectionOptions { diff --git a/packages/document/docs/zh/guides/advanced-features/international/locale-detection.mdx b/packages/document/docs/zh/guides/advanced-features/international/locale-detection.mdx index 36524d5c9f33..36a340f644a2 100644 --- a/packages/document/docs/zh/guides/advanced-features/international/locale-detection.mdx +++ b/packages/document/docs/zh/guides/advanced-features/international/locale-detection.mdx @@ -133,25 +133,34 @@ i18nPlugin({ ## 检测优先级 -当启用多种检测方式时,检测优先级按照 `detection.order` 中配置的顺序执行: +插件的语言检测遵循以下优先级顺序(从高到低): -1. **路径检测**(如果 `localePathRedirect` 为 `true`) -2. **i18next 检测器**(按照 `order` 配置的顺序) -3. **回退语言**(`fallbackLanguage`) +1. **SSR 数据**(最高优先级):从 `window._SSR_DATA` 中读取服务端渲染时设置的语言,适用于 SSR 和 CSR 项目 +2. **路径检测**:如果 `localePathRedirect` 为 `true`,从 URL 路径中检测语言前缀 +3. **i18next 检测器**:按照 `detection.order` 配置的顺序执行检测(Cookie、LocalStorage、查询参数、请求头等) +4. **用户配置语言**:使用 `initOptions.lng` 中配置的语言 +5. **回退语言**:使用 `fallbackLanguage` 作为最终回退 + +:::info +SSR 数据检测优先级最高,这是为了确保客户端能够使用服务端渲染时检测到的语言,避免客户端重新检测导致的语言闪烁问题。 +::: **示例**: ```ts -// 配置的检测顺序 +// 配置的检测顺序(仅影响 i18next 检测器内部的优先级) detection: { order: ['path', 'cookie', 'querystring', 'header'], } // 实际检测流程: -// 1. 首先检查 URL 路径(如果启用 localePathRedirect) -// 2. 然后检查 Cookie -// 3. 然后检查查询参数 -// 4. 然后检查请求头 +// 1. 首先检查 SSR 数据(window._SSR_DATA) +// 2. 然后检查 URL 路径(如果启用 localePathRedirect) +// 3. 然后按照 order 顺序检查 i18next 检测器: +// - Cookie +// - 查询参数 +// - 请求头 +// 4. 然后使用 initOptions.lng(如果配置) // 5. 最后使用 fallbackLanguage ``` @@ -159,20 +168,41 @@ detection: { ### order(检测顺序) -指定语言检测的顺序,可选值: +指定 i18next 检测器内部的检测顺序,可选值: -- `path`:从 URL 路径检测 -- `querystring`:从查询参数检测 +- `path`:从 URL 路径检测(需要 `localePathRedirect` 为 `true`) +- `querystring`:从查询参数检测(如 `?lng=en`) - `cookie`:从 Cookie 检测 -- `localStorage`:从 LocalStorage 检测 -- `sessionStorage`:从 SessionStorage 检测 -- `navigator`:从浏览器语言设置检测 -- `htmlTag`:从 HTML 标签检测 -- `header`:从 HTTP 请求头检测 -- `subdomain`:从子域名检测 +- `localStorage`:从 LocalStorage 检测(仅浏览器环境) +- `sessionStorage`:从 SessionStorage 检测(仅浏览器环境) +- `navigator`:从浏览器语言设置检测(仅浏览器环境) +- `htmlTag`:从 HTML 标签的 `lang` 属性检测(仅浏览器环境) +- `header`:从 HTTP 请求头检测(如 `Accept-Language`) +- `subdomain`:从子域名检测(如 `en.example.com`) + +**默认检测顺序**: + +如果不配置 `order`,插件会使用以下默认顺序: + +```ts +order: [ + 'querystring', // 查询参数优先级最高 + 'cookie', // 然后是 Cookie + 'localStorage', // 然后是 LocalStorage + 'header', // 然后是请求头 + 'navigator', // 然后是浏览器语言 + 'htmlTag', // 然后是 HTML 标签 + 'path', // 然后是路径 + 'subdomain', // 最后是子域名 +]; +``` :::warning -`path` 检测需要 `localePathRedirect` 为 `true`,`localStorage`、`navigator`、`htmlTag` 仅在浏览器环境可用。 +`path` 检测需要 `localePathRedirect` 为 `true`,`localStorage`、`sessionStorage`、`navigator`、`htmlTag` 仅在浏览器环境可用。 +::: + +:::info +注意:`order` 配置只影响 i18next 检测器内部的优先级。实际的检测优先级还包括 SSR 数据和路径检测,它们有更高的优先级(见上面的"检测优先级"章节)。 ::: ### caches(缓存方式) @@ -184,10 +214,83 @@ detection: { - `['localStorage']`:缓存到 LocalStorage(仅浏览器) - `['cookie', 'localStorage']`:同时缓存到 Cookie 和 LocalStorage -### lookupQuerystring、lookupCookie、lookupHeader +### lookupQuerystring、lookupCookie、lookupLocalStorage、lookupSession、lookupHeader -指定从查询参数、Cookie 或请求头中读取语言时使用的键名: +指定从查询参数、Cookie、LocalStorage、SessionStorage 或请求头中读取语言时使用的键名: - `lookupQuerystring`:默认 `'lng'`,例如 `?lng=en` - `lookupCookie`:默认 `'i18next'` +- `lookupLocalStorage`:默认 `'i18nextLng'`(仅浏览器环境) +- `lookupSession`:SessionStorage 的键名(仅浏览器环境) - `lookupHeader`:默认 `'accept-language'` + +### lookupFromPathIndex + +指定从 URL 路径的哪个位置开始检测语言(当 `order` 中包含 `'path'` 时): + +- `lookupFromPathIndex`:路径段索引,默认为 `0`(第一个路径段) + +**示例**: + +```ts +// URL: /api/v1/en/users +// 如果 lookupFromPathIndex = 2,则从第三个路径段('en')开始检测 +detection: { + order: ['path'], + lookupFromPathIndex: 2, +} +``` + +### cookieMinutes、cookieExpirationDate + +控制 Cookie 的过期时间: + +- `cookieMinutes`:Cookie 过期时间(分钟),默认 `525600`(1 年) +- `cookieExpirationDate`:Cookie 过期日期(Date 对象),优先级高于 `cookieMinutes` + +**示例**: + +```ts +detection: { + cookieMinutes: 60 * 24 * 7, // 7天后过期 + // 或 + cookieExpirationDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 7天后过期 +} +``` + +### ignoreRedirectRoutes + +指定哪些路由应该忽略自动语言重定向。这对于 API 路由、静态资源等不需要语言前缀的路径非常有用。 + +**配置方式**: + +```ts +i18nPlugin({ + localeDetection: { + localePathRedirect: true, + languages: ['zh', 'en'], + fallbackLanguage: 'en', + // 字符串数组:支持精确匹配和前缀匹配 + ignoreRedirectRoutes: ['/api', '/admin', '/static'], + // 或使用函数进行更灵活的判断 + ignoreRedirectRoutes: pathname => { + return pathname.startsWith('/api') || pathname.startsWith('/admin'); + }, + }, +}); +``` + +**匹配规则**: + +- 字符串数组:支持精确匹配(`'/api'`)和前缀匹配(`'/api'` 会匹配 `/api` 和 `/api/users`) +- 函数:接收路径名(已去除语言前缀),返回 `true` 表示忽略重定向 + +**示例**: + +```ts +// 忽略所有 API 路由和静态资源 +ignoreRedirectRoutes: ['/api', '/static', '/assets']; + +// 使用函数忽略所有以 /api 开头的路径 +ignoreRedirectRoutes: pathname => pathname.startsWith('/api'); +``` diff --git a/packages/document/docs/zh/guides/advanced-features/international/quick-start.mdx b/packages/document/docs/zh/guides/advanced-features/international/quick-start.mdx index 9c42fce359bc..bdc34e51d800 100644 --- a/packages/document/docs/zh/guides/advanced-features/international/quick-start.mdx +++ b/packages/document/docs/zh/guides/advanced-features/international/quick-start.mdx @@ -20,7 +20,7 @@ pnpm add @modern-js/plugin-i18n i18next react-i18next ## 基础配置 -### 1. 在 `modern.config.ts` 中配置插件 +### 在 `modern.config.ts` 中注册插件 ```ts import { appTools, defineConfig } from '@modern-js/app-tools'; @@ -53,7 +53,7 @@ export default defineConfig({ `server.publicDir` 是必需配置,用于指定资源文件的实际存放位置。即使使用默认的 `loadPath` 路径,也需要配置此项。 ::: -### 2. 创建语言资源文件 +### 创建语言资源文件 在项目根目录创建 `locales` 文件夹,并按语言组织资源文件: @@ -85,7 +85,7 @@ locales/ } ``` -### 3. 在组件中使用 +### 在组件中使用 ```tsx import { useModernI18n } from '@modern-js/plugin-i18n/runtime'; diff --git a/packages/document/docs/zh/guides/advanced-features/international/routing.mdx b/packages/document/docs/zh/guides/advanced-features/international/routing.mdx index 1f42a7c7b35c..e1df70799c7c 100644 --- a/packages/document/docs/zh/guides/advanced-features/international/routing.mdx +++ b/packages/document/docs/zh/guides/advanced-features/international/routing.mdx @@ -18,10 +18,34 @@ i18nPlugin({ localePathRedirect: true, languages: ['zh', 'en'], fallbackLanguage: 'en', + // 可选:忽略某些路由的自动重定向 + ignoreRedirectRoutes: ['/api', '/admin'], }, }); ``` +### 忽略重定向的路由 + +某些路由(如 API 路由、静态资源等)不需要语言前缀,可以使用 `ignoreRedirectRoutes` 配置来忽略这些路由的自动重定向: + +```ts +i18nPlugin({ + localeDetection: { + localePathRedirect: true, + languages: ['zh', 'en'], + fallbackLanguage: 'en', + // 字符串数组:支持精确匹配和前缀匹配 + ignoreRedirectRoutes: ['/api', '/admin', '/static'], + // 或使用函数进行更灵活的判断 + ignoreRedirectRoutes: (pathname) => { + return pathname.startsWith('/api') || pathname.startsWith('/admin'); + }, + }, +}); +``` + +更多详情请参考[语言检测文档](./locale-detection#ignoreredirectroutes)中的 `ignoreRedirectRoutes` 配置说明。 + ## 路由配置 启用路径重定向后,需要在路由配置中添加 `:lang` 动态参数。 From 3162b6824bdbab089a5f15cfc0f0d867fd665788 Mon Sep 17 00:00:00 2001 From: caohuilin Date: Mon, 1 Dec 2025 11:26:39 +0800 Subject: [PATCH 2/3] docs: update info block --- .../en/guides/advanced-features/international/api.mdx | 5 ++++- .../advanced-features/international/best-practices.mdx | 1 + .../advanced-features/international/quick-start.mdx | 9 +++++---- .../advanced-features/international/best-practices.mdx | 1 + .../advanced-features/international/configuration.mdx | 5 +++++ .../advanced-features/international/locale-detection.mdx | 8 ++++++++ .../advanced-features/international/quick-start.mdx | 2 ++ .../advanced-features/international/resource-loading.mdx | 1 + .../guides/advanced-features/international/routing.mdx | 3 ++- 9 files changed, 29 insertions(+), 6 deletions(-) diff --git a/packages/document/docs/en/guides/advanced-features/international/api.mdx b/packages/document/docs/en/guides/advanced-features/international/api.mdx index 7b3bb81825df..973efaed1fa1 100644 --- a/packages/document/docs/en/guides/advanced-features/international/api.mdx +++ b/packages/document/docs/en/guides/advanced-features/international/api.mdx @@ -86,6 +86,7 @@ await changeLanguage('zh'); :::info `changeLanguage` is an async function that returns a Promise. + ::: ### Language Support Check @@ -134,7 +135,8 @@ function MyComponent() { - If i18n instance is initialized - If any resources for the current language are currently loading (SDK backend only) - If all required namespaces for the current language are loaded in the store - ::: + +::: ## I18nLink Component @@ -301,4 +303,5 @@ type Resources = { :::info The namespace value can be a string (for simple key-value pairs) or an object (for nested translation structures). + ::: diff --git a/packages/document/docs/en/guides/advanced-features/international/best-practices.mdx b/packages/document/docs/en/guides/advanced-features/international/best-practices.mdx index cf3a36d91697..947676b308a0 100644 --- a/packages/document/docs/en/guides/advanced-features/international/best-practices.mdx +++ b/packages/document/docs/en/guides/advanced-features/international/best-practices.mdx @@ -91,6 +91,7 @@ function MyComponent() { :::tip `isResourcesReady` is more accurate for SDK backend scenarios as it checks if all required resources are actually loaded, not just if the instance is initialized. + ::: ## Type Safety diff --git a/packages/document/docs/en/guides/advanced-features/international/quick-start.mdx b/packages/document/docs/en/guides/advanced-features/international/quick-start.mdx index 77e859769d9a..9f868e089a8d 100644 --- a/packages/document/docs/en/guides/advanced-features/international/quick-start.mdx +++ b/packages/document/docs/en/guides/advanced-features/international/quick-start.mdx @@ -16,11 +16,12 @@ pnpm add @modern-js/plugin-i18n i18next react-i18next :::info `i18next` and `react-i18next` are peer dependencies and need to be installed manually. + ::: ## Basic Configuration -### 1. Configure Plugin in `modern.config.ts` +### Configure Plugin in `modern.config.ts` ```ts import { appTools, defineConfig } from '@modern-js/app-tools'; @@ -51,9 +52,10 @@ export default defineConfig({ :::info `server.publicDir` is a required configuration used to specify the actual location of resource files. Even when using the default `loadPath`, this configuration is still required. + ::: -### 2. Create Language Resource Files +### Create Language Resource Files Create a `locales` folder in the project root and organize resource files by language: @@ -85,7 +87,7 @@ locales/ } ``` -### 3. Use in Components +### Use in Components ```tsx import { useModernI18n } from '@modern-js/plugin-i18n/runtime'; @@ -122,4 +124,3 @@ export default App; - Learn detailed [Configuration](./configuration) instructions - Learn about multiple [Locale Detection](./locale-detection) methods - Check [Resource Loading](./resource-loading) configuration options - diff --git a/packages/document/docs/zh/guides/advanced-features/international/best-practices.mdx b/packages/document/docs/zh/guides/advanced-features/international/best-practices.mdx index a67969f241ee..a6f3c06b7188 100644 --- a/packages/document/docs/zh/guides/advanced-features/international/best-practices.mdx +++ b/packages/document/docs/zh/guides/advanced-features/international/best-practices.mdx @@ -91,6 +91,7 @@ function MyComponent() { :::tip 对于 SDK 后端场景,`isResourcesReady` 更准确,因为它会检查所有必需的资源是否实际已加载,而不仅仅是检查实例是否已初始化。 + ::: ## 类型安全 diff --git a/packages/document/docs/zh/guides/advanced-features/international/configuration.mdx b/packages/document/docs/zh/guides/advanced-features/international/configuration.mdx index e81cd670e7df..50f0ced9d36d 100644 --- a/packages/document/docs/zh/guides/advanced-features/international/configuration.mdx +++ b/packages/document/docs/zh/guides/advanced-features/international/configuration.mdx @@ -8,6 +8,7 @@ title: 配置说明 :::warning 函数类型的配置(如 SDK 加载函数)只能在运行时配置(`modern.runtime.ts`)中设置,不能在 CLI 配置中设置。这是因为 CLI 配置在构建时执行,无法序列化函数。 + ::: ## CLI 配置(modern.config.ts) @@ -37,6 +38,7 @@ export default defineConfig({ :::warning 如果启用了 `localePathRedirect`,`detection` 配置必须放在 CLI 配置(`modern.config.ts`)中,因为服务端插件需要根据此配置来获取语言信息并进行路径重定向。 + ::: ```ts @@ -105,6 +107,7 @@ i18nPlugin({ 1. **如果配置了 `loadPath` 或 `addPath`**:由于你已经指定了资源路径,backend 会自动启用(`enabled: true`),无需检测 locales 目录。 2. **如果没有配置 backend**:插件会自动检测以下位置是否存在 `locales` 目录: + - 项目根目录:`{项目根目录}/locales` - Config public 目录:`{项目根目录}/config/public/locales` - 通过 `server.publicDir` 配置的目录:`{项目根目录}/{publicDir}/locales` @@ -114,6 +117,7 @@ i18nPlugin({ 3. **如果显式设置 `enabled: false`**:不会进行自动检测,backend 保持禁用状态。 这种自动检测机制可以在 locales 目录不存在时减少不必要的 backend 注册,提升性能。 + ::: ```ts @@ -271,6 +275,7 @@ i18nPlugin({ :::warning 当仅使用 SDK 后端时,必须在 `modern.runtime.ts` 中提供实际的 SDK 函数,否则将回退到 HTTP/FS 后端。 + ::: ### 多入口配置 diff --git a/packages/document/docs/zh/guides/advanced-features/international/locale-detection.mdx b/packages/document/docs/zh/guides/advanced-features/international/locale-detection.mdx index 36a340f644a2..1c8cba22f0db 100644 --- a/packages/document/docs/zh/guides/advanced-features/international/locale-detection.mdx +++ b/packages/document/docs/zh/guides/advanced-features/international/locale-detection.mdx @@ -70,7 +70,9 @@ export default function About() { ``` :::info + 如果使用自定义路由(`modern.routes.ts`),需要在路由配置中添加 `:lang` 动态参数。约定式路由会自动根据文件结构生成对应的路由。 + ::: ### 2. i18next 语言检测器 @@ -142,7 +144,9 @@ i18nPlugin({ 5. **回退语言**:使用 `fallbackLanguage` 作为最终回退 :::info + SSR 数据检测优先级最高,这是为了确保客户端能够使用服务端渲染时检测到的语言,避免客户端重新检测导致的语言闪烁问题。 + ::: **示例**: @@ -198,11 +202,15 @@ order: [ ``` :::warning + `path` 检测需要 `localePathRedirect` 为 `true`,`localStorage`、`sessionStorage`、`navigator`、`htmlTag` 仅在浏览器环境可用。 + ::: :::info + 注意:`order` 配置只影响 i18next 检测器内部的优先级。实际的检测优先级还包括 SSR 数据和路径检测,它们有更高的优先级(见上面的"检测优先级"章节)。 + ::: ### caches(缓存方式) diff --git a/packages/document/docs/zh/guides/advanced-features/international/quick-start.mdx b/packages/document/docs/zh/guides/advanced-features/international/quick-start.mdx index bdc34e51d800..d5b2178e5a4f 100644 --- a/packages/document/docs/zh/guides/advanced-features/international/quick-start.mdx +++ b/packages/document/docs/zh/guides/advanced-features/international/quick-start.mdx @@ -16,6 +16,7 @@ pnpm add @modern-js/plugin-i18n i18next react-i18next :::info `i18next` 和 `react-i18next` 是 peer dependencies,需要手动安装。 + ::: ## 基础配置 @@ -51,6 +52,7 @@ export default defineConfig({ :::info `server.publicDir` 是必需配置,用于指定资源文件的实际存放位置。即使使用默认的 `loadPath` 路径,也需要配置此项。 + ::: ### 创建语言资源文件 diff --git a/packages/document/docs/zh/guides/advanced-features/international/resource-loading.mdx b/packages/document/docs/zh/guides/advanced-features/international/resource-loading.mdx index be88d6148ddb..1f273f56e7a3 100644 --- a/packages/document/docs/zh/guides/advanced-features/international/resource-loading.mdx +++ b/packages/document/docs/zh/guides/advanced-features/international/resource-loading.mdx @@ -125,6 +125,7 @@ i18nPlugin({ :::warning `loadPath` 配置会同时用于 HTTP 后端(前端)和文件系统后端(服务端)。如果配置的是以 `/` 开头的绝对路径(如 `/locales/{{lng}}/{{ns}}.json`),文件系统后端会自动将其转换为相对路径(`./locales/{{lng}}/{{ns}}.json`)。因此,建议在配置中使用绝对路径,这样可以同时满足前后端的需求。 + ::: ## SDK 后端 diff --git a/packages/document/docs/zh/guides/advanced-features/international/routing.mdx b/packages/document/docs/zh/guides/advanced-features/international/routing.mdx index e1df70799c7c..283db3d5b780 100644 --- a/packages/document/docs/zh/guides/advanced-features/international/routing.mdx +++ b/packages/document/docs/zh/guides/advanced-features/international/routing.mdx @@ -37,7 +37,7 @@ i18nPlugin({ // 字符串数组:支持精确匹配和前缀匹配 ignoreRedirectRoutes: ['/api', '/admin', '/static'], // 或使用函数进行更灵活的判断 - ignoreRedirectRoutes: (pathname) => { + ignoreRedirectRoutes: pathname => { return pathname.startsWith('/api') || pathname.startsWith('/admin'); }, }, @@ -139,6 +139,7 @@ function App() { :::info 约定式路由会自动根据文件结构生成对应的路由,推荐使用约定式路由。只有在需要特殊路由控制时才使用自定义路由。 + ::: ## I18nLink 组件 From 7a2f44287681afdcb30666feb08c8c23660a7513 Mon Sep 17 00:00:00 2001 From: caohuilin Date: Mon, 1 Dec 2025 11:29:34 +0800 Subject: [PATCH 3/3] fix: lint --- .../advanced-features/international/resource-loading.mdx | 1 + .../en/guides/advanced-features/international/routing.mdx | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/document/docs/en/guides/advanced-features/international/resource-loading.mdx b/packages/document/docs/en/guides/advanced-features/international/resource-loading.mdx index 9561b302b374..2126b230433f 100644 --- a/packages/document/docs/en/guides/advanced-features/international/resource-loading.mdx +++ b/packages/document/docs/en/guides/advanced-features/international/resource-loading.mdx @@ -125,6 +125,7 @@ i18nPlugin({ :::warning The `loadPath` configuration is used for both HTTP backend (frontend) and file system backend (server-side). If configured as an absolute path starting with `/` (e.g., `/locales/{{lng}}/{{ns}}.json`), the file system backend will automatically convert it to a relative path (`./locales/{{lng}}/{{ns}}.json`). Therefore, it's recommended to use absolute paths in the configuration, which can meet both frontend and backend requirements. + ::: ## SDK Backend diff --git a/packages/document/docs/en/guides/advanced-features/international/routing.mdx b/packages/document/docs/en/guides/advanced-features/international/routing.mdx index e8fbe1d0f287..7ec92863f147 100644 --- a/packages/document/docs/en/guides/advanced-features/international/routing.mdx +++ b/packages/document/docs/en/guides/advanced-features/international/routing.mdx @@ -37,7 +37,7 @@ i18nPlugin({ // String array: supports exact match and prefix match ignoreRedirectRoutes: ['/api', '/admin', '/static'], // Or use function for more flexible judgment - ignoreRedirectRoutes: (pathname) => { + ignoreRedirectRoutes: pathname => { return pathname.startsWith('/api') || pathname.startsWith('/admin'); }, }, @@ -139,6 +139,7 @@ function App() { :::info Convention-based routing will automatically generate corresponding routes based on the file structure. It's recommended to use convention-based routing. Only use custom routing when special route control is needed. + ::: ## I18nLink Component @@ -209,4 +210,3 @@ interface I18nLinkProps { Contact ``` -