Documentación

Localización en Lingui.js: archivos PO, i18n en React y automatización

Lingui.js es un framework de internacionalización (i18n) ligero pero potente para aplicaciones JavaScript y React. Utiliza archivos PO (Portable Object) estándar de la industria para catálogos de traducción, potentes macros en tiempo de compilación para una experiencia de desarrollador limpia y produce paquetes optimizados de menos de 2 kB. Esta guía cubre todo, desde la configuración del proyecto hasta flujos de trabajo de archivos PO, pluralización y automatización de traducciones con l10n.dev.

¿Por qué Lingui.js para i18n?

Lingui.js destaca entre las bibliotecas i18n de JavaScript por su combinación de experiencia de desarrollador, rendimiento y flujos de trabajo de traducción profesional:

  • Limpio y legible: Escribe traducciones de forma natural usando macros JSX; la biblioteca las compila a ICU MessageFormat internamente.
  • Universal: @lingui/core funciona en cualquier proyecto de JavaScript, mientras que @lingui/react añade componentes específicos de React, incluido el soporte para React Server Components (RSC).
  • Soporte completo de texto enriquecido: Usa componentes de React dentro de mensajes traducibles sin problemas: enlaces, texto en negrita, iconos y cualquier JSX son totalmente compatibles.
  • Formato de archivo PO: Utiliza el formato PO estándar de la industria compatible con prácticamente todas las herramientas de traducción, TMS y flujos de trabajo de traductores profesionales.
  • Ligero y optimizado: La biblioteca principal pesa menos de 2 kB comprimidos, los componentes de React añaden solo 1.3 kB. Los datos no esenciales se eliminan en tiempo de compilación.
  • Listo para traducciones con IA: Las descripciones de mensajes y los comentarios de contexto de Lingui brindan a los traductores de IA la información que necesitan para producir traducciones precisas y conscientes del contexto.

Instalación

Instala los paquetes principales y las herramientas de desarrollo de Lingui. Los paquetes de tiempo de ejecución (@lingui/core y @lingui/react) son necesarios en producción, mientras que la CLI, el plugin de Vite y la macro de Babel son solo para desarrollo:

npm install @lingui/core @lingui/react
npm install --save-dev @lingui/cli @lingui/vite-plugin @lingui/babel-plugin-lingui-macro

Configuración

Lingui requiere dos archivos de configuración: la configuración de Lingui (que define las configuraciones regionales y las rutas del catálogo) y la configuración de tu herramienta de compilación (para habilitar macros en tiempo de compilación).

Configuración de Lingui

Crea un archivo lingui.config.js en la raíz de tu proyecto. Esto define tu configuración regional de origen, las configuraciones regionales de destino, dónde almacenar los catálogos PO y el formato del catálogo. El formato PO es la opción predeterminada y recomendada:

// lingui.config.js
import { defineConfig } from "@lingui/cli";
import { formatter } from "@lingui/format-po";

export default defineConfig({
  sourceLocale: "en",
  locales: ["en", "fr", "de", "ja", "es", "zh-CN"],
  catalogs: [
    {
      path: "<rootDir>/src/locales/{locale}/messages",
      include: ["src"],
    },
  ],
  format: formatter({ lineNumbers: false }),
});

Configuración de Vite

Si usas Vite, añade el plugin de Lingui junto con el plugin de React con la macro de Babel. Esto permite la transformación de mensajes en tiempo de compilación y la compilación de catálogos sobre la marcha:

// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { lingui } from "@lingui/vite-plugin";

export default defineConfig({
  plugins: [
    react({
      babel: {
        plugins: ["@lingui/babel-plugin-lingui-macro"],
      },
    }),
    lingui(),
  ],
});

El formato de archivo PO

PO (Portable Object) es el formato de archivo de traducción estándar de la industria, originado en el sistema GNU gettext. Lingui utiliza PO como su formato de catálogo predeterminado porque es ampliamente compatible con herramientas de traducción, plataformas TMS y traductores profesionales de todo el mundo.

  • Legible: Incluso los archivos de traducción grandes siguen siendo legibles por humanos con pares msgid/msgstr claros.
  • Comentarios del traductor: Admite comentarios #. que llevan descripciones de contexto directamente a los traductores.
  • Referencias de origen: Cada mensaje incluye comentarios #: archivo:línea que muestran exactamente dónde se utiliza en tu código base.
  • Soporte de contexto: Usa msgctxt para desambiguar cadenas idénticas que tienen significados diferentes en contextos diferentes.
  • Soporte de herramientas universal: Compatible con prácticamente todos los sistemas de gestión de traducción (TMS), herramientas CAT y plataformas de localización.

