i18n 0.9.1 → 0.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 74991fa815d721be21fc8f4cb3d10dbe7c069059
4
- data.tar.gz: 9f325a9e4bc99bc01883448c5871fc13f1eff5a3
2
+ SHA256:
3
+ metadata.gz: 57b2ff3a6c23f6e74b39b1be0a56311a2b49025f71d9e16ac4fde2d93e6448bf
4
+ data.tar.gz: 7d21368bbe369fc644e10785db19f47f7d5eef492dfdebaa090152470ffe3c00
5
5
  SHA512:
6
- metadata.gz: 641844afc32707026b98596528a19fe177fef51e5d681f98db746d1980315c85f864dab53c5390f62f4d143d31b68b75f41b88e780478f0b00bde9e9e6cbf7dc
7
- data.tar.gz: f62868e06de0b22744316dfcc74d1e928c6263552043bfea8dfbfd985ad660dbdc404e8324d6b5a85dd62d8355935e8cb999a2c21f540fe5fd68725041d05b21
6
+ metadata.gz: 8bd2956e1905c8b3d0dfb65696f6f4b96e91583a649bdf0e81772dad80c72240ee1b96996983b8e44ee312fae58aee63732166268b34669ead66c3f87d716dee
7
+ data.tar.gz: e74c46af688ac02e8fb776b39dc873ae9951901b9567e08d1fd21b68d0d5677cbc9ceeba2d8b2f2c1500b3f886084e31eafc80083adaa4572017f3ccb67a0028
@@ -7,3 +7,4 @@ gem 'mocha'
7
7
  gem 'test_declarative'
8
8
  gem 'rake'
9
9
  gem 'minitest'
10
+ gem 'oj'
@@ -7,3 +7,4 @@ gem 'mocha'
7
7
  gem 'test_declarative'
8
8
  gem 'rake'
9
9
  gem 'minitest'
10
+ gem 'oj'
@@ -7,3 +7,4 @@ gem 'mocha'
7
7
  gem 'test_declarative'
8
8
  gem 'rake'
9
9
  gem 'minitest'
10
+ gem 'oj'
@@ -7,3 +7,4 @@ gem 'mocha'
7
7
  gem 'test_declarative'
8
8
  gem 'rake'
9
9
  gem 'minitest'
10
+ gem 'oj'
@@ -7,3 +7,4 @@ gem 'mocha'
7
7
  gem 'test_declarative'
8
8
  gem 'rake'
9
9
  gem 'minitest'
10
+ gem 'oj'
@@ -7,3 +7,4 @@ gem 'mocha'
7
7
  gem 'test_declarative'
8
8
  gem 'rake'
9
9
  gem 'minitest'
10
+ gem 'oj'
@@ -7,3 +7,4 @@ gem 'mocha'
7
7
  gem 'test_declarative'
8
8
  gem 'rake'
9
9
  gem 'minitest'
10
+ gem 'oj'
@@ -140,10 +140,14 @@ module I18n
140
140
  # called and passed the key and options.
141
141
  #
142
142
  # E.g. assuming the key <tt>:salutation</tt> resolves to:
143
- # lambda { |key, options| options[:gender] == 'm' ? "Mr. %{options[:name]}" : "Mrs. %{options[:name]}" }
143
+ # lambda { |key, options| options[:gender] == 'm' ? "Mr. #{options[:name]}" : "Mrs. #{options[:name]}" }
144
144
  #
145
145
  # Then <tt>I18n.t(:salutation, :gender => 'w', :name => 'Smith') will result in "Mrs. Smith".
146
146
  #
147
+ # Note that the string returned by lambda will go through string interpolation too,
148
+ # so the following lambda would give the same result:
149
+ # lambda { |key, options| options[:gender] == 'm' ? "Mr. %{name}" : "Mrs. %{name}" }
150
+ #
147
151
  # It is recommended to use/implement lambdas in an "idempotent" way. E.g. when
148
152
  # a cache layer is put in front of I18n.translate it will generate a cache key
149
153
  # from the argument values passed to #translate. Therefor your lambdas should
@@ -157,7 +161,6 @@ module I18n
157
161
  handling = options.delete(:throw) && :throw || options.delete(:raise) && :raise # TODO deprecate :raise
158
162
 
159
163
  enforce_available_locales!(locale)
160
- raise I18n::ArgumentError if key.is_a?(String) && key.empty?
161
164
 
162
165
  result = catch(:exception) do
163
166
  if key.is_a?(Array)
@@ -293,6 +296,10 @@ module I18n
293
296
  end
294
297
  end
295
298
 
