|
Documentación
Agenda una demoPlataforma
PlataformaMCPCLIAPIFlujos de trabajo
Guías
Registro de cambios

Localización

  • Resumen
  • API de traducción
  • Localización de apps web
  • Localización de apps móviles
  • iOS con String Catalogs
  • Android con strings.xml
  • Localización de emails
  • Contenido estático (p. ej., .md, .json)
  • Next.js con Markdoc
  • Rails con i18n

Flujos de trabajo

  • Configuración del motor con MCP
  • Triaje de Jira
  • CI/CD

Localización de Ruby on Rails con la API de i18n

La CLI de Lingo.dev traduce archivos YAML de Rails config/locales mediante un motor de localización configurado. Rails trae la API de i18n integrada de forma nativa: el texto traducible de tu app vive en archivos YAML por idioma. Lingo.dev encaja en tu pipeline actual sin añadir dependencias en tiempo de ejecución.

Esta guía te lleva paso a paso por la localización completa de una app de Rails: cómo configurar la CLI, organizar archivos YAML por idioma, cambiar de idioma en cada solicitud y automatizar las traducciones en CI.

Repositorio de demo

Clona o haz fork de lingodotdev/ruby-on-rails-localization-example para seguir el recorrido. Es una app de Rails funcional con archivos YAML de config/locales, un .lingo/config.json ya versionado y traducciones listas, para que puedas ver la configuración junto con el resultado que genera.

Cómo funciona la localización en Rails#

Rails lee las traducciones desde los archivos YAML en config/locales/. Cada archivo usa un código de idioma como clave raíz y contiene claves anidadas que reflejan las rutas de búsqueda que tu código usa con I18n.t.

CapaQué contieneArchivo de ejemplo
Textos de UIBotones, etiquetas, mensajes flashconfig/locales/en.yml
Copys de correoAsuntos y cuerpos para ActionMailerconfig/locales/mailers.en.yml
Errores del modeloMensajes de validación y nombres de atributosconfig/locales/activerecord.en.yml

La primera clave de cada archivo YAML de Rails es el propio código de idioma: en:, es:, fr:. Rails indexa las traducciones por esa clave raíz, no por el nombre del archivo: carga todos los archivos dentro de config/locales/ y guarda el contenido de cada uno bajo la raíz que declare. Así que un es.yml que todavía tiene en: como raíz no se ignora: se fusiona dentro del espacio de nombres de en. El español termina sin traducciones y las de inglés se sobrescriben silenciosamente.

Por eso, traducir este formato implica reescribir esa clave, no solo los valores. El formato yaml-root-key hace exactamente eso: recorre el árbol debajo de la clave raíz, traduce únicamente los valores de texto y escribe el archivo de destino con la raíz del idioma objetivo. Las claves anidadas, los tokens de interpolación %{name} y las categorías de plural de CLDR (zero/one/two/few/many/other) forman parte de la estructura, así que se conservan intactos, igual que los comentarios y las anchors de YAML.

Requisitos previos#

1

Crea un motor de localización

Cada ejecución de CLI envía el contenido a través de un motor de localización: la configuración que determina qué modelo de LLM, glossary, voz de marca y rules se aplican. Crea uno en el panel de Lingo.dev y genera una API key.

2

Verifica Ruby y Rails

Esta guía está pensada para Rails 7.2 o superior, que requiere Ruby 3.1 o superior. Revisa tus versiones:

bash
ruby -v
rails -v
3

Verifica Node.js

La CLI requiere Node.js 22 o superior:

bash
node -v
4

Configura i18n en Rails

