i18n 1.8.11 → 1.9.1
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/lib/i18n/backend/base.rb +13 -9
- data/lib/i18n/backend/chain.rb +2 -4
- data/lib/i18n/backend/fallbacks.rb +12 -1
- data/lib/i18n/backend/gettext.rb +2 -4
- data/lib/i18n/backend/key_value.rb +4 -6
- data/lib/i18n/backend/simple.rb +2 -4
- data/lib/i18n/exceptions.rb +3 -1
- data/lib/i18n/interpolate/ruby.rb +2 -2
- data/lib/i18n/locale/fallbacks.rb +12 -14
- data/lib/i18n/tests/defaults.rb +1 -1
- data/lib/i18n/tests/interpolation.rb +7 -7
- data/lib/i18n/tests/localization/date.rb +3 -3
- data/lib/i18n/tests/localization/date_time.rb +1 -1
- data/lib/i18n/tests/localization/procs.rb +1 -0
- data/lib/i18n/tests/localization/time.rb +1 -1
- data/lib/i18n/tests/lookup.rb +2 -2
- data/lib/i18n/tests/pluralization.rb +1 -1
- data/lib/i18n/tests/procs.rb +7 -1
- data/lib/i18n/utils.rb +55 -0
- data/lib/i18n/version.rb +1 -1
- data/lib/i18n.rb +25 -11
- metadata +8 -8
- data/lib/i18n/core_ext/hash.rb +0 -59
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 73eb29528a85ee9bb80e81091573b181a768e7eca83afba1222884afbdc81928
|
4
|
+
data.tar.gz: a807e1a214d3195204fa37b7bc0ac57d7ac8125889405f943c07901b4e2b3972
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4d7d1ac263e739f2b8a66fe50f0e5947150a9401e5e9a8d74a41d4f1ea0ac49b814a1474ab3b1e0e2c37f2e37692c76ab010cf962486709584580fc9ae72f15a
|
7
|
+
data.tar.gz: 3a87c0bb4b17b09af88afb9b8223df8f75251b9c073073200ed69ab343f8962ef230b63f93ad214243d1262c014ca6f735b1ef25f7c605c02249d66060fb3640
|
data/lib/i18n/backend/base.rb
CHANGED
@@ -2,12 +2,10 @@
|
|
2
2
|
|
3
3
|
require 'yaml'
|
4
4
|
require 'json'
|
5
|
-
require 'i18n/core_ext/hash'
|
6
5
|
|
7
6
|
module I18n
|
8
7
|
module Backend
|
9
8
|
module Base
|
10
|
-
using I18n::HashRefinements
|
11
9
|
include I18n::Backend::Transliterator
|
12
10
|
|
13
11
|
# Accepts a list of paths to translation files. Loads translations from
|
@@ -53,7 +51,7 @@ module I18n
|
|
53
51
|
end
|
54
52
|
|
55
53
|
deep_interpolation = options[:deep_interpolation]
|
56
|
-
values =
|
54
|
+
values = Utils.except(options, *RESERVED_KEYS)
|
57
55
|
if values
|
58
56
|
entry = if deep_interpolation
|
59
57
|
deep_interpolate(locale, entry, values)
|
@@ -223,17 +221,18 @@ module I18n
|
|
223
221
|
def load_file(filename)
|
224
222
|
type = File.extname(filename).tr('.', '').downcase
|
225
223
|
raise UnknownFileType.new(type, filename) unless respond_to?(:"load_#{type}", true)
|
226
|
-
data = send(:"load_#{type}", filename)
|
224
|
+
data, keys_symbolized = send(:"load_#{type}", filename)
|
227
225
|
unless data.is_a?(Hash)
|
228
226
|
raise InvalidLocaleData.new(filename, 'expects it to return a hash, but does not')
|
229
227
|
end
|
230
|
-
data.each { |locale, d| store_translations(locale, d || {}) }
|
228
|
+
data.each { |locale, d| store_translations(locale, d || {}, skip_symbolize_keys: keys_symbolized) }
|
231
229
|
end
|
232
230
|
|
233
231
|
# Loads a plain Ruby translations file. eval'ing the file must yield
|
234
232
|
# a Hash containing translation data with locales as toplevel keys.
|
235
233
|
def load_rb(filename)
|
236
|
-
eval(IO.read(filename), binding, filename)
|
234
|
+
translations = eval(IO.read(filename), binding, filename)
|
235
|
+
[translations, false]
|
237
236
|
end
|
238
237
|
|
239
238
|
# Loads a YAML translations file. The data must have locales as
|
@@ -241,9 +240,9 @@ module I18n
|
|
241
240
|
def load_yml(filename)
|
242
241
|
begin
|
243
242
|
if YAML.respond_to?(:unsafe_load_file) # Psych 4.0 way
|
244
|
-
YAML.unsafe_load_file(filename)
|
243
|
+
[YAML.unsafe_load_file(filename, symbolize_names: true, freeze: true), true]
|
245
244
|
else
|
246
|
-
YAML.load_file(filename)
|
245
|
+
[YAML.load_file(filename), false]
|
247
246
|
end
|
248
247
|
rescue TypeError, ScriptError, StandardError => e
|
249
248
|
raise InvalidLocaleData.new(filename, e.inspect)
|
@@ -255,7 +254,12 @@ module I18n
|
|
255
254
|
# toplevel keys.
|
256
255
|
def load_json(filename)
|
257
256
|
begin
|
258
|
-
|
257
|
+
# Use #load_file as a proxy for a version of JSON where symbolize_names and freeze are supported.
|
258
|
+
if ::JSON.respond_to?(:load_file)
|
259
|
+
[::JSON.load_file(filename, symbolize_names: true, freeze: true), true]
|
260
|
+
else
|
261
|
+
[::JSON.parse(File.read(filename)), false]
|
262
|
+
end
|
259
263
|
rescue TypeError, StandardError => e
|
260
264
|
raise InvalidLocaleData.new(filename, e.inspect)
|
261
265
|
end
|
data/lib/i18n/backend/chain.rb
CHANGED
@@ -17,8 +17,6 @@ module I18n
|
|
17
17
|
# The implementation assumes that all backends added to the Chain implement
|
18
18
|
# a lookup method with the same API as Simple backend does.
|
19
19
|
class Chain
|
20
|
-
using I18n::HashRefinements
|
21
|
-
|
22
20
|
module Implementation
|
23
21
|
include Base
|
24
22
|
|
@@ -55,7 +53,7 @@ module I18n
|
|
55
53
|
|
56
54
|
def translate(locale, key, default_options = EMPTY_HASH)
|
57
55
|
namespace = nil
|
58
|
-
options =
|
56
|
+
options = Utils.except(default_options, :default)
|
59
57
|
|
60
58
|
backends.each do |backend|
|
61
59
|
catch(:exception) do
|
@@ -101,7 +99,7 @@ module I18n
|
|
101
99
|
init_translations unless initialized?
|
102
100
|
translations
|
103
101
|
end
|
104
|
-
|
102
|
+
Utils.deep_merge!(memo, partial_translations) { |_, a, b| b || a }
|
105
103
|
end
|
106
104
|
end
|
107
105
|
|
@@ -43,7 +43,7 @@ module I18n
|
|
43
43
|
return super if options[:fallback_in_progress]
|
44
44
|
default = extract_non_symbol_default!(options) if options[:default]
|
45
45
|
|
46
|
-
fallback_options = options.merge(:fallback_in_progress => true)
|
46
|
+
fallback_options = options.merge(:fallback_in_progress => true, fallback_original_locale: locale)
|
47
47
|
I18n.fallbacks[locale].each do |fallback|
|
48
48
|
begin
|
49
49
|
catch(:exception) do
|
@@ -64,6 +64,17 @@ module I18n
|
|
64
64
|
throw(:exception, I18n::MissingTranslation.new(locale, key, options))
|
65
65
|
end
|
66
66
|
|
67
|
+
def resolve(locale, object, subject, options = EMPTY_HASH)
|
68
|
+
return subject if options[:resolve] == false
|
69
|
+
return super unless subject.is_a?(Symbol)
|
70
|
+
|
71
|
+
result = catch(:exception) do
|
72
|
+
options.delete(:fallback_in_progress)
|
73
|
+
I18n.translate(subject, **options.merge(locale: options[:fallback_original_locale], throw: true))
|
74
|
+
end
|
75
|
+
result unless result.is_a?(MissingTranslation)
|
76
|
+
end
|
77
|
+
|
67
78
|
def extract_non_symbol_default!(options)
|
68
79
|
defaults = [options[:default]].flatten
|
69
80
|
first_non_symbol_default = defaults.detect{|default| !default.is_a?(Symbol)}
|
data/lib/i18n/backend/gettext.rb
CHANGED
@@ -31,8 +31,6 @@ module I18n
|
|
31
31
|
# Without it strings containing periods (".") will not be translated.
|
32
32
|
|
33
33
|
module Gettext
|
34
|
-
using I18n::HashRefinements
|
35
|
-
|
36
34
|
class PoData < Hash
|
37
35
|
def set_comment(msgid_or_sym, comment)
|
38
36
|
# ignore
|
@@ -43,7 +41,7 @@ module I18n
|
|
43
41
|
def load_po(filename)
|
44
42
|
locale = ::File.basename(filename, '.po').to_sym
|
45
43
|
data = normalize(locale, parse(filename))
|
46
|
-
{ locale => data }
|
44
|
+
[{ locale => data }, false]
|
47
45
|
end
|
48
46
|
|
49
47
|
def parse(filename)
|
@@ -61,7 +59,7 @@ module I18n
|
|
61
59
|
{ part => _normalized.empty? ? value : _normalized }
|
62
60
|
end
|
63
61
|
|
64
|
-
|
62
|
+
Utils.deep_merge!(result, normalized)
|
65
63
|
end
|
66
64
|
result
|
67
65
|
end
|
@@ -67,8 +67,6 @@ module I18n
|
|
67
67
|
#
|
68
68
|
# This is useful if you are using a KeyValue backend chained to a Simple backend.
|
69
69
|
class KeyValue
|
70
|
-
using I18n::HashRefinements
|
71
|
-
|
72
70
|
module Implementation
|
73
71
|
attr_accessor :store
|
74
72
|
|
@@ -91,7 +89,7 @@ module I18n
|
|
91
89
|
when Hash
|
92
90
|
if @subtrees && (old_value = @store[key])
|
93
91
|
old_value = JSON.decode(old_value)
|
94
|
-
value =
|
92
|
+
value = Utils.deep_merge!(Utils.deep_symbolize_keys(old_value), value) if old_value.is_a?(Hash)
|
95
93
|
end
|
96
94
|
when Proc
|
97
95
|
raise "Key-value stores cannot handle procs"
|
@@ -115,12 +113,12 @@ module I18n
|
|
115
113
|
# them into a hash such as the one returned from loading the
|
116
114
|
# haml files
|
117
115
|
def translations
|
118
|
-
@translations = @store.keys.clone.map do |main_key|
|
116
|
+
@translations = Utils.deep_symbolize_keys(@store.keys.clone.map do |main_key|
|
119
117
|
main_value = JSON.decode(@store[main_key])
|
120
118
|
main_key.to_s.split(".").reverse.inject(main_value) do |value, key|
|
121
119
|
{key.to_sym => value}
|
122
120
|
end
|
123
|
-
end.inject{|hash, elem|
|
121
|
+
end.inject{|hash, elem| Utils.deep_merge!(hash, elem)})
|
124
122
|
end
|
125
123
|
|
126
124
|
def init_translations
|
@@ -141,7 +139,7 @@ module I18n
|
|
141
139
|
value = JSON.decode(value) if value
|
142
140
|
|
143
141
|
if value.is_a?(Hash)
|
144
|
-
|
142
|
+
Utils.deep_symbolize_keys(value)
|
145
143
|
elsif !value.nil?
|
146
144
|
value
|
147
145
|
elsif !@subtrees
|
data/lib/i18n/backend/simple.rb
CHANGED
@@ -19,8 +19,6 @@ module I18n
|
|
19
19
|
#
|
20
20
|
# I18n::Backend::Simple.include(I18n::Backend::Pluralization)
|
21
21
|
class Simple
|
22
|
-
using I18n::HashRefinements
|
23
|
-
|
24
22
|
module Implementation
|
25
23
|
include Base
|
26
24
|
|
@@ -40,8 +38,8 @@ module I18n
|
|
40
38
|
end
|
41
39
|
locale = locale.to_sym
|
42
40
|
translations[locale] ||= Concurrent::Hash.new
|
43
|
-
data = data.
|
44
|
-
translations[locale]
|
41
|
+
data = Utils.deep_symbolize_keys(data) unless options.fetch(:skip_symbolize_keys, false)
|
42
|
+
Utils.deep_merge!(translations[locale], data)
|
45
43
|
end
|
46
44
|
|
47
45
|
# Get available locales from the translations hash
|
data/lib/i18n/exceptions.rb
CHANGED
@@ -47,10 +47,12 @@ module I18n
|
|
47
47
|
|
48
48
|
class MissingTranslation < ArgumentError
|
49
49
|
module Base
|
50
|
+
PERMITTED_KEYS = [:scope].freeze
|
51
|
+
|
50
52
|
attr_reader :locale, :key, :options
|
51
53
|
|
52
54
|
def initialize(locale, key, options = EMPTY_HASH)
|
53
|
-
@key, @locale, @options = key, locale, options.
|
55
|
+
@key, @locale, @options = key, locale, options.slice(*PERMITTED_KEYS)
|
54
56
|
options.each { |k, v| self.options[k] = v.inspect if v.is_a?(Proc) }
|
55
57
|
end
|
56
58
|
|
@@ -5,7 +5,7 @@ module I18n
|
|
5
5
|
DEFAULT_INTERPOLATION_PATTERNS = [
|
6
6
|
/%%/,
|
7
7
|
/%\{([\w|]+)\}/, # matches placeholders like "%{foo} or %{foo|word}"
|
8
|
-
/%<(\w+)>(
|
8
|
+
/%<(\w+)>([^\d]*?\d*\.?\d*[bBdiouxXeEfgGcps])/ # matches placeholders like "%<foo>.d"
|
9
9
|
].freeze
|
10
10
|
INTERPOLATION_PATTERN = Regexp.union(DEFAULT_INTERPOLATION_PATTERNS)
|
11
11
|
deprecate_constant :INTERPOLATION_PATTERN
|
@@ -14,7 +14,7 @@ module I18n
|
|
14
14
|
# Return String or raises MissingInterpolationArgument exception.
|
15
15
|
# Missing argument's logic is handled by I18n.config.missing_interpolation_argument_handler.
|
16
16
|
def interpolate(string, values)
|
17
|
-
raise ReservedInterpolationKey.new($1.to_sym, string) if string =~
|
17
|
+
raise ReservedInterpolationKey.new($1.to_sym, string) if string =~ I18n.reserved_keys_pattern
|
18
18
|
raise ArgumentError.new('Interpolation values must be a Hash.') unless values.kind_of?(Hash)
|
19
19
|
interpolate_hash(string, values)
|
20
20
|
end
|
@@ -15,19 +15,12 @@
|
|
15
15
|
# * all parent locales of a given locale (e.g. :es for :"es-MX") first,
|
16
16
|
# * the current default locales and all of their parents second
|
17
17
|
#
|
18
|
-
# The default locales are set to [
|
19
|
-
# set to something else.
|
18
|
+
# The default locales are set to [] by default but can be set to something else.
|
20
19
|
#
|
21
20
|
# One can additionally add any number of additional fallback locales manually.
|
22
21
|
# These will be added before the default locales to the fallback chain. For
|
23
22
|
# example:
|
24
23
|
#
|
25
|
-
# # using the default locale as default fallback locale
|
26
|
-
#
|
27
|
-
# I18n.default_locale = :"en-US"
|
28
|
-
# I18n.fallbacks = I18n::Locale::Fallbacks.new(:"de-AT" => :"de-DE")
|
29
|
-
# I18n.fallbacks[:"de-AT"] # => [:"de-AT", :de, :"de-DE"]
|
30
|
-
#
|
31
24
|
# # using a custom locale as default fallback locale
|
32
25
|
#
|
33
26
|
# I18n.fallbacks = I18n::Locale::Fallbacks.new(:"en-GB", :"de-AT" => :de, :"de-CH" => :de)
|
@@ -71,13 +64,18 @@ module I18n
|
|
71
64
|
super || store(locale, compute(locale))
|
72
65
|
end
|
73
66
|
|
74
|
-
def map(
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
67
|
+
def map(*args, &block)
|
68
|
+
if args.count == 1 && !block_given?
|
69
|
+
mappings = args.first
|
70
|
+
mappings.each do |from, to|
|
71
|
+
from, to = from.to_sym, Array(to)
|
72
|
+
to.each do |_to|
|
73
|
+
@map[from] ||= []
|
74
|
+
@map[from] << _to.to_sym
|
75
|
+
end
|
80
76
|
end
|
77
|
+
else
|
78
|
+
@map.map(*args, &block)
|
81
79
|
end
|
82
80
|
end
|
83
81
|
|
data/lib/i18n/tests/defaults.rb
CHANGED
@@ -37,7 +37,7 @@ module I18n
|
|
37
37
|
end
|
38
38
|
|
39
39
|
test "defaults: given an array of missing keys it raises a MissingTranslationData exception" do
|
40
|
-
|
40
|
+
assert_raises I18n::MissingTranslationData do
|
41
41
|
I18n.t(:does_not_exist, :default => [:does_not_exist_2, :does_not_exist_3], :raise => true)
|
42
42
|
end
|
43
43
|
end
|
@@ -41,7 +41,7 @@ module I18n
|
|
41
41
|
end
|
42
42
|
|
43
43
|
test "interpolation: given values but missing a key it raises I18n::MissingInterpolationArgument" do
|
44
|
-
|
44
|
+
assert_raises(I18n::MissingInterpolationArgument) do
|
45
45
|
interpolate(:default => '%{foo}', :bar => 'bar')
|
46
46
|
end
|
47
47
|
end
|
@@ -77,13 +77,13 @@ module I18n
|
|
77
77
|
|
78
78
|
if Object.const_defined?(:Encoding)
|
79
79
|
test "interpolation: given a euc-jp translation and a utf-8 value it raises Encoding::CompatibilityError" do
|
80
|
-
|
80
|
+
assert_raises(Encoding::CompatibilityError) do
|
81
81
|
interpolate(:default => euc_jp('こんにちは、%{name}さん!'), :name => 'ゆきひろ')
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
85
85
|
test "interpolation: given a utf-8 translation and a euc-jp value it raises Encoding::CompatibilityError" do
|
86
|
-
|
86
|
+
assert_raises(Encoding::CompatibilityError) do
|
87
87
|
interpolate(:default => 'こんにちは、%{name}さん!', :name => euc_jp('ゆきひろ'))
|
88
88
|
end
|
89
89
|
end
|
@@ -108,10 +108,10 @@ module I18n
|
|
108
108
|
end
|
109
109
|
|
110
110
|
test "interpolation: given a translations containing a reserved key it raises I18n::ReservedInterpolationKey" do
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
111
|
+
assert_raises(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{exception_handler}') }
|
112
|
+
assert_raises(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{default}') }
|
113
|
+
assert_raises(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{separator}') }
|
114
|
+
assert_raises(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{scope}') }
|
115
115
|
end
|
116
116
|
|
117
117
|
test "interpolation: deep interpolation for default string" do
|
@@ -78,15 +78,15 @@ module I18n
|
|
78
78
|
end
|
79
79
|
|
80
80
|
test "localize Date: given nil it raises I18n::ArgumentError" do
|
81
|
-
|
81
|
+
assert_raises(I18n::ArgumentError) { I18n.l(nil) }
|
82
82
|
end
|
83
83
|
|
84
84
|
test "localize Date: given a plain Object it raises I18n::ArgumentError" do
|
85
|
-
|
85
|
+
assert_raises(I18n::ArgumentError) { I18n.l(Object.new) }
|
86
86
|
end
|
87
87
|
|
88
88
|
test "localize Date: given a format is missing it raises I18n::MissingTranslationData" do
|
89
|
-
|
89
|
+
assert_raises(I18n::MissingTranslationData) { I18n.l(@date, :format => :missing) }
|
90
90
|
end
|
91
91
|
|
92
92
|
test "localize Date: it does not alter the format string" do
|
@@ -78,7 +78,7 @@ module I18n
|
|
78
78
|
end
|
79
79
|
|
80
80
|
test "localize DateTime: given a format is missing it raises I18n::MissingTranslationData" do
|
81
|
-
|
81
|
+
assert_raises(I18n::MissingTranslationData) { I18n.l(@datetime, :format => :missing) }
|
82
82
|
end
|
83
83
|
|
84
84
|
protected
|
@@ -79,7 +79,7 @@ module I18n
|
|
79
79
|
end
|
80
80
|
|
81
81
|
test "localize Time: given a format is missing it raises I18n::MissingTranslationData" do
|
82
|
-
|
82
|
+
assert_raises(I18n::MissingTranslationData) { I18n.l(@time, :format => :missing) }
|
83
83
|
end
|
84
84
|
|
85
85
|
protected
|
data/lib/i18n/tests/lookup.rb
CHANGED
@@ -34,7 +34,7 @@ module I18n
|
|
34
34
|
end
|
35
35
|
|
36
36
|
test "lookup: given a missing key, no default and the raise option it raises MissingTranslationData" do
|
37
|
-
|
37
|
+
assert_raises(I18n::MissingTranslationData) { I18n.t(:missing, :raise => true) }
|
38
38
|
end
|
39
39
|
|
40
40
|
test "lookup: does not raise an exception if no translation data is present for the given locale" do
|
@@ -61,7 +61,7 @@ module I18n
|
|
61
61
|
# In fact it probably *should* fail but Rails currently relies on using the default locale instead.
|
62
62
|
# So we'll stick to this for now until we get it fixed in Rails.
|
63
63
|
test "lookup: given nil as a locale it does not raise but use the default locale" do
|
64
|
-
#
|
64
|
+
# assert_raises(I18n::InvalidLocale) { I18n.t(:bar, :locale => nil) }
|
65
65
|
assert_nothing_raised { I18n.t(:bar, :locale => nil) }
|
66
66
|
end
|
67
67
|
|
@@ -28,7 +28,7 @@ module I18n
|
|
28
28
|
end
|
29
29
|
|
30
30
|
test "pluralization: given incomplete pluralization data it raises I18n::InvalidPluralizationData" do
|
31
|
-
|
31
|
+
assert_raises(I18n::InvalidPluralizationData) { I18n.t(:default => { :one => 'bar' }, :count => 2) }
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
data/lib/i18n/tests/procs.rb
CHANGED
@@ -53,7 +53,13 @@ module I18n
|
|
53
53
|
|
54
54
|
|
55
55
|
def self.filter_args(*args)
|
56
|
-
args.map
|
56
|
+
args.map do |arg|
|
57
|
+
if arg.is_a?(Hash)
|
58
|
+
arg.delete(:fallback_in_progress)
|
59
|
+
arg.delete(:fallback_original_locale)
|
60
|
+
end
|
61
|
+
arg
|
62
|
+
end.inspect
|
57
63
|
end
|
58
64
|
end
|
59
65
|
end
|
data/lib/i18n/utils.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module I18n
|
4
|
+
module Utils
|
5
|
+
class << self
|
6
|
+
if Hash.method_defined?(:except)
|
7
|
+
def except(hash, *keys)
|
8
|
+
hash.except(*keys)
|
9
|
+
end
|
10
|
+
else
|
11
|
+
def except(hash, *keys)
|
12
|
+
hash = hash.dup
|
13
|
+
keys.each { |k| hash.delete(k) }
|
14
|
+
hash
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def deep_merge(hash, other_hash, &block)
|
19
|
+
deep_merge!(hash.dup, other_hash, &block)
|
20
|
+
end
|
21
|
+
|
22
|
+
def deep_merge!(hash, other_hash, &block)
|
23
|
+
hash.merge!(other_hash) do |key, this_val, other_val|
|
24
|
+
if this_val.is_a?(Hash) && other_val.is_a?(Hash)
|
25
|
+
deep_merge(this_val, other_val, &block)
|
26
|
+
elsif block_given?
|
27
|
+
yield key, this_val, other_val
|
28
|
+
else
|
29
|
+
other_val
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def deep_symbolize_keys(hash)
|
35
|
+
hash.each_with_object({}) do |(key, value), result|
|
36
|
+
result[key.respond_to?(:to_sym) ? key.to_sym : key] = deep_symbolize_keys_in_object(value)
|
37
|
+
result
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def deep_symbolize_keys_in_object(value)
|
44
|
+
case value
|
45
|
+
when Hash
|
46
|
+
deep_symbolize_keys(value)
|
47
|
+
when Array
|
48
|
+
value.map { |e| deep_symbolize_keys_in_object(e) }
|
49
|
+
else
|
50
|
+
value
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/i18n/version.rb
CHANGED
data/lib/i18n.rb
CHANGED
@@ -4,6 +4,7 @@ require 'concurrent/map'
|
|
4
4
|
require 'concurrent/hash'
|
5
5
|
|
6
6
|
require 'i18n/version'
|
7
|
+
require 'i18n/utils'
|
7
8
|
require 'i18n/exceptions'
|
8
9
|
require 'i18n/interpolate/ruby'
|
9
10
|
|
@@ -22,6 +23,7 @@ module I18n
|
|
22
23
|
exception_handler
|
23
24
|
fallback
|
24
25
|
fallback_in_progress
|
26
|
+
fallback_original_locale
|
25
27
|
format
|
26
28
|
object
|
27
29
|
raise
|
@@ -29,14 +31,26 @@ module I18n
|
|
29
31
|
scope
|
30
32
|
separator
|
31
33
|
throw
|
32
|
-
]
|
33
|
-
RESERVED_KEYS_PATTERN = /%\{(#{RESERVED_KEYS.join("|")})\}/
|
34
|
+
]
|
34
35
|
EMPTY_HASH = {}.freeze
|
35
36
|
|
36
37
|
def self.new_double_nested_cache # :nodoc:
|
37
38
|
Concurrent::Map.new { |h, k| h[k] = Concurrent::Map.new }
|
38
39
|
end
|
39
40
|
|
41
|
+
# Marks a key as reserved. Reserved keys are used internally,
|
42
|
+
# and can't also be used for interpolation. If you are using any
|
43
|
+
# extra keys as I18n options, you should call I18n.reserve_key
|
44
|
+
# before any I18n.translate (etc) calls are made.
|
45
|
+
def self.reserve_key(key)
|
46
|
+
RESERVED_KEYS << key.to_sym
|
47
|
+
@reserved_keys_pattern = nil
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.reserved_keys_pattern # :nodoc:
|
51
|
+
@reserved_keys_pattern ||= /%\{(#{RESERVED_KEYS.join("|")})\}/
|
52
|
+
end
|
53
|
+
|
40
54
|
module Base
|
41
55
|
# Gets I18n configuration object.
|
42
56
|
def config
|
@@ -260,14 +274,14 @@ module I18n
|
|
260
274
|
#
|
261
275
|
# Setting a Hash using Ruby:
|
262
276
|
#
|
263
|
-
# store_translations(:de, :
|
264
|
-
#
|
265
|
-
#
|
266
|
-
#
|
267
|
-
#
|
268
|
-
#
|
269
|
-
#
|
270
|
-
#
|
277
|
+
# store_translations(:de, i18n: {
|
278
|
+
# transliterate: {
|
279
|
+
# rule: {
|
280
|
+
# 'ü' => 'ue',
|
281
|
+
# 'ö' => 'oe'
|
282
|
+
# }
|
283
|
+
# }
|
284
|
+
# })
|
271
285
|
#
|
272
286
|
# Setting a Proc:
|
273
287
|
#
|
@@ -396,7 +410,7 @@ module I18n
|
|
396
410
|
keys.delete('')
|
397
411
|
keys.map! do |k|
|
398
412
|
case k
|
399
|
-
when /\A[-+]?[1-9]\d
|
413
|
+
when /\A[-+]?([1-9]\d*|0)\z/ # integer
|
400
414
|
k.to_i
|
401
415
|
when 'true'
|
402
416
|
true
|
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.9.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sven Fuchs
|
@@ -10,18 +10,18 @@ authors:
|
|
10
10
|
- Stephan Soller
|
11
11
|
- Saimon Moore
|
12
12
|
- Ryan Bigg
|
13
|
-
autorequire:
|
13
|
+
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
|
-
date:
|
16
|
+
date: 2022-01-27 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
|
+
name: concurrent-ruby
|
19
20
|
requirement: !ruby/object:Gem::Requirement
|
20
21
|
requirements:
|
21
22
|
- - "~>"
|
22
23
|
- !ruby/object:Gem::Version
|
23
24
|
version: '1.0'
|
24
|
-
name: concurrent-ruby
|
25
25
|
type: :runtime
|
26
26
|
prerelease: false
|
27
27
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -55,7 +55,6 @@ files:
|
|
55
55
|
- lib/i18n/backend/simple.rb
|
56
56
|
- lib/i18n/backend/transliterator.rb
|
57
57
|
- lib/i18n/config.rb
|
58
|
-
- lib/i18n/core_ext/hash.rb
|
59
58
|
- lib/i18n/exceptions.rb
|
60
59
|
- lib/i18n/gettext.rb
|
61
60
|
- lib/i18n/gettext/helpers.rb
|
@@ -81,6 +80,7 @@ files:
|
|
81
80
|
- lib/i18n/tests/lookup.rb
|
82
81
|
- lib/i18n/tests/pluralization.rb
|
83
82
|
- lib/i18n/tests/procs.rb
|
83
|
+
- lib/i18n/utils.rb
|
84
84
|
- lib/i18n/version.rb
|
85
85
|
homepage: https://github.com/ruby-i18n/i18n
|
86
86
|
licenses:
|
@@ -90,7 +90,7 @@ metadata:
|
|
90
90
|
changelog_uri: https://github.com/ruby-i18n/i18n/releases
|
91
91
|
documentation_uri: https://guides.rubyonrails.org/i18n.html
|
92
92
|
source_code_uri: https://github.com/ruby-i18n/i18n
|
93
|
-
post_install_message:
|
93
|
+
post_install_message:
|
94
94
|
rdoc_options: []
|
95
95
|
require_paths:
|
96
96
|
- lib
|
@@ -105,8 +105,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
105
105
|
- !ruby/object:Gem::Version
|
106
106
|
version: 1.3.5
|
107
107
|
requirements: []
|
108
|
-
rubygems_version: 3.
|
109
|
-
signing_key:
|
108
|
+
rubygems_version: 3.1.6
|
109
|
+
signing_key:
|
110
110
|
specification_version: 4
|
111
111
|
summary: New wave Internationalization support for Ruby
|
112
112
|
test_files: []
|
data/lib/i18n/core_ext/hash.rb
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
module I18n
|
2
|
-
module HashRefinements
|
3
|
-
refine Hash do
|
4
|
-
using I18n::HashRefinements
|
5
|
-
def except(*keys)
|
6
|
-
dup.except!(*keys)
|
7
|
-
end unless method_defined?(:except)
|
8
|
-
|
9
|
-
def except!(*keys)
|
10
|
-
keys.each { |key| delete(key) }
|
11
|
-
self
|
12
|
-
end
|
13
|
-
|
14
|
-
def deep_symbolize_keys
|
15
|
-
each_with_object({}) do |(key, value), result|
|
16
|
-
result[symbolize_key(key)] = deep_symbolize_keys_in_object(value)
|
17
|
-
result
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
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
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def symbolize_key(key)
|
42
|
-
key.respond_to?(:to_sym) ? key.to_sym : key
|
43
|
-
end
|
44
|
-
|
45
|
-
private
|
46
|
-
|
47
|
-
def deep_symbolize_keys_in_object(value)
|
48
|
-
case value
|
49
|
-
when Hash
|
50
|
-
value.deep_symbolize_keys
|
51
|
-
when Array
|
52
|
-
value.map { |e| deep_symbolize_keys_in_object(e) }
|
53
|
-
else
|
54
|
-
value
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|