r18n / r18n-rails-api

Rails I18n compatibility for R18n
GNU Lesser General Public License v3.0
0 stars 1 forks source link

Support activerecord error message scopes #8

Open 747 opened 3 years ago

747 commented 3 years ago

Rails activerecord has a function that looks up error messages in a fashion climbing up the inheritance tree (error message scopes). It seems to call I18n multiple times until it finds a translation, but R18n backend raises exception at the first try.

During debug, I change the following line: https://github.com/r18n/r18n-rails-api/blob/932c63fd4e16b115d867bdf31f998fcddcd52fb3/lib/r18n-rails-api/backend.rb#L64 like this:

        nil #raise ::I18n::MissingTranslationData.new(locale, key, options) 

It goes on normally and finds a more general key.

There should be a way that allows the default function to work well.

AlexWayfer commented 3 years ago

Hello. Thank you for your report. Can I get a more reproducible example please?

747 commented 3 years ago

Hi, this might be called a "minimal example", hopefully you can use it with gem install rails r18n-rails only. A simple model called Entity and requirement of r18n-rails are manually added.

test-rails-1.zip

You can see how R18n and I18n behave differently:

$ rails c
irb(main):001:0> e = Entity.new
=> #<Entity id: nil, name: nil, created_at: nil, updated_at: nil>
irb(main):002:0> e.name = 'e'
=> "e"
irb(main):003:0> e.validate
=> false
irb(main):004:0> e.errors[:name]
Traceback (most recent call last):
        1: from (irb):4
I18n::MissingTranslation (translation missing: en.activerecord.errors.models.entity.attributes.name.too_short)
irb(main):005:0> I18n.backend = I18n::Backend::Simple.new
=> #<I18n::Backend::Simple:0x000056369b619f18>
irb(main):006:0> f = Entity.new
=> #<Entity id: nil, name: nil, created_at: nil, updated_at: nil>
irb(main):007:0> f.name = 'f'
=> "f"
irb(main):008:0> f.validate
=> false
irb(main):009:0> f.errors[:name]
=> ["is too short (minimum is 3 characters)"]

I studied a bit, and the crucial parting seems here:

$ rails c
irb(main):001:0> I18n.t("activerecord.errors.that.do.not.exist")
Traceback (most recent call last):
        1: from (irb):1
I18n::MissingTranslation (translation missing: en.activerecord.errors.that.do.not.exist)
irb(main):002:0> I18n.backend = I18n::Backend::Simple.new
=> #<I18n::Backend::Simple:0x000055b199085908>
irb(main):003:0> I18n.t("activerecord.errors.that.do.not.exist")
=> "translation missing: en.activerecord.errors.that.do.not.exist"

It is because I18n throws an exception when a message is missing: https://github.com/ruby-i18n/i18n/blob/0888807ab2fe4f4c8a4b780f5654a8175df61feb/lib/i18n/backend/base.rb#L52

which will be caught by the caller: https://github.com/ruby-i18n/i18n/blob/0888807ab2fe4f4c8a4b780f5654a8175df61feb/lib/i18n.rb#L203-209

but R18n raises an exception so that it is brought up to the top level. https://github.com/r18n/r18n-rails-api/blob/932c63fd4e16b115d867bdf31f998fcddcd52fb3/lib/r18n-rails-api/backend.rb#L64