i18n 1.11.0 → 1.13.0

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
2
  SHA256:
3
- metadata.gz: fec00bc17a2d4f9845a6bf1394deefaab31a14460c440d5012db8939d4de2d19
4
- data.tar.gz: d5b2c057789154f3db274d6c0612dec850c2af96127c37204ac81308636ca841
3
+ metadata.gz: e85066f2cf6bbf170ff946391c6037d0335e5314d0c1e0723e980d5ee7df7af0
4
+ data.tar.gz: 2a4629aa0644c2a6e8cc5d175d4912b5f5cd4abc066dd5ee196270b7a3eadd08
5
5
  SHA512:
6
- metadata.gz: 468a6a2336896a0f5185350c16a49929e27b2201efe92bc5d067a7a03787bfa814bbe2de838be78205d870961e023633d8dbd494f488b1a6d77773082ed442de
7
- data.tar.gz: d6fb232b7a711de31cbc3ce93a624a858684c3f8258eb558774b36da2aa2a0ba9baa6bf6c65901cbdfc06f44b6810c383e6c0dd47eb1569c4ddb07394332f81d
6
+ metadata.gz: '01326189eb7b675594bd63c802ae9470135e9aab222de4df1429c99c585b9b59b172ed62386c03b82fd45c862bbb42484dc89e0289c83970315f9a5fa03ba91c'
7
+ data.tar.gz: 290489ae277759fe65197e65d6486b7cca67605c2c98197a472c91bb2496d9db168dfd2082706b87f6f806051827b8df12cc0037258f3bf10d5f74a9ddb9f575
data/README.md CHANGED
@@ -26,7 +26,7 @@ gem 'i18n'
26
26
  Then configure I18n with some translations, and a default locale:
27
27
 
28
28
  ```ruby
29
- I18n.load_path << Dir[File.expand_path("config/locales") + "/*.yml"]
29
+ I18n.load_path += Dir[File.expand_path("config/locales") + "/*.yml"]
30
30
  I18n.default_locale = :en # (note that `en` is already the default!)
31
31
  ```
32
32
 
@@ -54,7 +54,7 @@ module I18n
54
54
  end
55
55
 
56
56
  deep_interpolation = options[:deep_interpolation]
57
- values = Utils.except(options, *RESERVED_KEYS)
57
+ values = Utils.except(options, *RESERVED_KEYS) unless options.empty?
58
58
  if values
59
59
  entry = if deep_interpolation
60
60
  deep_interpolate(locale, entry, values)
@@ -66,7 +66,7 @@ module I18n
66
66
  end
67
67
 
68
68
  def exists?(locale, key, options = EMPTY_HASH)
69
- lookup(locale, key) != nil
69
+ lookup(locale, key, options[:scope]) != nil
70
70
  end
71
71
 
72
72
  # Acts the same as +strftime+, but uses a localized version of the
@@ -123,7 +123,12 @@ module I18n
123
123
  # first translation that can be resolved. Otherwise it tries to resolve
124
124
  # the translation directly.
125
125
  def default(locale, object, subject, options = EMPTY_HASH)
126
- options = options.reject { |key, value| key == :default }
126
+ if options.size == 1 && options.has_key?(:default)
127
+ options = {}
128
+ else
129
+ options = Utils.except(options, :default)
130
+ end
131
+
127
132
  case subject
128
133
  when Array
129
134
  subject.each do |item|
@@ -166,7 +171,7 @@ module I18n
166
171
  # Other backends can implement more flexible or complex pluralization rules.
167
172
  def pluralize(locale, entry, count)
168
173
  entry = entry.reject { |k, _v| k == :attributes } if entry.is_a?(Hash)
169
- return entry unless entry.is_a?(Hash) && count && entry.values.none? { |v| v.is_a?(Hash) }
174
+ return entry unless entry.is_a?(Hash) && count
170
175
 
171
176
  key = pluralization_key(entry, count)
172
177
  raise InvalidPluralizationData.new(entry, count, key) unless entry.has_key?(key)
