Marketing internacional

Internacionalização do Rails: das URLs ao JavaScript

Internacionalização do Rails: das URLs ao JavaScript
Atualizado em
18 de maio de 2026

O Rails vem com uma estrutura de internacionalização integrada. Não é preciso muito mais para começar — a API de internacionalização faz parte da pilha e lida bem com o básico: tradução de strings estáticas, formatação de datas e números e gerenciamento da pluralização entre diferentes configurações regionais.

Mas “integrado” não significa “completo”. No momento em que suas necessidades se estendem a URLs localizadas, traduções em JavaScript ou SEO multilíngue, você está indo além do que o Rails oferece nativamente. Essas lacunas exigem decisões arquitetônicas deliberadas.

Vamos examinar as duas camadas: o que a API I18n do Rails cuida e onde você precisará implementar – ou delegar.

O que o Rails I18n abrange e onde ele se limita

A API I18n oferece dois métodos principais: I18n.t para traduzir strings e I18n.l para localizar datas e números. Ambos leem arquivos YAML ou Ruby na pasta config/locales/, e o Rails os carrega automaticamente na inicialização.

Por padrão, isso abrange strings estáticas da interface do usuário, formatação de datas e números e mensagens de validação do ActiveRecord. Para a maioria dos projetos que envolvem a tradução de um idioma para outro, isso já é suficiente para o lançamento.

As lacunas ficam evidentes rapidamente à medida que se avança.

O Rails I18n não oferece suporte à estrutura de URLs: não há rotas localizadas, detecção de subdomínios nem prefixos de caminho. Ele não possui nenhum mecanismo para traduzir conteúdos armazenados no banco de dados, como nomes de produtos ou posts de blog. Os arquivos JavaScript ficam totalmente fora do pipeline. E o SEO multilíngue — que inclui elementos como tags hreflang, slugs traduzidos e mapas de site específicos para cada idioma — exige um trabalho à parte, que a estrutura não aborda.

É preciso saber onde fica o limite antes de começar a construir.

Estabelecendo as bases para a internacionalização

Você pode começar usando a gem rails-i18n.

O Rails fornece apenas dados de localização em inglês; portanto, sem eles, a função `I18n.l(Date.today)` falha em localizações que não sejam em inglês, e as strings do nível do framework, como as mensagens de validação do Active Record, permanecem em inglês, independentemente da localização atual.

# Gemfile

gem "rails-i18n"

Em seguida, configure as configurações padrão do seu aplicativo:

# config/application.rb

config.i18n.default_locale = :en

config.i18n.available_locales = [:en, :fr]

config.i18n.enforce_available_locales = true

O parâmetro `enforce_available_locales = true` gera um erro se o seu aplicativo tentar definir uma localidade fora dessa lista. Sem ele, um erro de digitação ou um parâmetro de URL malformado define silenciosamente uma localidade não suportada em produção.

Embora o Rails moderno faça a varredura em um nível de profundidade, muitas vezes ele não detecta pastas profundamente aninhadas (como config/locales/views/products/). Adicionar esta linha garante que todos os subdiretórios sejam incluídos à medida que sua aplicação cresce:

config.i18n.load_path += Dir[Rails.root.join("config", "locales", "**", "*.{rb,yml}")]

Isso permite dividir os arquivos de tradução por domínio:

config/locales/  
	en/    
		models.yml    
		visualizações.yml    
		mailers.yml  
	fr/    
		models.yml    
		visualizações.yml    
		mailers.yml

⚠️ O YAML interpreta valores como true e false como booleanos. Se você precisar deles como texto literal, coloque-os entre aspas explicitamente. As versões mais recentes do Ruby/YAML agora tratam yes e no como strings, mas colocá-los entre aspas continua sendo um hábito seguro por uma questão de compatibilidade:

pt:  
	respostas:    
		afirmativo: "sim"    
		negativo: "não"

Isso detecta um tipo de erro que só ocorre quando uma tradução retorna “true” em vez de “sim” e sua visualização não exibe nada ou, pior ainda, exibe a string “true”.

Auxiliares de tradução e pesquisa diferida nas visualizações

Nas visualizações, t e l são os dois auxiliares que você usará constantemente.

O `l` localiza datas, horas e números de acordo com a configuração regional atual. Com o `rails-i18n` instalado, as definições de formato para mais de 100 configurações regionais já vêm incluídas. Sem ele, chamar `l(Date.today)` em uma configuração regional que não seja o inglês geralmente retornará uma mensagem do tipo “tradução ausente” ou uma data sem formatação, já que o Rails não possui os padrões de formato localizados necessários.

<%= l(Date.today) %>

<%= l(Date.today, format: :long) %>

t traduz strings por chave. A forma completa é t("products.index.title"), mas nas visualizações você pode usar a sintaxe abreviada de pesquisa diferida:

