No Ruby on Rails 2.2 existe o suporte para I18n, ou seja, criar aplicações para múltiplos idiomas.
Vou mostrar como habilitar isso no Ruby on Rails 2.2.
Primeiro pare a sua aplicação.
Abra o arquivo environment.rb localizado no diretório config, nesse arquivo procure pela seguinte linha:
1 | # config.i18n.default_locale = :de |
Ela está comentada e até esse momento o idioma padrão do projeto e o inglês.
Remove o comentário dessa linha e defina o idioma padrão para “pt-BR”:
1 2 3 4 | # The internationalization framework can be changed to have another default locale (standard is :en) or more load paths. # All files from config/locales/*.rb,yml are added automatically. # config.i18n.load_path << Dir[File.join(RAILS_ROOT, 'my', 'locales', '*.{rb,yml}')] config.i18n.default_locale = "pt-BR" |
Agora precisamos criar um arquivo chamado pt-BR.yml, nesse arquivo irá ficar as traduções dos termos do projeto para o português.
Crie o arquivo pt-BR.yml no diretório config/locales, esse diretório config/locales é responsável por armazenar todos os arquivos de tradução do projeto.
Adicione o seguinte conteúdo no arquivo pt-BR.yml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | pt-BR: # formatos de data e hora date: formats: default: "%d/%m/%Y" short: "%d de %B" long: "%d de %B de %Y" only_day: "%d" day_names: [Domingo, Segunda, Terça, Quarta, Quinta, Sexta, Sábado] abbr_day_names: [Dom, Seg, Ter, Qua, Qui, Sex, Sáb] month_names: [~, Janeiro, Fevereiro, Março, Abril, Maio, Junho, Julho, Agosto, Setembro, Outubro, Novembro, Dezembro] abbr_month_names: [~, Jan, Fev, Mar, Abr, Mai, Jun, Jul, Ago, Set, Out, Nov, Dez] order: [:day,:month,:year] time: formats: default: "%A, %d de %B de %Y, %H:%M hs" time: "%H:%M hs" short: "%d/%m, %H:%M hs" long: "%A, %d de %B de %Y, %H:%M hs" only_second: "%S" datetime: formats: default: "%Y-%m-%dT%H:%M:%S%Z" am: '' pm: '' # date helper distanci em palavras datetime: distance_in_words: half_a_minute: 'meio minuto' less_than_x_seconds: one: 'menos de 1 segundo' other: 'menos de {{count}} segundos' x_seconds: one: '1 segundo' other: '{{count}} segundos' less_than_x_minutes: one: 'menos de um minuto' other: 'menos de {{count}} minutos' x_minutes: one: '1 minuto' other: '{{count}} minutos' about_x_hours: one: 'aproximadamente 1 hora' other: 'aproximadamente {{count}} horas' x_days: one: '1 dia' other: '{{count}} dias' about_x_months: one: 'aproximadamente 1 mês' other: 'aproximadamente {{count}} meses' x_months: one: '1 mês' other: '{{count}} meses' about_x_years: one: 'aproximadamente 1 ano' other: 'aproximadamente {{count}} anos' over_x_years: one: 'mais de 1 ano' other: 'mais de {{count}} anos' # numeros number: format: precision: 3 separator: ',' delimiter: '.' currency: format: unit: 'R$' precision: 2 format: '%u %n' separator: ',' delimiter: '.' percentage: format: delimiter: '.' precision: format: delimiter: '.' human: format: precision: 1 delimiter: '.' support: array: sentence_connector: "e" skip_last_comma: true # Active Record activerecord: errors: template: header: one: "{{model}} não pôde ser salvo: 1 erro" other: "{{model}} não pôde ser salvo: {{count}} erros." body: "Por favor, cheque os seguintes campos:" messages: inclusion: "não está incluso na lista" exclusion: "não está disponível" invalid: "não é válido" confirmation: "não bate com a confirmação" accepted: "precisa ser aceito" empty: "não pode ser vazio" blank: "não pode ser vazio" too_long: "é muito longo (não mais do que {{count}} caracteres)" too_short: "é muito curto (não menos do que {{count}} caracteres)" wrong_length: "não é do tamanho correto (precisa ter {{count}} caracteres)" taken: "não está disponível" not_a_number: "não é um número" greater_than: "precisa ser maior do que {{count}}" greater_than_or_equal_to: "precisa ser maior ou igual a {{count}}" equal_to: "precisa ser igual a {{count}}" less_than: "precisa ser menor do que {{count}}" less_than_or_equal_to: "precisa ser menor ou igual a {{count}}" odd: "precisa ser ímpar" even: "precisa ser par" |
Esse arquivo pt-BR.yml foi retirado de: http://github.com/svenfuchs/rails-i18n/tree/master nesse endereço você poderá encontrar traduções para outros idiomas.
Pronto! Agora é só rodar a aplicação e ver as mensagens e o restante traduzido para o português.
1 | ruby script/server |
Outro detalhe super importante e gera muitas perguntas nas listas e fóruns, é como traduzir os nomes dos atributos do model, por exemplo eu tenho um model com os seguintes atributos:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class CreateHistories < ActiveRecord::Migration def self.up create_table :histories do |t| t.string :title, :limit => 150, :null => false t.string :permalink, :limit => 255 t.text :content, :null => false t.timestamps end add_index(:histories, :permalink, :unique => true) end def self.down drop_table :histories end end |
Eu tenho os atributos title, permalink e content, muitas pessoas como eu gostam de programar tudo em inglês.
O problema é quando é exibida as mensagens de validação, os nomes dos atributos vem todos em inglês, por exemplo:
1 2 3 4 5 6 | 2 erros para history Foram detectados os seguintes erros: * Title não pode ser vazio * Content não pode ser vazio |
Para resolver esse problema e ser feliz, existe um outro plugin chamado activerecord_i18n_defaults que pode ser encontrado aqui: http://github.com/dcrec1/activerecord_i18n_defaults/tree/master.
Vamos usar ele.
Instalação
No diretório raiz do projeto digite:
1 | ruby script/plugin install git://github.com/dcrec1/activerecord_i18n_defaults.git |
Agora lembra do arquivo pt-BR.yml que criamos acima, vamos abrir ele e inserir novas traduções para os atributos do model.
Procure no arquivo pt-BR.yml por essa parte:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | ... # Active Record activerecord: errors: template: header: one: "model não pôde ser salvo: 1 erro" other: "model não pôde ser salvo: count erros." body: "Por favor, cheque os seguintes campos:" messages: inclusion: "não está incluso na lista" exclusion: "não está disponível" invalid: "não é válido" confirmation: "não bate com a confirmação" accepted: "precisa ser aceito" empty: "não pode ser vazio" blank: "não pode ser vazio" too_long: "é muito longo (não mais do que count caracteres)" too_short: "é muito curto (não menos do que count caracteres)" wrong_length: "não é do tamanho correto (precisa ter count caracteres)" taken: "não está disponível" not_a_number: "não é um número" greater_than: "precisa ser maior do que count" greater_than_or_equal_to: "precisa ser maior ou igual a count" equal_to: "precisa ser igual a count" less_than: "precisa ser menor do que count" less_than_or_equal_to: "precisa ser menor ou igual a count" odd: "precisa ser ímpar" even: "precisa ser par" |
Adicione o seguinte conteúdo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | ... # Active Record activerecord: attributes: _all: created_at: "Data de criação" updated_at: "Data de atualização" history: title: "Título" content: "Conteúdo" errors: template: header: one: "model não pôde ser salvo: 1 erro" other: "model não pôde ser salvo: count erros." body: "Por favor, cheque os seguintes campos:" messages: inclusion: "não está incluso na lista" exclusion: "não está disponível" invalid: "não é válido" confirmation: "não bate com a confirmação" accepted: "precisa ser aceito" empty: "não pode ser vazio" blank: "não pode ser vazio" too_long: "é muito longo (não mais do que count caracteres)" too_short: "é muito curto (não menos do que count caracteres)" wrong_length: "não é do tamanho correto (precisa ter count caracteres)" taken: "não está disponível" not_a_number: "não é um número" greater_than: "precisa ser maior do que count" greater_than_or_equal_to: "precisa ser maior ou igual a count" equal_to: "precisa ser igual a count" less_than: "precisa ser menor do que count" less_than_or_equal_to: "precisa ser menor ou igual a count" odd: "precisa ser ímpar" even: "precisa ser par" |
Ou seja, adicionei:
1 2 3 4 5 6 7 | attributes:
_all:
created_at: "Data de criação"
updated_at: "Data de atualização"
history:
title: "Título"
content: "Conteúdo" |
Tudo que fica abaixo do atributo _all, no caso created_at e updated_at são atributos do model comuns entre vários models, você define ali e todo mundo que tiver esses atributos já serão traduzidos.
E a parte abaixo são atributos específicos do model history:
1 2 3 | history:
title: "Título"
content: "Conteúdo" |
O bom de existir a parte com _all é que você não precisa ficar duplicando traduções, é o que as pessoas xaropes, manés e viciadas em acrónimos da informática chamam de DRY (o mundo seria bem melhor sem essas pessoas ;-)).
Eu percebi que a gem Brazilian Rails gera alguns conflitos nas mensagens de validações, por isso eu sugiro que você desabilite deixando o seu environment.rb assim:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | ... # Specify gems that this application depends on. # They can then be installed with "rake gems:install" on new installations. # You have to specify the :lib option for libraries, where the Gem name (sqlite3-ruby) differs from the file itself (sqlite3) # config.gem "bj" # config.gem "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net" # config.gem "sqlite3-ruby", :lib => "sqlite3" # config.gem "aws-s3", :lib => "aws/s3" # config.gem "brazilian-rails", :version => '2.0.13' config.gem "brcep", :version => '2.0.13' config.gem "brcpfcnpj", :version => '2.0.13' config.gem "brdata", :version => '2.0.13' config.gem "brdinheiro", :version => '2.0.13' config.gem "brhelper", :version => '2.0.13' config.gem "brnumeros", :version => '2.0.13' config.gem "brstring", :version => '2.0.13' # config.gem "brtraducao", :version => '2.0.13' ... |
Mais informações: http://iain.nl/2008/09/translating-activerecord/.
Se você gostou desse texto e acha que ajudou você, me recomende:
.

