PTC

Internacionalización de Rails (i18n): guía completa

Configure I18n en Rails, organice config/locales/*.yml, automatice las traducciones de YAML con IA y deje que PTC (Private Translation Cloud) revise su aplicación de Rails en ejecución en cada lanzamiento. Al final, tendrá una aplicación de Rails que responde a las URL /es/..., sirve vistas traducidas en 40 o más idiomas y se verifica mediante revisión visual.

Esta guía asume que tiene una aplicación existente en Rails 7 o superior. Los conceptos se aplican a versiones anteriores de Rails con diferencias menores en la API. La gema I18n en sí ha sido estable durante años. Para conocer la historia más amplia de la localización en CI/CD en diferentes stacks, consulte Localización de software con IA diseñada para pipelines de CI/CD.

Configure Rails para cargar locales, reconocer URL y cambiar por solicitud

La internacionalización de Rails requiere tres pasos de configuración. Establezca los locales disponibles, añada el locale a sus URL y haga que Rails cargue el locale correcto por solicitud. También debe instalar la gema rails-i18n para los datos del locale.

Declare los locales disponibles en config/application.rb

En config/application.rb, indique a Rails qué idiomas admite la aplicación y establezca uno predeterminado:

module MyApp
  class Application < Rails::Application
    config.i18n.available_locales = [:en, :es, :fr, :de, :ja]
    config.i18n.default_locale = :en
    config.i18n.fallbacks = true
    config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')]
  end
end

La línea load_path += Dir[...] es la clave. De forma predeterminada, Rails solo carga config/locales/*.yml (con un nivel de profundidad). Añadir el patrón glob recursivo le permite organizar las traducciones por espacio de nombres, modelo o función en subdirectorios.

Añada :locale al ámbito de su URL

Añada un ámbito :locale para que cada idioma tenga su propia ruta, como /en/time o /es/time:

# config/routes.rb
scope "/:locale" do
  get '/time', to: 'home#index', as: :time_display
end

Cambie el locale por solicitud con I18n.with_locale

En ApplicationController, cargue el locale correcto desde la URL e inclúyalo en todos los enlaces generados:

class ApplicationController < ActionController::Base
  around_action :switch_locale

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

  def default_url_options
    { locale: I18n.locale }
  end
end

I18n.with_locale es la forma idiomática de limitar un locale a una solicitud. Establece el locale, ejecuta el bloque, restaura el locale anterior y es thread-safe. default_url_options garantiza que cada URL que genera Rails lleve el locale actual, para que los usuarios se mantengan en el idioma seleccionado mientras navegan.

Instale rails-i18n para los nombres de meses traducidos y las reglas de pluralización

La gema rails-i18n proporciona datos de locale para docenas de idiomas. Esa gema incluye nombres de meses traducidos, reglas de pluralización y mensajes de error predeterminados de Rails. Así no tendrá que traducir ese texto repetitivo usted mismo.

# Gemfile
gem 'rails-i18n'
bundle install

Su aplicación de Rails ahora está completamente configurada para la internacionalización.

Añada un selector de idioma con url_for(locale: :code)

Debido a que default_url_options incluye automáticamente el locale en cada URL generada, su selector solo necesita actualizar el parámetro :locale mientras mantiene al usuario en la misma página.

<%# app/views/layouts/application.html.erb %>
<nav class="language-switcher">
  <%= link_to "English", url_for(locale: :en) %> |
  <%= link_to "Español", url_for(locale: :es) %> |
  <%= link_to "Deutsch", url_for(locale: :de) %>
</nav>

Cada enlace usa url_for(locale: :code) para generar una URL con el locale especificado. Cuando los usuarios hacen clic, switch_locale en ApplicationController detecta el cambio y Rails renderiza la página en el nuevo idioma.

Reemplace el texto incrustado en el código de las vistas con t(:key)

El texto incrustado en el código no aparecerá en sus archivos YAML, lo que significa que no se puede traducir. Use siempre claves de traducción para cualquier texto visible para el usuario.

<%# Correct - uses translation keys %>
<h1><%= t(:hello) %></h1>
<p><%= t(:current_time, time: @time) %></p>
<button id="click-me"><%= t(:refresh) %></button>

<%# Incorrect - hardcoded text %>
<h1>Hello</h1>
<p>Current time: <%= @time %></p>
<button>Refresh</button>

En los controladores (para mensajes flash):

def create
  if @post.save
    redirect_to @post, notice: t('flash.post.created')
  else
    flash.now[:alert] = t('flash.post.error')
    render :new, status: :unprocessable_entity
  end
end

En los modelos (para los mensajes de validación, use las convenciones de Active Model):

# config/locales/en.yml
en:
  activerecord:
    attributes:
      post:
        title: "Title"
    errors:
      models:
        post:
          attributes:
            title:
              blank: "is required"

Interpole variables con %{name}

%{name} en el YAML se reemplaza por el valor que usted pasa a t():

current_time: "Current time: %{time}"
<%= t(:current_time, time: @time) %>

Use la búsqueda diferida (.key) para traducciones con ámbito de vista

Cuando sus claves de traducción estén organizadas para coincidir con la estructura de carpetas de sus vistas, use un punto inicial. Rails completa el prefijo a partir de la vista actual:

<%# Instead of this: %>
<%= t('home.index.hello') %>

<%# Use this: %>
<%= t('.hello') %>

Rails detecta que usted está en home/index.html.erb y antepone home.index.. Si cambia el nombre o reubica una vista, las rutas de búsqueda diferida se actualizan automáticamente.

Organice config/locales/ por función en lugar de un único en.yml gigante

Para una aplicación del mundo real, un único en.yml gigante se vuelve imposible de mantener. Organice por función:

config/locales/
  en.yml                       # global / shared keys
  models/
    post.en.yml
  views/
    posts.en.yml
    home.en.yml
  flash.en.yml

Un ejemplo de config/locales/views/posts.en.yml:

en:
  posts:
    index:
      title: "All Posts"
      empty: "No posts yet"
    new:
      title: "Create a New Post"
    show:
      published_at: "Published %{date}"
      comments_count:
        zero: "No comments yet"
        one: "1 comment"
        other: "%{count} comments"

Convenciones:

  • Las claves anidadas agrupan cadenas relacionadas y permiten la búsqueda diferida.
  • Interpolación %{name} para variables en línea.
  • Claves de pluralización zero / one / other para sustantivos contables. Rails enruta a la clave correcta basándose en count:: t('posts.show.comments_count', count: 5).

Añada también las cadenas de JavaScript a YAML

Rails no extrae automáticamente el texto de los archivos JavaScript. Cualquier texto del lado del cliente (alertas, información sobre herramientas, mensajes de confirmación) debe residir en su YAML para que se traduzca junto con todo lo demás:

en:
  confirm: "Are you sure?"

Cuando traduzca con PTC en la siguiente sección, estas cadenas viajarán con el resto.

Traduzca config/locales/*.en.yml con PTC en 4 pasos

Una vez que sus archivos de traducción estén en su lugar, necesitará versiones para cada idioma de destino. PTC se encarga de esto:

  1. Inicie un proyecto de PTC y elija inglés como origen. La prueba cubre 20.000 palabras en 2 idiomas, sin tarjeta de crédito.
  2. Suba sus archivos config/locales/*.en.yml. PTC analiza el YAML, reconoce las claves de pluralización de Rails (zero, one, other, few, many) y conserva las interpolaciones %{name}.
  3. Añada una breve descripción de su aplicación de Rails y su público. PTC usa este contexto para traducir con el tono y la terminología correctos.
  4. Elija los idiomas de destino y confirme. PTC produce posts.es.yml, posts.fr.yml, posts.de.yml, estructuralmente idénticos al origen con los valores traducidos. Las formas plurales se generan por idioma. El polaco obtiene one / few / many / other. El japonés obtiene solo other.

Vuelva a colocar los archivos en config/locales/views/, reinicie su servidor de Rails y la aplicación servirá los nuevos idiomas.

Para proyectos basados en Git, conecte PTC a su repositorio. Las nuevas cadenas en cualquier *.en.yml activan la traducción automática. PTC abre un merge request con los archivos actualizados en los idiomas de destino. Consulte la referencia de la API de PTC para ver los endpoints subyacentes.

Use I18n.with_locale en trabajos en segundo plano, mailers y tareas cron

El patrón I18n.with_locale(locale, &block) es fundamental para cualquier código que se ejecute fuera de una solicitud normal. Eso incluye trabajos en segundo plano, tareas cron y mailers.

# Background job: send an email in the user's preferred locale
class WelcomeEmailJob < ApplicationJob
  def perform(user_id)
    user = User.find(user_id)
    I18n.with_locale(user.preferred_locale) do
      UserMailer.welcome(user).deliver_now
    end
  end
end

Sin with_locale, el trabajo se ejecuta en el locale que estuviera activo cuando se inició el worker. Generalmente :en, independientemente de la preferencia del usuario. Con él, el correo electrónico se renderiza en el idioma del usuario y el locale se restablece cuando termina el bloque.

Exporte traducciones de Rails a JSON con i18n-js para uso del lado del cliente

Las páginas renderizadas por Rails obtienen las traducciones mediante t() en ERB. El JavaScript que se ejecuta en el navegador no ve el I18n de Rails directamente. El patrón más limpio usa la gema i18n-js para exportar las traducciones como JSON y cargarlas del lado del cliente.

# Gemfile
gem 'i18n-js'
bundle install
i18n init

Actualice la configuración generada para exportar las traducciones a public/locales.json:

# config/i18n.rb
require "i18n-js"

I18n::JS.config do |config|
  config.export_i18n_js = false
  config.translations_path = "public/locales.json"
end

Genere el archivo JSON:

i18n export

Esto lee todos sus archivos YAML (en.yml, es.yml, de.yml) y escribe public/locales.json con cada traducción en un formato legible por JS.

Fije i18n-js con Importmap de Rails 7 o superior:

# config/importmap.rb
pin "i18n-js", to: "https://esm.sh/i18n-js@latest/dist/import/index.js"
pin "load_locale", to: "load_locale.js"

Cree un cargador:

// app/javascript/load_locale.js
export async function loadLocale() {
  const response = await fetch('/locales.json');
  return await response.json();
}

Pase el locale actual a JavaScript a través de la etiqueta <body>:

<%# app/views/layouts/application.html.erb %>
<body data-locale="<%= I18n.locale %>">

Luego, use las traducciones en su JavaScript:

// app/javascript/application.js
import { I18n } from "i18n-js";
import { loadLocale } from "./load_locale";

document.addEventListener('turbo:load', async () => {
  const translations = await loadLocale();
  const i18n = new I18n(translations);
  i18n.locale = document.body.dataset['locale'];

  if (confirm(i18n.t('confirm'))) {
    // User clicked OK
  }
});

i18n.t() funciona como el helper t de Rails. Cuando los usuarios cambian de idioma, JavaScript usa las traducciones correctas del atributo data-locale.

Traduzca el contenido de ActiveRecord con la API de PTC

El patrón anterior traduce las cadenas estáticas en sus archivos YAML. El contenido de ActiveRecord (publicaciones de usuarios, comentarios, descripciones de productos almacenadas como entrada del usuario) no aparece en YAML y necesita un enfoque diferente. La API REST de PTC traduce este contenido bajo demanda con autenticación Bearer, usando el mismo glosario y voz de marca que sus archivos config/locales/*.yml. Envíe su contenido a PTC mediante POST y, a continuación, reciba un callback cuando las traducciones estén listas o consulte el estado desde un trabajo en segundo plano.

Localice fechas, números y moneda con los helpers de Rails

Fechas y horas. Use el helper l (abreviatura de localize):

<%= l Time.now, format: :long %>

La gema rails-i18n proporciona formatos de fecha y hora predeterminados para muchos idiomas, incluyendo nombres de meses traducidos y formato específico del locale. Puede definir formatos personalizados en sus archivos YAML.

Números y moneda. Rails incluye helpers sensibles al locale:

<%= number_to_currency(100, locale: :es) %>   <!-- 100,00 € -->
<%= number_with_delimiter(1000000) %>          <!-- 1,000,000 -->

Estos respetan las convenciones del locale para los separadores decimales, los delimitadores de miles y los símbolos de moneda.

Vistas localizadas por idioma. Para páginas con contenido significativamente diferente por locale, cree archivos de vista separados. Rails renderiza la vista adecuada basándose en el locale actual:

app/views/pages/
  about.html.erb       <!-- Default -->
  about.es.html.erb    <!-- Spanish version -->
  about.de.html.erb    <!-- German version -->

Revisión visual de la traducción de su aplicación de Rails en ejecución: publique sin control de calidad manual en cada lanzamiento

Después de que PTC traduzca su config/locales/*.yml, la aplicación de Rails renderizada aún necesita verificación. Una etiqueta traducida puede desbordar un botón en alemán. Un mensaje de validación en francés puede usar la forma gramatical incorrecta. Una cadena en inglés incrustada en el código en una plantilla ERB (sin llamada a t()) se renderizará sin traducir sin importar cuántos idiomas publique.

El AI Visual QA de PTC sustituye la pasada de control de calidad manual. Para las aplicaciones de Rails (basadas en navegador), instale la extensión de navegador de PTC y grabe un recorrido por las pantallas críticas de su aplicación (inicio de sesión, flujos principales, páginas de administración). A partir de entonces, PTC vuelve a ejecutar la grabación en cada idioma de destino después de cada actualización de las traducciones, captura cada pantalla y le informa:

  • Correcciones en los archivos YAML cuando PTC los controla. PTC vuelve a traducir una acepción incorrecta, elige un sinónimo más corto o regenera una forma plural.
  • Prompts para Cursor o Claude Code cuando el problema reside en su código Ruby o ERB. Una cadena en inglés incrustada en el código fuera de t(), un mensaje flash construido mediante concatenación en lugar de interpolación o un helper que debería usar I18n.l para el formato de fecha.

El resultado: una aplicación de Rails multilingüe verificada en cada lanzamiento. No solo YAML traducido.

Traduzca notas de lanzamiento, mailers de Devise y páginas de marketing

Sus notas de lanzamiento, los correos electrónicos dirigidos al cliente enviados a través de Devise o Action Mailer y las páginas de marketing residen fuera de config/locales. La función Paste to Translate de PTC procesa ese texto en el mismo proyecto. Pegue el texto de origen en el panel de control de PTC, elija los idiomas de destino y reciba traducciones que usan el mismo glosario y voz de marca que sus traducciones de YAML.

Traduzca sus archivos config/locales/*.yml con PTC

Comience su prueba de 30 días: 20.000 palabras en 2 idiomas, sin tarjeta de crédito. Suba sus archivos YAML, obtenga versiones traducidas en minutos y luego instale la extensión de navegador para verificar su aplicación de Rails en ejecución.

Relacionado: