Интернационализация (i18n) в Rust: обзор библиотек и инструментов
Интернационализация (сокращённо i18n — от 18 букв между 'i' и 'n') — процесс проектирования приложения, позволяющий адаптировать его под различные языки и региональные стандарты без изменения исходного кода. В экосистеме Rust существует несколько зрелых библиотек для реализации i18n. В этой статье мы рассмотрим три основных подхода: классический gettext, макрос-ориентированная rust-i18n и современный fluent-rs от Mozilla.
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, неидеальная поддержка Unicode на Windows.
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();
args.set("count", 3);
let