Archivo PO extraído (mensajes de origen)

#: src/components/WelcomeBanner.js:6
msgid "Welcome to our platform"
msgstr ""

#: src/components/WelcomeBanner.js:8
msgid "Hello {userName}, check out your <0>dashboard</0> to get started."
msgstr ""

#: src/components/CartSummary.js:5
msgid "{itemCount, plural, =0 {Your cart is empty} one {You have # item in your cart} other {You have # items in your cart}}"
msgstr ""

Archivo PO traducido (francés)

Después de la traducción, cada msgstr se completa con la versión localizada. Lingui conserva la sintaxis de ICU MessageFormat, etiquetas indexadas para componentes de React y variables de marcador de posición en todas las traducciones.

#: src/components/WelcomeBanner.js:6
msgid "Welcome to our platform"
msgstr "Bienvenue sur notre plateforme"

#: src/components/WelcomeBanner.js:8
msgid "Hello {userName}, check out your <0>dashboard</0> to get started."
msgstr "Bonjour {userName}, consultez votre <0>tableau de bord</0> pour commencer."

#: src/components/CartSummary.js:5
msgid "{itemCount, plural, =0 {Your cart is empty} one {You have # item in your cart} other {You have # items in your cart}}"
msgstr "{itemCount, plural, =0 {Votre panier est vide} one {Vous avez # article dans votre panier} other {Vous avez # articles dans votre panier}}"

Estructura del proyecto

Organiza tus catálogos PO dentro de un directorio locales con una subcarpeta por configuración regional. La CLI de Lingui crea y actualiza automáticamente estos archivos durante la extracción. Los módulos JS compilados se generan en tiempo de compilación y no deben editarse manualmente.

src/
├── locales/
│   ├── en/
│   │   └── messages.po       ← Source (English)
│   ├── fr/
│   │   └── messages.po       ← French
│   ├── de/
│   │   └── messages.po       ← German
│   ├── ja/
│   │   └── messages.po       ← Japanese
│   ├── es/
│   │   └── messages.po       ← Spanish
│   └── zh-CN/
│       └── messages.po       ← Chinese Simplified
├── components/
├── i18n.ts
├── App.tsx
└── ...

Traducción de componentes de React

Lingui proporciona dos enfoques principales para marcar mensajes: macros JSX para el contenido de los componentes y el hook useLingui para cadenas imperativas. Ambos son macros de tiempo de compilación que producen una salida optimizada.

La macro Trans

Envuelve cualquier contenido JSX en la macro Trans para hacerlo traducible. Las variables, los elementos HTML y los componentes de React son totalmente compatibles; la macro los transforma automáticamente en ICU MessageFormat con etiquetas indexadas.

import { Trans } from "@lingui/react/macro";

function WelcomeBanner({ userName }) {
  return (
    <div>
      <h1>
        <Trans>Welcome to our platform</Trans>
      </h1>
      <p>
        <Trans>
          Hello {userName}, check out your <a href="/dashboard">dashboard</a> to
          get started.
        </Trans>
      </p>
    </div>
  );
}

El hook useLingui

Para cadenas fuera de JSX (mensajes de alerta, etiquetas aria, valores de atributos o cualquier código imperativo), usa el hook de macro useLingui con literales de plantilla etiquetados:

import { useLingui } from "@lingui/react/macro";

function NotificationButton() {
  const { t } = useLingui();

  const showAlert = () => {
    alert(t`Your changes have been saved.`);
  };

  return (
    <button onClick={showAlert} aria-label={t`Save changes`}>
      <Trans>Save</Trans>
    </button>
  );
}

IDs de mensaje y descripciones

Lingui admite dos enfoques para la identificación de mensajes: IDs generados automáticamente (derivados del contenido del mensaje de origen) y IDs explícitos (claves definidas por el desarrollador). Ambos enfoques funcionan con archivos PO.

import { Trans } from "@lingui/react/macro";

// Auto-generated ID (from message content)
<Trans>Welcome to our platform</Trans>

