i18n 1.8.10 → 1.14.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -45,30 +45,30 @@ module I18n
45
45
  "Ç"=>"C", "È"=>"E", "É"=>"E", "Ê"=>"E", "Ë"=>"E", "Ì"=>"I", "Í"=>"I",
46
46
  "Î"=>"I", "Ï"=>"I", "Ð"=>"D", "Ñ"=>"N", "Ò"=>"O", "Ó"=>"O", "Ô"=>"O",
47
47
  "Õ"=>"O", "Ö"=>"O", "×"=>"x", "Ø"=>"O", "Ù"=>"U", "Ú"=>"U", "Û"=>"U",
48
- "Ü"=>"U", "Ý"=>"Y", "Þ"=>"Th", "ß"=>"ss", "à"=>"a", "á"=>"a", "â"=>"a",
49
- "ã"=>"a", "ä"=>"a", "å"=>"a", "æ"=>"ae", "ç"=>"c", "è"=>"e", "é"=>"e",
50
- "ê"=>"e", "ë"=>"e", "ì"=>"i", "í"=>"i", "î"=>"i", "ï"=>"i", "ð"=>"d",
51
- "ñ"=>"n", "ò"=>"o", "ó"=>"o", "ô"=>"o", "õ"=>"o", "ö"=>"o", "ø"=>"o",
52
- "ù"=>"u", "ú"=>"u", "û"=>"u", "ü"=>"u", "ý"=>"y", "þ"=>"th", "ÿ"=>"y",
53
- "Ā"=>"A", "ā"=>"a", "Ă"=>"A", "ă"=>"a", "Ą"=>"A", "ą"=>"a", "Ć"=>"C",
54
- "ć"=>"c", "Ĉ"=>"C", "ĉ"=>"c", "Ċ"=>"C", "ċ"=>"c", "Č"=>"C", "č"=>"c",
55
- "Ď"=>"D", "ď"=>"d", "Đ"=>"D", "đ"=>"d", "Ē"=>"E", "ē"=>"e", "Ĕ"=>"E",
56
- "ĕ"=>"e", "Ė"=>"E", "ė"=>"e", "Ę"=>"E", "ę"=>"e", "Ě"=>"E", "ě"=>"e",
57
- "Ĝ"=>"G", "ĝ"=>"g", "Ğ"=>"G", "ğ"=>"g", "Ġ"=>"G", "ġ"=>"g", "Ģ"=>"G",
58
- "ģ"=>"g", "Ĥ"=>"H", "ĥ"=>"h", "Ħ"=>"H", "ħ"=>"h", "Ĩ"=>"I", "ĩ"=>"i",
59
- "Ī"=>"I", "ī"=>"i", "Ĭ"=>"I", "ĭ"=>"i", "Į"=>"I", "į"=>"i", "İ"=>"I",
60
- "ı"=>"i", "IJ"=>"IJ", "ij"=>"ij", "Ĵ"=>"J", "ĵ"=>"j", "Ķ"=>"K", "ķ"=>"k",
61
- "ĸ"=>"k", "Ĺ"=>"L", "ĺ"=>"l", "Ļ"=>"L", "ļ"=>"l", "Ľ"=>"L", "ľ"=>"l",
62
- "Ŀ"=>"L", "ŀ"=>"l", "Ł"=>"L", "ł"=>"l", "Ń"=>"N", "ń"=>"n", "Ņ"=>"N",
63
- "ņ"=>"n", "Ň"=>"N", "ň"=>"n", "ʼn"=>"'n", "Ŋ"=>"NG", "ŋ"=>"ng",
64
- "Ō"=>"O", "ō"=>"o", "Ŏ"=>"O", "ŏ"=>"o", "Ő"=>"O", "ő"=>"o", "Œ"=>"OE",
65
- "œ"=>"oe", "Ŕ"=>"R", "ŕ"=>"r", "Ŗ"=>"R", "ŗ"=>"r", "Ř"=>"R", "ř"=>"r",
66
- "Ś"=>"S", "ś"=>"s", "Ŝ"=>"S", "ŝ"=>"s", "Ş"=>"S", "ş"=>"s", "Š"=>"S",
67
- "š"=>"s", "Ţ"=>"T", "ţ"=>"t", "Ť"=>"T", "ť"=>"t", "Ŧ"=>"T", "ŧ"=>"t",
68
- "Ũ"=>"U", "ũ"=>"u", "Ū"=>"U", "ū"=>"u", "Ŭ"=>"U", "ŭ"=>"u", "Ů"=>"U",
69
- "ů"=>"u", "Ű"=>"U", "ű"=>"u", "Ų"=>"U", "ų"=>"u", "Ŵ"=>"W", "ŵ"=>"w",
70
- "Ŷ"=>"Y", "ŷ"=>"y", "Ÿ"=>"Y", "Ź"=>"Z", "ź"=>"z", "Ż"=>"Z", "ż"=>"z",
71
- "Ž"=>"Z", "ž"=>"z"
48
+ "Ü"=>"U", "Ý"=>"Y", "Þ"=>"Th", "ß"=>"ss", ""=>"SS", "à"=>"a",
49
+ "á"=>"a", "â"=>"a", "ã"=>"a", "ä"=>"a", "å"=>"a", "æ"=>"ae", "ç"=>"c",
50
+ "è"=>"e", "é"=>"e", "ê"=>"e", "ë"=>"e", "ì"=>"i", "í"=>"i", "î"=>"i",
51
+ "ï"=>"i", "ð"=>"d", "ñ"=>"n", "ò"=>"o", "ó"=>"o", "ô"=>"o", "õ"=>"o",
52
+ "ö"=>"o", "ø"=>"o", "ù"=>"u", "ú"=>"u", "û"=>"u", "ü"=>"u", "ý"=>"y",
53
+ "þ"=>"th", "ÿ"=>"y", "Ā"=>"A", "ā"=>"a", "Ă"=>"A", "ă"=>"a", "Ą"=>"A",
54
+ "ą"=>"a", "Ć"=>"C", "ć"=>"c", "Ĉ"=>"C", "ĉ"=>"c", "Ċ"=>"C", "ċ"=>"c",
55
+ "Č"=>"C", "č"=>"c", "Ď"=>"D", "ď"=>"d", "Đ"=>"D", "đ"=>"d", "Ē"=>"E",
56
+ "ē"=>"e", "Ĕ"=>"E", "ĕ"=>"e", "Ė"=>"E", "ė"=>"e", "Ę"=>"E", "ę"=>"e",
57
+ "Ě"=>"E", "ě"=>"e", "Ĝ"=>"G", "ĝ"=>"g", "Ğ"=>"G", "ğ"=>"g", "Ġ"=>"G",
58
+ "ġ"=>"g", "Ģ"=>"G", "ģ"=>"g", "Ĥ"=>"H", "ĥ"=>"h", "Ħ"=>"H", "ħ"=>"h",
59
+ "Ĩ"=>"I", "ĩ"=>"i", "Ī"=>"I", "ī"=>"i", "Ĭ"=>"I", "ĭ"=>"i", "Į"=>"I",
60
+ "į"=>"i", "İ"=>"I", "ı"=>"i", "IJ"=>"IJ", "ij"=>"ij", "Ĵ"=>"J", "ĵ"=>"j",
61
+ "Ķ"=>"K", "ķ"=>"k", "ĸ"=>"k", "Ĺ"=>"L", "ĺ"=>"l", "Ļ"=>"L", "ļ"=>"l",
62
+ "Ľ"=>"L", "ľ"=>"l", "Ŀ"=>"L", "ŀ"=>"l", "Ł"=>"L", "ł"=>"l", "Ń"=>"N",
63
+ "ń"=>"n", "Ņ"=>"N", "ņ"=>"n", "Ň"=>"N", "ň"=>"n", "ʼn"=>"'n", "Ŋ"=>"NG",
64
+ "ŋ"=>"ng", "Ō"=>"O", "ō"=>"o", "Ŏ"=>"O", "ŏ"=>"o", "Ő"=>"O", "ő"=>"o",
65
+ "Œ"=>"OE", "œ"=>"oe", "Ŕ"=>"R", "ŕ"=>"r", "Ŗ"=>"R", "ŗ"=>"r", "Ř"=>"R",
66
+ "ř"=>"r", "Ś"=>"S", "ś"=>"s", "Ŝ"=>"S", "ŝ"=>"s", "Ş"=>"S", "ş"=>"s",
67
+ "Š"=>"S", "š"=>"s", "Ţ"=>"T", "ţ"=>"t", "Ť"=>"T", "ť"=>"t", "Ŧ"=>"T",
68
+ "ŧ"=>"t", "Ũ"=>"U", "ũ"=>"u", "Ū"=>"U", "ū"=>"u", "Ŭ"=>"U", "ŭ"=>"u",
69
+ "Ů"=>"U", "ů"=>"u", "Ű"=>"U", "ű"=>"u", "Ų"=>"U", "ų"=>"u", "Ŵ"=>"W",
70
+ "ŵ"=>"w", "Ŷ"=>"Y", "ŷ"=>"y", "Ÿ"=>"Y", "Ź"=>"Z", "ź"=>"z", "Ż"=>"Z",
71
+ "ż"=>"z", "Ž"=>"Z", "ž"=>"z"
72
72
  }.freeze
