配置说明

插件的配置分为两部分:CLI 配置(modern.config.ts)和运行时配置(modern.runtime.ts)。两者需要结合使用,CLI 配置用于插件的基础设置,运行时配置用于 i18next 的初始化选项。

Warning

函数类型的配置(如 SDK 加载函数)只能在运行时配置(modern.runtime.ts)中设置,不能在 CLI 配置中设置。这是因为 CLI 配置在构建时执行,无法序列化函数。

CLI 配置(modern.config.ts)

modern.config.ts 中配置插件选项:

import { i18nPlugin } from '@modern-js/plugin-i18n';

export default defineConfig({
  plugins: [
    i18nPlugin({
      localeDetection: {
        // 语言检测配置
      },
      backend: {
        // 后端资源加载配置
      },
    }),
  ],
});

localeDetection 配置

localeDetection 用于配置语言检测相关选项:

Warning

如果启用了 localePathRedirectdetection 配置必须放在 CLI 配置(modern.config.ts)中,因为服务端插件需要根据此配置来获取语言信息并进行路径重定向。

interface BaseLocaleDetectionOptions {
  /** 是否启用路径重定向,启用后会在 URL 中添加语言前缀 */
  localePathRedirect?: boolean;

  /** 是否启用 i18next 语言检测器 */
  i18nextDetector?: boolean;

  /** 支持的语言列表 */
  languages?: string[];

  /** 默认回退语言 */
  fallbackLanguage?: string;

  /** 自定义检测配置 */
  detection?: LanguageDetectorOptions;

  /** 忽略自动重定向的路由列表或函数
   *
   * 可以是一个字符串数组(路径模式),或一个函数来判断是否应该忽略重定向。
   * 支持精确匹配和前缀匹配(如 '/api' 会匹配 '/api' 和 '/api/users')。
   *
   * @example
   * // 字符串数组
   * ignoreRedirectRoutes: ['/api', '/admin']
   *
   * // 函数
   * ignoreRedirectRoutes: (pathname) => pathname.startsWith('/api')
   */
  ignoreRedirectRoutes?: string[] | ((pathname: string) => boolean);
}

interface LocaleDetectionOptions extends BaseLocaleDetectionOptions {
  /** 按入口配置语言检测(多入口场景) */
  localeDetectionByEntry?: Record<string, BaseLocaleDetectionOptions>;
}

示例

i18nPlugin({
  localeDetection: {
    localePathRedirect: true,
    i18nextDetector: true,
    languages: ['zh', 'en', 'ja'],
    fallbackLanguage: 'en',
    detection: {
      order: ['path', 'cookie', 'header'],
      lookupCookie: 'i18next',
      caches: ['cookie'],
    },
  },
});

backend 配置

backend 用于配置资源加载方式:

Info

自动检测:插件会在以下场景自动检测并启用 backend:

  1. 如果配置了 loadPathaddPath:由于你已经指定了资源路径,backend 会自动启用(enabled: true),无需检测 locales 目录。

  2. 如果没有配置 backend:插件会自动检测以下位置是否存在 locales 目录:

    • 项目根目录:{项目根目录}/locales
    • Config public 目录:{项目根目录}/config/public/locales
    • 通过 server.publicDir 配置的目录:{项目根目录}/{publicDir}/locales

    如果目录存在且包含 JSON 文件,backend 会自动启用。

  3. 如果显式设置 enabled: false:不会进行自动检测,backend 保持禁用状态。

这种自动检测机制可以在 locales 目录不存在时减少不必要的 backend 注册,提升性能。

interface BaseBackendOptions {
  /** 是否启用后端资源加载 */
  enabled?: boolean;

  /** 资源文件加载路径(HTTP 后端) */
  loadPath?: string;

  /** 缺失翻译保存路径(可选) */
  addPath?: string;

