La CLI de Lingo.dev traduce archivos YAML de Rails config/locales a través de un motor de localización configurado. Rails incorpora la API de i18n de serie, por lo que el texto traducible de tu aplicación se guarda 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 acompaña de principio a fin en la localización de una aplicación Rails: cómo configurar la CLI, organizar archivos YAML por idioma, cambiar el idioma en cada solicitud y automatizar las traducciones con GitHub Actions.
Repositorio de ejemplo
Clona o haz un fork de lingodotdev/ruby-on-rails-localization-example para seguir el proceso paso a paso. El repositorio incluye una aplicación Rails funcional con archivos YAML config/locales, una configuración de la CLI de Lingo.dev y un flujo de trabajo de GitHub Actions.
Cómo funciona la localización en Rails#
Rails lee las traducciones desde los archivos YAML de 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 utiliza con I18n.t.
| Capa | Qué contiene | Archivo de ejemplo |
|---|---|---|
| Textos de la interfaz | Botones, etiquetas, mensajes flash | config/locales/en.yml |
| Textos del mailer | Asuntos y cuerpos de ActionMailer | config/locales/mailers.en.yml |
| Errores del modelo | Mensajes de validación y nombres de atributos | config/locales/activerecord.en.yml |
La primera clave de cada archivo YAML de Rails es el propio código de idioma: en:, es:, fr:. El bucket yaml-root-key de la CLI entiende esta estructura: elimina el prefijo del idioma antes de enviar el contenido a tu motor de localización y, después, escribe un archivo paralelo con el código de idioma de destino como nueva clave raíz. Se conservan las claves anidadas, los tokens de interpolación %{name} y las categorías de plural de CLDR (zero/one/two/few/many/other).
Requisitos previos#
Crea un motor de localización
Cada ejecución de la CLI envía el contenido a través de un motor de localización: la configuración que determina qué modelo LLM, glossary, voz de marca e instructions se aplican. Crea uno en el panel de Lingo.dev y genera una clave de API.
Comprueba Ruby y Rails
Esta guía está pensada para Rails 7.2 o superior, que requiere Ruby 3.1 o superior. Comprueba qué versiones tienes:
ruby -v
rails -vComprueba Node.js
La CLI requiere Node.js 18 o superior:
node -vConfigura i18n en Rails
Esta guía da por hecho que tu aplicación ya guarda las traducciones en config/locales/*.yml. Si tienes cadenas hardcodeadas en vistas o controladores, extráelas primero a llamadas de t(). Por ejemplo, sustituye:
<h1>Welcome</h1>por:
<h1><%= t(".welcome") %></h1>y luego añade la clave correspondiente en config/locales/en.yml. Consulta la guía de internacionalización de Rails para ver todos los pasos de la migración.
Organiza los archivos de traducción#
Rails carga automáticamente todos los archivos *.yml que encuentre en config/locales/. Mantén el idioma de origen junto a sus versiones traducidas para que el directorio actúe como fuente única de verdad:
config/locales/
en.yml # Source locale
es.yml # Generated by Lingo.dev
fr.yml
de.ymlUn archivo en.yml típico combina cadenas simples, espacios de nombres anidados, interpolación %{name} y pluralización:
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#
Crea un archivo i18n.json en la raíz del proyecto. Declara un bucket yaml-root-key que apunte a los archivos de idioma:
{
"$schema": "https://lingo.dev/schema/i18n.json",
"version": "1.15",
"locale": {
"source": "en",
"targets": ["es", "fr", "de"]
},
"buckets": {
"yaml-root-key": {
"include": ["config/locales/[locale].yml"]
}
}
}El marcador [locale] se resuelve como cada código de idioma configurado. Con source: "en", la CLI lee config/locales/en.yml y escribe los archivos traducidos en config/locales/es.yml, config/locales/fr.yml y config/locales/de.yml.
Rails carga sin problema mailers.en.yml, pages.en.yml y así sucesivamente junto a en.yml. Añade patrones adicionales al array include de tu bucket yaml-root-key:
{
"buckets": {
"yaml-root-key": {
"include": [
"config/locales/[locale].yml",
"config/locales/mailers.[locale].yml",
"config/locales/pages.[locale].yml"
]
}
}
}Configura Rails para varios idiomas#
Indica a Rails qué idiomas están disponibles y cuál debe usar por defecto. En config/application.rb:
module YourApp
class Application < Rails::Application
config.i18n.available_locales = [:en, :es, :fr, :de]
config.i18n.default_locale = :en
config.i18n.fallbacks = [:en]
end
endSelecciona el idioma de cada solicitud en ApplicationController a partir de un parámetro de la URL o de la cabecera Accept-Language:
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
endMuestra las traducciones en las vistas#
Usa los helpers t y l en las plantillas ERB. Un punto al principio 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:
<h1><%= t(".welcome", name: @user_name) %></h1>
<p><%= t("notifications.unread", count: @unread_count) %></p>
<%= link_to t(".cta"), signup_path, class: "btn-primary" %>Añade un selector de idioma a tu layout:
<nav>
<% I18n.available_locales.each do |locale| %>
<%= link_to locale.upcase, url_for(locale: locale) %>
<% end %>
</nav>Traduce en local#
Configura tu clave de API y ejecuta la CLI:
export LINGO_API_KEY="your-api-key"
npx lingo.dev@latest runLa CLI lee todos los archivos que coinciden con los patrones de tu bucket, identifica las entradas sin traducir mediante el lockfile, traduce el delta a través de tu motor de localización y escribe los resultados en cada archivo del idioma de destino. Se conservan la clave raíz del idioma, los espacios de nombres anidados, los tokens de interpolación con formato %{name} y las categorías de plural; solo cambia el texto traducible.
Para traducir a un idioma concreto durante el desarrollo:
npx lingo.dev@latest run --target-locale esReinicia el servidor de Rails después de la primera ejecución de traducción para que se carguen los nuevos archivos YAML:
bin/rails serverVisita /es para ver el resultado 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:
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 sitio. 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 con GitHub Actions#
Añade un archivo de flujo de trabajo en .github/workflows/translate.yml para traducir con cada push:
Las traducciones se confirman directamente en main: sin fricción, ideal para equipos pequeños.
name: Translate
on:
push:
branches: [main]
permissions:
contents: write
jobs:
translate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Lingo.dev
uses: lingodotdev/lingo.dev@main
with:
api-key: ${{ secrets.LINGODOTDEV_API_KEY }}Guarda tu clave de API como LINGODOTDEV_API_KEY en Settings > Secrets and variables > Actions dentro de tu repositorio de GitHub.
Verifica antes de desplegar#
Usa la marca --frozen como control previo al despliegue para asegurarte de que no se publique contenido sin traducir en producción. La CLI termina con un estado distinto de cero si alguna entrada necesita traducción:
npx lingo.dev@latest run --frozenAñádelo como un paso de CI independiente antes de la precompilación de assets o de la build del contenedor:
- name: Verify translations
run: npx lingo.dev@latest run --frozen
- name: Precompile assets
run: bundle exec rails assets:precompile