@@ -282,8 +287,8 @@ module I18n
282
287
  when '%^b' then I18n.t!(:"date.abbr_month_names", :locale => locale, :format => format)[object.mon].upcase
283
288
  when '%B' then I18n.t!(:"date.month_names", :locale => locale, :format => format)[object.mon]
284
289
  when '%^B' then I18n.t!(:"date.month_names", :locale => locale, :format => format)[object.mon].upcase
285
- when '%p' then I18n.t!(:"time.#{object.hour < 12 ? :am : :pm}", :locale => locale, :format => format).upcase if object.respond_to? :hour
286
- when '%P' then I18n.t!(:"time.#{object.hour < 12 ? :am : :pm}", :locale => locale, :format => format).downcase if object.respond_to? :hour
290
+ when '%p' then I18n.t!(:"time.#{(object.respond_to?(:hour) ? object.hour : 0) < 12 ? :am : :pm}", :locale => locale, :format => format).upcase
291
+ when '%P' then I18n.t!(:"time.#{(object.respond_to?(:hour) ? object.hour : 0) < 12 ? :am : :pm}", :locale => locale, :format => format).downcase
287
292
  end
288
293
  end
289
294
  rescue MissingTranslationData => e
@@ -41,6 +41,12 @@ module I18n
41
41
 
42
42
  pluralizer = pluralizer(locale)
43
43
  if pluralizer.respond_to?(:call)
44
+ # Deprecation: The use of the `zero` key in this way is incorrect.
45
+ # Users that want a different string for the case of `count == 0` should use the explicit "0" key instead.
46
+ # We keep this incorrect behaviour for now for backwards compatibility until we can remove it.
47
+ # Ref: https://github.com/ruby-i18n/i18n/issues/629
48
+ return entry[:zero] if count == 0 && entry.has_key?(:zero)
49
+
44
50
  # "0" and "1" are special cases
45
51
  # https://unicode-org.github.io/cldr/ldml/tr35-numbers.html#Explicit_0_1_rules
46
52
  if count == 0 || count == 1
@@ -21,6 +21,9 @@ module I18n
21
21
  class Simple
22
22
  module Implementation
23
23
  include Base
24
+
25
+ # Mutex to ensure that concurrent translations loading will be thread-safe
26
+ MUTEX = Mutex.new
24
27
 
25
28
  def initialized?
26
29
  @initialized ||= false
@@ -68,7 +71,11 @@ module I18n
68
71
  # call `init_translations`
69
72
  init_translations if do_init && !initialized?
70
73
 
71
- @translations ||= Concurrent::Hash.new { |h, k| h[k] = Concurrent::Hash.new }
74
+ @translations ||= Concurrent::Hash.new do |h, k|
75
+ MUTEX.synchronize do
76
+ h[k] = Concurrent::Hash.new
77
+ end
78
+ end
72
79
  end
73
80
 
74
81
  protected
@@ -94,7 +101,7 @@ module I18n
94
101
  return nil unless result.has_key?(_key)
95
102
  end
96
103
  result = result[_key]
97
- result = resolve_entry(locale, _key, result, options.merge(:scope => nil)) if result.is_a?(Symbol)
104
+ result = resolve_entry(locale, _key, result, Utils.except(options.merge(:scope => nil), :count)) if result.is_a?(Symbol)
98
105
  result
99
106
  end
100
107
  end
@@ -45,30 +45,30 @@ module I18n
45
45
  "Ç"=>"C", "È"=>"E", "É"=>"E", "Ê"=>"E", "Ë"=>"E", "Ì"=>"I", "Í"=>"I",
46
46
  "Î"=>"I", "Ï"=>"I", "Ð"=>"D", "Ñ"=>"N", "Ò"=>"O", "Ó"=>"O", "Ô"=>"O",
47
47
  "Õ"=>"O", "Ö"=>"O", "×"=>"x", "Ø"=>"O", "Ù"=>"U", "Ú"=>"U", "Û"=>"U",
