Internacionalización con Fluent (fluent)

Fluentopen in new window es un sistema de localización creado por la Fundación Mozilla para realizar traducciones naturales. Tiene una sintaxis muy potente y elegante que permite a cualquiera escribir traducciones eficientes y totalmente comprensibles. Este plugin aprovecha este increíble sistema de localización para hacer que los bots alimentados por grammY sean fluidos con traducciones de alta calidad.

Inicializar Fluent

Lo primero que hay que hacer es inicializar una instancia de Fluent:

import { Fluent } from "@moebius/fluent";

const fluent = new Fluent();

A continuación, tendrá que añadir al menos una traducción a la instancia de Fluent:

await fluent.addTranslation({
  // Especifica una o más localizaciones soportadas por tu traducción:
  locales: "es",

  // Puede especificar el contenido de la traducción directamente:
  source: "{SU CONTENIDO DE ARCHIVO DE TRADUCCIÓN}",

  // O los archivos de traducción:
  filePath: [
    `${__dirname}/feature-1/translation.en.ftl`,
    `${__dirname}/feature-2/translation.en.ftl`,
  ],

  // Todos los aspectos de Fluent son altamente configurables:
  bundleOptions: {
    // Utilice esta opción para evitar los caracteres invisibles alrededor de los elementos colocables.
    useIsolating: false,
  },
});

Escribir mensajes de traducción

La sintaxis de Fluent debería ser fácil de dominar. Puedes empezar mirando los ejemplos oficialesopen in new window o estudiando la guía completa de sintaxisopen in new window.

Empecemos con este ejemplo por ahora:

-bot-name = Apples Bot

welcome =
  Welcome, {$name}, to the {-bot-name}!
  You have { NUMBER($applesCount) ->
    [0] no apples
    [one] {$applesCount} apple
    *[other] {$applesCount} apples
  }.

Demuestra tres características importantes de Fluent, a saber: términos, sustitución de variables (también conocidos como placeables) y pluralización.

El welcome es el identificador del mensaje, que se utilizará para referenciar su mensaje siempre que se renderice.

La sentencia -bot-name = Apples Bot define un término con nombre bot-name y valor Apples Bot. La construcción {-bot-name} hace referencia al término previamente definido y será reemplazado por el valor del término cuando se renderice.

La declaración {$name} será reemplazada por el valor de la variable name que tendrá que pasar a la función de traducción usted mismo.

Y la última sentencia (líneas 5 a 9) define un selector (muy similar a una sentencia switch) que toma el resultado de la función especial NUMBER aplicada a la variable applesCount y selecciona uno de los tres posibles mensajes a renderizar basándose en el valor coincidente. La función NUMBER devolverá una categoría plural CLDRopen in new window basada en el valor proporcionado y la configuración regional utilizada. Esto implementa efectivamente la pluralización.

grammY Configuración

Ahora vamos a ver cómo este mensaje de arriba podría ser renderizado por un bot. Pero primero, necesitaremos configurar grammY para usar el plugin.

Antes que nada, necesitarás configurar tu bot para que utilice el sabor de contexto Fluent. Si no estás familiarizado con este concepto, deberías leer los documentos oficiales sobre Context Flavors.

import { Context } from "grammy";
import { FluentContextFlavor } from "@grammyjs/fluent";

// Extiende tu tipo de contexto de aplicación con la interfaz de sabor proporcionada.
export type MyAppContext =
  & Context
  & FluentContextFlavor;

Tendrás que crear tu instancia de bot de la siguiente manera para poder utilizar el tipo de contexto aumentado:

const bot = new Bot<MyAppContext>();

Y el último paso sería registrar el propio plugin de Fluent con grammY:

bot.use(useFluent({
  fluent,
}));

Asegúrate de pasar la instancia de Fluent previamente creada.

Renderizar los mensajes localizados

Genial, ¡ya tenemos todo listo para renderizar nuestros mensajes! Vamos a hacerlo definiendo un comando de prueba en nuestro bot:

bot.command("i18n_test", async (ctx) => {
  // Llama al helper "translate" o "t" para renderizar el
  // mensaje especificando su ID y parámetros adicionales:
  await ctx.reply(ctx.t("welcome", {
    nombre: ctx.from.first_name,
    applesCount: 1,
  }));
});

Ahora puedes iniciar tu bot y utilizar el comando /i18n_test. Debería mostrar el siguiente mensaje:

¡Bienvenido, Slava, al Bot de las Manzanas!
Tienes 1 manzana.

Por supuesto, verás tu propio nombre en lugar de “Slava”. Prueba a cambiar el valor de la variable applesCount para ver cómo cambia el mensaje renderizado.

Ten en cuenta que ahora puedes utilizar la función de traducción en todos los lugares donde el Contexto esté disponible. La librería determinará automáticamente la mejor localización posible para cada usuario que interactúe con tu bot, basándose en sus preferencias personales (el idioma establecido en la configuración del cliente de Telegram). Sólo tendrás que crear varios archivos de traducción y asegurarte de que todas las traducciones están correctamente sincronizadas.

Otros pasos

Resumen del plugin