3
3
module I18n
4
4
module Backend
5
5
class Simple
6
- INTERPOLATION_RESERVED_KEYS = %w( scope default )
6
+ RESERVED_KEYS = [ : scope, : default]
7
7
MATCH = /(\\ \\ )?\{ \{ ([^\} ]+)\} \} /
8
8
9
9
# Accepts a list of paths to translation files. Loads translations from
@@ -23,15 +23,15 @@ def store_translations(locale, data)
23
23
24
24
def translate ( locale , key , options = { } )
25
25
raise InvalidLocale . new ( locale ) if locale . nil?
26
- return key . map { |k | translate ( locale , k , options ) } if key . is_a? Array
26
+ return key . map { |k | translate ( locale , k , options ) } if key . is_a? ( Array )
27
27
28
- reserved = :scope , :default
29
- count , scope , default = options . values_at ( :count , *reserved )
30
- default = options . delete ( :default )
31
- values = options . reject { |name , value | reserved . include? ( name ) }
28
+ count , scope , default = options . values_at ( :count , *RESERVED_KEYS )
29
+ values = options . reject { |name , value | RESERVED_KEYS . include? ( name ) }
32
30
33
- entry = lookup ( locale , key , scope ) || resolve ( locale , key , default , options ) || raise ( I18n ::MissingTranslationData . new ( locale , key , options ) )
34
- entry = entry . call ( values ) if entry . is_a? Proc
31
+ entry = lookup ( locale , key , scope )
32
+ entry = entry . nil? ? default ( locale , key , default , options ) : resolve ( locale , key , entry , options )
33
+
34
+ raise ( I18n ::MissingTranslationData . new ( locale , key , options ) ) if entry . nil?
35
35
entry = pluralize ( locale , entry , count )
36
36
entry = interpolate ( locale , entry , values )
37
37
entry
@@ -47,16 +47,16 @@ def localize(locale, object, format = :default, options={})
47
47
type = object . respond_to? ( :sec ) ? 'time' : 'date'
48
48
format = lookup ( locale , :"#{ type } .formats.#{ format } " )
49
49
end
50
+
50
51
format = resolve ( locale , object , format , options . merge ( :raise => true ) )
51
- format = format . to_s . dup
52
52
53
53
# TODO only translate these if the format string is actually present
54
- # TODO check which format strings are present, then bulk translate then , then replace them
54
+ # TODO check which format strings are present, then bulk translate them , then replace them
55
55
format . gsub! ( /%a/ , translate ( locale , :"date.abbr_day_names" ) [ object . wday ] )
56
56
format . gsub! ( /%A/ , translate ( locale , :"date.day_names" ) [ object . wday ] )
57
57
format . gsub! ( /%b/ , translate ( locale , :"date.abbr_month_names" ) [ object . mon ] )
58
58
format . gsub! ( /%B/ , translate ( locale , :"date.month_names" ) [ object . mon ] )
59
- format . gsub! ( /%p/ , translate ( locale , :"time.#{ object . hour < 12 ? :am : :pm } " ) ) if object . respond_to? :hour
59
+ format . gsub! ( /%p/ , translate ( locale , :"time.#{ object . hour < 12 ? :am : :pm } " ) ) if object . respond_to? ( :hour )
60
60
object . strftime ( format )
61
61
end
62
62
@@ -103,21 +103,34 @@ def lookup(locale, key, scope = [])
103
103
end
104
104
end
105
105
106
+ # Evaluates defaults.
107
+ # If given subject is an Array, it walks the array and returns the
108
+ # first translation that can be resolved. Otherwise it tries to resolve
109
+ # the translation directly.
110
+ def default ( locale , object , subject , options = { } )
111
+ options = options . dup . reject { |key , value | key == :default }
112
+ case subject
113
+ when Array
114
+ subject . each do |subject |
115
+ result = resolve ( locale , object , subject , options ) and return result
116
+ end and nil
117
+ else
118
+ resolve ( locale , object , subject , options )
119
+ end
120
+ end
121
+
106
122
# Resolves a translation.
107
- # If the given default is a String it is used literally. If it is a Symbol
108
- # it will be translated with the given options. If it is an Array the first
109
- # translation yielded will be returned. If it is a Proc then it is evaluated.
110
- #
111
- # <em>I.e.</em>, <tt>resolve(locale, [:foo, 'default'])</tt> will return +default+ if
112
- # <tt>translate(locale, :foo)</tt> does not yield a result.
123
+ # If the given subject is a Symbol, it will be translated with the
124
+ # given options. If it is a Proc then it will be evaluated. All other
125
+ # subjects will be returned directly.
113
126
def resolve ( locale , object , subject , options = { } )
114
127
case subject
115
- when String then subject
116
- when Symbol then translate locale , subject , options
117
- when Proc then subject . call object , options
118
- when Array then subject . each do | subject |
119
- result = resolve ( locale , object , subject , options . dup ) and return result
120
- end and nil
128
+ when Symbol
129
+ translate ( locale , subject , options )
130
+ when Proc
131
+ subject . call ( object , options )
132
+ else
133
+ subject
121
134
end
122
135
rescue MissingTranslationData
123
136
nil
@@ -129,7 +142,7 @@ def resolve(locale, object, subject, options = {})
129
142
# implement more flexible or complex pluralization rules.
130
143
def pluralize ( locale , entry , count )
131
144
return entry unless entry . is_a? ( Hash ) and count
132
- # raise InvalidPluralizationData.new(entry, count) unless entry.is_a?(Hash)
145
+
133
146
key = :zero if count == 0 && entry . has_key? ( :zero )
134
147
key ||= count == 1 ? :one : :other
135
148
raise InvalidPluralizationData . new ( entry , count ) unless entry . has_key? ( key )
@@ -148,14 +161,14 @@ def interpolate(locale, string, values = {})
148
161
return string unless string . is_a? ( String )
149
162
150
163
string . gsub ( MATCH ) do
151
- escaped , pattern , key = $1, $2 , $2. to_sym
164
+ escaped , key = $1, $2. to_sym
152
165
153
166
if escaped
154
- pattern
155
- elsif INTERPOLATION_RESERVED_KEYS . include? ( pattern )
156
- raise ReservedInterpolationKey . new ( pattern , string )
167
+ key
168
+ elsif RESERVED_KEYS . include? ( key )
169
+ raise ReservedInterpolationKey . new ( key , string )
157
170
elsif !values . include? ( key )
158
- raise MissingInterpolationArgument . new ( pattern , string )
171
+ raise MissingInterpolationArgument . new ( key , string )
159
172
else
160
173
values [ key ] . to_s
161
174
end
@@ -200,11 +213,20 @@ def merge_translations(locale, data)
200
213
# Return a new hash with all keys and nested keys converted to symbols.
201
214
def deep_symbolize_keys ( hash )
202
215
hash . inject ( { } ) { |result , ( key , value ) |
203
- value = deep_symbolize_keys ( value ) if value . is_a? Hash
216
+ value = deep_symbolize_keys ( value ) if value . is_a? ( Hash )
204
217
result [ ( key . to_sym rescue key ) || key ] = value
205
218
result
206
219
}
207
220
end
221
+
222
+ # Flatten the given array once
223
+ def flatten_once ( array )
224
+ result = [ ]
225
+ for element in array # a little faster than each
226
+ result . push ( *element )
227
+ end
228
+ result
229
+ end
208
230
end
209
231
end
210
232
end
0 commit comments