ruby-on-railsrubyrails-i18nmobility

Set per request i18n fallbacks in Rails?


I have a multi-country Rails app. And I need to set per request i18n fallbacks schema. Is it possible and how to achieve this?

UPD

class Country < ApplicationRecord
  # String attribute "languages" (array)
end

class CountriesController < ApplicationController

  def show
    @country = Country.find params[:id]

    I18n.fallbacks = {
      @country.languages.first => @country.languages.second
    } # This does not work

    render 'show'
  end
end

Solution

  • Experimenting a bit (with Rails 6), it is possible to change the fallbacks using the Simple (default) backend, but doing so is not thread-safe and will likely cause problems if you do it on a per-request basis. It's somewhat counter-intuitive -- setting I18n.locale is the documented way to dynamically set locale per request, so it's natural to assume fallbacks would work the same way. However, from the the i18n source:

    The only configuration value that is not global and scoped to thread is :locale.

    Even that isn't very clearly worded. But indeed locale is defined as an instance variable, and all other configuration attributes are @@ class variables.

    The Rails guide for I18n says that the Simple (default) backend was designed to only do the "simplest thing that could possibly work", but the framework allows for plugging in custom backends that go beyond that. So, the best way for you to achieve your result will be to find (or create) a backend that supports per-request fallbacks in a thread-safe way.


    For reference, if someone does need to change a language fallback outside the initializer (again, that's globally), fallbacks.map() does that:

    I18n.fallbacks.map(:ca => :"es-ES")
    

    My original answer mentioned fiddling with the fallback hash directly, but using .map() preserves falling back to the default locale.