  /** 链式后端的缓存命中模式(仅在同时配置 `loadPath` 和 `sdk` 时生效)
   *
   * - `'none'`(默认):如果第一个后端返回了资源,则停止,不再尝试下一个后端
   * - `'refresh'`:尝试从下一个后端刷新缓存并更新缓存
   * - `'refreshAndUpdateStore'`:尝试从下一个后端刷新缓存,更新缓存并同时更新 i18next 资源存储。
   *   这允许先显示 FS/HTTP 资源,然后 SDK 资源会异步更新它们。
   *
   * @default 'refreshAndUpdateStore' 当同时配置 loadPath 和 sdk 时
   */
  cacheHitMode?: 'none' | 'refresh' | 'refreshAndUpdateStore';

  /** SDK 加载函数(自定义后端)
   *
   * 注意:在 CLI 配置中只能设置为 `true` 或字符串标识符来启用 SDK 模式。
   * 实际的 SDK 函数必须在运行时配置(`modern.runtime.ts`)中通过 `initOptions.backend.sdk` 提供。
   *
   * 当同时配置 `loadPath`(或 FS 后端)和 `sdk` 时,插件会自动使用 `i18next-chained-backend`
   * 来链式加载多个后端。加载顺序为:
   * 1. HTTP/FS 后端(主要)- 先从 `loadPath` 或文件系统加载,用于快速初始显示
   * 2. SDK 后端(更新)- 从 SDK 函数加载,用于更新/刷新翻译
   *
   * 使用 `cacheHitMode: 'refreshAndUpdateStore'`(默认)时,FS/HTTP 资源会立即显示,
   * 然后 SDK 资源会异步加载以更新翻译。
   */
  sdk?: I18nSdkLoader | boolean | string;
}

interface BackendOptions extends BaseBackendOptions {
  /** 按入口配置后端(多入口场景) */
  backendOptionsByEntry?: Record<string, BaseBackendOptions>;
}

示例

1. 仅使用 HTTP/FS 后端

你可以显式启用 backend:

i18nPlugin({
  backend: {
    enabled: true,
    loadPath: '/locales/{{lng}}/{{ns}}.json',
  },
});

或者只需配置 loadPathaddPath,backend 会自动启用:

i18nPlugin({
  backend: {
    // enabled 会自动设置为 true
    loadPath: '/locales/{{lng}}/{{ns}}.json',
  },
});

无配置时的自动检测

如果你完全不配置 backend,插件会自动检测 locales 目录:

i18nPlugin({
  // 没有 backend 配置 - 插件会自动检测 locales 目录
  localeDetection: {
    languages: ['zh', 'en'],
    fallbackLanguage: 'en',
  },
});

如果 locales 目录存在且包含 JSON 文件,backend 会自动启用,使用默认的 loadPath: '/locales/{{lng}}/{{ns}}.json'

2. 链式后端(推荐):同时使用 HTTP/FS 后端和 SDK 后端

backend.enabled = true 且配置了 sdk 时,如果未显式配置 loadPath,将自动使用默认的 loadPath 并启用链式后端:

i18nPlugin({
  backend: {
    enabled: true,
    // 当未配置 loadPath 时,将自动使用默认的 '/locales/{{lng}}/{{ns}}.json'
    sdk: true, // SDK 后端
    // cacheHitMode: 'refreshAndUpdateStore', // 默认值,可省略
  },
});

你也可以显式配置 loadPath

i18nPlugin({
  backend: {
    enabled: true,
    loadPath: '/locales/{{lng}}/{{ns}}.json', // HTTP/FS 后端
    sdk: true, // SDK 后端
  },
});

modern.runtime.ts 中提供 SDK 函数:

export default defineRuntimeConfig({
  i18n: {
    initOptions: {
      backend: {
        sdk: async options => {
          // SDK 实现
          if (options.lng && options.ns) {
            return await mySdk.getResource(options.lng, options.ns);
          }
        },
      },
    },
  },
});

使用链式后端时,系统会:

  1. 首先从 /locales/{{lng}}/{{ns}}.json 加载资源并立即显示(快速显示基础翻译)
  2. 然后异步从 SDK 加载资源并更新 i18next store(更新/补充翻译)

这样可以确保用户快速看到页面内容,同时后台加载最新的翻译资源。

3. 仅使用 SDK 后端

如果你需要禁用 HTTP/FS 后端并仅使用 SDK 后端,可以显式设置 loadPath: ''

