Rust 中的国际化 (i18n):最佳库与实践

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

Rust 中的国际化 (i18n):库与工具概览



国际化(缩写为 i18n——取自 'i' 和 'n' 之间的 18 个字母)是一种应用程序设计过程,允许在不修改源代码的情况下,使其适应不同的语言和区域标准。在 Rust 生态系统中,有多个成熟的库可用于实现 i18n。在本文中,我们将探讨三种主要方法:经典的 gettext、基于宏的 rust-i18n 以及 Mozilla 开发的现代 fluent-rs。



1. gettext 库(crate gettext-rs)

gettext 是 Unix 本地化的事实标准。Rust 封装 gettext-rs 提供了对 GNU gettext 功能的完整访问。



安装

[dependencies]gettext-rs = "0.7"


使用示例

use gettextrs::*;use std::env;

fn main() { // 设置区域和域 setlocale(LocaleCategory::LcAll, "ru_RU.UTF-8"); bindtextdomain("myapp", "/usr/share/locale").unwrap(); textdomain("myapp");

// 字符串翻译 println!("{}", gettext("Hello, world!")); // 复数形式 let n = 5; println!("{}", ngettext("{} apple", "{} apples", n, n));}


优点:成熟、支持复数形式、上下文翻译 (pgettext)、与 Poedit 和 Transifex 集成。
缺点:需要安装系统级 gettext,在 Windows 上对 Unicode 支持不完美。



2. rust-i18n 库

纯 Rust 实现,无外部依赖。使用 YAML 文件存储翻译,并使用宏提取字符串。



安装

[dependencies]rust-i18n = "3.0"


项目结构

locales/├── en.yml└── ru.yml


locales/ru.yml 示例:

hello: "Привет, мир!"apples:   zero: "Нет яблок"  one: "{} яблоко"  few: "{} яблока"  many: "{} яблок"


在代码中使用

use rust_i18n::t;

rust_i18n::i18n!("locales");

fn main() { // 简单翻译 println!("{}", t!("hello"));

// 考虑俄语规则的复数形式 let n = 3; println!("{}", t!("apples", count = n, n));}


优点:简单、自动检测区域、支持占位符和复杂语言(俄语、阿拉伯语)的复数形式。
缺点:不如 gettext 灵活,不支持上下文。



3. fluent-rs 库

由 Mozilla 为 Firefox 开发。使用其专有的 FTL(Fluent Translation List)语法。



安装

[dependencies]fluent = "0.16"fluent-bundle = "0.15"fluent-resmgr = "0.4"


FTL 文件示例(locales/ru/main.ftl)

hello = Привет, мир!apples =     { $count ->        [0] Нет яблок        [one] { $count } яблоко        [few] { $count } яблока       *[many] { $count } яблок    }


在 Rust 中使用

use fluent_bundle::{FluentBundle, FluentResource};use fluent_resmgr::ResourceManager;use unic_langid::langid;

fn main() { let langid = langid!("ru"); let res_mgr = ResourceManager::new("./locales/".into()); let mut bundle = FluentBundle::new(&[langid]); let ftl_string = res_mgr.load("ru/main.ftl").unwrap(); let resource = FluentResource::try_new(ftl_string).unwrap(); bundle.add_resource(resource).unwrap();

let mut errors = vec![]; let msg = bundle.format_pattern( bundle.get_message("hello").unwrap().value().unwrap(), None, &mut errors ); println!("{}", msg);

// 复数形式 let mut args = fluent_bundle::FluentArgs::new();

推荐