// Explicit ID (developer-defined key)
<Trans id="nav.welcome">Welcome to our platform</Trans>

Añadir contexto para traductores e IA

Usa la propiedad comment en cualquier macro para añadir una descripción. Este comentario se extrae en el archivo PO como una nota del traductor, proporcionando un contexto crítico sobre dónde y cómo aparece el mensaje.

import { Trans } from "@lingui/react/macro";

<Trans comment="Shown on the homepage hero section above the fold">
  Start building with confidence
</Trans>
Las descripciones de mensajes son especialmente valiosas para la traducción impulsada por IA. Proporcionan el contexto que la IA necesita para desambiguar cadenas cortas de la interfaz de usuario, convirtiendo traducciones genéricas en traducciones precisas y conscientes del contexto.

Pluralización

Lingui utiliza ICU MessageFormat para la pluralización, que admite todas las categorías de plurales CLDR. La macro Plural facilita el manejo de diferentes formas plurales directamente en JSX:

  • Usa el componente Plural con valor, one, other y formas exactas opcionales (_0, _2, etc.).
  • El marcador de posición # se reemplaza automáticamente por el valor plural.
  • l10n.dev genera todas las formas plurales requeridas para cada idioma de destino, incluidos idiomas complejos como el árabe (6 formas), el ruso y el polaco, sin intervención manual.
import { Plural } from "@lingui/react/macro";

function CartSummary({ itemCount }) {
  return (
    <p>
      <Plural
        value={itemCount}
        _0="Your cart is empty"
        one="You have # item in your cart"
        other="You have # items in your cart"
      />
    </p>
  );
}

Inicialización en tiempo de ejecución

Después de extraer y compilar tus mensajes, configura la instancia de i18n y envuelve tu aplicación en el I18nProvider.

Configuración del módulo i18n

Crea un módulo i18n que cargue catálogos de mensajes compilados dinámicamente. El plugin de Lingui Vite permite importaciones directas de archivos PO, que se compilan sobre la marcha durante el desarrollo:

// src/i18n.ts
import { i18n } from "@lingui/core";

export async function loadCatalog(locale: string) {
  const { messages } = await import(`./locales/${locale}/messages.po`);
  i18n.load(locale, messages);
  i18n.activate(locale);
}

// Initialize with default locale
loadCatalog("en");

export default i18n;

Configuración de I18nProvider

Envuelve toda tu aplicación con I18nProvider para que las traducciones estén disponibles para todos los componentes a través del contexto de React:

// src/App.tsx
import { I18nProvider } from "@lingui/react";
import { i18n } from "./i18n";

function App() {
  return (
    <I18nProvider i18n={i18n}>
      <YourAppContent />
    </I18nProvider>
  );
}

Cambio de idioma en tiempo de ejecución

Cambiar de idioma es sencillo: carga el nuevo catálogo, activa la configuración regional y React vuelve a renderizar automáticamente todo el contenido traducido. Aquí tienes un componente de cambio de idioma completo:

import { useState } from "react";
import { loadCatalog } from "./i18n";
import { Trans } from "@lingui/react/macro";

const LANGUAGES = {
  en: "English",
  fr: "Français",
  de: "Deutsch",
  ja: "日本語",
  es: "Español",
};

function LanguageSwitcher() {
  const [currentLocale, setCurrentLocale] = useState("en");

  const handleChange = async (locale: string) => {
    await loadCatalog(locale);
    setCurrentLocale(locale);
  };

  return (
    <select
      value={currentLocale}
      onChange={(e) => handleChange(e.target.value)}
    >
      {Object.entries(LANGUAGES).map(([code, name]) => (
        <option key={code} value={code}>
          {name}
        </option>
      ))}
    </select>
  );
}

Flujo de trabajo de extracción y compilación

La CLI de Lingui proporciona dos comandos clave que forman el núcleo de tu flujo de trabajo de traducción: extract para extraer mensajes del código fuente a catálogos PO, y compile para convertir archivos PO en módulos JavaScript optimizados para producción.

# Extract messages from source code into PO catalogs
npx lingui extract

# Translate your PO files (manually, with a TMS, or with AI)

