i18n-inflector 2.1.0 → 2.2.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.
- data/ChangeLog +412 -0
- data/Manifest.txt +3 -0
- data/README.rdoc +38 -17
- data/docs/EXAMPLES +111 -22
- data/docs/HISTORY +37 -0
- data/docs/TODO +3 -27
- data/lib/i18n-inflector/api.rb +22 -234
- data/lib/i18n-inflector/api_strict.rb +1 -1
- data/lib/i18n-inflector/backend.rb +78 -23
- data/lib/i18n-inflector/config.rb +297 -0
- data/lib/i18n-inflector/errors.rb +184 -58
- data/lib/i18n-inflector/hset.rb +28 -0
- data/lib/i18n-inflector/inflection_data.rb +3 -1
- data/lib/i18n-inflector/inflection_data_strict.rb +3 -1
- data/lib/i18n-inflector/inflector.rb +1 -39
- data/lib/i18n-inflector/interpolate.rb +404 -0
- data/lib/i18n-inflector/lazy_enum.rb +52 -6
- data/lib/i18n-inflector/long_comments.rb +463 -157
- data/lib/i18n-inflector/options.rb +116 -20
- data/lib/i18n-inflector/version.rb +1 -1
- data/lib/i18n-inflector.rb +4 -1
- data/test/inflector_test.rb +179 -22
- data.tar.gz.sig +0 -0
- metadata +7 -4
- metadata.gz.sig +0 -0
data/docs/EXAMPLES
CHANGED
@@ -11,21 +11,21 @@ This data will be used in any further example:
|
|
11
11
|
|
12
12
|
@person:
|
13
13
|
i: "i"
|
14
|
-
|
14
|
+
u: "you"
|
15
15
|
he: "he"
|
16
16
|
she: "she"
|
17
17
|
it: "it"
|
18
|
-
|
18
|
+
you: @u
|
19
19
|
|
20
20
|
gender:
|
21
21
|
m: "male"
|
22
22
|
f: "female"
|
23
23
|
n: "neuter"
|
24
|
-
default:
|
24
|
+
default: n
|
25
25
|
|
26
26
|
|
27
27
|
welcome: "Dear @{f:Lady|m:Sir|n:You|All}!"
|
28
|
-
sayit: "@person{i:I|u:You|he:He|she:She|it:It}
|
28
|
+
sayit: "@person{i:I|u:You|he:He|she:She|it:It}{ }{i:am|u:are|he,she,it:is}"
|
29
29
|
tobe: "%{person} @person{i:am|u:are|he,she,it:is}"
|
30
30
|
|
31
31
|
|
@@ -49,7 +49,7 @@ This data will be used in any further example:
|
|
49
49
|
}})
|
50
50
|
|
51
51
|
I18n.backend.store_translations(:en, 'welcome' => 'Dear @{f:Lady|m:Sir|n:You|All}!')
|
52
|
-
I18n.backend.store_translations(:en, 'sayit' => '@person{i:I|u:You|he:He|she:She|it:It}
|
52
|
+
I18n.backend.store_translations(:en, 'sayit' => '@person{i:I|u:You|he:He|she:She|it:It}{ }{i:am|u:are|he,she,it:is}')
|
53
53
|
I18n.backend.store_translations(:en, 'tobe' => '%{person} @person{i:am|u:are|he,she,it:is}')
|
54
54
|
I18n.locale = :en
|
55
55
|
|
@@ -141,13 +141,17 @@ Getting all known strict kinds:
|
|
141
141
|
|
142
142
|
I18n.inflector.strict.kinds
|
143
143
|
#=> [:person]
|
144
|
-
|
144
|
+
|
145
145
|
Getting all known kinds for language 'pl':
|
146
146
|
|
147
147
|
I18n.inflector.kinds(:pl)
|
148
148
|
#=> []
|
149
|
-
|
150
|
-
|
149
|
+
|
150
|
+
=== Listing all known options
|
151
|
+
|
152
|
+
I18n.inflector.options.known
|
153
|
+
#=> [:inflector_cache_aware, :inflector_raises, :inflector_aliased_patterns,
|
154
|
+
# :inflector_unknown_defaults, :inflector_excluded_defaults]
|
151
155
|
|
152
156
|
== Real-life example for Polish language
|
153
157
|
|
@@ -163,7 +167,7 @@ prefixes and suffixes of words we're able make our patterns compact.
|
|
163
167
|
=== YAML
|
164
168
|
|
165
169
|
pl:
|
166
|
-
are_you_sure: "@{m,f:Jesteś pew}
|
170
|
+
are_you_sure: "@{m,f:Jesteś pew}{m:ien|f:na}{n:Na pewno}?"
|
167
171
|
|
168
172
|
i18n:
|
169
173
|
inflections:
|
@@ -173,27 +177,18 @@ prefixes and suffixes of words we're able make our patterns compact.
|
|
173
177
|
n: "forma bezosobowa"
|
174
178
|
masculine: @m
|
175
179
|
facet: @m
|
176
|
-
chłop: @m
|
177
180
|
chłopak: @m
|
178
|
-
chłopiec: @m
|
179
|
-
mąż: @m
|
180
181
|
feminine: @f
|
181
182
|
pani: @f
|
182
183
|
kobieta: @f
|
183
184
|
k: @f
|
184
185
|
dziewczyna: @f
|
185
|
-
baba: @f
|
186
|
-
babka: @f
|
187
|
-
facetka: @f
|
188
186
|
impersonal: @n
|
189
187
|
default: n
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
188
|
+
|
194
189
|
=== Code
|
195
190
|
|
196
|
-
# Using shorter form than YAML
|
191
|
+
# Using shorter form than listed as YAML
|
197
192
|
|
198
193
|
I18n.backend.store_translations(:pl, :i18n => { :inflections => { :gender =>
|
199
194
|
{ :f => 'f', :m=>'m', :n=>'n', :kobieta=>:@f, :facet => :@m, :default=>:n }}})
|
@@ -215,8 +210,102 @@ prefixes and suffixes of words we're able make our patterns compact.
|
|
215
210
|
#=> "Na pewno?"
|
216
211
|
|
217
212
|
# It would look like that without commas:
|
218
|
-
I18n.backend.store_translations(:pl, :are_you_sure => "@{m:Jesteś pewien|f:Jesteś pewna
|
213
|
+
I18n.backend.store_translations(:pl, :are_you_sure => "@{m:Jesteś pewien|f:Jesteś pewna|n:Na pewno}?")
|
219
214
|
|
220
215
|
# That would also work but it's less readable.
|
221
216
|
# PS: Have you ever configured Sendmail? ;-)
|
222
|
-
I18n.backend.store_translations(:pl, :are_you_sure => "@{n:Na|m,f:Jesteś} pew
|
217
|
+
I18n.backend.store_translations(:pl, :are_you_sure => "@{n:Na|m,f:Jesteś}{ pew}{m:ie}{n}{f:a|n:o}?")
|
218
|
+
|
219
|
+
=== Complex pattern usage
|
220
|
+
|
221
|
+
# Store needed translations
|
222
|
+
I18n.backend.store_translations(:pl,
|
223
|
+
:i18n => { :inflections => {
|
224
|
+
:@gender =>
|
225
|
+
{ :f => 'f', :m => 'm', :n => 'n',
|
226
|
+
:kobieta => :@f, :facet => :@m, :default => :n },
|
227
|
+
:@tense =>
|
228
|
+
{ :t => 'teraz', :w => 'przeszły', :j => 'przyszły',
|
229
|
+
:teraz => :@t, :wczoraj => :@w, :jutro => :@j,
|
230
|
+
:default => :t }
|
231
|
+
}})
|
232
|
+
|
233
|
+
I18n.backend.store_translations(:pl,
|
234
|
+
:msg_receive => "@gender+tense{n+w:Otrzymano|Dosta}{m,f,n+t:jesz|m,f,n+j:niesz|f+w:łaś|m+w:łeś} wiadomość")
|
235
|
+
|
236
|
+
I18n.locale = :pl
|
237
|
+
|
238
|
+
p I18n.translate('msg_receive', :gender => :kobieta)
|
239
|
+
#=> "Dostajesz wiadomość"
|
240
|
+
|
241
|
+
p I18n.translate('msg_receive', :gender => :facet)
|
242
|
+
#=> "Dostajesz wiadomość"
|
243
|
+
|
244
|
+
p I18n.translate('msg_receive')
|
245
|
+
#=> "Dostajesz wiadomość"
|
246
|
+
|
247
|
+
p I18n.translate('msg_receive', :gender => :kobieta, :tense => :wczoraj)
|
248
|
+
#=> "Dostałaś wiadomość"
|
249
|
+
|
250
|
+
p I18n.translate('msg_receive', :gender => :facet, :tense => :wczoraj)
|
251
|
+
#=> "Dostałeś wiadomość"
|
252
|
+
|
253
|
+
p I18n.translate('msg_receive', :tense => :jutro)
|
254
|
+
#=> "Dostaniesz wiadomość"
|
255
|
+
|
256
|
+
p I18n.translate('msg_receive', :tense => :wczoraj)
|
257
|
+
#=> "Otrzymano wiadomość"
|
258
|
+
|
259
|
+
==== YAML for the example above
|
260
|
+
|
261
|
+
The example above may use this YAML content instead of +store_translations+:
|
262
|
+
|
263
|
+
pl:
|
264
|
+
msg_receive: "@gender+tense{n+w:Otrzymano|Dosta}{m,f,n+t:jesz|m,f,n+j:niesz|f+w:łaś|m+w:łeś} wiadomość"
|
265
|
+
|
266
|
+
i18n:
|
267
|
+
inflections:
|
268
|
+
@gender:
|
269
|
+
m: 'male'
|
270
|
+
f: 'female'
|
271
|
+
n: 'neuter'
|
272
|
+
kobieta: @f
|
273
|
+
facet: @m
|
274
|
+
default: n
|
275
|
+
@tense:
|
276
|
+
t: 'teraźniejszy'
|
277
|
+
w: 'przeszły'
|
278
|
+
j: 'przyszły'
|
279
|
+
teraz: @t
|
280
|
+
wczoraj: @w
|
281
|
+
jutro: @j
|
282
|
+
default: @t
|
283
|
+
|
284
|
+
===== Alternative for +msg_receive+ key
|
285
|
+
|
286
|
+
The +msg_receive+ might also be expressed using two infleciton keys:
|
287
|
+
|
288
|
+
pl:
|
289
|
+
@msg_receive_1:
|
290
|
+
@kind: gender+tense
|
291
|
+
@free: 'Dosta'
|
292
|
+
n+w: 'Otrzymano'
|
293
|
+
|
294
|
+
@msg_receive_2:
|
295
|
+
@kind: gender+tense
|
296
|
+
@suffix: " wiadomość"
|
297
|
+
m,f,n+t: "jesz"
|
298
|
+
m,f,n+j: "niesz"
|
299
|
+
f+w: "łaś"
|
300
|
+
m+w: "łeś"
|
301
|
+
|
302
|
+
But then you have to change the translation call too, e.g.:
|
303
|
+
|
304
|
+
p I18n.translate(['@msg_receive_1','@msg_receive_2'], :gender => :kobieta).join
|
305
|
+
#=> "Dostajesz wiadomość"
|
306
|
+
|
307
|
+
The split is necessary because we have two patterns here and no way to express them
|
308
|
+
as one inflection key.
|
309
|
+
|
310
|
+
<i>to be continued…</i>
|
311
|
+
|
data/docs/HISTORY
CHANGED
@@ -1,3 +1,40 @@
|
|
1
|
+
=== 2.2.0 / 2011-02-09
|
2
|
+
|
3
|
+
* major enhancements
|
4
|
+
|
5
|
+
* Added loud tokens support
|
6
|
+
* Added complex patterns support
|
7
|
+
* Added key-based inflection support
|
8
|
+
* Added :cache_aware switch
|
9
|
+
* Improved validation of token and kind identifiers
|
10
|
+
|
11
|
+
* minor enhancements
|
12
|
+
|
13
|
+
* Refactored error reporting code
|
14
|
+
* Refactored options gathering code
|
15
|
+
* Removed magic symbols and strings
|
16
|
+
* Removed intermediate array from LazyHashEnumerator#to_h
|
17
|
+
* Added multiple patterns support (syntactic sugar)
|
18
|
+
* Added I18n::Inflector::Config module
|
19
|
+
* Added I18n::Inflector::LazyArrayEnumerator class
|
20
|
+
* Added I18n::Inflector::HSet class for keeping collections of data
|
21
|
+
* Added error classes: I18n::InvalidInflectionOption and I18n::InvalidInflectionKind
|
22
|
+
* Interpolation method moved to I18n::Inflector::Interpolate module
|
23
|
+
* All inflection related exceptions now have the attribute "key" containing key name
|
24
|
+
|
25
|
+
* major bugfixes
|
26
|
+
|
27
|
+
* Fixed handling of missing inflection option when :inflector_raises is set
|
28
|
+
|
29
|
+
* minor bugfixes
|
30
|
+
|
31
|
+
* Fixed interpolation when :excluded_defaults is on and a kind is strict
|
32
|
+
* Fixed interpolation when pattern is escaped and locale is not inflected
|
33
|
+
* Enabled filtering of reserved names in options
|
34
|
+
* Enabled filtering of inflection options for options that go to original translate method
|
35
|
+
* Updated documentation in a section describing options
|
36
|
+
* Fixed some examples
|
37
|
+
|
1
38
|
=== 2.1.0 / 2011-01-27
|
2
39
|
|
3
40
|
* major enhancements
|
data/docs/TODO
CHANGED
@@ -1,31 +1,7 @@
|
|
1
1
|
== Near future
|
2
2
|
|
3
|
-
* do something with that to_h that creates intermediate array
|
4
|
-
|
5
|
-
* add a switch that causes inflection arguments to be gathered and removed before using original
|
6
|
-
version of translate and then injected when interpolating happens (default value
|
7
|
-
for that switch should be true if there is I18n version 4 installed)
|
8
|
-
|
9
|
-
- not so good idea to turn it on by default since the same variable may be used to interpolate
|
10
|
-
inflections and for direct interpolation
|
11
|
-
|
12
|
-
* attach inflection key name to some raised errors
|
13
|
-
|
14
|
-
* add some external iterators for tokens, aliases, kinds, true_tokens
|
15
|
-
|
16
|
-
* allow different descriptions for aliases pointing to the same token, e.g.: now: @present ="description"
|
17
|
-
|
18
3
|
== Distant future
|
19
4
|
|
20
|
-
*
|
21
|
-
|
22
|
-
*
|
23
|
-
|
24
|
-
- @person+time{i+now:am|i+past:was}
|
25
|
-
- @person+time{i+now:am|i+past:was|he,she,it+now:is}
|
26
|
-
- @g_sender+g_receiver{...} - for Hebrew for example
|
27
|
-
|
28
|
-
* case-insensitivity switch for inflection options (?)
|
29
|
-
|
30
|
-
* think about allowing negative matches to be AND-ed, e.g.: !m&!f:impersonal (?)
|
31
|
-
- that will double positive-matching syntax, and make it even less KISS
|
5
|
+
* add "any token" operator - will make it easier to create complex patterns - (use negative matching to non-existant, reserved value)
|
6
|
+
* split interpolate_core and make it more reusable by raw data (e.g. pattern content)
|
7
|
+
* allow different descriptions for aliases pointing to the same token, e.g.: now: @present ="description"
|
data/lib/i18n-inflector/api.rb
CHANGED
@@ -44,6 +44,8 @@ module I18n
|
|
44
44
|
# @api public
|
45
45
|
class API < API_Strict
|
46
46
|
|
47
|
+
include I18n::Inflector::Interpolate
|
48
|
+
|
47
49
|
# Options controlling the engine.
|
48
50
|
#
|
49
51
|
# @api public
|
@@ -64,6 +66,11 @@ module I18n
|
|
64
66
|
# I18n.translate('welcome', :inflector_raises => true)
|
65
67
|
attr_reader :options
|
66
68
|
|
69
|
+
# @private
|
70
|
+
def config
|
71
|
+
I18n::Inflector::Config
|
72
|
+
end
|
73
|
+
|
67
74
|
# @private
|
68
75
|
def strict
|
69
76
|
@strict ||= I18n::Inflector::API_Strict.new(@idb_strict, @options)
|
@@ -184,7 +191,7 @@ module I18n
|
|
184
191
|
# @note If +kind+ begins with the +@+ symbol then the variant of this method
|
185
192
|
# operating on strict kinds will be called ({I18n::Inflector::API_Strict#inflected_locales})
|
186
193
|
def inflected_locales(kind=nil)
|
187
|
-
if kind.to_s[0..0] ==
|
194
|
+
if kind.to_s[0..0] == Markers::PATTERN
|
188
195
|
strict.inflected_locales(kind.to_s[1..-1])
|
189
196
|
else
|
190
197
|
(super + strict.inflected_locales(kind)).uniq
|
@@ -209,7 +216,7 @@ module I18n
|
|
209
216
|
# @param [Symbol] locale the locale identifier
|
210
217
|
# @return [Boolean] +true+ if the given +kind+ exists, +false+ otherwise
|
211
218
|
def has_kind?(kind, locale=nil)
|
212
|
-
if kind.to_s[0..0] ==
|
219
|
+
if kind.to_s[0..0] == Markers::PATTERN
|
213
220
|
return strict.has_kind?(kind.to_s[1..-1], locale)
|
214
221
|
end
|
215
222
|
super
|
@@ -235,7 +242,7 @@ module I18n
|
|
235
242
|
# there is no default token
|
236
243
|
def default_token(kind, locale=nil)
|
237
244
|
return nil if (kind.nil? || kind.to_s.empty?)
|
238
|
-
if kind.to_s[0..0] ==
|
245
|
+
if kind.to_s[0..0] == Markers::PATTERN
|
239
246
|
return strict.default_token(kind.to_s[1..-1], locale)
|
240
247
|
end
|
241
248
|
super
|
@@ -278,7 +285,7 @@ module I18n
|
|
278
285
|
unless kind.nil?
|
279
286
|
kind = kind.to_s
|
280
287
|
reutrn false if kind.empty?
|
281
|
-
if kind[0..0] ==
|
288
|
+
if kind[0..0] == Markers::PATTERN
|
282
289
|
return strict.has_alias?(token, kind[1..-1], locale)
|
283
290
|
end
|
284
291
|
kind = kind.to_sym
|
@@ -324,7 +331,7 @@ module I18n
|
|
324
331
|
unless kind.nil?
|
325
332
|
kind = kind.to_s
|
326
333
|
return false if kind.empty?
|
327
|
-
if kind[0..0] ==
|
334
|
+
if kind[0..0] == Markers::PATTERN
|
328
335
|
return strict.has_true_token?(token, kind[1..-1], locale)
|
329
336
|
end
|
330
337
|
kind = kind.to_sym
|
@@ -370,7 +377,7 @@ module I18n
|
|
370
377
|
unless kind.nil?
|
371
378
|
kind = kind.to_s
|
372
379
|
return false if kind.empty?
|
373
|
-
if kind[0..0] ==
|
380
|
+
if kind[0..0] == Markers::PATTERN
|
374
381
|
return strict.has_token?(token, kind[1..-1], locale)
|
375
382
|
end
|
376
383
|
kind = kind.to_sym
|
@@ -420,7 +427,7 @@ module I18n
|
|
420
427
|
unless kind.nil?
|
421
428
|
kind = kind.to_s
|
422
429
|
return nil if kind.empty?
|
423
|
-
if kind[0..0] ==
|
430
|
+
if kind[0..0] == Markers::PATTERN
|
424
431
|
return strict.true_token(token, kind[1..-1], locale)
|
425
432
|
end
|
426
433
|
kind = kind.to_sym
|
@@ -465,7 +472,7 @@ module I18n
|
|
465
472
|
unless kind.nil?
|
466
473
|
kind = kind.to_s
|
467
474
|
return nil if kind.empty?
|
468
|
-
if kind[0..0] ==
|
475
|
+
if kind[0..0] == Markers::PATTERN
|
469
476
|
return strict.kind(token, kind[1..-1], locale)
|
470
477
|
end
|
471
478
|
kind = kind.to_sym
|
@@ -507,7 +514,7 @@ module I18n
|
|
507
514
|
unless kind.nil?
|
508
515
|
kind = kind.to_s
|
509
516
|
return {} if kind.empty?
|
510
|
-
if kind[0..0] ==
|
517
|
+
if kind[0..0] == Markers::PATTERN
|
511
518
|
return strict.tokens(kind[1..-1], locale)
|
512
519
|
end
|
513
520
|
kind = kind.to_sym
|
@@ -548,7 +555,7 @@ module I18n
|
|
548
555
|
unless kind.nil?
|
549
556
|
kind = kind.to_s
|
550
557
|
return {} if kind.empty?
|
551
|
-
if kind[0..0] ==
|
558
|
+
if kind[0..0] == Markers::PATTERN
|
552
559
|
return strict.tokens_raw(kind[1..-1], locale)
|
553
560
|
end
|
554
561
|
kind = kind.to_sym
|
@@ -586,7 +593,7 @@ module I18n
|
|
586
593
|
unless kind.nil?
|
587
594
|
kind = kind.to_s
|
588
595
|
return {} if kind.empty?
|
589
|
-
if kind[0..0] ==
|
596
|
+
if kind[0..0] == Markers::PATTERN
|
590
597
|
return strict.tokens_true(kind[1..-1], locale)
|
591
598
|
end
|
592
599
|
kind = kind.to_sym
|
@@ -620,7 +627,7 @@ module I18n
|
|
620
627
|
unless kind.nil?
|
621
628
|
kind = kind.to_s
|
622
629
|
return nil if kind.empty?
|
623
|
-
if kind[0..0] ==
|
630
|
+
if kind[0..0] == Markers::PATTERN
|
624
631
|
return strict.aliases(kind[1..-1], locale)
|
625
632
|
end
|
626
633
|
kind = kind.to_sym
|
@@ -672,7 +679,7 @@ module I18n
|
|
672
679
|
unless kind.nil?
|
673
680
|
kind = kind.to_s
|
674
681
|
return nil if kind.empty?
|
675
|
-
if kind[0..0] ==
|
682
|
+
if kind[0..0] == Markers::PATTERN
|
676
683
|
return strict.token_description(token, kind[1..-1], locale)
|
677
684
|
end
|
678
685
|
kind = kind.to_sym
|
@@ -680,225 +687,6 @@ module I18n
|
|
680
687
|
data_safe(locale).get_description(token.to_sym, kind)
|
681
688
|
end
|
682
689
|
|
683
|
-
# Interpolates inflection values in the given +string+
|
684
|
-
# using kinds given in +options+ and a matching tokens.
|
685
|
-
#
|
686
|
-
# @param [String] string the translation string
|
687
|
-
# containing patterns to interpolate
|
688
|
-
# @param [String,Symbol] locale the locale identifier
|
689
|
-
# @param [Hash] options the options
|
690
|
-
# @option options [Boolean] :inflector_excluded_defaults (false) local switch
|
691
|
-
# that overrides global setting (see: {I18n::Inflector::InflectionOptions#excluded_defaults})
|
692
|
-
# @option options [Boolean] :inflector_unknown_defaults (true) local switch
|
693
|
-
# that overrides global setting (see: {I18n::Inflector::InflectionOptions#unknown_defaults})
|
694
|
-
# @option options [Boolean] :inflector_raises (false) local switch
|
695
|
-
# that overrides global setting (see: {I18n::Inflector::InflectionOptions#raises})
|
696
|
-
# @option options [Boolean] :inflector_aliased_patterns (false) local switch
|
697
|
-
# that overrides global setting (see: {I18n::Inflector::InflectionOptions#aliased_patterns})
|
698
|
-
# @return [String] the string with interpolated patterns
|
699
|
-
def interpolate(string, locale, options = {})
|
700
|
-
used_kinds = options.except(*INFLECTOR_RESERVED_KEYS)
|
701
|
-
sw, op = @options, options
|
702
|
-
raises = (s=op.delete :inflector_raises).nil? ? sw.raises : s
|
703
|
-
aliased_patterns = (s=op.delete :inflector_aliased_patterns).nil? ? sw.aliased_patterns : s
|
704
|
-
unknown_defaults = (s=op.delete :inflector_unknown_defaults).nil? ? sw.unknown_defaults : s
|
705
|
-
excluded_defaults = (s=op.delete :inflector_excluded_defaults).nil? ? sw.excluded_defaults : s
|
706
|
-
|
707
|
-
idb = @idb[locale]
|
708
|
-
idb_strict = @idb_strict[locale]
|
709
|
-
|
710
|
-
string.gsub(PATTERN) do
|
711
|
-
pattern_fix = $1
|
712
|
-
strict_kind = $2
|
713
|
-
pattern_content = $3
|
714
|
-
ext_pattern = $&
|
715
|
-
ext_value = nil
|
716
|
-
ext_freetext = ''
|
717
|
-
found = false
|
718
|
-
parsed_default_v= nil
|
719
|
-
|
720
|
-
# leave escaped pattern as-is
|
721
|
-
unless pattern_fix.empty?
|
722
|
-
ext_pattern = ext_pattern[1..-1]
|
723
|
-
next ext_pattern if ESCAPES[pattern_fix]
|
724
|
-
end
|
725
|
-
|
726
|
-
# set parsed kind if strict kind is given (named pattern is parsed)
|
727
|
-
if strict_kind.empty?
|
728
|
-
parsed_symbol = nil
|
729
|
-
strict_kind = nil
|
730
|
-
parsed_kind = nil
|
731
|
-
default_token = nil
|
732
|
-
subdb = idb
|
733
|
-
else
|
734
|
-
parsed_symbol = (NAMED_MARKER + strict_kind).to_sym
|
735
|
-
strict_kind = strict_kind.to_sym
|
736
|
-
parsed_kind = strict_kind
|
737
|
-
subdb = idb_strict
|
738
|
-
default_token = subdb.get_default_token(parsed_kind)
|
739
|
-
end
|
740
|
-
|
741
|
-
# process pattern content's
|
742
|
-
pattern_content.scan(TOKENS) do
|
743
|
-
ext_token = $1.to_s
|
744
|
-
ext_value = $2.to_s
|
745
|
-
ext_freetext = $3.to_s
|
746
|
-
tokens = Hash.new(false)
|
747
|
-
negatives = Hash.new(false)
|
748
|
-
kind = nil
|
749
|
-
option = nil
|
750
|
-
|
751
|
-
# token not found?
|
752
|
-
if ext_token.empty?
|
753
|
-
# free text not found too? that should never happend.
|
754
|
-
if ext_freetext.empty?
|
755
|
-
raise I18n::InvalidInflectionToken.new(ext_pattern, ext_token) if raises
|
756
|
-
end
|
757
|
-
next
|
758
|
-
end
|
759
|
-
|
760
|
-
# split tokens if comma is present and put into fast list
|
761
|
-
ext_token.split(OPERATOR_MULTI).each do |t|
|
762
|
-
# token name corrupted
|
763
|
-
if t.empty?
|
764
|
-
raise I18n::InvalidInflectionToken.new(ext_pattern, t) if raises
|
765
|
-
next
|
766
|
-
end
|
767
|
-
|
768
|
-
# mark negative-matching tokens and put them to negatives fast list
|
769
|
-
if t[0..0] == OPERATOR_NOT
|
770
|
-
t = t[1..-1]
|
771
|
-
if t.empty?
|
772
|
-
raise I18n::InvalidInflectionToken.new(ext_pattern, t) if raises
|
773
|
-
next
|
774
|
-
end
|
775
|
-
t = t.to_sym
|
776
|
-
t = subdb.get_true_token(t, strict_kind) if aliased_patterns
|
777
|
-
negatives[t] = true
|
778
|
-
end
|
779
|
-
|
780
|
-
t = t.to_sym
|
781
|
-
t = subdb.get_true_token(t, strict_kind) if aliased_patterns
|
782
|
-
|
783
|
-
# get kind for that token
|
784
|
-
kind = subdb.get_kind(t, strict_kind)
|
785
|
-
if kind.nil?
|
786
|
-
raise I18n::InvalidInflectionToken.new(ext_pattern, t) if raises
|
787
|
-
next
|
788
|
-
end
|
789
|
-
|
790
|
-
# set processed kind after matching first token in a pattern
|
791
|
-
if parsed_kind.nil?
|
792
|
-
parsed_kind = kind
|
793
|
-
parsed_symbol = kind.to_sym
|
794
|
-
default_token = subdb.get_default_token(parsed_kind)
|
795
|
-
elsif parsed_kind != kind
|
796
|
-
# tokens of different kinds in one regular (not named) pattern are prohibited
|
797
|
-
if raises
|
798
|
-
raise I18n::MisplacedInflectionToken.new(ext_pattern, t, parsed_symbol)
|
799
|
-
end
|
800
|
-
next
|
801
|
-
end
|
802
|
-
|
803
|
-
# use that token
|
804
|
-
tokens[t] = true unless negatives[t]
|
805
|
-
end
|
806
|
-
|
807
|
-
# self-explanatory
|
808
|
-
if (tokens.empty? && negatives.empty?)
|
809
|
-
raise I18n::InvalidInflectionToken.new(ext_pattern, ext_token) if raises
|
810
|
-
end
|
811
|
-
|
812
|
-
# try @-style option for strict kind, fallback to regular if not found
|
813
|
-
# and memorize option name for error reporting
|
814
|
-
oname = !strict_kind.nil? && options.has_key?(parsed_symbol) ?
|
815
|
-
parsed_symbol : (options.has_key?(kind) ? kind : nil)
|
816
|
-
|
817
|
-
# Get option if possible and memorize for error reporting;
|
818
|
-
# fallback to default token if option still not found
|
819
|
-
if oname.nil?
|
820
|
-
option = default_token
|
821
|
-
orig_option = nil
|
822
|
-
else
|
823
|
-
option = options[oname]
|
824
|
-
orig_option = option
|
825
|
-
end
|
826
|
-
|
827
|
-
if (option.nil? || option.to_s.empty?)
|
828
|
-
# if option is given but is unknown, empty or nil
|
829
|
-
# then use default option for a kind if unknown_defaults is switched on
|
830
|
-
option = unknown_defaults ? default_token : nil
|
831
|
-
else
|
832
|
-
# validate option and if it's unknown try in aliases
|
833
|
-
option = subdb.get_true_token(option.to_sym, strict_kind)
|
834
|
-
|
835
|
-
# if still nothing then fall back to default value
|
836
|
-
# for a kind if unknown_defaults switch is on
|
837
|
-
if option.nil?
|
838
|
-
option = unknown_defaults ? default_token : nil
|
839
|
-
end
|
840
|
-
end
|
841
|
-
|
842
|
-
# if the option is still unknown or bad
|
843
|
-
# raise an exception
|
844
|
-
if option.nil?
|
845
|
-
if raises
|
846
|
-
if oname.nil?
|
847
|
-
ex = InflectionOptionNotFound
|
848
|
-
oname = parsed_symbol
|
849
|
-
orig_option = nil
|
850
|
-
else
|
851
|
-
ex = InflectionOptionIncorrect
|
852
|
-
end
|
853
|
-
raise ex.new(ext_pattern, oname, ext_token, orig_option)
|
854
|
-
end
|
855
|
-
next
|
856
|
-
end
|
857
|
-
|
858
|
-
# memorize default value for further processing
|
859
|
-
# outside this block if excluded_defaults switch is on
|
860
|
-
parsed_default_v = ext_value if (excluded_defaults && !default_token.nil?)
|
861
|
-
|
862
|
-
# throw the value if the given option matches one of the tokens from group
|
863
|
-
# or negatively matches one of the negated tokens
|
864
|
-
case negatives.count
|
865
|
-
when 0 then next unless tokens[option]
|
866
|
-
when 1 then next if negatives[option]
|
867
|
-
end
|
868
|
-
|
869
|
-
# skip further evaluation of the pattern
|
870
|
-
# since the right token has been found
|
871
|
-
found = true
|
872
|
-
break
|
873
|
-
|
874
|
-
end # single token (or a group) processing
|
875
|
-
|
876
|
-
result = nil
|
877
|
-
|
878
|
-
# return value of a token that matches option's value
|
879
|
-
# given for a kind or try to return a free text
|
880
|
-
# if it's present
|
881
|
-
if found
|
882
|
-
result = ext_value
|
883
|
-
elsif (excluded_defaults && !parsed_kind.nil?)
|
884
|
-
# if there is excluded_defaults switch turned on
|
885
|
-
# and a correct token was found in an inflection option but
|
886
|
-
# has not been found in a pattern then interpolate
|
887
|
-
# the pattern with a value picked for the default
|
888
|
-
# token for that kind if a default token was present
|
889
|
-
# in a pattern
|
890
|
-
kind = nil
|
891
|
-
token = options[parsed_kind]
|
892
|
-
kind = subdb.get_kind(token)
|
893
|
-
result = parsed_default_v unless kind.nil?
|
894
|
-
end
|
895
|
-
|
896
|
-
pattern_fix + (result || ext_freetext)
|
897
|
-
|
898
|
-
end # single pattern processing
|
899
|
-
|
900
|
-
end
|
901
|
-
|
902
690
|
protected
|
903
691
|
|
904
692
|
# @private
|
@@ -947,9 +735,9 @@ module I18n
|
|
947
735
|
def tkl_args(args)
|
948
736
|
token, kind, locale = case args.count
|
949
737
|
when 1 then [args[0], nil, nil]
|
950
|
-
when 2 then args[1].to_s[0..0] ==
|
738
|
+
when 2 then args[1].to_s[0..0] == Markers::PATTERN ? [args[0], args[1], nil] : [args[0], nil, args[1]]
|
951
739
|
when 3 then args
|
952
|
-
else raise ArgumentError.new("wrong number of arguments: #{args.count} for (1..3)")
|
740
|
+
else raise I18n::ArgumentError.new("wrong number of arguments: #{args.count} for (1..3)")
|
953
741
|
end
|
954
742
|
[token,kind,locale]
|
955
743
|
end
|
@@ -491,7 +491,7 @@ module I18n
|
|
491
491
|
when 1 then [args[0], nil, nil]
|
492
492
|
when 2 then [args[0], args[1], nil]
|
493
493
|
when 3 then args
|
494
|
-
else raise ArgumentError.new("wrong number of arguments: #{args.count} for (1..3)")
|
494
|
+
else raise I18n::ArgumentError.new("wrong number of arguments: #{args.count} for (1..3)")
|
495
495
|
end
|
496
496
|
token = token.nil? || token.to_s.empty? ? nil : token.to_sym
|
497
497
|
kind = kind.nil? || kind.to_s.empty? ? nil : kind.to_sym
|