i18n 0.9.5 → 1.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +71 -32
  3. data/lib/i18n/backend/base.rb +75 -31
  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 +37 -6
  8. data/lib/i18n/backend/fallbacks.rb +43 -14
  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 +3 -1
  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 +3 -1
  17. data/lib/i18n/backend/simple.rb +29 -16
  18. data/lib/i18n/backend/transliterator.rb +2 -0
  19. data/lib/i18n/backend.rb +5 -1
  20. data/lib/i18n/config.rb +20 -2
  21. data/lib/i18n/exceptions.rb +60 -17
  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 +8 -6
  26. data/lib/i18n/locale/fallbacks.rb +21 -20
  27. data/lib/i18n/locale/tag/parents.rb +8 -6
  28. data/lib/i18n/locale/tag/simple.rb +1 -1
  29. data/lib/i18n/locale.rb +2 -0
  30. data/lib/i18n/middleware.rb +2 -0
  31. data/lib/i18n/tests/basics.rb +3 -5
  32. data/lib/i18n/tests/defaults.rb +1 -1
  33. data/lib/i18n/tests/interpolation.rb +12 -7
  34. data/lib/i18n/tests/link.rb +11 -1
  35. data/lib/i18n/tests/localization/date.rb +32 -10
  36. data/lib/i18n/tests/localization/date_time.rb +28 -7
  37. data/lib/i18n/tests/localization/procs.rb +7 -5
  38. data/lib/i18n/tests/localization/time.rb +27 -5
  39. data/lib/i18n/tests/lookup.rb +4 -4
  40. data/lib/i18n/tests/pluralization.rb +1 -1
  41. data/lib/i18n/tests/procs.rb +12 -1
  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 +123 -50
  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
@@ -1,27 +1,34 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'cgi'
2
4
 
3
5
  module I18n
4
- # Handles exceptions raised in the backend. All exceptions except for
5
- # MissingTranslationData exceptions are re-thrown. When a MissingTranslationData
6
- # was caught the handler returns an error message string containing the key/scope.
7
- # Note that the exception handler is not called when the option :throw was given.
8
6
  class ExceptionHandler
9
- include Module.new {
10
- def call(exception, locale, key, options)
11
- case exception
12
- when MissingTranslation
13
- exception.message
14
- when Exception
15
- raise exception
16
- else
17
- throw :exception, exception
18
- end
7
+ def call(exception, _locale, _key, _options)
8
+ if exception.is_a?(MissingTranslation)
9
+ exception.message
10
+ else
11
+ raise exception
19
12
  end
20
- }
13
+ end
21
14
  end
22
15
 
23
16
  class ArgumentError < ::ArgumentError; end
24
17
 
18
+ class Disabled < ArgumentError
19
+ def initialize(method)
20
+ super(<<~MESSAGE)
21
+ I18n.#{method} is currently disabled, likely because your application is still in its loading phase.
22
+
23
+ This method is meant to display text in the user locale, so calling it before the user locale has
24
+ been set is likely to display text from the wrong locale to some users.
25
+
26
+ If you have a legitimate reason to access i18n data outside of the user flow, you can do so by passing
27
+ the desired locale explictly with the `locale` argument, e.g. `I18n.#{method}(..., locale: :en)`
28
+ MESSAGE
29
+ end
30
+ end
31
+
25
32
  class InvalidLocale < ArgumentError
26
33
  attr_reader :locale
27
34
  def initialize(locale)
@@ -40,10 +47,12 @@ module I18n
40
47
 
41
48
  class MissingTranslation < ArgumentError
42
49
  module Base
50
+ PERMITTED_KEYS = [:scope].freeze
51
+
43
52
  attr_reader :locale, :key, :options
44
53
 
45
- def initialize(locale, key, options = {})
46
- @key, @locale, @options = key, locale, options.dup
54
+ def initialize(locale, key, options = EMPTY_HASH)
55
+ @key, @locale, @options = key, locale, options.slice(*PERMITTED_KEYS)
47
56
  options.each { |k, v| self.options[k] = v.inspect if v.is_a?(Proc) }
48
57
  end
49
58
 
@@ -101,4 +110,38 @@ module I18n
101
110
  super "can not load translations from #{filename}, the file type #{type} is not known"
102
111
  end
103
112
  end
