i18n 1.0.0 → 1.14.7

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.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +75 -32
  3. data/lib/i18n/backend/base.rb +93 -34
  4. data/lib/i18n/backend/cache.rb +10 -11
  5. data/lib/i18n/backend/cache_file.rb +36 -0
  6. data/lib/i18n/backend/cascade.rb +3 -1
  7. data/lib/i18n/backend/chain.rb +39 -6
  8. data/lib/i18n/backend/fallbacks.rb +48 -15
  9. data/lib/i18n/backend/flatten.rb +10 -5
  10. data/lib/i18n/backend/gettext.rb +4 -2
  11. data/lib/i18n/backend/interpolation_compiler.rb +8 -8
  12. data/lib/i18n/backend/key_value.rb +31 -4
  13. data/lib/i18n/backend/lazy_loadable.rb +184 -0
  14. data/lib/i18n/backend/memoize.rb +10 -2
  15. data/lib/i18n/backend/metadata.rb +5 -3
  16. data/lib/i18n/backend/pluralization.rb +61 -18
  17. data/lib/i18n/backend/simple.rb +44 -24
  18. data/lib/i18n/backend/transliterator.rb +26 -24
  19. data/lib/i18n/backend.rb +5 -1
  20. data/lib/i18n/config.rb +22 -4
  21. data/lib/i18n/exceptions.rb +71 -18
  22. data/lib/i18n/gettext/helpers.rb +4 -2
  23. data/lib/i18n/gettext/po_parser.rb +7 -7
  24. data/lib/i18n/gettext.rb +2 -0
  25. data/lib/i18n/interpolate/ruby.rb +22 -6
  26. data/lib/i18n/locale/fallbacks.rb +33 -22
  27. data/lib/i18n/locale/tag/parents.rb +8 -6
  28. data/lib/i18n/locale/tag/simple.rb +2 -2
  29. data/lib/i18n/locale.rb +2 -0
  30. data/lib/i18n/middleware.rb +2 -0
  31. data/lib/i18n/tests/basics.rb +5 -7
  32. data/lib/i18n/tests/defaults.rb +8 -1
  33. data/lib/i18n/tests/interpolation.rb +34 -7
  34. data/lib/i18n/tests/link.rb +11 -1
  35. data/lib/i18n/tests/localization/date.rb +37 -10
  36. data/lib/i18n/tests/localization/date_time.rb +28 -7
  37. data/lib/i18n/tests/localization/procs.rb +9 -7
  38. data/lib/i18n/tests/localization/time.rb +27 -5
  39. data/lib/i18n/tests/lookup.rb +11 -5
  40. data/lib/i18n/tests/pluralization.rb +1 -1
  41. data/lib/i18n/tests/procs.rb +23 -7
  42. data/lib/i18n/tests.rb +2 -0
  43. data/lib/i18n/utils.rb +55 -0
  44. data/lib/i18n/version.rb +3 -1
  45. data/lib/i18n.rb +179 -58
  46. metadata +16 -61
  47. data/gemfiles/Gemfile.rails-3.2.x +0 -10
  48. data/gemfiles/Gemfile.rails-4.0.x +0 -10
  49. data/gemfiles/Gemfile.rails-4.1.x +0 -10
  50. data/gemfiles/Gemfile.rails-4.2.x +0 -10
  51. data/gemfiles/Gemfile.rails-5.0.x +0 -10
  52. data/gemfiles/Gemfile.rails-5.1.x +0 -10
  53. data/gemfiles/Gemfile.rails-master +0 -10
  54. data/lib/i18n/core_ext/hash.rb +0 -29
  55. data/lib/i18n/core_ext/kernel/suppress_warnings.rb +0 -8
  56. data/lib/i18n/core_ext/string/interpolate.rb +0 -9
  57. data/test/api/all_features_test.rb +0 -58
  58. data/test/api/cascade_test.rb +0 -28
  59. data/test/api/chain_test.rb +0 -24
  60. data/test/api/fallbacks_test.rb +0 -30
  61. data/test/api/key_value_test.rb +0 -24
  62. data/test/api/memoize_test.rb +0 -56
  63. data/test/api/override_test.rb +0 -42
  64. data/test/api/pluralization_test.rb +0 -30
  65. data/test/api/simple_test.rb +0 -28
  66. data/test/backend/cache_test.rb +0 -109
  67. data/test/backend/cascade_test.rb +0 -86
  68. data/test/backend/chain_test.rb +0 -122
  69. data/test/backend/exceptions_test.rb +0 -36
  70. data/test/backend/fallbacks_test.rb +0 -219
  71. data/test/backend/interpolation_compiler_test.rb +0 -118
  72. data/test/backend/key_value_test.rb +0 -61
  73. data/test/backend/memoize_test.rb +0 -79
  74. data/test/backend/metadata_test.rb +0 -48
  75. data/test/backend/pluralization_test.rb +0 -45
  76. data/test/backend/simple_test.rb +0 -103
  77. data/test/backend/transliterator_test.rb +0 -84
  78. data/test/core_ext/hash_test.rb +0 -36
  79. data/test/gettext/api_test.rb +0 -214
  80. data/test/gettext/backend_test.rb +0 -92
  81. data/test/i18n/exceptions_test.rb +0 -117
  82. data/test/i18n/gettext_plural_keys_test.rb +0 -20
  83. data/test/i18n/interpolate_test.rb +0 -91
  84. data/test/i18n/load_path_test.rb +0 -34
  85. data/test/i18n/middleware_test.rb +0 -24
  86. data/test/i18n_test.rb +0 -462
  87. data/test/locale/fallbacks_test.rb +0 -133
  88. data/test/locale/tag/rfc4646_test.rb +0 -143
  89. data/test/locale/tag/simple_test.rb +0 -32
  90. data/test/run_all.rb +0 -20
  91. data/test/test_data/locales/de.po +0 -82
  92. data/test/test_data/locales/en.rb +0 -3
  93. data/test/test_data/locales/en.yml +0 -3
  94. data/test/test_data/locales/invalid/empty.yml +0 -0
  95. data/test/test_data/locales/invalid/syntax.yml +0 -4
  96. data/test/test_data/locales/plurals.rb +0 -113
  97. data/test/test_helper.rb +0 -61