48
- "Ü"=>"U", "Ý"=>"Y", "Þ"=>"Th", "ß"=>"ss", "à"=>"a", "á"=>"a", "â"=>"a",
49
- "ã"=>"a", "ä"=>"a", "å"=>"a", "æ"=>"ae", "ç"=>"c", "è"=>"e", "é"=>"e",
50
- "ê"=>"e", "ë"=>"e", "ì"=>"i", "í"=>"i", "î"=>"i", "ï"=>"i", "ð"=>"d",
51
- "ñ"=>"n", "ò"=>"o", "ó"=>"o", "ô"=>"o", "õ"=>"o", "ö"=>"o", "ø"=>"o",
52
- "ù"=>"u", "ú"=>"u", "û"=>"u", "ü"=>"u", "ý"=>"y", "þ"=>"th", "ÿ"=>"y",
53
- "Ā"=>"A", "ā"=>"a", "Ă"=>"A", "ă"=>"a", "Ą"=>"A", "ą"=>"a", "Ć"=>"C",
54
- "ć"=>"c", "Ĉ"=>"C", "ĉ"=>"c", "Ċ"=>"C", "ċ"=>"c", "Č"=>"C", "č"=>"c",
55
- "Ď"=>"D", "ď"=>"d", "Đ"=>"D", "đ"=>"d", "Ē"=>"E", "ē"=>"e", "Ĕ"=>"E",
56
- "ĕ"=>"e", "Ė"=>"E", "ė"=>"e", "Ę"=>"E", "ę"=>"e", "Ě"=>"E", "ě"=>"e",
57
- "Ĝ"=>"G", "ĝ"=>"g", "Ğ"=>"G", "ğ"=>"g", "Ġ"=>"G", "ġ"=>"g", "Ģ"=>"G",
58
- "ģ"=>"g", "Ĥ"=>"H", "ĥ"=>"h", "Ħ"=>"H", "ħ"=>"h", "Ĩ"=>"I", "ĩ"=>"i",
59
- "Ī"=>"I", "ī"=>"i", "Ĭ"=>"I", "ĭ"=>"i", "Į"=>"I", "į"=>"i", "İ"=>"I",
60
- "ı"=>"i", "IJ"=>"IJ", "ij"=>"ij", "Ĵ"=>"J", "ĵ"=>"j", "Ķ"=>"K", "ķ"=>"k",
61
- "ĸ"=>"k", "Ĺ"=>"L", "ĺ"=>"l", "Ļ"=>"L", "ļ"=>"l", "Ľ"=>"L", "ľ"=>"l",
62
- "Ŀ"=>"L", "ŀ"=>"l", "Ł"=>"L", "ł"=>"l", "Ń"=>"N", "ń"=>"n", "Ņ"=>"N",
63
- "ņ"=>"n", "Ň"=>"N", "ň"=>"n", "ʼn"=>"'n", "Ŋ"=>"NG", "ŋ"=>"ng",
64
- "Ō"=>"O", "ō"=>"o", "Ŏ"=>"O", "ŏ"=>"o", "Ő"=>"O", "ő"=>"o", "Œ"=>"OE",
65
- "œ"=>"oe", "Ŕ"=>"R", "ŕ"=>"r", "Ŗ"=>"R", "ŗ"=>"r", "Ř"=>"R", "ř"=>"r",
66
- "Ś"=>"S", "ś"=>"s", "Ŝ"=>"S", "ŝ"=>"s", "Ş"=>"S", "ş"=>"s", "Š"=>"S",
67
- "š"=>"s", "Ţ"=>"T", "ţ"=>"t", "Ť"=>"T", "ť"=>"t", "Ŧ"=>"T", "ŧ"=>"t",
68
- "Ũ"=>"U", "ũ"=>"u", "Ū"=>"U", "ū"=>"u", "Ŭ"=>"U", "ŭ"=>"u", "Ů"=>"U",
69
- "ů"=>"u", "Ű"=>"U", "ű"=>"u", "Ų"=>"U", "ų"=>"u", "Ŵ"=>"W", "ŵ"=>"w",
70
- "Ŷ"=>"Y", "ŷ"=>"y", "Ÿ"=>"Y", "Ź"=>"Z", "ź"=>"z", "Ż"=>"Z", "ż"=>"z",
71
- "Ž"=>"Z", "ž"=>"z"
48
+ "Ü"=>"U", "Ý"=>"Y", "Þ"=>"Th", "ß"=>"ss", ""=>"SS", "à"=>"a",
49
+ "á"=>"a", "â"=>"a", "ã"=>"a", "ä"=>"a", "å"=>"a", "æ"=>"ae", "ç"=>"c",
50
+ "è"=>"e", "é"=>"e", "ê"=>"e", "ë"=>"e", "ì"=>"i", "í"=>"i", "î"=>"i",
51
+ "ï"=>"i", "ð"=>"d", "ñ"=>"n", "ò"=>"o", "ó"=>"o", "ô"=>"o", "õ"=>"o",
52
+ "ö"=>"o", "ø"=>"o", "ù"=>"u", "ú"=>"u", "û"=>"u", "ü"=>"u", "ý"=>"y",
53
+ "þ"=>"th", "ÿ"=>"y", "Ā"=>"A", "ā"=>"a", "Ă"=>"A", "ă"=>"a", "Ą"=>"A",
54
+ "ą"=>"a", "Ć"=>"C", "ć"=>"c", "Ĉ"=>"C", "ĉ"=>"c", "Ċ"=>"C", "ċ"=>"c",
55
+ "Č"=>"C", "č"=>"c", "Ď"=>"D", "ď"=>"d", "Đ"=>"D", "đ"=>"d", "Ē"=>"E",
56
+ "ē"=>"e", "Ĕ"=>"E", "ĕ"=>"e", "Ė"=>"E", "ė"=>"e", "Ę"=>"E", "ę"=>"e",
57
+ "Ě"=>"E", "ě"=>"e", "Ĝ"=>"G", "ĝ"=>"g", "Ğ"=>"G", "ğ"=>"g", "Ġ"=>"G",
58
+ "ġ"=>"g", "Ģ"=>"G", "ģ"=>"g", "Ĥ"=>"H", "ĥ"=>"h", "Ħ"=>"H", "ħ"=>"h",
59
+ "Ĩ"=>"I", "ĩ"=>"i", "Ī"=>"I", "ī"=>"i", "Ĭ"=>"I", "ĭ"=>"i", "Į"=>"I",
60
+ "į"=>"i", "İ"=>"I", "ı"=>"i", "IJ"=>"IJ", "ij"=>"ij", "Ĵ"=>"J", "ĵ"=>"j",
61
+ "Ķ"=>"K", "ķ"=>"k", "ĸ"=>"k", "Ĺ"=>"L", "ĺ"=>"l", "Ļ"=>"L", "ļ"=>"l",
62
+ "Ľ"=>"L", "ľ"=>"l", "Ŀ"=>"L", "ŀ"=>"l", "Ł"=>"L", "ł"=>"l", "Ń"=>"N",
63
+ "ń"=>"n", "Ņ"=>"N", "ņ"=>"n", "Ň"=>"N", "ň"=>"n", "ʼn"=>"'n", "Ŋ"=>"NG",
64
+ "ŋ"=>"ng", "Ō"=>"O", "ō"=>"o", "Ŏ"=>"O", "ŏ"=>"o", "Ő"=>"O", "ő"=>"o",
65
+ "Œ"=>"OE", "œ"=>"oe", "Ŕ"=>"R", "ŕ"=>"r", "Ŗ"=>"R", "ŗ"=>"r", "Ř"=>"R",
66
+ "ř"=>"r", "Ś"=>"S", "ś"=>"s", "Ŝ"=>"S", "ŝ"=>"s", "Ş"=>"S", "ş"=>"s",
67
+ "Š"=>"S", "š"=>"s", "Ţ"=>"T", "ţ"=>"t", "Ť"=>"T", "ť"=>"t", "Ŧ"=>"T",
68
+ "ŧ"=>"t", "Ũ"=>"U", "ũ"=>"u", "Ū"=>"U", "ū"=>"u", "Ŭ"=>"U", "ŭ"=>"u",
69
+ "Ů"=>"U", "ů"=>"u", "Ű"=>"U", "ű"=>"u", "Ų"=>"U", "ų"=>"u", "Ŵ"=>"W",
70
+ "ŵ"=>"w", "Ŷ"=>"Y", "ŷ"=>"y", "Ÿ"=>"Y", "Ź"=>"Z", "ź"=>"z", "Ż"=>"Z",
71
+ "ż"=>"z", "Ž"=>"Z", "ž"=>"z"
72
72
  }.freeze