Tomei a liberdade de citar seu post no meu:
http://blog.improveit.com.br/articles/2009/02/13/o-brazilian-rails-e-o-suporte-i18n
[]‘s
Muito bom seu blog, cara, tirou muitas dúvidas minhas…
A tradução dos atributos dos models utilizando _all não está funcionando aqui não.
Estou usando o rails 2.3.2.
Eu traduzindo model por model funciona porém essa dica do _all ele não traduz. Tem alguma coisa a mais que tem que fazer?
vlw
Outra coisa, tem como fazer com que o
utilize a internacionalização também? Pois as mensagens de erro traduz o atributo (se eu especificar por model) porém o f.label não :(
A questão do label resolvi com o plugin i18n_label. Fica a dica caso precise.
http://github.com/iain/i18n_label/tree/master
Você instalou o plugin mencionado no texto: “Para resolver esse problema e ser feliz, existe um outro plugin chamado activerecord_i18n_defaults que pode ser encontrado aqui: http://github.com/dcrec1/activerecord_i18n_defaults/tree/master.“?
É necessário esse plugin para o _all funcionar, estou usando no Rails 2.2.2 e está funcionando bem.
No Rails 2.3.2 eu não testei ainda.
Para traduzir o label eu fazia no braço:
[sourcecode language="ruby"]
< %= f.label :content, "Conteúdo" %>
[/sourcecode]
Vou começar a usar esse plugin i18n_label.
Valeu pela dica.
Abraço.
Não tinha instalado o plugin não, malz.
Porém no tutorial não está muito claro para que ele serve.
Tem escrito
“O problema é quando é exibida as mensagens de validação, os nomes dos atributos vem todos em inglês, por exemplo:”
e abaixo
“Para resolver esse problema e ser feliz, existe um outro plugin chamado activerecord_i18n_defaults que pode ser encontrado aqui:”
Sendo que o plugin é para ser usado para atributos comuns utilizados em mais de um model.
vlw, funcionou aqui agora depois do plugin instalado. Porém tiver que fazer uma correção no plugin para o rails 2.3.2, pois teve um método que foi deprecated, conforme mostra aqui.
http://apidock.com/rails/ActiveRecord/Base/self_and_descendents_from_active_record/class
Opa, Patrick, blz?!
Fiz um fork do ActiveRecord_i18n_defaults, adaptando para o raisl 2.3.2. Aproveitei e fiz um merge com o i18n_label que o Thiago comentou. Dá uma olhada na página do GitHub. http://github.com/uchoaaa/activerecord_i18n_defaults/tree/master
Abraços
Beleza e por ae?
Legal! Iniciativa bacana ;-)
Abraço.
Excelente post, deixou as coisas bem mais claras. Vou voltar a desenvolver com RoR… e agora estou sentindo firmeza com i18n.
[]s
e ae! show de bola. parabéns.
tem q mudar uma parada no arquivo pt-BR.yml, como mencionado aqui: http://groups.google.com.br/group/rails-br/browse_thread/thread/c4226a74c9347729?pli=1
vlw
Cara, muito bom o post para quem nunca usou o i18n como eu. A dica do @Thiago tbm foi muito boa.
Valeu pessoal!
Depois que eu fiz quase tudo isso achei seu post, muito bom.
S’o lembranbdo que se pode traduzir os modulos tambem acrescentando uma area models: no arquivo pt-BR.yml para nao aparecer algo como:
User não pôde ser salvo: 1 erro
Funciona muito bem, outra dica eh que no arquivo vendor/plugins/activerecord_i18n_defaults/lib/activerecord_i18n_defaults.rb do plugin ActiveRecord_i18n_defaults pode-se colocar no inicio do arquivo:
def self.self_and_descendants_from_active_record
[self]
end
caso a variavel seja undefined.
Otimo post
Pessoal já instalei o Brazilian Rails e o i18n, descomentei a linha no enviroment.rb e mudei o idioma para “pt-BR”e adicionei o arquivo na pasta locales.
Mas euestou usando mongomapper e eu vi que o arquvo pt-BR faz referencia ao activerecord… E no meu não está funcionando as minhas mensagens continuam aparecendo “”can’t be empty”.
Tem alguma coisa haver com eu estar usando mongomapper?
Ajuda por favor!
Se você está usando o MongoMapper dá uma olhada nessa gem: http://github.com/jmonteiro/mongomapper_i18n
Ótimo post.
Tem como instalar o activerecord_i18n_defaults sem ter o git na máquina?
Acredito que tenha sim, você pode fazer o download dele no git.
Funcionou Patrick,
coloquei em vendor>plugins>activerecord_i18n_defaults
Obrigado.