i18n 0.4.0 → 1.14.4

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 (58) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +0 -0
  3. data/README.md +127 -0
  4. data/lib/i18n/backend/base.rb +189 -111
  5. data/lib/i18n/backend/cache.rb +58 -22
  6. data/lib/i18n/backend/cache_file.rb +36 -0
  7. data/lib/i18n/backend/cascade.rb +9 -10
  8. data/lib/i18n/backend/chain.rb +95 -42
  9. data/lib/i18n/backend/fallbacks.rb +68 -22
  10. data/lib/i18n/backend/flatten.rb +13 -8
  11. data/lib/i18n/backend/gettext.rb +33 -25
  12. data/lib/i18n/backend/interpolation_compiler.rb +12 -14
  13. data/lib/i18n/backend/key_value.rb +112 -10
  14. data/lib/i18n/backend/lazy_loadable.rb +184 -0
  15. data/lib/i18n/backend/memoize.rb +13 -7
  16. data/lib/i18n/backend/metadata.rb +12 -6
  17. data/lib/i18n/backend/pluralization.rb +64 -25
  18. data/lib/i18n/backend/simple.rb +44 -18
  19. data/lib/i18n/backend/transliterator.rb +43 -33
  20. data/lib/i18n/backend.rb +5 -3
  21. data/lib/i18n/config.rb +91 -10
  22. data/lib/i18n/exceptions.rb +118 -22
  23. data/lib/i18n/gettext/helpers.rb +14 -4
  24. data/lib/i18n/gettext/po_parser.rb +7 -7
  25. data/lib/i18n/gettext.rb +6 -5
  26. data/lib/i18n/interpolate/ruby.rb +53 -0
  27. data/lib/i18n/locale/fallbacks.rb +33 -26
  28. data/lib/i18n/locale/tag/parents.rb +8 -8
  29. data/lib/i18n/locale/tag/rfc4646.rb +0 -2
  30. data/lib/i18n/locale/tag/simple.rb +2 -4
  31. data/lib/i18n/locale.rb +2 -0
  32. data/lib/i18n/middleware.rb +17 -0
  33. data/lib/i18n/tests/basics.rb +58 -0
  34. data/lib/i18n/tests/defaults.rb +52 -0
  35. data/lib/i18n/tests/interpolation.rb +167 -0
  36. data/lib/i18n/tests/link.rb +66 -0
  37. data/lib/i18n/tests/localization/date.rb +122 -0
  38. data/lib/i18n/tests/localization/date_time.rb +103 -0
  39. data/lib/i18n/tests/localization/procs.rb +118 -0
  40. data/lib/i18n/tests/localization/time.rb +103 -0
  41. data/lib/i18n/tests/localization.rb +19 -0
  42. data/lib/i18n/tests/lookup.rb +81 -0
  43. data/lib/i18n/tests/pluralization.rb +35 -0
  44. data/lib/i18n/tests/procs.rb +66 -0
  45. data/lib/i18n/tests.rb +14 -0
  46. data/lib/i18n/utils.rb +55 -0
  47. data/lib/i18n/version.rb +3 -1
  48. data/lib/i18n.rb +200 -87
  49. metadata +64 -56
  50. data/CHANGELOG.textile +0 -135
  51. data/README.textile +0 -93
  52. data/lib/i18n/backend/active_record/missing.rb +0 -65
  53. data/lib/i18n/backend/active_record/store_procs.rb +0 -38
  54. data/lib/i18n/backend/active_record/translation.rb +0 -93
  55. data/lib/i18n/backend/active_record.rb +0 -61
  56. data/lib/i18n/backend/cldr.rb +0 -100
  57. data/lib/i18n/core_ext/hash.rb +0 -29
  58. data/lib/i18n/core_ext/string/interpolate.rb +0 -98
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  # Locale Fallbacks
4
2
  #
5
3
  # Extends the I18n module to hold a fallbacks instance which is set to an
@@ -17,22 +15,15 @@
17
15
  # * all parent locales of a given locale (e.g. :es for :"es-MX") first,
18
16
  # * the current default locales and all of their parents second
19
17
  #
20
- # The default locales are set to [I18n.default_locale] by default but can be
21
- # set to something else.
18
+ # The default locales are set to [] by default but can be set to something else.
22
19
  #
