i18n 1.14.1 → 1.14.5
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 +4 -4
- data/README.md +4 -0
- data/lib/i18n/backend/base.rb +5 -3
- data/lib/i18n/backend/fallbacks.rb +1 -1
- data/lib/i18n/backend/interpolation_compiler.rb +5 -7
- data/lib/i18n/locale/fallbacks.rb +13 -3
- data/lib/i18n/tests/interpolation.rb +22 -0
- data/lib/i18n/version.rb +1 -1
- data/lib/i18n.rb +41 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8e29c720198c6fd20a8ec55a99ad4ce81c2ff09abf74a55ee6e09513ac17546c
|
4
|
+
data.tar.gz: 6ad9b851da6ba7c857dbd79b9e817493f7eaba91be46f16cec3a86cb94c32c11
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7de3901b122039da2a99507e40dbe5e57ce8e5622c14591ebf251adf563c763f55d2f1fb1bc7d54c5f2be427a37b81839e636de7eee434a53ab80a39c4f8bf53
|
7
|
+
data.tar.gz: 1bfd4bd7c5dd8de6df524ae64d652e2f785955a1928bd3bca66e3ba8515e2d4d60c83ff576c51ca84e744625874145c0850f301b8d2fd6090c226541ad389575
|
data/README.md
CHANGED
@@ -13,10 +13,14 @@ Currently maintained by @radar.
|
|
13
13
|
|
14
14
|
You will most commonly use this library within a Rails app.
|
15
15
|
|
16
|
+
We support Rails versions from 6.0 and up.
|
17
|
+
|
16
18
|
[See the Rails Guide](https://guides.rubyonrails.org/i18n.html) for an example of its usage.
|
17
19
|
|
18
20
|
### Ruby (without Rails)
|
19
21
|
|
22
|
+
We support Ruby versions from 3.0 and up.
|
23
|
+
|
20
24
|
If you want to use this library without Rails, you can simply add `i18n` to your `Gemfile`:
|
21
25
|
|
22
26
|
```ruby
|
data/lib/i18n/backend/base.rb
CHANGED
@@ -55,12 +55,14 @@ module I18n
|
|
55
55
|
|
56
56
|
deep_interpolation = options[:deep_interpolation]
|
57
57
|
values = Utils.except(options, *RESERVED_KEYS) unless options.empty?
|
58
|
-
if values
|
58
|
+
if values && !values.empty?
|
59
59
|
entry = if deep_interpolation
|
60
60
|
deep_interpolate(locale, entry, values)
|
61
61
|
else
|
62
62
|
interpolate(locale, entry, values)
|
63
63
|
end
|
64
|
+
elsif entry.is_a?(String) && entry =~ I18n.reserved_keys_pattern
|
65
|
+
raise ReservedInterpolationKey.new($1.to_sym, entry)
|
64
66
|
end
|
65
67
|
entry
|
66
68
|
end
|
@@ -186,8 +188,8 @@ module I18n
|
|
186
188
|
#
|
187
189
|
# if the given subject is an array then:
|
188
190
|
# each element of the array is recursively interpolated (until it finds a string)
|
189
|
-
# method interpolates ["yes, %{user}", ["maybe no, %{user}, "no, %{user}"]], :user => "bartuz"
|
190
|
-
# # =>
|
191
|
+
# method interpolates ["yes, %{user}", ["maybe no, %{user}", "no, %{user}"]], :user => "bartuz"
|
192
|
+
# # => ["yes, bartuz", ["maybe no, bartuz", "no, bartuz"]]
|
191
193
|
def interpolate(locale, subject, values = EMPTY_HASH)
|
192
194
|
return subject if values.empty?
|
193
195
|
|
@@ -95,7 +95,7 @@ module I18n
|
|
95
95
|
return super unless options.fetch(:fallback, true)
|
96
96
|
I18n.fallbacks[locale].each do |fallback|
|
97
97
|
begin
|
98
|
-
return true if super(fallback, key)
|
98
|
+
return true if super(fallback, key, options)
|
99
99
|
rescue I18n::InvalidLocale
|
100
100
|
# we do nothing when the locale is invalid, as this is a fallback anyways.
|
101
101
|
end
|
@@ -21,8 +21,7 @@ module I18n
|
|
21
21
|
module Compiler
|
22
22
|
extend self
|
23
23
|
|
24
|
-
TOKENIZER
|
25
|
-
INTERPOLATION_SYNTAX_PATTERN = /(%)?(%\{([^\}]+)\})/
|
24
|
+
TOKENIZER = /(%%?\{[^}]+\})/
|
26
25
|
|
27
26
|
def compile_if_an_interpolation(string)
|
28
27
|
if interpolated_str?(string)
|
@@ -37,7 +36,7 @@ module I18n
|
|
37
36
|
end
|
38
37
|
|
39
38
|
def interpolated_str?(str)
|
40
|
-
str.kind_of?(::String) && str =~
|
39
|
+
str.kind_of?(::String) && str =~ TOKENIZER
|
41
40
|
end
|
42
41
|
|
43
42
|
protected
|
@@ -48,13 +47,12 @@ module I18n
|
|
48
47
|
|
49
48
|
def compiled_interpolation_body(str)
|
50
49
|
tokenize(str).map do |token|
|
51
|
-
|
50
|
+
token.match(TOKENIZER) ? handle_interpolation_token(token) : escape_plain_str(token)
|
52
51
|
end.join
|
53
52
|
end
|
54
53
|
|
55
|
-
def handle_interpolation_token(
|
56
|
-
|
57
|
-
escaped ? pattern : compile_interpolation_token(key.to_sym)
|
54
|
+
def handle_interpolation_token(token)
|
55
|
+
token.start_with?('%%') ? token[1..] : compile_interpolation_token(token[2..-2])
|
58
56
|
end
|
59
57
|
|
60
58
|
def compile_interpolation_token(key)
|
@@ -79,14 +79,24 @@ module I18n
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
|
+
def empty?
|
83
|
+
@map.empty? && @defaults.empty?
|
84
|
+
end
|
85
|
+
|
86
|
+
def inspect
|
87
|
+
"#<#{self.class.name} @map=#{@map.inspect} @defaults=#{@defaults.inspect}>"
|
88
|
+
end
|
89
|
+
|
82
90
|
protected
|
83
91
|
|
84
92
|
def compute(tags, include_defaults = true, exclude = [])
|
85
|
-
result =
|
93
|
+
result = []
|
94
|
+
Array(tags).each do |tag|
|
86
95
|
tags = I18n::Locale::Tag.tag(tag).self_and_parents.map! { |t| t.to_sym } - exclude
|
87
|
-
|
88
|
-
tags
|
96
|
+
result += tags
|
97
|
+
tags.each { |_tag| result += compute(@map[_tag], false, exclude + result) if @map[_tag] }
|
89
98
|
end
|
99
|
+
|
90
100
|
result.push(*defaults) if include_defaults
|
91
101
|
result.uniq!
|
92
102
|
result.compact!
|
@@ -112,6 +112,28 @@ module I18n
|
|
112
112
|
assert_raises(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{default}') }
|
113
113
|
assert_raises(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{separator}') }
|
114
114
|
assert_raises(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{scope}') }
|
115
|
+
assert_raises(I18n::ReservedInterpolationKey) { interpolate(:default => '%{scope}') }
|
116
|
+
|
117
|
+
I18n.backend.store_translations(:en, :interpolate => 'Hi %{scope}!')
|
118
|
+
assert_raises(I18n::ReservedInterpolationKey) { interpolate(:interpolate) }
|
119
|
+
end
|
120
|
+
|
121
|
+
test "interpolation: it does not raise I18n::ReservedInterpolationKey for escaped variables" do
|
122
|
+
assert_nothing_raised do
|
123
|
+
assert_equal '%{separator}', interpolate(:foo => :bar, :default => '%%{separator}')
|
124
|
+
end
|
125
|
+
|
126
|
+
# Note: The two interpolations below do not remove the escape character (%) because
|
127
|
+
# I18n should not alter the strings when no interpolation parameters are given,
|
128
|
+
# see the comment at the top of this file.
|
129
|
+
assert_nothing_raised do
|
130
|
+
assert_equal '%%{scope}', interpolate(:default => '%%{scope}')
|
131
|
+
end
|
132
|
+
|
133
|
+
I18n.backend.store_translations(:en, :interpolate => 'Hi %%{scope}!')
|
134
|
+
assert_nothing_raised do
|
135
|
+
assert_equal 'Hi %%{scope}!', interpolate(:interpolate)
|
136
|
+
end
|
115
137
|
end
|
116
138
|
|
117
139
|
test "interpolation: deep interpolation for default string" do
|
data/lib/i18n/version.rb
CHANGED
data/lib/i18n.rb
CHANGED
@@ -48,7 +48,7 @@ module I18n
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def self.reserved_keys_pattern # :nodoc:
|
51
|
-
@reserved_keys_pattern ||=
|
51
|
+
@reserved_keys_pattern ||= /(?<!%)%\{(#{RESERVED_KEYS.join("|")})\}/
|
52
52
|
end
|
53
53
|
|
54
54
|
module Base
|
@@ -231,6 +231,35 @@ module I18n
|
|
231
231
|
end
|
232
232
|
alias :t! :translate!
|
233
233
|
|
234
|
+
# Returns an array of interpolation keys for the given translation key
|
235
|
+
#
|
236
|
+
# *Examples*
|
237
|
+
#
|
238
|
+
# Suppose we have the following:
|
239
|
+
# I18n.t 'example.zero' == 'Zero interpolations'
|
240
|
+
# I18n.t 'example.one' == 'One interpolation %{foo}'
|
241
|
+
# I18n.t 'example.two' == 'Two interpolations %{foo} %{bar}'
|
242
|
+
# I18n.t 'example.three' == ['One %{foo}', 'Two %{bar}', 'Three %{baz}']
|
243
|
+
# I18n.t 'example.one', locale: :other == 'One interpolation %{baz}'
|
244
|
+
#
|
245
|
+
# Then we can expect the following results:
|
246
|
+
# I18n.interpolation_keys('example.zero') #=> []
|
247
|
+
# I18n.interpolation_keys('example.one') #=> ['foo']
|
248
|
+
# I18n.interpolation_keys('example.two') #=> ['foo', 'bar']
|
249
|
+
# I18n.interpolation_keys('example.three') #=> ['foo', 'bar', 'baz']
|
250
|
+
# I18n.interpolation_keys('one', scope: 'example', locale: :other) #=> ['baz']
|
251
|
+
# I18n.interpolation_keys('does-not-exist') #=> []
|
252
|
+
# I18n.interpolation_keys('example') #=> []
|
253
|
+
def interpolation_keys(key, **options)
|
254
|
+
raise I18n::ArgumentError if !key.is_a?(String) || key.empty?
|
255
|
+
|
256
|
+
return [] unless exists?(key, **options.slice(:locale, :scope))
|
257
|
+
|
258
|
+
translation = translate(key, **options.slice(:locale, :scope))
|
259
|
+
interpolation_keys_from_translation(translation)
|
260
|
+
.flatten.compact
|
261
|
+
end
|
262
|
+
|
234
263
|
# Returns true if a translation exists for a given key, otherwise returns false.
|
235
264
|
def exists?(key, _locale = nil, locale: _locale, **options)
|
236
265
|
locale ||= config.locale
|
@@ -429,6 +458,17 @@ module I18n
|
|
429
458
|
keys
|
430
459
|
end
|
431
460
|
end
|
461
|
+
|
462
|
+
def interpolation_keys_from_translation(translation)
|
463
|
+
case translation
|
464
|
+
when ::String
|
465
|
+
translation.scan(Regexp.union(I18n.config.interpolation_patterns))
|
466
|
+
when ::Array
|
467
|
+
translation.map { |element| interpolation_keys_from_translation(element) }
|
468
|
+
else
|
469
|
+
[]
|
470
|
+
end
|
471
|
+
end
|
432
472
|
end
|
433
473
|
|
434
474
|
extend Base
|
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.14.
|
4
|
+
version: 1.14.5
|
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:
|
16
|
+
date: 2024-05-06 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: concurrent-ruby
|
@@ -106,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
106
106
|
- !ruby/object:Gem::Version
|
107
107
|
version: 1.3.5
|
108
108
|
requirements: []
|
109
|
-
rubygems_version: 3.
|
109
|
+
rubygems_version: 3.5.1
|
110
110
|
signing_key:
|
111
111
|
specification_version: 4
|
112
112
|
summary: New wave Internationalization support for Ruby
|