@@ -3,18 +3,20 @@ module I18n
3
3
  module Tag
4
4
  module Parents
5
5
  def parent
6
- @parent ||= begin
7
- segs = to_a.compact
8
- segs.length > 1 ? self.class.tag(*segs[0..(segs.length-2)].join('-')) : nil
9
- end
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] + parents
15
+ @self_and_parents ||= [self].concat parents
14
16
  end
15
17
 
16
18
  def parents
17
- @parents ||= ([parent] + (parent ? parent.parents : [])).compact
19
+ @parents ||= parent ? [parent].concat(parent.parents) : []
18
20
  end
19
21
  end
20
22
  end
@@ -1,5 +1,5 @@
1
1
  # Simple Locale tag implementation that computes subtags by simply splitting
2
- # the locale tag at '-' occurences.
2
+ # the locale tag at '-' occurrences.
3
3
  module I18n
4
4
  module Locale
5
5
  module Tag
@@ -19,7 +19,7 @@ module I18n
19
19
  end
20
20
 
21
21
  def subtags
22
- @subtags = tag.to_s.split('-').map { |subtag| subtag.to_s }
22
+ @subtags = tag.to_s.split('-').map!(&:to_s)
23
23
  end
24
24
 
25
25
  def to_sym
data/lib/i18n/locale.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module I18n
2
4
  module Locale
3
5
  autoload :Fallbacks, 'i18n/locale/fallbacks'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module I18n
2
4
  class Middleware
3
5
 
@@ -5,12 +5,11 @@ module I18n
5
5
  I18n.available_locales = nil
6
6
  end
7
7
 
8
- test "available_locales returns the locales stored to the backend by default" do
8
+ test "available_locales returns the available_locales produced by the backend, by default" do
9
9
  I18n.backend.store_translations('de', :foo => 'bar')
10
10
  I18n.backend.store_translations('en', :foo => 'foo')
11
11
 
12
- assert I18n.available_locales.include?(:de)
13
- assert I18n.available_locales.include?(:en)
12
+ assert_equal I18n.available_locales, I18n.backend.available_locales
14
13
  end
15
14
 
16
15
  test "available_locales can be set to something else independently from the actual locale data" do
@@ -24,11 +23,10 @@ module I18n
24
23
  assert_equal [:foo, :bar], I18n.available_locales
25
24
 
26
25
  I18n.available_locales = nil
27
- assert I18n.available_locales.include?(:de)
28
- assert I18n.available_locales.include?(:en)
26
+ assert_equal I18n.available_locales, I18n.backend.available_locales
29
27
  end
30
28
 