73
73
 
74
74
  def initialize(rule = nil)
data/lib/i18n/backend.rb CHANGED
@@ -3,7 +3,6 @@
3
3
  module I18n
4
4
  module Backend
5
5
  autoload :Base, 'i18n/backend/base'
6
- autoload :InterpolationCompiler, 'i18n/backend/interpolation_compiler'
7
6
  autoload :Cache, 'i18n/backend/cache'
8
7
  autoload :CacheFile, 'i18n/backend/cache_file'
9
8
  autoload :Cascade, 'i18n/backend/cascade'
@@ -11,7 +10,9 @@ module I18n
11
10
  autoload :Fallbacks, 'i18n/backend/fallbacks'
12
11
  autoload :Flatten, 'i18n/backend/flatten'
13
12
  autoload :Gettext, 'i18n/backend/gettext'
13
+ autoload :InterpolationCompiler, 'i18n/backend/interpolation_compiler'
14
14
  autoload :KeyValue, 'i18n/backend/key_value'
15
+ autoload :LazyLoadable, 'i18n/backend/lazy_loadable'
15
16
  autoload :Memoize, 'i18n/backend/memoize'
16
17
  autoload :Metadata, 'i18n/backend/metadata'
17
18
  autoload :Pluralization, 'i18n/backend/pluralization'