# Compile PO catalogs into optimized JS modules for production
npx lingui compile
  1. Extract: Escanea tus archivos de origen y crea o actualiza catálogos PO con todos los mensajes traducibles.
  2. Translate: Completa los campos msgstr en tus archivos PO (manualmente, con un TMS o automáticamente con traducción impulsada por IA).
  3. Compile: Convierte catálogos PO en módulos JS ligeros que se cargan en tiempo de ejecución. Solo se incluyen los mensajes traducidos.

Soporte completo de PO en l10n.dev

l10n.dev proporciona soporte nativo para archivos PO, lo que lo convierte en el compañero perfecto para proyectos de Lingui.js. Sube tu catálogo PO de origen y recibe archivos traducidos con precisión:

  • Formato PO nativo: Sube archivos PO directamente; l10n.dev lee las entradas msgid, las traduce y escribe archivos PO correctamente formateados con los valores msgstr correctos.
  • Consciente de ICU MessageFormat: Los marcadores de posición ({name}), etiquetas indexadas (<0>), formas plurales y expresiones de selección se conservan correctamente en todas las traducciones.
  • Traducción con IA consciente del contexto: Los comentarios del traductor (#.) y el contexto del mensaje (msgctxt) son utilizados por nuestra IA para producir traducciones más precisas y conscientes del contexto.
  • Generación de plurales: Se generan todas las formas plurales CLDR requeridas para cada idioma de destino. Los idiomas con reglas plurales complejas (árabe, ruso, polaco) se manejan automáticamente.
  • Actualizaciones por lotes e incrementales: Traduce catálogos completos a la vez o usa la bandera --update para traducir solo los mensajes nuevos y modificados, preservando las traducciones existentes.

Automatiza traducciones con npm

Usa el paquete npm ai-l10n para traducir tus catálogos PO de Lingui desde la línea de comandos o como parte de una canalización CI/CD. Instálalo una vez y luego traduce a cualquier número de idiomas con un solo comando.

# Install the CLI
npm install ai-l10n

# Translate your source PO file to multiple languages
npx ai-l10n translate src/locales/en/messages.po \
  --languages fr,de,ja,zh-CN,es,ko

Integración en tu proceso de compilación

Conecta ai-l10n directamente en tu proceso de compilación de Lingui para que las traducciones estén siempre actualizadas. Combina la extracción, la traducción y la compilación en un solo flujo de trabajo.

A través de scripts de package.json

Añade extract, translate y compile como scripts y encadénalos. El script i18n ejecuta la canalización completa; úsalo en prebuild para asegurar que las traducciones estén siempre actualizadas antes de enviar.

{
  "scripts": {
    "extract": "lingui extract",
    "compile": "lingui compile",
    "translate": "ai-l10n translate src/locales/en/messages.po --languages fr,de,ja,zh-CN,es,ko --update",
    "i18n": "npm run extract && npm run translate && npm run compile",
    "prebuild": "npm run i18n",
    "build": "vite build",
    "dev": "vite"
  }
}

A través de Makefile

Si tu equipo usa Make, declara la extracción, la traducción y la compilación como objetivos separados con las dependencias adecuadas:

LANGUAGES = fr,de,ja,zh-CN,es,ko

extract:
	npx lingui extract

translate:
	npx ai-l10n translate src/locales/en/messages.po --languages $(LANGUAGES) --update

compile:
	npx lingui compile

i18n: extract translate compile

dev: i18n
	npx vite

build: i18n
	npx vite build

Para obtener información sobre la integración CI/CD, actualizaciones incrementales, traducción por lotes en varios archivos y ejemplos de flujo de trabajo de GitHub Actions, consulta la Guía de automatización de localización.

Extensión de VS Code

La extensión de VS Code de l10n.dev lleva la traducción de archivos PO directamente a tu editor. Traduce tus catálogos de Lingui sin salir de VS Code.

Cómo funciona en VS Code:

  1. Abre tu archivo PO de origen (por ejemplo, src/locales/en/messages.po) en el editor.
  2. Haz clic derecho en el editor y selecciona "Translate..." (también funciona con archivos PO).
  3. Elige uno o más idiomas de destino (por ejemplo, francés, japonés, alemán).
  4. La extensión crea archivos PO traducidos en las carpetas de configuración regional correspondientes, listos para compilar.

Empieza a localizar tu aplicación React con Lingui

¿Listo para llegar a usuarios globales? Traduce tus archivos PO de Lingui directamente en el espacio de trabajo de l10n.dev, automatiza con la CLI de npm o traduce directamente dentro de VS Code: