svenfuchs
4/14/2010 - 8:02 AM

rails_i18n_fallbacks.rb

class I18n::Railtie
  # ...
  config.i18n.fallbacks = ActiveSupport::OrderedOptions.new
  # ...
  config.after_initialize do |app|
    app.config.i18n.each do |setting, value|
      case setting
      # ...
      when :fallbacks
        init_fallbacks(setting)
      # ...
      end
    end
  end
  
  def init_fallbacks(fallbacks)
    if fallbacks
      include_fallbacks_module
      args = Hash === fallbacks || Array === fallbacks ? Array.make_array(fallbacks) : []
      I18n.fallbacks = I18n::Fallbacks.new(*args)
    
      if ActiveSupport::OrderedOptions === fallbacks
        fallbacks.each { |key, value| I18n.fallbacks.send(key, value) }
      end
    else
      I18n.fallbacks = nil
    end
  end
  
  def include_fallbacks_module
    unless I18n.backend.class.included_modules.include?(I18n::Backend::Fallbacks)
      I18n.backend.class.send(:include, I18n::Backend::Fallbacks)
    end
  end
end

# USAGE

# do nothing in config
# => uses I18n::Fallbacks.new, which just always falls back to the default locale

# set to true
config.fallbacks = true
# => same thing as doing nothing

# set to false or nil
config.fallbacks = false
config.fallbacks = nil
# => sets I18n.fallbacks to nil, i.e. disables fallbacks

# use the OrderedOptions
config.fallbacks.map = { :'de-DE' => :de }
config.fallbacks.defaults = [:'de-DE', :de]
# => uses I18n::Fallbacks.new, then calls map(:'de-DE' => :de) and defaults([:'de-DE', :de]) on the instance
# does the same thing as below

# SHORTCUTS

# set to an Array of defaults
config.fallbacks = [:'de-DE', :de]
# => uses I18n::Fallbacks.new(:'de-DE', :de), which additionally always falls back through de-DE and de

# set to a Hash of mappings
config.fallbacks = { :'de-DE' => :de }
# => uses I18n::Fallbacks.new(:'de-DE', :de), which additionally falls back from only de-DE to de

# default Array and mappings Hash can be mixed, too
config.fallbacks = [:'en-GB', :'en-US', { :'de-DE' => :de }]
# => uses I18n::Fallbacks.new(:'en-GB', :'en-US', { :'de-DE' => :de })


# Might omit the shortcuts which only spare a single line in the config block
# which would make the implementation of init_fallbacks much simpler.
#
# I18n::Fallbacks is a rather arcane feature anyway, I guess almost nobody will
# need to use special defaults and mappings.


# DEFAULT SETTING
#
# If we have Rails default I18n.fallbacks to some setting then this has to be
# reloaded during after_initialize, right? If so then there's no way to decide
# if whatever is in I18n.fallbacks already was initialized during the last
# request (in which case it would need to be overwritten) or somewhere earlier
# during the intialization process (e.g. engines, in which case it should not
# be overwritten).
#
# Another problem with a Rails default is that we don't know for sure that any
# backend class that people might want to use is definitely compatible with 
# the I18n::Backend::Fallbacks module. Backend classes shipped with I18n are,
# but we've encouraged people to build their own backends in the past. So having
# Rails include a module that potentially might not be compatible seems a bit
# intrusive.
#
# I'd thus suggest to not have Rails default to I18n.fallbacks but let people
# easily opt in through config.fallbacks = true