diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 00000000..9711239b --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,21 @@ +## What I tried to do + +* Fill this out! + +## What I expected to happen + +* Fill this out! + +## What actually happened + +* Fill this out! + +## Versions of i18n, rails, and anything else you think is neccessary + +* Fill this out! + +---- + +Bonus points for providing an application or a small code example which reproduces the issue. + +Thanks! :heart: diff --git a/.gitignore b/.gitignore index b066d1ea..ea8628bb 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ vendor/**/* pkg .bundle .rvmrc +Gemfile.lock diff --git a/.travis.yml b/.travis.yml index 77aa4460..c5b54361 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,9 +4,10 @@ before_install: rvm: - 1.9.3 - 2.0.0 - - 2.1.8 - - 2.2.4 - - 2.3.1 + - 2.1.10 + - 2.2.6 + - 2.3.3 + - 2.4.0 - ruby-head - rbx - jruby @@ -27,22 +28,15 @@ matrix: gemfile: gemfiles/Gemfile.rails-master - rvm: 2.0.0 gemfile: gemfiles/Gemfile.rails-master - - rvm: 2.1.8 + - rvm: 2.1.10 gemfile: gemfiles/Gemfile.rails-master - rvm: 1.9.3 gemfile: gemfiles/Gemfile.rails-5.0.x - rvm: 2.0.0 gemfile: gemfiles/Gemfile.rails-5.0.x - - rvm: 2.1.8 + - rvm: 2.1.10 gemfile: gemfiles/Gemfile.rails-5.0.x - # activesupport has a dependency on json, which does not build on this version - - rvm: ruby-head - gemfile: gemfiles/Gemfile.rails-4.1.x - # activesupport has a dependency on json, which does not build on this version - - rvm: ruby-head - gemfile: gemfiles/Gemfile.rails-4.2.x allow_failures: - - rvm: 2.2 - rvm: rbx - rvm: jruby fast_finish: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 7608c5f9..af66dc98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,18 @@ -# master +# 0.8.3 -* `Hash#slice` ignores non existing keys. +See https://github.com/svenfuchs/i18n/releases/tag/v0.8.3 + +# 0.8.2 + +See https://github.com/svenfuchs/i18n/releases/tag/v0.8.2 + +# 0.8.1 + +See https://github.com/svenfuchs/i18n/releases/tag/v0.8.1 + +# 0.8.0 + +See https://github.com/svenfuchs/i18n/releases/tag/v0.8.0 # 0.7.0 diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index 0df21bea..00000000 --- a/Gemfile.lock +++ /dev/null @@ -1,30 +0,0 @@ -PATH - remote: . - specs: - i18n (0.7.0) - concurrent-ruby (= 1.0.2) - -GEM - remote: https://rubygems.org/ - specs: - concurrent-ruby (1.0.2) - metaclass (0.0.4) - minitest (5.9.1) - mocha (1.2.1) - metaclass (~> 0.0.1) - rake (11.3.0) - test_declarative (0.0.5) - -PLATFORMS - java - ruby - -DEPENDENCIES - i18n! - minitest - mocha - rake - test_declarative - -BUNDLED WITH - 1.13.6 diff --git a/README.md b/README.md index ae9faf7d..12b8ada1 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ Ruby Internationalization and localization solution. +[See the Rails Guide](http://guides.rubyonrails.org/i18n.html) for an example of its usage. (Note: This library can be used independently from Rails.) + Features: * translation and localization diff --git a/gemfiles/Gemfile.rails-3.2.x.lock b/gemfiles/Gemfile.rails-3.2.x.lock deleted file mode 100644 index 1aa3d4f4..00000000 --- a/gemfiles/Gemfile.rails-3.2.x.lock +++ /dev/null @@ -1,32 +0,0 @@ -PATH - remote: .. - specs: - i18n (0.7.0) - -GEM - remote: https://rubygems.org/ - specs: - activesupport (3.2.21) - i18n (~> 0.6, >= 0.6.4) - multi_json (~> 1.0) - metaclass (0.0.4) - minitest (5.9.1) - mocha (1.1.0) - metaclass (~> 0.0.1) - multi_json (1.11.0) - rake (10.4.2) - test_declarative (0.0.5) - -PLATFORMS - ruby - -DEPENDENCIES - activesupport (~> 3.2.0) - i18n! - minitest - mocha - rake - test_declarative - -BUNDLED WITH - 1.13.5 diff --git a/gemfiles/Gemfile.rails-4.0.x.lock b/gemfiles/Gemfile.rails-4.0.x.lock deleted file mode 100644 index d14c35f1..00000000 --- a/gemfiles/Gemfile.rails-4.0.x.lock +++ /dev/null @@ -1,37 +0,0 @@ -PATH - remote: .. - specs: - i18n (0.7.0) - -GEM - remote: https://rubygems.org/ - specs: - activesupport (4.0.13) - i18n (~> 0.6, >= 0.6.9) - minitest (~> 4.2) - multi_json (~> 1.3) - thread_safe (~> 0.1) - tzinfo (~> 0.3.37) - metaclass (0.0.4) - minitest (4.7.5) - mocha (1.1.0) - metaclass (~> 0.0.1) - multi_json (1.11.0) - rake (10.4.2) - test_declarative (0.0.5) - thread_safe (0.3.5) - tzinfo (0.3.43) - -PLATFORMS - ruby - -DEPENDENCIES - activesupport (~> 4.0.0) - i18n! - minitest - mocha - rake - test_declarative - -BUNDLED WITH - 1.13.5 diff --git a/gemfiles/Gemfile.rails-4.1.x.lock b/gemfiles/Gemfile.rails-4.1.x.lock deleted file mode 100644 index 93dc7ae0..00000000 --- a/gemfiles/Gemfile.rails-4.1.x.lock +++ /dev/null @@ -1,38 +0,0 @@ -PATH - remote: .. - specs: - i18n (0.7.0) - -GEM - remote: https://rubygems.org/ - specs: - activesupport (4.1.10) - i18n (~> 0.6, >= 0.6.9) - json (~> 1.7, >= 1.7.7) - minitest (~> 5.1) - thread_safe (~> 0.1) - tzinfo (~> 1.1) - json (1.8.2) - metaclass (0.0.4) - minitest (5.5.1) - mocha (1.1.0) - metaclass (~> 0.0.1) - rake (10.4.2) - test_declarative (0.0.5) - thread_safe (0.3.5) - tzinfo (1.2.2) - thread_safe (~> 0.1) - -PLATFORMS - ruby - -DEPENDENCIES - activesupport (~> 4.1.0) - i18n! - minitest - mocha - rake - test_declarative - -BUNDLED WITH - 1.13.5 diff --git a/gemfiles/Gemfile.rails-4.2.x.lock b/gemfiles/Gemfile.rails-4.2.x.lock deleted file mode 100644 index 6459e822..00000000 --- a/gemfiles/Gemfile.rails-4.2.x.lock +++ /dev/null @@ -1,38 +0,0 @@ -PATH - remote: .. - specs: - i18n (0.7.0) - -GEM - remote: https://rubygems.org/ - specs: - activesupport (4.2.1) - i18n (~> 0.7) - json (~> 1.7, >= 1.7.7) - minitest (~> 5.1) - thread_safe (~> 0.3, >= 0.3.4) - tzinfo (~> 1.1) - json (1.8.2) - metaclass (0.0.4) - minitest (5.5.1) - mocha (1.1.0) - metaclass (~> 0.0.1) - rake (10.4.2) - test_declarative (0.0.5) - thread_safe (0.3.5) - tzinfo (1.2.2) - thread_safe (~> 0.1) - -PLATFORMS - ruby - -DEPENDENCIES - activesupport (~> 4.2.0) - i18n! - minitest - mocha - rake - test_declarative - -BUNDLED WITH - 1.13.5 diff --git a/gemfiles/Gemfile.rails-5.0.x.lock b/gemfiles/Gemfile.rails-5.0.x.lock deleted file mode 100644 index 74442adf..00000000 --- a/gemfiles/Gemfile.rails-5.0.x.lock +++ /dev/null @@ -1,37 +0,0 @@ -PATH - remote: .. - specs: - i18n (0.7.0) - -GEM - remote: https://rubygems.org/ - specs: - activesupport (5.0.0.1) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (~> 0.7) - minitest (~> 5.1) - tzinfo (~> 1.1) - concurrent-ruby (1.0.2) - metaclass (0.0.4) - minitest (5.9.1) - mocha (1.2.1) - metaclass (~> 0.0.1) - rake (11.3.0) - test_declarative (0.0.5) - thread_safe (0.3.5) - tzinfo (1.2.2) - thread_safe (~> 0.1) - -PLATFORMS - ruby - -DEPENDENCIES - activesupport (~> 5.0.0) - i18n! - minitest - mocha - rake - test_declarative - -BUNDLED WITH - 1.13.6 diff --git a/gemfiles/Gemfile.rails-master.lock b/gemfiles/Gemfile.rails-master.lock deleted file mode 100644 index f5b9f7bb..00000000 --- a/gemfiles/Gemfile.rails-master.lock +++ /dev/null @@ -1,43 +0,0 @@ -GIT - remote: git://github.com/rails/rails.git - revision: da23e125f8d755917b08f5cca1f7fe1ff38c8b7e - branch: master - specs: - activesupport (5.1.0.alpha) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (~> 0.7) - minitest (~> 5.1) - tzinfo (~> 1.1) - -PATH - remote: .. - specs: - i18n (0.7.0) - -GEM - remote: https://rubygems.org/ - specs: - concurrent-ruby (1.0.2) - metaclass (0.0.4) - minitest (5.5.1) - mocha (1.1.0) - metaclass (~> 0.0.1) - rake (10.4.2) - test_declarative (0.0.5) - thread_safe (0.3.5) - tzinfo (1.2.2) - thread_safe (~> 0.1) - -PLATFORMS - ruby - -DEPENDENCIES - activesupport! - i18n! - minitest - mocha - rake - test_declarative - -BUNDLED WITH - 1.13.6 diff --git a/lib/i18n.rb b/lib/i18n.rb index 52a19635..9b4b2972 100644 --- a/lib/i18n.rb +++ b/lib/i18n.rb @@ -11,7 +11,7 @@ module I18n autoload :Locale, 'i18n/locale' autoload :Tests, 'i18n/tests' - RESERVED_KEYS = [:scope, :default, :separator, :resolve, :object, :fallback, :format, :cascade, :throw, :raise, :deep_interpolation] + RESERVED_KEYS = [:scope, :default, :separator, :resolve, :object, :fallback, :fallback_in_progress, :format, :cascade, :throw, :raise, :deep_interpolation] RESERVED_KEYS_PATTERN = /%\{(#{RESERVED_KEYS.join("|")})\}/ module Base diff --git a/lib/i18n/backend/base.rb b/lib/i18n/backend/base.rb index 668a4221..c8bb070f 100644 --- a/lib/i18n/backend/base.rb +++ b/lib/i18n/backend/base.rb @@ -23,7 +23,7 @@ def store_translations(locale, data, options = {}) def translate(locale, key, options = {}) raise InvalidLocale.new(locale) unless locale - entry = key && lookup(locale, key, options[:scope], options) + entry = lookup(locale, key, options[:scope], options) unless key.nil? if entry.nil? && options.key?(:default) entry = default(locale, key, options[:default], options) @@ -136,14 +136,14 @@ def resolve(locale, object, subject, options = {}) # - It will pick the :other subkey otherwise. # - It will pick the :zero subkey in the special case where count is # equal to 0 and there is a :zero subkey present. This behaviour is - # not stand with regards to the CLDR pluralization rules. + # not standard with regards to the CLDR pluralization rules. # Other backends can implement more flexible or complex pluralization rules. def pluralize(locale, entry, count) return entry unless entry.is_a?(Hash) && count key = :zero if count == 0 && entry.has_key?(:zero) key ||= count == 1 ? :one : :other - raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key) + raise InvalidPluralizationData.new(entry, count, key) unless entry.has_key?(key) entry[key] end diff --git a/lib/i18n/backend/fallbacks.rb b/lib/i18n/backend/fallbacks.rb index 86bd972b..7a49fa2c 100644 --- a/lib/i18n/backend/fallbacks.rb +++ b/lib/i18n/backend/fallbacks.rb @@ -35,11 +35,12 @@ module Fallbacks # it's a Symbol. When the default contains a String, Proc or Hash # it is evaluated last after all the fallback locales have been tried. def translate(locale, key, options = {}) - return super if options[:fallback] + return super unless options.fetch(:fallback, true) + return super if options[:fallback_in_progress] default = extract_non_symbol_default!(options) if options[:default] begin - options[:fallback] = true + options[:fallback_in_progress] = true I18n.fallbacks[locale].each do |fallback| begin catch(:exception) do @@ -51,7 +52,7 @@ def translate(locale, key, options = {}) end end ensure - options.delete(:fallback) + options.delete(:fallback_in_progress) end return super(locale, nil, options.merge(:default => default)) if default diff --git a/lib/i18n/backend/pluralization.rb b/lib/i18n/backend/pluralization.rb index c73a009a..01e68d27 100644 --- a/lib/i18n/backend/pluralization.rb +++ b/lib/i18n/backend/pluralization.rb @@ -32,7 +32,7 @@ def pluralize(locale, entry, count) pluralizer = pluralizer(locale) if pluralizer.respond_to?(:call) key = count == 0 && entry.has_key?(:zero) ? :zero : pluralizer.call(count) - raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key) + raise InvalidPluralizationData.new(entry, count, key) unless entry.has_key?(key) entry[key] else super diff --git a/lib/i18n/backend/transliterator.rb b/lib/i18n/backend/transliterator.rb index 538dd600..2617bcf2 100644 --- a/lib/i18n/backend/transliterator.rb +++ b/lib/i18n/backend/transliterator.rb @@ -75,7 +75,8 @@ def initialize(rule = nil) add rule if rule end - def transliterate(string, replacement = DEFAULT_REPLACEMENT_CHAR) + def transliterate(string, replacement = nil) + replacement ||= DEFAULT_REPLACEMENT_CHAR string.gsub(/[^\x00-\x7f]/u) do |char| approximations[char] || replacement end diff --git a/lib/i18n/exceptions.rb b/lib/i18n/exceptions.rb index c0d7477c..7e8b0d69 100644 --- a/lib/i18n/exceptions.rb +++ b/lib/i18n/exceptions.rb @@ -71,10 +71,10 @@ class MissingTranslationData < ArgumentError end class InvalidPluralizationData < ArgumentError - attr_reader :entry, :count - def initialize(entry, count) - @entry, @count = entry, count - super "translation data #{entry.inspect} can not be used with :count => #{count}" + attr_reader :entry, :count, :key + def initialize(entry, count, key) + @entry, @count, @key = entry, count, key + super "translation data #{entry.inspect} can not be used with :count => #{count}. key '#{key}' is missing." end end diff --git a/lib/i18n/gettext.rb b/lib/i18n/gettext.rb index 26a5d482..392cccd3 100644 --- a/lib/i18n/gettext.rb +++ b/lib/i18n/gettext.rb @@ -8,11 +8,12 @@ module Gettext @@plural_keys = { :en => [:one, :other] } class << self - # returns an array of plural keys for the given locale so that we can - # convert from gettext's integer-index based style + # returns an array of plural keys for the given locale or the whole hash + # of locale mappings to plural keys so that we can convert from gettext's + # integer-index based style # TODO move this information to the pluralization module - def plural_keys(locale) - @@plural_keys[locale] || @@plural_keys[:en] + def plural_keys(*args) + args.empty? ? @@plural_keys : @@plural_keys[args.first] || @@plural_keys[:en] end def extract_scope(msgid, separator) diff --git a/lib/i18n/interpolate/ruby.rb b/lib/i18n/interpolate/ruby.rb index 442677f2..d2fdda75 100644 --- a/lib/i18n/interpolate/ruby.rb +++ b/lib/i18n/interpolate/ruby.rb @@ -22,7 +22,7 @@ def interpolate_hash(string, values) if match == '%%' '%' else - key = ($1 || $2).to_sym + key = ($1 || $2 || match.tr("%{}", "")).to_sym value = if values.key?(key) values[key] else diff --git a/lib/i18n/tests/basics.rb b/lib/i18n/tests/basics.rb index dc0596a3..951d7ab5 100644 --- a/lib/i18n/tests/basics.rb +++ b/lib/i18n/tests/basics.rb @@ -37,8 +37,9 @@ def teardown end test "available_locales delegates to the backend when not set explicitely" do - I18n.backend.expects(:available_locales).twice - assert_equal I18n.available_locales, I18n.available_locales + original_available_locales_value = I18n.backend.available_locales + I18n.backend.expects(:available_locales).returns(original_available_locales_value).twice + assert_equal I18n.backend.available_locales, I18n.available_locales end test "exists? is implemented by the backend" do diff --git a/lib/i18n/tests/defaults.rb b/lib/i18n/tests/defaults.rb index c9caf8e3..08f92887 100644 --- a/lib/i18n/tests/defaults.rb +++ b/lib/i18n/tests/defaults.rb @@ -29,7 +29,7 @@ def setup end test "defaults: given nil it returns nil" do - assert_equal nil, I18n.t(:does_not_exist, :default => nil) + assert_nil I18n.t(:does_not_exist, :default => nil) end test "defaults: given an array of missing keys it raises a MissingTranslationData exception" do diff --git a/lib/i18n/tests/localization/procs.rb b/lib/i18n/tests/localization/procs.rb index 7b7813e2..de624888 100644 --- a/lib/i18n/tests/localization/procs.rb +++ b/lib/i18n/tests/localization/procs.rb @@ -52,19 +52,19 @@ module Procs test "localize Time: given a format that resolves to a Proc it calls the Proc with the object" do setup_time_proc_translations time = ::Time.utc(2008, 3, 1, 6, 0) - assert_equal inspect_args([time, {}]), I18n.l(time, :format => :proc, :locale => :ru) + assert_equal I18n::Tests::Localization::Procs.inspect_args([time, {}]), I18n.l(time, :format => :proc, :locale => :ru) end test "localize Time: given a format that resolves to a Proc it calls the Proc with the object and extra options" do setup_time_proc_translations time = ::Time.utc(2008, 3, 1, 6, 0) options = { :foo => 'foo' } - assert_equal inspect_args([time, options]), I18n.l(time, options.merge(:format => :proc, :locale => :ru)) + assert_equal I18n::Tests::Localization::Procs.inspect_args([time, options]), I18n.l(time, options.merge(:format => :proc, :locale => :ru)) end protected - def inspect_args(args) + def self.inspect_args(args) args = args.map do |arg| case arg when ::Time, ::DateTime @@ -72,7 +72,7 @@ def inspect_args(args) when ::Date arg.strftime('%a, %d %b %Y') when Hash - arg.delete(:fallback) + arg.delete(:fallback_in_progress) arg.inspect else arg.inspect @@ -85,12 +85,12 @@ def setup_time_proc_translations I18n.backend.store_translations :ru, { :time => { :formats => { - :proc => lambda { |*args| inspect_args(args) } + :proc => lambda { |*args| I18n::Tests::Localization::Procs.inspect_args(args) } } }, :date => { :formats => { - :proc => lambda { |*args| inspect_args(args) } + :proc => lambda { |*args| I18n::Tests::Localization::Procs.inspect_args(args) } }, :'day_names' => lambda { |key, options| (options[:format] =~ /^%A/) ? diff --git a/lib/i18n/tests/procs.rb b/lib/i18n/tests/procs.rb index 55ff9529..aa2df19a 100644 --- a/lib/i18n/tests/procs.rb +++ b/lib/i18n/tests/procs.rb @@ -4,28 +4,29 @@ module I18n module Tests module Procs test "lookup: given a translation is a proc it calls the proc with the key and interpolation values" do - I18n.backend.store_translations(:en, :a_lambda => lambda { |*args| filter_args(*args) }) + I18n.backend.store_translations(:en, :a_lambda => lambda { |*args| I18n::Tests::Procs.filter_args(*args) }) assert_equal '[:a_lambda, {:foo=>"foo"}]', I18n.t(:a_lambda, :foo => 'foo') end test "defaults: given a default is a Proc it calls it with the key and interpolation values" do - proc = lambda { |*args| filter_args(*args) } + proc = lambda { |*args| I18n::Tests::Procs.filter_args(*args) } assert_equal '[nil, {:foo=>"foo"}]', I18n.t(nil, :default => proc, :foo => 'foo') end test "defaults: given a default is a key that resolves to a Proc it calls it with the key and interpolation values" do - I18n.backend.store_translations(:en, :a_lambda => lambda { |*args| filter_args(*args) }) + the_lambda = lambda { |*args| I18n::Tests::Procs.filter_args(*args) } + I18n.backend.store_translations(:en, :a_lambda => the_lambda) assert_equal '[:a_lambda, {:foo=>"foo"}]', I18n.t(nil, :default => :a_lambda, :foo => 'foo') assert_equal '[:a_lambda, {:foo=>"foo"}]', I18n.t(nil, :default => [nil, :a_lambda], :foo => 'foo') end test "interpolation: given an interpolation value is a lambda it calls it with key and values before interpolating it" do - proc = lambda { |*args| filter_args(*args) } + proc = lambda { |*args| I18n::Tests::Procs.filter_args(*args) } assert_match %r(\[\{:foo=>#\}\]), I18n.t(nil, :default => '%{foo}', :foo => proc) end test "interpolation: given a key resolves to a Proc that returns a string then interpolation still works" do - proc = lambda { |*args| "%{foo}: " + filter_args(*args) } + proc = lambda { |*args| "%{foo}: " + I18n::Tests::Procs.filter_args(*args) } assert_equal 'foo: [nil, {:foo=>"foo"}]', I18n.t(nil, :default => proc, :foo => 'foo') end @@ -37,18 +38,17 @@ module Procs end test "lookup: given the option :resolve => false was passed it does not resolve proc translations" do - I18n.backend.store_translations(:en, :a_lambda => lambda { |*args| filter_args(*args) }) + I18n.backend.store_translations(:en, :a_lambda => lambda { |*args| I18n::Tests::Procs.filter_args(*args) }) assert_equal Proc, I18n.t(:a_lambda, :resolve => false).class end test "lookup: given the option :resolve => false was passed it does not resolve proc default" do - assert_equal Proc, I18n.t(nil, :default => lambda { |*args| filter_args(*args) }, :resolve => false).class + assert_equal Proc, I18n.t(nil, :default => lambda { |*args| I18n::Tests::Procs.filter_args(*args) }, :resolve => false).class end - protected - def filter_args(*args) - args.map {|arg| arg.delete(:fallback) if arg.is_a?(Hash) ; arg }.inspect + def self.filter_args(*args) + args.map {|arg| arg.delete(:fallback_in_progress) if arg.is_a?(Hash) ; arg }.inspect end end end diff --git a/lib/i18n/version.rb b/lib/i18n/version.rb index 4a9efa9f..fbd6c5a3 100644 --- a/lib/i18n/version.rb +++ b/lib/i18n/version.rb @@ -1,3 +1,3 @@ module I18n - VERSION = "0.7.0" + VERSION = "0.8.6" end diff --git a/test/backend/fallbacks_test.rb b/test/backend/fallbacks_test.rb index a1d5a74a..9a44c143 100644 --- a/test/backend/fallbacks_test.rb +++ b/test/backend/fallbacks_test.rb @@ -8,7 +8,7 @@ class Backend < I18n::Backend::Simple def setup super I18n.backend = Backend.new - store_translations(:en, :foo => 'Foo in :en', :bar => 'Bar in :en', :buz => 'Buz in :en') + store_translations(:en, :foo => 'Foo in :en', :bar => 'Bar in :en', :buz => 'Buz in :en', :interpolate => 'Interpolate %{value}') store_translations(:de, :bar => 'Bar in :de', :baz => 'Baz in :de') store_translations(:'de-DE', :baz => 'Baz in :de-DE') store_translations(:'pt-BR', :baz => 'Baz in :pt-BR') @@ -20,6 +20,10 @@ def setup assert_equal 'Baz in :de-DE', I18n.t(:baz, :locale => :'de-DE') end + test "returns interpolated value if no key provided" do + assert_equal 'Interpolate %{value}', I18n.t(:interpolate) + end + test "returns the :en translation for a missing :de translation" do assert_equal 'Foo in :en', I18n.t(:foo, :locale => :de) end @@ -68,6 +72,14 @@ def setup assert_equal 'Default 6 Bars', I18n.t(:missing_foo, :locale => :'de-DE', :default => [:missing_bar, {:other => "Default %{count} Bars"}, "Default Bar"], :count => 6) end + test "returns the default translation for a missing :de translation even when default is a String when fallback is disabled" do + assert_equal 'Default String', I18n.t(:foo, :locale => :de, :default => 'Default String', :fallback => false) + end + + test "raises I18n::MissingTranslationData exception when fallback is disabled even when fallback translation exists" do + assert_raise(I18n::MissingTranslationData) { I18n.t(:foo, :locale => :de, :fallback => false, :raise => true) } + end + test "raises I18n::MissingTranslationData exception when no translation was found" do assert_raise(I18n::MissingTranslationData) { I18n.t(:faa, :locale => :en, :raise => true) } assert_raise(I18n::MissingTranslationData) { I18n.t(:faa, :locale => :de, :raise => true) } @@ -195,4 +207,4 @@ def setup assert_equal false, I18n.exists?(:baz, :de) assert_equal false, I18n.exists?(:bogus, :'de-DE') end -end \ No newline at end of file +end diff --git a/test/i18n/exceptions_test.rb b/test/i18n/exceptions_test.rb index 3e528c64..84e1c8fc 100644 --- a/test/i18n/exceptions_test.rb +++ b/test/i18n/exceptions_test.rb @@ -32,16 +32,19 @@ def test_invalid_locale_stores_locale end end - test "InvalidPluralizationData stores entry and count" do + test "InvalidPluralizationData stores entry, count and key" do force_invalid_pluralization_data do |exception| - assert_equal [:bar], exception.entry + assert_equal({:other => "bar"}, exception.entry) assert_equal 1, exception.count + assert_equal :one, exception.key end end - test "InvalidPluralizationData message contains count and data" do + test "InvalidPluralizationData message contains count, data and missing key" do force_invalid_pluralization_data do |exception| - assert_equal 'translation data [:bar] can not be used with :count => 1', exception.message + assert_match '1', exception.message + assert_match '{:other=>"bar"}', exception.message + assert_match 'one', exception.message end end @@ -71,7 +74,7 @@ def test_invalid_locale_stores_locale assert_equal 'reserved key :scope used in "%{scope}"', exception.message end end - + test "MissingTranslationData#new can be initialized with just two arguments" do assert I18n::MissingTranslationData.new('en', 'key') end @@ -92,7 +95,7 @@ def force_missing_translation_data(options = {}) end def force_invalid_pluralization_data - store_translations('de', :foo => [:bar]) + store_translations('de', :foo => { :other => 'bar' }) I18n.translate(:foo, :count => 1, :locale => :de) rescue I18n::ArgumentError => e block_given? ? yield(e) : raise(e) diff --git a/test/i18n/gettext_plural_keys_test.rb b/test/i18n/gettext_plural_keys_test.rb new file mode 100644 index 00000000..4d0c9778 --- /dev/null +++ b/test/i18n/gettext_plural_keys_test.rb @@ -0,0 +1,20 @@ +require 'test_helper' + +class I18nGettextPluralKeysTest < I18n::TestCase + def setup + super + I18n::Gettext.plural_keys[:zz] = [:value1, :value2] + end + + test "Returns the plural keys of the given locale if present" do + assert_equal I18n::Gettext.plural_keys(:zz), [:value1, :value2] + end + + test "Returns the plural keys of :en if given locale not present" do + assert_equal I18n::Gettext.plural_keys(:yy), [:one, :other] + end + + test "Returns the whole hash with no arguments" do + assert_equal I18n::Gettext.plural_keys, { :en => [:one, :other], :zz => [:value1, :value2] } + end +end diff --git a/test/i18n/interpolate_test.rb b/test/i18n/interpolate_test.rb index 4bc63926..78e54d3b 100644 --- a/test/i18n/interpolate_test.rb +++ b/test/i18n/interpolate_test.rb @@ -57,6 +57,17 @@ class I18nInterpolateTest < I18n::TestCase def test_sprintf_mix_unformatted_and_formatted_named_placeholders assert_equal "foo 1.000000", I18n.interpolate("%{name} %f", :name => "foo", :num => 1.0) end + + class RailsSafeBuffer < String + + def gsub(*args, &block) + to_str.gsub(*args, &block) + end + + end + test "with String subclass that redefined gsub method" do + assert_equal "Hello mars world", I18n.interpolate(RailsSafeBuffer.new("Hello %{planet} world"), :planet => 'mars') + end end class I18nMissingInterpolationCustomHandlerTest < I18n::TestCase diff --git a/test/i18n_test.rb b/test/i18n_test.rb index 728e7ed9..39e98e53 100644 --- a/test/i18n_test.rb +++ b/test/i18n_test.rb @@ -6,6 +6,7 @@ def setup super store_translations(:en, :currency => { :format => { :separator => '.', :delimiter => ',', } }) store_translations(:nl, :currency => { :format => { :separator => ',', :delimiter => '.', } }) + store_translations(:en, "true" => "Yes", "false" => "No") end test "exposes its VERSION constant" do @@ -224,6 +225,14 @@ def setup end end + test "translate given true as a key works" do + assert_equal "Yes", I18n.t(true) + end + + test "translate given false as a key works" do + assert_equal "No", I18n.t(false) + end + test "available_locales can be replaced at runtime" do begin I18n.config.enforce_available_locales = true @@ -270,7 +279,7 @@ def setup end test "localize given nil and default returns default" do - assert_equal nil, I18n.l(nil, :default => nil) + assert_nil I18n.l(nil, :default => nil) end test "localize given an Object raises an I18n::ArgumentError" do @@ -351,6 +360,10 @@ def call(exception, locale, key, options); key; end end end + test "transliterate non-ASCII chars not in map with default replacement char" do + assert_equal "???", I18n.transliterate("日本語") + end + test "I18n.locale_available? returns true when the passed locale is available" do I18n.available_locales = [:en, :de] assert_equal true, I18n.locale_available?(:de)