i18nPlugin({
  backend: {
    enabled: true,
    loadPath: '', // 显式禁用 HTTP/FS 后端
    sdk: true, // 仅使用 SDK 后端
  },
});
Warning

当仅使用 SDK 后端时,必须在 modern.runtime.ts 中提供实际的 SDK 函数,否则将回退到 HTTP/FS 后端。

多入口配置

如果项目有多个入口,可以为每个入口单独配置:

i18nPlugin({
  localeDetection: {
    localePathRedirect: true,
    languages: ['zh', 'en'],
    fallbackLanguage: 'en',
    // 为特定入口覆盖配置
    localeDetectionByEntry: {
      admin: {
        localePathRedirect: false, // admin 入口不使用路径重定向
      },
    },
  },
  backend: {
    enabled: true,
    // 为特定入口覆盖配置
    backendOptionsByEntry: {
      admin: {
        loadPath: '/admin/locales/{{lng}}/{{ns}}.json',
      },
    },
  },
});

运行时配置(modern.runtime.ts)

src/modern.runtime.ts 中可以配置运行时选项:

import { defineRuntimeConfig } from '@modern-js/runtime';
import i18next from 'i18next';

// 建议创建一个新的 i18next 实例,避免使用全局默认实例
const i18nInstance = i18next.createInstance();

export default defineRuntimeConfig({
  i18n: {
    // 使用自定义 i18next 实例(可选)
    i18nInstance: i18nInstance,

    // i18next 初始化选项
    initOptions: {
      fallbackLng: 'en',
      supportedLngs: ['zh', 'en'],
      // 其他 i18next 配置选项
    },
  },
});

i18nInstance 配置

如果需要使用自定义的 i18n 实例,可以在运行时配置中提供:

import { defineRuntimeConfig } from '@modern-js/runtime';
import i18next from 'i18next';

// 创建自定义实例
const customI18n = i18next.createInstance({
  // 自定义配置
});

export default defineRuntimeConfig({
  i18n: {
    i18nInstance: customI18n,
  },
});

initOptions 配置

initOptions 会传递给 i18next 的 init 方法,支持所有 i18next 配置选项:

Info

如果启用了 localePathRedirectdetection 配置应该在 CLI 配置中设置,而不是在 initOptions 中。这是因为服务端插件需要读取 CLI 配置中的 detection 选项来进行语言检测和路径重定向。

export default defineRuntimeConfig({
  i18n: {
    initOptions: {
      // 语言相关
      lng: 'en',
      fallbackLng: 'en',
      supportedLngs: ['zh', 'en'],

      // 命名空间相关
      ns: ['translation', 'common'],
      defaultNS: 'translation',

      // React 相关
      react: {
        useSuspense: false,
      },

      // 其他 i18next 选项
      interpolation: {
        escapeValue: false,
      },
    },
  },
});

SDK 后端配置

如果使用 SDK 后端,需要在运行时配置中提供实际的 SDK 函数:

Info

函数类型的配置只能在运行时配置中设置。在 CLI 配置中,sdk 只能设置为 true 或字符串标识符来启用 SDK 模式,实际的函数实现必须在 modern.runtime.ts 中提供。

modern.config.ts 中启用 SDK 模式

i18nPlugin({
  backend: {
    enabled: true,
    sdk: true, // 启用 SDK 模式
  },
});

modern.runtime.ts 中提供 SDK 函数

import { defineRuntimeConfig } from '@modern-js/runtime';
import type { I18nSdkLoader } from '@modern-js/plugin-i18n/runtime';

const mySdkLoader: I18nSdkLoader = async options => {
  if (options.all) {
    // 加载所有资源
    return await fetchAllResources();
  }

  if (options.lng && options.ns) {
    // 加载单个资源
    const response = await fetch(`/api/i18n/${options.lng}/${options.ns}`);
    return response.json();
  }

  // 处理其他情况
  return {};
};

export default defineRuntimeConfig({
  i18n: {
    initOptions: {
      backend: {
        sdk: mySdkLoader,
      },
    },
  },
});