Cómo usar i18n con Rails 4 enumeraciones

Rails 4 Active Record Enums son geniales, pero ¿cuál es el patrón correcto para traducir con i18n?

Tampoco encontré ningún patrón específico, así que simplemente agregué:

en: user_status: active: Active pending: Pending... archived: Archived 

a un archivo arbitrario .yml. Entonces en mi opinión:

 I18n.t :"user_status.#{user.status}" 

A partir de Rails 5, todos los modelos heredarán de ApplicationRecord .

 class User < ApplicationRecord enum status: [:active, :pending, :archived] end 

Uso esta superclase para implementar una solución genérica para traducir enumeraciones:

 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 

Luego agrego las traducciones en mi archivo .yml :

 en: activerecord: attributes: user: statuses: active: "Active" pending: "Pending" archived: "Archived" 

Finalmente, para obtener la traducción que uso:

 User.human_enum_name(:status, :pending) => "Pending" 

Aquí hay una vista:

 select_tag :gender, options_for_select(Profile.gender_attributes_for_select) 

Aquí hay un modelo (puedes mover este código a un ayudante o un decorador en realidad)

 class Profile < ActiveRecord::Base enum gender: {male: 1, female: 2, trans: 3} # @return [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 

Y aquí está el archivo local:

 en: activerecord: attributes: profile: genders: male: Male female: Female trans: Trans 

Para mantener la internacionalización similar a cualquier otro atributo, seguí el modo de atributo nested como puede ver aquí .

Si tienes un User clase:

 class User < ActiveRecord::Base enum role: [ :teacher, :coordinator ] end 

Y un yml como este:

 pt-BR: activerecord: attributes: user/role: # You need to nest the values under model_name/attribute_name coordinator: Coordenador teacher: Professor 

Puedes usar:

 User.human_attribute_name("role.#{@user.role}") 

Modelo:

 enum stage: { starting: 1, course: 2, ending: 3 } def self.i18n_stages(hash = {}) stages.keys.each { |key| hash[I18n.t("checkpoint_stages.#{key}")] = key } hash end 

Lugar:

 checkpoint_stages: starting: Saída course: Percurso ending: Chegada 

Y en la vista (.slim):

 = f.input_field :stage, collection: Checkpoint.i18n_stages, as: :radio_buttons 

Al elaborar la respuesta del usuario3647358, puede lograr eso muy de cerca a lo que está acostumbrado al traducir los nombres de los atributos.

Archivo regional:

 en: activerecord: attributes: profile: genders: male: Male female: Female trans: Trans 

Traduzca llamando a I18n # t:

 profile = Profile.first I18n.t(profile.gender, scope: [:activerecord, :attributes, :profile, :genders]) 

He creado una joya para esto.

http://rubygems.org/gems/translated_attribute_value

Agregue a su gemfile:

 gem 'translated_attribute_value' 

Si tiene un campo de estado para el usuario:

 pt-BR: activerecord: attributes: user: status_translation: value1: 'Translation for value1' value2: 'Translation for value2' 

Y en su opinión, puede llamar así:

 user.status_translated 

Funciona con registro activo, mongoid o cualquier otra clase con getter / setters:

https://github.com/viniciusoyama/translated_attribute_value

Intenta usar la gem TranslateEnum para estos propósitos

 class Post < ActiveRecord::Base enum status: { published: 0, archive: 1 } translate_enum :status end Post.translated_status(:published) Post.translated_statuses @post = Post.new(status: :published) @post.translated_status 

Combinando las respuestas de Repolês y Aliaksandr , para Rails 5, podemos construir 2 métodos que le permitan traducir un valor único o una colección de valores de un atributo enum.

Configure las traducciones en su archivo .yml :

 en: activerecord: attributes: user: statuses: active: "Active" pending: "Pending" archived: "Archived" 