31
- test "available_locales memoizes when set explicitely" do
29
+ test "available_locales memoizes when set explicitly" do
32
30
  I18n.backend.expects(:available_locales).never
33
31
  I18n.available_locales = [:foo]
34
32
  I18n.backend.store_translations('de', :bar => 'baz')
@@ -36,7 +34,7 @@ module I18n
36
34
  assert_equal [:foo], I18n.available_locales
37
35
  end
38
36
 
39
- test "available_locales delegates to the backend when not set explicitely" do
37
+ test "available_locales delegates to the backend when not set explicitly" do
40
38
  original_available_locales_value = I18n.backend.available_locales
41
39
  I18n.backend.expects(:available_locales).returns(original_available_locales_value).twice
42
40
  assert_equal I18n.backend.available_locales, I18n.available_locales
@@ -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
- assert_raise I18n::MissingTranslationData do
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
@@ -47,6 +47,13 @@ module I18n
47
47
  I18n.backend.store_translations(:en, { :foo => { :bar => 'bar' } }, { :separator => '|' })
48
48
  assert_equal 'bar', I18n.t(nil, :default => :'foo|bar', :separator => '|')
49
49
  end
50
+
51
+ # Addresses issue: #599
52
+ test "defaults: only interpolates once when resolving defaults" do
53
+ I18n.backend.store_translations(:en, :greeting => 'hey %{name}')
54
+ assert_equal 'hey %{dont_interpolate_me}',
55
+ I18n.t(:does_not_exist, :name => '%{dont_interpolate_me}', default: [:greeting])
56
+ end
50
57
  end
51
58
  end
52
59
  end
@@ -24,6 +24,10 @@ module I18n
24
24
  assert_equal 'Hi David!', interpolate(:default => 'Hi %{name}!', :name => 'David')
25
25
  end
26
26
 
27
+ test "interpolation: works with a pipe" do
28
+ assert_equal 'Hi david!', interpolate(:default => 'Hi %{name|lowercase}!', :'name|lowercase' => 'david')
29
+ end
30
+
27
31
  test "interpolation: given a nil value it still interpolates it into the string" do
28
32
  assert_equal 'Hi !', interpolate(:default => 'Hi %{name}!', :name => nil)
29
33
  end
@@ -37,13 +41,13 @@ module I18n
37
41
  end
38
42
 
39
43
  test "interpolation: given values but missing a key it raises I18n::MissingInterpolationArgument" do
40
- assert_raise(I18n::MissingInterpolationArgument) do
44
+ assert_raises(I18n::MissingInterpolationArgument) do
41
45
  interpolate(:default => '%{foo}', :bar => 'bar')
42
46
  end
43
47
  end
44
48
 
45
49
  test "interpolation: it does not raise I18n::MissingInterpolationArgument for escaped variables" do
46
- assert_nothing_raised(I18n::MissingInterpolationArgument) do
50
+ assert_nothing_raised do
47
51
  assert_equal 'Barr %{foo}', interpolate(:default => '%{bar} %%{foo}', :bar => 'Barr')
48
52
  end
49
53
  end
@@ -73,13 +77,13 @@ module I18n
73
77
 
74
78
  if Object.const_defined?(:Encoding)
75
79
  test "interpolation: given a euc-jp translation and a utf-8 value it raises Encoding::CompatibilityError" do
76
- assert_raise(Encoding::CompatibilityError) do
80
+ assert_raises(Encoding::CompatibilityError) do
77
81
  interpolate(:default => euc_jp('こんにちは、%{name}さん!'), :name => 'ゆきひろ')
78
82
  end
79
83
  end
80
84
 
81
85
  test "interpolation: given a utf-8 translation and a euc-jp value it raises Encoding::CompatibilityError" do
82
- assert_raise(Encoding::CompatibilityError) do
86
+ assert_raises(Encoding::CompatibilityError) do
83
87
  interpolate(:default => 'こんにちは、%{name}さん!', :name => euc_jp('ゆきひろ'))
84
88
  end
85
89
  end
@@ -104,9 +108,32 @@ module I18n
104
108
  end
105
109
 
106
110
  test "interpolation: given a translations containing a reserved key it raises I18n::ReservedInterpolationKey" do
107
- assert_raise(I18n::ReservedInterpolationKey) { interpolate(:default => '%{default}', :foo => :bar) }
108
- assert_raise(I18n::ReservedInterpolationKey) { interpolate(:default => '%{scope}', :foo => :bar) }
109
- assert_raise(I18n::ReservedInterpolationKey) { interpolate(:default => '%{separator}', :foo => :bar) }
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
+ 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
110
137
  end