data/lib/i18n/config.rb CHANGED
@@ -38,7 +38,7 @@ module I18n
38
38
  end
39
39
 
40
40
  # Returns an array of locales for which translations are available.
41
- # Unless you explicitely set these through I18n.available_locales=
41
+ # Unless you explicitly set these through I18n.available_locales=
42
42
  # the call will be delegated to the backend.
43
43
  def available_locales
44
44
  @@available_locales ||= nil
@@ -106,7 +106,7 @@ module I18n
106
106
  # if you don't care about arity.
107
107
  #
108
108
  # == Example:
109
- # You can supress raising an exception and return string instead:
109
+ # You can suppress raising an exception and return string instead:
110
110
  #
111
111
  # I18n.config.missing_interpolation_argument_handler = Proc.new do |key|
112
112
  # "#{key} is missing"
@@ -24,7 +24,7 @@ module I18n
24
24
  been set is likely to display text from the wrong locale to some users.
25
25
 
26
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)`
27
+ the desired locale explicitly with the `locale` argument, e.g. `I18n.#{method}(..., locale: :en)`
28
28
  MESSAGE
29
29
  end
30
30
  end
@@ -47,10 +47,12 @@ module I18n
47
47
 
48
48
  class MissingTranslation < ArgumentError
49
49
  module Base
50
+ PERMITTED_KEYS = [:scope, :default].freeze
51
+
50
52
  attr_reader :locale, :key, :options
51
53
 
52
54
  def initialize(locale, key, options = EMPTY_HASH)
53
- @key, @locale, @options = key, locale, options.dup
55
+ @key, @locale, @options = key, locale, options.slice(*PERMITTED_KEYS)
54
56
  options.each { |k, v| self.options[k] = v.inspect if v.is_a?(Proc) }
55
57
  end
56
58
 
@@ -61,8 +63,18 @@ module I18n
61
63
  end
62
64
 
63
65
  def message
64
- "translation missing: #{keys.join('.')}"
66
+ if (default = options[:default]).is_a?(Array) && default.any?
67
+ other_options = ([key, *default]).map { |k| normalized_option(k).prepend('- ') }.join("\n")
68
+ "Translation missing. Options considered were:\n#{other_options}"
69
+ else
70
+ "Translation missing: #{keys.join('.')}"
71
+ end
72
+ end
73
+
74
+ def normalized_option(key)
75
+ I18n.normalize_keys(locale, key, options[:scope]).join('.')
65
76
  end