299
+ def available_locales_initialized?
300
+ config.available_locales_initialized?
301
+ end
302
+
296
303
  private
297
304
 
298
305
  # Any exceptions thrown in translate will be sent to the @@exception_handler
@@ -22,7 +22,10 @@ module I18n
22
22
  end
23
23
 
24
24
  def translate(locale, key, options = {})
25
+ raise I18n::ArgumentError if (key.is_a?(String) || key.is_a?(Symbol)) && key.empty?
25
26
  raise InvalidLocale.new(locale) unless locale
27
+ return nil if key.nil? && !options.key?(:default)
28
+
26
29
  entry = lookup(locale, key, options[:scope], options) unless key.nil?
27
30
 
28
31
  if entry.nil? && options.key?(:default)
@@ -31,17 +34,17 @@ module I18n
31
34
  entry = resolve(locale, key, entry, options)
32
35
  end
33
36
 
37
+ entry = entry.dup if entry.is_a?(String)
38
+
39
+ count = options[:count]
40
+ entry = pluralize(locale, entry, count) if count
41
+
34
42
  if entry.nil?
35
43
  if (options.key?(:default) && !options[:default].nil?) || !options.key?(:default)
36
44
  throw(:exception, I18n::MissingTranslation.new(locale, key, options))
37
45
  end
38
46
  end
39
47
 
40
- entry = entry.dup if entry.is_a?(String)
41
-
42
- count = options[:count]
43
- entry = pluralize(locale, entry, count) if count
44
-
45
48
  deep_interpolation = options[:deep_interpolation]
46
49
  values = options.except(*RESERVED_KEYS)
47
50
  if values
@@ -103,7 +106,8 @@ module I18n
103
106
  case subject
104
107
  when Array
105
108
  subject.each do |item|
106
- result = resolve(locale, object, item, options) and return result
109
+ result = resolve(locale, object, item, options)
110
+ return result unless result.nil?
107
111
  end and nil
108
112
  else
109
113
  resolve(locale, object, subject, options)
@@ -147,15 +151,26 @@ module I18n
147
151
  entry[key]
148
152
  end
149
153
 
150
- # Interpolates values into a given string.
154
+ # Interpolates values into a given subject.
151
155
  #
152
- # interpolate "file %{file} opened by %%{user}", :file => 'test.txt', :user => 'Mr. X'
156
+ # if the given subject is a string then:
157
+ # method interpolates "file %{file} opened by %%{user}", :file => 'test.txt', :user => 'Mr. X'
153
158
  # # => "file test.txt opened by %{user}"
154
- def interpolate(locale, string, values = {})
155
- if string.is_a?(::String) && !values.empty?
156
- I18n.interpolate(string, values)
159
+ #
160
+ # if the given subject is an array then:
161
+ # each element of the array is recursively interpolated (until it finds a string)
162
+ # method interpolates ["yes, %{user}", ["maybe no, %{user}, "no, %{user}"]], :user => "bartuz"
163
+ # # => "["yes, bartuz",["maybe no, bartuz", "no, bartuz"]]"
164
+
165
+
166
+ def interpolate(locale, subject, values = {})
167
+ return subject if values.empty?
168
+
169
+ case subject
170
+ when ::String then I18n.interpolate(subject, values)
171
+ when ::Array then subject.map { |element| interpolate(locale, element, values) }
157
172
  else
158
- string
173
+ subject
159
174
  end
160
175
  end
161
176
 
@@ -1,7 +1,24 @@
1
1
  require 'i18n/backend/base'
2
- require 'active_support/json'
3
2
 
4
3
  module I18n
4
+
5
+ begin
6
+ require 'oj'
7
+ class JSON
8
+ class << self
9
+ def encode(value)
10
+ Oj::Rails.encode(value)
11
+ end
12
+ def decode(value)
13
+ Oj.load(value)
14
+ end
15
+ end
16
+ end
17
+ rescue LoadError
18
+ require 'active_support/json'
19
+ JSON = ActiveSupport::JSON
20
+ end
21
+
5
22
  module Backend
6
23
  # This is a basic backend for key value stores. It receives on
7
24
  # initialization the store, which should respond to three methods:
@@ -65,14 +82,14 @@ module I18n
65
82
  case value
66
83
  when Hash
67
84
  if @subtrees && (old_value = @store[key])
68
- old_value = ActiveSupport::JSON.decode(old_value)
85
+ old_value = JSON.decode(old_value)
69
86
  value = old_value.deep_symbolize_keys.deep_merge!(value) if old_value.is_a?(Hash)
70
87
  end
71
88
  when Proc
72
89
  raise "Key-value stores cannot handle procs"
73
90
  end