111
138
 
112
139
  test "interpolation: deep interpolation for default string" do
@@ -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
@@ -11,8 +11,7 @@ module I18n
11
11
  end
12
12
 
13
13
  test "localize Date: given the short format it uses it" do
14
- # TODO should be Mrz, shouldn't it?
15
- assert_equal '01. Mar', I18n.l(@date, :format => :short, :locale => :de)
14
+ assert_equal '01. Mär', I18n.l(@date, :format => :short, :locale => :de)
16
15
  end
17
16
 
18
17
  test "localize Date: given the long format it uses it" do
@@ -27,17 +26,45 @@ module I18n
27
26
  assert_equal 'Samstag', I18n.l(@date, :format => '%A', :locale => :de)
28
27
  end
29
28
 
29
+ test "localize Date: given a uppercased day name format it returns the correct day name in upcase" do
30
+ assert_equal 'samstag'.upcase, I18n.l(@date, :format => '%^A', :locale => :de)
31
+ end
32
+
30
33
  test "localize Date: given an abbreviated day name format it returns the correct abbreviated day name" do
31
34
  assert_equal 'Sa', I18n.l(@date, :format => '%a', :locale => :de)
32
35
  end
33
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
+
42
+ test "localize Date: given an abbreviated and uppercased day name format it returns the correct abbreviated day name in upcase" do
43
+ assert_equal 'sa'.upcase, I18n.l(@date, :format => '%^a', :locale => :de)
44
+ end
45
+
34
46
  test "localize Date: given a month name format it returns the correct month name" do
35
47
  assert_equal 'März', I18n.l(@date, :format => '%B', :locale => :de)
36
48
  end
37
49
 
50
+ test "localize Date: given a uppercased month name format it returns the correct month name in upcase" do
51
+ assert_equal 'märz'.upcase, I18n.l(@date, :format => '%^B', :locale => :de)
52
+ end
53
+
38
54
  test "localize Date: given an abbreviated month name format it returns the correct abbreviated month name" do
39
- # TODO should be Mrz, shouldn't it?
40
- assert_equal 'Mar', I18n.l(@date, :format => '%b', :locale => :de)
55
+ assert_equal 'Mär', I18n.l(@date, :format => '%b', :locale => :de)
56
+ end
57
+
58
+ test "localize Date: given an abbreviated and uppercased month name format it returns the correct abbreviated month name in upcase" do
59
+ assert_equal 'mär'.upcase, I18n.l(@date, :format => '%^b', :locale => :de)
60
+ end
61
+
62
+ test "localize Date: given a date format with the month name upcased it returns the correct value" do
63
+ assert_equal '1. FEBRUAR 2008', I18n.l(::Date.new(2008, 2, 1), :format => "%-d. %^B %Y", :locale => :de)
64
+ end
65
+
66
+ test "localize Date: given missing translations it returns the correct error message" do
67
+ assert_equal 'Translation missing: fr.date.abbr_month_names', I18n.l(@date, :format => '%b', :locale => :fr)
41
68
  end
42
69
 
43
70
  test "localize Date: given an unknown format it does not fail" do
@@ -46,9 +73,9 @@ module I18n
46
73
 
47
74
  test "localize Date: does not modify the options hash" do
48
75
  options = { :format => '%b', :locale => :de }
49
- assert_equal 'Mar', I18n.l(@date, options)
76
+ assert_equal 'Mär', I18n.l(@date, **options)
50
77
  assert_equal({ :format => '%b', :locale => :de }, options)
51
- assert_nothing_raised { I18n.l(@date, options.freeze) }
78
+ assert_nothing_raised { I18n.l(@date, **options.freeze) }
52
79
  end
53
80
 
54
81
  test "localize Date: given nil with default value it returns default" do
@@ -56,15 +83,15 @@ module I18n
56
83
  end
57
84
 
58
85
  test "localize Date: given nil it raises I18n::ArgumentError" do
59
- assert_raise(I18n::ArgumentError) { I18n.l(nil) }
86
+ assert_raises(I18n::ArgumentError) { I18n.l(nil) }
60
87
  end
61
88
 
62
89
  test "localize Date: given a plain Object it raises I18n::ArgumentError" do
63
- assert_raise(I18n::ArgumentError) { I18n.l(Object.new) }
90
+ assert_raises(I18n::ArgumentError) { I18n.l(Object.new) }
64
91
  end
65
92
 
