i18n-inflector 2.2.0 → 2.3.0

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.
@@ -191,7 +191,7 @@ module I18n
191
191
  # @note If +kind+ begins with the +@+ symbol then the variant of this method
192
192
  # operating on strict kinds will be called ({I18n::Inflector::API_Strict#inflected_locales})
193
193
  def inflected_locales(kind=nil)
194
- if kind.to_s[0..0] == Markers::PATTERN
194
+ if kind.to_s[0..0] == Markers::STRICT_KIND
195
195
  strict.inflected_locales(kind.to_s[1..-1])
196
196
  else
197
197
  (super + strict.inflected_locales(kind)).uniq
@@ -216,7 +216,7 @@ module I18n
216
216
  # @param [Symbol] locale the locale identifier
217
217
  # @return [Boolean] +true+ if the given +kind+ exists, +false+ otherwise
218
218
  def has_kind?(kind, locale=nil)
219
- if kind.to_s[0..0] == Markers::PATTERN
219
+ if kind.to_s[0..0] == Markers::STRICT_KIND
220
220
  return strict.has_kind?(kind.to_s[1..-1], locale)
221
221
  end
222
222
  super
@@ -242,7 +242,7 @@ module I18n
242
242
  # there is no default token
243
243
  def default_token(kind, locale=nil)
244
244
  return nil if (kind.nil? || kind.to_s.empty?)
245
- if kind.to_s[0..0] == Markers::PATTERN
245
+ if kind.to_s[0..0] == Markers::STRICT_KIND
246
246
  return strict.default_token(kind.to_s[1..-1], locale)
247
247
  end
248
248
  super
@@ -285,7 +285,7 @@ module I18n
285
285
  unless kind.nil?
286
286
  kind = kind.to_s
287
287
  reutrn false if kind.empty?
288
- if kind[0..0] == Markers::PATTERN
288
+ if kind[0..0] == Markers::STRICT_KIND
289
289
  return strict.has_alias?(token, kind[1..-1], locale)
290
290
  end
291
291
  kind = kind.to_sym
@@ -331,7 +331,7 @@ module I18n
331
331
  unless kind.nil?
332
332
  kind = kind.to_s
333
333
  return false if kind.empty?
334
- if kind[0..0] == Markers::PATTERN
334
+ if kind[0..0] == Markers::STRICT_KIND
335
335
  return strict.has_true_token?(token, kind[1..-1], locale)
336
336
  end
337
337
  kind = kind.to_sym
@@ -377,7 +377,7 @@ module I18n
377
377
  unless kind.nil?
378
378
  kind = kind.to_s
379
379
  return false if kind.empty?
380
- if kind[0..0] == Markers::PATTERN
380
+ if kind[0..0] == Markers::STRICT_KIND
381
381
  return strict.has_token?(token, kind[1..-1], locale)
382
382
  end
383
383
  kind = kind.to_sym
@@ -427,7 +427,7 @@ module I18n
427
427
  unless kind.nil?
428
428
  kind = kind.to_s
429
429
  return nil if kind.empty?
430
- if kind[0..0] == Markers::PATTERN
430
+ if kind[0..0] == Markers::STRICT_KIND
431
431
  return strict.true_token(token, kind[1..-1], locale)
432
432
  end
433
433
  kind = kind.to_sym
@@ -472,7 +472,7 @@ module I18n
472
472
  unless kind.nil?
473
473
  kind = kind.to_s
474
474
  return nil if kind.empty?
475
- if kind[0..0] == Markers::PATTERN
475
+ if kind[0..0] == Markers::STRICT_KIND
476
476
  return strict.kind(token, kind[1..-1], locale)
477
477
  end
478
478
  kind = kind.to_sym
@@ -514,7 +514,7 @@ module I18n
514
514
  unless kind.nil?
515
515
  kind = kind.to_s
516
516
  return {} if kind.empty?
517
- if kind[0..0] == Markers::PATTERN
517
+ if kind[0..0] == Markers::STRICT_KIND
518
518
  return strict.tokens(kind[1..-1], locale)
519
519
  end
520
520
  kind = kind.to_sym
@@ -555,7 +555,7 @@ module I18n
555
555
  unless kind.nil?
556
556
  kind = kind.to_s
557
557
  return {} if kind.empty?
558
- if kind[0..0] == Markers::PATTERN
558
+ if kind[0..0] == Markers::STRICT_KIND
559
559
  return strict.tokens_raw(kind[1..-1], locale)
560
560
  end
561
561
  kind = kind.to_sym
@@ -593,7 +593,7 @@ module I18n
593
593
  unless kind.nil?