En la clase ApplicationRecord , de la que todos los modelos heredan, definimos un método que maneja las traducciones para un único valor y otro que maneja las matrices llamándolas:

 class ApplicationRecord < ActiveRecord::Base self.abstract_class = true def self.translate_enum_name(enum_name, enum_value) I18n.t("activerecord.attributes.#{model_name.i18n_key}.#{enum_name.to_s.pluralize}.#{enum_value}") end def self.translate_enum_collection(enum_name) enum_values = self.send(enum_name.to_s.pluralize).keys enum_values.map do |enum_value| self.translate_enum_name enum_name, enum_value end end end 

En nuestra opinión, podemos traducir valores únicos:

 

User Status: <%= User.translate_enum_name :status, @user.status %>

O toda la colección de valores enum:

 <%= f.select(:status, User.translate_enum_collection :status) %> 

Prueba la gem enum_help . De su descripción:

Ayuda a la función ActiveRecord :: Enum a funcionar bien con I18n y simple_form.

Aquí hay un método t_enum helper que uso.

 <%= t_enum(@user, :status) %> 

enum_helper.rb :

 module EnumHelper def t_enum(inst, enum) value = inst.send(enum); t_enum_class(inst.class, enum, value) end def t_enum_class(klass, enum, value) unless value.blank? I18n.t("activerecord.enums.#{klass.to_s.demodulize.underscore}.#{enum}.#{value}") end end end 

user.rb :

 class User < ActiveRecord::Base enum status: [:active, :pending, :archived] end 

en.yml :

 en: activerecord: enums: user: status: active: "Active" pending: "Pending..." archived: "Archived" 

El modelo:

 class User < ActiveRecord::Base enum role: [:master, :apprentice] end 

El archivo de configuración regional:

 en: activerecord: attributes: user: master: Master apprentice: Apprentice 

Uso:

 User.human_attribute_name(:master) # => Master User.human_attribute_name(:apprentice) # => Apprentice 

Prefiero un simple ayudante en application_helper

  def translate_enum(object, enum_name) I18n.t("activerecord.attributes.#{object.model_name.i18n_key}.#{enum_name.to_s.pluralize}.#{object.send(enum_name)}") end 

Luego en mi archivo YML:

 fr: activerecord: attributes: my_model: my_enum_plural: pending: "En cours" accepted: "Accepté" refused: "Refusé" 

Sin embargo, de otra manera, me parece un poco más conveniente usar una preocupación en los modelos

Preocupación

 module EnumTranslation extend ActiveSupport::Concern def t_enum(enum) I18n.t "activerecord.attributes.#{self.class.name.underscore}.enums.#{enum}.#{self.send(enum)}" end end 

YML:

 fr: activerecord: attributes: campaign: title: Titre short_description: Description courte enums: status: failed: "Echec" 

Vista:

 <% @campaigns.each do |c| %> <%= c.t_enum("status") %> <% end %> 

No se olvide de agregar preocupación en su modelo:

 class Campaign < ActiveRecord::Base include EnumTranslation enum status: [:designed, :created, :active, :failed, :success] end 

Simplemente puede agregar un ayudante:

 def my_something_list modes = 'activerecord.attributes.mymodel.my_somethings' I18n.t(modes).map {|k, v| [v, k]} end 

y configúralo como siempre:

 en: activerecord: attributes: mymodel: my_somethings: my_enum_value: "My enum Value!" 

luego my_something_list con tu selección: my_something_list

 class ApplicationRecord < ActiveRecord::Base self.abstract_class = true def self.enum(definitions) defind_i18n_text(definitions) if definitions.delete(:_human) super(definitions) end def self.defind_i18n_text(definitions) scope = i18n_scope definitions.each do |name, values| next if name.to_s.start_with?('_') define_singleton_method("human_#{name.to_s.tableize}") do p values values.map { |key, _value| [key, I18n.t("#{scope}.enums.#{model_name.i18n_key}.#{name}.#{key}")] }.to_h end define_method("human_#{name}") do I18n.t("#{scope}.enums.#{model_name.i18n_key}.#{name}.#{send(name)}") end end end end en: activerecord: enums: mymodel: my_somethings: my_enum_value: "My enum Value!" enum status: [:unread, :down], _human: true