summaryrefslogtreecommitdiff
path: root/vendor/bundle/ruby/3.4.0/gems/i18n-1.15.2/lib/i18n/tests/interpolation.rb
blob: 991c4ecd0cd3ac4e0fec9369ff43d7cf9f9bf643 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# encoding: utf-8

module I18n
  module Tests
    module Interpolation
      # If no interpolation parameter is not given, I18n should not alter the string.
      # This behavior is due to three reasons:
      #
      #   * Checking interpolation keys in all strings hits performance, badly;
      #
      #   * This allows us to retrieve untouched values through I18n. For example
      #     I could have a middleware that returns I18n lookup results in JSON
      #     to be processed through Javascript. Leaving the keys untouched allows
      #     the interpolation to happen at the javascript level;
      #
      #   * Security concerns: if I allow users to translate a web site, they can
      #     insert %{} in messages causing the I18n lookup to fail in every request.
      #
      test "interpolation: given no values it does not alter the string" do
        assert_equal 'Hi %{name}!', interpolate(:default => 'Hi %{name}!')
      end

      test "interpolation: given values it interpolates them into the string" do
        assert_equal 'Hi David!', interpolate(:default => 'Hi %{name}!', :name => 'David')
      end

      test "interpolation: works with a pipe" do
        assert_equal 'Hi david!', interpolate(:default => 'Hi %{name|lowercase}!', :'name|lowercase' => 'david')
      end

      test "interpolation: given a nil value it still interpolates it into the string" do
        assert_equal 'Hi !', interpolate(:default => 'Hi %{name}!', :name => nil)
      end

      test "interpolation: given a lambda as a value it calls it if the string contains the key" do
        assert_equal 'Hi David!', interpolate(:default => 'Hi %{name}!', :name => lambda { |*args| 'David' })
      end

      test "interpolation: given a lambda as a value it does not call it if the string does not contain the key" do
        assert_nothing_raised { interpolate(:default => 'Hi!', :name => lambda { |*args| raise 'fail' }) }
      end

      test "interpolation: given values but missing a key it raises I18n::MissingInterpolationArgument" do
        assert_raises(I18n::MissingInterpolationArgument) do
          interpolate(:default => '%{foo}', :bar => 'bar')
        end
      end

      test "interpolation: it does not raise I18n::MissingInterpolationArgument for escaped variables" do
        assert_nothing_raised do
          assert_equal 'Barr %{foo}', interpolate(:default => '%{bar} %%{foo}', :bar => 'Barr')
        end
      end

      test "interpolation: it does not change the original, stored translation string" do
        I18n.backend.store_translations(:en, :interpolate => 'Hi %{name}!')
        assert_equal 'Hi David!', interpolate(:interpolate, :name => 'David')
        assert_equal 'Hi Yehuda!', interpolate(:interpolate, :name => 'Yehuda')
      end

      test "interpolation: given an array interpolates each element" do
        I18n.backend.store_translations(:en, :array_interpolate => ['Hi', 'Mr. %{name}', 'or sir %{name}'])
        assert_equal ['Hi', 'Mr. Bartuz', 'or sir Bartuz'], interpolate(:array_interpolate, :name => 'Bartuz')
      end

      test "interpolation: given the translation is in utf-8 it still works" do
        assert_equal 'Häi David!', interpolate(:default => 'Häi %{name}!', :name => 'David')
      end

      test "interpolation: given the value is in utf-8 it still works" do
        assert_equal 'Hi ゆきひろ!', interpolate(:default => 'Hi %{name}!', :name => 'ゆきひろ')
      end

      test "interpolation: given the translation and the value are in utf-8 it still works" do
        assert_equal 'こんにちは、ゆきひろさん!', interpolate(:default => 'こんにちは、%{name}さん!', :name => 'ゆきひろ')
      end

      if Object.const_defined?(:Encoding)
        test "interpolation: given a euc-jp translation and a utf-8 value it raises Encoding::CompatibilityError" do
          assert_raises(Encoding::CompatibilityError) do
            interpolate(:default => euc_jp('こんにちは、%{name}さん!'), :name => 'ゆきひろ')
          end
        end

        test "interpolation: given a utf-8 translation and a euc-jp value it raises Encoding::CompatibilityError" do
          assert_raises(Encoding::CompatibilityError) do
            interpolate(:default => 'こんにちは、%{name}さん!', :name => euc_jp('ゆきひろ'))
          end
        end

        test "interpolation: ASCII strings in the backend should be encoded to UTF8 if interpolation options are in UTF8" do
          I18n.backend.store_translations 'en', 'encoding' => ('%{who} let me go'.dup.force_encoding(Encoding::US_ASCII))
          result = I18n.t 'encoding', :who => "måmmå miå"
          assert_equal Encoding::UTF_8, result.encoding
        end

        test "interpolation: UTF8 strings in the backend are still returned as UTF8 with ASCII interpolation" do
          I18n.backend.store_translations 'en', 'encoding' => 'måmmå miå %{what}'
          result = I18n.t 'encoding', :what => 'let me go'.dup.force_encoding(Encoding::US_ASCII)
          assert_equal Encoding::UTF_8, result.encoding
        end

        test "interpolation: UTF8 strings in the backend are still returned as UTF8 even with numbers interpolation" do
          I18n.backend.store_translations 'en', 'encoding' => '%{count} times: måmmå miå'
          result = I18n.t 'encoding', :count => 3
          assert_equal Encoding::UTF_8, result.encoding
        end
      end

      test "interpolation: given a translations containing a reserved key it raises I18n::ReservedInterpolationKey" do
        assert_raises(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{exception_handler}') }
        assert_raises(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{default}') }
        assert_raises(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{separator}') }
        assert_raises(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{scope}') }
        assert_raises(I18n::ReservedInterpolationKey) { interpolate(:default => '%{scope}') }

        I18n.backend.store_translations(:en, :interpolate => 'Hi %{scope}!')
        assert_raises(I18n::ReservedInterpolationKey) { interpolate(:interpolate) }
      end

      test "interpolation: it does not raise I18n::ReservedInterpolationKey for escaped variables" do
        assert_nothing_raised do
          assert_equal '%{separator}', interpolate(:foo => :bar, :default => '%%{separator}')
        end

        # Note: The two interpolations below do not remove the escape character (%) because
        #   I18n should not alter the strings when no interpolation parameters are given,
        #   see the comment at the top of this file.
        assert_nothing_raised do
          assert_equal '%%{scope}', interpolate(:default => '%%{scope}')
        end

        I18n.backend.store_translations(:en, :interpolate => 'Hi %%{scope}!')
        assert_nothing_raised do
          assert_equal 'Hi %%{scope}!', interpolate(:interpolate)
        end
      end

      test "interpolation: deep interpolation for default string" do
        assert_equal 'Hi %{name}!', interpolate(:default => 'Hi %{name}!', :deep_interpolation => true)
      end

      test "interpolation: deep interpolation for interpolated string" do
        assert_equal 'Hi Ann!', interpolate(:default => 'Hi %{name}!', :name => 'Ann', :deep_interpolation => true)
      end

      test "interpolation: deep interpolation for Hash" do
        people = { :people => { :ann => 'Ann is %{ann}', :john => 'John is %{john}' } }
        interpolated_people = { :people => { :ann => 'Ann is good', :john => 'John is big' } }
        assert_equal interpolated_people, interpolate(:default => people, :ann => 'good', :john => 'big', :deep_interpolation => true)
      end

      test "interpolation: deep interpolation for Array" do
        people = { :people => ['Ann is %{ann}', 'John is %{john}'] }
        interpolated_people = { :people => ['Ann is good', 'John is big'] }
        assert_equal interpolated_people, interpolate(:default => people, :ann => 'good', :john => 'big', :deep_interpolation => true)
      end

      protected

      def capture(stream)
        begin
          stream = stream.to_s
          eval "$#{stream} = StringIO.new"
          yield
          result = eval("$#{stream}").string
        ensure
          eval("$#{stream} = #{stream.upcase}")
        end

        result
      end

      def euc_jp(string)
        string.encode(Encoding::EUC_JP)
      end

      def interpolate(*args)
        options = args.last.is_a?(Hash) ? args.pop : {}
        key = args.pop
        I18n.backend.translate('en', key, options)
      end
    end
  end
end