Skip to content

Commit

Permalink
Allow symbol links to be resolved recursively. Imagine the following …
Browse files Browse the repository at this point in the history
…setup:

  en:
    activemodel:
      errors:
        messages:
          blank: "can't be blank"

  en:
    activerecord:
      errors:
        messages: :"activemodel.errors.messages"

Prior to this patch, the following did not work:

  I18n.t "activerecord.errors.messages.blank"

Now it does. This patch also resolves links for Fast backend when
storing the translations, so such links are also optimized. Finally,
it also unifies ActiveRecord and Fast backend implementation.
  • Loading branch information
josevalim authored and Sven Fuchs committed Dec 29, 2009
1 parent 2e13fc1 commit 2c50bd2
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 30 deletions.
9 changes: 4 additions & 5 deletions lib/i18n/backend/base.rb
Expand Up @@ -114,11 +114,10 @@ def lookup(locale, key, scope = [], separator = nil)
keys = I18n.send(:normalize_translation_keys, locale, key, scope, separator)
keys.inject(translations) do |result, key|
key = key.to_sym
if result.respond_to?(:has_key?) and result.has_key?(key)
result[key]
else
return nil
end
return nil unless result.is_a?(Hash) && result.has_key?(key)
result = result[key]
result = resolve(locale, key, result, :scope => scope, :separator => separator) if result.is_a?(Symbol)
result
end
end

Expand Down
18 changes: 2 additions & 16 deletions lib/i18n/backend/fast.rb
Expand Up @@ -35,22 +35,8 @@ def init_translations
protected
# flatten_hash({:a=>'a', :b=>{:c=>'c', :d=>'d', :f=>{:x=>'x'}}})
# # => {:a=>'a', :b=>{:c=>'c', :d=>'d', :f=>{:x=>'x'}}, :"b.f" => {:x=>"x"}, :"b.c"=>"c", :"b.f.x"=>"x", :"b.d"=>"d"}
def flatten_hash(h, nested_stack = [], flattened_h = {})
h.each_pair do |k, v|
new_nested_stack = nested_stack + [escape_default_separator(k)]
flattened_h[nested_stack_to_flat_key(new_nested_stack)] = v
flatten_hash(v, new_nested_stack, flattened_h) if v.kind_of?(Hash)
end

flattened_h
end

def escape_default_separator(key)
key.to_s.tr(I18n.default_separator, SEPARATOR_ESCAPE_CHAR)
end

def nested_stack_to_flat_key(nested_stack)
nested_stack.join(I18n.default_separator).to_sym
def flatten_hash(h, nested_stack = [], flattened_h = {}, orig_h=h)
deep_symbolize_keys(wind_keys(h, nil, true))
end

def flatten_translations(translations)
Expand Down
37 changes: 32 additions & 5 deletions lib/i18n/backend/helpers.rb
@@ -1,6 +1,8 @@
module I18n
module Backend
module Helpers
SEPARATOR_ESCAPE_CHAR = "\001"

# Return a new hash with all keys and nested keys converted to symbols.
def deep_symbolize_keys(hash)
hash.inject({}) { |result, (key, value)|
Expand All @@ -13,16 +15,41 @@ def deep_symbolize_keys(hash)
# Flatten keys for nested Hashes by chaining up keys using the separator
# >> { "a" => { "b" => { "c" => "d", "e" => "f" }, "g" => "h" }, "i" => "j"}.wind
# => { "a.b.c" => "d", "a.b.e" => "f", "a.g" => "h", "i" => "j" }
def wind_keys(hash, separator = ".", prev_key = nil, result = {})
hash.inject(result) do |result, pair|
key, value = *pair
def wind_keys(hash, separator = nil, subtree = false, prev_key = nil, result = {}, orig_hash=hash)
separator ||= I18n.default_separator

hash.each_pair do |key, value|
key = escape_default_separator(key, separator)
curr_key = [prev_key, key].compact.join(separator)

if value.is_a?(Symbol)
value = hash_lookup(orig_hash, value, separator) ||
hash_lookup(hash, value, separator)
end

if value.is_a?(Hash)
wind_keys(value, separator, curr_key, result)
result[curr_key] = value if subtree
wind_keys(value, separator, subtree, curr_key, result, orig_hash)
else
result[curr_key] = value
end
result
end

result
end

def escape_default_separator(key, separator=nil)
key.to_s.tr(separator || I18n.default_separator, SEPARATOR_ESCAPE_CHAR)
end

def hash_lookup(hash, keys, separator = ".")
keys.to_s.split(separator).inject(hash) do |result, key|
key = key.to_sym
if result.respond_to?(:has_key?) and result.has_key?(key)
result[key]
else
return nil
end
end
end

Expand Down
5 changes: 5 additions & 0 deletions test/api/link.rb
Expand Up @@ -22,6 +22,11 @@ module Link
setup_linked_translations
assert_equal('baz', I18n.backend.translate('en', :link_to_baz, :scope => :bar))
end

define_method "test linked lookup: given the first key resolves to a symbol it looks up the symbol with remaining keys" do
setup_linked_translations
assert_equal('baz', I18n.backend.translate('en', :"link_to_bar.baz"))
end

protected

Expand Down
9 changes: 5 additions & 4 deletions test/test_helper.rb
@@ -1,12 +1,13 @@
# encoding: utf-8

$: << "lib"
$: << File.expand_path(File.dirname(__FILE__))
$:.unshift File.expand_path("../lib", File.dirname(__FILE__))
$:.unshift File.expand_path(File.dirname(__FILE__))

require 'rubygems'
require 'test/unit'
require 'i18n'
require 'i18n/core_ext/object/meta_class'

require 'rubygems'
require 'test/unit'
require 'time'
require 'yaml'

Expand Down

0 comments on commit 2c50bd2

Please sign in to comment.