i18n-inflector 2.0.1 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +1 -0
- data/ChangeLog +412 -0
- data/Gemfile +1 -0
- data/Manifest.txt +6 -1
- data/README.rdoc +16 -11
- data/Rakefile +15 -2
- data/ci/i18n-inflector.gemspec +1 -1
- data/ci/i18nv4-Gemfile +15 -0
- data/docs/EXAMPLES +222 -0
- data/docs/HISTORY +31 -0
- data/docs/LEGAL +0 -1
- data/docs/RELATIONS +16 -13
- data/docs/TODO +25 -3
- data/lib/i18n-inflector/api.rb +964 -0
- data/lib/i18n-inflector/api_strict.rb +519 -0
- data/lib/i18n-inflector/backend.rb +77 -40
- data/lib/i18n-inflector/errors.rb +56 -14
- data/lib/i18n-inflector/inflection_data.rb +133 -105
- data/lib/i18n-inflector/inflection_data_strict.rb +290 -0
- data/lib/i18n-inflector/inflector.rb +21 -660
- data/lib/i18n-inflector/lazy_enum.rb +120 -0
- data/lib/i18n-inflector/long_comments.rb +203 -14
- data/lib/i18n-inflector/version.rb +1 -1
- data/lib/i18n-inflector.rb +5 -3
- data/test/inflector_test.rb +334 -34
- data/test/test_helper.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +10 -6
- metadata.gz.sig +0 -0
- data/lib/i18n-inflector/util.rb +0 -67
@@ -42,7 +42,7 @@ module I18n
|
|
42
42
|
# Translates given key taking care of inflections.
|
43
43
|
#
|
44
44
|
# @api public
|
45
|
-
# @see I18n::Inflector::
|
45
|
+
# @see I18n::Inflector::API#interpolate
|
46
46
|
# @see I18n::Inflector::InflectionOptions
|
47
47
|
# @param [Symbol] locale locale
|
48
48
|
# @param [Symbol,String] key translation key
|
@@ -52,12 +52,13 @@ module I18n
|
|
52
52
|
# particular option should be the same as the name of a kind of tokens from a pattern.
|
53
53
|
# All +options+ along with a +string+ and +locale+ are passed to
|
54
54
|
# {I18n::Backend::Simple#translate I18n::Backend::Simple#translate}
|
55
|
-
# and the result is processed by {I18n::Inflector::
|
55
|
+
# and the result is processed by {I18n::Inflector::API#interpolate}
|
56
56
|
# @return [String] the translated string with interpolated patterns
|
57
57
|
def translate(locale, key, options = {})
|
58
|
+
orig_options = options.dup
|
58
59
|
translated_string = super
|
59
60
|
|
60
|
-
return translated_string if locale.to_s.empty?
|
61
|
+
return translated_string if (locale.nil? || locale.to_s.empty?)
|
61
62
|
|
62
63
|
unless @inflector.inflected_locale?(locale)
|
63
64
|
return translated_string.gsub(I18n::Inflector::PATTERN,'')
|
@@ -67,7 +68,7 @@ module I18n
|
|
67
68
|
return translated_string
|
68
69
|
end
|
69
70
|
|
70
|
-
@inflector.interpolate(translated_string, locale,
|
71
|
+
@inflector.interpolate(translated_string, locale, orig_options)
|
71
72
|
end
|
72
73
|
|
73
74
|
# Stores translations in memory.
|
@@ -88,8 +89,8 @@ module I18n
|
|
88
89
|
unless subdata.nil?
|
89
90
|
subdata = (subdata[:inflections] || subdata['inflections'])
|
90
91
|
unless subdata.nil?
|
91
|
-
|
92
|
-
@inflector.
|
92
|
+
db, db_strict = load_inflection_tokens(locale, r[:i18n][:inflections])
|
93
|
+
@inflector.add_databases(db, db_strict)
|
93
94
|
end
|
94
95
|
end
|
95
96
|
end
|
@@ -103,7 +104,7 @@ module I18n
|
|
103
104
|
# @return [void]
|
104
105
|
def inflector_try_init
|
105
106
|
return nil if (defined?(@inflector) && !@inflector.nil?)
|
106
|
-
@inflector = I18n::Inflector::
|
107
|
+
@inflector = I18n::Inflector::API.new
|
107
108
|
nil
|
108
109
|
end
|
109
110
|
|
@@ -122,7 +123,7 @@ module I18n
|
|
122
123
|
end
|
123
124
|
|
124
125
|
# Gives an access to the internal structure containing configuration data
|
125
|
-
# for
|
126
|
+
# for the given locale.
|
126
127
|
#
|
127
128
|
# @note Under some very rare conditions this method may be called while
|
128
129
|
# translation data is loading. It must always return when translations
|
@@ -130,7 +131,7 @@ module I18n
|
|
130
131
|
# will eat a kittien!
|
131
132
|
# @param [Symbol] locale the locale to use
|
132
133
|
# @return [Hash,nil] part of the translation data that
|
133
|
-
# reflects inflections for
|
134
|
+
# reflects inflections for the given locale or +nil+
|
134
135
|
# if translations are not initialized
|
135
136
|
def inflection_subtree(locale)
|
136
137
|
return nil unless initialized?
|
@@ -174,13 +175,13 @@ module I18n
|
|
174
175
|
if kind_subtree.has_key?(token)
|
175
176
|
return token
|
176
177
|
else
|
177
|
-
# that should never happend but who knows
|
178
178
|
raise I18n::BadInflectionToken.new(locale, token, kind)
|
179
179
|
end
|
180
180
|
else
|
181
181
|
orig_token = token
|
182
182
|
token = value[1..-1]
|
183
|
-
|
183
|
+
|
184
|
+
if (token.nil? || token.to_s.empty?)
|
184
185
|
raise I18n::BadInflectionToken.new(locale, token, kind)
|
185
186
|
end
|
186
187
|
token = token.to_sym
|
@@ -195,7 +196,8 @@ module I18n
|
|
195
196
|
|
196
197
|
# Uses the inflections subtree and creates internal mappings
|
197
198
|
# to resolve kinds assigned to inflection tokens and aliases, including defaults.
|
198
|
-
# @return [
|
199
|
+
# @return [I18n::Inflector::InflectionData,nil] the database containing inflections tokens
|
200
|
+
# or +nil+ if something went wrong
|
199
201
|
# @raise [I18n::BadInflectionToken] if a name of some loaded token is invalid
|
200
202
|
# @raise [I18n::BadInflectionAlias] if a loaded alias points to a token that does not exists
|
201
203
|
# @raise [I18n::DuplicatedInflectionToken] if a token has already appeard in loaded configuration
|
@@ -204,65 +206,100 @@ module I18n
|
|
204
206
|
# Loads inflection tokens for the given locale using internal hash of stored translations. Requires
|
205
207
|
# translations to be initialized.
|
206
208
|
# @param [Symbol] locale the locale to use and work for
|
207
|
-
# @return [
|
209
|
+
# @return [I18n::Inflector::InflectionData,nil] the database containing inflections tokens
|
210
|
+
# or +nil+ if something went wrong
|
208
211
|
# @overload load_inflection_tokens(locale, subtree)
|
209
|
-
# Loads inflection tokens for the given locale using
|
212
|
+
# Loads inflection tokens for the given locale using datthe given in an argument
|
210
213
|
# @param [Symbol] locale the locale to use and work for
|
211
214
|
# @param [Hash] subtree the tree (in a form of nested Hashes) containing inflection tokens to scan
|
212
|
-
# @return [
|
215
|
+
# @return [I18n::Inflector::InflectionData,nil] the database containing inflections tokens
|
216
|
+
# or +nil+ if something went wrong
|
213
217
|
def load_inflection_tokens(locale, subtree=nil)
|
214
218
|
inflections_tree = subtree || inflection_subtree(locale)
|
215
219
|
return nil if (inflections_tree.nil? || inflections_tree.empty?)
|
216
220
|
|
217
|
-
idb
|
221
|
+
idb = I18n::Inflector::InflectionData.new(locale)
|
222
|
+
idb_strict = I18n::Inflector::InflectionData_Strict.new(locale)
|
223
|
+
|
224
|
+
return nil if (idb.nil? || idb_strict.nil?)
|
218
225
|
|
219
|
-
|
226
|
+
inflections = prepare_inflections(inflections_tree, idb, idb_strict)
|
227
|
+
|
228
|
+
inflections.each do |orig_kind, kind, strict_kind, subdb, tokens|
|
220
229
|
tokens.each_pair do |token, description|
|
221
230
|
|
222
231
|
# test for duplicate
|
223
|
-
if
|
224
|
-
raise I18n::DuplicatedInflectionToken.new(
|
232
|
+
if subdb.has_token?(token, strict_kind)
|
233
|
+
raise I18n::DuplicatedInflectionToken.new(subdb.get_kind(token, strict_kind), orig_kind, token)
|
225
234
|
end
|
226
235
|
|
227
236
|
# validate token's name
|
228
|
-
raise I18n::BadInflectionToken.new(locale, token,
|
237
|
+
raise I18n::BadInflectionToken.new(locale, token, orig_kind) if (token.nil? || token.to_s.empty?)
|
229
238
|
|
230
239
|
# validate token's description
|
231
240
|
if description.nil?
|
232
|
-
raise I18n::BadInflectionToken.new(locale, token,
|
241
|
+
raise I18n::BadInflectionToken.new(locale, token, orig_kind, description)
|
233
242
|
elsif description[0..0] == I18n::Inflector::ALIAS_MARKER
|
234
243
|
next
|
235
244
|
end
|
236
245
|
|
237
|
-
#
|
238
|
-
if token == :default
|
239
|
-
if idb.has_default_token?(kind) # should never happend unless someone is messing with @translations
|
240
|
-
raise I18n::DuplicatedInflectionToken.new(kind, nil, token)
|
241
|
-
end
|
242
|
-
idb.set_default_token(kind, description)
|
243
|
-
next
|
244
|
-
end
|
246
|
+
# skip default token for later processing
|
247
|
+
next if token == :default
|
245
248
|
|
246
|
-
|
249
|
+
subdb.add_token(token, kind, description)
|
247
250
|
end
|
248
251
|
end
|
249
252
|
|
250
253
|
# handle aliases
|
251
|
-
|
254
|
+
inflections.each do |orig_kind, kind, strict_kind, subdb, tokens|
|
252
255
|
tokens.each_pair do |token, description|
|
256
|
+
next if token == :default
|
253
257
|
next if description[0..0] != I18n::Inflector::ALIAS_MARKER
|
254
|
-
real_token = shorten_inflection_alias(token,
|
255
|
-
|
258
|
+
real_token = shorten_inflection_alias(token, orig_kind, locale, inflections_tree)
|
259
|
+
subdb.add_alias(token, real_token, kind) unless real_token.nil?
|
256
260
|
end
|
257
261
|
end
|
258
262
|
|
259
|
-
#
|
260
|
-
|
261
|
-
|
263
|
+
# handle default tokens
|
264
|
+
inflections.each do |orig_kind, kind, strict_kind, subdb, tokens|
|
265
|
+
next unless tokens.has_key?(:default)
|
266
|
+
if subdb.has_default_token?(kind)
|
267
|
+
raise I18n::DuplicatedInflectionToken.new(orig_kind, nil, :default)
|
268
|
+
end
|
269
|
+
orig_target = tokens[:default]
|
270
|
+
target = orig_target.to_s
|
271
|
+
target = target[1..-1] if target[0..0] == I18n::Inflector::ALIAS_MARKER
|
272
|
+
if target.empty?
|
273
|
+
raise I18n::BadInflectionToken.new(locale, token, orig_kind, orig_target)
|
274
|
+
end
|
275
|
+
target = subdb.get_true_token(target.to_sym, kind)
|
276
|
+
if target.nil?
|
277
|
+
raise I18n::BadInflectionAlias.new(locale, :default, orig_kind, orig_target)
|
278
|
+
end
|
279
|
+
subdb.set_default_token(kind, target)
|
280
|
+
end
|
281
|
+
|
282
|
+
[idb, idb_strict]
|
283
|
+
end
|
262
284
|
|
263
|
-
|
285
|
+
# @private
|
286
|
+
def prepare_inflections(inflections, idb, idb_strict)
|
287
|
+
I18n::Inflector::LazyHashEnumerator.new(inflections).ary_map do |kind, tokens|
|
288
|
+
next if (tokens.nil? || tokens.empty?)
|
289
|
+
subdb = idb
|
290
|
+
strict_kind = nil
|
291
|
+
orig_kind = kind
|
292
|
+
if kind.to_s[0..0] == I18n::Inflector::NAMED_MARKER
|
293
|
+
kind = kind.to_s[1..-1]
|
294
|
+
next if kind.empty?
|
295
|
+
kind = kind.to_sym
|
296
|
+
subdb = idb_strict
|
297
|
+
strict_kind = kind
|
298
|
+
end
|
299
|
+
[orig_kind, kind, strict_kind, subdb, tokens]
|
300
|
+
end
|
264
301
|
end
|
265
302
|
|
266
|
-
end
|
267
|
-
end
|
268
|
-
end
|
303
|
+
end # module Inflector
|
304
|
+
end # module Backend
|
305
|
+
end # module I18n
|
@@ -8,78 +8,119 @@
|
|
8
8
|
|
9
9
|
module I18n
|
10
10
|
|
11
|
-
# This
|
12
|
-
# is
|
13
|
-
#
|
14
|
-
# This exception will also be raised when a required option, describing token selected
|
15
|
-
# for a kind, is empty or doesn't match any acceptable tokens.
|
11
|
+
# @abstract This class is a parent class for exceptions raised when
|
12
|
+
# inflection option is bad or missing.
|
16
13
|
class InvalidOptionForKind < ArgumentError
|
14
|
+
|
17
15
|
attr_reader :pattern, :kind, :token, :option
|
16
|
+
|
18
17
|
def initialize(pattern, kind, token, option)
|
19
|
-
@pattern, @kind, @token, @option = pattern, kind, token, option
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
18
|
+
@pattern, @kind, @token, @option, @option_present = pattern, kind, token, option
|
19
|
+
@message ||= ""
|
20
|
+
super(@message)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
# This is raised when there is no kind given in options. The kind
|
26
|
+
# is determined by looking at token placed in a pattern.
|
27
|
+
class InflectionOptionNotFound < InvalidOptionForKind
|
28
|
+
|
29
|
+
def initialize(pattern, kind, token, option=nil)
|
30
|
+
kind = kind.to_s
|
31
|
+
unless kind.empty?
|
32
|
+
if kind[0..0] == I18n::Inflector::NAMED_MARKER
|
33
|
+
kind = ":#{kind} (or :#{kind[1..-1]})"
|
34
|
+
else
|
35
|
+
kind = kind.to_sym.inspect
|
36
|
+
end
|
26
37
|
end
|
38
|
+
@message = "option #{kind} required by the " +
|
39
|
+
"pattern #{pattern.inspect} was not found"
|
40
|
+
super
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
# This exception will be raised when a required option, describing token selected
|
46
|
+
# for a kind, is +nil+, empty or doesn't match any acceptable tokens.
|
47
|
+
class InflectionOptionIncorrect < InvalidOptionForKind
|
48
|
+
|
49
|
+
def initialize(pattern, kind, token, option)
|
50
|
+
@message = "value #{option.inspect} of option #{kind.inspect} required by " +
|
51
|
+
"#{pattern.inspect} does not match any token"
|
52
|
+
super
|
27
53
|
end
|
54
|
+
|
28
55
|
end
|
29
56
|
|
30
57
|
# This is raised when token given in pattern is invalid (empty or has no
|
31
58
|
# kind assigned).
|
32
59
|
class InvalidInflectionToken < ArgumentError
|
60
|
+
|
33
61
|
attr_reader :pattern, :token
|
62
|
+
|
34
63
|
def initialize(pattern, token)
|
35
64
|
@pattern, @token = pattern, token
|
36
65
|
super "token #{token.inspect} used in translation " +
|
37
66
|
"pattern #{pattern.inspect} is invalid"
|
38
67
|
end
|
68
|
+
|
39
69
|
end
|
40
70
|
|
41
71
|
# This is raised when an inflection token used in a pattern does not match
|
42
72
|
# an assumed kind determined by reading previous tokens from that pattern.
|
43
73
|
class MisplacedInflectionToken < ArgumentError
|
74
|
+
|
44
75
|
attr_reader :pattern, :token, :kind
|
76
|
+
|
45
77
|
def initialize(pattern, token, kind)
|
46
78
|
@pattern, @token, @kind = pattern, token, kind
|
47
79
|
super "inflection token #{token.inspect} from pattern #{pattern.inspect} " +
|
48
80
|
"is not of the expected kind #{kind.inspect}"
|
49
81
|
end
|
82
|
+
|
50
83
|
end
|
51
84
|
|
52
85
|
# This is raised when an inflection token of the same name is already defined in
|
53
86
|
# inflections tree of translation data.
|
54
87
|
class DuplicatedInflectionToken < ArgumentError
|
88
|
+
|
55
89
|
attr_reader :original_kind, :kind, :token
|
90
|
+
|
56
91
|
def initialize(original_kind, kind, token)
|
57
92
|
@original_kind, @kind, @token = original_kind, kind, token
|
58
93
|
and_cannot = kind.nil? ? "" : "and cannot be used with kind #{kind.inspect}"
|
59
94
|
super "inflection token #{token.inspect} was already assigned " +
|
60
|
-
"to kind #{original_kind}" + and_cannot
|
95
|
+
"to kind #{original_kind} " + and_cannot
|
61
96
|
end
|
97
|
+
|
62
98
|
end
|
63
99
|
|
64
100
|
# This is raised when an alias for an inflection token points to a token that
|
65
101
|
# doesn't exists. It is also raised when default token of some kind points
|
66
102
|
# to a non-existent token.
|
67
103
|
class BadInflectionAlias < ArgumentError
|
104
|
+
|
68
105
|
attr_reader :locale, :token, :kind, :pointer
|
106
|
+
|
69
107
|
def initialize(locale, token, kind, pointer)
|
70
108
|
@locale, @token, @kind, @pointer = locale, token, kind, pointer
|
71
109
|
what = token == :default ? "default token" : "alias"
|
72
110
|
lang = locale.nil? ? "" : "for language #{locale.inspect} "
|
73
111
|
kinn = kind.nil? ? "" : "of kind #{kind.inspect} "
|
74
|
-
super "the #{what} #{token.inspect}" + kinn + lang +
|
112
|
+
super "the #{what} #{token.inspect} " + kinn + lang +
|
75
113
|
"points to an unknown token #{pointer.inspect}"
|
76
114
|
end
|
115
|
+
|
77
116
|
end
|
78
117
|
|
79
118
|
# This is raised when an inflection token or its description has a bad name. This
|
80
119
|
# includes an empty name or a name containing prohibited characters.
|
81
120
|
class BadInflectionToken < ArgumentError
|
121
|
+
|
82
122
|
attr_reader :locale, :token, :kind, :description
|
123
|
+
|
83
124
|
def initialize(locale, token, kind=nil, description=nil)
|
84
125
|
@locale, @token, @kind, @description = locale, token, kind, description
|
85
126
|
kinn = kind.nil? ? "" : "of kind #{kind.inspect} "
|
@@ -91,6 +132,7 @@ module I18n
|
|
91
132
|
"for language #{locale.inspect} has a bad description #{description.inspect}"
|
92
133
|
end
|
93
134
|
end
|
135
|
+
|
94
136
|
end
|
95
137
|
|
96
138
|
end
|