Интернационализация (i18n) в Rust: библиотека gettext-rs и fluent-rs

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Интернационализация (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

Рекомендаций