23
20
  # One can additionally add any number of additional fallback locales manually.
24
21
  # These will be added before the default locales to the fallback chain. For
25
22
  # example:
26
23
  #
27
- # # using the default locale as default fallback locale
28
- #
29
- # I18n.default_locale = :"en-US"
30
- # I18n.fallbacks = I18n::Fallbacks.new(:"de-AT" => :"de-DE")
31
- # I18n.fallbacks[:"de-AT"] # => [:"de-AT", :"de-DE", :de, :"en-US", :en]
32
- #
33
24
  # # using a custom locale as default fallback locale
34
25
  #
35
- # I18n.fallbacks = I18n::Fallbacks.new(:"en-GB", :"de-AT" => :de, :"de-CH" => :de)
26
+ # I18n.fallbacks = I18n::Locale::Fallbacks.new(:"en-GB", :"de-AT" => :de, :"de-CH" => :de)
36
27
  # I18n.fallbacks[:"de-AT"] # => [:"de-AT", :de, :"en-GB", :en]
37
28
  # I18n.fallbacks[:"de-CH"] # => [:"de-CH", :de, :"en-GB", :en]
38
29
  #
@@ -48,7 +39,7 @@
48
39
  # fallbacks[:"ar-PS"] # => [:"ar-PS", :ar, :"he-IL", :he, :"en-US", :en]
49
40
  # fallbacks[:"ar-EG"] # => [:"ar-EG", :ar, :"en-US", :en]
50
41
  #
51
- # # people speaking Sami as spoken in Finnland also speak Swedish and Finnish as spoken in Finnland
42
+ # # people speaking Sami as spoken in Finland also speak Swedish and Finnish as spoken in Finland
52
43
  # fallbacks.map(:sms => [:"se-FI", :"fi-FI"])
53
44
  # fallbacks[:sms] # => [:sms, :"se-FI", :se, :"fi-FI", :fi, :"en-US", :en]
54
45
 
@@ -58,40 +49,56 @@ module I18n
58
49
  def initialize(*mappings)
59
50
  @map = {}
60
51
  map(mappings.pop) if mappings.last.is_a?(Hash)
61
- self.defaults = mappings.empty? ? [I18n.default_locale.to_sym] : mappings
52
+ self.defaults = mappings.empty? ? [] : mappings
62
53
  end
63
54
 
64
55
  def defaults=(defaults)
65
- @defaults = defaults.map { |default| compute(default, false) }.flatten
56
+ @defaults = defaults.flat_map { |default| compute(default, false) }
66
57
  end
67
58
  attr_reader :defaults
68
59
 
69
60
  def [](locale)
70
61
  raise InvalidLocale.new(locale) if locale.nil?
62
+ raise Disabled.new('fallback#[]') if locale == false
71
63
  locale = locale.to_sym
72
64
  super || store(locale, compute(locale))
73
65
  end
74
66
 
75
- def map(mappings)
76
- mappings.each do |from, to|
77
- from, to = from.to_sym, Array(to)
78
- to.each do |to|
79
- @map[from] ||= []
80
- @map[from] << to.to_sym
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
81
76
  end
77
+ else
78
+ @map.map(*args, &block)
82
79
  end
83
80
  end
84
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
+
85
90
  protected
86
91
 
87
- def compute(tags, include_defaults = true)
88
- result = Array(tags).collect do |tag|
89
- tags = I18n::Locale::Tag.tag(tag).self_and_parents.map! { |t| t.to_sym }
90
- tags.each { |tag| tags += compute(@map[tag]) if @map[tag] }
92
+ def compute(tags, include_defaults = true, exclude = [])
93
+ result = Array(tags).flat_map do |tag|
94
+ tags = I18n::Locale::Tag.tag(tag).self_and_parents.map! { |t| t.to_sym } - exclude
95
+ tags.each { |_tag| tags += compute(@map[_tag], false, exclude + tags) if @map[_tag] }
91
96
  tags
92
- end.flatten
97
+ end
93
98
  result.push(*defaults) if include_defaults
94
- result.uniq
99
+ result.uniq!
100
+ result.compact!
101
+ result
95
102
  end
96
103
  end
