views:

175

answers:

1

Could you tell me whats the best practice for storing constants with internationalization in rails3?

f.e. i want to have a constant-hash for haircolours for my user model:

# btw: how can I store such hashes in the locales.yml-files?
# en.yml
HAIR_COLOURS = { "brown" => 0, "white" => 1, "red" => 2, "dark-brown" => 3...}

# de.yml
HAIR_COLOURS = { "braun" => 0, "weiss" => 1, "rot" => 2, "dunkel-braun" => 3...}

# i18n.default_locale = :de
User.find(1).haircolour
=> 0
User.find(1).haircolour_str
=> "brown"

# i18n.default_locale = :de
User.find(1).haircolour
=> 0
User.find(1).haircolour_str
=> "braun"
+1  A: 

I would suggest the following. Create a string column for the hair colour. This would normally be an enumeration column (ENUM), but this isn't supported by Rails unless you're okay with some SQL in your migrations.

In your model, restrict the colours to a few valid values.

class User < ActiveRecord::Base
  # Store the colours in the database as string identifiers (my preference
  # would be English, lower case, with underscores). Only accept known values.

  validates_inclusion_of :hair_colour, :in => %w{brown white red dark_brown}
end

Then, in config/locales/en.yml:

en:
  user:
    hair_colours:
      brown: brown
      white: white
      red: red
      dark_brown: dark brown

And in condig/locales/de.yml:

de:
  user:
    hair_colours:
      brown: braun
      white: weiss
      red: rot
      dark_brown: dunkelbraun

In any view, you can do:

<%= t "user.hair_colours.#{@user.hair_colour}" %>

Or you can write a helper method in app/helpers/users_helper.rb:

def translated_hair_colour(user)
  t "user.hair_colours.#{user.hair_colour}"
end

Because I believe that translation is in principle a concern of the presentation, I would not create a method on the User model, but in principle there is nothing stopping you from doing:

class User
  # ...

  def hair_colour_name
    I18n.t "user.hair_colours.#{hair_colour}"
  end
end

Update:

Making select boxes in a view that are translated can be done in two ways. The first option is to use the translated values as a source. This requires the translations to be complete and accurate. If not all values are translated, the missing values will not be displayed in the select box.

<%= form_for @user do |user| -%>
  <%# ... %>
  <%= user.select :hair_colour, t("user.hair_colours").invert %>
  <%= user.submit %>
<% end -%>

The second option is to use the validation values from your model. This is the "right" way, but it requires a slight adjustment to the setup of the validation.

class User < ActiveRecord::Base
  HAIR_COLOURS = %w{brown white red dark_brown}
  validates_inclusion_of :hair_colour, :in => HAIR_COLOURS
end

Now, in your views:

<%= form_for @user do |user| -%>
  <%= user.select :hair_colour,
    User::HAIR_COLOURS.map { |c| [t("user.hair_colours.#{c}"), c] } %>
  <%= user.submit %>
<% end -%>

Of course, the mapping can be easily extracted into a helper.

molf
Hmmm sound good..! Thanks! but is there maybe a even smarter solution? Will check this as answer if the bounty doesnt bring something better...!
Lichtamberg
Could you tell me how to make select_boxes with this solution? Will mark your answer as accepted if you answer... Thx!
Lichtamberg
@Lichtamberg: No problem! Answer has been updated.
molf