113
+
114
+ class UnsupportedMethod < ArgumentError
115
+ attr_reader :method, :backend_klass, :msg
116
+ def initialize(method, backend_klass, msg)
117
+ @method = method
118
+ @backend_klass = backend_klass
119
+ @msg = msg
120
+ super "#{backend_klass} does not support the ##{method} method. #{msg}"
121
+ end
122
+ end
123
+
124
+ class InvalidFilenames < ArgumentError
125
+ NUMBER_OF_ERRORS_SHOWN = 20
126
+ def initialize(file_errors)
127
+ super <<~MSG
128
+ Found #{file_errors.count} error(s).
129
+ The first #{[file_errors.count, NUMBER_OF_ERRORS_SHOWN].min} error(s):
130
+ #{file_errors.map(&:message).first(NUMBER_OF_ERRORS_SHOWN).join("\n")}
131
+
132
+ To use the LazyLoadable backend:
133
+ 1. Filenames must start with the locale.
134
+ 2. An underscore must separate the locale with any optional text that follows.
135
+ 3. The file must only contain translation data for the single locale.
136
+
137
+ Example:
138
+ "/config/locales/fr.yml" which contains:
139
+ ```yml
140
+ fr:
141
+ dog:
142
+ chien
143
+ ```
144
+ MSG
145
+ end
146
+ end
104
147
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'i18n/gettext'
2
4
 
3
5
  module I18n
@@ -16,8 +18,8 @@ module I18n
16
18
  msgsid
17
19
  end
18
20
 
19
- def gettext(msgid, options = {})
20
- I18n.t(msgid, { :default => msgid, :separator => '|' }.merge(options))
21
+ def gettext(msgid, options = EMPTY_HASH)
22
+ I18n.t(msgid, **{:default => msgid, :separator => '|'}.merge(options))
21
23
  end
22
24
  alias _ gettext
23
25
 
@@ -28,7 +28,7 @@ module_eval <<'..end src/poparser.ry modeval..id7a99570e05', 'src/poparser.ry',
28
28
  ret.gsub!(/\\"/, "\"")
29
29
  ret
30
30
  end
31
-
31
+
32
32
  def parse(str, data, ignore_fuzzy = true)
33
33
  @comments = []
34
34
  @data = data
@@ -64,7 +64,7 @@ module_eval <<'..end src/poparser.ry modeval..id7a99570e05', 'src/poparser.ry',
64
64
  str = $'
65
65
  when /\A\#(.*)/
66
66
  @q.push [:COMMENT, $&]
67
- str = $'
67
+ str = $'
68
68
  when /\A\"(.*)\"/
69
69
  @q.push [:STRING, $1]
70
70
  str = $'
@@ -73,7 +73,7 @@ module_eval <<'..end src/poparser.ry modeval..id7a99570e05', 'src/poparser.ry',
73
73
  #@q.push [:STRING, c]
74
74
  str = str[1..-1]
75
75
  end
76
- end
76
+ end
77
77
  @q.push [false, '$end']
78
78
  if $DEBUG
79
79
  @q.each do |a,b|
@@ -88,7 +88,7 @@ module_eval <<'..end src/poparser.ry modeval..id7a99570e05', 'src/poparser.ry',
88
88
  end
89
89
  @data
90
90
  end
91
-
91
+
92
92
  def next_token
93
93
  @q.shift
94
94
  end
@@ -101,11 +101,11 @@ module_eval <<'..end src/poparser.ry modeval..id7a99570e05', 'src/poparser.ry',
101
101
  @comments.clear
102
102
  @msgctxt = ""
103
103
  end
104
-
104
+
105
105
  def on_comment(comment)
106
106
  @fuzzy = true if (/fuzzy/ =~ comment)
107
107
  @comments << comment
108
- end
108
+ end
109
109
 
110
110
 
111
111
  ..end src/poparser.ry modeval..id7a99570e05
@@ -245,7 +245,7 @@ module_eval <<'.,.,', 'src/poparser.ry', 25
245
245
 
246
246
  module_eval <<'.,.,', 'src/poparser.ry', 48
247
247
  def _reduce_8( val, _values, result )
248
- if @fuzzy and $ignore_fuzzy
248
+ if @fuzzy and $ignore_fuzzy
249
249
  if val[1] != ""
250
250
  $stderr.print _("Warning: fuzzy message was ignored.\n")
251
251
  $stderr.print " msgid '#{val[1]}'\n"
data/lib/i18n/gettext.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module I18n
2
4
  module Gettext
3
5
  PLURAL_SEPARATOR = "\001"
