i18n 0.9.1 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
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