77
+
66
78
  alias :to_s :message
67
79
 
68
80
  def to_exception
@@ -108,4 +120,38 @@ module I18n
108
120
  super "can not load translations from #{filename}, the file type #{type} is not known"
109
121
  end
110
122
  end
123
+
124
+ class UnsupportedMethod < ArgumentError
125
+ attr_reader :method, :backend_klass, :msg
126
+ def initialize(method, backend_klass, msg)
127
+ @method = method
128
+ @backend_klass = backend_klass
129
+ @msg = msg
130
+ super "#{backend_klass} does not support the ##{method} method. #{msg}"
131
+ end
132
+ end
133
+
134
+ class InvalidFilenames < ArgumentError
135
+ NUMBER_OF_ERRORS_SHOWN = 20
136
+ def initialize(file_errors)
137
+ super <<~MSG
138
+ Found #{file_errors.count} error(s).
139
+ The first #{[file_errors.count, NUMBER_OF_ERRORS_SHOWN].min} error(s):
140
+ #{file_errors.map(&:message).first(NUMBER_OF_ERRORS_SHOWN).join("\n")}
141
+
142
+ To use the LazyLoadable backend:
143
+ 1. Filenames must start with the locale.
144
+ 2. An underscore must separate the locale with any optional text that follows.
145
+ 3. The file must only contain translation data for the single locale.
146
+
147
+ Example:
148
+ "/config/locales/fr.yml" which contains:
149
+ ```yml
150
+ fr:
151
+ dog:
152
+ chien
153
+ ```
154
+ MSG
155
+ end
156
+ end
111
157
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # heavily based on Masao Mutoh's gettext String interpolation extension
2
4
  # http://github.com/mutoh/gettext/blob/f6566738b981fe0952548c421042ad1e0cdfb31e/lib/gettext/core_ext/string.rb
3
5
 
@@ -5,22 +7,32 @@ module I18n
5
7
  DEFAULT_INTERPOLATION_PATTERNS = [
6
8
  /%%/,
7
9
  /%\{([\w|]+)\}/, # matches placeholders like "%{foo} or %{foo|word}"
8
- /%<(\w+)>(.*?\d*\.?\d*[bBdiouxXeEfgGcps])/ # matches placeholders like "%<foo>.d"
10
+ /%<(\w+)>([^\d]*?\d*\.?\d*[bBdiouxXeEfgGcps])/ # matches placeholders like "%<foo>.d"
9
11
  ].freeze
10
12
  INTERPOLATION_PATTERN = Regexp.union(DEFAULT_INTERPOLATION_PATTERNS)
11
13
  deprecate_constant :INTERPOLATION_PATTERN
12
14
 
15
+ INTERPOLATION_PATTERNS_CACHE = Hash.new do |hash, patterns|
16
+ hash[patterns] = Regexp.union(patterns)
17
+ end
18
+ private_constant :INTERPOLATION_PATTERNS_CACHE
19
+
13
20
  class << self
14
21
  # Return String or raises MissingInterpolationArgument exception.
15
22
  # Missing argument's logic is handled by I18n.config.missing_interpolation_argument_handler.
16
23
  def interpolate(string, values)
17
- raise ReservedInterpolationKey.new($1.to_sym, string) if string =~ RESERVED_KEYS_PATTERN
24
+ raise ReservedInterpolationKey.new($1.to_sym, string) if string =~ I18n.reserved_keys_pattern
18
25
  raise ArgumentError.new('Interpolation values must be a Hash.') unless values.kind_of?(Hash)
19
26
  interpolate_hash(string, values)
20
27
  end
21
28
 
22
29
  def interpolate_hash(string, values)
23
- string.gsub(Regexp.union(config.interpolation_patterns)) do |match|
30
+ pattern = INTERPOLATION_PATTERNS_CACHE[config.interpolation_patterns]
31
+ interpolated = false
32
+
33
+ interpolated_string = string.gsub(pattern) do |match|
34
+ interpolated = true
35
+
24
36
  if match == '%%'
25
37
  '%'
26
38
  else
@@ -34,6 +46,8 @@ module I18n
34
46
  $3 ? sprintf("%#{$3}", value) : value
35
47
  end
36
48
  end
49
+
50
+ interpolated ? interpolated_string : string
37
51
  end
38
52
  end
39
53
  end
