Интернационализация (i18n) в Rust: gettext-rs и fluent-rs
Интернационализация (i18n) — ключевой аспект разработки современных приложений, позволяющий адаптировать программное обеспечение для пользователей из разных стран и культур. В экосистеме Rust существует несколько мощных библиотек для реализации i18n. В этой статье мы рассмотрим две наиболее популярные: gettext-rs (классический подход на основе gettext) и fluent-rs (современная система локализации от Mozilla).
1. Библиотека gettext-rs
gettext-rs — это Rust-обёртка над классической системой GNU gettext. Она идеально подходит для проектов, где уже используется gettext, или для тех, кто предпочитает проверенные временем решения.
Установка и настройка
Добавьте зависимость в Cargo.toml:
[dependencies]
gettext-rs = "0.7"
gettext-sys = "0.21"
Базовый пример использования
use gettextrs::*;
fn main() {
// Устанавливаем локаль и домен перевода
setlocale(LocaleCategory::LcAll, "ru_RU.UTF-8");
bindtextdomain("myapp", "/usr/share/locale").unwrap();
textdomain("myapp").unwrap();
// Используем перевод
let greeting = gettext("Hello, world!");
println!("{}", greeting);
// Плюральные формы
let items = 5;
let message = ngettext("{} item", "{} items", items);
println!("{}", message.replace("{}", &items.to_string()));
}
Работа с контекстом
Для различения одинаковых строк в разных контекстах используйте pgettext:
let menu_item = pgettext("menu", "File");
let dialog_title = pgettext("dialog", "File");
2. Библиотека fluent-rs
fluent-rs — это современная, гибкая и мощная система локализации, разработанная Mozilla. Она поддерживает сложные грамматические конструкции, плюральные формы и контекстные переводы.
Установка
[dependencies]
fluent = "0.16"
fluent-bundle = "0.15"
fluent-resmgr = "0.5"
fluent-langneg = "0.4"
unic-langid = "0.9"
Создание файлов перевода (FTL)
Fluent использует собственный формат файлов .ftl. Пример для русского языка (ru.ftl):
hello-world = Привет, мир!
greeting = Здравствуйте, {$name}!
items-count = { $count ->
[one] {$count} элемент
[few] {$count} элемента
[many] {$count} элементов
*[other] {$count} элементов
}
Пример использования fluent-rs
use fluent_bundle::{FluentBundle, FluentResource};
use unic_langid::langid;
use std::fs;
fn main() {
// Загружаем файл перевода
let ftl_string = fs::read_to_string("locales/ru.ftl")
.expect("Не удалось прочитать файл локализации");
let resource = FluentResource::try_new(ftl_string)
.expect("Ошибка парсинга FTL");
// Создаём бандл для русского языка
let lang_ru = langid!("ru");
let mut bundle = FluentBundle::new(&[lang_ru]);
bundle.add_resource(&resource).unwrap();
// Получаем перевод с параметрами
let mut errors = vec![];
let msg = bundle.get_message("greeting").unwrap();
let mut args = fluent_bundle::FluentArgs::new();
args.set("name", "Алексей");
let pattern = msg.value().unwrap();
let value = bundle.format_pattern(pattern, Some(&args), &mut errors);
println!("{}", value);
// Плюральные формы
let msg = bundle.get_message("items-count").unwrap();
let mut args = fluent_bundle::FluentArgs::new();
args.set("count", 3);
let pattern = msg.value().unwrap();
let value = bundle.format_pattern(pattern, Some(&args), &mut errors);
println!("{}", value);
}
3. Сравнение gettext-rs и fluent-rs
- gettext-rs:
- Проверенная временем технология
- Широкая поддержка инструментов (Poedit, Lokalize)
- Простая интеграция с существующими проектами
- Ограниченная поддержка сложных грамматических конструкций
- fluent-rs:
- Современный дизайн и гибкость
- Встроенная поддержка плюральных форм и контекстов
-
Также в библиотеке
Рекомендаций