10
votes

Rails somehow mixes my locales an I have absolutely no clue why. Most of my translated strings work as expected, but for some it mixes the locales.

Interestingly, this only happens on one of our systems. Specifically running Passenger with Apache.

When using Webrick, Thin, or Passenger Standalone on my development system everything is alright.

This is what I have in my application.rb:

config.i18n.default_locale = :de

This is in application_controller.rb:

before_filter :set_locale

def set_locale
  I18n.locale = @current_client ? @current_client.locale : I18n.default_locale
end

(I experience the problems on pages where @current_client is nil and the else part gets executed).

So, I am basically using the :de locale. When showing a validation error on a form, I experience mixed up translations like this:

ist zu kurz (nicht weniger als 6 Zeichen) und translation missing: en.activerecord.errors.custom.password_format

As you can see, the error message from the first failing validation is translated as expected, for the second error message tries to access the English translation (which does not exist).

I suspect a problem with lazy loading of translated strings even before the before_filter gets executed.

Any clues why this might happen?

For the record: This is Rails 3

EDIT:

I just discovered that this depends on the environment used. When using the development environment, everything is fine. When using the production environment (or a production-like) environment, I experience the behavior described above.

EDIT 2:

I found out even more: It specifically depends on config.cache_classes. When set to true, I see the mixed translations. When set to false (as in the typical development environment), i18n works as expected.

EDIT 3:

Maybe this is related to the following bug?

https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/5522

Edit 4:

This IS related to the bug mentioned above, the problem is due to eagerly loaded model classes, which use I18n strings, but eager class loading happens before I18n initialization, hence the translations are not found. There even is another bug about this:

https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/6353

Unfortunately, the Rails guys did not manage to include the fix in the recent 3.0.4 release (as far as I can tell). Hence I'm trying to figure out a workaround like this (in my application configuration):

 config.before_eager_load do
   I18n.load_path += Dir[Rails.root.join('config', 'locales', 'de.yml').to_s]
   I18n::Railtie.reloader.paths.concat I18n.load_path
   I18n::Railtie.reloader.execute_if_updated
   I18n.reload!
 end

Unlucky, this does not work. Any clues?

4
Mix generally appear when a translation is missing in your current locale.apneadiving
Well, the funny thing is, that the German translation is the complete one (the app is in German) and the English translation lacks most of the strings. As I wrote, it works on another machine, hence the translations are actually present. And the default locale is DE, so why does Rails try to use EN anyway?tbk

4 Answers

14
votes

This problem may also occours in case you have a Gem that also uses I18n (I was having this problem with active_admin). Rails sets I18n to late for the Gem to be able to use that same load_paths.

What I have done was to add this to production.rb:

config.before_configuration do
      I18n.load_path += Dir[Rails.root.join('config', 'locales', '*.{rb,yml}').to_s]
      I18n.locale = 'pt-PT'
      I18n.reload!
    end
2
votes

Here is my final workaround, which seems to work (put this in application.rb or one of your environment configuration files, as needed):

 # THIS IS A WORKAROUND FOR A I18N BUG IN RAILS!
 # Only required when cache_classes is set to true
 # See https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/6353
 config.before_eager_load do
   I18n.locale = :de
   I18n.load_path += Dir[Rails.root.join('config', 'locales', 'de.yml').to_s]
   I18n.reload!
 end

Hope this is useful to anybody else...

EDIT:

If this does not work for you, try before_configuration instead of before_eager_load (see solution below). At least, works again as workaround for me in Rails 3.0.10

0
votes

Have you tried fiddling with the Passenger spawn method settings? Try to set it to Conservative, this way Passenger should behave the same as Thin.

0
votes

Upgrading to rails 3.0.5 should fix this and similar I18n problems.

See: https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/6353