594
594
  kind = kind.to_s
595
595
  return {} if kind.empty?
596
- if kind[0..0] == Markers::PATTERN
596
+ if kind[0..0] == Markers::STRICT_KIND
597
597
  return strict.tokens_true(kind[1..-1], locale)
598
598
  end
599
599
  kind = kind.to_sym
@@ -627,7 +627,7 @@ module I18n
627
627
  unless kind.nil?
628
628
  kind = kind.to_s
629
629
  return nil if kind.empty?
630
- if kind[0..0] == Markers::PATTERN
630
+ if kind[0..0] == Markers::STRICT_KIND
631
631
  return strict.aliases(kind[1..-1], locale)
632
632
  end
633
633
  kind = kind.to_sym
@@ -679,7 +679,7 @@ module I18n
679
679
  unless kind.nil?
680
680
  kind = kind.to_s
681
681
  return nil if kind.empty?
682
- if kind[0..0] == Markers::PATTERN
682
+ if kind[0..0] == Markers::STRICT_KIND
683
683
  return strict.token_description(token, kind[1..-1], locale)
684
684
  end
685
685
  kind = kind.to_sym
@@ -735,7 +735,7 @@ module I18n
735
735
  def tkl_args(args)
736
736
  token, kind, locale = case args.count
737
737
  when 1 then [args[0], nil, nil]
738
- when 2 then args[1].to_s[0..0] == Markers::PATTERN ? [args[0], args[1], nil] : [args[0], nil, args[1]]
738
+ when 2 then args[1].to_s[0..0] == Markers::STRICT_KIND ? [args[0], args[1], nil] : [args[0], nil, args[1]]
739
739
  when 3 then args
740
740
  else raise I18n::ArgumentError.new("wrong number of arguments: #{args.count} for (1..3)")
741
741
  end
@@ -74,7 +74,7 @@ module I18n
74
74
  translated_string = super
75
75
 
76
76
  # generate a pattern from key-based inflection object
77
- if (translated_string.is_a?(Hash) && key.to_s[0..0] == InflectorCfg::Markers::PATTERN)
77
+ if (translated_string.is_a?(Hash) && key.to_s[0..0] == InflectorCfg::Markers::STRICT_KIND)
78
78
  translated_string = @inflector.key_to_pattern(translated_string)
79
79
  end
80
80
 
@@ -344,7 +344,7 @@ module I18n
344
344
  subdb = idb
345
345
  strict_kind = nil
346
346
  orig_kind = kind
347
- if kind.to_s[0..0] == InflectorCfg::Markers::PATTERN
347
+ if kind.to_s[0..0] == InflectorCfg::Markers::STRICT_KIND
348
348
  kind = kind.to_s[1..-1]
349
349
  next if kind.empty?
350
350
  kind = kind.to_sym
@@ -63,10 +63,12 @@ module I18n
63
63
  # giving the shape for a pattern and its elements.
64
64
  module Markers
65
65
 
66
- # A character that is used to mark pattern
67
- # and a strict kind.
66
+ # A character that is used to mark pattern.
68
67
  PATTERN = '@'
69
68
 
69
+ # A character that is used to mark a strict kind.
70
+ STRICT_KIND = '@'
71
+
70
72
  # A character that is used to open a pattern.
71
73
  PATTERN_BEGIN = '{'
72
74
 
@@ -109,18 +111,22 @@ module I18n
109
111
  # A character used to mark patterns as complex
110
112
  # and to separate token groups assigned to different
111
113
  # strict kinds.
112
- AND = '+'
114
+ AND = '+'
113
115
 
114
116
  # A character that is used to separate tokens
115
117
  # or token groups within a pattern.
116
- OR = '|'
118
+ OR = '|'
117
119
 
118
120
  # A character used to assign value to a token
119
121
  # or a group of tokens.
120
- ASSIGN = ':'
122
+ ASSIGN = ':'
123
+
124
+ # A character used to create a virtual token
125
+ # that always matches.
126
+ WILDCARD = '*'
121
127
 
122
128
  # All token groups operators.
123
- ALL = Config.all_consts(self)
129
+ ALL = Config.all_consts(self)
124
130
 
125
131
  end # module Tokens
126
132
 
@@ -129,13 +135,13 @@ module I18n
129
135
  module Token
130
136
 
131
137
  # A character used to separate multiple tokens.
132
- OR = ','
138
+ OR = ','
133
139
 
134
140
  # A character used to mark tokens as negative.
135
- NOT = '!'
141
+ NOT = '!'
136
142
 
137
143
  # All token operators.
138
- ALL = Config.all_consts(self)
144
+ ALL = Config.all_consts(self)
139
145
 
