UPDATE: you don’t need this code, because starting from the 2.2 version of Rails, localization support is built-in.

Localization for Active Record error messages

Today i had to answer to one of the questions every non-english Rails developer stumbles upon now or after.. how to localize AR error messages for pleasant appearance to a non-english customer ;).

First off, thanks to defunkt’s excellent gibberish plugin and to the way AR validation errors are exposed, the task was accomplished in an easy and clean manner, without messing too much with AR’s internals.

I started by translating every default AR error message, with this translation file located in lang/it.yml:

# Active Record errors
#
ar_accepted:     "deve essere accettato" 
ar_not_a_number: "non è un numero" 
ar_blank:        "è un campo obbligatorio" 
ar_empty:        "è un campo obbligatorio" 
ar_inclusion:    "non è nella lista dei valori validi" 
ar_too_long:     "è troppo lungo (massimo %d caratteri)" 
ar_exclusion:    "è riservato" 
ar_too_short:    "è troppo corto (minimo %d caratteri)" 
ar_invalid:      "non è valido" 
ar_wrong_length: "è errato, dovrebbe essere di %d caratteri" 
ar_confirmation: "non corrisponde" 
ar_taken:        "esiste già" 
# This one is not a default key, but I use it in my validations
ar_greater_zero: "deve essere maggiore di zero" 

and four lines in config/environment.rb:

Gibberish.current_language = :it
ActiveRecord::Errors.default_error_messages =
  ActiveRecord::Errors.default_error_messages.inject({}) {|h, (key, string)|
    h.update(key => string["ar_#{key}".intern]) # <em>Gibberish magic</em>
}

The first one simply sets Italian (:it) as the default language, the inject builds a new error_messages hash using Gibberish to translate the default ones. I named every AR error key in my translation file with an “ar_” prefix, in order to avoid possible future key clashes. Finally, AR array is overwritten with the new one freshly built.

This solution assumes that the application will show only in a single language, if you need localized error messages in different language you should put this code in some around_filter, like Gibberish documentation suggests.

OK, messages are translated, but what about field names? I used english field names in my tables, how about translating them as well? First, we need the actual translations in lang/it.yml:

# Field names
#
fld_multiplier:  "La dimensione" 
fld_service_id:  "Il servizio" 
fld_customer_id: "Il contraente" 
fld_address_id:  "L'indirizzo" 
fld_user_id:     "L'utente" 
fld_city_id:     "La città" 
fld_state_id:    "La provincia" 
fld_address:     "L'indirizzo" 
fld_terms_of_service: "Il testo di informativa sulla privacy" 

And then a customized helper that our view will call, loosely based on the default error_messages_for Rails helper:

  # error messages localization
  # uses gibberish.
  def foo_object_error_messages
    return '' if @foo_object.errors.count.zero?
    header_message = "Si prega di correggere i seguenti errori:" 
    error_messages = @foo_objects.errors.map do |field, err|
      field = field["fld_#{field}".intern] # [i]Gibberish magic[/i]
      content_tag(:li, "#{field} #{err}")
    end 
    content_tag(:div,
      content_tag(:h2, header_message) <<
        content_tag(:ul, error_messages),
      :class => 'errorExplanation',
      :id    => 'errorExplanation'
    )   
  end 

Here, easily, every field name is substituted by its translated counterpart, and a div is built with the plain vanilla class and id used by Rails’ [code]scaffold.css[/code], so that I won’t have to write a single line of CSS.

In your view: <%= foo_object_error_messages %>

This helper could be of course improved, but I’m a bit lazy right now.

Have fun! :D