<%= t(".title") %>

O ponto inicial indica ao Rails para resolver a chave em relação ao caminho da visualização atual. Em app/views/products/index.html.erb, t(".title") é expandido automaticamente para t("products.index.title"). Isso mantém as chaves curtas e garante uma convenção de nomenclatura consistente sem esforço adicional.

For interpolation, use %{variable} in your YAML and pass the value as a keyword argument:

en:  
	welcome: "Hello, %{name}"
<%= t(".welcome", name: current_user.name) %>

Se uma tradução contiver HTML em que você confia, acrescente _html ao nome da chave. O Rails a marca automaticamente como segura, sem a necessidade de chamar o método html_safe.

en:  
	notice_html: "Please <strong>confirm</strong> your email."

A pesquisa preguiçosa só funciona quando o Rails consegue inferir o caminho da visualização, o que significa que ela não funciona em tarefas em segundo plano e controladores de API. Nesses contextos, use sempre a chave completa.

Escolhendo uma estratégia de detecção de local

Antes de escrever qualquer código de detecção de localidade, escolha uma estratégia. Existem cinco abordagens principais, e a escolha certa depende da estrutura do seu aplicativo e dos requisitos de SEO.

Estratégia Exemplo Melhor para
Parâmetro de URL /produtos?locale=fr Ferramentas internas, prototipagem rápida
Prefixo do caminho /fr/produtos Sites públicos que necessitam de SEO multilíngue
Subdomínio fr.example.com Marcas regionais distintas
TLD example.fr Domínios específicos de cada país que você já possui
Preferência de banco de dados Armazenado no registro do usuário Aplicativos autenticados com configurações do usuário

O prefixo de caminho, como /fr/products, é a opção mais comum para aplicativos Rails voltados para o público. Ele mantém a localização explícita em cada URL, o que permite que os mecanismos de busca indexem cada idioma de forma independente.

As estratégias de subdomínios e TLDs funcionam bem quando se busca uma identidade regional mais forte, mas acarretam uma sobrecarga na configuração do DNS e nos certificados SSL.

Parâmetros de URL, como /products?locale=fr, são adequados para ferramentas internas nas quais o SEO não é relevante.

As preferências armazenadas no banco de dados funcionam para aplicativos autenticados nos quais a configuração regional acompanha o usuário, e não a URL.

Seja qual for a estratégia escolhida, há um erro de implementação que causa pequenos erros de produção: usar `I18n.locale =` diretamente.

# Don't do this

before_action { I18n.locale = params[:locale] }

I18n.locale = grava em Thread.current.

Se você estiver usando um servidor web Puma, ele reutiliza threads entre as solicitações. Se uma solicitação não definir explicitamente a localidade, ela herdará a configuração deixada pela solicitação anterior.

No desenvolvimento local com um único segmento de execução, isso nunca ocorre. Em produção, isso causa respostas intermitentes em idioma incorreto, difíceis de reproduzir e ainda mais difíceis de rastrear.

Em vez disso, use `I18n.with_locale` dentro de uma ação `around_action`:

around_action :switch_locale‍d


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

with_locale restaura a localidade anterior após o bloqueio ser encerrado, independentemente de como a solicitação termine.

Implementação de rotas localizadas e detecção de subdomínios

Defina suas rotas na pasta /:locale e substitua o arquivo default_url_options para que o Rails insira automaticamente a localidade atual no início de cada helper de URL:

# config/routes.rb
scope "/:locale" do
  resources :products
  root "home#index"
end

# app/controllers/application_controller.rb
around_action :switch_locale

def switch_locale(&action)
  locale = params[:locale]
  # Fallback to default if the param is missing or unsupported
  valid_locale = I18n.available_locales.map(&:to_s).include?(locale) ? locale : I18n.default_locale
  I18n.with_locale(valid_locale, &action)
end

def default_url_options
  { locale: I18n.locale }
end

Com a opção `default_url_options` definida, a URL `products_path` é renderizada automaticamente como `/fr/products ` quando a localização atual é :fr.

Se você quiser que a localidade padrão omita o prefixo, torne o segmento opcional com o escopo "(:locale)". Isso direciona para /products em inglês e para /fr/products em francês, mas cria ambiguidade. Um caminho como /about poderia corresponder tanto a uma localidade ausente quanto a um controlador chamado about, dependendo da ordem das rotas.

Para a detecção de subdomínios, leia o valor de `request.subdomains.first` e verifique se ele está de acordo com `available_locales` antes de definir qualquer coisa:

def extrair_localização_do_subdomínio
  subdomain = request.subdomains.first
  retornar nil se subdomain.blank? || subdomain == "www"
  subdomínio se I18n.available_locales.map(&:to_s).include?(subdomain)
end

