-->

Rails: Model.human_attribute_name :field should ra

2019-05-27 12:53发布

问题:

We often stumble over untranslated model attributes in our application. They most often come because an attribute was renamed or something like this.

It would be really helpful to have I18n raise an error when Model.human_attribute_name :field doesn't find a translation. Is there a way to achieve this?

Update:

It seems there's some other problem. here are my I18n settings:

I18n.enforce_available_locales = false
config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')]
config.i18n.default_locale = 'de-CH'
config.i18n.available_locales = ['de', 'de-CH', 'en']
config.i18n.locale = 'de-CH'
config.i18n.fallbacks = {'de-CH' => 'de', 'en-GB' => 'en'}

I can't set fallbacks = false because I want missing translations of de-CH to gracefully delegate to de, which in general seems to work fine. But for my state machine attribute human_to_state method it doesn't seem to work. Here's the view code causing the problem:

= f.input :state_event, collection: f.object.state_transitions,
                        label_method: :human_to_name # This causes the problem!

This is printed out as "State event" in the view, and when I add the following I18n key, it's translated successfully to "Status":

de: mongoid: attributes: activity: state_event: Status

So there really is a missing translation, but I18n doesn't complain in any way. I also tried to catch the exception using a custom exception handler, but this doesn't seem to be raised:

I18n.exception_handler = lambda do |exception, locale, key, options|
  binding.pry # This is never reached!
end

Any idea what's going on? Is it a problem with state machine?

回答1:

The problem lies in the fact that human_attribute_name falls back to

defaults << attribute.to_s.humanize

when nothing else found. In other words, human_attribute_name will never raise an error.

I "fixed" this by overriding human_attribute_name, patching the above mentioned line:

(put this in an initializer)

require 'active_support/core_ext/hash/reverse_merge'

module ActiveModel
  module Translation
    include ActiveModel::Naming

    def human_attribute_name(attribute, options = {})
      defaults = lookup_ancestors.map do |klass|
        [:"#{self.i18n_scope}.attributes.#{klass.model_name.i18n_key}.#{attribute}",
         :"#{self.i18n_scope}.attributes.#{klass.model_name.i18n_key.to_s.tr('.', '/')}.#{attribute}"]
      end.flatten

      defaults << :"attributes.#{attribute}"
      defaults << options.delete(:default) if options[:default]
      defaults << attribute.to_s.humanize if Rails.env.production? # Monkey patch

      options.reverse_merge! :count => 1, :default => defaults
      I18n.translate(defaults.shift, options)
    end
  end
end


回答2:

Possible duplicate of : How to enable Rails I18n translation errors in views?

The accepted answer is:

config.i18n.fallbacks = false

@BettySt 's answer is pretty cool too, you should take a look at her solution.

Doc about how to handle I18n translation errors: http://guides.rubyonrails.org/i18n.html#using-different-exception-handlers