Rails: как использовать i18n с перечислениями Rails 4

Ответы:

52

Я также не нашел конкретного шаблона, поэтому просто добавил:

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

в произвольный файл .yml. Тогда в моих взглядах:

I18n.t :"user_status.#{user.status}"
Pierrea
источник
5
Я сделал что-то подобное, но я поместил его под {locale}.activerecord.attributes.{model}.{attribute}и написал t_enum(model, enum, value)вспомогательный метод, чтобы перевод enum был рядом с переводом метки
Крис Бек
77

Начиная с Rails 5, все модели наследуют от ApplicationRecord.

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

Я использую этот суперкласс для реализации универсального решения для перевода перечислений:

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

Затем я добавляю переводы в свой .ymlфайл:

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

Наконец, чтобы получить перевод, я использую:

User.human_enum_name(:status, :pending)
=> "Pending"
Repolês
источник
3
Как бы вы справились, используя это в раскрывающемся списке (то есть, когда не отображается одно значение)?
tirdadc
6
@tirdadc вы можете обрабатывать выпадающий список , как это: <%= f.select :status, User.statuses.keys.collect { |status| [User.human_enum_name(:status, status), status] } %>.
Repolês
3
+1 хороший ответ. Я настроил его для использования в качестве вспомогательного метода представления, поскольку я считаю, что это больше касается представления, и чтобы не использовать имя атрибута во множественном числе: gist.github.com/abevoelker/fed59c2ec908de15acd27965e4725762 Назовите его в представлении, например,human_enum_name(@user, :status)
Abe Voelker
1
За Repolês, можно также добавить еще один метод класса к базовой модели для выпадающих: self.human_enum_collection(enum_name). Код будет send(enum_name.to_s.pluralize).keys.collect { |val| [human_enum_name(enum_name, val), val] }
armchairdj
32

Вот вид:

select_tag :gender, options_for_select(Profile.gender_attributes_for_select)

Вот модель (вы можете переместить этот код в помощник или декоратор)

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

А вот и файл локали:

en:
  activerecord:
    attributes:
      profile:
        genders:
          male: Male
          female: Female
          trans: Trans
Александр
источник
1
а как в этом случае получить перевод для отдельной записи? Потому .human_attribute_name('genders.male')что не работают
Стииг
Спасибо, в моем случае работает как шарм !
Matiss
Я сделал для этих целей облегченный гем github.com/shlima/translate_enum
Александр,
30

Чтобы интернационализация оставалась такой же, как и для любого другого атрибута, я использовал метод вложенных атрибутов, как вы можете видеть здесь .

Если у вас есть класс User:

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

И ymlвот так:

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

Вы можете использовать:

User.human_attribute_name("role.#{@user.role}")
Doguita
источник
1
Это визуально привлекательным , но он ломает рельсы условность activerecord.attributes.<fieldname>быть labelперевод формы хелперов
Крис Бек
5
@ChrisBeck, похоже, это следует соглашению, описанному в Руководстве по Rails I18n: guides.rubyonrails.org/…
danblaker
По моему опыту, это работает без использования roleключа. Гнездиться можно coordinatorи teacherпрямо под user.
Райан Криспин Хениз
7

Модель:

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

Локаль:

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

И на виде (.slim):

= f.input_field :stage, collection: Checkpoint.i18n_stages, as: :radio_buttons
Освальдо Феррейра
источник
6

Разрабатывая ответ user3647358, вы можете выполнить это очень близко к тому, к чему вы привыкли при переводе имен атрибутов.

Файл локали:

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

Переведите, позвонив по телефону I18n # t:

profile = Profile.first
I18n.t(profile.gender, scope: [:activerecord, :attributes, :profile, :genders])
Рафаэль Вальверде
источник
4

Попробуйте использовать для этих целей гем TranslateEnum

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 
Александр
источник
1
Мы тоже используем этот драгоценный камень. Имеет самый чистый подход из всех рассмотренных нами вариантов и содержится в хорошем состоянии.
cseelus
3

Я создал для этого жемчужину.

http://rubygems.org/gems/translated_attribute_value

Добавьте в свой гем-файл:

gem 'translated_attribute_value'

Если у вас есть поле статуса для пользователя:

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

И, на ваш взгляд, вы можете позвонить так:

user.status_translated

Он работает с активной записью, монгоидом или любым другим классом с геттерами / сеттерами:

https://github.com/viniciusoyama/translated_attribute_value

Винисиус Ояма
источник
3

Объединяя ответы Реполеша и Александра , для Rails 5, мы можем построить 2 методы , которые позволяют переводить одно значение или набор значений из атрибута перечислений.

Настройте переводы в своем .ymlфайле:

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

В ApplicationRecordклассе, от которого наследуются все модели, мы определяем метод, который обрабатывает переводы для одного значения, и другой, который обрабатывает массивы, вызывая его:

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 

Затем в наших представлениях мы можем переводить отдельные значения:

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

Или весь набор значений перечисления:

<%= f.select(:status, User.translate_enum_collection :status) %>
ne5t
источник
2

Попробуйте гем enum_help . Из его описания:

Помогите функции ActiveRecord :: Enum нормально работать с I18n и simple_form.

Кукунин
источник
2

Вот t_enumвспомогательный метод, который я использую.

<%= 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"
Cweston
источник
2

Модель:

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

Файл локали:

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

Применение:

User.human_attribute_name(:master) # => Master
User.human_attribute_name(:apprentice) # => Apprentice
Дмитрий Швецов
источник
Как насчет того @user.role, что это главная проблема.
Code-MonKy
Самый простой, чистый и элегантный способ.
Fabian Winkler
5
AnyModel.human_attribute_name (: i_dont_exist) => «Я не существую»
Шиясон
1

Я предпочитаю простой помощник в 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

Затем в моем файле YML:

fr:
  activerecord:
    attributes:
      my_model:
        my_enum_plural:
          pending:  "En cours"
          accepted: "Accepté"
          refused:  "Refusé"
Змея
источник
0

Еще один способ, который мне кажется более удобным - использовать озабоченность в моделях.

Беспокойство :

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"

Посмотреть :

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

Не забудьте добавить беспокойство в свою модель:

class Campaign < ActiveRecord::Base
  include EnumTranslation

  enum status: [:designed, :created, :active, :failed, :success]
end
Джеффри Х
источник
0

Вы можете просто добавить помощника:

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

и настроим как обычно:

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

затем используйте его с вашим выбором: my_something_list

ftshtw
источник
0
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
Кевин Синь
источник