A verificação do www impede que ele seja tratado como uma configuração regional. No localhost, request.subdomains retorna uma matriz vazia, portanto, a detecção de subdomínios falha no ambiente de desenvolvimento, a menos que você use um servidor Pow ou adicione entradas ao arquivo /etc/hosts.

Uma coisa a ser configurada separadamente: a variável `default_url_options` definida no `ApplicationController` não é aplicada aos mailers nem às tarefas em segundo plano. Defina-a explicitamente para esses contextos:

Rails.application.routes.default_url_options = { host: "example.com", locale: :en }

As rotas localizadas fornecem a estrutura de URL, mas as tags hreflang, os slugs traduzidos e os mapas do site multilíngues continuam sendo totalmente manuais após essa configuração.

A integração de proxy reverso Weglot lida com essa camada automaticamente, gerando tags hreflang e URLs específicas para cada idioma sem necessidade de configuração adicional.

Pluralização, alternativas e a gem rails-i18n

A formação do plural em inglês é simples. Uma forma para o singular e outra para todos os demais casos.

en:
  messages:
    one: "%{count} message"
    other: "%{count} messages"

A maioria das línguas não é assim tão simples.

O búlgaro, por exemplo, possui um plural regular e um “plural de contagem” especial para algumas palavras na forma masculina. Assim, ден (dia) torna-se дни (muitos dias) normalmente, mas два дена (dois dias) quando se trata de contagem.

bg:
  cities:
    one: "%{count} ден"
    few: "%{count} дена"
    many: "%{count} дни"

Sem o rails-i18n, o Rails não tem conhecimento dessas regras. Suas traduções para o búlgaro gerariam erros ou voltariam à outra forma em todos os casos.

O gem implementa a lógica de pluralização para mais de 100 configurações regionais, de modo que tudo é resolvido corretamente em búlgaro, russo, árabe, polonês e qualquer outro idioma com regras de plural diferentes das do inglês.

Os fallbacks são uma questão à parte e estão desativados por padrão. Sem eles, qualquer chave de tradução ausente resulta em uma mensagem de “tradução ausente” no ambiente de produção. É o tipo de coisa que acaba sendo lançada e aparece nas capturas de tela.

Habilite os fallbacks e defina um destino padrão no arquivo config/application.rb:

config.i18n.fallbacks = [I18n.default_locale]

Com fallbacks = true, uma chave ausente na localidade atual recorre à default_locale. Para variantes regionais, é possível definir cadeias explícitas:

config.i18n.fallbacks = { "fr-CA": :fr, "en-GB": :en }

Configure isso desde o início. Implementar um comportamento alternativo em um aplicativo que já possui traduções parciais em produção é mais difícil do que configurá-lo desde o início.

Passando traduções para controladores de estímulo e JavaScript

O JavaScript não tem acesso ao pipeline de internacionalização do Rails.

Não há nenhum helper `t`, carregador YAML ou ponte integrada entre seus arquivos de tradução e seus controladores Stimulus. Você precisa passar as traduções explicitamente do lado do servidor.

A abordagem mais simples no Stimulus é a API de valores. Defina a tradução como um valor no controlador, insira-a no HTML e leia-a no JavaScript:

# app/views/products/index.html.erb
<div data-controller="notification"
     data-notification-message-value="<%= t('.success_message') %>">

O valor é renderizado no servidor usando o helper t padrão, portanto, ele respeita automaticamente a localização atual. No JavaScript, declare-o como um valor estático e acesse-o por meio da API de valores:

// app/javascript/controllers/notification_controller.js
export default class extends Controller {
  static values = { message: String }

  show() {
    alert(this.messageValue)
  }
}

Cada tradução é explícita e restrita ao controlador que precisa dela. Nada vaza para o escopo global.

Se um controlador precisar de várias traduções ao mesmo tempo, agrupá-las como um atributo de dados JSON é mais simples do que adicionar definições de valor individuais para cada string:

<div data-controller="cart"
     data-cart-i18n-value="<%= { add: t('.add'), remove: t('.remove') }.to_json %>">

No JavaScript, declare i18n como um objeto e acesse as chaves individualmente:

static values = { i18n: Object }

add() {
  console.log(this.i18nValue.add)
}

Para aplicativos em que o JavaScript precisa de amplo acesso à tradução em vários controladores, a gem i18n-js exporta seus arquivos YAML para um objeto JavaScript que você pode consultar como I18n.t("chave").

Funciona, mas acrescenta uma etapa à compilação e envia todo o conjunto de traduções para o cliente. Use-o quando os dois primeiros padrões se tornarem repetitivos, e não como padrão.

Ao usar Turbo Frames, se a URL de origem de um Turbo Frame omitir o prefixo de localidade, a solicitação geralmente falhará com um erro de roteamento (404), pois não corresponderá ao padrão do seu escopo "/:locale". Sempre use auxiliares de caminho sensíveis à localidade para as origens dos frames.

