I18n in model validations: Possible or not?

Hi there,

I have the following validation in a model:

  validates_inclusion_of :whatever, :in => [true, false], :message => I18n.t('please_select_whatever')

It seems that the translation does not work in production mode: in all languages it's always the english translation that gets diplayed (probably because I set english as the default locale in my app...?).

So I am assuming that we can't translate validations in models, because models get loaded only once - when the server is booted (and then, the default locale would be applied).

Am I right? If yes, how would you solve this problem?

Thanks for your help! Tom

try passing the argument as a lambda function

:message =>lambda { I18n.t(‘please_select_whatever’) }

i havent try it but it makes sense

:message =>lambda { I18n.t('please_select_whatever') }

Thanks for the suggestion - unfortunately, it doesn't change the outcome...

Tom Ha wrote in post #968590:

:message =>lambda { I18n.t('please_select_whatever') }

Thanks for the suggestion - unfortunately, it doesn't change the outcome...

Perhaps you should just have the validation routine generate the translation key (in other words, leave off I18n.t), then apply the translation in the view layer.

Best,

since that is the default behavior i assumed ‘please_select_whatever’ is a dynamic value taken from the model, if its not the case everything should word without the need of doing the translation in the model

then apply the translation in the view layer.

Thanks... In that case, how could that be done if I have the following partial, for the error messages?

<%= error_messages_for :whatever_model, :header_message => nil, :message => nil %>

Tom Ha wrote in post #968598:

then apply the translation in the view layer.

Thanks... In that case, how could that be done if I have the following partial, for the error messages?

<%= error_messages_for :whatever_model, :header_message => nil, :message => nil %>

I don't think it can. You'd need to use the errors array instead.

Best,

you are going to need to create a custom validation and add the field to the locales it seems

http://railscasts.com/episodes/211-validations-in-rails-3

Radhames Brito wrote in post #968604:

you are going to need to create a custom validation and add the field to the locales it seems

#211 Validations in Rails 3 - RailsCasts

I don't see why.

Best,

In particular see the table in section "5.1.2 Error Message Interpolation"

Rails Internationalization (I18n) API — Ruby on Rails Guides

In particular see the table in section "5.1.2 Error Message Interpolation"

Thanks, that helped. The following works:

In the model:

validates_inclusion_of :whatever, :in => [true, false], :message => I18n.t('activerecord.errors.models.my_model.attributes.whatever.please_select_whatever')

In config/locales/en.yml:

en:   activerecord:     errors:       models:         my_model:           attributes:             whatever:               please_select_whatever: "Please select whatever."

In the model:

validates_inclusion_of :whatever, :in => [true, false], :message =>

I18n.t('activerecord.errors.models.my_model.attributes.whatever.please_select_whatever')

In config/locales/en.yml:

en:   activerecord:     errors:       models:         my_model:           attributes:             whatever:               please_select_whatever: "Please select whatever."

Nope, this doesn't work. I suspect it's still the same problem: it seems not possible to have translations in models (since they only get loaded once).

It may work for the default "keys" (for "validates_presence_of :name" the key would be "blank"), but not the custom ones.

It may work for the default "keys" (for "validates_presence_of :name" the key would be "blank"), but not the custom ones.

To sum it up: The solution is NOT to include any *custom* message keys in the models, like...

:message => I18n.t('activerecord.errors.models.my_model.attributes.whatever.please_select_whatever')

The model will then apply the default message keys, for example ":inclusion" in the case of "validates_inclusion_of"

...and in config/locales/en.yml you need to have:

en:   activerecord:     errors:       models:         my_model:           attributes:             whatever:               inclusion: "Please select whatever." # see key: "inclusion"

We've done it in the Kete app (http://github.com/kete/kete), but I can't recall the trick. I'll check with the guy that did it an see if he has an answer for you...

Cheers, Walter

I'll check with the guy that did it an see if he has an answer for you...

Thanks - why not, if there's a better/more elegant trick than the solution above (it works...).

Cheers, Tom

That's what I get for skimming...

We used lambda which I believe was already shown.

from Kete's app/models/choice.rb:

  validates_uniqueness_of :label, :message => lambda { I18n.t('choice_model.must_be_unique') }

Kieran, feel free to update with more info, if there are more details to point out.

Cheers, Walter

Hey,

In order to get locales working at runtime, I made the ActiveRecord validations call a proc (IIRC, similar to how Rails 3 does it now).

https://github.com/kete/kete/commit/5cd0e3fc728e76e88856e9dbec8d34639883924e

If you're using a Rails gem, or Rails is vendored, and you don't want it to be lost when upgrading, put it in an all_extensions.rb initializer, like I did here:

https://github.com/kete/kete/blob/master/config/initializers/all_extensions.rb#L98-107

Regards Kieran

Thanks for all the input!