Skip to content

Commit

Permalink
Merge remote branch 'wlorentson/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
Dylan Stamat committed Dec 2, 2009
2 parents 07205da + e5769ae commit 6a8bdee
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 1 deletion.
48 changes: 48 additions & 0 deletions lib/i18n_backend_database/database.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,21 @@ def translate(locale, key, options = {})
return translate(@locale.code, default, options.dup)
end

# The requested key might not be a parent node in a hierarchy of keys instead of a regular 'leaf' node
# that would simply result in a string return. If so, check the database for possible children
# and return them in a nested hash if we find them.
# We can safely ignore pluralization indeces here since they should never apply to a hash return
if !entry && (key.is_a?(String) || key.is_a?(Symbol))
#We need to escape % and \. Rails will handle the rest.
escaped_key = key.to_s.gsub('\\', '\\\\\\\\').gsub(/%/, '\%')
children = @locale.translations.find :all, :conditions => ["raw_key like ?", "#{escaped_key}.%"]
if children.size > 0
entry = hashify_record_array(key.to_s, children)
@cache_store.write(Translation.ck(@locale, key), entry) unless cache_lookup == true
return entry
end
end

# we check the database before creating a translation as we can have translations with nil values
# if we still have no blasted translation just go and create one for the current locale!
unless entry
Expand Down Expand Up @@ -210,6 +225,39 @@ def interpolate(locale, string, values = {})
result
end

def strip_root_key(root_key, key)
return nil if key.nil?
return key.gsub(/^#{root_key}\./, '')
end

def hashify_record_array(root_key, record_array)
return nil if record_array.nil? || record_array.empty?

#Make sure that all of our records have raw_keys
record_array.reject! {|record| record.raw_key.nil?}

# Start building our return hash
result = {}
record_array.each { |record|
key = strip_root_key(root_key, record.raw_key)
next unless key.present?

# If we contain a period delimiter, we need to add a sub-hash.
# Otherwise, we just insert the value at this level.
if key.index(".")
internal_node = key.slice(0, key.index('.'))
new_root = root_key + '.' + internal_node
new_record_array = record_array.select {|record| record.raw_key.starts_with? new_root}
result[internal_node.to_sym] = hashify_record_array(new_root, new_record_array)
else
value = record.value
value = value.to_i if value == "0" || value.to_i != 0 #simple integer cast
result[key.to_sym] = value
end
}
result
end

end
end
end
2 changes: 1 addition & 1 deletion lib/i18n_util.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def self.extract_i18n_keys(hash, parent_keys = [])
if value.is_a?(Hash)
# Nested hash
keys += extract_i18n_keys(value, full_key)
elsif value.present?
elsif !value.nil?
# String leaf node
keys << full_key.join(".")
end
Expand Down
37 changes: 37 additions & 0 deletions spec/translate_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,43 @@ def write(key, value, options = nil)
@backend.cache_store.clear
end

describe "returning hashes for non-leaves" do
before do
#Set up a translation hierarchy
@locale = Locale.create!(:code => "en")
I18n.default_locale = "en"
end

it "should return a hash when asked for a non-leaf node" do
format_hash = {:separator => ".", :precision => 3, :delimiter => ","}
@locale.translations.create!(:key => "number.format.separator", :value => format_hash[:separator])
@locale.translations.create!(:key => "number.format.precision", :value => format_hash[:precision])
@locale.translations.create!(:key => "number.format.delimiter", :value => format_hash[:delimiter])
@backend.translate("en", "number.format").should == format_hash
end

it "should return a nested hash" do
nested_hash = {:a => "b", :c => {:d => "e", :f => "g"}}
@locale.translations.create!(:key => "nested.a", :value => "b")
@locale.translations.create!(:key => "nested.c.d", :value => "e")
@locale.translations.create!(:key => "nested.c.f", :value => "g")
@backend.translate("en", "nested").should == nested_hash
end

it "should not be fooled by SQL injection" do
#for bad_string in ["number.format%", "number.format\%", "number.format\\"] do
for bad_string in ["number.format\\"] do
@backend.translate("en", bad_string).should == bad_string
end
end

it "should not be fooled by keys ending in a delimiter" do
@locale.translations.create!(:key => "number.format.", :value => 'this should be a normal leaf')
@backend.translate('en', 'number.format.').should == 'this should be a normal leaf'
end

end

describe "with default locale en" do
before(:each) do
I18n.default_locale = "en"
Expand Down

0 comments on commit 6a8bdee

Please sign in to comment.