Isso não é um bug do Turbo. Trata-se, na verdade, de um descuido no roteamento, e a função `around_action` da seção de detecção de localização impede que isso ocorra, desde que todas as URLs no frame utilizem um helper de caminho sensível à localização.

O proxy reverso Weglot adota uma abordagem totalmente diferente. Ele traduz o DOM renderizado após o carregamento da página, de modo que o conteúdo renderizado pelo Stimulus e as sequências inseridas dinamicamente são suportados sem a necessidade de nenhuma configuração adicional.

O que o Rails I18n deixa de fora

Existem três categorias que estão totalmente fora do âmbito do que o Rails I18n lida:

  • O SEO multilíngue no Rails i18n traduz strings, mas não gera tags hreflang, mapas do site específicos para cada idioma nem metadados traduzidos. Essas tarefas exigem trabalho manual além da configuração do i18n.
  • Conteúdos armazenados em bancos de dados, como nomes de produtos e publicações de blog, não podem ser armazenados em arquivos YAML. Recomenda-se o uso da gem Mobility para isso, pois ela oferece suporte a vários back-ends de armazenamento. O Traco é uma alternativa mais leve para modelos menores com traduções por coluna.
  • O fluxo de trabalho de tradução no Rails depende de arquivos YAML. O gerenciamento do processo de tradução, dos ciclos de revisão e das atualizações, bem como a sincronização das traduções com o aplicativo, devem ser realizados fora do framework.

Weglot trata tudo isso na camada de saída, em vez de na camada de código:

  • Em vez de se integrar ao pipeline de internacionalização do Rails, ele traduz o HTML renderizado produzido pela sua aplicação. Isso significa que o conteúdo do banco de dados, as strings renderizadas por JavaScript e as traduções estáticas são todos tratados da mesma forma.
  • O SEO/GEO multilíngue está incluído: as tags hreflang, os URLs traduzidos e os mapas do site são gerados automaticamente.
  • O fluxo de trabalho de tradução é executado pelo painel Weglot, em vez de ciclos de exportação YAML.

Dito isso, há algumas limitações que vale a pena conhecer antes de avaliá-lo:

  • snippet de JavaScript não é indexada para SEO; é necessário configurar o proxy reverso para que as páginas traduzidas apareçam nos resultados de pesquisa.
  • O roteamento personalizado de subdiretórios, útil caso você já tenha uma configuração de CDN ou Nginx, está disponível apenas na versão Enterprise.
  • Ao contrário das traduções integradas ao seu código-fonte, Weglot uma assinatura ativa para manter o conteúdo traduzido visível.

Escolhendo sua arquitetura de internacionalização (i18n) no Rails

Toda implementação de i18n no Rails se resume às mesmas decisões, tomadas aproximadamente na mesma ordem.

Primeiro, defina sua estratégia de URL antes de escrever qualquer código de detecção de localidade. Segmentos de caminho funcionam para a maioria dos aplicativos voltados para o público. Subdomínios fazem sentido quando a identidade regional é importante. Preferências armazenadas no banco de dados são adequadas para aplicativos autenticados, nos quais a localidade acompanha o usuário, e não a URL.

Em segundo lugar, decida como o JavaScript obtém as traduções. A API de valores do Stimulus cobre a maioria dos casos. Os atributos JSON são úteis quando um controlador precisa de várias strings de uma só vez.

Em terceiro lugar, decida o que você vai desenvolver manualmente. O Rails lida bem com strings estáticas. A camada de SEO, o fluxo de trabalho do tradutor e o conteúdo do banco de dados exigem decisões específicas. Você pode desenvolver cada um deles ou delegar a camada de saída a uma ferramenta como Weglot concentrar o tempo de desenvolvimento na própria aplicação.

Ignore completamente a camada de saída. Experimente Weglot por 14 dias e tenha SEO/GEO multilíngue, URLs traduzidas e detecção automática de conteúdo sem precisar mexer no seu código de internacionalização.

ícone de direção
Descubra a Weglot

Junte-se a mais de 110.000 marcas que já traduzem seus sites com a Weglot

Traduza seu site na hora com inteligência artificial, ajuste com edições humanas e coloque no ar em minutos.

Neste artigo, vamos explorar:
Ícone do foguete

Pronto para começar?

A melhor maneira de compreender o poder do Weglot experimentá-lo você mesmo. Teste-o gratuitamente e sem qualquer compromisso.

Um site de demonstração está disponível no seu painel de controle, caso ainda não esteja pronto para conectar o seu site.

Leia artigos que você também pode gostar

Ícone de Perguntas Frequentes

Perguntas comuns

Nenhum item encontrado.

Seta azul

Seta azul

Seta azul