界面文本与语言¶
用户阅读的所有文本都来自 packages/i18n(@openbot/i18n)中的语言目录。桌面端、共享 UI、Web 客户端和移动端使用相同的目录。英文是源语言。巴西葡萄牙语使用 pt 目录。德语(de)、西班牙语(es)、法语(fr)、意大利语(it)、日语(ja)、韩语(ko)、荷兰语(nl)、波兰语(pl)、巴西葡萄牙语(pt)、俄语(ru)、土耳其语(tr)和简体中文(zh)在桌面端、Web 客户端和移动端翻译所有键。缺失翻译时显示其英文源文本。
文本存放位置¶
packages/i18n/src/messages/<locale>/<area>.ts 存放一个区域的内容。区域是读者查找文本的界面:settings、chat、mobile/settings、error/team。
common保存没有自身上下文的短词:Cancel、Save、Retry。如果翻译可能随屏幕变化,请将键放在该屏幕的区域中,即使英文相同也是如此。format保存单位和列表词,createFormat会使用它们。language保存语言名称,例如听写语言。error/*和status/*保存由主进程、后端、主机或团队客户端发送的英文文本。参见 来自其他进程的文本。mobile/*保存仅移动应用显示的文本。移动端包包含common、format、language、error/*、status/*和mobile/*,不包含桌面端区域。
en/index.ts、en/mobile.ts、en/source.ts 和 en/shared.ts 仅用于拼接区域模块。不要在其中放入键。
添加键¶
- 将键添加到其区域的英文模块中:
export const messages = defineMessages("settings", {
"settings.language.title": "Language",
"settings.agents.count": { one: "{count} agent", other: "{count} agents" },
});
defineMessages 会在键不以模块前缀开头时使构建失败。带有 {count} 的消息具有复数形式。其他值是 {name} 占位符。
2. 渲染它。将键写成字面量,以便 bun run i18n:check 和搜索能找到它。
3. 如果可以,请向 de/、es/、fr/、it/、ja/、ko/、nl/、pl/、pt/、ru/、tr/ 和 zh/ 中的同一模块添加翻译。
如果无法添加,请省略该键:屏幕会显示英文,并且检查会将该键报告为未翻译。
按英文顺序放置每个已翻译的键。bun run i18n:check --fix 会为你执行此操作。
4. 保持按钮、标签页、菜单项或徽章的标签简短。按钮不会换行或缩小,因此过长的标签会撑开所在行;徽章或菜单项可能会截断标签。找到最短的自然词,而不是逐字翻译:例如,德语中用 "Wiederholen" 来表示 "Retry",而不是 "Erneut versuchen"。如果译文长度约超过英文的 1.5 倍,请寻找更短的词。
对于从值到文本的映射,请映射到键,而不是文本:
const STATUS_LABEL = {
running: "agent.status.running",
stopped: "agent.status.stopped",
} as const satisfies Record<AgentStatus, AppTextKey>;
使用文本¶
| 界面 | API |
|---|---|
桌面渲染器和 packages/ui |
const { t, format, errorMessage } = useText() from @openbot/ui/text |
| 移动端屏幕 | useText() from @/shared/lib/text |
React 之外的移动端代码(stores、Alert.alert 回调) |
currentText() from @/shared/lib/text |
| 主进程、原生 UI(对话框、菜单、窗口标题) | language.translate from LanguageService |
| 主进程、后端、团队客户端:错误和状态文本 | sourceText(key, params) from @openbot/i18n/source |
- 在
packages/ui中,调用useText()。不要添加t属性。文本上下文是共享 UI 从上下文读取的唯一应用值。在 Provider 之外,它会是英文,因此测试或 story 无需设置即可工作。 errorMessage(error, fallback)返回读者语言的userErrorMessage。请为其提供已翻译的回退文本:errorMessage(err, t("skill.saveFailed"))。- 渲染器的
I18nProvider在每个窗口中提供文本上下文。Web 客户端和 Storybook 使用带固定 locale 的StaticI18nProvider。
来自其他进程的文本¶
错误仅以消息形式通过 IPC 传递,Team API 会向每个已发布版本的客户端发送 { error: message }。因此,发送方编写英文,屏幕再将其翻译:
源键的英文文本必须与之前代码发送的文本逐字节相同。旧客户端以及比较错误文本的代码都依赖此一致性。要更改 error.* 或 status.* 键的英文文本,请将其视为一次线上变更(wire change):找到每个比较位置以及所有读取它的旧客户端。
屏幕会调用 errorMessage 或 sourceText(text)。这些函数会找到英文模板与文本匹配的键,并以读者的语言渲染该键。{count} 匹配数字,其他占位符匹配任意文本。{reason} 和 {detail} 会被再次翻译。没有模板匹配的文本(例如来自较旧主机或提供者的文本)会原样显示。远程客户端读取的是它自己的语言,而不是主机的语言。
当两个源模板可能匹配同一文本时,bun run i18n:check 会失败。
不要翻译¶
- 协议值、IPC 通道、标识符和已保存的值。在渲染时,将已保存的值映射到键;绝不要保存已翻译的文本。
- 分析事件名称和属性,以及日志行。
- Agent 提示词,以及应用发送给提供者的文本。
- 用户内容:消息、文件名、Agent 名称。
- 产品名称和品牌名称:OpenBot、提供者名称、ZIP、JSON。
- 只有畸形负载、编程错误或开发工具才能导致的错误,例如
*-inputs.ts文件中的结构检查失败。
数字、日期和大小¶
不要在没有 locale 的情况下调用 toLocaleString(),也不要使用固定的 "en-US":两者都会忽略用户选择的语言。请使用 useText() 中的 format:
| 方法 | 输出 |
|---|---|
format.number(value, options) |
1,234.5 |
format.compact(value) |
1.2K |
format.percent(ratio) |
25% for 0.25 |
format.currencyUsd(value) |
$1.50 |
format.date(value, options) |
Intl.DateTimeFormat 选项 |
format.list(items) |
a, b, and c |
format.fileSize(bytes) |
512 B, 12 KB, 3.4 MB |
移动应用运行在 Hermes 上,它可能不支持 Intl.PluralRules、Intl.ListFormat 或紧凑数字(尚未在设备上确认)。packages/i18n 为每一项都提供了回退方案。
检查¶
tools/ui-foundation/no-hardcoded-ui-text.grit会对src/renderer/src、packages/ui/src和apps/mobile/src中的字面文本报错:JSX 文本、字面量aria-label、title、placeholder、alt、label、description、accessibilityLabel或accessibilityHint、字面量 toast 或 alert,以及字面量errorMessage回退文本。测试和 stories 不在检查范围内。bun run i18n:check会在以下情况失败:键前缀错误、一个键出现在两个模块中、英文没有的翻译键、英文没有的占位符、复数形式与英文不一致、有歧义的源模板,以及代码中没有引用的英文键。它会报告未翻译的键,以及键顺序与英文不一致的已翻译模块。bun run i18n:check --fix会将这些键按英文顺序排列。每个键会连同其上方注释和空行一起移动,且不改变任何文本。bun run i18n:check --json会写入.openbot-build/i18n-report.json。- Storybook 的工具栏中有一个 Locale(语言)菜单。使用它可查看每种语言下的 story。
bun scripts/i18n-fit-e2e.ts --storybook=<url>会打开每种语言下的每个 story,打开其菜单,并查找被截断、超出方框或换行的控件文本。--locales=de,pl和--stories=<part of an id>可缩短运行时间。它使用一个浏览器;使用--workers=2时,所有语言的所有 stories 大约需要一小时。它会写入.openbot-build/i18n-fit/report.json,并为每个英文中不会出现的失败项生成一张截图。- 在开发应用打开的情况下,
bun scripts/i18n-e2e.ts --allow-mutations会让应用依次切换每种语言。当屏幕上的目录键或占位符出现时,或当英文能适配但控件文本无法适配时,它会失败。
添加语言¶
- 将 BCP 47 标签添加到
packages/contracts/src/app-language.ts中的APP_LANGUAGES。切勿重命名已发布的标签:否则已保存的偏好设置会被读回为未知语言。 - 将其添加到
packages/i18n/src/locale.ts中的TRANSLATED_LOCALES。 - 将
packages/i18n/src/messages/fr/复制到messages/<tag>/。将每个模块清空为{} as const satisfies PartialTranslation<typeof source>,然后尽可能翻译。 - 将新目录添加到
packages/i18n/src/app-catalogs.ts、source-catalogs.ts、format-catalogs.ts和mobile-catalogs.ts中的catalogs映射,添加到mobile-catalogs.native.ts中的switch,以及lazy-catalogs.ts中的loaders记录。公共 Web 构建使用lazy-catalogs.ts代替前三个文件。编译器会提示每个需要修改的位置。 - 将 CLDR 复数规则添加到
packages/i18n/src/plural.ts中的BUILT_IN_RULES。 - 将语言自身的名称及其
lang标签添加到packages/i18n/src/languages.ts。 - 运行
bun run typecheck:i18n和bun run i18n:check。在开发应用打开的情况下,运行bun scripts/i18n-e2e.ts --allow-mutations;它会写入.openbot-build/i18n-e2e/report.json。
当标签位于 APP_LANGUAGES 中时,两个“设置”屏幕都会显示新语言。
术语¶
在每种目录中保持这些术语一致。德语使用 du。西班牙语使用 tú,并避免地区特定措辞。法语使用 vous。日语使用 です・ます。韩语句子使用 해요체,按钮、标签页和标签使用简短名词。简体中文使用“你”,动作保持动词原形;在按钮或菜单项已标明动作时,不使用“请”。巴西葡萄牙语使用 você。俄语使用 вы。波兰语对动作使用非正式的 ty 命令式。意大利语对动作使用非正式的 tu 和命令式。荷兰语对动作使用非正式的 je 和命令式。pt-BR 和 pt-PT 系统设置都选择 pt 目录;数字和日期保留系统的区域惯例。所有 zh 系统设置都会选择简体中文目录,因此设置为 zh-TW 或 zh-HK 的电脑也会读取该目录。
| 英语 | 法语 | 日语 | 葡萄牙语(巴西) | 俄语 | 土耳其语 |
|---|---|---|---|---|---|
| agent | agent | エージェント | agente | агент | ajan |
| chat | discussion | チャット | chat | чат | sohbet |
| conversation | conversation | 会話 | conversa | диалог | konuşma |
| channel | canal | チャンネル | canal | канал | kanal |
| server | serveur | サーバー | servidor | сервер | sunucu |
| host | hôte | ホスト | computador anfitrião | хост | ana makine |
| skill | compétence | スキル | habilidade | навык | beceri |
| routine | routine | ルーティン | rotina | регулярная задача | rutin |
| workspace | espace de travail | ワークスペース | espaço de trabalho | рабочее пространство | çalışma alanı |
| provider | fournisseur | プロバイダー | provedor | провайдер | sağlayıcı |
| Settings | Réglages | 設定 | Configurações | Настройки | Ayarlar |
德语、西班牙语、波兰语和意大利语术语:
| 英语 | 德语 | 西班牙语 | 波兰语 | 意大利语 |
|---|---|---|---|---|
| agent | Agent | agente | agent | agente |
| chat | Chat | chat | czat | chat |
| conversation | Unterhaltung | conversación | rozmowa | conversazione |
| channel | Kanal | canal | kanał | canale |
| server | Server | servidor | serwer | server |
| host | Host | host | host | host |
| skill | Fähigkeit | habilidad | umiejętność | skill |
| routine | Routine | rutina | rutyna | routine |
| workspace | Arbeitsbereich | espacio de trabajo | obszar roboczy | workspace |
| provider | Anbieter | proveedor | dostawca | provider |
| Settings | Einstellungen | Ajustes | Ustawienia | Impostazioni |
| Computer Use | Computersteuerung | Uso del equipo | Sterowanie komputerem | Controllo del computer |
| Steer | Steuern | Orientar | Pokieruj | Indirizza |
韩语术语:
| 英语 | 韩语 |
|---|---|
| agent | 에이전트 |
| chat | 채팅 |
| conversation | 대화 |
| channel | 채널 |
| server | 서버 |
| host | 호스트 |
| skill | 스킬 |
| routine | 루틴 |
| workspace | 워크스페이스 |
| provider | 제공자 |
| Settings | 설정 |
| Computer Use | 컴퓨터 제어 |
| Steer | 방향 지시 |
荷兰语术语:
| 英语 | 荷兰语 |
|---|---|
| agent | agent |
| chat | chat |
| conversation | gesprek |
| channel | kanaal |
| server | server |
| host | host |
| skill | vaardigheid |
| routine | routine |
| workspace | werkruimte |
| provider | aanbieder |
| permissions | machtigingen |
| Settings | Instellingen |
| Computer Use | Computerbesturing |
| Steer | Bijsturen |
设置标签页或设置行的空间有限,因此可以使用术语的短形式。页面标题保留完整术语。Computer Use 标签页:德语 PC-Steuerung、意大利语 Controllo PC、波兰语 Sterowanie PC、俄语 Управление ПК。自动化任务标签页或行:俄语 Автозадачи。
简体中文术语:
| 英语 | 简体中文 |
|---|---|
| agent | 助手 |
| chat, of an agent | 对话 |
| chat, of a messaging connection | 聊天 |
| conversation | 对话 |
| channel | 频道 |
| server | 服务器 |
| host | 主机 |
| skill | 技能 |
| routine | 自动化任务 |
| workspace | 工作区 |
| provider | 服务商 |
| Settings | 设置 |
| Computer Use | Computer Use |
| Steer | 引导 |
| session | 会话 |
中文只有一种复数形式,因此每个数量都采用 other 文本,并且 plural.ts 中 zh 对每个数字都返回 other。agent 的 chat 和 conversation 都对应“对话”;消息连接(如 Telegram 聊天)上的 chat 对应“聊天”;session 对应“会话”。目录使用中国大陆的引号“ ”,更倾向于用“该”表示确定的事物(该服务器、该文件),而不是书面语中的“此”。
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 openbo/openbot