@@ -2,23 +2,25 @@
2
2
  # http://github.com/mutoh/gettext/blob/f6566738b981fe0952548c421042ad1e0cdfb31e/lib/gettext/core_ext/string.rb
3
3
 
4
4
  module I18n
5
- INTERPOLATION_PATTERN = Regexp.union(
5
+ DEFAULT_INTERPOLATION_PATTERNS = [
6
6
  /%%/,
7
- /%\{(\w+)\}/, # matches placeholders like "%{foo}"
8
- /%<(\w+)>(.*?\d*\.?\d*[bBdiouxXeEfgGcps])/ # matches placeholders like "%<foo>.d"
9
- )
7
+ /%\{([\w|]+)\}/, # matches placeholders like "%{foo} or %{foo|word}"
8
+ /%<(\w+)>([^\d]*?\d*\.?\d*[bBdiouxXeEfgGcps])/ # matches placeholders like "%<foo>.d"
9
+ ].freeze
10
+ INTERPOLATION_PATTERN = Regexp.union(DEFAULT_INTERPOLATION_PATTERNS)
11
+ deprecate_constant :INTERPOLATION_PATTERN
10
12
 
11
13
  class << self
12
14
  # Return String or raises MissingInterpolationArgument exception.
13
15
  # Missing argument's logic is handled by I18n.config.missing_interpolation_argument_handler.
14
16
  def interpolate(string, values)
15
- raise ReservedInterpolationKey.new($1.to_sym, string) if string =~ RESERVED_KEYS_PATTERN
17
+ raise ReservedInterpolationKey.new($1.to_sym, string) if string =~ I18n.reserved_keys_pattern
16
18
  raise ArgumentError.new('Interpolation values must be a Hash.') unless values.kind_of?(Hash)
17
19
  interpolate_hash(string, values)
18
20
  end
19
21
 
20
22
  def interpolate_hash(string, values)
21
- string.gsub(INTERPOLATION_PATTERN) do |match|
23
+ string.gsub(Regexp.union(config.interpolation_patterns)) do |match|
22
24
  if match == '%%'
23
25
  '%'
24
26
  else
@@ -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 [I18n.default_locale] by default but can be
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, :"en-US", :en]
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)
@@ -46,7 +39,7 @@
46
39
  # fallbacks[:"ar-PS"] # => [:"ar-PS", :ar, :"he-IL", :he, :"en-US", :en]
47
40
  # fallbacks[:"ar-EG"] # => [:"ar-EG", :ar, :"en-US", :en]
48
41
  #
49
- # # 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
50
43
  # fallbacks.map(:sms => [:"se-FI", :"fi-FI"])
51
44
  # fallbacks[:sms] # => [:sms, :"se-FI", :se, :"fi-FI", :fi, :"en-US", :en]
52
45
 
@@ -56,40 +49,48 @@ module I18n
56
49
  def initialize(*mappings)
57
50
  @map = {}
58
51
  map(mappings.pop) if mappings.last.is_a?(Hash)
59
- self.defaults = mappings.empty? ? [I18n.default_locale.to_sym] : mappings
52
+ self.defaults = mappings.empty? ? [] : mappings
60
53
  end
61
54
 
62
55
  def defaults=(defaults)
63
- @defaults = defaults.map { |default| compute(default, false) }.flatten
56
+ @defaults = defaults.flat_map { |default| compute(default, false) }
64
57
  end
65
58
  attr_reader :defaults
66
59
 
67
60
  def [](locale)
68
61
  raise InvalidLocale.new(locale) if locale.nil?
62
+ raise Disabled.new('fallback#[]') if locale == false
69
63
  locale = locale.to_sym
70
64
  super || store(locale, compute(locale))
71
65
  end
72
66
 
73
- def map(mappings)
74
- mappings.each do |from, to|
75
- from, to = from.to_sym, Array(to)
76
- to.each do |_to|
77
- @map[from] ||= []
78
- @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
79
76
  end
77
+ else
78
+ @map.map(*args, &block)
80
79
  end
81
80
  end
82
81
 
83
82
  protected
84
83
 
85
84
  def compute(tags, include_defaults = true, exclude = [])
86
- result = Array(tags).collect do |tag|
85
+ result = Array(tags).flat_map do |tag|
87
86
  tags = I18n::Locale::Tag.tag(tag).self_and_parents.map! { |t| t.to_sym } - exclude
