logo
  • 指南
  • 配置
  • 插件
  • API
  • 示例
  • 社区
  • Modern.js 2.x 文档
  • 简体中文
    • 简体中文
    • English
    • 开始
      介绍
      快速上手
      版本升级
      名词解释
      技术栈
      核心概念
      页面入口
      构建工具
      Web 服务器
      基础功能
      路由
      路由基础
      配置式路由
      数据管理
      数据获取
      数据写入
      数据缓存
      渲染
      服务端渲染(SSR)
      服务端流式渲染(Streaming SSR)
      渲染缓存
      静态站点生成(SSG)
      渲染预处理 (Render Preprocessing)
      样式开发
      引入 CSS
      使用 CSS Modules
      使用 CSS-in-JS
      使用 Tailwind CSS
      HTML 模板
      引用静态资源
      引用 JSON 文件
      引用 SVG 资源
      引用 Wasm 资源
      调试
      数据模拟(Mock)
      网络代理
      使用 Rsdoctor
      使用 Storybook
      测试
      Playwright
      Vitest
      Jest
      Cypress
      路径别名
      环境变量
      构建产物目录
      部署应用
      进阶功能
      使用 Rspack
      使用 BFF
      基础用法
      运行时框架
      扩展 BFF Server
      扩展一体化调用 SDK
      文件上传
      跨项目调用
      优化页面性能
      代码分割
      静态资源内联
      产物体积优化
      React Compiler
      提升构建性能
      浏览器兼容性
      配置底层工具
      源码构建模式
      服务端监控
      Monitors
      日志事件
      指标事件
      国际化
      基础概念
      快速开始
      配置说明
      语言检测
      资源加载
      路由集成
      API 参考
      高级用法
      最佳实践
      自定义 Web Server
      专题详解
      模块联邦
      简介
      开始使用
      应用级别模块
      服务端渲染
      部署
      集成国际化能力
      常见问题
      依赖安装问题
      命令行问题
      构建相关问题
      热更新问题
      已下线功能
      📝 编辑此页面
      上一页语言检测下一页路由集成

      #资源加载

      插件支持三种资源加载方式:HTTP 后端、文件系统后端(FS Backend)和 SDK 后端。同时,插件还支持链式后端,可以组合使用多个后端。

      #HTTP 后端

      HTTP 后端通过 HTTP 请求加载资源文件,适用于客户端渲染(CSR)场景。

      #配置方式

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

      #资源文件结构

      资源文件需要放在 config/public 目录或通过 server.publicDir 配置的目录中:

      config/public/
      └── locales/
          ├── en/
          │   └── translation.json
          └── zh/
              └── translation.json

      或者通过 server.publicDir 配置自定义目录:

      export default defineConfig({
        server: {
          publicDir: './locales', // 指定资源文件目录
        },
        plugins: [
          i18nPlugin({
            backend: {
              enabled: true,
              loadPath: '/locales/{{lng}}/{{ns}}.json',
            },
          }),
        ],
      });

      资源文件格式:

      {
        "key1": "value1",
        "key2": "value2",
        "nested": {
          "key": "value"
        }
      }

      #路径变量

      loadPath 支持以下变量:

      • {{lng}}:语言代码(如 en、zh)
      • {{ns}}:命名空间(如 translation、common)

      示例:

      // 默认路径格式
      loadPath: '/locales/{{lng}}/{{ns}}.json';
      // 实际加载路径:
      // /locales/en/translation.json
      // /locales/zh/translation.json
      
      // 自定义路径格式
      loadPath: '/i18n/{{lng}}/{{ns}}.json';
      // 实际加载路径:
      // /i18n/en/translation.json
      // /i18n/zh/translation.json

      #文件系统后端(FS Backend)

      文件系统后端直接从文件系统读取资源文件,适用于服务端渲染(SSR)场景。

      #配置方式

      在 SSR 场景下,插件会自动使用文件系统后端。资源文件需要放在项目目录中:

      项目根目录/
      └── locales/
          ├── en/
          │   └── translation.json
          └── zh/
              └── translation.json

      #资源文件路径

      文件系统后端的默认路径格式为相对路径:

      ./locales/{{lng}}/{{ns}}.json

      可以通过 loadPath 自定义路径:

      i18nPlugin({
        backend: {
          enabled: true,
          loadPath: '/locales/{{lng}}/{{ns}}.json', // 使用绝对路径(推荐)
        },
      });
      Warning

      loadPath 配置会同时用于 HTTP 后端(前端)和文件系统后端(服务端)。如果配置的是以 / 开头的绝对路径(如 /locales/{{lng}}/{{ns}}.json),文件系统后端会自动将其转换为相对路径(./locales/{{lng}}/{{ns}}.json)。因此,建议在配置中使用绝对路径,这样可以同时满足前后端的需求。

      #SDK 后端

      SDK 后端允许通过自定义函数加载资源,适用于需要从外部服务、数据库或其他自定义来源加载翻译资源的场景。

      #启用 SDK 模式

      步骤 1:在 modern.config.ts 中启用 SDK 模式

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

      步骤 2:在 modern.runtime.ts 中实现 SDK 函数

      import { defineRuntimeConfig } from '@modern-js/runtime';
      import type { I18nSdkLoader, Resources } from '@modern-js/plugin-i18n/runtime';
      
      const mySdkLoader: I18nSdkLoader = async options => {
        // 实现资源加载逻辑
        if (options.all) {
          // 加载所有资源
          return await loadAllResources();
        }
      
        if (options.lng && options.ns) {
          // 加载单个资源
          return await loadSingleResource(options.lng, options.ns);
        }
      
        return {};
      };
      
      export default defineRuntimeConfig({
        i18n: {
          initOptions: {
            backend: {
              sdk: mySdkLoader,
            },
          },
        },
      });

      #实现 SDK 加载函数

      SDK 函数接收一个 I18nSdkLoadOptions 参数,需要返回 Resources 格式的数据:

      interface I18nSdkLoadOptions {
        /** 单个语言代码 */
        lng?: string;
        /** 单个命名空间 */
        ns?: string;
        /** 多个语言代码 */
        lngs?: string[];
        /** 多个命名空间 */
        nss?: string[];
        /** 加载所有资源 */
        all?: boolean;
      }
      
      type Resources = {
        [lng: string]: {
          [ns: string]: Record<string, string>;
        };
      };

      #批量加载示例

      SDK 后端支持多种加载模式:

      1. 加载单个资源:

      const sdkLoader: I18nSdkLoader = async options => {
        if (options.lng && options.ns) {
          const response = await fetch(`/api/i18n/${options.lng}/${options.ns}`);
          const data = await response.json();
          return {
            [options.lng]: {
              [options.ns]: data,
            },
          };
        }
        return {};
      };

      2. 批量加载多个语言:

      const sdkLoader: I18nSdkLoader = async options => {
        if (options.lngs && options.ns) {
          const resources: Resources = {};
          for (const lng of options.lngs) {
            const response = await fetch(`/api/i18n/${lng}/${options.ns}`);
            resources[lng] = {
              [options.ns]: await response.json(),
            };
          }
          return resources;
        }
        return {};
      };

      3. 批量加载多个命名空间:

      const sdkLoader: I18nSdkLoader = async options => {
        if (options.lng && options.nss) {
          const resources: Resources = {
            [options.lng]: {},
          };
          for (const ns of options.nss) {
            const response = await fetch(`/api/i18n/${options.lng}/${ns}`);
            resources[options.lng][ns] = await response.json();
          }
          return resources;
        }
        return {};
      };

      4. 加载所有资源:

      const sdkLoader: I18nSdkLoader = async options => {
        if (options.all) {
          const response = await fetch('/api/i18n/all');
          return await response.json();
        }
        return {};
      };

      #检查资源加载状态

      使用 SDK 后端时,可以使用 isResourcesReady 检查资源是否已加载:

      import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
      
      function MyComponent() {
        const { isResourcesReady } = useModernI18n();
      
        if (!isResourcesReady) {
          return <div>正在加载翻译资源...</div>;
        }
      
        return <div>资源已准备好!</div>;
      }

      这在资源异步加载时特别有用,因为它确保当前语言的所有必需命名空间都已加载完成,然后再渲染依赖翻译的内容。

      #链式后端(Chained Backend)

      链式后端允许同时使用多个后端,实现资源的渐进式加载和更新。当同时配置 loadPath(或 FS 后端)和 sdk 时,插件会自动使用 i18next-chained-backend 来链式加载资源。

      #工作原理

      链式后端的工作流程:

      1. 初始加载:首先从 HTTP/FS 后端加载资源并立即显示(快速显示基础翻译)
      2. 异步更新:然后从 SDK 后端异步加载资源并更新 i18next store(更新/补充翻译)

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

      #配置方式

      步骤 1:在 modern.config.ts 中配置链式后端

      i18nPlugin({
        backend: {
          enabled: true,
          loadPath: '/locales/{{lng}}/{{ns}}.json', // HTTP/FS 后端
          sdk: true, // SDK 后端
          // cacheHitMode: 'refreshAndUpdateStore', // 默认值,可省略
        },
      });

      步骤 2:在 modern.runtime.ts 中实现 SDK 函数

      import { defineRuntimeConfig } from '@modern-js/runtime';
      
      export default defineRuntimeConfig({
        i18n: {
          initOptions: {
            backend: {
              sdk: async options => {
                // SDK 实现
                if (options.lng && options.ns) {
                  return await mySdk.getResource(options.lng, options.ns);
                }
              },
            },
          },
        },
      });

      #缓存命中模式(cacheHitMode)

      cacheHitMode 选项控制链式后端的行为:

      • 'none'(默认,仅当未配置链式后端时):如果第一个后端返回了资源,则停止,不再尝试下一个后端
      • 'refresh':尝试从下一个后端刷新缓存并更新缓存
      • 'refreshAndUpdateStore'(链式后端的默认值):尝试从下一个后端刷新缓存,更新缓存并同时更新 i18next 资源存储。这允许先显示 FS/HTTP 资源,然后 SDK 资源会异步更新它们。

      配置示例:

      i18nPlugin({
        backend: {
          enabled: true,
          loadPath: '/locales/{{lng}}/{{ns}}.json',
          sdk: true,
          cacheHitMode: 'refreshAndUpdateStore', // 显式指定(默认值)
        },
      });

      #使用场景

      链式后端特别适用于以下场景:

      1. 渐进式加载:先显示本地/静态资源,然后从远程服务加载最新翻译
      2. 离线支持:本地资源作为离线 fallback,SDK 资源提供在线更新
      3. 性能优化:快速显示基础翻译,后台加载完整翻译内容
      4. A/B 测试:本地资源作为默认值,SDK 提供动态翻译变体

      #完整示例

      // modern.config.ts
      i18nPlugin({
        backend: {
          enabled: true,
          loadPath: '/locales/{{lng}}/{{ns}}.json', // 本地资源
          sdk: true, // 远程 SDK 资源
          cacheHitMode: 'refreshAndUpdateStore',
        },
      });
      
      // modern.runtime.ts
      import { defineRuntimeConfig } from '@modern-js/runtime';
      
      export default defineRuntimeConfig({
        i18n: {
          initOptions: {
            backend: {
              sdk: async options => {
                if (options.lng && options.ns) {
                  // 从远程服务加载最新翻译
                  const response = await fetch(
                    `https://api.example.com/i18n/${options.lng}/${options.ns}`,
                  );
                  return {
                    [options.lng]: {
                      [options.ns]: await response.json(),
                    },
                  };
                }
                return {};
              },
            },
          },
        },
      });

      在这个示例中:

      • 页面加载时,首先从 /locales/{{lng}}/{{ns}}.json 加载资源并立即显示
      • 后台异步从 https://api.example.com/i18n/... 加载最新翻译
      • SDK 资源加载完成后,自动更新 i18next store,界面文案自动更新