From dad80ad7862834543783974a22d316f074cfee66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 20 Jun 2010 14:44:38 +0200 Subject: [PATCH] I18n.reload! is only called if any of the locale files actually changed. --- activesupport/lib/active_support/i18n.rb | 1 + .../lib/active_support/i18n_railtie.rb | 80 +++++++++++ activesupport/lib/active_support/railtie.rb | 72 +--------- .../application/initializers/i18n_test.rb | 133 +++++++++++++++--- railties/test/railties/i18n_railtie_test.rb | 89 ------------ 5 files changed, 196 insertions(+), 179 deletions(-) create mode 100644 activesupport/lib/active_support/i18n_railtie.rb delete mode 100644 railties/test/railties/i18n_railtie_test.rb diff --git a/activesupport/lib/active_support/i18n.rb b/activesupport/lib/active_support/i18n.rb index 0ffdd904fd..45b9d20c01 100644 --- a/activesupport/lib/active_support/i18n.rb +++ b/activesupport/lib/active_support/i18n.rb @@ -4,5 +4,6 @@ $stderr.puts "You don't have i18n installed in your application. Please add it to your Gemfile and run bundle install" raise e end + I18n.load_path << "#{File.dirname(__FILE__)}/locale/en.yml" ActiveSupport.run_load_hooks(:i18n) diff --git a/activesupport/lib/active_support/i18n_railtie.rb b/activesupport/lib/active_support/i18n_railtie.rb new file mode 100644 index 0000000000..d82e54f1d4 --- /dev/null +++ b/activesupport/lib/active_support/i18n_railtie.rb @@ -0,0 +1,80 @@ +require "active_support" +require "rails" +require "active_support/file_update_checker" + +module I18n + class Railtie < Rails::Railtie + config.i18n = ActiveSupport::OrderedOptions.new + config.i18n.railties_load_path = [] + config.i18n.load_path = [] + config.i18n.fallbacks = ActiveSupport::OrderedOptions.new + + def self.reloader + @reloader ||= ActiveSupport::FileUpdateChecker.new([]){ I18n.reload! } + end + + # Add I18n::Railtie.reloader to ActionDispatch callbacks. Since, at this + # point, no path was added to the reloader, I18n.reload! is not triggered + # on to_prepare callbacks. This will only happen on the config.after_initialize + # callback below. + initializer "i18n.callbacks" do + ActionDispatch::Callbacks.to_prepare do + I18n::Railtie.reloader.execute_if_updated + end + end + + # Set the i18n configuration only after initialization since a lot of + # configuration is still usually done in application initializers. + config.after_initialize do |app| + fallbacks = app.config.i18n.delete(:fallbacks) + + app.config.i18n.each do |setting, value| + case setting + when :railties_load_path + app.config.i18n.load_path.unshift(*value) + when :load_path + I18n.load_path += value + else + I18n.send("#{setting}=", value) + end + end + + init_fallbacks(fallbacks) if fallbacks && validate_fallbacks(fallbacks) + + reloader.paths.concat I18n.load_path + reloader.execute_if_updated + end + + protected + + def self.include_fallbacks_module + I18n.backend.class.send(:include, I18n::Backend::Fallbacks) + end + + def self.init_fallbacks(fallbacks) + include_fallbacks_module + + args = case fallbacks + when ActiveSupport::OrderedOptions + [*(fallbacks[:defaults] || []) << fallbacks[:map]].compact + when Hash, Array + Array.wrap(fallbacks) + else # TrueClass + [] + end + + I18n.fallbacks = I18n::Locale::Fallbacks.new(*args) + end + + def self.validate_fallbacks(fallbacks) + case fallbacks + when ActiveSupport::OrderedOptions + !fallbacks.empty? + when TrueClass, Array, Hash + true + else + raise "Unexpected fallback type #{fallbacks.inspect}" + end + end + end +end \ No newline at end of file diff --git a/activesupport/lib/active_support/railtie.rb b/activesupport/lib/active_support/railtie.rb index 59f9ab18b1..1f32f8718f 100644 --- a/activesupport/lib/active_support/railtie.rb +++ b/activesupport/lib/active_support/railtie.rb @@ -1,5 +1,6 @@ require "active_support" require "rails" +require "active_support/i18n_railtie" module ActiveSupport class Railtie < Rails::Railtie @@ -26,75 +27,4 @@ class Railtie < Rails::Railtie Time.zone_default = zone_default end end -end - -module I18n - class Railtie < Rails::Railtie - config.i18n = ActiveSupport::OrderedOptions.new - config.i18n.railties_load_path = [] - config.i18n.load_path = [] - config.i18n.fallbacks = ActiveSupport::OrderedOptions.new - - initializer "i18n.initialize" do - ActiveSupport.on_load(:i18n) do - I18n.reload! - - ActionDispatch::Callbacks.to_prepare do - I18n.reload! - end - end - end - - # Set the i18n configuration from config.i18n but special-case for - # the load_path which should be appended to what's already set instead of overwritten. - config.after_initialize do |app| - fallbacks = app.config.i18n.delete(:fallbacks) - - app.config.i18n.each do |setting, value| - case setting - when :railties_load_path - app.config.i18n.load_path.unshift(*value) - when :load_path - I18n.load_path += value - else - I18n.send("#{setting}=", value) - end - end - - init_fallbacks(fallbacks) if fallbacks && validate_fallbacks(fallbacks) - I18n.reload! - end - - class << self - protected - - def init_fallbacks(fallbacks) - include_fallbacks_module - args = case fallbacks - when ActiveSupport::OrderedOptions - [*(fallbacks[:defaults] || []) << fallbacks[:map]].compact - when Hash, Array - Array.wrap(fallbacks) - else # TrueClass - [] - end - I18n.fallbacks = I18n::Locale::Fallbacks.new(*args) - end - - def include_fallbacks_module - I18n.backend.class.send(:include, I18n::Backend::Fallbacks) - end - - def validate_fallbacks(fallbacks) - case fallbacks - when ActiveSupport::OrderedOptions - !fallbacks.empty? - when TrueClass, Array, Hash - true - else - raise "Unexpected fallback type #{fallbacks.inspect}" - end - end - end - end end \ No newline at end of file diff --git a/railties/test/application/initializers/i18n_test.rb b/railties/test/application/initializers/i18n_test.rb index 99b2d86013..a1fcba3310 100644 --- a/railties/test/application/initializers/i18n_test.rb +++ b/railties/test/application/initializers/i18n_test.rb @@ -8,48 +8,143 @@ def setup build_app boot_rails FileUtils.rm_rf "#{app_path}/config/environments" + require "rails/all" end - # i18n + def load_app + require "#{app_path}/config/environment" + end + + def app + @app ||= Rails::Application + end + + def assert_fallbacks(fallbacks) + fallbacks.each do |locale, expected| + actual = I18n.fallbacks[locale] + assert_equal expected, actual, "expected fallbacks for #{locale.inspect} to be #{expected.inspect}, but were #{actual.inspect}" + end + end + + def assert_no_fallbacks + assert !I18n.backend.class.included_modules.include?(I18n::Backend::Fallbacks) + end + + # Locales test "setting another default locale" do add_to_config <<-RUBY - config.root = "#{app_path}" config.i18n.default_locale = :de RUBY - require "#{app_path}/config/environment" + load_app assert_equal :de, I18n.default_locale end + # Load paths test "no config locales dir present should return empty load path" do FileUtils.rm_rf "#{app_path}/config/locales" - add_to_config <<-RUBY - config.root = "#{app_path}" - RUBY - require "#{app_path}/config/environment" - + load_app assert_equal [], Rails.application.config.i18n.load_path end - test "config locales dir present should be added to load path" do + test "locale files should be added to the load path" do + app_file "config/another_locale.yml", "" + add_to_config <<-RUBY - config.root = "#{app_path}" + config.i18n.load_path << config.root.join("config/another_locale.yml").to_s RUBY - require "#{app_path}/config/environment" - assert_equal ["#{app_path}/config/locales/en.yml"], Rails.application.config.i18n.load_path + load_app + assert_equal [ + "#{app_path}/config/locales/en.yml", "#{app_path}/config/another_locale.yml" + ], Rails.application.config.i18n.load_path + + assert I18n.load_path.include?("#{app_path}/config/locales/en.yml") + assert I18n.load_path.include?("#{app_path}/config/another_locale.yml") end - test "config defaults should be added with config settings" do + test "locales are reloaded if they change between requests" do add_to_config <<-RUBY - config.root = "#{app_path}" - config.i18n.load_path << "my/other/locale.yml" + config.cache_classes = false RUBY - require "#{app_path}/config/environment" - assert_equal [ - "#{app_path}/config/locales/en.yml", "my/other/locale.yml" - ], Rails.application.config.i18n.load_path + app_file "config/locales/en.yml", <<-YAML +en: + foo: "1" + YAML + + app_file 'config/routes.rb', <<-RUBY + AppTemplate::Application.routes.draw do |map| + match '/i18n', :to => lambda { |env| [200, {}, [I18n.t(:foo)]] } + end + RUBY + + require 'rack/test' + extend Rack::Test::Methods + load_app + + get "/i18n" + assert_equal "1", last_response.body + + app_file "config/locales/en.yml", <<-YAML +en: + foo: "2" + YAML + + get "/i18n" + assert_equal "2", last_response.body + end + + # Fallbacks + test "not using config.i18n.fallbacks does not initialize I18n.fallbacks" do + I18n.backend = Class.new { include I18n::Backend::Base }.new + load_app + assert_no_fallbacks + end + + test "config.i18n.fallbacks = true initializes I18n.fallbacks with default settings" do + I18n::Railtie.config.i18n.fallbacks = true + load_app + assert I18n.backend.class.included_modules.include?(I18n::Backend::Fallbacks) + assert_fallbacks :de => [:de, :en] + end + + test "config.i18n.fallbacks = true initializes I18n.fallbacks with default settings even when backend changes" do + I18n::Railtie.config.i18n.fallbacks = true + I18n::Railtie.config.i18n.backend = Class.new { include I18n::Backend::Base }.new + load_app + assert I18n.backend.class.included_modules.include?(I18n::Backend::Fallbacks) + assert_fallbacks :de => [:de, :en] + end + + test "config.i18n.fallbacks.defaults = [:'en-US'] initializes fallbacks with en-US as a fallback default" do + I18n::Railtie.config.i18n.fallbacks.defaults = [:'en-US'] + load_app + assert_fallbacks :de => [:de, :'en-US', :en] + end + + test "config.i18n.fallbacks.map = { :ca => :'es-ES' } initializes fallbacks with a mapping ca => es-ES" do + I18n::Railtie.config.i18n.fallbacks.map = { :ca => :'es-ES' } + load_app + assert_fallbacks :ca => [:ca, :"es-ES", :es, :en] + end + + test "[shortcut] config.i18n.fallbacks = [:'en-US'] initializes fallbacks with en-US as a fallback default" do + I18n::Railtie.config.i18n.fallbacks = [:'en-US'] + load_app + assert_fallbacks :de => [:de, :'en-US', :en] + end + + test "[shortcut] config.i18n.fallbacks = [{ :ca => :'es-ES' }] initializes fallbacks with a mapping de-AT => de-DE" do + I18n::Railtie.config.i18n.fallbacks.map = { :ca => :'es-ES' } + load_app + assert_fallbacks :ca => [:ca, :"es-ES", :es, :en] + end + + test "[shortcut] config.i18n.fallbacks = [:'en-US', { :ca => :'es-ES' }] initializes fallbacks with the given arguments" do + I18n::Railtie.config.i18n.fallbacks = [:'en-US', { :ca => :'es-ES' }] + load_app + assert_fallbacks :ca => [:ca, :"es-ES", :es, :'en-US', :en] end end end \ No newline at end of file diff --git a/railties/test/railties/i18n_railtie_test.rb b/railties/test/railties/i18n_railtie_test.rb deleted file mode 100644 index 2b1950b3d5..0000000000 --- a/railties/test/railties/i18n_railtie_test.rb +++ /dev/null @@ -1,89 +0,0 @@ -require "isolation/abstract_unit" - -module RailtiesTest - class I18nRailtieTest < Test::Unit::TestCase - include ActiveSupport::Testing::Isolation - - def setup - build_app - boot_rails - FileUtils.rm_rf("#{app_path}/config/environments") - require "rails/all" - end - - def load_app - require "#{app_path}/config/environment" - end - - def assert_fallbacks(fallbacks) - fallbacks.each do |locale, expected| - actual = I18n.fallbacks[locale] - assert_equal expected, actual, "expected fallbacks for #{locale.inspect} to be #{expected.inspect}, but were #{actual.inspect}" - end - end - - def assert_no_fallbacks - assert !I18n.backend.class.included_modules.include?(I18n::Backend::Fallbacks) - end - - test "config.i18n.load_path gets added to I18n.load_path" do - I18n.load_path = ['existing/path/to/locales'] - I18n::Railtie.config.i18n.load_path = ['new/path/to/locales'] - load_app - - assert I18n.load_path.include?('existing/path/to/locales') - assert I18n.load_path.include?('new/path/to/locales') - end - - test "not using config.i18n.fallbacks does not initialize I18n.fallbacks" do - I18n.backend = Class.new { include I18n::Backend::Base }.new - load_app - assert_no_fallbacks - end - - test "config.i18n.fallbacks = true initializes I18n.fallbacks with default settings" do - I18n::Railtie.config.i18n.fallbacks = true - load_app - assert I18n.backend.class.included_modules.include?(I18n::Backend::Fallbacks) - assert_fallbacks :de => [:de, :en] - end - - test "config.i18n.fallbacks = true initializes I18n.fallbacks with default settings even when backend changes" do - I18n::Railtie.config.i18n.fallbacks = true - I18n::Railtie.config.i18n.backend = Class.new { include I18n::Backend::Base }.new - load_app - assert I18n.backend.class.included_modules.include?(I18n::Backend::Fallbacks) - assert_fallbacks :de => [:de, :en] - end - - test "config.i18n.fallbacks.defaults = [:'en-US'] initializes fallbacks with en-US as a fallback default" do - I18n::Railtie.config.i18n.fallbacks.defaults = [:'en-US'] - load_app - assert_fallbacks :de => [:de, :'en-US', :en] - end - - test "config.i18n.fallbacks.map = { :ca => :'es-ES' } initializes fallbacks with a mapping ca => es-ES" do - I18n::Railtie.config.i18n.fallbacks.map = { :ca => :'es-ES' } - load_app - assert_fallbacks :ca => [:ca, :"es-ES", :es, :en] - end - - test "[shortcut] config.i18n.fallbacks = [:'en-US'] initializes fallbacks with en-US as a fallback default" do - I18n::Railtie.config.i18n.fallbacks = [:'en-US'] - load_app - assert_fallbacks :de => [:de, :'en-US', :en] - end - - test "[shortcut] config.i18n.fallbacks = [{ :ca => :'es-ES' }] initializes fallbacks with a mapping de-AT => de-DE" do - I18n::Railtie.config.i18n.fallbacks.map = { :ca => :'es-ES' } - load_app - assert_fallbacks :ca => [:ca, :"es-ES", :es, :en] - end - - test "[shortcut] config.i18n.fallbacks = [:'en-US', { :ca => :'es-ES' }] initializes fallbacks with the given arguments" do - I18n::Railtie.config.i18n.fallbacks = [:'en-US', { :ca => :'es-ES' }] - load_app - assert_fallbacks :ca => [:ca, :"es-ES", :es, :'en-US', :en] - end - end -end \ No newline at end of file -- GitLab