97
104
  end
@@ -1,22 +1,22 @@
1
- # encoding: utf-8
2
-
3
1
  module I18n
4
2
  module Locale
5
3
  module Tag
6
4
  module Parents
7
5
  def parent
8
- @parent ||= begin
9
- segs = to_a.compact
10
- segs.length > 1 ? self.class.tag(*segs[0..(segs.length-2)].join('-')) : nil
11
- 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
12
12
  end
13
13
 
14
14
  def self_and_parents
15
- @self_and_parents ||= [self] + parents
15
+ @self_and_parents ||= [self].concat parents
16
16
  end
17
17
 
18
18
  def parents
19
- @parents ||= ([parent] + (parent ? parent.parents : [])).compact
19
+ @parents ||= parent ? [parent].concat(parent.parents) : []
20
20
  end
21
21
  end
22
22
  end
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  # RFC 4646/47 compliant Locale tag implementation that parses locale tags to
4
2
  # subtags such as language, script, region, variant etc.
5
3
  #
@@ -1,7 +1,5 @@
1
- # encoding: utf-8
2
-
3
1
  # Simple Locale tag implementation that computes subtags by simply splitting
4
- # the locale tag at '-' occurences.
2
+ # the locale tag at '-' occurrences.
5
3
  module I18n
6
4
  module Locale
7
5
  module Tag
@@ -21,7 +19,7 @@ module I18n
21
19
  end
22
20
 
23
21
  def subtags
24
- @subtags = tag.to_s.split('-').map { |subtag| subtag.to_s }
22
+ @subtags = tag.to_s.split('-').map!(&:to_s)
25
23
  end
26
24
 
