4

I am building a Rails 4 site for a client in Singapore, Malaysia, Taiwan and China.

The locale code for a Chinese speaking Malaysian is zh-MY.

I would like to keep a base zh-CN (Simplified Chinese) set of locale files and for zh-MY to fallback to zh-CN.

Just having a zh is not correct as zh-TW (Traditional Chinese) is what Taiwan uses and there are big differences between that and zh-CN.

So here's my config/application.rb file as per the Rails Guide.

require File.expand_path('../boot', __FILE__)

require 'rails/all'
require "i18n/backend/fallbacks"

module MyAwesomeApp
  class Application < Rails::Application
    I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)

    # all translations from config/locales/**/*.rb,yml are auto loaded.
    config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')]

    # The default locale is :en
    config.i18n.default_locale = :en

    # See http://guides.rubyonrails.org/i18n.html#localized-views for a discussion of
    # how language codes fall-back.
    config.i18n.available_locales = [:en, :'zh-CN', :'zh-TW', :'en-SG', :'en-MY', :'zh-MY']
    I18n.fallbacks.map(:'zh-MY' => :'zh-CN')
  end
end

But this simply doesn't work.

When I actually set the locale to :zh-MY it does not fall back to :zh-CN but to :en

What am I missing?

update: If I puts "I18n.fallbacks #{I18n.fallbacks}" it says I18n.fallbacks {}. Clearly I18n.fallbacks.map is failing.

update As per the suggestion in the comments I looked at I18n.fallbacks[:'zh-MY'] in the very next line after I checked I18n.fallbacks and it returns [:"zh-MY", :zh, :"zh-CN", :en]

update With a binding.pry in my application controller I have checked the locale etc and observe this:

[1] pry(#<ServicesController>)> I18n.locale
=> :"zh-MY"
[2] pry(#<ServicesController>)> I18n.fallbacks
=> {:en=>[:en], :"zh-MY"=>[:"zh-MY", :zh, :en]}

So somewhere between the Rails app starting up and the controller's set_locale method being called, I18n.fallbacks is being reset to the default.

Dave Sag
  • 12,289
  • 8
  • 77
  • 118

1 Answers1

6

Don't ask me why but this works, despite what the official docs say.

require File.expand_path('../boot', __FILE__)

require 'rails/all'
require "i18n/backend/fallbacks"

Bundler.require(*Rails.groups)

module MyAwesomeApp
  class Application < Rails::Application
    # all translations from config/locales/**/*.rb,yml are auto loaded.
    config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')]

    # The default locale is :en
    config.i18n.default_locale = :en

    # See http://guides.rubyonrails.org/i18n.html#localized-views for a
    # mostly correct discussion of how language codes fall-back.
    config.i18n.available_locales = [:en, :'zh-CN', :'zh-TW', :'en-SG', :'en-MY', :'zh-MY']
    config.i18n.fallbacks = {:'zh-MY' => :'zh-CN'}
  end
end

Removing the I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks) and setting the fallbacks via config.i18n.fallbacks = {:'zh-MY' => :'zh-CN'} rather than I18n.fallbacks.map(:'zh-MY' => :'zh-CN') makes it all work perfectly.

And now in my controller, at the same breakpoint as discussed in the 3rd question update:

[1] pry(#<ServicesController>)> I18n.fallbacks
=> {:en=>[:en], :"zh-MY"=>[:"zh-MY", :zh, :"zh-CN", :en]}

I hope this is helpful to others.

Dave Sag
  • 12,289
  • 8
  • 77
  • 118