Hello community, here is the log from the commit of package rubygem-i18n for openSUSE:Factory checked in at 2017-04-11 09:32:15 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/rubygem-i18n (Old) and /work/SRC/openSUSE:Factory/.rubygem-i18n.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "rubygem-i18n" Tue Apr 11 09:32:15 2017 rev:12 rq:479088 version:0.8.1 Changes: -------- --- /work/SRC/openSUSE:Factory/rubygem-i18n/rubygem-i18n.changes 2015-01-29 09:57:15.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.rubygem-i18n.new/rubygem-i18n.changes 2017-04-11 09:32:16.482320922 +0200 @@ -1,0 +2,12 @@ +Mon Mar 13 15:28:26 UTC 2017 - [email protected] + +- Update to version 0.8.1 + no changelog found + +------------------------------------------------------------------- +Wed Feb 1 05:38:55 UTC 2017 - [email protected] + +- updated to version 0.8.0 + no changelog found + +------------------------------------------------------------------- Old: ---- i18n-0.7.0.gem New: ---- gem2rpm.yml i18n-0.8.1.gem ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ rubygem-i18n.spec ++++++ --- /var/tmp/diff_new_pack.j0l3jT/_old 2017-04-11 09:32:17.670153162 +0200 +++ /var/tmp/diff_new_pack.j0l3jT/_new 2017-04-11 09:32:17.670153162 +0200 @@ -1,7 +1,7 @@ # # spec file for package rubygem-i18n # -# Copyright (c) 2015 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -16,17 +16,25 @@ # +# +# This file was generated with a gem2rpm.yml and not just plain gem2rpm. +# All sections marked as MANUAL, license headers, summaries and descriptions +# can be maintained in that file. Please consult this file before editing any +# of those fields +# + Name: rubygem-i18n -Version: 0.7.0 +Version: 0.8.1 Release: 0 %define mod_name i18n %define mod_full_name %{mod_name}-%{version} BuildRoot: %{_tmppath}/%{name}-%{version}-build +BuildRequires: %{ruby >= 1.9.3} BuildRequires: %{rubygem gem2rpm} -BuildRequires: %{ruby} BuildRequires: ruby-macros >= 5 Url: http://github.com/svenfuchs/i18n Source: http://rubygems.org/gems/%{mod_full_name}.gem +Source1: gem2rpm.yml Summary: New wave Internationalization support for Ruby License: MIT Group: Development/Languages/Ruby @@ -40,7 +48,7 @@ %install %gem_install \ - --doc-files="README.md MIT-LICENSE" \ + --doc-files="MIT-LICENSE README.md" \ -f %gem_packages ++++++ gem2rpm.yml ++++++ # --- # ## used by gem2rpm # :summary: this is a custom summary # ## used by gem2rpm # :description: |- # this is a custom description # # it can be multiline # ## used by gem2rpm # :license: MIT or Ruby # ## used by gem2rpm and gem_packages # :version_suffix: -x_y # ## used by gem2rpm and gem_packages # :disable_docs: true # ## used by gem2rpm # :disable_automatic_rdoc_dep: true # ## used by gem2rpm # :preamble: |- # BuildRequires: foobar # Requires: foobar # ## used by gem2rpm # :patches: # foo.patch: -p1 # bar.patch: # :post_patch: # if you need to fiddle with the source dir before rebuilding the gem # ## used by gem2rpm :sources: # - foo.desktop # - bar.desktop # :gem_install_args: '....' # ## used by gem2rpm # :pre_install: |- # %if 0%{?use_system_libev} # export USE_VENDORED_LIBEV="no" # %endif # ## used by gem2rpm # :post_install: |- # # delete custom files here or do other fancy stuff # install -D -m 0644 %{S:1} %{buildroot}%{_bindir}/gem2rpm-opensuse # ## used by gem2rpm # :testsuite_command: |- # (pushd %{buildroot}%{gem_base}/gems/%{mod_full_name} && rake test) # ## used by gem2rpm # :filelist: |- # /usr/bin/gem2rpm-opensuse # ## used by gem2rpm # :scripts: # :post: |- # /bin/echo foo # ## used by gem_packages # :main: # :preamble: |- # Requires: util-linux # Recommends: pwgen # :filelist: |- # /usr/bin/gem2rpm-opensuse # ## used by gem_packages # :custom_pkgs: # apache: # :preamble: |- # Requires: ..... # :filelist: |- # /etc/apache2/conf.d/passenger.conf # :summary: Custom summary is optional # :description: |- # Custom description is optional # # bar # :post: |- # /bin/echo foo # ++++++ i18n-0.7.0.gem -> i18n-0.8.1.gem ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/README.md new/README.md --- old/README.md 2014-12-19 18:06:15.000000000 +0100 +++ new/README.md 2017-02-22 03:51:26.000000000 +0100 @@ -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 @@ -22,7 +24,7 @@ * Cache * Pluralization: lambda pluralizers stored as translation data * Locale fallbacks, RFC4647 compliant (optionally: RFC4646 locale validation) -* Gettext support +* [Gettext support](https://github.com/svenfuchs/i18n/wiki/Gettext) * Translation metadata Alternative backends: @@ -31,7 +33,7 @@ * ActiveRecord (optionally: ActiveRecord::Missing and ActiveRecord::StoreProcs) * KeyValue (uses active_support/json and cannot store procs) -For more information and lots of resources see: [http://ruby-i18n.org/wiki](http://ruby-i18n.org/wiki) +For more information and lots of resources see [the 'Resources' page on the wiki](https://github.com/svenfuchs/i18n/wiki/Resources). ## Installation @@ -71,7 +73,7 @@ * [Joshua Harvey](http://www.workingwithrails.com/person/759-joshua-harvey) * [Stephan Soller](http://www.arkanis-development.de) * [Saimon Moore](http://saimonmoore.net) -* [Matt Aimonetti](http://railsontherun.com) +* [Matt Aimonetti](https://matt.aimonetti.net/) ## Contributors Binary files old/checksums.yaml.gz and new/checksums.yaml.gz differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gemfiles/Gemfile.rails-3.2.x new/gemfiles/Gemfile.rails-3.2.x --- old/gemfiles/Gemfile.rails-3.2.x 2014-12-19 18:06:15.000000000 +0100 +++ new/gemfiles/Gemfile.rails-3.2.x 2017-02-22 03:51:26.000000000 +0100 @@ -6,3 +6,4 @@ gem 'mocha' gem 'test_declarative' gem 'rake' +gem 'minitest' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gemfiles/Gemfile.rails-3.2.x.lock new/gemfiles/Gemfile.rails-3.2.x.lock --- old/gemfiles/Gemfile.rails-3.2.x.lock 2014-12-19 18:06:15.000000000 +0100 +++ new/gemfiles/Gemfile.rails-3.2.x.lock 1970-01-01 01:00:00.000000000 +0100 @@ -1,27 +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) - mocha (1.1.0) - metaclass (~> 0.0.1) - multi_json (1.10.1) - rake (10.4.2) - test_declarative (0.0.5) - -PLATFORMS - ruby - -DEPENDENCIES - activesupport (~> 3.2.0) - i18n! - mocha - rake - test_declarative diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gemfiles/Gemfile.rails-4.0.x new/gemfiles/Gemfile.rails-4.0.x --- old/gemfiles/Gemfile.rails-4.0.x 2014-12-19 18:06:15.000000000 +0100 +++ new/gemfiles/Gemfile.rails-4.0.x 2017-02-22 03:51:26.000000000 +0100 @@ -6,3 +6,4 @@ gem 'mocha' gem 'test_declarative' gem 'rake' +gem 'minitest' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gemfiles/Gemfile.rails-4.0.x.lock new/gemfiles/Gemfile.rails-4.0.x.lock --- old/gemfiles/Gemfile.rails-4.0.x.lock 2014-12-19 18:06:15.000000000 +0100 +++ new/gemfiles/Gemfile.rails-4.0.x.lock 1970-01-01 01:00:00.000000000 +0100 @@ -1,33 +0,0 @@ -PATH - remote: .. - specs: - i18n (0.7.0) - -GEM - remote: https://rubygems.org/ - specs: - activesupport (4.0.12) - 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.10.1) - rake (10.4.2) - test_declarative (0.0.5) - thread_safe (0.3.4) - tzinfo (0.3.42) - -PLATFORMS - ruby - -DEPENDENCIES - activesupport (~> 4.0.0) - i18n! - mocha - rake - test_declarative diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gemfiles/Gemfile.rails-4.1.x new/gemfiles/Gemfile.rails-4.1.x --- old/gemfiles/Gemfile.rails-4.1.x 2014-12-19 18:06:15.000000000 +0100 +++ new/gemfiles/Gemfile.rails-4.1.x 2017-02-22 03:51:26.000000000 +0100 @@ -6,3 +6,4 @@ gem 'mocha' gem 'test_declarative' gem 'rake' +gem 'minitest' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gemfiles/Gemfile.rails-4.1.x.lock new/gemfiles/Gemfile.rails-4.1.x.lock --- old/gemfiles/Gemfile.rails-4.1.x.lock 2014-12-19 18:06:15.000000000 +0100 +++ new/gemfiles/Gemfile.rails-4.1.x.lock 1970-01-01 01:00:00.000000000 +0100 @@ -1,34 +0,0 @@ -PATH - remote: .. - specs: - i18n (0.7.0) - -GEM - remote: https://rubygems.org/ - specs: - activesupport (4.1.8) - 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.1) - metaclass (0.0.4) - minitest (5.5.0) - mocha (1.1.0) - metaclass (~> 0.0.1) - rake (10.4.2) - test_declarative (0.0.5) - thread_safe (0.3.4) - tzinfo (1.2.2) - thread_safe (~> 0.1) - -PLATFORMS - ruby - -DEPENDENCIES - activesupport (~> 4.1.0) - i18n! - mocha - rake - test_declarative diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gemfiles/Gemfile.rails-4.2.x new/gemfiles/Gemfile.rails-4.2.x --- old/gemfiles/Gemfile.rails-4.2.x 2014-12-19 18:06:15.000000000 +0100 +++ new/gemfiles/Gemfile.rails-4.2.x 2017-02-22 03:51:26.000000000 +0100 @@ -2,7 +2,8 @@ gemspec :path => '..' -gem 'activesupport', '~> 4.2.0.rc3' +gem 'activesupport', '~> 4.2.0' gem 'mocha' gem 'test_declarative' gem 'rake' +gem 'minitest' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gemfiles/Gemfile.rails-4.2.x.lock new/gemfiles/Gemfile.rails-4.2.x.lock --- old/gemfiles/Gemfile.rails-4.2.x.lock 2014-12-19 18:06:15.000000000 +0100 +++ new/gemfiles/Gemfile.rails-4.2.x.lock 1970-01-01 01:00:00.000000000 +0100 @@ -1,34 +0,0 @@ -PATH - remote: .. - specs: - i18n (0.7.0) - -GEM - remote: https://rubygems.org/ - specs: - activesupport (4.2.0.rc3) - i18n (>= 0.7.0.beta1, < 0.8) - json (~> 1.7, >= 1.7.7) - minitest (~> 5.1) - thread_safe (~> 0.1) - tzinfo (~> 1.1) - json (1.8.1) - metaclass (0.0.4) - minitest (5.5.0) - mocha (1.1.0) - metaclass (~> 0.0.1) - rake (10.4.2) - test_declarative (0.0.5) - thread_safe (0.3.4) - tzinfo (1.2.2) - thread_safe (~> 0.1) - -PLATFORMS - ruby - -DEPENDENCIES - activesupport (~> 4.2.0.rc3) - i18n! - mocha - rake - test_declarative diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gemfiles/Gemfile.rails-5.0.x new/gemfiles/Gemfile.rails-5.0.x --- old/gemfiles/Gemfile.rails-5.0.x 1970-01-01 01:00:00.000000000 +0100 +++ new/gemfiles/Gemfile.rails-5.0.x 2017-02-22 03:51:26.000000000 +0100 @@ -0,0 +1,9 @@ +source 'https://rubygems.org' + +gemspec :path => '..' + +gem 'activesupport', '~> 5.0.0' +gem 'mocha' +gem 'test_declarative' +gem 'rake' +gem 'minitest' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gemfiles/Gemfile.rails-master new/gemfiles/Gemfile.rails-master --- old/gemfiles/Gemfile.rails-master 2014-12-19 18:06:15.000000000 +0100 +++ new/gemfiles/Gemfile.rails-master 2017-02-22 03:51:26.000000000 +0100 @@ -6,3 +6,4 @@ gem 'mocha' gem 'test_declarative' gem 'rake' +gem 'minitest' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gemfiles/Gemfile.rails-master.lock new/gemfiles/Gemfile.rails-master.lock --- old/gemfiles/Gemfile.rails-master.lock 2014-12-19 18:06:15.000000000 +0100 +++ new/gemfiles/Gemfile.rails-master.lock 1970-01-01 01:00:00.000000000 +0100 @@ -1,40 +0,0 @@ -GIT - remote: git://github.com/rails/rails.git - revision: fe46f009be1ece58e45abc51195e2381a71bd023 - branch: master - specs: - activesupport (5.0.0.alpha) - i18n (>= 0.7.0.beta1, < 0.8) - json (~> 1.7, >= 1.7.7) - minitest (~> 5.1) - thread_safe (~> 0.1) - tzinfo (~> 1.1) - -PATH - remote: .. - specs: - i18n (0.7.0) - -GEM - remote: https://rubygems.org/ - specs: - json (1.8.1) - metaclass (0.0.4) - minitest (5.5.0) - mocha (1.1.0) - metaclass (~> 0.0.1) - rake (10.4.2) - test_declarative (0.0.5) - thread_safe (0.3.4) - tzinfo (1.2.2) - thread_safe (~> 0.1) - -PLATFORMS - ruby - -DEPENDENCIES - activesupport! - i18n! - mocha - rake - test_declarative diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/i18n/backend/base.rb new/lib/i18n/backend/base.rb --- old/lib/i18n/backend/base.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/lib/i18n/backend/base.rb 2017-02-22 03:51:26.000000000 +0100 @@ -25,20 +25,32 @@ raise InvalidLocale.new(locale) unless locale entry = key && lookup(locale, key, options[:scope], options) - if options.empty? - entry = resolve(locale, key, entry, options) + if entry.nil? && options.key?(:default) + entry = default(locale, key, options[:default], options) else - count, default = options.values_at(:count, :default) - values = options.except(*RESERVED_KEYS) - entry = entry.nil? && default ? - default(locale, key, default, options) : resolve(locale, key, entry, options) + entry = resolve(locale, key, entry, options) + end + + if entry.nil? + if (options.key?(:default) && !options[:default].nil?) || !options.key?(:default) + throw(:exception, I18n::MissingTranslation.new(locale, key, options)) + end end - throw(:exception, I18n::MissingTranslation.new(locale, key, options)) if entry.nil? entry = entry.dup if entry.is_a?(String) + count = options[:count] entry = pluralize(locale, entry, count) if count - entry = interpolate(locale, entry, values) if values + + deep_interpolation = options[:deep_interpolation] + values = options.except(*RESERVED_KEYS) + if values + entry = if deep_interpolation + deep_interpolate(locale, entry, values) + else + interpolate(locale, entry, values) + end + end entry end @@ -50,6 +62,9 @@ # format string. Takes a key from the date/time formats translations as # a format argument (<em>e.g.</em>, <tt>:short</tt> in <tt>:'date.formats'</tt>). def localize(locale, object, format = :default, options = {}) + if object.nil? && options.include?(:default) + return options[:default] + end raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime) if Symbol === format @@ -59,18 +74,7 @@ format = I18n.t(:"#{type}.formats.#{key}", options) end - # format = resolve(locale, object, format, options) - format = format.to_s.gsub(/%[aAbBpP]/) do |match| - case match - when '%a' then I18n.t(:"date.abbr_day_names", :locale => locale, :format => format)[object.wday] - when '%A' then I18n.t(:"date.day_names", :locale => locale, :format => format)[object.wday] - when '%b' then I18n.t(:"date.abbr_month_names", :locale => locale, :format => format)[object.mon] - when '%B' then I18n.t(:"date.month_names", :locale => locale, :format => format)[object.mon] - when '%p' then I18n.t(:"time.#{object.hour < 12 ? :am : :pm}", :locale => locale, :format => format).upcase if object.respond_to? :hour - when '%P' then I18n.t(:"time.#{object.hour < 12 ? :am : :pm}", :locale => locale, :format => format).downcase if object.respond_to? :hour - end - end - + format = translate_localization_format(locale, object, format, options) object.strftime(format) end @@ -155,6 +159,30 @@ end end + # Deep interpolation + # + # deep_interpolate { people: { ann: "Ann is %{ann}", john: "John is %{john}" } }, + # ann: 'good', john: 'big' + # #=> { people: { ann: "Ann is good", john: "John is big" } } + def deep_interpolate(locale, data, values = {}) + return data if values.empty? + + case data + when ::String + I18n.interpolate(data, values) + when ::Hash + data.each_with_object({}) do |(k, v), result| + result[k] = deep_interpolate(locale, v, values) + end + when ::Array + data.map do |v| + deep_interpolate(locale, v, values) + end + else + data + end + end + # Loads a single translations file by delegating to #load_rb or # #load_yml depending on the file extension and directly merges the # data to the existing translations. Raises I18n::UnknownFileType @@ -184,6 +212,19 @@ raise InvalidLocaleData.new(filename, e.inspect) end end + + def translate_localization_format(locale, object, format, options) + format.to_s.gsub(/%[aAbBpP]/) do |match| + case match + when '%a' then I18n.t(:"date.abbr_day_names", :locale => locale, :format => format)[object.wday] + when '%A' then I18n.t(:"date.day_names", :locale => locale, :format => format)[object.wday] + when '%b' then I18n.t(:"date.abbr_month_names", :locale => locale, :format => format)[object.mon] + when '%B' then I18n.t(:"date.month_names", :locale => locale, :format => format)[object.mon] + when '%p' then I18n.t(:"time.#{object.hour < 12 ? :am : :pm}", :locale => locale, :format => format).upcase if object.respond_to? :hour + when '%P' then I18n.t(:"time.#{object.hour < 12 ? :am : :pm}", :locale => locale, :format => format).downcase if object.respond_to? :hour + end + end + end end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/i18n/backend/cache.rb new/lib/i18n/backend/cache.rb --- old/lib/i18n/backend/cache.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/lib/i18n/backend/cache.rb 2017-02-22 03:51:26.000000000 +0100 @@ -13,9 +13,13 @@ # You can use any cache implementation you want that provides the same API as # ActiveSupport::Cache (only the methods #fetch and #write are being used). # -# The cache_key implementation assumes that you only pass values to -# I18n.translate that return a valid key from #hash (see -# http://www.ruby-doc.org/core/classes/Object.html#M000337). +# The cache_key implementation by default assumes you pass values that return +# a valid key from #hash (see +# http://www.ruby-doc.org/core/classes/Object.html#M000337). However, you can +# configure your own digest method via which responds to #hexdigest (see +# http://ruby-doc.org/stdlib/libdoc/digest/rdoc/index.html): +# +# I18n.cache_key_digest = Digest::MD5.new # # If you use a lambda as a default value in your translation like this: # @@ -37,6 +41,7 @@ class << self @@cache_store = nil @@cache_namespace = nil + @@cache_key_digest = nil def cache_store @@cache_store @@ -54,6 +59,14 @@ @@cache_namespace = namespace end + def cache_key_digest + @@cache_key_digest + end + + def cache_key_digest=(key_digest) + @@cache_key_digest = key_digest + end + def perform_caching? !cache_store.nil? end @@ -76,7 +89,8 @@ end def _fetch(cache_key, &block) - result = I18n.cache_store.read(cache_key) and return result + result = I18n.cache_store.read(cache_key) + return result unless result.nil? result = catch(:exception, &block) I18n.cache_store.write(cache_key, result) unless result.is_a?(Proc) result @@ -84,13 +98,17 @@ def cache_key(locale, key, options) # This assumes that only simple, native Ruby values are passed to I18n.translate. - "i18n/#{I18n.cache_namespace}/#{locale}/#{key.hash}/#{USE_INSPECT_HASH ? options.inspect.hash : options.hash}" + "i18n/#{I18n.cache_namespace}/#{locale}/#{digest_item(key)}/#{USE_INSPECT_HASH ? digest_item(options.inspect) : digest_item(options)}" end private # In Ruby < 1.9 the following is true: { :foo => 1, :bar => 2 }.hash == { :foo => 2, :bar => 1 }.hash # Therefore we must use the hash of the inspect string instead to avoid cache key colisions. USE_INSPECT_HASH = RUBY_VERSION <= "1.9" + + def digest_item(key) + I18n.cache_key_digest ? I18n.cache_key_digest.hexdigest(key.to_s) : key.hash + end end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/i18n/backend/chain.rb new/lib/i18n/backend/chain.rb --- old/lib/i18n/backend/chain.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/lib/i18n/backend/chain.rb 2017-02-22 03:51:26.000000000 +0100 @@ -17,7 +17,7 @@ class Chain module Implementation include Base - + attr_accessor :backends def initialize(*backends) @@ -46,7 +46,7 @@ translation = backend.translate(locale, key, options) if namespace_lookup?(translation, options) namespace = _deep_merge(translation, namespace || {}) - elsif !translation.nil? + elsif !translation.nil? || (options.key?(:default) && options[:default].nil?) return translation end end @@ -75,7 +75,7 @@ def namespace_lookup?(result, options) result.is_a?(Hash) && !options.has_key?(:count) end - + private # This is approximately what gets used in ActiveSupport. # However since we are not guaranteed to run in an ActiveSupport context diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/i18n/backend/fallbacks.rb new/lib/i18n/backend/fallbacks.rb --- old/lib/i18n/backend/fallbacks.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/lib/i18n/backend/fallbacks.rb 2017-02-22 03:51:26.000000000 +0100 @@ -35,21 +35,25 @@ # 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 (@fallback_locked ||= false) default = extract_non_symbol_default!(options) if options[:default] - options[:fallback] = true - I18n.fallbacks[locale].each do |fallback| - begin - catch(:exception) do - result = super(fallback, key, options) - return result unless result.nil? + begin + @fallback_locked = true + I18n.fallbacks[locale].each do |fallback| + begin + catch(:exception) do + result = super(fallback, key, options) + return result if (result.nil? && options.key?(:default) && options[:default].nil?) || !result.nil? + end + rescue I18n::InvalidLocale + # we do nothing when the locale is invalid, as this is a fallback anyways. end - rescue I18n::InvalidLocale - # we do nothing when the locale is invalid, as this is a fallback anyways. end + ensure + @fallback_locked = false end - options.delete(:fallback) return super(locale, nil, options.merge(:default => default)) if default throw(:exception, I18n::MissingTranslation.new(locale, key, options)) @@ -64,6 +68,17 @@ return first_non_symbol_default end + def exists?(locale, key) + I18n.fallbacks[locale].each do |fallback| + begin + return true if super(fallback, key) + rescue I18n::InvalidLocale + # we do nothing when the locale is invalid, as this is a fallback anyways. + end + end + + false + end end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/i18n/backend/gettext.rb new/lib/i18n/backend/gettext.rb --- old/lib/i18n/backend/gettext.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/lib/i18n/backend/gettext.rb 2017-02-22 03:51:26.000000000 +0100 @@ -1,24 +1,33 @@ require 'i18n/gettext' require 'i18n/gettext/po_parser' -# Experimental support for using Gettext po files to store translations. -# -# To use this you can simply include the module to the Simple backend - or -# whatever other backend you are using. -# -# I18n::Backend::Simple.include(I18n::Backend::Gettext) -# -# Now you should be able to include your Gettext translation (*.po) files to -# the I18n.load_path so they're loaded to the backend and you can use them as -# usual: -# -# I18n.load_path += Dir["path/to/locales/*.po"] -# -# Following the Gettext convention this implementation expects that your -# translation files are named by their locales. E.g. the file en.po would -# contain the translations for the English locale. module I18n module Backend + # Experimental support for using Gettext po files to store translations. + # + # To use this you can simply include the module to the Simple backend - or + # whatever other backend you are using. + # + # I18n::Backend::Simple.include(I18n::Backend::Gettext) + # + # Now you should be able to include your Gettext translation (*.po) files to + # the +I18n.load_path+ so they're loaded to the backend and you can use them as + # usual: + # + # I18n.load_path += Dir["path/to/locales/*.po"] + # + # Following the Gettext convention this implementation expects that your + # translation files are named by their locales. E.g. the file en.po would + # contain the translations for the English locale. + # + # To translate text <b>you must use</b> one of the translate methods provided by + # I18n::Gettext::Helpers. + # + # include I18n::Gettext::Helpers + # puts _("some string") + # + # Without it strings containing periods (".") will not be translated. + module Gettext class PoData < Hash def set_comment(msgid_or_sym, comment) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/i18n/backend/metadata.rb new/lib/i18n/backend/metadata.rb --- old/lib/i18n/backend/metadata.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/lib/i18n/backend/metadata.rb 2017-02-22 03:51:26.000000000 +0100 @@ -21,11 +21,15 @@ def included(base) Object.class_eval do def translation_metadata - @translation_metadata ||= {} + unless self.frozen? + @translation_metadata ||= {} + else + {} + end end def translation_metadata=(translation_metadata) - @translation_metadata = translation_metadata + @translation_metadata = translation_metadata unless self.frozen? end end unless Object.method_defined?(:translation_metadata) end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/i18n/backend/simple.rb new/lib/i18n/backend/simple.rb --- old/lib/i18n/backend/simple.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/lib/i18n/backend/simple.rb 2017-02-22 03:51:26.000000000 +0100 @@ -63,7 +63,7 @@ end # Looks up a translation from the translations hash. Returns nil if - # eiher key is nil, or locale, scope or key do not exist as a key in the + # either key is nil, or locale, scope or key do not exist as a key in the # nested translations hash. Splits keys or scopes containing dots # into multiple keys, i.e. <tt>currency.format</tt> is regarded the same as # <tt>%w(currency format)</tt>. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/i18n/backend/transliterator.rb new/lib/i18n/backend/transliterator.rb --- old/lib/i18n/backend/transliterator.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/lib/i18n/backend/transliterator.rb 2017-02-22 03:51:26.000000000 +0100 @@ -71,13 +71,14 @@ def initialize(rule = nil) @rule = rule - add DEFAULT_APPROXIMATIONS.dup + add_default_approximations add rule if rule end def transliterate(string, replacement = nil) + replacement ||= DEFAULT_REPLACEMENT_CHAR string.gsub(/[^\x00-\x7f]/u) do |char| - approximations[char] || replacement || DEFAULT_REPLACEMENT_CHAR + approximations[char] || replacement end end @@ -87,6 +88,12 @@ @approximations ||= {} end + def add_default_approximations + DEFAULT_APPROXIMATIONS.each do |key, value| + approximations[key] = value + end + end + # Add transliteration rules to the approximations hash. def add(hash) hash.each do |key, value| @@ -96,4 +103,4 @@ end end end -end \ No newline at end of file +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/i18n/config.rb new/lib/i18n/config.rb --- old/lib/i18n/config.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/lib/i18n/config.rb 2017-02-22 03:51:26.000000000 +0100 @@ -5,7 +5,7 @@ # The only configuration value that is not global and scoped to thread is :locale. # It defaults to the default_locale. def locale - @locale ||= default_locale + defined?(@locale) && @locale ? @locale : default_locale end # Sets the current locale pseudo-globally, i.e. in the Thread.current hash. @@ -124,6 +124,8 @@ # behave like a Ruby Array. def load_path=(load_path) @@load_path = load_path + @@available_locales_set = nil + backend.reload! end # Whether or not to verify if locales are in the list of available locales. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/i18n/core_ext/hash.rb new/lib/i18n/core_ext/hash.rb --- old/lib/i18n/core_ext/hash.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/lib/i18n/core_ext/hash.rb 2017-02-22 03:51:26.000000000 +0100 @@ -1,7 +1,7 @@ class Hash def slice(*keep_keys) - h = {} - keep_keys.each { |key| h[key] = fetch(key) } + h = self.class.new + keep_keys.each { |key| h[key] = fetch(key) if has_key?(key) } h end unless Hash.method_defined?(:slice) @@ -21,7 +21,7 @@ MERGER = proc do |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &MERGER) : v2 end - + def deep_merge!(data) merge!(data, &MERGER) end unless Hash.method_defined?(:deep_merge!) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/i18n/exceptions.rb new/lib/i18n/exceptions.rb --- old/lib/i18n/exceptions.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/lib/i18n/exceptions.rb 2017-02-22 03:51:26.000000000 +0100 @@ -38,12 +38,12 @@ end end - class MissingTranslation + class MissingTranslation < ArgumentError module Base attr_reader :locale, :key, :options - def initialize(locale, key, options = nil) - @key, @locale, @options = key, locale, options.dup || {} + def initialize(locale, key, options = {}) + @key, @locale, @options = key, locale, options.dup options.each { |k, v| self.options[k] = v.inspect if v.is_a?(Proc) } end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/i18n/gettext/helpers.rb new/lib/i18n/gettext/helpers.rb --- old/lib/i18n/gettext/helpers.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/lib/i18n/gettext/helpers.rb 2017-02-22 03:51:26.000000000 +0100 @@ -7,6 +7,15 @@ # # include I18n::Gettext::Helpers module Helpers + # Makes dynamic translation messages readable for the gettext parser. + # <tt>_(fruit)</tt> cannot be understood by the gettext parser. To help the parser find all your translations, + # you can add <tt>fruit = N_("Apple")</tt> which does not translate, but tells the parser: "Apple" needs translation. + # * msgid: the message id. + # * Returns: msgid. + def N_(msgsid) + msgsid + end + def gettext(msgid, options = {}) I18n.t(msgid, { :default => msgid, :separator => '|' }.merge(options)) end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/i18n/interpolate/ruby.rb new/lib/i18n/interpolate/ruby.rb --- old/lib/i18n/interpolate/ruby.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/lib/i18n/interpolate/ruby.rb 2017-02-22 03:51:26.000000000 +0100 @@ -22,7 +22,7 @@ if match == '%%' '%' else - key = ($1 || $2).to_sym + key = ($1 || $2 || match.tr("%{}", "")).to_sym value = if values.key?(key) values[key] else diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/i18n/tests/basics.rb new/lib/i18n/tests/basics.rb --- old/lib/i18n/tests/basics.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/lib/i18n/tests/basics.rb 2017-02-22 03:51:26.000000000 +0100 @@ -37,8 +37,9 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/i18n/tests/defaults.rb new/lib/i18n/tests/defaults.rb --- old/lib/i18n/tests/defaults.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/lib/i18n/tests/defaults.rb 2017-02-22 03:51:26.000000000 +0100 @@ -24,6 +24,14 @@ assert_equal 'bar', I18n.t(:does_not_exist, :default => [:does_not_exist_2, :'foo.bar']) end + test "defaults: given false it returns false" do + assert_equal false, I18n.t(:does_not_exist, :default => false) + end + + test "defaults: given nil it returns nil" do + assert_nil I18n.t(:does_not_exist, :default => nil) + end + test "defaults: given an array of missing keys it raises a MissingTranslationData exception" do assert_raise I18n::MissingTranslationData do I18n.t(:does_not_exist, :default => [:does_not_exist_2, :does_not_exist_3], :raise => true) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/i18n/tests/interpolation.rb new/lib/i18n/tests/interpolation.rb --- old/lib/i18n/tests/interpolation.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/lib/i18n/tests/interpolation.rb 2017-02-22 03:51:26.000000000 +0100 @@ -104,6 +104,26 @@ assert_raise(I18n::ReservedInterpolationKey) { interpolate(:default => '%{separator}', :foo => :bar) } end + test "interpolation: deep interpolation for default string" do + assert_equal 'Hi %{name}!', interpolate(:default => 'Hi %{name}!', :deep_interpolation => true) + end + + test "interpolation: deep interpolation for interpolated string" do + assert_equal 'Hi Ann!', interpolate(:default => 'Hi %{name}!', :name => 'Ann', :deep_interpolation => true) + end + + test "interpolation: deep interpolation for Hash" do + people = { :people => { :ann => 'Ann is %{ann}', :john => 'John is %{john}' } } + interpolated_people = { :people => { :ann => 'Ann is good', :john => 'John is big' } } + assert_equal interpolated_people, interpolate(:default => people, :ann => 'good', :john => 'big', :deep_interpolation => true) + end + + test "interpolation: deep interpolation for Array" do + people = { :people => ['Ann is %{ann}', 'John is %{john}'] } + interpolated_people = { :people => ['Ann is good', 'John is big'] } + assert_equal interpolated_people, interpolate(:default => people, :ann => 'good', :john => 'big', :deep_interpolation => true) + end + protected def capture(stream) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/i18n/tests/localization/date.rb new/lib/i18n/tests/localization/date.rb --- old/lib/i18n/tests/localization/date.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/lib/i18n/tests/localization/date.rb 2017-02-22 03:51:26.000000000 +0100 @@ -51,6 +51,10 @@ assert_nothing_raised { I18n.l(@date, options.freeze) } end + test "localize Date: given nil with default value it returns default" do + assert_equal 'default', I18n.l(nil, :default => 'default') + end + test "localize Date: given nil it raises I18n::ArgumentError" do assert_raise(I18n::ArgumentError) { I18n.l(nil) } end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/i18n/tests/localization/procs.rb new/lib/i18n/tests/localization/procs.rb --- old/lib/i18n/tests/localization/procs.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/lib/i18n/tests/localization/procs.rb 2017-02-22 03:51:26.000000000 +0100 @@ -52,19 +52,19 @@ 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 @@ -85,12 +85,12 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/i18n/tests/procs.rb new/lib/i18n/tests/procs.rb --- old/lib/i18n/tests/procs.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/lib/i18n/tests/procs.rb 2017-02-22 03:51:26.000000000 +0100 @@ -4,28 +4,29 @@ 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=>#<Proc.*>\}\]), 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,17 +38,16 @@ 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) + def self.filter_args(*args) args.map {|arg| arg.delete(:fallback) if arg.is_a?(Hash) ; arg }.inspect end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/i18n/version.rb new/lib/i18n/version.rb --- old/lib/i18n/version.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/lib/i18n/version.rb 2017-02-22 03:51:26.000000000 +0100 @@ -1,3 +1,3 @@ module I18n - VERSION = "0.7.0" + VERSION = "0.8.1" end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/i18n.rb new/lib/i18n.rb --- old/lib/i18n.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/lib/i18n.rb 2017-02-22 03:51:26.000000000 +0100 @@ -9,10 +9,10 @@ autoload :Locale, 'i18n/locale' autoload :Tests, 'i18n/tests' - RESERVED_KEYS = [:scope, :default, :separator, :resolve, :object, :fallback, :format, :cascade, :throw, :raise] + RESERVED_KEYS = [:scope, :default, :separator, :resolve, :object, :fallback, :format, :cascade, :throw, :raise, :deep_interpolation] RESERVED_KEYS_PATTERN = /%\{(#{RESERVED_KEYS.join("|")})\}/ - extend(Module.new { + module Base # Gets I18n configuration object. def config Thread.current[:i18n_config] ||= I18n::Config.new @@ -337,5 +337,7 @@ def normalized_key_cache @normalized_key_cache ||= Hash.new { |h,k| h[k] = {} } end - }) + end + + extend Base end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/metadata new/metadata --- old/metadata 2014-12-19 18:06:15.000000000 +0100 +++ new/metadata 2017-02-22 03:51:26.000000000 +0100 @@ -1,7 +1,7 @@ --- !ruby/object:Gem::Specification name: i18n version: !ruby/object:Gem::Version - version: 0.7.0 + version: 0.8.1 platform: ruby authors: - Sven Fuchs @@ -12,7 +12,7 @@ autorequire: bindir: bin cert_chain: [] -date: 2014-12-19 00:00:00.000000000 Z +date: 2017-02-22 00:00:00.000000000 Z dependencies: [] description: New wave Internationalization support for Ruby. email: [email protected] @@ -23,15 +23,11 @@ - MIT-LICENSE - README.md - gemfiles/Gemfile.rails-3.2.x -- gemfiles/Gemfile.rails-3.2.x.lock - gemfiles/Gemfile.rails-4.0.x -- gemfiles/Gemfile.rails-4.0.x.lock - gemfiles/Gemfile.rails-4.1.x -- gemfiles/Gemfile.rails-4.1.x.lock - gemfiles/Gemfile.rails-4.2.x -- gemfiles/Gemfile.rails-4.2.x.lock +- gemfiles/Gemfile.rails-5.0.x - gemfiles/Gemfile.rails-master -- gemfiles/Gemfile.rails-master.lock - lib/i18n.rb - lib/i18n/backend.rb - lib/i18n/backend/base.rb @@ -136,7 +132,7 @@ version: 1.3.5 requirements: [] rubyforge_project: "[none]" -rubygems_version: 2.4.3 +rubygems_version: 2.6.8 signing_key: specification_version: 4 summary: New wave Internationalization support for Ruby diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/backend/cache_test.rb new/test/backend/cache_test.rb --- old/test/backend/cache_test.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/test/backend/cache_test.rb 2017-02-22 03:51:26.000000000 +0100 @@ -15,6 +15,7 @@ I18n.backend = Backend.new super I18n.cache_store = ActiveSupport::Cache.lookup_store(:memory_store) + I18n.cache_key_digest = nil end def teardown @@ -37,6 +38,12 @@ assert_equal 'Bar', I18n.t(:bar) end + test "translate returns a cached false response" do + I18n.backend.expects(:lookup).never + I18n.cache_store.expects(:read).returns(false) + assert_equal false, I18n.t(:foo) + end + test "still raises MissingTranslationData but also caches it" do assert_raise(I18n::MissingTranslationData) { I18n.t(:missing, :raise => true) } assert_raise(I18n::MissingTranslationData) { I18n.t(:missing, :raise => true) } @@ -60,10 +67,19 @@ test "adds locale and hash of key and hash of options" do options = { :bar=>1 } - options_hash = I18n::Backend::Cache::USE_INSPECT_HASH ? options.inspect.hash : options.hash + options_hash = RUBY_VERSION <= "1.9" ? options.inspect.hash : options.hash assert_equal "i18n//en/#{:foo.hash}/#{options_hash}", I18n.backend.send(:cache_key, :en, :foo, options) end + test "cache_key uses configured digest method" do + md5 = Digest::MD5.new + options = { :bar=>1 } + options_hash = options.inspect + with_cache_key_digest(md5) do + assert_equal "i18n//en/#{md5.hexdigest(:foo.to_s)}/#{md5.hexdigest(options_hash)}", I18n.backend.send(:cache_key, :en, :foo, options) + end + end + test "keys should not be equal" do interpolation_values1 = { :foo => 1, :bar => 2 } interpolation_values2 = { :foo => 2, :bar => 1 } @@ -81,6 +97,12 @@ yield I18n.cache_namespace = nil end + + def with_cache_key_digest(digest) + I18n.cache_key_digest = digest + yield + I18n.cache_key_digest = nil + end end end # AS cache check diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/backend/fallbacks_test.rb new/test/backend/fallbacks_test.rb --- old/test/backend/fallbacks_test.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/test/backend/fallbacks_test.rb 2017-02-22 03:51:26.000000000 +0100 @@ -68,6 +68,14 @@ 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) } @@ -141,6 +149,10 @@ assert_equal 'FOO', I18n.t(:foo, :locale => :'de-DE') end + test "falls back from de-DE to de when there is no translation for de-DE available when using arrays, too" do + assert_equal ['FOO', 'FOO'], I18n.t([:foo, :foo], :locale => :'de-DE') + end + test "should not raise error when enforce_available_locales is true, :'pt' is missing and default is a Symbol" do I18n.enforce_available_locales = true begin @@ -150,3 +162,45 @@ end end end + +class I18nBackendFallbacksExistsTest < I18n::TestCase + class Backend < I18n::Backend::Simple + include I18n::Backend::Fallbacks + end + + def setup + super + I18n.backend = Backend.new + store_translations(:en, :foo => 'Foo in :en', :bar => 'Bar in :en') + store_translations(:de, :bar => 'Bar in :de') + store_translations(:'de-DE', :baz => 'Baz in :de-DE') + end + + test "exists? given an existing key will return true" do + assert_equal true, I18n.exists?(:foo) + end + + test "exists? given a non-existing key will return false" do + assert_equal false, I18n.exists?(:bogus) + end + + test "exists? given an existing key and an existing locale will return true" do + assert_equal true, I18n.exists?(:foo, :en) + assert_equal true, I18n.exists?(:bar, :de) + end + + test "exists? given a non-existing key and an existing locale will return false" do + assert_equal false, I18n.exists?(:bogus, :en) + assert_equal false, I18n.exists?(:bogus, :de) + end + + test "exists? should return true given a key which is missing from the given locale and exists in a fallback locale" do + assert_equal true, I18n.exists?(:foo, :de) + assert_equal true, I18n.exists?(:foo, :'de-DE') + end + + test "exists? should return false given a key which is missing from the given locale and all its fallback locales" do + assert_equal false, I18n.exists?(:baz, :de) + assert_equal false, I18n.exists?(:bogus, :'de-DE') + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/core_ext/hash_test.rb new/test/core_ext/hash_test.rb --- old/test/core_ext/hash_test.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/test/core_ext/hash_test.rb 2017-02-22 03:51:26.000000000 +0100 @@ -14,6 +14,18 @@ assert_equal expected, hash.slice(:foo) end + test "#slice non-existent key" do + hash = { :foo => 'bar', :baz => 'bar' } + expected = { :foo => 'bar' } + assert_equal expected, hash.slice(:foo, :not_here) + end + + test "#slice maintains subclasses of Hash" do + klass = Class.new(Hash) + hash = klass[:foo, 'bar', :baz, 'bar'] + assert_instance_of klass, hash.slice(:foo) + end + test "#except" do hash = { :foo => 'bar', :baz => 'bar' } expected = { :foo => 'bar' } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/gettext/api_test.rb new/test/gettext/api_test.rb --- old/test/gettext/api_test.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/test/gettext/api_test.rb 2017-02-22 03:51:26.000000000 +0100 @@ -18,6 +18,13 @@ }, :separator => '|' end + # N_ + def test_N_returns_original_msg + assert_equal 'foo|bar', N_('foo|bar') + I18n.locale = :de + assert_equal 'Hi Gettext!', N_('Hi Gettext!') + end + # gettext def test_gettext_uses_msg_as_default assert_equal 'Hi Gettext!', _('Hi Gettext!') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/i18n/exceptions_test.rb new/test/i18n/exceptions_test.rb --- old/test/i18n/exceptions_test.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/test/i18n/exceptions_test.rb 2017-02-22 03:51:26.000000000 +0100 @@ -13,6 +13,11 @@ end end + test "MissingTranslation can be initialized without options" do + exception = I18n::MissingTranslation.new(:en, 'foo') + assert_equal({}, exception.options) + end + test "MissingTranslationData exception stores locale, key and options" do force_missing_translation_data do |exception| assert_equal 'de', exception.locale @@ -66,6 +71,10 @@ 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 private diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/i18n/interpolate_test.rb new/test/i18n/interpolate_test.rb --- old/test/i18n/interpolate_test.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/test/i18n/interpolate_test.rb 2017-02-22 03:51:26.000000000 +0100 @@ -57,6 +57,17 @@ def test_sprintf_mix_unformatted_and_formatted_named_placeholders assert_equal "foo 1.000000", I18n.interpolate("%{name} %<num>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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/i18n_test.rb new/test/i18n_test.rb --- old/test/i18n_test.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/test/i18n_test.rb 2017-02-22 03:51:26.000000000 +0100 @@ -269,6 +269,10 @@ assert_raise(I18n::ArgumentError) { I18n.l nil } end + test "localize given nil and default returns default" do + assert_nil I18n.l(nil, :default => nil) + end + test "localize given an Object raises an I18n::ArgumentError" do assert_raise(I18n::ArgumentError) { I18n.l Object.new } end @@ -347,6 +351,10 @@ 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) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/test_data/locales/plurals.rb new/test/test_data/locales/plurals.rb --- old/test/test_data/locales/plurals.rb 2014-12-19 18:06:15.000000000 +0100 +++ new/test/test_data/locales/plurals.rb 2017-02-22 03:51:26.000000000 +0100 @@ -74,7 +74,7 @@ :or => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :pa => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :pap => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, - :pl => { :i18n => { :plural => { :keys => [:one, :few, :other], :rule => lambda { |n| n == 1 ? :one : [2, 3, 4].include?(n % 10) && ![12, 13, 14].include?(n % 100) ? :few : :other } } } }, + :pl => { :i18n => { :plural => { :keys => [:one, :few, :many, :other], :rule => lambda { |n| n == 1 ? :one : [2, 3, 4].include?(n % 10) && ![12, 13, 14].include?(n % 100) ? :few : (n != 1 && [0, 1].include?(n % 10)) || [5, 6, 7, 8, 9].include?(n % 10) || [12, 13, 14].include?(n % 100) ? :many : :other } } } }, :ps => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :pt => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| [0, 1].include?(n) ? :one : :other } } } }, :"pt-PT" => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } },
