From bd2f09f0a251ca793b0e8ecc7e32177a2f091c23 Mon Sep 17 00:00:00 2001 From: thedarkone Date: Tue, 8 Dec 2009 20:54:05 +0100 Subject: [PATCH] Implement Fast backend as a module. --- lib/i18n/backend.rb | 1 + lib/i18n/backend/fast.rb | 69 +++++++++++++++++++++++++++++++++ test/cases/api/fast_test.rb | 31 +++++++++++++++ test/cases/backend/fast_test.rb | 50 ++++++++++++++++++++++++ 4 files changed, 151 insertions(+) create mode 100644 lib/i18n/backend/fast.rb create mode 100644 test/cases/api/fast_test.rb create mode 100644 test/cases/backend/fast_test.rb diff --git a/lib/i18n/backend.rb b/lib/i18n/backend.rb index 81bca000..bc38d8d8 100644 --- a/lib/i18n/backend.rb +++ b/lib/i18n/backend.rb @@ -16,6 +16,7 @@ module Backend autoload :Cache, 'i18n/backend/cache' autoload :Chain, 'i18n/backend/chain' autoload :Fallbacks, 'i18n/backend/fallbacks' + autoload :Fast, 'i18n/backend/fast' autoload :Gettext, 'i18n/backend/gettext' autoload :Helpers, 'i18n/backend/helpers' autoload :InterpolationCompiler, 'i18n/backend/interpolation_compiler' diff --git a/lib/i18n/backend/fast.rb b/lib/i18n/backend/fast.rb new file mode 100644 index 00000000..fc110399 --- /dev/null +++ b/lib/i18n/backend/fast.rb @@ -0,0 +1,69 @@ +# encoding: utf-8 + +module I18n + module Backend + module Fast + SEPARATOR_ESCAPE_CHAR = "\001" + + def reset_flattened_translations! + @flattened_translations = nil + end + + def flattened_translations + @flattened_translations ||= flatten_translations(translations) + end + + def merge_translations(locale, data) + super + reset_flattened_translations! + end + + def init_translations + super + reset_flattened_translations! + end + + 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 + end + + def flatten_translations(translations) + # don't flatten locale roots + translations.inject({}) do |flattened_h, (locale_name, locale_translations)| + flattened_h[locale_name] = flatten_hash(locale_translations) + flattened_h + end + end + + def lookup(locale, key, scope = nil, separator = nil) + init_translations unless @initialized + if separator + key = cleanup_non_standard_separator(key, separator) + scope = Array(scope).map{|k| cleanup_non_standard_separator(k, separator)} if scope + end + flattened_translations[locale.to_sym][(scope ? (Array(scope) + [key]).join(I18n.default_separator) : key).to_sym] rescue nil + end + + def cleanup_non_standard_separator(key, user_separator) + escape_default_separator(key).tr(user_separator, I18n.default_separator) + end + end + end +end \ No newline at end of file diff --git a/test/cases/api/fast_test.rb b/test/cases/api/fast_test.rb new file mode 100644 index 00000000..9cc77947 --- /dev/null +++ b/test/cases/api/fast_test.rb @@ -0,0 +1,31 @@ +# encoding: utf-8 + +require File.expand_path(File.dirname(__FILE__) + '/../../test_helper') + +class I18nFastBackendApiTest < Test::Unit::TestCase + include Tests::Api::Basics + include Tests::Api::Defaults + include Tests::Api::Interpolation + include Tests::Api::Link + include Tests::Api::Lookup + include Tests::Api::Pluralization + include Tests::Api::Procs + include Tests::Api::Localization::Date + include Tests::Api::Localization::DateTime + include Tests::Api::Localization::Time + include Tests::Api::Localization::Procs + + class FastBackend + include I18n::Backend::Base + include I18n::Backend::Fast + end + + def setup + I18n.backend = FastBackend.new + super + end + + define_method "test: make sure we use the FastBackend backend" do + assert_equal FastBackend, I18n.backend.class + end +end \ No newline at end of file diff --git a/test/cases/backend/fast_test.rb b/test/cases/backend/fast_test.rb new file mode 100644 index 00000000..5768857e --- /dev/null +++ b/test/cases/backend/fast_test.rb @@ -0,0 +1,50 @@ +# encoding: utf-8 + +require File.expand_path(File.dirname(__FILE__) + '/../../test_helper') +require File.expand_path(File.dirname(__FILE__) + '/simple_test') + +class I18nBackendFastTest < I18nBackendSimpleTest + class FastBackend + include I18n::Backend::Base + include I18n::Backend::Fast + end + + def setup + super + I18n.backend = FastBackend.new + end +end + +class I18nBackendFastSpecificTest < Test::Unit::TestCase + class FastBackend + include I18n::Backend::Base + include I18n::Backend::Fast + end + + def setup + @backend = FastBackend.new + end + + def assert_flattens(expected, nested) + assert_equal expected, @backend.send(:flatten_hash, nested) + end + + def test_hash_flattening_works + assert_flattens( + {:a=>'a', :b=>{:c=>'c', :d=>'d', :f=>{:x=>'x'}}, :"b.f" => {:x=>"x"}, :"b.c"=>"c", :"b.f.x"=>"x", :"b.d"=>"d"}, + {:a=>'a', :b=>{:c=>'c', :d=>'d', :f=>{:x=>'x'}}} + ) + assert_flattens({:a=>{:b =>['a', 'b']}, :"a.b"=>['a', 'b']}, {:a=>{:b =>['a', 'b']}}) + end + + def test_pluralization_logic_and_lookup_works + counts_hash = {:zero => 'zero', :one => 'one', :other => 'other'} + @backend.store_translations :en, {:a => counts_hash} + assert_equal 'one', @backend.translate(:en, :a, :count => 1) + end + + def test_translation_subtree_retrieval + @backend.store_translations :en, :a => {:foo => 'bar'} + assert_equal({:foo => 'bar'}, @backend.translate(:en, :a)) + end +end