66
93
  test "localize Date: given a format is missing it raises I18n::MissingTranslationData" do
67
- assert_raise(I18n::MissingTranslationData) { I18n.l(@date, :format => :missing) }
94
+ assert_raises(I18n::MissingTranslationData) { I18n.l(@date, :format => :missing) }
68
95
  end
69
96
 
70
97
  test "localize Date: it does not alter the format string" do
@@ -85,7 +112,7 @@ module I18n
85
112
  :day_names => %w(Sonntag Montag Dienstag Mittwoch Donnerstag Freitag Samstag),
86
113
  :abbr_day_names => %w(So Mo Di Mi Do Fr Sa),
87
114
  :month_names => %w(Januar Februar März April Mai Juni Juli August September Oktober November Dezember).unshift(nil),
88
- :abbr_month_names => %w(Jan Feb Mar Apr Mai Jun Jul Aug Sep Okt Nov Dez).unshift(nil)
115
+ :abbr_month_names => %w(Jan Feb Mär Apr Mai Jun Jul Aug Sep Okt Nov Dez).unshift(nil)
89
116
  }
90
117
  }
91
118
  end
@@ -12,8 +12,7 @@ module I18n
12
12
  end
13
13
 
14
14
  test "localize DateTime: given the short format it uses it" do
15
- # TODO should be Mrz, shouldn't it?
16
- assert_equal '01. Mar 06:00', I18n.l(@datetime, :format => :short, :locale => :de)
15
+ assert_equal '01. Mär 06:00', I18n.l(@datetime, :format => :short, :locale => :de)
17
16
  end
18
17
 
19
18
  test "localize DateTime: given the long format it uses it" do
@@ -21,25 +20,47 @@ module I18n
21
20
  end
22
21
 
23
22
  test "localize DateTime: given the default format it uses it" do
24
- # TODO should be Mrz, shouldn't it?
25
- assert_equal 'Sa, 01. Mar 2008 06:00:00 +0000', I18n.l(@datetime, :format => :default, :locale => :de)
23
+ assert_equal 'Sa, 01. Mär 2008 06:00:00 +0000', I18n.l(@datetime, :format => :default, :locale => :de)
26
24
  end
27
25
 
28
26
  test "localize DateTime: given a day name format it returns the correct day name" do
29
27
  assert_equal 'Samstag', I18n.l(@datetime, :format => '%A', :locale => :de)
30
28
  end
31
29
 
30
+ test "localize DateTime: given a uppercased day name format it returns the correct day name in upcase" do
31
+ assert_equal 'samstag'.upcase, I18n.l(@datetime, :format => '%^A', :locale => :de)
32
+ end
33
+
32
34
  test "localize DateTime: given an abbreviated day name format it returns the correct abbreviated day name" do
33
35
  assert_equal 'Sa', I18n.l(@datetime, :format => '%a', :locale => :de)
34
36
  end
35
37
 
38
+ test "localize DateTime: given an abbreviated and uppercased day name format it returns the correct abbreviated day name in upcase" do
39
+ assert_equal 'sa'.upcase, I18n.l(@datetime, :format => '%^a', :locale => :de)
40
+ end
41
+
36
42
  test "localize DateTime: given a month name format it returns the correct month name" do
37
43
  assert_equal 'März', I18n.l(@datetime, :format => '%B', :locale => :de)
38
44
  end
39
45
 
46
+ test "localize DateTime: given a uppercased month name format it returns the correct month name in upcase" do
47
+ assert_equal 'märz'.upcase, I18n.l(@datetime, :format => '%^B', :locale => :de)
48
+ end
49
+
40
50
  test "localize DateTime: given an abbreviated month name format it returns the correct abbreviated month name" do
41
- # TODO should be Mrz, shouldn't it?
42
- assert_equal 'Mar', I18n.l(@datetime, :format => '%b', :locale => :de)
51
+ assert_equal 'Mär', I18n.l(@datetime, :format => '%b', :locale => :de)
52
+ end
53
+
54
+ test "localize DateTime: given an abbreviated and uppercased month name format it returns the correct abbreviated month name in upcase" do
55
+ assert_equal 'mär'.upcase, I18n.l(@datetime, :format => '%^b', :locale => :de)
56
+ end
57
+
58
+ test "localize DateTime: given a date format with the month name upcased it returns the correct value" do
59
+ assert_equal '1. FEBRUAR 2008', I18n.l(::DateTime.new(2008, 2, 1, 6), :format => "%-d. %^B %Y", :locale => :de)
60
+ end
61
+
62
+ test "localize DateTime: given missing translations it returns the correct error message" do
63
+ assert_equal 'Translation missing: fr.date.abbr_month_names', I18n.l(@datetime, :format => '%b', :locale => :fr)
43
64
  end