74
91
 
75
- @store[key] = ActiveSupport::JSON.encode(value) unless value.is_a?(Symbol)
92
+ @store[key] = JSON.encode(value) unless value.is_a?(Symbol)
76
93
  end
77
94
  end
78
95
 
@@ -89,8 +106,52 @@ module I18n
89
106
  def lookup(locale, key, scope = [], options = {})
90
107
  key = normalize_flat_keys(locale, key, scope, options[:separator])
91
108
  value = @store["#{locale}.#{key}"]
92
- value = ActiveSupport::JSON.decode(value) if value
93
- value.is_a?(Hash) ? value.deep_symbolize_keys : value
109
+ value = JSON.decode(value) if value
110
+
111
+ if value.is_a?(Hash)
112
+ value.deep_symbolize_keys
113
+ elsif !value.nil?
114
+ value
115
+ elsif !@subtrees
116
+ SubtreeProxy.new("#{locale}.#{key}", @store)
117
+ end
118
+ end
119
+ end
120
+
121
+ class SubtreeProxy
122
+ def initialize(master_key, store)
123
+ @master_key = master_key
124
+ @store = store
125
+ @subtree = nil
126
+ end
127
+
128
+ def has_key?(key)
129
+ @subtree && @subtree.has_key?(key) || self[key]
130
+ end
131
+
132
+ def [](key)
133
+ unless @subtree && value = @subtree[key]
134
+ value = @store["#{@master_key}.#{key}"]
135
+ (@subtree ||= {})[key] = JSON.decode(value) if value
136
+ end
137
+ value
138
+ end
139
+
140
+ def is_a?(klass)
141
+ Hash == klass || super
142
+ end
143
+ alias :kind_of? :is_a?
144
+
145
+ def instance_of?(klass)
146
+ Hash == klass || super
147
+ end
148
+
149
+ def nil?
150
+ @subtree.nil?
151
+ end
152
+
153
+ def inspect
154
+ @subtree.inspect
94
155
  end
95
156
  end
96
157
 
@@ -29,6 +29,11 @@ module I18n
29
29
  # translations will be overwritten by new ones only at the deepest
30
30
  # level of the hash.
31
31
  def store_translations(locale, data, options = {})
32
+ if I18n.available_locales_initialized? &&
33
+ !I18n.available_locales.include?(locale.to_sym) &&
34
+ !I18n.available_locales.include?(locale.to_s)
35
+ return data
36
+ end
32
37
  locale = locale.to_sym
33
38
  translations[locale] ||= {}
34
39
  data = data.deep_symbolize_keys
@@ -57,6 +57,11 @@ module I18n
57
57
  @@available_locales = nil if @@available_locales.empty?
58
58
  @@available_locales_set = nil
59
59
  end
60
+
61
+ # Returns true if the available_locales have been initialized
62
+ def available_locales_initialized?
63
+ ( !!defined?(@@available_locales) && !!@@available_locales )
64
+ end
60
65
 
61
66
  # Clears the available locales set so it can be recomputed again after I18n
62
67
  # gets reloaded.
@@ -24,6 +24,10 @@ module I18n
24
24
  assert_equal 'bar', I18n.t(:does_not_exist, :default => [:does_not_exist_2, :'foo.bar'])
25
25
  end
26
26
 
27
+ test "defaults: given an array as a default with false it returns false" do
28
+ assert_equal false, I18n.t(:does_not_exist, :default => [false])
29
+ end
30
+
27
31
  test "defaults: given false it returns false" do
28
32
  assert_equal false, I18n.t(:does_not_exist, :default => false)
29
33
  end
@@ -54,6 +54,11 @@ module I18n
54
54
  assert_equal 'Hi Yehuda!', interpolate(:interpolate, :name => 'Yehuda')
55
55
  end
56
56
 
57
+ test "interpolation: given an array interpolates each element" do
58
+ I18n.backend.store_translations(:en, :array_interpolate => ['Hi', 'Mr. %{name}', 'or sir %{name}'])
59
+ assert_equal ['Hi', 'Mr. Bartuz', 'or sir Bartuz'], interpolate(:array_interpolate, :name => 'Bartuz')
60
+ end
61
+
57
62
  test "interpolation: given the translation is in utf-8 it still works" do
58
63
  assert_equal 'Häi David!', interpolate(:default => 'Häi %{name}!', :name => 'David')
59
64
  end
@@ -1,3 +1,3 @@
1
1
  module I18n
2
- VERSION = "0.9.1"
2
+ VERSION = "0.9.3"
3
3
  end
@@ -40,4 +40,10 @@ class I18nBackendKeyValueTest < I18n::TestCase
40
40
  I18n.t("foo", :raise => true)