73
73
 
74
74
  def initialize(rule = nil)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # heavily based on Masao Mutoh's gettext String interpolation extension
2
4
  # http://github.com/mutoh/gettext/blob/f6566738b981fe0952548c421042ad1e0cdfb31e/lib/gettext/core_ext/string.rb
3
5
 
@@ -10,6 +12,11 @@ module I18n
10
12
  INTERPOLATION_PATTERN = Regexp.union(DEFAULT_INTERPOLATION_PATTERNS)
11
13
  deprecate_constant :INTERPOLATION_PATTERN
12
14
 
15
+ INTERPOLATION_PATTERNS_CACHE = Hash.new do |hash, patterns|
16
+ hash[patterns] = Regexp.union(patterns)
17
+ end
18
+ private_constant :INTERPOLATION_PATTERNS_CACHE
19
+
13
20
  class << self
14
21
  # Return String or raises MissingInterpolationArgument exception.
15
22
  # Missing argument's logic is handled by I18n.config.missing_interpolation_argument_handler.
@@ -20,7 +27,12 @@ module I18n
20
27
  end
21
28
 
22
29
  def interpolate_hash(string, values)
23
- string.gsub(Regexp.union(config.interpolation_patterns)) do |match|
30
+ pattern = INTERPOLATION_PATTERNS_CACHE[config.interpolation_patterns]
31
+ interpolated = false
32
+
33
+ interpolated_string = string.gsub(pattern) do |match|
34
+ interpolated = true
35
+
24
36
  if match == '%%'
