i18n-inflector 2.0.1 → 2.1.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/.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
|