Rails: Cách sử dụng i18n với Rails 4 enums


Câu trả lời:


51

Tôi cũng không tìm thấy bất kỳ mẫu cụ thể nào, vì vậy tôi chỉ cần thêm:

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

vào một tệp .yml tùy ý. Sau đó, theo quan điểm của tôi:

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

5
tôi đã làm một cái gì đó tương tự, nhưng tôi đặt nó dưới {locale}.activerecord.attributes.{model}.{attribute}và viết một t_enum(model, enum, value)phương pháp helper nên dịch enum sẽ tiếp giáp với dịch nhãn
Chris Beck

77

Bắt đầu từ Rails 5, tất cả các mô hình sẽ kế thừa từ ApplicationRecord.

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

Tôi sử dụng lớp cha này để triển khai một giải pháp chung để dịch các enum:

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

Sau đó, tôi thêm các bản dịch vào .ymltệp của mình :

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

Cuối cùng, để có được bản dịch tôi sử dụng:

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

3
Bạn sẽ xử lý như thế nào khi sử dụng điều này trong trình đơn thả xuống (tức là khi không hiển thị một giá trị duy nhất)?
tirdadc

6
@tirdadc bạn có thể xử lý một thả xuống như thế này: <%= f.select :status, User.statuses.keys.collect { |status| [User.human_enum_name(:status, status), status] } %>.
Repolês

3
+1 câu trả lời hay. Tôi đã chỉnh sửa nó để sử dụng làm phương pháp trợ giúp chế độ xem vì tôi cảm thấy đây là mối quan tâm nhiều hơn đến chế độ xem và không đa dạng hóa tên thuộc tính: gist.github.com/abevoelker/fed59c2ec908de15acd27965e4725762 Gọi nó ở chế độ xem nhưhuman_enum_name(@user, :status)
Abe Voelker

1
Mỗi Repolês, bạn cũng có thể thêm một phương pháp lớp để mô hình cơ sở của bạn cho Dropdowns: self.human_enum_collection(enum_name). Mã sẽ là send(enum_name.to_s.pluralize).keys.collect { |val| [human_enum_name(enum_name, val), val] }
armchairdj

32

Đây là một cái nhìn:

select_tag :gender, options_for_select(Profile.gender_attributes_for_select)

Đây là một mô hình (bạn có thể chuyển mã này thành một người trợ giúp hoặc một người trang trí trên thực tế)

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

Và đây là tệp ngôn ngữ:

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

1
nhưng làm thế nào để có được bản dịch cho một bản ghi trong trường hợp này? Bởi vì .human_attribute_name('genders.male')không hoạt động
Stiig

Cảm ơn bạn, hoạt động giống như sự quyến rũ trong trường hợp của tôi !
matiss

Tôi đã thực hiện đá quý nhẹ cho những mục đích github.com/shlima/translate_enum
Aliaksandr

30

Để giữ cho việc quốc tế hóa tương tự như bất kỳ thuộc tính nào khác, tôi đã làm theo cách thuộc tính lồng nhau như bạn có thể thấy ở đây .

Nếu bạn có một lớp học User:

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

ymlnhư thế này:

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

Bạn có thể dùng:

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

1
Điều này hấp dẫn trực quan nhưng nó phá vỡ quy ước đường ray activerecord.attributes.<fieldname>labelbản dịch cho người trợ giúp biểu mẫu
Chris Beck

5
@ChrisBeck nó xuất hiện này theo quy ước mô tả trong Rails i18n Hướng dẫn: guides.rubyonrails.org/...
danblaker

Theo kinh nghiệm của tôi, điều này hoạt động mà không cần sử dụng rolechìa khóa. Bạn có thể lồng coordinatorteachertrực tiếp dưới user.
Ryan Crispin Heneise

7

Mô hình:

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

Ngôn ngữ:

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

Và trên chế độ xem (.slim):

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

6

Dựa trên câu trả lời của user3647358, bạn có thể hoàn thành điều đó rất gần với những gì bạn đã quen khi dịch tên thuộc tính.

Tệp ngôn ngữ:

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

Dịch bằng cách gọi I18n # t:

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

4

Hãy thử sử dụng đá quý TranslateEnum cho những mục đích này

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
Chúng tôi cũng sử dụng đá quý này. Có cách tiếp cận sạch nhất từ ​​tất cả các tùy chọn mà chúng tôi đã đánh giá và được duy trì tốt.
cseelus

3

Tôi đã tạo ra một viên ngọc cho việc này.

http://rubygems.org/gems/translated_attribute_value

Thêm vào tệp gem của bạn:

gem 'translated_attribute_value'

Nếu bạn có trường trạng thái cho người dùng:

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

Và theo quan điểm của bạn, bạn có thể gọi như thế này:

user.status_translated

Nó hoạt động với bản ghi hoạt động, mongoid hoặc bất kỳ lớp nào khác với getter / setters:

https://github.com/viniciusoyama/translated_attribute_value


3

Kết hợp các câu trả lời từ RepolêsAliaksandr , đối với Rails 5, chúng ta có thể xây dựng 2 phương thức cho phép bạn dịch một giá trị đơn lẻ hoặc một tập hợp các giá trị từ một thuộc tính enum.

Thiết lập các bản dịch trong .ymltệp của bạn :

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

Trong ApplicationRecordlớp, từ đó tất cả các mô hình kế thừa, chúng tôi xác định một phương thức xử lý các bản dịch cho một giá trị duy nhất và một phương thức khác xử lý các mảng bằng cách gọi nó:

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 

Theo quan điểm của chúng tôi, sau đó chúng tôi có thể dịch các giá trị đơn lẻ:

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

Hoặc toàn bộ tập hợp các giá trị enum:

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

2

Hãy thử đá quý enum_help . Từ mô tả của nó:

Giúp tính năng ActiveRecord :: Enum hoạt động tốt với I18n và simple_form.


2

Đây là một t_enumphương pháp trợ giúp mà tôi sử dụng.

<%= 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"

2

Ngươi mâu:

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

Tệp ngôn ngữ:

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

Sử dụng:

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

Làm thế nào về @user.role, bởi vì đó là vấn đề chính.
Code-MonKy

Một cách thẳng thắn nhất, sạch sẽ và thanh lịch.
Fabian Winkler

5
AnyModel.human_attribute_name (: i_dont_exist) => "Tôi không tồn tại"
Shiyason

1

Tôi thích một người trợ giúp đơn giản trong 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

Sau đó, trong tệp YML của tôi:

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

0

Tuy nhiên, theo một cách khác, tôi thấy thuận tiện hơn một chút khi sử dụng mối quan tâm trong các mô hình

Liên quan :

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"

Lượt xem :

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

Đừng quên thêm mối quan tâm vào mô hình của bạn:

class Campaign < ActiveRecord::Base
  include EnumTranslation

  enum status: [:designed, :created, :active, :failed, :success]
end

0

Bạn chỉ cần thêm một người trợ giúp:

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

và thiết lập nó như thường lệ:

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

sau đó sử dụng nó với lựa chọn của bạn: my_something_list


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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.