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.
This commit is contained in:
Ben Hollis 2013-04-02 23:28:47 -07:00
parent cc418c7a2d
commit 4d5c509688
10 changed files with 52 additions and 5 deletions

View file

@ -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

View file

@ -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

View file

@ -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))

View file

@ -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"

View file

@ -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

View file

@ -0,0 +1,3 @@
---
en:
hello: "Hello"

View file

@ -0,0 +1,3 @@
---
es:
hello: "Hola"

View file

@ -0,0 +1,3 @@
---
fr:
hello: "Bonjour"

View file

@ -0,0 +1,2 @@
Greeting: #{I18n.t 'hello'}
I18n.locale: #{I18n.locale}

View file

@ -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