88
87
  tags.each { |_tag| tags += compute(@map[_tag], false, exclude + tags) if @map[_tag] }
89
88
  tags
90
- end.flatten
89
+ end
91
90
  result.push(*defaults) if include_defaults
92
- result.uniq.compact
91
+ result.uniq!
92
+ result.compact!
93
+ result
93
94
  end
94
95
  end
95
96
  end
@@ -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
@@ -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,8 +23,7 @@ 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
29
  test "available_locales memoizes when set explicitely" do
@@ -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
@@ -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,10 @@ 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}') }
110
115
  end
111
116
 
112
117
  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,40 @@ 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 abbreviated and uppercased day name format it returns the correct abbreviated day name in upcase" do
38
+ assert_equal 'sa'.upcase, I18n.l(@date, :format => '%^a', :locale => :de)
39
+ end
40
+
34
41
  test "localize Date: given a month name format it returns the correct month name" do
35
42
  assert_equal 'März', I18n.l(@date, :format => '%B', :locale => :de)
36
43
  end
37
44
 
45
+ test "localize Date: given a uppercased month name format it returns the correct month name in upcase" do
46
+ assert_equal 'märz'.upcase, I18n.l(@date, :format => '%^B', :locale => :de)
47
+ end
48
+
38
49
  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)
50
+ assert_equal 'Mär', I18n.l(@date, :format => '%b', :locale => :de)
51
+ end
52
+
53
+ test "localize Date: given an abbreviated and uppercased month name format it returns the correct abbreviated month name in upcase" do
54
+ assert_equal 'mär'.upcase, I18n.l(@date, :format => '%^b', :locale => :de)
55
+ end
56
+
57
+ test "localize Date: given a date format with the month name upcased it returns the correct value" do
58
+ assert_equal '1. FEBRUAR 2008', I18n.l(::Date.new(2008, 2, 1), :format => "%-d. %^B %Y", :locale => :de)
59
+ end
60
+
61
+ test "localize Date: given missing translations it returns the correct error message" do
62
+ assert_equal 'translation missing: fr.date.abbr_month_names', I18n.l(@date, :format => '%b', :locale => :fr)
41
63
  end
42
64
 
43
65
  test "localize Date: given an unknown format it does not fail" do
@@ -46,9 +68,9 @@ module I18n
46
68
 
47
69
  test "localize Date: does not modify the options hash" do
48
70
  options = { :format => '%b', :locale => :de }
49
- assert_equal 'Mar', I18n.l(@date, options)
71
+ assert_equal 'Mär', I18n.l(@date, **options)
50
72
  assert_equal({ :format => '%b', :locale => :de }, options)
51
- assert_nothing_raised { I18n.l(@date, options.freeze) }
73
+ assert_nothing_raised { I18n.l(@date, **options.freeze) }
52
74
  end
53
75
 
54
76
  test "localize Date: given nil with default value it returns default" do
@@ -56,15 +78,15 @@ module I18n
56
78
  end
57
79
 
58
80
  test "localize Date: given nil it raises I18n::ArgumentError" do
59
- assert_raise(I18n::ArgumentError) { I18n.l(nil) }
81
+ assert_raises(I18n::ArgumentError) { I18n.l(nil) }
60
82
  end
61
83
 
62
84
  test "localize Date: given a plain Object it raises I18n::ArgumentError" do
63
- assert_raise(I18n::ArgumentError) { I18n.l(Object.new) }
85
+ assert_raises(I18n::ArgumentError) { I18n.l(Object.new) }
64
86
  end
65
87
 
66
88
  test "localize Date: given a format is missing it raises I18n::MissingTranslationData" do
67
- assert_raise(I18n::MissingTranslationData) { I18n.l(@date, :format => :missing) }
89
+ assert_raises(I18n::MissingTranslationData) { I18n.l(@date, :format => :missing) }
68
90
  end
69
91
 
70
92
  test "localize Date: it does not alter the format string" do
@@ -85,7 +107,7 @@ module I18n
85
107
  :day_names => %w(Sonntag Montag Dienstag Mittwoch Donnerstag Freitag Samstag),
86
108
  :abbr_day_names => %w(So Mo Di Mi Do Fr Sa),
87
109
  :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)
110
+ :abbr_month_names => %w(Jan Feb Mär Apr Mai Jun Jul Aug Sep Okt Nov Dez).unshift(nil)
89
111
  }
90
112
  }
91
113
  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