0

I just noticed, that the I18n of activerecord.messages.restrict_dependent_destroy interpolates the %{record} key while making it downcase:

activerecord:
  errors:
    messages:
      restrict_dependent_destroy:
        one: Cannot delete record because a dependent %{record} exists

Becomes:

Cannot delete record because a dependent users exists

For english, this is fine, but for German, nouns must start uppercase:

Kann Datensatz nicht löschen, weil abhängige benutzer existieren # Must be "Benutzer"!

How can I change this behaviour?

Joshua Muheim
  • 12,617
  • 9
  • 76
  • 152
  • I think the only possible way is by monkeypatching [I18n.interpolate_hash](https://github.com/ruby-i18n/i18n/blob/3269c01edf3bb9537602bf0467a6bab38b3d9ba6/lib/i18n/interpolate/ruby.rb#L22) to eval the placeholder so that you can do `Kann Datensatz nicht löschen, weil abhängige #{record.capitalize} existieren`. There is an older question [here](https://stackoverflow.com/questions/9642901/how-to-change-case-of-interpolated-variables-in-rails-locale-file) that may be a duplicate but I'm not sure its relevant for the latest versions of rails. – max Sep 03 '19 at 14:33
  • Another possible solution is by overriding [ActiveModel::Naming#model_name](https://api.rubyonrails.org/classes/ActiveModel/Naming.html#method-i-model_name) in your models with something like `I18n.locale == :de ? super.capitalize : super`. But that might just create new problems as its not context aware. – max Sep 03 '19 at 14:44

2 Answers2

2

The problem does not lie in your translation dictionaries.Thats why changing it to uppercase in your dictionaries did not work.

Below are the code snippets from the activerecord-5.1.6 handler function for both has_one and has_many associations for your specific error, meaning: restrict_dependent_destroy.

has_one:

  def handle_dependency
    case options[:dependent]
    when :restrict_with_exception
      raise ActiveRecord::DeleteRestrictionError.new(reflection.name) if load_target

    when :restrict_with_error
      if load_target
        record = owner.class.human_attribute_name(reflection.name).downcase
        owner.errors.add(:base, :'restrict_dependent_destroy.has_one', record: record)
        throw(:abort)
      end

    else
      delete
    end
  end

has_many:

def handle_dependency
    case options[:dependent]
    when :restrict_with_exception
      raise ActiveRecord::DeleteRestrictionError.new(reflection.name) unless empty?

    when :restrict_with_error
      unless empty?
        record = owner.class.human_attribute_name(reflection.name).downcase
        owner.errors.add(:base, :'restrict_dependent_destroy.has_many', record: record)
        throw(:abort)
      end

    when :destroy
      # No point in executing the counter update since we're going to destroy the parent anyway
      load_target.each { |t| t.destroyed_by_association = reflection }
      destroy_all
    else
      delete_all
    end
  end

In both cases as you can see the "record" is obtained through the following line:

record = owner.class.human_attribute_name(reflection.name).downcase

You stated that this is your problem.

Override the specific functions I just showed in the snippets and remove the .downcase call from the end of both of them and its bound to work.

If you do not know how to override gem module methods refer to this question

JBlanco
  • 517
  • 5
  • 9
0

It's recommended to change the locale of User:

# config/locales/de.yml
de:
  activerecord:
    models:
      user: "Benutzer"

By doing so, your translation should pickup the new translation with upercase in the code above. Don't forget to restart your rails server.

Vibol
  • 1,158
  • 1
  • 9
  • 23
  • I think the correct key would be `de.activerecord.models.user.one`. This is exactly the way I'm having it in my app, and I expected it to work. But it doesn't. Hence this question. – Joshua Muheim Sep 04 '19 at 18:35