140
146
  end # module Token
141
147
 
@@ -164,7 +170,7 @@ module I18n
164
170
  OPTION = DB
165
171
 
166
172
  # Reserved characters in token identifiers placed in patterns.
167
- PATTERN = OPTION
173
+ PATTERN = OPTION - [Operators::Tokens::WILDCARD]
168
174
 
169
175
  # This module contains constants defining
170
176
  # regular expressions for reserved characters
@@ -276,7 +282,7 @@ module I18n
276
282
  # @private
277
283
  PATTERN_MARKER = Config::Markers::PATTERN
278
284
  # @private
279
- NAMED_MARKER = Config::Markers::PATTERN
285
+ NAMED_MARKER = Config::Markers::STRICT_KIND
280
286
  # @private
281
287
  ALIAS_MARKER = Config::Markers::ALIAS
282
288
  # @private
@@ -75,7 +75,7 @@ module I18n
75
75
  def message
76
76
  kind = @kind.to_s
77
77
  unless kind.empty?
78
- if kind[0..0] == I18n::Inflector::Config::Markers::PATTERN
78
+ if kind[0..0] == I18n::Inflector::Config::Markers::STRICT_KIND
79
79
  kindmsg = ":#{kind} (or :#{kind[1..-1]})"
80
80
  else
81
81
  kindmsg = kind.to_sym.inspect
@@ -164,7 +164,7 @@ module I18n
164
164
  end
165
165
 
166
166
  # This is raised when a complex inflection pattern is malformed
167
- # and cannot be reduced to regular patterns.
167
+ # and cannot be reduced to set of regular patterns.
168
168
  class ComplexPatternMalformed < InflectionPatternException
169
169
 
170
170
  def initialize(locale, pattern, token, complex_kind)
@@ -22,6 +22,17 @@ module I18n
22
22
  end
23
23
  end
24
24
 
25
+ # @version 2.3
26
+ # @api public
27
+ #
28
+ # This module contains inflection classes and modules for enabling
29
+ # the inflection support in I18n translations.
30
+ # It is used by the module called {I18n::Backend::Inflector}
31
+ # that overwrites the translate method from the Simple backend
32
+ # so it will interpolate additional inflection data present
33
+ # in translations.
34
+ #
35
+ # @see file:USAGE
25
36
  module Inflector
26
37
 
27
38
  end # module Inflector
@@ -87,6 +87,7 @@ module I18n
87
87
  found = nil
88
88
  default_value = nil
89
89
  tb_raised = nil
90
+ wildcard_value = nil
90
91
 
91
92
  # leave escaped pattern as-is
92
93
  unless pattern_fix.empty?
@@ -114,15 +115,15 @@ module I18n
114
115
  default_token = nil
115
116
  subdb = idb
116
117
  else
117
- sym_parsed_kind = (Markers::PATTERN + strict_kind).to_sym
118
+ sym_parsed_kind = (Markers::STRICT_KIND + strict_kind).to_sym
118
119
 
119
120
  if strict_kind.include?(Operators::Tokens::AND)
120
121
 
121
122
  # Complex markers processing
122
123
  begin
123
124
  result = interpolate_complex(strict_kind,
124
- pattern_content,
125
- locale, options)
125
+ pattern_content,
126
+ locale, options)
126
127
  rescue I18n::InflectionPatternException => e
127
128
  e.pattern = ext_pattern
128
129
  raise
@@ -175,6 +176,18 @@ module I18n
175
176
  next
176
177
  end
177
178
 
179
+ # unroll wildcard token
180
+ if ext_token == Operators::Tokens::WILDCARD
181
+
182
+ if parsed_kind.nil?
183
+ # wildcard for a regular kind that we do not know yet
184
+ wildcard_value = ext_value
185
+ else
186
+ # wildcard for a known strict or regular kind
187
+ ext_token = subdb.get_true_tokens(parsed_kind).keys.join(Operators::Token::OR)
188
+ end
189
+ end
190
+
178
191
  # split tokens from group if comma is present and put into fast list
179
192
  ext_token.split(Operators::Token::OR).each do |t|
180
193
  # token name corrupted
@@ -233,7 +246,7 @@ module I18n
233
246
  tokens[t] = true
234
247
  default_value = ext_value if t == default_token
235
248
  end
236
- end
249
+ end # token group processing
237
250
 
238
251
  # self-explanatory
239
252
  if (tokens.empty? && negatives.empty?)
@@ -252,7 +265,14 @@ module I18n
252
265
 
253
266
  # get passed token from options or from a default token
254
267
  if passed_kinds.has_key?(expected_kind)
