Skip to content

国际化与翻译

Slint 的翻译基础设施让你的应用能够支持多种语言。

你可以选择使用 gettext 的运行时翻译,或者在 gettext 不可用或不切实际的平台上,将翻译直接捆绑到可执行文件中。

要翻译你的应用,请按以下步骤操作:

  1. 找出所有需要翻译的用户可见字符串,并用 @tr() 宏标注它们。
  2. 运行 slint-tr-extractor 工具提取已标注的字符串,生成 .pot 文件。
  3. 使用第三方工具将字符串翻译为每种目标语言的 .po 文件。
  4. (仅用于运行时 gettext 翻译) 使用 gettext 的 msgfmt 将 .po 文件转换为 .mo 文件。
  5. (仅用于捆绑翻译) 在构建过程中配置捆绑,将翻译嵌入到你的应用中。
  6. 使用 Slint 的 API 根据用户的 locale 选择合适的翻译。

此时,所有标记为翻译的字符串都会自动以所选语言渲染。

在 .slint 文件中使用 @tr 宏将字符串标记为可翻译。 该宏支持格式化和复数形式,并且可以包含上下文信息。

第一个参数必须是纯字符串字面量,其后是各个参数:

export component Example {
property <string> name;
Text {
text: @tr("Hello, {}", name);
}
}
slint

格式字符串中的每个 {} 占位符都会按顺序替换为对应的参数。 占位符可以指定一个从零开始的位置,如 {0} 或 {1},以显式选择某个参数。 在一个格式字符串中不能混用位置占位符和非位置占位符。 即使源字符串没有使用位置占位符,翻译也可以使用它们。

通过将 { 或 } 加倍,即写成 {{ 或 }},来写出字面量。 未终止的占位符、未转义的 { 或 },或者占位符多于参数,都是错误。

复数形式根据计数在两个格式字符串之间选择。 其写法是在两个字符串字面量之间加 |,并在计数表达式前加 %:

@tr("I have {n} item" | "I have {n} items" % count)
slint

| 的两侧都必须是纯字符串字面量,计数表达式会被转换为 int。 {n} 占位符指代计数,只在复数形式中有效。 其他占位符仍然指代计数之后的参数:

export component Example inherits Text {
in property <int> score;
in property <int> name;
text: @tr("Hello {0}, you have one point" | "Hello {0}, you have {n} points" % score, name);
}
slint

上下文用于区分源文本相同但含义不同的字符串。 其写法是在格式字符串之前写一个纯字符串字面量,后跟 =>:

export component MenuItem {
property <string> name: @tr("Default Name"); // context: `MenuItem`
property <string> tooltip: @tr("ToolTip" => "ToolTip for {}", name); // context: `ToolTip`
}
slint

如果没有提供上下文,则默认为外层组件的名称。

如果你不希望组件名称成为默认上下文,请向 slint-tr-extractor 传递 --no-default-translation-context 标志。同样的选项也需要传递给 Slint 编译器:

使用 slint-tr-extractor 生成一个包含所有已标记为翻译的字符串的 .pot 文件:

Terminal window
find -name \*.slint | xargs slint-tr-extractor -o MY_PROJECT.pot
bash

这会创建一个名为 MY_PROJECT.pot 的文件。将 “MY_PROJECT” 替换为你的实际项目名称。 要了解项目名称如何影响翻译的查找,请阅读下面的章节。

通过从 .pot 文件创建 .po 文件来开始一个新的翻译。两种文件格式完全相同。 你可以手动复制文件,或者使用类似 Gettext 的 msginit 这样的工具来创建一个新的 .po 文件。

.po 文件包含目标语言的字符串。

.po 和 .pot 文件是纯文本文件,你可以用文本编辑器编辑它们。我们建议 使用专门的翻译工具来处理它们,例如以下几种:

Slint 可以使用 Gettext 库在运行时加载翻译。

Gettext 期望翻译文件(称为消息目录)按以下目录层级组织:

  • Directorydir_name/
    • Directorylocale/ 例如 fr、en、de 等
      • DirectoryLC_MESSAGES/
        • domain_name.mo
  • dir_name:你可以自由选择的基础目录。

  • locale:给定目标语言对应的用户 locale 名称,例如法语用 fr,德语用 de。

    locale 通常是使用操作系统设置的环境变量来确定的。

  • domain_name:根据你使用 Slint 时所搭配的编程语言来选择。

将人类可读的 .po 文件转换为便于机器处理的 .mo 文件,后者是一种二进制表示, 代码读取起来更高效。

使用 Gettext 的 msgfmt 命令行工具将 .po 文件转换为 .mo 文件:

Terminal window
msgfmt translation.po -o translation.mo
bash

首先,在 features 部分启用 slint crate 的 gettext feature,以访问翻译 API 并激活运行时翻译支持。

接下来,使用 slint::init_translations! 宏指定 .mo 文件的基础位置。 这就是上一节方案中的 dir_name。Slint 期望 .mo 文件位于 相应的子目录中,并且它们的文件名——domain_name——必须与 你的 Cargo.toml 中的包名匹配。这通常与 crate 名称相同。

例如:

slint::init_translations!(concat!(env!("CARGO_MANIFEST_DIR"), "/lang/"));
rust

例如,如果你的 Cargo.toml 包含以下几行,且用户的 locale 是 fr:

[package]
name = "gallery"
toml

使用这些设置,Slint 会在 lang/fr/LC_MESSAGES/gallery.mo 中查找 gallery.mo。

捆绑翻译将翻译后的字符串直接嵌入到你的应用二进制文件中。 这种方法非常适合 WASM 或微控制器等 gettext 不可用的平台。

通过向 Slint 编译器提供翻译路径来配置翻译捆绑。 翻译文件应按以下层级组织:

path/<lang>/LC_MESSAGES/<domain>.po
plaintext

使用 slint_build::CompilerConfiguration 的 with_bundled_translations() 函数在 build.rs 中设置捆绑:

let config = slint_build::CompilerConfiguration::new()
.with_bundled_translations("path/to/translations");
slint_build::compile_with_config("path/to/main-ui.slint", config).unwrap();
rust

<domain> 就是 crate 名称。

如果你为 Slint 启用了 std feature,翻译语言会根据 locale 检测: 如果某个捆绑语言与所选 locale 匹配,就会使用该语言。

使用

slint::select_bundled_translation

函数在运行时更改翻译。

确保在构建 slint-viewer 时启用了 gettext feature。 使用 --translation-domain 和 --translation-dir 命令行选项加载翻译以进行预览。

float 和 string 之间的转换使用 locale 的小数分隔符, 例如德语 locale 中的逗号(,)。 转换规则参见 数字与字符串之间的转换。

从 Platform.decimal-separator 读取当前使用的分隔符。 它默认是点(.)。

在捆绑翻译时,每种语言的小数分隔符在编译时确定, 并与应用一起捆绑: 选择某种翻译也会选择其小数分隔符。 当启用 gettext feature 时,小数分隔符由系统 locale 决定。


© 2026 SixtyFPS GmbH