Esta guía asume que tu app ya guarda las traducciones en config/locales/*.yml. Si tienes cadenas hardcodeadas en vistas o controladores, primero extráelas a llamadas de t(). Por ejemplo, reemplaza:

erb
<h1>Welcome</h1>

por:

erb
<h1><%= t(".welcome") %></h1>

y luego agrega la clave correspondiente en config/locales/en.yml. Consulta la guía de internacionalización de Rails para ver todos los pasos de migración.

Organiza los archivos de traducción#

Rails carga automáticamente cada archivo *.yml dentro de config/locales/. Mantén el idioma de origen junto a sus versiones traducidas para que el directorio funcione como fuente única de verdad:

text
config/locales/
  en.yml          # Source locale
  es.yml          # Generated by Lingo.dev
  fr.yml
  de.yml

Un archivo en.yml típico combina cadenas simples, espacios de nombres anidados, interpolación %{name} y pluralización:

yaml
en:
  hello: "Hello"
  home:
    welcome: "Welcome, %{name}!"
    cta: "Get started"
  notifications:
    unread:
      zero: "No unread notifications"
      one: "1 unread notification"
      other: "%{count} unread notifications"
  errors:
    messages:
      blank: "can't be blank"

Configura la CLI#

Instala la CLI, autentícate y vincula el proyecto a tu motor:

bash
npm install -g @lingo.dev/cli
lingo login
lingo init
lingo link

lingo init y lingo link crean .lingo/config.json con tus idiomas y el orgId y engineId de tu motor. Haz commit de ese archivo, junto con .lingo/lock.json, para que todas las máquinas y cada ejecución de CI compartan el mismo estado.

Haz que una entrada de files[] apunte al archivo del idioma de origen y define el formato de forma explícita:

json
{
  "orgId": "org_...",
  "engineId": "eng_...",
  "sourceLocale": "en",
  "targetLocales": ["es", "fr", "de"],
  "files": [{ "pattern": "config/locales/en.yml", "format": "yaml-root-key" }]
}

Aquí, "format": "yaml-root-key" es obligatorio, no opcional. Una ruta .yml no puede indicar si su clave raíz corresponde a un idioma o a una configuración común, así que la CLI no intenta adivinarlo: si omites format, el archivo se trata como yaml genérico, lo que traduce los valores y deja la raíz en en:: el fallo silencioso descrito arriba.

Los destinos se derivan de la ruta de origen, así que config/locales/en.yml genera config/locales/es.yml, config/locales/fr.yml y config/locales/de.yml.

Rails también carga archivos por dominio junto con en.yml: devise.en.yml, mailers.en.yml, activerecord.en.yml. Agrega una segunda entrada con un glob para incluirlos:

json
{
  "files": [
    { "pattern": "config/locales/en.yml", "format": "yaml-root-key" },
    { "pattern": "config/locales/*.en.yml", "format": "yaml-root-key" }
  ]
}

Los dos patrones no se superponen: el primero solo coincide con en.yml, y el segundo solo con archivos que terminan en .en.yml, así que archivos ya traducidos como es.yml y devise.es.yml nunca se toman como origen. devise.en.yml genera devise.es.yml.

Configura Rails para varios idiomas#

Indícale a Rails qué idiomas están disponibles y cuál debe usar por defecto. En config/application.rb:

ruby
module YourApp
  class Application < Rails::Application
    config.i18n.available_locales = [:en, :es, :fr, :de]
    config.i18n.default_locale = :en
    config.i18n.fallbacks = [:en]
  end
end

Selecciona el idioma de la solicitud en ApplicationController a partir de un parámetro en la URL o del encabezado Accept-Language:

ruby
class ApplicationController < ActionController::Base
  around_action :switch_locale

  private

  def switch_locale(&action)
    locale = params[:locale] || http_accept_locale || I18n.default_locale
    I18n.with_locale(locale, &action)
  end

  def http_accept_locale
    header = request.headers["Accept-Language"].to_s
    header.scan(/[a-z]{2}/).find { |l| I18n.available_locales.map(&:to_s).include?(l) }
  end

  def default_url_options
    { locale: I18n.locale }
  end
end

Renderiza traducciones en las vistas#

Usa los helpers t y l en las plantillas ERB. Un punto al inicio de la clave se resuelve en función de la ruta de la vista actual, lo que mantiene las claves de traducción junto a las plantillas que las usan:

erb
<h1><%= t(".welcome", name: @user_name) %></h1>
<p><%= t("notifications.unread", count: @unread_count) %></p>
<%= link_to t(".cta"), signup_path, class: "btn-primary" %>

Agrega un selector de idioma a tu layout:

erb
<nav>
  <% I18n.available_locales.each do |locale| %>
    <%= link_to locale.upcase, url_for(locale: locale) %>
  <% end %>
</nav>

Traduce localmente#

bash
lingo push --wait

push sube los archivos de origen, los procesa con tu motor de localización y vuelve a escribir los archivos traducidos. --wait hace que el comando espere hasta que los resultados estén listos; vale la pena pasarlo explícitamente, porque una próxima versión cambiará el valor predeterminado para que push envíe la ejecución y regrese de inmediato, dejándote recuperar los resultados con lingo pull.

Las ejecuciones posteriores traducen solo el delta: push genera un hash del origen y lo compara con .lingo/lock.json, así que las entradas sin cambios no cuestan nada. La primera ejecución en un proyecto —o después de agregar un idioma— necesita todo el corpus:

bash
lingo push --backfill-missing

Limita una ejecución a un subconjunto de archivos pasando un glob:

bash
lingo push "config/locales/**"

Para traer resultados generados en otro lugar —otra máquina o CI— ejecuta lingo pull.

Reinicia el servidor de Rails después de la primera ejecución de traducción para que se carguen los nuevos archivos YAML:

bash
bin/rails server

Visita /es para ver la versión en español.

Plurales#

Rails usa categorías de plural de CLDR: zero, one, two, few, many, other. Pasa un argumento count: a I18n.t y Rails elegirá la clave correspondiente:

ruby
t("notifications.unread", count: 0)   # => "No unread notifications"
t("notifications.unread", count: 1)   # => "1 unread notification"
t("notifications.unread", count: 12)  # => "12 unread notifications"

La CLI traduce cada variante plural en su lugar. Si tu idioma de destino necesita más categorías que one/other en inglés, defínelas en tu archivo fuente en.yml.

Automatiza en CI#

La Lingo.dev GitHub App traduce en cada push y pull request, del lado del servidor: sin runner y sin guardar una API key en tu repositorio. Resuelve el motor a partir del .lingo/config.json versionado, así que orgId y engineId deben estar presentes en el archivo que subas con commit.

Si prefieres ejecutar la CLI en tu propio pipeline —GitHub Actions, GitLab CI, Bitbucket Pipelines— consulta CI/CD Workflows. Proporciona LINGO_API_KEY como secreto y ejecuta lingo push --wait como cualquier otro paso de build.

Verifica antes de desplegar#

Usa lingo check como control de despliegue para que no llegue contenido sin traducir a producción. Devuelve un estado distinto de cero si alguna entrada todavía necesita traducción y no escribe nada:

bash
lingo check

Agrégalo como un paso de CI independiente antes de la precompilación de assets o de la construcción del contenedor:

yaml
- name: Verify translations
  run: lingo check
- name: Precompile assets
  run: bundle exec rails assets:precompile

Próximos pasos#

Localización de contenido estático
Markdown, MDX, JSON, YAML y otros formatos de archivos estáticos
Localización de apps web
Patrones de textos de UI en frameworks web comunes
Flujos de trabajo de CI/CD
Patrones para GitHub Actions, GitLab CI y Bitbucket Pipelines
Glosarios
Protege los nombres de marca y los términos técnicos para que no se traduzcan

¿Te resultó útil esta página?

Max PrilutskiyMax Prilutskiy·Actualizado hace 8 días·7 min de lectura