i18n-inflector 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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)