255
- passed_token = passed_kinds[expected_kind]
268
+ passed_token = passed_kinds[expected_kind]
269
+ if passed_token.is_a?(Method)
270
+ passed_token = passed_token.call { next expected_kind, locale }
271
+ passed_kinds[expected_kind] = passed_token # cache the result
272
+ elsif passed_token.is_a?(Proc)
273
+ passed_token = passed_token.call(expected_kind, locale)
274
+ passed_kinds[expected_kind] = passed_token # cache the result
275
+ end
256
276
  orig_passed_token = passed_token
257
277
  # validate passed token's name
258
278
  if Reserved::Tokens.invalid?(passed_token, :OPTION)
@@ -278,6 +298,14 @@ module I18n
278
298
  passed_token = default_token if passed_token.nil? && unknown_defaults
279
299
  end
280
300
 
301
+ # handle memorized wildcard waiting for a kind
302
+ if !wildcard_value.nil? && !parsed_kind.nil?
303
+ found = passed_token
304
+ result = wildcard_value
305
+ wildcard_value = nil
306
+ break
307
+ end
308
+
281
309
  # throw the value if the given option matches one of the tokens from group
282
310
  # or negatively matches one of the negated tokens
283
311
  case negatives.count
@@ -295,6 +323,33 @@ module I18n
295
323
 
296
324
  # RESULTS PROCESSING
297
325
 
326
+ # handle memorized wildcard token
327
+ # when there was no way to deduce a token or a kind
328
+ # it's just for regular kinds
329
+ unless (wildcard_value.nil? || passed_kinds.nil?)
330
+ parsed_kind = nil
331
+ found = nil
332
+ passed_kinds.each do |k, ot|
333
+ t = subdb.get_true_token(ot, k)
334
+ if Reserved::Tokens.invalid?(t, :OPTION)
335
+ raise I18n::InvalidInflectionOption.new(locale, ext_pattern, ot) if raises
336
+ next
337
+ end
338
+ unless t.nil?
339
+ found = t
340
+ parsed_kind = k
341
+ break
342
+ end
343
+ end
344
+ unless (parsed_kind.nil? || found.nil?)
345
+ result = wildcard_value
346
+ wildcard_value = nil
347
+ else
348
+ found = nil
349
+ parsed_kind = nil
350
+ end
351
+ end
352
+
298
353
  # if there was no hit for that option
299
354
  if result.nil?
300
355
  raise tb_raised unless tb_raised.nil?
@@ -307,10 +362,22 @@ module I18n
307
362
  # the pattern with a value picked for the default
308
363
  # token for that kind if a default token was present
309
364
  # in a pattern
310
- result = (excluded_defaults &&
311
- !parsed_kind.nil? &&
312
- subdb.has_token?(passed_kinds[parsed_kind], parsed_kind)) ?
313
- default_value : nil
365
+ if (excluded_defaults && !parsed_kind.nil?)
366
+ expected_kind = sym_parsed_kind
367
+ expected_kind = parsed_kind unless passed_kinds.has_key?(expected_kind)
368
+ t = passed_kinds[expected_kind]
369
+ if t.is_a?(Method)
370
+ t = t.call { next expected_kind, locale }
371
+ passed_kinds[expected_kind] = t # cache the result
372
+ elsif t.is_a?(Proc)
373
+ t = t.call(expected_kind, locale)
374
+ passed_kinds[expected_kind] = t # cache the result
375
+ end
376
+ if Reserved::Tokens.invalid?(t, :OPTION)
377
+ raise I18n::InvalidInflectionOption.new(locale, ext_pattern, t) if raises
378
+ end
379
+ result = subdb.has_token?(t, parsed_kind) ? default_value : nil
380
+ end
314
381
 
315
382
  # interpolate loud tokens
316
383
  elsif result == Markers::LOUD_VALUE
@@ -364,7 +431,7 @@ module I18n
364
431
  r = interpolate_core(Markers::PATTERN + kinds.next.to_s + Markers::PATTERN_BEGIN + token.to_s +
365
432
  Operators::Tokens::ASSIGN + value.to_s + Operators::Tokens::OR +
366
433
  Markers::PATTERN + Markers::PATTERN_END, locale, options)
367
- break if r == Markers::PATTERN
434
+ break if r == Markers::PATTERN # using this marker only as a helper to indicate empty result!
368
435
  else
369
436
  r = interpolate_core(Markers::PATTERN + kinds.next.to_s + Markers::PATTERN_BEGIN + token.to_s +
370
437
  Operators::Tokens::ASSIGN + value.to_s + Markers::PATTERN_END, locale, options)