国际化

GPUI Component 的组件文案位于 crates/component/locales/ui.yml,其中有 en、zh-CN、zh-HK、zh-TW、it 等语言的条目;不同 key 的覆盖程度不一定相同。应用负责自己的文案、语言选择策略和数据格式化,也可以通过 rust-i18n 新增或覆盖组件翻译,无需复制整个内置文件。

此功能需要 rust-i18n 4.2 或更高版本。

#添加依赖

在持有 locale 文件的应用 crate 中添加 rust-i18n:

[dependencies]
gpui-kit = "0.6"
rust-i18n = "4.2"

#创建应用 locale 文件

在应用 crate 中创建 locales/ui.yml,并将组件翻译放在 gpui_component namespace 下:

_version: 2
app:
  save:
    en: Save
    fr: Enregistrer
gpui_component:
  Calendar:
    week.0:
      fr: Di
    month.January:
      fr: Janvier
  DatePicker:
    placeholder:
      fr: Sélectionner une date

应用自己的 key 放在 gpui_component 之外。组件翻译的 namespace 必须是 gpui_component,它对应 Rust crate 名称 gpui-component,其中连字符转换为下划线。请从 GPUI Component 内置 locale 文件逐字核对 key;例如 month.January 是 Calendar 下的一个完整 key。

#注册扩展

首先在应用的 crate root 初始化 locales:

rust_i18n::i18n!("locales", fallback = "en");

然后在初始化 GPUI Component 之前注册扩展:

app.run(move |cx| {
    use gpui_kit::component as gpui_component;
    rust_i18n::extend!(gpui_component);
    gpui_kit::init(cx);

    // Open a window and initialize the rest of the application.
});

应用启动期间只需调用一次 extend!。crates/story/src/lib.rs使用了同样的别名和调用顺序。

#查找优先级

应用提供的翻译优先于组件的内置翻译:

Application locales (locales/ui.yml)
             │
             │ key not found
             ▼
GPUI Component built-in locales

这种 deep merge 行为意味着:

  • 新语言(例如 fr)只需提供应用需要的 key。
  • locale 和 key 都相同时,应用提供的翻译会覆盖内置值。
  • 应用未提供的 key 会继续使用组件内置值。
  • GPUI Component 后续新增的翻译无需复制,也会自动可用。

例如,只定义 gpui_component.Calendar.month.January.en 会修改一月份的英文标签,其他英文日历标签仍然来自 GPUI Component。

#命名空间只对组件内部的查找生效

extend! 改变的是 GPUI Component 查找自身 key 的方式,它不会让应用自己的 t! 调用能访问到内置翻译:

// Inside GPUI Component: check the application first, then built-in locales.
t!("Calendar.month.February")             // -> "February"

// In application code: only the application's locale files are searched.
t!("gpui_component.Calendar.month.February")   // -> returns the key if undefined

组件文案应当通过渲染组件来呈现,不要自己去查这些 key。

应用文案可在应用 crate 中调用 rust_i18n::t!("app.save")。将整句放在同一个翻译 key 中,让每种语言自行决定语序和标点。组件占位符的翻译不会顺带翻译周围的应用标题、标签或菜单项。

#切换语言

gpui-component 已经再导出 locale 相关方法,应用无需直接依赖 rust-i18n 即可切换语言:

use gpui_kit::component::{locale, set_locale};

set_locale("fr");
let current = locale();

组件随后会按照上述优先级,使用当前 locale 查找翻译文本。

当前 locale 是 GPUI 变更跟踪之外的全局状态,单独修改它不会触发重绘。如果语言选择器由某个 view 处理,切换后通知这个 view:

use gpui_kit::component::set_locale;

set_locale("fr");
cx.notify();

cx.notify() 如何安排 View 更新,见 Context。

如果应用级 action 在 &mut App 中切换语言,则刷新展示翻译内容的窗口:

use gpui_kit::{App, component::set_locale};

fn select_locale(language: &str, cx: &mut App) {
    set_locale(language);
    cx.refresh_windows();
}

其他已缓存的界面内容还需显式重建。例如 story 应用的 SelectLocale 处理函数切换语言后会重建原生菜单和窗口内菜单,使选中状态更新;这些状态并非实时读取翻译。Story 的菜单标签目前也是固定字符串,因此这个选择器展示的是组件翻译和选中状态,并不表示整个画廊都已翻译。

#不同文字系统的文本与布局

翻译改变字符串,文本系统随后解析字体、塑形字形并测量结果。中文等 CJK 文本或中英混排需要字体包含相应字形。字体族可加载,也可能缺少特定字形;回退字体还可能改变换行和控件高度。详见字体和文本系统。在每个目标平台上,以长译文、窄按钮、输入框占位符和应用缩放检查界面。自定义文本的宽度应以塑形后的布局测量,不能按字符数估算。

GPUI Kit 的这个 locale API 没有提供应用级 RTL 布局切换。选择阿拉伯语或希伯来语 locale 可以选出对应文案,但不会自动镜像导航、图标方向、对齐、焦点顺序,以及指针和键盘行为。应按目标语言逐个检查页面,并在目标平台测试双向文本和编辑操作。文字塑形与整个界面的镜像是两项不同的检查。

#在应用中格式化数据

这里的 rust-i18n 用于选择文案;set_locale 不会替应用数据格式化日期、数字、货币、单位或复数。根据应用需求选择支持 locale 的格式化工具,将完成的文本传给 view。将变量放进完整的翻译消息,使译者能够调整位置。不要把分别翻译的片段拼成句子,也不要假定 format!("{value}") 会采用当地的数字分隔符。日期选择器可以翻译自己的月份名称,而应用其他地方显示的日期仍需遵循应用的格式化策略。

#验证集成

仓库中的 story crate 提供可运行的扩展和法语覆盖。从仓库根目录运行 cargo run -p gpui-component-story,在 Language 菜单中选择 Français,再打开日历或日期选择器 story;月份名称和日期占位符会使用 crates/story/locales/ui.yml 中的 fr 值。切回英语并检查相同控件;菜单选中标记应跟随选择。还可运行 cargo test -p gpui-component-story --features test-support extends_component_translations_with_story_locales,验证 story 的翻译叠加测试。

#常见问题

现象检查项
组件仍显示旧语言调用 set_locale 后通知所属 view 或刷新窗口;重建缓存的菜单或标签。
覆盖没有生效key 应放在 gpui_component 下,拼写和 locale 代码须与内置文件一致,并在 gpui_kit::init 前注册 extend!。
应用中的 t! 返回 key在应用 locale 文件中定义该 key;组件内置文案供组件查找,不供应用直接查找。
CJK 出现方框或布局变化检查目标平台的字体字形覆盖和回退;见字体。
RTL 文案已出现但界面仍不顺手逐项检查布局和交互;切换 locale 不会镜像整个界面。

CC BY 4.0 · GPUI Kit 有权授权的原创文档正文与图示可在注明署名后复制或改编。 许可条款。请署名 GPUI Kit,链接到 本页原文及 CC BY 4.0 许可,并注明是否修改。 代码示例与软件源码仍适用 Apache-2.0。既有 Apache 权利不受影响;第三方材料保留各自许可。