Translate model nested attribute validation message

starfry picture starfry · Aug 4, 2014 · Viewed 8.9k times · Source

I have a nested attribute on which I perform presence validation. I am trying without success to provide translations for the attribute name that is returned in the full error message text.

The model is called Identity and contains an attribute called identity The model is nested within another with a has_many relationship.

A typical error message is currently returned like this

Identities identity can't be blank

I want to translate the attribute (by default Identities identity) into something else.

I have

en:
  activerecord:
    models:
      identity:
        identity: "whatever"

If I do this, I get an error

I18n::InvalidPluralizationData (translation data {:identity=>"whatever"} can not be used with :count => 1):

I have tried to add pluralisation data to this by altering the above to

en:
  activerecord:
    models:
      identity:
        identity:
          one: "one"
          other: "other"

This changes the error to

I18n::InvalidPluralizationData (translation data {:identity=>{:one=>"one", :other=>"other"}} can not be used with :count => 1):

I have also tried many instead of other without difference.

I have spent a few hours trying to make this work, having read other questions on Stack Overflow and elsewhere, without success. What is the correct way to write translations for attribute names ?

Answer

starfry picture starfry · Aug 4, 2014

Adding some debugging output to the human_attribute_name method reveals what the i18n path should be.

The example has a user model with a has_many :identities relationship. The desired attribute is identity, an attribute of the Identity model, of which the User model has many.

I looked in gems/activemodel-4.0.1/lib/active_model, file translation.rb. The human_attribute_name method looks up the following path:

:"activerecord.attributes.user/identities.identity"

It also specifies the following as defaults, which are fallback translations:

:"activerecord.attributes.user/identities.identity"
:"activerecord.attributes.identities.identity"
:"attributes.identity"
"Identities identity"
"Identity"

the last two are strings, the first will match if none of the paths represented as symbols match available translations. So, in the case of no translations, the output will be the string "Identities identity" (the other string, "Identity" will never be used).

So, any of the following translation paths will work:

activerecord.attributes.user/identities.identity
activerecord.attributes.identities.identity
attributes.identity

The paths are tried in that order and the first to match is the one that will be used.