☰
如何给 Yaak 加多语言:4 步实现实时切换
2026/10/8 7:52:34 网站建设 项目流程

如何给 Yaak 加多语言:4 步实现实时切换

【免费下载链接】yaakThe most intuitive desktop API client. Organize and execute REST, GraphQL, WebSockets, Server Sent Events, and gRPC 🦬项目地址: https://gitcode.com/GitHub_Trending/ya/yaak

你的团队新来了位日本同事,打开 Yaak 却只能面对满屏英文菜单。给 Yaak 多语言切换做上,界面就能跟随系统语言走,中文用户也能一眼看懂每个按钮。

4 步路线图:存翻译、管状态、换文本、记偏好

整套 Yaak 本地化改动可以压成一条线:

  1. 存翻译——客户端目录下每种语言一个 JSON;
  2. 管状态——一个 jotai atom 存"当前语言",全局唯一;
  3. 换文本——把 JSX 里写死的英文换成t()查表调用;
  4. 记偏好——选择写入 KV 存储,启动时读系统语言做兜底。

前三步做完,功能就已经能跑了,先别急着碰持久化和检测。

第 1 步:语言文件放哪、怎么分层

翻译需要一个"唯一事实来源"。在客户端根目录新建apps/yaak-client/locales/,英文作为基准语言单独放一个文件,其他语言与它保持同构的 key:

apps/yaak-client/locales/ ├── en.json ├── zh-CN.json ├── ja.json └── ko.json

key 按功能域分组,而不是平铺:

{ "common": { "send": "发送", "cancel": "取消" }, "settings": { "language": "界面语言" }, "sidebar": { "newRequest": "新建请求" } }

为什么要分组:加文案时按目录找文件不会乱,删一个功能模块时整块 key 一起走,各语言文件之间的 diff 也小、好评审。

第 2 步:一个 atom 实现实时语言切换

要解决的问题很具体:用户在下拉里切到中文,所有正在显示的文本要立刻变,而不是刷新之后才知道换了。

Yaak 客户端前端本来就用 jotai 管理状态(apps/yaak-client/lib/atoms.ts里布局、设置都是 atom),所以别引入第二套方案,直接加一个语言 atom:

import { atom, useAtomValue } from "jotai"; export const languageAtom = atom("en"); export function useT() { const lang = useAtomValue(languageAtom); return (key: string) => lookup(lang, key); }

组件里useT()拿到t,t内部根据当前 atom 值查对应 JSON。atom 一变,订阅它的组件自动重渲染,这就是实时语言切换不需要 reload 的原因——复用现有状态系统,还省掉了同步两套状态的代码。

切换入口本身很简单:在 SettingsGeneral 里照 Update Channel 那行的写法加一个SettingRowSelect,选项是 en / zh-CN / ja / ko,onChange里写languageAtom即可。

第 3 步:把硬编码文本换成 t()

先别全仓库扫,挑一个组件对比一下改造前后:

// 改造前:文案写死在 JSX 里 <Button>Send Request</Button> <Select options={["Stable", "Beta"]} /> // 改造后:只留 key,文案在 locales 里 <Button>{t("common.send")}</Button> <Select options={["stable", "beta"].map(mapLangOption)} />

为什么必须走 key 而不是直接写中文:key 是代码里唯一稳定的部分,文案可以无限次替换,翻译还能独立评审;而且这种"改造前/改造后"的 diff 一眼能看出哪段逻辑没动。

文本量大的话,先跑一遍 grep 把硬编码英文列成清单,按界面分批改。API 客户端 i18n 的常见坑就在这里:按钮、菜单好改,散落在 description 提示里的长句子容易漏,清单能堵住。

第 4 步:记住选择,并按系统语言兜底

裸 atom 有个毛病:重启就回 "en"。项目里已有现成的持久化封装atomWithKVStorage(apps/yaak-client/lib/atoms/atomWithKVStorage.ts,负责读 KV 存储并在写入时回写),直接换掉裸 atom:

import { atomWithKVStorage } from "./atoms/atomWithKVStorage"; export const languageAtom = atomWithKVStorage("language", "en");

启动时再补一层系统语言检测:存储里没有值,就取navigator.language,映射不到支持的语言再回退 en:

if (stored == null) { const nav = navigator.language; // "zh-CN" / "ja" / "ko" setLanguage(normalize(nav) ?? "en"); }

为什么要分两层:用户手动选过的语言永远优先,系统语言只服务"第一次打开"的场景——日语系统的同事装完应用直接就是日文界面,不用进设置找开关。这个"系统偏好当初始值"的写法,和 usePreferredAppearance 处理明暗主题的方式同构,不引入新的心智负担。

进阶选项:RTL 方向、按需加载、插件扩展点

三件事都不急着做,但方向可以先定下来。RTL:切换语言时同步document.documentElement.dir为 rtl 或 ltr,阿拉伯语和希伯来语用户的排版才正确。按需加载:语言文件多起来后,用import(../locales/${lang}.json)只取当前语言的包,首屏不背全部翻译。插件生态:plugins/下不少插件自带 UI,给插件 manifest 加一个 locale 字段,第三方插件也能参与整套 Yaak 本地化。

改完后的自检清单

四条都过,Yaak 多语言切换就算跑通了:

  1. 下拉切到任意语言,1 秒内全部文本更新,无需刷新页面;
  2. 重启应用,语言保持上次选择;
  3. 中文系统首次打开自动显示 Yaak 中文界面;之后手动切过语言,改系统语言也不会再跳回去;
  4. en.json里每个 key 在其他语言文件中都存在,缺 key 时显示英文而不是空白。

写在最后

做完这四步,Yaak 本地化的骨架就搭好了,文案层和逻辑层从此分开:以后加西班牙语只是多一个 es.json,而不是再动一遍组件。再往后,可以补一个 key 覆盖率检查脚本,或者把翻译文件开放给社区维护。把仓库 clone 下来(git clone https://gitcode.com/GitHub_Trending/ya/yaak),挑一个文本最少的界面,从第一个t()改起。

【免费下载链接】yaakThe most intuitive desktop API client. Organize and execute REST, GraphQL, WebSockets, Server Sent Events, and gRPC 🦬项目地址: https://gitcode.com/GitHub_Trending/ya/yaak

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询