Internacionalización de aplicaciones Rust: de cero a multilingüismo

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Por qué su aplicación Rust necesita internacionalización (y cómo no meter la pata)

\n\n

Ha escrito un analizador perfecto en Rust. Vuela más rápido que un rayo y consume menos memoria que un humilde gorrión. Pero hay un problema: su texto solo se muestra en inglés. Y los usuarios de Tokio, Berlín y San Petersburgo quieren ver la interfaz en su idioma nativo.

\n\n

La internacionalización (i18n) no es solo «traducir botones». Es una decisión arquitectónica que puede convertir su código en un elegante constructor o en un infierno de if-else. En este artículo, analizaremos cómo hacer internacionalización en Rust correctamente: sin dolor, con ejemplos y respetando la mente del desarrollador futuro (la suya).

\n\n

Hablaremos de dos enfoques potentes: la biblioteca fluent (recomendación de Mozilla) y el clásico rust-i18n basado en gettext. Al final del artículo, podrá agregar soporte para ruso, inglés y cualquier otro idioma a su herramienta en 15 minutos.

\n\n

Plan de batalla: qué son i18n y l10n en el mundo Rust

\n\n

Antes de lanzarnos al código, acordemos los términos:

\n
    \n
  • Internacionalización (i18n) — preparación del código para la traducción. Extrae todas las cadenas a archivos separados y enseña al programa a seleccionar la configuración regional correcta.
  • \n
  • Localización (l10n) — la traducción en sí. Creación de archivos para cada idioma.
  • \n
  • Configuración regional (locale) — combinación de idioma y región (por ejemplo, ru-RU, en-US, de-DE).
  • \n
\n\n

En Rust hay varios caminos. Veremos los dos más populares:

\n
    \n
  • Fluent — sistema moderno de Mozilla. Potente, flexible, con soporte para pluralización y contexto.
  • \n
  • rust-i18n — macros inspiradas en Ruby on Rails. Más simple, pero menos flexible.
  • \n
\n\n

La elección depende de la tarea. Para utilidades CLI, rust-i18n es suficiente. Para aplicaciones web o GUI complejas (por ejemplo, en Tauri), es mejor usar Fluent.

\n\n

Método n.º 1: Internacionalización de Rust con Fluent (enfoque profesional)

\n\n

Instalación y configuración de Fluent

\n\n

Creemos un nuevo proyecto y agreguemos dependencias:

\n\n
cargo new i18n_demo\ncd i18n_demo\ncargo add fluent fluent-bundle fluent-langtag unic-langid\n
\n\n

La estructura de archivos será la siguiente:

\n\n
proyecto/\n├── Cargo.toml\n├── locales/\n│   ├── ru/\n│   │   └── main.ftl\n│   └── en/\n│       └── main.ftl\n└── src/\n    └── main.rs\n
\n\n

Creación de archivos de localización (FTL)

\n\n

Fluent utiliza el formato FTL (Fluent Translation List). Es pureza y potencia:

\n\n

locales/en/main.ftl:

\n
greeting = Hello, { $name }!\ngoodbye = Goodbye\napples = { $count ->\n    [one] { $count } apple\n    [few] { $count } apples\n    *[other] { $count } apples\n}\n
\n\n

locales/ru/main.ftl:

\n
greeting = Привет, { $name }!\ngoodbye = До свидания\napples = { $count ->\n    [one] { $count } яблоко\n    [few] { $count } яблока\n    [many] { $count } яблок\n    *[other] { $count } яблок\n}\n
\n\n

Observe la pluralización. En ruso hay cuatro formas (uno, dos-cuatro, cinco-veinte, el resto), mientras que en inglés hay dos (uno, el resto). Fluent maneja esto automáticamente.

\n\n

Escribiendo código en Rust para cargar configuraciones regionales

\n\n

Ahora viene lo interesante: el código que seleccionará el idioma adecuado según el sistema del usuario:

\n\n
use 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("Configuración regional no válida");\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                

Blogs

Book Recommendations