@wxt-dev/i18n
@wxt-dev/i18n 是对 browser.i18n API 的简单、类型安全的封装。相比标准 API,它提供了以下优势:
- 简洁的消息文件格式
- 复数形式支持
- 与 I18n Ally VS Code 扩展 集成
相比其他非浏览器扩展专用的 I18n 包,它还具有以下优势:
- 不会将本地化文件打包到每个入口点中
- 无需异步获取本地化文件
- 可以在 manifest 和 CSS 文件中进行本地化
不过,它有一个主要缺点:
- 与
browser.i18nAPI 一样,要更改语言,用户必须更改浏览器的语言
IMPORTANT
你不必使用 wxt 也能使用这个包——它可以在任何打包工具配置中工作。详情请参阅不使用 WXT 安装。
安装
使用 WXT
通过包管理器安装
@wxt-dev/i18n:shpnpm i @wxt-dev/i18n在
wxt.config.ts文件中添加 WXT 模块并设置默认语言:tsexport default defineConfig({ modules: ['@wxt-dev/i18n/module'], manifest: { default_locale: 'en', }, });在
<srcDir>/locales/<default_locale>.yml创建本地化文件,或将现有的本地化文件移动到该位置。yml# <srcDir>/locales/en.yml helloWorld: Hello world!@wxt-dev/i18n支持标准消息格式,因此如果你已经在<rootDir>/public/_locale/<lang>/messages.json有本地化文件,无需将它们转换为 YAML 或重构——只需将它们移动到<srcDir>/locales/<lang>.json,即可直接使用!要获取翻译,使用自动导入的
i18n对象或手动导入:tsimport { i18n } from '#i18n'; i18n.t('helloWorld'); // "Hello world!"
大功告成!使用 WXT,你可以开箱即用地获得类型安全。
不使用 WXT
通过包管理器安装
@wxt-dev/i18n:shpnpm i @wxt-dev/i18n在
_locales/<lang>/messages.json创建消息文件,或将现有的翻译文件移动到该位置:json{ "helloWorld": { "message": "Hello world!" } }创建
i18n对象,导出它,然后在任何地方使用!tsimport { createI18n } from '@wxt-dev/i18n'; export const i18n = createI18n(); i18n.t('helloWorld'); // "Hello world!";
配置
可以通过 i18n 配置来配置该模块:
export default defineConfig({
modules: ['@wxt-dev/i18n'],
i18n: {
// ...
},
});选项在编辑器中有 JSDocs 可用,你也可以在源码中查看:I18nOptions。
消息文件格式
DANGER
只有将 @wxt-dev/i18n 集成到构建流程后,你才能使用本页讨论的文件格式。如果没有集成到构建流程中,你必须像普通浏览器扩展一样使用 _locales 目录中的 JSON 文件。
文件扩展名
你可以使用以下几种文件类型来定义消息:
.yml.yaml.json.jsonc.json5.toml
嵌套键
你可以将翻译放在顶层或嵌套分组:
ok: OK
cancel: Cancel
welcome:
title: Welcome to XYZ
dialogs:
confirmation:
title: 'Are you sure?'要访问嵌套键,使用 .:
i18n.t('ok'); // "OK"
i18n.t('cancel'); // "Cancel"
i18n.t('welcome.title'); // "Welcome to XYZ"
i18n.t('dialogs.confirmation.title'); // "Are you sure?"替换
因为 @wxt-dev/i18n 基于 browser.i18n,你可以用相同的方式定义替换,使用 $1-$9:
hello: Hello $1!
order: Thanks for ordering your $1转义 $
要转义美元符号,在其前面加上另一个 $:
dollars: $$$1i18n.t('dollars', ['1.00']); // "$1.00"复数形式
WARNING
目前不支持像阿拉伯语这样对"少数"或"多数"有不同形式的语言的复数支持。如果你对此感兴趣,欢迎提交 PR!
要根据数量获取不同的翻译:
items:
1: 1 item
n: $1 items然后将数量作为第二个参数传递给 i18n.t:
i18n.t('items', 0); // "0 items"
i18n.t('items', 1); // "1 item"
i18n.t('items', 2); // "2 items"要为 0 个项目添加自定义翻译:
items:
0: No items
1: 1 item
n: $1 itemsi18n.t('items', 0); // "No items"
i18n.t('items', 1); // "1 item"
i18n.t('items', 2); // "2 items"如果你需要为 $1 传递自定义替换而不是数量,只需添加替换:
items:
0: No items
1: $1 item
n: $1 itemsi18n.t('items', 0, ['Zero']); // "No items"
i18n.t('items', 1, ['One']); // "One item"
i18n.t('items', 2, ['Multiple']); // "Multiple items"详细键
@wxt-dev/i18n 兼容 browser.i18n 使用的消息格式。
IMPORTANT
这意味着如果你正在迁移到 @wxt-dev/i18n 并且已经在使用详细格式,你不需要做任何更改!
当一个键满足以下条件时,它被视为"详细"的:
- 在顶层(未嵌套)
- 仅包含以下属性:
message、description和/或placeholder
{
"appName": {
"message": "GitHub - Better Line Counts",
"description": "The app's name, should not be translated"
},
"ok": "OK",
"deleteConfirmation": {
"title": "Delete XYZ?",
"message": "You cannot undo this action once taken."
}
}在这个例子中,只有 appName 被视为详细的。deleteConfirmation 不是详细的,因为它包含额外的属性 title。
i18n.t('appName'); // ✅ "GitHub - Better Line Counts"
i18n.t('appName.message'); // ❌
i18n.t('ok'); // ✅ "OK"
i18n.t('deleteConfirmation'); // ❌
i18n.t('deleteConfirmation.title'); // ✅ "Delete XYZ?"
i18n.t('deleteConfirmation.message'); // ✅ "You cannot undo this action once taken."如果这让你感到困惑,不用担心!有了类型安全,如果你用错了会得到类型错误。如果类型安全被禁用,你会在开发者工具控制台中收到运行时警告。
WARNING
不建议使用详细格式。目前还没有看到开箱即用支持这种格式的翻译服务和软件。尽可能使用简洁格式。
构建集成
要使用自定义消息文件格式,你需要使用 @wxt-dev/i18n/build 将自定义格式转换为浏览器期望的格式。
WXT
请参阅使用 WXT 安装。
简而言之,你只需要:
// wxt.config.ts
export default defineConfig({
modules: ['@wxt-dev/i18n/module'],
});每次运行 wxt prepare 或其他构建命令时,类型都会自动生成。
自定义
如果你没有使用 WXT,你需要自己预处理本地化文件。以下是一个生成 _locales/.../messages.json 和 wxt-i18n-structure.d.ts 文件的基本脚本:
// build-i18n.js
import {
parseMessagesFile,
generateChromeMessagesFile,
generateTypeFile,
} from '@wxt-dev/i18n/build';
// 读取你的本地化文件
const messages = {
en: await parseMessagesFile('path/locales/en.yml'),
de: await parseMessagesFile('path/locales/de.yml'),
// ...
};
// 为扩展生成 JSON 文件
await generateChromeMessagesFile('dist/_locales/en/messages.json', messages.en);
await generateChromeMessagesFile('dist/_locales/de/messages.json', messages.de);
// ...
// 根据你的 default_locale 生成类型文件
await generateTypeFile('wxt-i18n-structure.d.ts', messages.en);然后运行脚本:
node generate-i18n.js如果你的构建工具有开发模式,你还需要在更改本地化文件时重新运行该脚本。
类型安全
生成 wxt-i18n-structure.d.ts 后(参见自定义部分),你可以用它将生成的类型传递给 createI18n:
import type { WxtI18nStructure } from './wxt-i18n-structure';
export const i18n = createI18n<WxtI18nStructure>();就这样,你就拥有了类型安全!
编辑器支持
为了获得更好的开发体验,你可以为编辑器配置插件和扩展。
VS Code
I18n Ally 扩展 为 VS Code 添加了以下功能:
- 跳转到翻译定义
- 内联预览文本
- 悬停查看其他翻译
你需要配置该扩展,以便它知道你的本地化文件在哪里以及哪个函数表示获取翻译:
.vscode/i18n-ally-custom-framework.yml:
# 包含 VS Code 定义的语言 ID 的字符串数组
# 你可以在这里查看可用的语言 ID:https://code.visualstudio.com/docs/languages/identifiers
languageIds:
- typescript
- typescriptreact
# 查找 t("...")
usageMatchRegex:
- "[^\\w\\d]t\\(['\"`]({key})['\"`]"
# 禁用其他内置的 I18n Ally 框架
monopoly: true.vscode/settings.json:
{
"i18n-ally.localesPaths": ["src/locales"],
"i18n-ally.keystyle": "nested"
}Zed
截至撰写时(2024 年 8 月 18 日),Zed 尚无可用的 I18n 支持扩展。
Jetbrains IDE
安装 I18n Ally 插件。关于 Jetbrains 支持的文档有限,但你可能需要类似于 VS Code 的方式配置插件……不过不确定文件应该放在哪里。
如果你弄清楚了,欢迎提交 PR!