From 4d5c5096883d422fe6db45d1e6df4c7ef08b0eb8 Mon Sep 17 00:00:00 2001 From: Ben Hollis Date: Tue, 2 Apr 2013 23:28:47 -0700 Subject: [PATCH] Fix several issues around i18n and resource metadata. There are a few things changing here. One is that we always dup metadata before using it - this prevents a class of nasty bugs where after the first resource list build, blocks had been deleted from metadata hashes, meaning they would no longer be applied. Now they will always stick around. Then, I made sure that whenever we render a file, we save the previous I18n.locale and restore it afterwards, in case people change locale from blocks. This should help in some weird cases where files are rendered recursively. Finally, I've added a :lang option that can be used from "page" or "proxy" to allow people to specify the language for one or more files without having to pass a block that sets I18n.locale directly, which should make that pattern much cleaner. This fixes #809 and may also fix middleman/middleman-blog#106. --- .../lib/middleman-core/core_extensions/rendering.rb | 4 ++++ .../lib/middleman-core/sitemap/resource.rb | 1 + middleman-core/lib/middleman-core/sitemap/store.rb | 4 ++-- middleman-more/features/i18n_force_locale.feature | 13 +++++++++++++ middleman-more/fixtures/i18n-force-locale/config.rb | 13 +++++++++++++ .../fixtures/i18n-force-locale/locales/en.yml | 3 +++ .../fixtures/i18n-force-locale/locales/es.yml | 3 +++ .../fixtures/i18n-force-locale/locales/fr.yml | 3 +++ .../fixtures/i18n-force-locale/source/index.haml | 2 ++ .../lib/middleman-more/core_extensions/i18n.rb | 11 ++++++++--- 10 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 middleman-more/features/i18n_force_locale.feature create mode 100644 middleman-more/fixtures/i18n-force-locale/config.rb create mode 100644 middleman-more/fixtures/i18n-force-locale/locales/en.yml create mode 100644 middleman-more/fixtures/i18n-force-locale/locales/es.yml create mode 100644 middleman-more/fixtures/i18n-force-locale/locales/fr.yml create mode 100644 middleman-more/fixtures/i18n-force-locale/source/index.haml diff --git a/middleman-core/lib/middleman-core/core_extensions/rendering.rb b/middleman-core/lib/middleman-core/core_extensions/rendering.rb index 9cf1baff..2b155c7b 100644 --- a/middleman-core/lib/middleman-core/core_extensions/rendering.rb +++ b/middleman-core/lib/middleman-core/core_extensions/rendering.rb @@ -128,6 +128,9 @@ module Middleman # Store last engine for later (could be inside nested renders) @current_engine, engine_was = engine, @current_engine + old_locale = ::I18n.locale + + I18n.locale = opts[:lang] if opts[:lang] # Use a dup of self as a context so that instance variables set within # the template don't persist for other templates. @@ -165,6 +168,7 @@ module Middleman ensure # Pop all the saved variables from earlier as we may be returning to a # previous render (layouts, partials, nested layouts). + ::I18n.locale = old_locale @current_engine = engine_was @content_blocks = nil @current_locs = nil diff --git a/middleman-core/lib/middleman-core/sitemap/resource.rb b/middleman-core/lib/middleman-core/sitemap/resource.rb index ed213d12..96b71d77 100644 --- a/middleman-core/lib/middleman-core/sitemap/resource.rb +++ b/middleman-core/lib/middleman-core/sitemap/resource.rb @@ -76,6 +76,7 @@ module Middleman # Merge in new metadata specific to this resource. # @param [Hash] metadata A metadata block like provides_metadata_for_path takes def add_metadata(metadata={}, &block) + metadata = metadata.dup if metadata.has_key?(:blocks) @local_metadata[:blocks] << metadata.delete(:blocks) end diff --git a/middleman-core/lib/middleman-core/sitemap/store.rb b/middleman-core/lib/middleman-core/sitemap/store.rb index 73902ecc..935e051b 100644 --- a/middleman-core/lib/middleman-core/sitemap/store.rb +++ b/middleman-core/lib/middleman-core/sitemap/store.rb @@ -113,7 +113,7 @@ module Middleman provides_metadata.inject(blank_metadata) do |result, (callback, matcher)| next result if matcher && !source_file.match(matcher) - metadata = callback.call(source_file) + metadata = callback.call(source_file).dup if metadata.has_key?(:blocks) result[:blocks] << metadata[:blocks] @@ -152,7 +152,7 @@ module Middleman next result unless File.fnmatch("/" + Util.strip_leading_slash(matcher), "/#{request_path}") end - metadata = callback.call(request_path) + metadata = callback.call(request_path).dup result[:blocks] += Array(metadata.delete(:blocks)) diff --git a/middleman-more/features/i18n_force_locale.feature b/middleman-more/features/i18n_force_locale.feature new file mode 100644 index 00000000..afe8fc3b --- /dev/null +++ b/middleman-more/features/i18n_force_locale.feature @@ -0,0 +1,13 @@ +Feature: i18n manually setting locale + + Scenario: Setting I18n.locale in a block (see issue #809) or with the :lang option + Given the Server is running at "i18n-force-locale" + When I go to "/en/index.html" + Then I should see "Hello" + Then I should see "I18n.locale: en" + When I go to "/es/index.html" + Then I should see "Hola" + Then I should see "I18n.locale: es" + When I go to "/fr/index.html" + Then I should see "Bonjour" + Then I should see "I18n.locale: fr" diff --git a/middleman-more/fixtures/i18n-force-locale/config.rb b/middleman-more/fixtures/i18n-force-locale/config.rb new file mode 100644 index 00000000..08ee30e5 --- /dev/null +++ b/middleman-more/fixtures/i18n-force-locale/config.rb @@ -0,0 +1,13 @@ +[:en, :es].each do |locale| + proxy "/#{locale}/index.html", "index.html", :ignore => true do + ::I18n.locale = locale + end +end + +proxy "/fr/index.html", "index.html", :lang => :fr + +activate :i18n + +# This is what breaks i18n, just because it adds a resource list manipulator that +# forces a rebuild of the resource list. +activate :asset_hash diff --git a/middleman-more/fixtures/i18n-force-locale/locales/en.yml b/middleman-more/fixtures/i18n-force-locale/locales/en.yml new file mode 100644 index 00000000..0b36b800 --- /dev/null +++ b/middleman-more/fixtures/i18n-force-locale/locales/en.yml @@ -0,0 +1,3 @@ +--- +en: + hello: "Hello" diff --git a/middleman-more/fixtures/i18n-force-locale/locales/es.yml b/middleman-more/fixtures/i18n-force-locale/locales/es.yml new file mode 100644 index 00000000..38e080bd --- /dev/null +++ b/middleman-more/fixtures/i18n-force-locale/locales/es.yml @@ -0,0 +1,3 @@ +--- +es: + hello: "Hola" \ No newline at end of file diff --git a/middleman-more/fixtures/i18n-force-locale/locales/fr.yml b/middleman-more/fixtures/i18n-force-locale/locales/fr.yml new file mode 100644 index 00000000..8ba12956 --- /dev/null +++ b/middleman-more/fixtures/i18n-force-locale/locales/fr.yml @@ -0,0 +1,3 @@ +--- +fr: + hello: "Bonjour" \ No newline at end of file diff --git a/middleman-more/fixtures/i18n-force-locale/source/index.haml b/middleman-more/fixtures/i18n-force-locale/source/index.haml new file mode 100644 index 00000000..d23aceec --- /dev/null +++ b/middleman-more/fixtures/i18n-force-locale/source/index.haml @@ -0,0 +1,2 @@ +Greeting: #{I18n.t 'hello'} +I18n.locale: #{I18n.locale} diff --git a/middleman-more/lib/middleman-more/core_extensions/i18n.rb b/middleman-more/lib/middleman-more/core_extensions/i18n.rb index 057a0789..6321ed34 100644 --- a/middleman-more/lib/middleman-more/core_extensions/i18n.rb +++ b/middleman-more/lib/middleman-more/core_extensions/i18n.rb @@ -60,13 +60,15 @@ module Middleman end instance_vars = Proc.new do - ::I18n.locale = lang @lang = lang @page_id = page_id end - locals = { :lang => lang, :page_id => page_id } - { :blocks => [instance_vars], :locals => locals } + locals = { :lang => lang, + :page_id => page_id } + { :blocks => [instance_vars], + :locals => locals, + :options => { :lang => lang } } end @app.sitemap.register_resource_list_manipulator( @@ -111,6 +113,7 @@ module Middleman page_id = File.basename(resource.path, File.extname(resource.path)) + old_locale = ::I18n.locale langs.map do |lang| ::I18n.locale = lang @@ -139,6 +142,8 @@ module Middleman new_resources << p end + ::I18n.locale = old_locale + end resources + new_resources