@@ -15,19 +15,12 @@
15
15
  # * all parent locales of a given locale (e.g. :es for :"es-MX") first,
16
16
  # * the current default locales and all of their parents second
17
17
  #
18
- # The default locales are set to [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"]
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
 
@@ -71,13 +64,18 @@ module I18n
71
64
  super || store(locale, compute(locale))
72
65
  end
73
66
 
74
- def map(mappings)
75
- mappings.each do |from, to|
76
- from, to = from.to_sym, Array(to)
77
- to.each do |_to|
78
- @map[from] ||= []
79
- @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
80
76
  end
77
+ else
78
+ @map.map(*args, &block)
81
79
  end
82
80
  end
83
81
 
@@ -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
@@ -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
@@ -41,7 +41,7 @@ module I18n
41
41
  end
42
42
 
43
43
  test "interpolation: given values but missing a key it raises I18n::MissingInterpolationArgument" do
44
- assert_raise(I18n::MissingInterpolationArgument) do
44
+ assert_raises(I18n::MissingInterpolationArgument) do
45
45
  interpolate(:default => '%{foo}', :bar => 'bar')
46
46
  end
47
47
  end
@@ -77,13 +77,13 @@ module I18n
77
77
 
78
78
  if Object.const_defined?(:Encoding)
79
79
  test "interpolation: given a euc-jp translation and a utf-8 value it raises Encoding::CompatibilityError" do
80
- assert_raise(Encoding::CompatibilityError) do
80
+ assert_raises(Encoding::CompatibilityError) do
81
81
  interpolate(:default => euc_jp('こんにちは、%{name}さん!'), :name => 'ゆきひろ')
82
82
  end
83
83
  end
84
84
 
85
85
  test "interpolation: given a utf-8 translation and a euc-jp value it raises Encoding::CompatibilityError" do
86
- assert_raise(Encoding::CompatibilityError) do
86
+ assert_raises(Encoding::CompatibilityError) do
87
87
  interpolate(:default => 'こんにちは、%{name}さん!', :name => euc_jp('ゆきひろ'))
88
88
  end
89
89
  end
@@ -108,10 +108,10 @@ module I18n
108
108
  end
109
109
 
110
110
  test "interpolation: given a translations containing a reserved key it raises I18n::ReservedInterpolationKey" do