44
65
 
45
66
  test "localize DateTime: given a meridian indicator format it returns the correct meridian indicator" do
@@ -57,7 +78,7 @@ module I18n
57
78
  end
58
79
 
59
80
  test "localize DateTime: given a format is missing it raises I18n::MissingTranslationData" do
60
- assert_raise(I18n::MissingTranslationData) { I18n.l(@datetime, :format => :missing) }
81
+ assert_raises(I18n::MissingTranslationData) { I18n.l(@datetime, :format => :missing) }
61
82
  end
62
83
 
63
84
  protected
@@ -34,7 +34,7 @@ module I18n
34
34
  test "localize Date: given a format that resolves to a Proc it calls the Proc with the object and extra options" do
35
35
  setup_time_proc_translations
36
36
  date = ::Date.new(2008, 3, 1)
37
- assert_equal '[Sat, 01 Mar 2008, {:foo=>"foo"}]', I18n.l(date, :format => :proc, :foo => 'foo', :locale => :ru)
37
+ assert_equal %|[Sat, 01 Mar 2008, #{{:foo=>"foo"}}]|, I18n.l(date, :format => :proc, :foo => 'foo', :locale => :ru)
38
38
  end
39
39
 
40
40
  test "localize DateTime: given a format that resolves to a Proc it calls the Proc with the object" do
@@ -46,25 +46,26 @@ module I18n
46
46
  test "localize DateTime: given a format that resolves to a Proc it calls the Proc with the object and extra options" do
47
47
  setup_time_proc_translations
48
48
  datetime = ::DateTime.new(2008, 3, 1, 6)
49
- assert_equal '[Sat, 01 Mar 2008 06:00:00 +00:00, {:foo=>"foo"}]', I18n.l(datetime, :format => :proc, :foo => 'foo', :locale => :ru)
49
+ assert_equal %|[Sat, 01 Mar 2008 06:00:00 +00:00, #{{:foo=>"foo"}}]|, I18n.l(datetime, :format => :proc, :foo => 'foo', :locale => :ru)
50
50
  end
51
51
 
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, {}]), I18n.l(time, :format => :proc, :locale => :ru)
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]), I18n.l(time, options.merge(:format => :proc, :locale => :ru))
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
@@ -73,6 +74,7 @@ module I18n
73
74
  arg.strftime('%a, %d %b %Y')
74
75
  when Hash
75
76
  arg.delete(:fallback_in_progress)
77
+ arg.delete(:fallback_original_locale)
76
78
  arg.inspect
77
79
  else
78
80
  arg.inspect
