Rails: How to use i18n with Rails 4 enums
Starting from Rails 5, all models will inherit from ApplicationRecord
.
class User < ApplicationRecord
enum status: [:active, :pending, :archived]
end
I use this superclass to implement a generic solution for translating enums:
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
def self.human_enum_name(enum_name, enum_value)
I18n.t("activerecord.attributes.#{model_name.i18n_key}.#{enum_name.to_s.pluralize}.#{enum_value}")
end
end
Then I add the translations in my .yml
file:
en:
activerecord:
attributes:
user:
statuses:
active: "Active"
pending: "Pending"
archived: "Archived"
Finally, to get the translation I use:
User.human_enum_name(:status, :pending)
=> "Pending"
I didn't find any specific pattern either, so I simply added:
en:
user_status:
active: Active
pending: Pending...
archived: Archived
to an arbitrary .yml file. Then in my views:
I18n.t :"user_status.#{user.status}"
Here is a view:
select_tag :gender, options_for_select(Profile.gender_attributes_for_select)
Here is a model (you can move this code into a helper or a decorator actually)
class Profile < ActiveRecord::Base
enum gender: {male: 1, female: 2, trans: 3}
# @return [Array<Array>]
def self.gender_attributes_for_select
genders.map do |gender, _|
[I18n.t("activerecord.attributes.#{model_name.i18n_key}.genders.#{gender}"), gender]
end
end
end
And here is locale file:
en:
activerecord:
attributes:
profile:
genders:
male: Male
female: Female
trans: Trans
To keep the internationalization similar as any other attribute I followed the nested attribute way as you can see here.
If you have a class User
:
class User < ActiveRecord::Base
enum role: [ :teacher, :coordinator ]
end
And a yml
like this:
pt-BR:
activerecord:
attributes:
user/role: # You need to nest the values under model_name/attribute_name
coordinator: Coordenador
teacher: Professor
You can use:
User.human_attribute_name("role.#{@user.role}")