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"
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 config/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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With