27
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'
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module I18n
4
+ class Middleware
5
+
6
+ def initialize(app)
7
+ @app = app
8
+ end
9
+
10
+ def call(env)
11
+ @app.call(env)
12
+ ensure
13
+ Thread.current[:i18n_config] = I18n::Config.new
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,58 @@
1
+ module I18n
2
+ module Tests
3
+ module Basics
4
+ def teardown
5
+ I18n.available_locales = nil
6
+ end
7
+
8
+ test "available_locales returns the available_locales produced by the backend, by default" do
9
+ I18n.backend.store_translations('de', :foo => 'bar')
10
+ I18n.backend.store_translations('en', :foo => 'foo')
11
+
12
+ assert_equal I18n.available_locales, I18n.backend.available_locales
13
+ end
14
+
15
+ test "available_locales can be set to something else independently from the actual locale data" do
16
+ I18n.backend.store_translations('de', :foo => 'bar')
17
+ I18n.backend.store_translations('en', :foo => 'foo')
18
+
19
+ I18n.available_locales = :foo
20
+ assert_equal [:foo], I18n.available_locales
21
+
22
+ I18n.available_locales = [:foo, 'bar']
23
+ assert_equal [:foo, :bar], I18n.available_locales
24
+
25
+ I18n.available_locales = nil
26
+ assert_equal I18n.available_locales, I18n.backend.available_locales
27
+ end
28
+
29
+ test "available_locales memoizes when set explicitly" do
30
+ I18n.backend.expects(:available_locales).never
31
+ I18n.available_locales = [:foo]
32
+ I18n.backend.store_translations('de', :bar => 'baz')
33
+ I18n.reload!
34
+ assert_equal [:foo], I18n.available_locales
35
+ end
36
+
37
+ test "available_locales delegates to the backend when not set explicitly" do
38
+ original_available_locales_value = I18n.backend.available_locales
39
+ I18n.backend.expects(:available_locales).returns(original_available_locales_value).twice
40
+ assert_equal I18n.backend.available_locales, I18n.available_locales
41
+ end
42
+
43
+ test "exists? is implemented by the backend" do
44
+ I18n.backend.store_translations(:foo, :bar => 'baz')
45
+ assert I18n.exists?(:bar, :foo)
46
+ end
47
+
48
+ test "storing a nil value as a translation removes it from the available locale data" do
49
+ I18n.backend.store_translations(:en, :to_be_deleted => 'bar')
50
+ assert_equal 'bar', I18n.t(:to_be_deleted, :default => 'baz')
51
+
52
+ I18n.cache_store.clear if I18n.respond_to?(:cache_store) && I18n.cache_store
53
+ I18n.backend.store_translations(:en, :to_be_deleted => nil)
54
+ assert_equal 'baz', I18n.t(:to_be_deleted, :default => 'baz')
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,52 @@
1
+ # encoding: utf-8
2
+
3
+ module I18n
4
+ module Tests
5
+ module Defaults
6
+ def setup
7
+ super
8
+ I18n.backend.store_translations(:en, :foo => { :bar => 'bar', :baz => 'baz' })
9
+ end
10
+
11
+ test "defaults: given nil as a key it returns the given default" do
12
+ assert_equal 'default', I18n.t(nil, :default => 'default')
13
+ end
14
+
15
+ test "defaults: given a symbol as a default it translates the symbol" do
16
+ assert_equal 'bar', I18n.t(nil, :default => :'foo.bar')
17
+ end
18
+
19
+ test "defaults: given a symbol as a default and a scope it stays inside the scope when looking up the symbol" do
20
+ assert_equal 'bar', I18n.t(:missing, :default => :bar, :scope => :foo)
21
+ end
22
+
23
+ test "defaults: given an array as a default it returns the first match" do
24
+ assert_equal 'bar', I18n.t(:does_not_exist, :default => [:does_not_exist_2, :'foo.bar'])
25
+ end
26
+
27
+ test "defaults: given an array as a default with false it returns false" do
28
+ assert_equal false, I18n.t(:does_not_exist, :default => [false])
29
+ end
30
+
31
+ test "defaults: given false it returns false" do
32
+ assert_equal false, I18n.t(:does_not_exist, :default => false)
33
+ end
34
+
35
+ test "defaults: given nil it returns nil" do
36
+ assert_nil I18n.t(:does_not_exist, :default => nil)
37
+ end
38
+
39
+ test "defaults: given an array of missing keys it raises a MissingTranslationData exception" do
40
+ assert_raises I18n::MissingTranslationData do
41
+ I18n.t(:does_not_exist, :default => [:does_not_exist_2, :does_not_exist_3], :raise => true)
42
+ end
43
+ end
44
+
45
+ test "defaults: using a custom scope separator" do
46
+ # data must have been stored using the custom separator when using the ActiveRecord backend
47
+ I18n.backend.store_translations(:en, { :foo => { :bar => 'bar' } }, { :separator => '|' })
48
+ assert_equal 'bar', I18n.t(nil, :default => :'foo|bar', :separator => '|')
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,167 @@
1
+ # encoding: utf-8
2
+
3
+ module I18n
4
+ module Tests
5
+ module Interpolation
6
+ # If no interpolation parameter is not given, I18n should not alter the string.
7
+ # This behavior is due to three reasons:
8
+ #
9
+ # * Checking interpolation keys in all strings hits performance, badly;
10
+ #
11
+ # * This allows us to retrieve untouched values through I18n. For example
12
+ # I could have a middleware that returns I18n lookup results in JSON
13
+ # to be processed through Javascript. Leaving the keys untouched allows
14
+ # the interpolation to happen at the javascript level;
15
+ #
16
+ # * Security concerns: if I allow users to translate a web site, they can
17
+ # insert %{} in messages causing the I18n lookup to fail in every request.
18
+ #
19
+ test "interpolation: given no values it does not alter the string" do
20
+ assert_equal 'Hi %{name}!', interpolate(:default => 'Hi %{name}!')
21
+ end
22
+
23
+ test "interpolation: given values it interpolates them into the string" do
24
+ assert_equal 'Hi David!', interpolate(:default => 'Hi %{name}!', :name => 'David')
25
+ end
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
+
31
+ test "interpolation: given a nil value it still interpolates it into the string" do
32
+ assert_equal 'Hi !', interpolate(:default => 'Hi %{name}!', :name => nil)
33
+ end
34
+
35
+ test "interpolation: given a lambda as a value it calls it if the string contains the key" do
36
+ assert_equal 'Hi David!', interpolate(:default => 'Hi %{name}!', :name => lambda { |*args| 'David' })
37
+ end
38
+
39
+ test "interpolation: given a lambda as a value it does not call it if the string does not contain the key" do
40
+ assert_nothing_raised { interpolate(:default => 'Hi!', :name => lambda { |*args| raise 'fail' }) }
41
+ end
42
+
43
+ test "interpolation: given values but missing a key it raises I18n::MissingInterpolationArgument" do
44
+ assert_raises(I18n::MissingInterpolationArgument) do
45
+ interpolate(:default => '%{foo}', :bar => 'bar')
46
+ end
47
+ end
48
+
49
+ test "interpolation: it does not raise I18n::MissingInterpolationArgument for escaped variables" do
50
+ assert_nothing_raised do
51
+ assert_equal 'Barr %{foo}', interpolate(:default => '%{bar} %%{foo}', :bar => 'Barr')
52
+ end
53
+ end
54
+
55
+ test "interpolation: it does not change the original, stored translation string" do
56
+ I18n.backend.store_translations(:en, :interpolate => 'Hi %{name}!')
57
+ assert_equal 'Hi David!', interpolate(:interpolate, :name => 'David')
58
+ assert_equal 'Hi Yehuda!', interpolate(:interpolate, :name => 'Yehuda')
59
+ end
60
+
61
+ test "interpolation: given an array interpolates each element" do
62
+ I18n.backend.store_translations(:en, :array_interpolate => ['Hi', 'Mr. %{name}', 'or sir %{name}'])
63
+ assert_equal ['Hi', 'Mr. Bartuz', 'or sir Bartuz'], interpolate(:array_interpolate, :name => 'Bartuz')
64
+ end
65
+
66
+ test "interpolation: given the translation is in utf-8 it still works" do
67
+ assert_equal 'Häi David!', interpolate(:default => 'Häi %{name}!', :name => 'David')
68
+ end
69
+
70
+ test "interpolation: given the value is in utf-8 it still works" do
71
+ assert_equal 'Hi ゆきひろ!', interpolate(:default => 'Hi %{name}!', :name => 'ゆきひろ')
72
+ end
73
+
74
+ test "interpolation: given the translation and the value are in utf-8 it still works" do
75
+ assert_equal 'こんにちは、ゆきひろさん!', interpolate(:default => 'こんにちは、%{name}さん!', :name => 'ゆきひろ')
76
+ end
77
+
78
+ if Object.const_defined?(:Encoding)
79
+ test "interpolation: given a euc-jp translation and a utf-8 value it raises Encoding::CompatibilityError" do
80
+ assert_raises(Encoding::CompatibilityError) do
81
+ interpolate(:default => euc_jp('こんにちは、%{name}さん!'), :name => 'ゆきひろ')
82
+ end
83
+ end
84
+
85
+ test "interpolation: given a utf-8 translation and a euc-jp value it raises Encoding::CompatibilityError" do
86
+ assert_raises(Encoding::CompatibilityError) do
87
+ interpolate(:default => 'こんにちは、%{name}さん!', :name => euc_jp('ゆきひろ'))
88
+ end
89
+ end
90
+
91
+ test "interpolation: ASCII strings in the backend should be encoded to UTF8 if interpolation options are in UTF8" do
92
+ I18n.backend.store_translations 'en', 'encoding' => ('%{who} let me go'.force_encoding("ASCII"))
93
+ result = I18n.t 'encoding', :who => "måmmå miå"
94
+ assert_equal Encoding::UTF_8, result.encoding
95
+ end
96
+
97
+ test "interpolation: UTF8 strings in the backend are still returned as UTF8 with ASCII interpolation" do
98
+ I18n.backend.store_translations 'en', 'encoding' => 'måmmå miå %{what}'
99
+ result = I18n.t 'encoding', :what => 'let me go'.force_encoding("ASCII")
100
+ assert_equal Encoding::UTF_8, result.encoding
101
+ end
102
+
103
+ test "interpolation: UTF8 strings in the backend are still returned as UTF8 even with numbers interpolation" do
104
+ I18n.backend.store_translations 'en', 'encoding' => '%{count} times: måmmå miå'
105
+ result = I18n.t 'encoding', :count => 3
106
+ assert_equal Encoding::UTF_8, result.encoding
107
+ end
108
+ end
109
+
110
+ test "interpolation: given a translations containing a reserved key it raises I18n::ReservedInterpolationKey" do
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: deep interpolation for default string" do
122
+ assert_equal 'Hi %{name}!', interpolate(:default => 'Hi %{name}!', :deep_interpolation => true)
123
+ end
124
+
125
+ test "interpolation: deep interpolation for interpolated string" do
126
+ assert_equal 'Hi Ann!', interpolate(:default => 'Hi %{name}!', :name => 'Ann', :deep_interpolation => true)
127
+ end
128
+
129
+ test "interpolation: deep interpolation for Hash" do
130
+ people = { :people => { :ann => 'Ann is %{ann}', :john => 'John is %{john}' } }
131
+ interpolated_people = { :people => { :ann => 'Ann is good', :john => 'John is big' } }
132
+ assert_equal interpolated_people, interpolate(:default => people, :ann => 'good', :john => 'big', :deep_interpolation => true)
133
+ end
134
+
135
+ test "interpolation: deep interpolation for Array" do
136
+ people = { :people => ['Ann is %{ann}', 'John is %{john}'] }
137
+ interpolated_people = { :people => ['Ann is good', 'John is big'] }
138
+ assert_equal interpolated_people, interpolate(:default => people, :ann => 'good', :john => 'big', :deep_interpolation => true)
139
+ end
140
+
141
+ protected
142
+
143
+ def capture(stream)
144
+ begin
145
+ stream = stream.to_s
146
+ eval "$#{stream} = StringIO.new"
147
+ yield
148
+ result = eval("$#{stream}").string
149
+ ensure
150
+ eval("$#{stream} = #{stream.upcase}")
151
+ end
152
+
153
+ result
154
+ end
155
+
156
+ def euc_jp(string)
157
+ string.encode!(Encoding::EUC_JP)
158
+ end
159
+
160
+ def interpolate(*args)
161
+ options = args.last.is_a?(Hash) ? args.pop : {}
162
+ key = args.pop
163
+ I18n.backend.translate('en', key, options)
164
+ end
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+
3
+ module I18n
4
+ module Tests
5
+ module Link
6
+ test "linked lookup: if a key resolves to a symbol it looks up the symbol" do
7
+ I18n.backend.store_translations 'en', {
8
+ :link => :linked,
9
+ :linked => 'linked'
10
+ }
11
+ assert_equal 'linked', I18n.backend.translate('en', :link)
12
+ end
13
+
14
+ test "linked lookup: if a key resolves to a dot-separated symbol it looks up the symbol" do
15
+ I18n.backend.store_translations 'en', {
16
+ :link => :"foo.linked",
17
+ :foo => { :linked => 'linked' }
18
+ }
19
+ assert_equal('linked', I18n.backend.translate('en', :link))
20
+ end
21
+
22
+ test "linked lookup: if a dot-separated key resolves to a symbol it looks up the symbol" do
23
+ I18n.backend.store_translations 'en', {
24
+ :foo => { :link => :linked },
25
+ :linked => 'linked'
26
+ }
27
+ assert_equal('linked', I18n.backend.translate('en', :'foo.link'))
28
+ end
29
+
30
+ test "linked lookup: if a dot-separated key resolves to a dot-separated symbol it looks up the symbol" do
31
+ I18n.backend.store_translations 'en', {
32
+ :foo => { :link => :"bar.linked" },
33
+ :bar => { :linked => 'linked' }
34
+ }
35
+ assert_equal('linked', I18n.backend.translate('en', :'foo.link'))
36
+ end
37
+
38
+ test "linked lookup: links always refer to the absolute key" do
39
+ I18n.backend.store_translations 'en', {
40
+ :foo => { :link => :linked, :linked => 'linked in foo' },
41
+ :linked => 'linked absolutely'
42
+ }
43
+ assert_equal 'linked absolutely', I18n.backend.translate('en', :link, :scope => :foo)
44
+ end
45
+
46
+ test "linked lookup: a link can resolve to a namespace in the middle of a dot-separated key" do
47
+ I18n.backend.store_translations 'en', {
48
+ :activemodel => { :errors => { :messages => { :blank => "can't be blank" } } },
49
+ :activerecord => { :errors => { :messages => :"activemodel.errors.messages" } }
50
+ }
51
+ assert_equal "can't be blank", I18n.t(:"activerecord.errors.messages.blank")
52
+ assert_equal "can't be blank", I18n.t(:"activerecord.errors.messages.blank")
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
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,122 @@
1
+ # encoding: utf-8
2
+
3
+ module I18n
4
+ module Tests
5
+ module Localization
6
+ module Date
7
+ def setup
8
+ super
9
+ setup_date_translations
10
+ @date = ::Date.new(2008, 3, 1)
11
+ end
12
+
13
+ test "localize Date: given the short format it uses it" do
14
+ assert_equal '01. Mär', I18n.l(@date, :format => :short, :locale => :de)
15
+ end
16
+
17
+ test "localize Date: given the long format it uses it" do
18
+ assert_equal '01. März 2008', I18n.l(@date, :format => :long, :locale => :de)
19
+ end
20
+
21
+ test "localize Date: given the default format it uses it" do
22
+ assert_equal '01.03.2008', I18n.l(@date, :format => :default, :locale => :de)
23
+ end
24
+
25
+ test "localize Date: given a day name format it returns the correct day name" do
26
+ assert_equal 'Samstag', I18n.l(@date, :format => '%A', :locale => :de)
27
+ end
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
+
33
+ test "localize Date: given an abbreviated day name format it returns the correct abbreviated day name" do
34
+ assert_equal 'Sa', I18n.l(@date, :format => '%a', :locale => :de)
35
+ end
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
+
46
+ test "localize Date: given a month name format it returns the correct month name" do
47
+ assert_equal 'März', I18n.l(@date, :format => '%B', :locale => :de)
48
+ end
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
+
54
+ test "localize Date: given an abbreviated month name format it returns the correct abbreviated month name" do
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)
68
+ end
69
+
70
+ test "localize Date: given an unknown format it does not fail" do
71
+ assert_nothing_raised { I18n.l(@date, :format => '%x') }
72
+ end
73
+
74
+ test "localize Date: does not modify the options hash" do
75
+ options = { :format => '%b', :locale => :de }
76
+ assert_equal 'Mär', I18n.l(@date, **options)
77
+ assert_equal({ :format => '%b', :locale => :de }, options)
78
+ assert_nothing_raised { I18n.l(@date, **options.freeze) }
79
+ end
80
+
81
+ test "localize Date: given nil with default value it returns default" do
82
+ assert_equal 'default', I18n.l(nil, :default => 'default')
83
+ end
84
+
85
+ test "localize Date: given nil it raises I18n::ArgumentError" do
86
+ assert_raises(I18n::ArgumentError) { I18n.l(nil) }
87
+ end
88
+
89
+ test "localize Date: given a plain Object it raises I18n::ArgumentError" do
90
+ assert_raises(I18n::ArgumentError) { I18n.l(Object.new) }
91
+ end
92
+
93
+ test "localize Date: given a format is missing it raises I18n::MissingTranslationData" do
94
+ assert_raises(I18n::MissingTranslationData) { I18n.l(@date, :format => :missing) }
95
+ end
96
+
97
+ test "localize Date: it does not alter the format string" do
98
+ assert_equal '01. Februar 2009', I18n.l(::Date.parse('2009-02-01'), :format => :long, :locale => :de)
99
+ assert_equal '01. Oktober 2009', I18n.l(::Date.parse('2009-10-01'), :format => :long, :locale => :de)
100
+ end
101
+
102
+ protected
103
+
104
+ def setup_date_translations
105
+ I18n.backend.store_translations :de, {
106
+ :date => {
107
+ :formats => {
108
+ :default => "%d.%m.%Y",
109
+ :short => "%d. %b",
110
+ :long => "%d. %B %Y",
111
+ },
112
+ :day_names => %w(Sonntag Montag Dienstag Mittwoch Donnerstag Freitag Samstag),
113
+ :abbr_day_names => %w(So Mo Di Mi Do Fr Sa),
114
+ :month_names => %w(Januar Februar März April Mai Juni Juli August September Oktober November Dezember).unshift(nil),
115
+ :abbr_month_names => %w(Jan Feb Mär Apr Mai Jun Jul Aug Sep Okt Nov Dez).unshift(nil)
116
+ }
117
+ }
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end