@@ -85,12 +87,12 @@ module I18n
85
87
  I18n.backend.store_translations :ru, {
86
88
  :time => {
87
89
  :formats => {
88
- :proc => lambda { |*args| I18n::Tests::Localization::Procs.inspect_args(args) }
90
+ :proc => lambda { |*args, **kwargs| I18n::Tests::Localization::Procs.inspect_args(args, kwargs) }
89
91
  }
90
92
  },
91
93
  :date => {
92
94
  :formats => {
93
- :proc => lambda { |*args| I18n::Tests::Localization::Procs.inspect_args(args) }
95
+ :proc => lambda { |*args, **kwargs| I18n::Tests::Localization::Procs.inspect_args(args, kwargs) }
94
96
  },
95
97
  :'day_names' => lambda { |key, options|
96
98
  (options[:format] =~ /^%A/) ?
@@ -12,8 +12,7 @@ module I18n
12
12
  end
13
13
 
14
14
  test "localize Time: given the short format it uses it" do
15
- # TODO should be Mrz, shouldn't it?
16
- assert_equal '01. Mar 06:00', I18n.l(@time, :format => :short, :locale => :de)
15
+ assert_equal '01. Mär 06:00', I18n.l(@time, :format => :short, :locale => :de)
17
16
  end
18
17
 
19
18
  test "localize Time: given the long format it uses it" do
@@ -29,17 +28,40 @@ module I18n
29
28
  assert_equal 'Samstag', I18n.l(@time, :format => '%A', :locale => :de)
30
29
  end
31
30
 
31
+ test "localize Time: given a uppercased day name format it returns the correct day name in upcase" do
32
+ assert_equal 'samstag'.upcase, I18n.l(@time, :format => '%^A', :locale => :de)
33
+ end
34
+
32
35
  test "localize Time: given an abbreviated day name format it returns the correct abbreviated day name" do
33
36
  assert_equal 'Sa', I18n.l(@time, :format => '%a', :locale => :de)
34
37
  end
35
38
 
39
+ test "localize Time: given an abbreviated and uppercased day name format it returns the correct abbreviated day name in upcase" do
40
+ assert_equal 'sa'.upcase, I18n.l(@time, :format => '%^a', :locale => :de)
41
+ end
42
+
36
43
  test "localize Time: given a month name format it returns the correct month name" do
37
44
  assert_equal 'März', I18n.l(@time, :format => '%B', :locale => :de)
38
45
  end
39
46
 
47
+ test "localize Time: given a uppercased month name format it returns the correct month name in upcase" do
48
+ assert_equal 'märz'.upcase, I18n.l(@time, :format => '%^B', :locale => :de)
49
+ end
50
+
40
51
  test "localize Time: given an abbreviated month name format it returns the correct abbreviated month name" do
41
- # TODO should be Mrz, shouldn't it?
42
- assert_equal 'Mar', I18n.l(@time, :format => '%b', :locale => :de)
52
+ assert_equal 'Mär', I18n.l(@time, :format => '%b', :locale => :de)
53
+ end
54
+
55
+ test "localize Time: given an abbreviated and uppercased month name format it returns the correct abbreviated month name in upcase" do
56
+ assert_equal 'mär'.upcase, I18n.l(@time, :format => '%^b', :locale => :de)
57
+ end
58
+
59
+ test "localize Time: given a date format with the month name upcased it returns the correct value" do
60
+ assert_equal '1. FEBRUAR 2008', I18n.l(::Time.utc(2008, 2, 1, 6, 0), :format => "%-d. %^B %Y", :locale => :de)
61
+ end
62
+
63
+ test "localize Time: given missing translations it returns the correct error message" do
64
+ assert_equal 'Translation missing: fr.date.abbr_month_names', I18n.l(@time, :format => '%b', :locale => :fr)
43
65
  end
44
66
 
45
67
  test "localize Time: given a meridian indicator format it returns the correct meridian indicator" do
@@ -57,7 +79,7 @@ module I18n
57
79
  end
58
80
 
59
81
  test "localize Time: given a format is missing it raises I18n::MissingTranslationData" do
60
- assert_raise(I18n::MissingTranslationData) { I18n.l(@time, :format => :missing) }
82
+ assert_raises(I18n::MissingTranslationData) { I18n.l(@time, :format => :missing) }
61
83
  end
62
84
 
63
85
  protected
@@ -30,11 +30,11 @@ module I18n
30
30
  end
31
31
 
32
32
  test "lookup: given a missing key, no default and no raise option it returns an error message" do
33
- assert_equal "translation missing: en.missing", I18n.t(:missing)
33
+ assert_equal "Translation missing: en.missing", I18n.t(:missing)
34
34
  end
35
35
 
36
36
  test "lookup: given a missing key, no default and the raise option it raises MissingTranslationData" do
37
- assert_raise(I18n::MissingTranslationData) { I18n.t(:missing, :raise => true) }
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
@@ -43,9 +43,9 @@ module I18n
43
43
 
44
44
  test "lookup: does not modify the options hash" do
45
45
  options = {}
46
- assert_equal "a", I18n.t(:string, options)
46
+ assert_equal "a", I18n.t(:string, **options)
47
47
  assert_equal({}, options)
48
- assert_nothing_raised { I18n.t(:string, options.freeze) }
48
+ assert_nothing_raised { I18n.t(:string, **options.freeze) }
49
49
  end
50
50
 
51
51
  test "lookup: given an array of keys it translates all of them" 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
- # assert_raise(I18n::InvalidLocale) { I18n.t(:bar, :locale => nil) }
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
 
@@ -76,6 +76,12 @@ module I18n
76
76
  test "lookup: a resulting Hash is not frozen" do
77
77
  assert !I18n.t(:hash).frozen?
78
78
  end
79
+
80
+ # Addresses issue: #599
81
+ test "lookup: only interpolates once when resolving symbols" do
82
+ I18n.backend.store_translations(:en, foo: :bar, bar: '%{value}')
83
+ assert_equal '%{dont_interpolate_me}', I18n.t(:foo, value: '%{dont_interpolate_me}')
84
+ end
79
85
  end
80
86
  end
81
87
  end
@@ -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
- assert_raise(I18n::InvalidPluralizationData) { I18n.t(:default => { :one => 'bar' }, :count => 2) }
31
+ assert_raises(I18n::InvalidPluralizationData) { I18n.t(:default => { :one => 'bar' }, :count => 2) }
32
32
  end
33
33
  end
34
34
  end
@@ -5,29 +5,38 @@ module I18n
5
5
  module Procs
6
6
  test "lookup: given a translation is a proc it calls the proc with the key and interpolation values" do
7
7
  I18n.backend.store_translations(:en, :a_lambda => lambda { |*args| I18n::Tests::Procs.filter_args(*args) })
8
- assert_equal '[:a_lambda, {:foo=>"foo"}]', I18n.t(:a_lambda, :foo => 'foo')
8
+ assert_equal %|[:a_lambda, #{{:foo=>"foo"}}]|, I18n.t(:a_lambda, :foo => 'foo')
9
+ end
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')
9
14
  end
10
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
- assert_equal '[nil, {:foo=>"foo"}]', I18n.t(nil, :default => proc, :foo => 'foo')
18
+ assert_equal %|[nil, #{{:foo=>"foo"}}]|, I18n.t(nil, :default => proc, :foo => 'foo')
14
19
  end
15
20
 
16
21
  test "defaults: given a default is a key that resolves to a Proc it calls it with the key and interpolation values" do
17
22
  the_lambda = lambda { |*args| I18n::Tests::Procs.filter_args(*args) }
18
23
  I18n.backend.store_translations(:en, :a_lambda => the_lambda)
19
- assert_equal '[:a_lambda, {:foo=>"foo"}]', I18n.t(nil, :default => :a_lambda, :foo => 'foo')
20
- assert_equal '[:a_lambda, {:foo=>"foo"}]', I18n.t(nil, :default => [nil, :a_lambda], :foo => 'foo')
24
+ assert_equal %|[:a_lambda, #{{:foo=>"foo"}}]|, I18n.t(nil, :default => :a_lambda, :foo => 'foo')
25
+ assert_equal %|[:a_lambda, #{{:foo=>"foo"}}]|, I18n.t(nil, :default => [nil, :a_lambda], :foo => 'foo')
21
26
  end
22
27
 
23
28
  test "interpolation: given an interpolation value is a lambda it calls it with key and values before interpolating it" do
24
29
  proc = lambda { |*args| I18n::Tests::Procs.filter_args(*args) }
25
- assert_match %r(\[\{:foo=>#<Proc.*>\}\]), I18n.t(nil, :default => '%{foo}', :foo => proc)
30
+ if RUBY_VERSION < "3.4"
31
+ assert_match %r(\[\{:foo=>#<Proc.*>\}\]), I18n.t(nil, :default => '%{foo}', :foo => proc)
32
+ else
33
+ assert_match %r(\[\{foo: #<Proc.*>\}\]), I18n.t(nil, :default => '%{foo}', :foo => proc)
34
+ end
26
35
  end
27
36
 
28
37
  test "interpolation: given a key resolves to a Proc that returns a string then interpolation still works" do
29
38
  proc = lambda { |*args| "%{foo}: " + I18n::Tests::Procs.filter_args(*args) }
30
- assert_equal 'foo: [nil, {:foo=>"foo"}]', I18n.t(nil, :default => proc, :foo => 'foo')
39
+ assert_equal %|foo: [nil, #{{:foo=>"foo"}}]|, I18n.t(nil, :default => proc, :foo => 'foo')
31
40
  end
32
41
 
33
42
  test "pluralization: given a key resolves to a Proc that returns valid data then pluralization still works" do
@@ -48,7 +57,14 @@ module I18n
48
57
 
49
58
 
50
59
  def self.filter_args(*args)
51
- args.map {|arg| arg.delete(:fallback_in_progress) if arg.is_a?(Hash) ; arg }.inspect
60
+ args.map do |arg|
61
+ if arg.is_a?(Hash)
62
+ arg.delete(:fallback_in_progress)
63
+ arg.delete(:fallback_original_locale)
64
+ arg.delete(:skip_interpolation)
65
+ end
66
+ arg
67
+ end.inspect
52
68
  end
53
69
  end
54
70
  end
data/lib/i18n/tests.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module I18n
2
4
  module Tests
3
5
  autoload :Basics, 'i18n/tests/basics'