Pourquoi votre application Rust a besoin d'internationalisation (et comment éviter les pièges)
\n\nVous avez écrit un analyseur parfait en Rust. Il vole plus vite que l'éclair et consomme moins de mémoire qu'une modeste mésange. Mais il y a un problème : votre texte s'affiche uniquement en anglais. Et les utilisateurs de Tokyo, Berlin et Saint-Pétersbourg veulent voir l'interface dans leur langue maternelle.
\n\nL'internationalisation (i18n) n'est pas simplement « traduire les boutons ». C'est une décision architecturale qui peut transformer votre code en un constructeur élégant ou en un dépotoir infernal de if-else. Dans cet article, nous allons voir comment faire de l'internationalisation en Rust correctement : sans douleur, avec des exemples et dans le respect du cerveau du futur développeur (le vôtre).
\n\nNous parlerons de deux approches puissantes : la bibliothèque fluent (recommandation de Mozilla) et le classique rust-i18n basé sur gettext. À la fin de cet article, vous pourrez ajouter la prise en charge du russe, de l'anglais et de toute autre langue à votre outil en 15 minutes.
Plan de bataille : qu'est-ce que i18n et l10n dans le monde Rust
\n\nAvant de se jeter dans le code, mettons-nous d'accord sur les termes :
\n- \n
- Internationalisation (i18n) — la préparation du code à la traduction. Vous extrayez toutes les chaînes dans des fichiers séparés et apprenez au programme à charger la locale appropriée. \n
- Localisation (l10n) — la traduction elle-même. Création de fichiers pour chaque langue. \n
- Locale — une combinaison de langue et de région (par exemple,
ru-RU,en-US,de-DE). \n
En Rust, il existe plusieurs chemins. Nous allons examiner les deux plus populaires :
\n- \n
- Fluent — un système moderne de Mozilla. Puissant, flexible, avec prise en charge de la pluralisation et du contexte. \n
- rust-i18n — des macros inspirées de Ruby on Rails. Plus simple, mais moins flexible. \n
Le choix dépend de la tâche. Pour les utilitaires CLI, rust-i18n suffit. Pour les applications web ou les GUI complexes (par exemple, sur Tauri), il est préférable d'utiliser Fluent.
Méthode n°1 : Internationalisation Rust avec Fluent (approche professionnelle)
\n\nInstallation et configuration de Fluent
\n\nCréons un nouveau projet et ajoutons les dépendances :
\n\ncargo new i18n_demo\ncd i18n_demo\ncargo add fluent fluent-bundle fluent-langtag unic-langid\n\n\nLa structure des fichiers sera la suivante :
\n\nprojet/\n├── Cargo.toml\n├── locales/\n│ ├── ru/\n│ │ └── main.ftl\n│ └── en/\n│ └── main.ftl\n└── src/\n └── main.rs\n\n\nCréation des fichiers de localisation (FTL)
\n\nFluent utilise le format FTL (Fluent Translation List). C'est la pureté et la puissance :
\n\nlocales/en/main.ftl :
\ngreeting = Hello, { $name }!\ngoodbye = Goodbye\napples = { $count ->\n [one] { $count } apple\n [few] { $count } apples\n *[other] { $count } apples\n}\n\n\nlocales/ru/main.ftl :
\ngreeting = Привет, { $name }!\ngoodbye = До свидания\napples = { $count ->\n [one] { $count } яблоко\n [few] { $count } яблока\n [many] { $count } яблок\n *[other] { $count } яблок\n}\n\n\nRemarquez la pluralisation. En russe, il y a quatre formes (un, deux-quatre, cinq-vingt, le reste), tandis qu'en anglais il y en a deux (un, le reste). Fluent gère cela automatiquement.
\n\nÉcriture du code Rust pour charger les locales
\n\nMaintenant, la partie intéressante — le code qui sélectionnera la langue appropriée en fonction du système de l'utilisateur :
\n\nuse fluent_bundle::{FluentBundle, FluentResource};\nuse unic_langid::LanguageIdentifier;\nuse std::fs;\nuse std::path::Path;\n\nfn load_locale(locale: &str) -> FluentBundle<FluentResource> {\n let langid: LanguageIdentifier = locale.parse().expect("Locale invalide");\n let mut bundle = FluentBundle::new(vec![langid]);\n\n let file_path = format!("locales/{}/main.ftl", locale);\n let source = fs::read_to_string(&file_path)\n .expect(&fo