111
- assert_raise(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{exception_handler}') }
112
- assert_raise(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{default}') }
113
- assert_raise(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{separator}') }
114
- assert_raise(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{scope}') }
111
+ assert_raises(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{exception_handler}') }
112
+ assert_raises(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{default}') }
113
+ assert_raises(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{separator}') }
114
+ assert_raises(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{scope}') }
115
115
  end
116
116
 
117
117
  test "interpolation: deep interpolation for default string" do
@@ -34,6 +34,11 @@ module I18n
34
34
  assert_equal 'Sa', I18n.l(@date, :format => '%a', :locale => :de)
35
35
  end
36
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
+
37
42
  test "localize Date: given an abbreviated and uppercased day name format it returns the correct abbreviated day name in upcase" do
38
43
  assert_equal 'sa'.upcase, I18n.l(@date, :format => '%^a', :locale => :de)
39
44
  end
@@ -59,7 +64,7 @@ module I18n
59
64
  end
60
65
 
61
66
  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)
67
+ assert_equal 'Translation missing: fr.date.abbr_month_names', I18n.l(@date, :format => '%b', :locale => :fr)
63
68
  end
64
69
 
65
70
  test "localize Date: given an unknown format it does not fail" do
@@ -78,15 +83,15 @@ module I18n
78
83
  end
79
84
 
80
85
  test "localize Date: given nil it raises I18n::ArgumentError" do
81
- assert_raise(I18n::ArgumentError) { I18n.l(nil) }
86
+ assert_raises(I18n::ArgumentError) { I18n.l(nil) }
82
87
  end
83
88
 
84
89
  test "localize Date: given a plain Object it raises I18n::ArgumentError" do
85
- assert_raise(I18n::ArgumentError) { I18n.l(Object.new) }
90
+ assert_raises(I18n::ArgumentError) { I18n.l(Object.new) }
86
91
  end
87
92
 
88
93
  test "localize Date: given a format is missing it raises I18n::MissingTranslationData" do
89
- assert_raise(I18n::MissingTranslationData) { I18n.l(@date, :format => :missing) }
94
+ assert_raises(I18n::MissingTranslationData) { I18n.l(@date, :format => :missing) }
90
95
  end
91
96
 
92
97
  test "localize Date: it does not alter the format string" do
@@ -60,7 +60,7 @@ module I18n
60
60
  end
61
61
 
62
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)
63
+ assert_equal 'Translation missing: fr.date.abbr_month_names', I18n.l(@datetime, :format => '%b', :locale => :fr)
64
64
  end
65
65
 
66
66
  test "localize DateTime: given a meridian indicator format it returns the correct meridian indicator" do
@@ -78,7 +78,7 @@ module I18n
78
78
  end
79
79
 
80
80
  test "localize DateTime: given a format is missing it raises I18n::MissingTranslationData" do
81
- assert_raise(I18n::MissingTranslationData) { I18n.l(@datetime, :format => :missing) }
81
+ assert_raises(I18n::MissingTranslationData) { I18n.l(@datetime, :format => :missing) }
82
82
  end
83
83
 
84
84
  protected
@@ -74,6 +74,7 @@ module I18n
74
74
  arg.strftime('%a, %d %b %Y')
75
75
  when Hash
76
76
  arg.delete(:fallback_in_progress)
77
+ arg.delete(:fallback_original_locale)
77
78
  arg.inspect
78
79
  else
79
80
  arg.inspect
@@ -61,7 +61,7 @@ module I18n
61
61
  end
62
62
 
63
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)
64
+ assert_equal 'Translation missing: fr.date.abbr_month_names', I18n.l(@time, :format => '%b', :locale => :fr)
65
65
  end
66
66
 
67
67
  test "localize Time: given a meridian indicator format it returns the correct meridian indicator" do
@@ -79,7 +79,7 @@ module I18n
79
79
  end
80
80
 
81
81
  test "localize Time: given a format is missing it raises I18n::MissingTranslationData" do
82
- assert_raise(I18n::MissingTranslationData) { I18n.l(@time, :format => :missing) }
82
+ assert_raises(I18n::MissingTranslationData) { I18n.l(@time, :format => :missing) }
83
83
  end
84
84
 
85
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
@@ -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
 
@@ -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
@@ -53,7 +53,13 @@ module I18n
53
53
 
54
54
 
55
55
  def self.filter_args(*args)
56
- args.map {|arg| arg.delete(:fallback_in_progress) if arg.is_a?(Hash) ; arg }.inspect
56
+ args.map do |arg|
57
+ if arg.is_a?(Hash)
58
+ arg.delete(:fallback_in_progress)
59
+ arg.delete(:fallback_original_locale)
60
+ end
61
+ arg
62
+ end.inspect
57
63
  end
58
64
  end
59
65
  end
data/lib/i18n/utils.rb ADDED
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module I18n
4
+ module Utils
5
+ class << self
6
+ if Hash.method_defined?(:except)
7
+ def except(hash, *keys)
8
+ hash.except(*keys)
9
+ end
10
+ else
11
+ def except(hash, *keys)
12
+ hash = hash.dup
13
+ keys.each { |k| hash.delete(k) }
14
+ hash
15
+ end
16
+ end
17
+
18
+ def deep_merge(hash, other_hash, &block)
19
+ deep_merge!(hash.dup, other_hash, &block)
20
+ end
21
+
22
+ def deep_merge!(hash, other_hash, &block)
23
+ hash.merge!(other_hash) do |key, this_val, other_val|
24
+ if this_val.is_a?(Hash) && other_val.is_a?(Hash)
25
+ deep_merge(this_val, other_val, &block)
26
+ elsif block_given?
27
+ yield key, this_val, other_val
28
+ else
29
+ other_val
30
+ end
31
+ end
32
+ end
33
+
34
+ def deep_symbolize_keys(hash)
35
+ hash.each_with_object({}) do |(key, value), result|
36
+ result[key.respond_to?(:to_sym) ? key.to_sym : key] = deep_symbolize_keys_in_object(value)
37
+ result
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def deep_symbolize_keys_in_object(value)
44
+ case value
45
+ when Hash
46
+ deep_symbolize_keys(value)
47
+ when Array
48
+ value.map { |e| deep_symbolize_keys_in_object(e) }
49
+ else
50
+ value
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
data/lib/i18n/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module I18n
4
- VERSION = "1.8.10"
4
+ VERSION = "1.14.1"
5
5
  end