41
41
  end
42
42
  end
43
+
44
+ test "translate handles subtrees for pluralization" do
45
+ setup_backend!(false)
46
+ store_translations(:en, :bar => { :one => "One" })
47
+ assert_equal("One", I18n.t("bar", :count => 1))
48
+ end
43
49
  end if I18n::TestCase.key_value?
@@ -70,6 +70,14 @@ class I18nBackendSimpleTest < I18n::TestCase
70
70
  assert_equal Hash[:'en', {:foo => {:bar => 'bar', :baz => 'baz'}}], translations
71
71
  end
72
72
 
73
+ test "simple store_translations: do not store translations for locales not explicitly marked as available" do
74
+ I18n.available_locales = [:en, :es]
75
+ store_translations(:fr, :foo => {:bar => 'barfr', :baz => 'bazfr'})
76
+ store_translations(:es, :foo => {:bar => 'bares', :baz => 'bazes'})
77
+ assert_nil translations[:fr]
78
+ assert_equal Hash[:foo, {:bar => 'bares', :baz => 'bazes'}], translations[:es]
79
+ end
80
+
73
81
  # reloading translations
74
82
 
75
83
  test "simple reload_translations: unloads translations" do
@@ -216,6 +216,22 @@ class I18nTest < I18n::TestCase
216
216
  assert_raise(I18n::ArgumentError) { I18n.t("") }
217
217
  end
218
218
 
219
+ test "translate given an empty symbol as a key raises an I18n::ArgumentError" do
220
+ assert_raise(I18n::ArgumentError) { I18n.t(:"") }
221
+ end
222
+
223
+ test "translate given an array with empty string as a key raises an I18n::ArgumentError" do
224
+ assert_raise(I18n::ArgumentError) { I18n.t(["", :foo]) }
225
+ end
226
+
227
+ test "translate given an empty array as a key returns empty array" do
228
+ assert_equal [], I18n.t([])
229
+ end
230
+
231
+ test "translate given nil returns nil" do
232
+ assert_nil I18n.t(nil)
233
+ end
234
+
219
235
  test "translate given an unavailable locale rases an I18n::InvalidLocale" do
220
236
  begin
221
237
  I18n.config.enforce_available_locales = true
@@ -405,7 +421,7 @@ class I18nTest < I18n::TestCase
405
421
  I18n.config.enforce_available_locales = false
406
422
  end
407
423
  end
408
-
424
+
409
425
  test 'I18n.reload! reloads the set of locales that are enforced' do
410
426
  begin
411
427
  # Clear the backend that affects the available locales and somehow can remain
@@ -413,9 +429,9 @@ class I18nTest < I18n::TestCase
413
429
  # For instance, it contains enough translations to cause a false positive with
414
430
  # this test when ran with --seed=50992
415
431
  I18n.backend = I18n::Backend::Simple.new
416
-
432
+
417
433
  assert !I18n.available_locales.include?(:de), "Available locales should not include :de at this point"
418
-
434
+
419
435
  I18n.enforce_available_locales = true
420
436
 
421
437
  assert_raise(I18n::InvalidLocale) { I18n.default_locale = :de }
@@ -431,11 +447,11 @@ class I18nTest < I18n::TestCase
431
447
  store_translations(:en, :foo => 'Foo in :en')
432
448
  store_translations(:de, :foo => 'Foo in :de')
433
449
  store_translations(:pl, :foo => 'Foo in :pl')
434
-
450
+
435
451
  assert I18n.available_locales.include?(:de), ":de should now be allowed"
436
452
  assert I18n.available_locales.include?(:en), ":en should now be allowed"
437
453
  assert I18n.available_locales.include?(:pl), ":pl should now be allowed"
438
-
454
+
439
455
  assert_nothing_raised { I18n.default_locale = I18n.locale = :en }
440
456
  assert_nothing_raised { I18n.default_locale = I18n.locale = :de }
441
457
  assert_nothing_raised { I18n.default_locale = I18n.locale = :pl }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: i18n
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.1
4
+ version: 0.9.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sven Fuchs
@@ -13,7 +13,7 @@ authors:
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2017-11-03 00:00:00.000000000 Z
16
+ date: 2018-01-22 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: concurrent-ruby
@@ -151,7 +151,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
151
151
  version: 1.3.5
152
152
  requirements: []
153
153
  rubyforge_project: "[none]"
154
- rubygems_version: 2.6.11
154
+ rubygems_version: 2.7.4
155
155
  signing_key:
156
156
  specification_version: 4
157
157
  summary: New wave Internationalization support for Ruby