25
37
  '%'
26
38
  else
@@ -34,6 +46,8 @@ module I18n
34
46
  $3 ? sprintf("%#{$3}", value) : value
35
47
  end
36
48
  end
49
+
50
+ interpolated ? interpolated_string : string
37
51
  end
38
52
  end
39
53
  end
@@ -34,6 +34,11 @@ module I18n
34
34
  assert_equal 'Sa', I18n.l(@date, :format => '%a', :locale => :de)
35
35
  end
36
36
 
37
+ test "localize Date: given an meridian indicator format it returns the correct meridian indicator" do
38
+ assert_equal 'AM', I18n.l(@date, :format => '%p', :locale => :de)
39
+ assert_equal 'am', I18n.l(@date, :format => '%P', :locale => :de)
40
+ end
41
+
37
42
  test "localize Date: given an abbreviated and uppercased day name format it returns the correct abbreviated day name in upcase" do
38
43
  assert_equal 'sa'.upcase, I18n.l(@date, :format => '%^a', :locale => :de)
39
44
  end
data/lib/i18n/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module I18n
4
- VERSION = "1.11.0"
4
+ VERSION = "1.13.0"
5
5
  end
data/lib/i18n.rb CHANGED
@@ -331,12 +331,11 @@ module I18n
331
331
  # keys are Symbols.
332
332
  def normalize_keys(locale, key, scope, separator = nil)
333
333
  separator ||= I18n.default_separator
334
+ locale = locale.to_sym if locale
334
335
 
335
- [
336
- *normalize_key(locale, separator),
337
- *normalize_key(scope, separator),
338
- *normalize_key(key, separator)
339
- ]
336
+ result = [locale]
337
+ result.concat(normalize_key(scope, separator)) if scope
338
+ result.concat(normalize_key(key, separator))
340
339
  end
341
340
 
342
341
  # Returns true when the passed locale, which can be either a String or a
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: 1.11.0
4
+ version: 1.13.0
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: 2022-07-10 00:00:00.000000000 Z
16
+ date: 2023-04-26 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: concurrent-ruby