i18n-inflector 2.1.0 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|