Ruby on Rails 2.2 como usar I18n, traduzir as mensagens de validação do model e atributos do model

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: Recommend Me.

  • Share/Bookmark

19 Comments

  1. Ricardo

    Muito bom seu blog, cara, tirou muitas dúvidas minhas…

  2. Thiago Antonius

    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

  3. Thiago Antonius

    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 :(

  4. Thiago Antonius

    A questão do label resolvi com o plugin i18n_label. Fica a dica caso precise.

    http://github.com/iain/i18n_label/tree/master

  5. patrickespake

    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.

  6. patrickespake

    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.

  7. Thiago Antonius

    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

  8. uchoaaa

    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

  9. patrickespake

    Beleza e por ae?
    Legal! Iniciativa bacana ;-)

    Abraço.

  10. Excelente post, deixou as coisas bem mais claras. Vou voltar a desenvolver com RoR… e agora estou sentindo firmeza com i18n.

    []s

  11. leandro

    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

  12. Cara, muito bom o post para quem nunca usou o i18n como eu. A dica do @Thiago tbm foi muito boa.

    Valeu pessoal!

  13. 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

  14. 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!

  15. Se você está usando o MongoMapper dá uma olhada nessa gem: http://github.com/jmonteiro/mongomapper_i18n

  16. Claudiney

    Ótimo post.

    Tem como instalar o activerecord_i18n_defaults sem ter o git na máquina?

  17. Acredito que tenha sim, você pode fazer o download dele no git.

  18. Claudiney

    Funcionou Patrick,
    coloquei em vendor>plugins>activerecord_i18n_defaults

    Obrigado.


3 Trackbacks/Pingbacks

  1. ActiveRecord I18n Defaults forked « puts “hello word” 31 03 09
  2. Ruby on Rails Authlogic com I18n para pt-BR | Blog Patrick Espake 01 09 09
  3. links for 2009-12-12 « sySolution 12 12 09

Add Your Comment