i18n 1.7.0 → 1.8.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +20 -23
- data/lib/i18n.rb +19 -3
- data/lib/i18n/backend/base.rb +4 -3
- data/lib/i18n/backend/chain.rb +3 -4
- data/lib/i18n/backend/fallbacks.rb +13 -2
- data/lib/i18n/backend/flatten.rb +8 -5
- data/lib/i18n/backend/pluralization.rb +1 -1
- data/lib/i18n/core_ext/hash.rb +17 -5
- data/lib/i18n/locale/fallbacks.rb +6 -4
- data/lib/i18n/locale/tag/parents.rb +8 -6
- data/lib/i18n/locale/tag/simple.rb +1 -1
- data/lib/i18n/tests/link.rb +11 -1
- data/lib/i18n/tests/localization/procs.rb +6 -5
- data/lib/i18n/tests/procs.rb +5 -0
- data/lib/i18n/version.rb +1 -1
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 461ee8866033d12fb5dd2daaa85703916b83ba58c225afd5bfe31e30c3231aa6
|
4
|
+
data.tar.gz: 9bd10034e9629c3fb72c07974fef0b069047b269dbab165ecbd5b8c38c9c5567
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: feb783a73598b1ab9e319f5569d71b14c061816bdb8e7d887262fed6531ec0a3c77afa36a4257080bbc7a1ec5239963a08b2f37a3dd449db82f9e402c5f57fbc
|
7
|
+
data.tar.gz: fdb2f914e53484a8cf925b71de1004a4d0c1bfa3da4b7d50bd14fcda1ab036ae12d773e692cbf85ade5e78906af24fcc05b22156e280a4615e26430f8929eb75
|
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# Ruby I18n
|
2
2
|
|
3
|
-
[![Build Status](https://
|
3
|
+
[![Build Status](https://github.com/ruby-i18n/i18n/workflows/Ruby/badge.svg)](https://github.com/ruby-i18n/i18n/actions?query=workflow%3ARuby)
|
4
4
|
|
5
|
-
Ruby
|
5
|
+
Ruby internationalization and localization (i18n) solution.
|
6
6
|
|
7
7
|
Currently maintained by @radar.
|
8
8
|
|
@@ -12,7 +12,7 @@ Currently maintained by @radar.
|
|
12
12
|
|
13
13
|
You will most commonly use this library within a Rails app.
|
14
14
|
|
15
|
-
[See the Rails Guide](
|
15
|
+
[See the Rails Guide](https://guides.rubyonrails.org/i18n.html) for an example of its usage.
|
16
16
|
|
17
17
|
### Ruby (without Rails)
|
18
18
|
|
@@ -51,16 +51,16 @@ I18n.t(:test) # => "Dies ist ein Test"
|
|
51
51
|
|
52
52
|
## Features
|
53
53
|
|
54
|
-
*
|
55
|
-
*
|
56
|
-
*
|
57
|
-
*
|
58
|
-
*
|
59
|
-
*
|
60
|
-
*
|
61
|
-
*
|
62
|
-
*
|
63
|
-
*
|
54
|
+
* Translation and localization
|
55
|
+
* Interpolation of values to translations
|
56
|
+
* Pluralization (CLDR compatible)
|
57
|
+
* Customizable transliteration to ASCII
|
58
|
+
* Flexible defaults
|
59
|
+
* Bulk lookup
|
60
|
+
* Lambdas as translation data
|
61
|
+
* Custom key/scope separator
|
62
|
+
* Custom exception handlers
|
63
|
+
* Extensible architecture with a swappable backend
|
64
64
|
|
65
65
|
## Pluggable Features
|
66
66
|
|
@@ -106,19 +106,16 @@ follow the usual test setup and should be easy to grok.
|
|
106
106
|
|
107
107
|
## More Documentation
|
108
108
|
|
109
|
-
Additional documentation can be found here: https://github.com/
|
110
|
-
|
111
|
-
## Authors
|
112
|
-
|
113
|
-
* [Sven Fuchs](http://www.artweb-design.de)
|
114
|
-
* [Joshua Harvey](http://www.workingwithrails.com/person/759-joshua-harvey)
|
115
|
-
* [Stephan Soller](http://www.arkanis-development.de)
|
116
|
-
* [Saimon Moore](http://saimonmoore.net)
|
117
|
-
* [Matt Aimonetti](https://matt.aimonetti.net/)
|
109
|
+
Additional documentation can be found here: https://github.com/ruby-i18n/i18n/wiki
|
118
110
|
|
119
111
|
## Contributors
|
120
112
|
|
121
|
-
|
113
|
+
* @radar
|
114
|
+
* @carlosantoniodasilva
|
115
|
+
* @josevalim
|
116
|
+
* @knapo
|
117
|
+
* @tigrish
|
118
|
+
* [and many more](https://github.com/ruby-i18n/i18n/graphs/contributors)
|
122
119
|
|
123
120
|
## License
|
124
121
|
|
data/lib/i18n.rb
CHANGED
@@ -176,6 +176,22 @@ module I18n
|
|
176
176
|
# from the argument values passed to #translate. Therefore your lambdas should
|
177
177
|
# always return the same translations/values per unique combination of argument
|
178
178
|
# values.
|
179
|
+
#
|
180
|
+
# *Ruby 2.7+ keyword arguments warning*
|
181
|
+
#
|
182
|
+
# This method uses keyword arguments.
|
183
|
+
# There is a breaking change in ruby that produces warning with ruby 2.7 and won't work as expected with ruby 3.0
|
184
|
+
# The "hash" parameter must be passed as keyword argument.
|
185
|
+
#
|
186
|
+
# Good:
|
187
|
+
# I18n.t(:salutation, :gender => 'w', :name => 'Smith')
|
188
|
+
# I18n.t(:salutation, **{ :gender => 'w', :name => 'Smith' })
|
189
|
+
# I18n.t(:salutation, **any_hash)
|
190
|
+
#
|
191
|
+
# Bad:
|
192
|
+
# I18n.t(:salutation, { :gender => 'w', :name => 'Smith' })
|
193
|
+
# I18n.t(:salutation, any_hash)
|
194
|
+
#
|
179
195
|
def translate(key = nil, *, throw: false, raise: false, locale: nil, **options) # TODO deprecate :raise
|
180
196
|
locale ||= config.locale
|
181
197
|
raise Disabled.new('t') if locale == false
|
@@ -207,11 +223,11 @@ module I18n
|
|
207
223
|
alias :t! :translate!
|
208
224
|
|
209
225
|
# Returns true if a translation exists for a given key, otherwise returns false.
|
210
|
-
def exists?(key, _locale = nil, locale: _locale)
|
226
|
+
def exists?(key, _locale = nil, locale: _locale, **options)
|
211
227
|
locale ||= config.locale
|
212
228
|
raise Disabled.new('exists?') if locale == false
|
213
229
|
raise I18n::ArgumentError if key.is_a?(String) && key.empty?
|
214
|
-
config.backend.exists?(locale, key)
|
230
|
+
config.backend.exists?(locale, key, options)
|
215
231
|
end
|
216
232
|
|
217
233
|
# Transliterates UTF-8 characters to ASCII. By default this method will
|
@@ -373,7 +389,7 @@ module I18n
|
|
373
389
|
@@normalized_key_cache[separator][key] ||=
|
374
390
|
case key
|
375
391
|
when Array
|
376
|
-
key.
|
392
|
+
key.flat_map { |k| normalize_key(k, separator) }
|
377
393
|
else
|
378
394
|
keys = key.to_s.split(separator)
|
379
395
|
keys.delete('')
|
data/lib/i18n/backend/base.rb
CHANGED
@@ -64,7 +64,7 @@ module I18n
|
|
64
64
|
entry
|
65
65
|
end
|
66
66
|
|
67
|
-
def exists?(locale, key)
|
67
|
+
def exists?(locale, key, options = EMPTY_HASH)
|
68
68
|
lookup(locale, key) != nil
|
69
69
|
end
|
70
70
|
|
@@ -146,7 +146,7 @@ module I18n
|
|
146
146
|
I18n.translate(subject, **options.merge(:locale => locale, :throw => true))
|
147
147
|
when Proc
|
148
148
|
date_or_time = options.delete(:object) || object
|
149
|
-
resolve(locale, object, subject.call(date_or_time, options))
|
149
|
+
resolve(locale, object, subject.call(date_or_time, **options))
|
150
150
|
else
|
151
151
|
subject
|
152
152
|
end
|
@@ -163,7 +163,8 @@ module I18n
|
|
163
163
|
# not standard with regards to the CLDR pluralization rules.
|
164
164
|
# Other backends can implement more flexible or complex pluralization rules.
|
165
165
|
def pluralize(locale, entry, count)
|
166
|
-
|
166
|
+
entry = entry.reject { |k, _v| k == :attributes } if entry.is_a?(Hash)
|
167
|
+
return entry unless entry.is_a?(Hash) && count && entry.values.none? { |v| v.is_a?(Hash) }
|
167
168
|
|
168
169
|
key = pluralization_key(entry, count)
|
169
170
|
raise InvalidPluralizationData.new(entry, count, key) unless entry.has_key?(key)
|
data/lib/i18n/backend/chain.rb
CHANGED
@@ -73,9 +73,9 @@ module I18n
|
|
73
73
|
throw(:exception, I18n::MissingTranslation.new(locale, key, options))
|
74
74
|
end
|
75
75
|
|
76
|
-
def exists?(locale, key)
|
76
|
+
def exists?(locale, key, options = EMPTY_HASH)
|
77
77
|
backends.any? do |backend|
|
78
|
-
backend.exists?(locale, key)
|
78
|
+
backend.exists?(locale, key, options)
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
@@ -101,8 +101,7 @@ module I18n
|
|
101
101
|
init_translations unless initialized?
|
102
102
|
translations
|
103
103
|
end
|
104
|
-
|
105
|
-
memo.deep_merge!(partial_translations)
|
104
|
+
memo.deep_merge!(partial_translations) { |_, a, b| b || a }
|
106
105
|
end
|
107
106
|
end
|
108
107
|
|
@@ -46,7 +46,10 @@ module I18n
|
|
46
46
|
begin
|
47
47
|
catch(:exception) do
|
48
48
|
result = super(fallback, key, fallback_options)
|
49
|
-
|
49
|
+
unless result.nil?
|
50
|
+
on_fallback(locale, fallback, key, options) if locale != fallback
|
51
|
+
return result
|
52
|
+
end
|
50
53
|
end
|
51
54
|
rescue I18n::InvalidLocale
|
52
55
|
# we do nothing when the locale is invalid, as this is a fallback anyways.
|
@@ -68,7 +71,8 @@ module I18n
|
|
68
71
|
return first_non_symbol_default
|
69
72
|
end
|
70
73
|
|
71
|
-
def exists?(locale, key)
|
74
|
+
def exists?(locale, key, options = EMPTY_HASH)
|
75
|
+
return super unless options.fetch(:fallback, true)
|
72
76
|
I18n.fallbacks[locale].each do |fallback|
|
73
77
|
begin
|
74
78
|
return true if super(fallback, key)
|
@@ -79,6 +83,13 @@ module I18n
|
|
79
83
|
|
80
84
|
false
|
81
85
|
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
# Overwrite on_fallback to add specified logic when the fallback succeeds.
|
90
|
+
def on_fallback(_original_locale, _fallback_locale, _key, _optoins)
|
91
|
+
nil
|
92
|
+
end
|
82
93
|
end
|
83
94
|
end
|
84
95
|
end
|
data/lib/i18n/backend/flatten.rb
CHANGED
@@ -18,14 +18,17 @@ module I18n
|
|
18
18
|
# and creates way less objects than the one at I18n.normalize_keys.
|
19
19
|
# It also handles escaping the translation keys.
|
20
20
|
def self.normalize_flat_keys(locale, key, scope, separator)
|
21
|
-
keys = [scope, key]
|
21
|
+
keys = [scope, key]
|
22
|
+
keys.flatten!
|
23
|
+
keys.compact!
|
24
|
+
|
22
25
|
separator ||= I18n.default_separator
|
23
26
|
|
24
27
|
if separator != FLATTEN_SEPARATOR
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
28
|
+
from_str = "#{FLATTEN_SEPARATOR}#{separator}"
|
29
|
+
to_str = "#{SEPARATOR_ESCAPE_CHAR}#{FLATTEN_SEPARATOR}"
|
30
|
+
|
31
|
+
keys.map! { |k| k.to_s.tr from_str, to_str }
|
29
32
|
end
|
30
33
|
|
31
34
|
keys.join(".")
|
@@ -29,7 +29,7 @@ module I18n
|
|
29
29
|
# either pick a special :zero translation even for languages where the
|
30
30
|
# pluralizer does not return a :zero key.
|
31
31
|
def pluralize(locale, entry, count)
|
32
|
-
return entry unless entry.is_a?(Hash)
|
32
|
+
return entry unless entry.is_a?(Hash) && count
|
33
33
|
|
34
34
|
pluralizer = pluralizer(locale)
|
35
35
|
if pluralizer.respond_to?(:call)
|
data/lib/i18n/core_ext/hash.rb
CHANGED
@@ -18,12 +18,24 @@ module I18n
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
#
|
22
|
-
|
23
|
-
|
24
|
-
|
21
|
+
# deep_merge from activesupport 5
|
22
|
+
# Copyright (c) 2005-2019 David Heinemeier Hansson
|
23
|
+
def deep_merge(other_hash, &block)
|
24
|
+
dup.deep_merge!(other_hash, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
# deep_merge! from activesupport 5
|
28
|
+
# Copyright (c) 2005-2019 David Heinemeier Hansson
|
29
|
+
def deep_merge!(other_hash, &block)
|
30
|
+
merge!(other_hash) do |key, this_val, other_val|
|
31
|
+
if this_val.is_a?(Hash) && other_val.is_a?(Hash)
|
32
|
+
this_val.deep_merge(other_val, &block)
|
33
|
+
elsif block_given?
|
34
|
+
block.call(key, this_val, other_val)
|
35
|
+
else
|
36
|
+
other_val
|
37
|
+
end
|
25
38
|
end
|
26
|
-
merge!(data, &merger)
|
27
39
|
end
|
28
40
|
|
29
41
|
def symbolize_key(key)
|
@@ -60,7 +60,7 @@ module I18n
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def defaults=(defaults)
|
63
|
-
@defaults = defaults.
|
63
|
+
@defaults = defaults.flat_map { |default| compute(default, false) }
|
64
64
|
end
|
65
65
|
attr_reader :defaults
|
66
66
|
|
@@ -84,13 +84,15 @@ module I18n
|
|
84
84
|
protected
|
85
85
|
|
86
86
|
def compute(tags, include_defaults = true, exclude = [])
|
87
|
-
result = Array(tags).
|
87
|
+
result = Array(tags).flat_map do |tag|
|
88
88
|
tags = I18n::Locale::Tag.tag(tag).self_and_parents.map! { |t| t.to_sym } - exclude
|
89
89
|
tags.each { |_tag| tags += compute(@map[_tag], false, exclude + tags) if @map[_tag] }
|
90
90
|
tags
|
91
|
-
end
|
91
|
+
end
|
92
92
|
result.push(*defaults) if include_defaults
|
93
|
-
result.uniq
|
93
|
+
result.uniq!
|
94
|
+
result.compact!
|
95
|
+
result
|
94
96
|
end
|
95
97
|
end
|
96
98
|
end
|
@@ -3,18 +3,20 @@ module I18n
|
|
3
3
|
module Tag
|
4
4
|
module Parents
|
5
5
|
def parent
|
6
|
-
@parent ||=
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
@parent ||=
|
7
|
+
begin
|
8
|
+
segs = to_a
|
9
|
+
segs.compact!
|
10
|
+
segs.length > 1 ? self.class.tag(*segs[0..(segs.length - 2)].join('-')) : nil
|
11
|
+
end
|
10
12
|
end
|
11
13
|
|
12
14
|
def self_and_parents
|
13
|
-
@self_and_parents ||= [self]
|
15
|
+
@self_and_parents ||= [self].concat parents
|
14
16
|
end
|
15
17
|
|
16
18
|
def parents
|
17
|
-
@parents ||=
|
19
|
+
@parents ||= parent ? [parent].concat(parent.parents) : []
|
18
20
|
end
|
19
21
|
end
|
20
22
|
end
|
data/lib/i18n/tests/link.rb
CHANGED
@@ -26,7 +26,7 @@ module I18n
|
|
26
26
|
}
|
27
27
|
assert_equal('linked', I18n.backend.translate('en', :'foo.link'))
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
test "linked lookup: if a dot-separated key resolves to a dot-separated symbol it looks up the symbol" do
|
31
31
|
I18n.backend.store_translations 'en', {
|
32
32
|
:foo => { :link => :"bar.linked" },
|
@@ -51,6 +51,16 @@ module I18n
|
|
51
51
|
assert_equal "can't be blank", I18n.t(:"activerecord.errors.messages.blank")
|
52
52
|
assert_equal "can't be blank", I18n.t(:"activerecord.errors.messages.blank")
|
53
53
|
end
|
54
|
+
|
55
|
+
test "linked lookup: a link can resolve with option :count" do
|
56
|
+
I18n.backend.store_translations 'en', {
|
57
|
+
:counter => :counted,
|
58
|
+
:counted => { :foo => { :one => "one", :other => "other" }, :bar => "bar" }
|
59
|
+
}
|
60
|
+
assert_equal "one", I18n.t(:'counter.foo', count: 1)
|
61
|
+
assert_equal "other", I18n.t(:'counter.foo', count: 2)
|
62
|
+
assert_equal "bar", I18n.t(:'counter.bar', count: 3)
|
63
|
+
end
|
54
64
|
end
|
55
65
|
end
|
56
66
|
end
|
@@ -52,19 +52,20 @@ module I18n
|
|
52
52
|
test "localize Time: given a format that resolves to a Proc it calls the Proc with the object" do
|
53
53
|
setup_time_proc_translations
|
54
54
|
time = ::Time.utc(2008, 3, 1, 6, 0)
|
55
|
-
assert_equal I18n::Tests::Localization::Procs.inspect_args([time, {}
|
55
|
+
assert_equal I18n::Tests::Localization::Procs.inspect_args([time], {}), I18n.l(time, :format => :proc, :locale => :ru)
|
56
56
|
end
|
57
57
|
|
58
58
|
test "localize Time: given a format that resolves to a Proc it calls the Proc with the object and extra options" do
|
59
59
|
setup_time_proc_translations
|
60
60
|
time = ::Time.utc(2008, 3, 1, 6, 0)
|
61
61
|
options = { :foo => 'foo' }
|
62
|
-
assert_equal I18n::Tests::Localization::Procs.inspect_args([time, options
|
62
|
+
assert_equal I18n::Tests::Localization::Procs.inspect_args([time], options), I18n.l(time, **options.merge(:format => :proc, :locale => :ru))
|
63
63
|
end
|
64
64
|
|
65
65
|
protected
|
66
66
|
|
67
|
-
def self.inspect_args(args)
|
67
|
+
def self.inspect_args(args, kwargs)
|
68
|
+
args << kwargs
|
68
69
|
args = args.map do |arg|
|
69
70
|
case arg
|
70
71
|
when ::Time, ::DateTime
|
@@ -85,12 +86,12 @@ module I18n
|
|
85
86
|
I18n.backend.store_translations :ru, {
|
86
87
|
:time => {
|
87
88
|
:formats => {
|
88
|
-
:proc => lambda { |*args| I18n::Tests::Localization::Procs.inspect_args(args) }
|
89
|
+
:proc => lambda { |*args, **kwargs| I18n::Tests::Localization::Procs.inspect_args(args, kwargs) }
|
89
90
|
}
|
90
91
|
},
|
91
92
|
:date => {
|
92
93
|
:formats => {
|
93
|
-
:proc => lambda { |*args| I18n::Tests::Localization::Procs.inspect_args(args) }
|
94
|
+
:proc => lambda { |*args, **kwargs| I18n::Tests::Localization::Procs.inspect_args(args, kwargs) }
|
94
95
|
},
|
95
96
|
:'day_names' => lambda { |key, options|
|
96
97
|
(options[:format] =~ /^%A/) ?
|
data/lib/i18n/tests/procs.rb
CHANGED
@@ -8,6 +8,11 @@ module I18n
|
|
8
8
|
assert_equal '[:a_lambda, {:foo=>"foo"}]', I18n.t(:a_lambda, :foo => 'foo')
|
9
9
|
end
|
10
10
|
|
11
|
+
test "lookup: given a translation is a proc it passes the interpolation values as keyword arguments" do
|
12
|
+
I18n.backend.store_translations(:en, :a_lambda => lambda { |key, foo:, **| I18n::Tests::Procs.filter_args(key, foo: foo) })
|
13
|
+
assert_equal '[:a_lambda, {:foo=>"foo"}]', I18n.t(:a_lambda, :foo => 'foo')
|
14
|
+
end
|
15
|
+
|
11
16
|
test "defaults: given a default is a Proc it calls it with the key and interpolation values" do
|
12
17
|
proc = lambda { |*args| I18n::Tests::Procs.filter_args(*args) }
|
13
18
|
assert_equal '[nil, {:foo=>"foo"}]', I18n.t(nil, :default => proc, :foo => 'foo')
|
data/lib/i18n/version.rb
CHANGED
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.
|
4
|
+
version: 1.8.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:
|
16
|
+
date: 2020-06-05 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: concurrent-ruby
|
@@ -95,11 +95,15 @@ post_install_message: |2+
|
|
95
95
|
HEADS UP! i18n 1.1 changed fallbacks to exclude default locale.
|
96
96
|
But that may break your application.
|
97
97
|
|
98
|
+
If you are upgrading your Rails application from an older version of Rails:
|
99
|
+
|
98
100
|
Please check your Rails app for 'config.i18n.fallbacks = true'.
|
99
101
|
If you're using I18n (>= 1.1.0) and Rails (< 5.2.2), this should be
|
100
102
|
'config.i18n.fallbacks = [I18n.default_locale]'.
|
101
103
|
If not, fallbacks will be broken in your app by I18n 1.1.x.
|
102
104
|
|
105
|
+
If you are starting a NEW Rails application, you can ignore this notice.
|
106
|
+
|
103
107
|
For more info see:
|
104
108
|
https://github.com/svenfuchs/i18n/releases/tag/v1.1.0
|
105
109
|
|
@@ -117,7 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
117
121
|
- !ruby/object:Gem::Version
|
118
122
|
version: 1.3.5
|
119
123
|
requirements: []
|
120
|
-
rubygems_version: 3.
|
124
|
+
rubygems_version: 3.1.2
|
121
125
|
signing_key:
|
122
126
|
specification_version: 4
|
123
127
|
summary: New wave Internationalization support for Ruby
|