插件支持三种资源加载方式:HTTP 后端、文件系统后端(FS Backend)和 SDK 后端。同时,插件还支持链式后端,可以组合使用多个后端。
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文件系统后端直接从文件系统读取资源文件,适用于服务端渲染(SSR)场景。
在 SSR 场景下,插件会自动使用文件系统后端。资源文件需要放在项目目录中:
项目根目录/
└── locales/
├── en/
│ └── translation.json
└── zh/
└── translation.json文件系统后端的默认路径格式为相对路径:
./locales/{{lng}}/{{ns}}.json可以通过 loadPath 自定义路径:
i18nPlugin({
backend: {
enabled: true,
loadPath: '/locales/{{lng}}/{{ns}}.json', // 使用绝对路径(推荐)
},
});
loadPath 配置会同时用于 HTTP 后端(前端)和文件系统后端(服务端)。如果配置的是以 / 开头的绝对路径(如 /locales/{{lng}}/{{ns}}.json),文件系统后端会自动将其转换为相对路径(./locales/{{lng}}/{{ns}}.json)。因此,建议在配置中使用绝对路径,这样可以同时满足前后端的需求。
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 函数接收一个 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>;
}这在资源异步加载时特别有用,因为它确保当前语言的所有必需命名空间都已加载完成,然后再渲染依赖翻译的内容。
链式后端允许同时使用多个后端,实现资源的渐进式加载和更新。当同时配置 loadPath(或 FS 后端)和 sdk 时,插件会自动使用 i18next-chained-backend 来链式加载资源。
链式后端的工作流程:
这样可以确保用户快速看到页面内容,同时后台加载最新的翻译资源。
步骤 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 选项控制链式后端的行为:
'none'(默认,仅当未配置链式后端时):如果第一个后端返回了资源,则停止,不再尝试下一个后端'refresh':尝试从下一个后端刷新缓存并更新缓存'refreshAndUpdateStore'(链式后端的默认值):尝试从下一个后端刷新缓存,更新缓存并同时更新 i18next 资源存储。这允许先显示 FS/HTTP 资源,然后 SDK 资源会异步更新它们。配置示例:
i18nPlugin({
backend: {
enabled: true,
loadPath: '/locales/{{lng}}/{{ns}}.json',
sdk: true,
cacheHitMode: 'refreshAndUpdateStore', // 显式指定(默认值)
},
});链式后端特别适用于以下场景:
// 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/... 加载最新翻译