activesupport 2.3.6.pre → 2.3.6

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activesupport might be problematic. Click here for more details.

Files changed (123) hide show
  1. data/CHANGELOG +9 -5
  2. data/lib/active_support/buffered_logger.rb +1 -1
  3. data/lib/active_support/cache/memory_store.rb +7 -1
  4. data/lib/active_support/cache/strategy/local_cache.rb +1 -1
  5. data/lib/active_support/core_ext/array/conversions.rb +1 -1
  6. data/lib/active_support/core_ext/array/random_access.rb +11 -1
  7. data/lib/active_support/core_ext/class/attribute_accessors.rb +35 -28
  8. data/lib/active_support/core_ext/date/calculations.rb +14 -4
  9. data/lib/active_support/core_ext/kernel/reporting.rb +1 -1
  10. data/lib/active_support/core_ext/module/aliasing.rb +1 -1
  11. data/lib/active_support/core_ext/module/attr_accessor_with_default.rb +1 -1
  12. data/lib/active_support/core_ext/module/attribute_accessors.rb +33 -26
  13. data/lib/active_support/core_ext/module/synchronization.rb +1 -1
  14. data/lib/active_support/core_ext/object/blank.rb +20 -2
  15. data/lib/active_support/core_ext/string/output_safety.rb +10 -2
  16. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -4
  17. data/lib/active_support/core_ext/time.rb +8 -4
  18. data/lib/active_support/core_ext/time/calculations.rb +11 -2
  19. data/lib/active_support/deprecation.rb +3 -2
  20. data/lib/active_support/inflections.rb +1 -1
  21. data/lib/active_support/inflector.rb +4 -1
  22. data/lib/active_support/json/backends/yaml.rb +10 -7
  23. data/lib/active_support/json/decoding.rb +1 -1
  24. data/lib/active_support/memoizable.rb +1 -1
  25. data/lib/active_support/multibyte/unicode_database.rb +2 -2
  26. data/lib/active_support/multibyte/utils.rb +6 -7
  27. data/lib/active_support/ordered_hash.rb +24 -30
  28. data/lib/active_support/testing/assertions.rb +14 -0
  29. data/lib/active_support/values/time_zone.rb +84 -76
  30. data/lib/active_support/vendor.rb +1 -1
  31. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n.rb +92 -34
  32. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend.rb +2 -0
  33. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/active_record.rb +9 -13
  34. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/active_record/missing.rb +1 -1
  35. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/active_record/store_procs.rb +6 -6
  36. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/active_record/translation.rb +14 -9
  37. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/base.rb +23 -16
  38. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/cache.rb +1 -0
  39. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/cascade.rb +22 -8
  40. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/chain.rb +2 -1
  41. data/lib/active_support/vendor/i18n-0.3.7/i18n/backend/cldr.rb +100 -0
  42. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/fallbacks.rb +20 -3
  43. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/fast.rb +14 -13
  44. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/gettext.rb +1 -1
  45. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/helpers.rb +4 -16
  46. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/interpolation_compiler.rb +2 -2
  47. data/lib/active_support/vendor/i18n-0.3.7/i18n/backend/links.rb +34 -0
  48. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/metadata.rb +0 -0
  49. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/pluralization.rb +1 -1
  50. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/backend/simple.rb +0 -0
  51. data/lib/active_support/vendor/i18n-0.3.7/i18n/core_ext/hash/except.rb +8 -0
  52. data/lib/active_support/vendor/i18n-0.3.7/i18n/core_ext/hash/slice.rb +8 -0
  53. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/core_ext/object/meta_class.rb +0 -0
  54. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/core_ext/string/interpolate.rb +1 -1
  55. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/exceptions.rb +1 -1
  56. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/gettext.rb +0 -0
  57. data/lib/active_support/vendor/{i18n-0.3.3/vendor → i18n-0.3.7/i18n/gettext}/po_parser.rb +0 -0
  58. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/helpers.rb +0 -0
  59. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/helpers/gettext.rb +3 -2
  60. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/locale.rb +0 -0
  61. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/locale/fallbacks.rb +0 -0
  62. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/locale/tag.rb +0 -0
  63. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/locale/tag/parents.rb +0 -0
  64. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/locale/tag/rfc4646.rb +0 -0
  65. data/lib/active_support/vendor/{i18n-0.3.3/lib → i18n-0.3.7}/i18n/locale/tag/simple.rb +0 -0
  66. data/lib/active_support/vendor/i18n-0.3.7/i18n/version.rb +3 -0
  67. metadata +42 -96
  68. data/lib/active_support/vendor/i18n-0.3.3/CHANGELOG.textile +0 -76
  69. data/lib/active_support/vendor/i18n-0.3.3/MIT-LICENSE +0 -20
  70. data/lib/active_support/vendor/i18n-0.3.3/README.textile +0 -81
  71. data/lib/active_support/vendor/i18n-0.3.3/Rakefile +0 -24
  72. data/lib/active_support/vendor/i18n-0.3.3/benchmark/example.yml +0 -144
  73. data/lib/active_support/vendor/i18n-0.3.3/benchmark/run.rb +0 -71
  74. data/lib/active_support/vendor/i18n-0.3.3/contributors.txt +0 -17
  75. data/lib/active_support/vendor/i18n-0.3.3/i18n.gemspec +0 -165
  76. data/lib/active_support/vendor/i18n-0.3.3/init.rb +0 -1
  77. data/lib/active_support/vendor/i18n-0.3.3/lib/i18n/version.rb +0 -3
  78. data/lib/active_support/vendor/i18n-0.3.3/test/all.rb +0 -8
  79. data/lib/active_support/vendor/i18n-0.3.3/test/api/basics.rb +0 -15
  80. data/lib/active_support/vendor/i18n-0.3.3/test/api/defaults.rb +0 -40
  81. data/lib/active_support/vendor/i18n-0.3.3/test/api/interpolation.rb +0 -92
  82. data/lib/active_support/vendor/i18n-0.3.3/test/api/link.rb +0 -55
  83. data/lib/active_support/vendor/i18n-0.3.3/test/api/localization/date.rb +0 -91
  84. data/lib/active_support/vendor/i18n-0.3.3/test/api/localization/date_time.rb +0 -90
  85. data/lib/active_support/vendor/i18n-0.3.3/test/api/localization/procs.rb +0 -54
  86. data/lib/active_support/vendor/i18n-0.3.3/test/api/localization/time.rb +0 -84
  87. data/lib/active_support/vendor/i18n-0.3.3/test/api/lookup.rb +0 -45
  88. data/lib/active_support/vendor/i18n-0.3.3/test/api/pluralization.rb +0 -35
  89. data/lib/active_support/vendor/i18n-0.3.3/test/api/procs.rb +0 -40
  90. data/lib/active_support/vendor/i18n-0.3.3/test/cases/api/active_record_test.rb +0 -29
  91. data/lib/active_support/vendor/i18n-0.3.3/test/cases/api/all_features_test.rb +0 -40
  92. data/lib/active_support/vendor/i18n-0.3.3/test/cases/api/cascade_test.rb +0 -31
  93. data/lib/active_support/vendor/i18n-0.3.3/test/cases/api/chain_test.rb +0 -26
  94. data/lib/active_support/vendor/i18n-0.3.3/test/cases/api/fallbacks_test.rb +0 -33
  95. data/lib/active_support/vendor/i18n-0.3.3/test/cases/api/fast_test.rb +0 -31
  96. data/lib/active_support/vendor/i18n-0.3.3/test/cases/api/pluralization_test.rb +0 -33
  97. data/lib/active_support/vendor/i18n-0.3.3/test/cases/api/simple_test.rb +0 -21
  98. data/lib/active_support/vendor/i18n-0.3.3/test/cases/backend/active_record/missing_test.rb +0 -60
  99. data/lib/active_support/vendor/i18n-0.3.3/test/cases/backend/active_record_test.rb +0 -52
  100. data/lib/active_support/vendor/i18n-0.3.3/test/cases/backend/cache_test.rb +0 -72
  101. data/lib/active_support/vendor/i18n-0.3.3/test/cases/backend/cascade_test.rb +0 -66
  102. data/lib/active_support/vendor/i18n-0.3.3/test/cases/backend/chain_test.rb +0 -64
  103. data/lib/active_support/vendor/i18n-0.3.3/test/cases/backend/fallbacks_test.rb +0 -57
  104. data/lib/active_support/vendor/i18n-0.3.3/test/cases/backend/fast_test.rb +0 -50
  105. data/lib/active_support/vendor/i18n-0.3.3/test/cases/backend/helpers_test.rb +0 -26
  106. data/lib/active_support/vendor/i18n-0.3.3/test/cases/backend/interpolation_compiler_test.rb +0 -107
  107. data/lib/active_support/vendor/i18n-0.3.3/test/cases/backend/metadata_test.rb +0 -67
  108. data/lib/active_support/vendor/i18n-0.3.3/test/cases/backend/pluralization_test.rb +0 -43
  109. data/lib/active_support/vendor/i18n-0.3.3/test/cases/backend/simple_test.rb +0 -77
  110. data/lib/active_support/vendor/i18n-0.3.3/test/cases/core_ext/string/interpolate_test.rb +0 -94
  111. data/lib/active_support/vendor/i18n-0.3.3/test/cases/gettext/api_test.rb +0 -201
  112. data/lib/active_support/vendor/i18n-0.3.3/test/cases/gettext/backend_test.rb +0 -91
  113. data/lib/active_support/vendor/i18n-0.3.3/test/cases/i18n_exceptions_test.rb +0 -97
  114. data/lib/active_support/vendor/i18n-0.3.3/test/cases/i18n_load_path_test.rb +0 -23
  115. data/lib/active_support/vendor/i18n-0.3.3/test/cases/i18n_test.rb +0 -172
  116. data/lib/active_support/vendor/i18n-0.3.3/test/cases/locale/fallbacks_test.rb +0 -126
  117. data/lib/active_support/vendor/i18n-0.3.3/test/cases/locale/tag/rfc4646_test.rb +0 -143
  118. data/lib/active_support/vendor/i18n-0.3.3/test/cases/locale/tag/simple_test.rb +0 -33
  119. data/lib/active_support/vendor/i18n-0.3.3/test/fixtures/locales/de.po +0 -72
  120. data/lib/active_support/vendor/i18n-0.3.3/test/fixtures/locales/en.rb +0 -3
  121. data/lib/active_support/vendor/i18n-0.3.3/test/fixtures/locales/en.yml +0 -3
  122. data/lib/active_support/vendor/i18n-0.3.3/test/fixtures/locales/plurals.rb +0 -113
  123. data/lib/active_support/vendor/i18n-0.3.3/test/test_helper.rb +0 -100
@@ -23,7 +23,7 @@ end
23
23
  begin
24
24
  gem 'i18n', '>= 0.3.3'
25
25
  rescue Gem::LoadError
26
- $:.unshift "#{File.dirname(__FILE__)}/vendor/i18n-0.3.3/lib"
26
+ $:.unshift "#{File.dirname(__FILE__)}/vendor/i18n-0.3.7"
27
27
  end
28
28
  require 'i18n'
29
29
 
@@ -15,13 +15,18 @@ module I18n
15
15
  autoload :Helpers, 'i18n/helpers'
16
16
  autoload :Locale, 'i18n/locale'
17
17
 
18
- @@backend = nil
19
- @@load_path = nil
20
- @@default_locale = :en
21
- @@default_separator = '.'
22
- @@exception_handler = :default_exception_handler
18
+ class Config
19
+ # The only configuration value that is not global and scoped to thread is :locale.
20
+ # It defaults to the default_locale.
21
+ def locale
22
+ @locale ||= default_locale
23
+ end
24
+
25
+ # Sets the current locale pseudo-globally, i.e. in the Thread.current hash.
26
+ def locale=(locale)
27
+ @locale = locale.to_sym rescue nil
28
+ end
23
29
 
24
- class << self
25
30
  # Returns the current backend. Defaults to +Backend::Simple+.
26
31
  def backend
27
32
  @@backend ||= Backend::Simple.new
@@ -34,7 +39,7 @@ module I18n
34
39
 
35
40
  # Returns the current default locale. Defaults to :'en'
36
41
  def default_locale
37
- @@default_locale
42
+ @@default_locale ||= :en
38
43
  end
39
44
 
40
45
  # Sets the current default locale. Used to set a custom default locale.
@@ -42,16 +47,6 @@ module I18n
42
47
  @@default_locale = locale.to_sym rescue nil
43
48
  end
44
49
 
45
- # Returns the current locale. Defaults to I18n.default_locale.
46
- def locale
47
- Thread.current[:locale] ||= default_locale
48
- end
49
-
50
- # Sets the current locale pseudo-globally, i.e. in the Thread.current hash.
51
- def locale=(locale)
52
- Thread.current[:locale] = locale.to_sym rescue nil
53
- end
54
-
55
50
  # Returns an array of locales for which translations are available.
56
51
  # Unless you explicitely set the these through I18n.available_locales=
57
52
  # the call will be delegated to the backend and memoized on the I18n module.
@@ -66,7 +61,7 @@ module I18n
66
61
 
67
62
  # Returns the current default scope separator. Defaults to '.'
68
63
  def default_separator
69
- @@default_separator
64
+ @@default_separator ||= '.'
70
65
  end
71
66
 
72
67
  # Sets the current default scope separator.
@@ -74,6 +69,11 @@ module I18n
74
69
  @@default_separator = separator
75
70
  end
76
71
 
72
+ # Return the current exception handler. Defaults to :default_exception_handler.
73
+ def exception_handler
74
+ @@exception_handler ||= :default_exception_handler
75
+ end
76
+
77
77
  # Sets the exception handler.
78
78
  def exception_handler=(exception_handler)
79
79
  @@exception_handler = exception_handler
@@ -96,12 +96,39 @@ module I18n
96
96
  def load_path=(load_path)
97
97
  @@load_path = load_path
98
98
  end
99
+ end
100
+
101
+ class << self
102
+
103
+ # Gets I18n configuration object.
104
+ def config
105
+ Thread.current[:i18n_config] ||= I18n::Config.new
106
+ end
107
+
108
+ # Sets I18n configuration object.
109
+ def config=(value)
110
+ Thread.current[:i18n_config] = value
111
+ end
112
+
113
+ # Write methods which delegates to the configuration object
114
+ %w(locale backend default_locale available_locales default_separator
115
+ exception_handler load_path).each do |method|
116
+ module_eval <<-DELEGATORS, __FILE__, __LINE__ + 1
117
+ def #{method}
118
+ config.#{method}
119
+ end
120
+
121
+ def #{method}=(value)
122
+ config.#{method} = (value)
123
+ end
124
+ DELEGATORS
125
+ end
99
126
 
100
127
  # Tells the backend to reload translations. Used in situations like the
101
128
  # Rails development environment. Backends can implement whatever strategy
102
129
  # is useful.
103
130
  def reload!
104
- backend.reload!
131
+ config.backend.reload!
105
132
  end
106
133
 
107
134
  # Translates, pluralizes and interpolates a given key using a given locale,
@@ -203,9 +230,9 @@ module I18n
203
230
  def translate(*args)
204
231
  options = args.pop if args.last.is_a?(Hash)
205
232
  key = args.shift
206
- locale = options && options.delete(:locale) || I18n.locale
233
+ locale = options && options.delete(:locale) || config.locale
207
234
  raises = options && options.delete(:raise)
208
- backend.translate(locale, key, options || {})
235
+ config.backend.translate(locale, key, options || {})
209
236
  rescue I18n::ArgumentError => exception
210
237
  raise exception if raises
211
238
  handle_exception(exception, locale, key, options)
@@ -219,12 +246,22 @@ module I18n
219
246
 
220
247
  # Localizes certain objects, such as dates and numbers to local formatting.
221
248
  def localize(object, options = {})
222
- locale = options[:locale] || I18n.locale
223
- format = options[:format] || :default
224
- backend.localize(locale, object, format)
249
+ locale = options.delete(:locale) || config.locale
250
+ format = options.delete(:format) || :default
251
+ config.backend.localize(locale, object, format, options)
225
252
  end
226
253
  alias :l :localize
227
254
 
255
+ # Merges the given locale, key and scope into a single array of keys.
256
+ # Splits keys that contain dots into multiple keys. Makes sure all
257
+ # keys are Symbols.
258
+ def normalize_keys(locale, key, scope, separator = nil)
259
+ separator ||= I18n.default_separator
260
+ normalize_key(locale, separator) +
261
+ normalize_key(scope, separator) +
262
+ normalize_key(key, separator)
263
+ end
264
+
228
265
  # making these private until Ruby 1.9.2 can send to protected methods again
229
266
  # see http://redmine.ruby-lang.org/repositories/revision/ruby-19?rev=24280
230
267
  private
@@ -256,22 +293,43 @@ module I18n
256
293
  # I18n.exception_handler = I18nExceptionHandler.new # an object
257
294
  # I18n.exception_handler.call(exception, locale, key, options) # will be called like this
258
295
  def handle_exception(exception, locale, key, options)
259
- case @@exception_handler
296
+ case config.exception_handler
260
297
  when Symbol
261
- send(@@exception_handler, exception, locale, key, options)
298
+ send(config.exception_handler, exception, locale, key, options)
262
299
  else
263
- @@exception_handler.call(exception, locale, key, options)
300
+ config.exception_handler.call(exception, locale, key, options)
264
301
  end
265
302
  end
266
303
 
267
- # Merges the given locale, key and scope into a single array of keys.
268
- # Splits keys that contain dots into multiple keys. Makes sure all
269
- # keys are Symbols.
304
+ # Deprecated. Will raise a warning in future versions and then finally be
305
+ # removed. Use I18n.normalize_keys instead.
270
306
  def normalize_translation_keys(locale, key, scope, separator = nil)
271
- keys = [locale] + Array(scope) + Array(key)
272
- keys = keys.map { |k| k.to_s.split(separator || I18n.default_separator) }
273
- keys = keys.flatten - ['']
274
- keys.map { |k| k.to_sym }
307
+ normalize_keys(locale, key, scope, separator)
308
+ end
309
+
310
+ def normalize_key(key, separator)
311
+ normalized_key_cache(separator)[key] ||=
312
+ case key
313
+ when Array
314
+ key.map { |k| normalize_key(k, separator) }.flatten
315
+ when nil
316
+ []
317
+ else
318
+ key = key.to_s
319
+ if key == ''
320
+ []
321
+ elsif key.include?(separator)
322
+ keys = key.split(separator) - ['']
323
+ keys.map { |k| k.to_sym }
324
+ else
325
+ [key.to_sym]
326
+ end
327
+ end
328
+ end
329
+
330
+ def normalized_key_cache(separator)
331
+ @normalized_key_cache ||= Hash.new { |h,k| h[k] = {} }
332
+ @normalized_key_cache[separator]
275
333
  end
276
334
  end
277
335
  end
@@ -5,10 +5,12 @@ module I18n
5
5
  autoload :Cache, 'i18n/backend/cache'
6
6
  autoload :Cascade, 'i18n/backend/cascade'
7
7
  autoload :Chain, 'i18n/backend/chain'
8
+ autoload :Cldr, 'i18n/backend/cldr'
8
9
  autoload :Fallbacks, 'i18n/backend/fallbacks'
9
10
  autoload :Fast, 'i18n/backend/fast'
10
11
  autoload :Gettext, 'i18n/backend/gettext'
11
12
  autoload :Helpers, 'i18n/backend/helpers'
13
+ autoload :Links, 'i18n/backend/links'
12
14
  autoload :InterpolationCompiler, 'i18n/backend/interpolation_compiler'
13
15
  autoload :Metadata, 'i18n/backend/metadata'
14
16
  autoload :Pluralization, 'i18n/backend/pluralization'
@@ -1,13 +1,6 @@
1
1
  require 'i18n/backend/base'
2
2
  require 'i18n/backend/active_record/translation'
3
3
 
4
- #
5
- # This backend reads translations from a Translations table in environment database. Note that the database
6
- # will not automatically be prepopulated with missing keys. You can achieve this effect with the ActiveRecordMissing backend,
7
- # as the following example shows:
8
- #
9
- # I18n.backend = I18n::Backend::Chain.new(I18n::Backend::ActiveRecord.new, I18.backend, I18n::Backend::ActiveRecordMissing.new)
10
- #
11
4
  module I18n
12
5
  module Backend
13
6
  class ActiveRecord
@@ -15,16 +8,17 @@ module I18n
15
8
  autoload :StoreProcs, 'i18n/backend/active_record/store_procs'
16
9
  autoload :Translation, 'i18n/backend/active_record/translation'
17
10
 
18
- include Base
11
+ include Base, Links
19
12
 
20
13
  def reload!
21
14
  end
22
15
 
23
16
  def store_translations(locale, data, options = {})
24
17
  separator = options[:separator] || I18n.default_separator
25
- wind_keys(data, separator).each do |key, v|
18
+ wind_keys(data, separator).each do |key, value|
19
+ store_link(locale, key, value) if value.is_a?(Symbol)
26
20
  Translation.locale(locale).lookup(expand_keys(key, separator), separator).delete_all
27
- Translation.create(:locale => locale.to_s, :key => key.to_s, :value => v)
21
+ Translation.create(:locale => locale.to_s, :key => key.to_s, :value => value)
28
22
  end
29
23
  end
30
24
 
@@ -38,13 +32,15 @@ module I18n
38
32
 
39
33
  protected
40
34
 
41
- def lookup(locale, key, scope = [], separator = nil)
35
+ def lookup(locale, key, scope = [], options = {})
42
36
  return unless key
43
37
 
44
- separator ||= I18n.default_separator
45
- key = (Array(scope) + Array(key)).join(separator)
38
+ separator = options[:separator] || I18n.default_separator
46
39
 
40
+ key = resolve_link(locale, key)
41
+ key = (Array(scope) + Array(key)).join(separator)
47
42
  result = Translation.locale(locale).lookup(key, separator).all
43
+
48
44
  if result.empty?
49
45
  return nil
50
46
  elsif result.first.key == key
@@ -37,7 +37,7 @@ module I18n
37
37
  count, scope, default, separator = options.values_at(:count, *Base::RESERVED_KEYS)
38
38
  separator ||= I18n.default_separator
39
39
 
40
- keys = I18n.send(:normalize_translation_keys, locale, key, scope, separator)[1..-1]
40
+ keys = I18n.normalize_keys(locale, key, scope, separator)[1..-1]
41
41
  key = keys.join(separator || I18n.default_separator)
42
42
 
43
43
  unless ActiveRecord::Translation.locale(locale).lookup(key, separator).exists?
@@ -23,15 +23,15 @@ module I18n
23
23
  module StoreProcs
24
24
  def value=(v)
25
25
  case v
26
- when Proc
27
- write_attribute(:value, v.to_ruby)
28
- write_attribute(:is_proc, true)
29
- else
30
- write_attribute(:value, v)
26
+ when Proc
27
+ write_attribute(:value, v.to_ruby)
28
+ write_attribute(:is_proc, true)
29
+ else
30
+ write_attribute(:value, v)
31
31
  end
32
32
  end
33
33
 
34
- Translation.send(:include, self) unless RUBY_VERSION >= '1.9'
34
+ Translation.send(:include, self) if method(:to_s).respond_to?(:to_ruby)
35
35
  end
36
36
  end
37
37
  end
@@ -10,7 +10,8 @@ module I18n
10
10
  # create_table :translations do |t|
11
11
  # t.string :locale
12
12
  # t.string :key
13
- # t.string :value
13
+ # t.text :value
14
+ # t.text :interpolations
14
15
  # t.boolean :is_proc, :default => false
15
16
  # end
16
17
  #
@@ -47,31 +48,35 @@ module I18n
47
48
  class Translation < ::ActiveRecord::Base
48
49
  set_table_name 'translations'
49
50
  attr_protected :is_proc, :interpolations
50
-
51
+
51
52
  serialize :value
52
53
  serialize :interpolations, Array
53
54
 
54
- named_scope :locale, lambda { |locale|
55
+ scope_method = ::ActiveRecord::VERSION::MAJOR == 2 ? :named_scope : :scope
56
+
57
+ send scope_method, :locale, lambda { |locale|
55
58
  { :conditions => { :locale => locale.to_s } }
56
59
  }
57
60
 
58
- named_scope :lookup, lambda { |keys, *separator|
59
- keys = Array(keys).map! { |key| key.to_s }
60
- separator = separator.first || I18n.default_separator
61
- { :conditions => ["`key` IN (?) OR `key` LIKE '#{keys.last}#{separator}%'", keys] }
61
+ send scope_method, :lookup, lambda { |keys, *separator|
62
+ column_name = connection.quote_column_name('key')
63
+ keys = Array(keys).map! { |key| key.to_s }
64
+ separator = separator.first || I18n.default_separator
65
+ namespace = "#{keys.last}#{separator}%"
66
+ { :conditions => ["#{column_name} IN (?) OR #{column_name} LIKE ?", keys, namespace] }
62
67
  }
63
68
 
64
69
  def self.available_locales
65
70
  Translation.find(:all, :select => 'DISTINCT locale').map { |t| t.locale.to_sym }
66
71
  end
67
-
72
+
68
73
  def interpolates?(key)
69
74
  self.interpolations.include?(key) if self.interpolations
70
75
  end
71
76
 
72
77
  def value
73
78
  if is_proc
74
- Kernel.eval read_attribute(:value)
79
+ Kernel.eval(read_attribute(:value))
75
80
  else
76
81
  value = read_attribute(:value)
77
82
  value == 'f' ? false : value
@@ -1,13 +1,14 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require 'yaml'
4
+ require 'i18n/core_ext/hash/except'
4
5
 
5
6
  module I18n
6
7
  module Backend
7
8
  module Base
8
9
  include I18n::Backend::Helpers
9
10
 
10
- RESERVED_KEYS = [:scope, :default, :separator]
11
+ RESERVED_KEYS = [:scope, :default, :separator, :resolve]
11
12
  INTERPOLATION_SYNTAX_PATTERN = /(\\)?\{\{([^\}]+)\}\}/
12
13
 
13
14
  # Accepts a list of paths to translation files. Loads translations from
@@ -22,7 +23,7 @@ module I18n
22
23
  # translations will be overwritten by new ones only at the deepest
23
24
  # level of the hash.
24
25
  def store_translations(locale, data, options = {})
25
- merge_translations(locale, data)
26
+ merge_translations(locale, data, options)
26
27
  end
27
28
 
28
29
  def translate(locale, key, options = {})
@@ -33,10 +34,10 @@ module I18n
33
34
  entry = resolve(locale, key, lookup(locale, key), options)
34
35
  raise(I18n::MissingTranslationData.new(locale, key, options)) if entry.nil?
35
36
  else
36
- count, scope, default, separator = options.values_at(:count, :scope, :default, :separator)
37
+ count, scope, default = options.values_at(:count, :scope, :default)
37
38
  values = options.reject { |name, value| RESERVED_KEYS.include?(name) }
38
39
 
39
- entry = lookup(locale, key, scope, separator)
40
+ entry = lookup(locale, key, scope, options)
40
41
  entry = entry.nil? && default ? default(locale, key, default, options) : resolve(locale, key, entry, options)
41
42
  raise(I18n::MissingTranslationData.new(locale, key, options)) if entry.nil?
42
43
 
@@ -56,11 +57,10 @@ module I18n
56
57
  if Symbol === format
57
58
  key = format
58
59
  type = object.respond_to?(:sec) ? 'time' : 'date'
59
- format = lookup(locale, :"#{type}.formats.#{key}")
60
- raise(MissingTranslationData.new(locale, key, options)) if format.nil?
60
+ format = I18n.t(:"#{type}.formats.#{key}", :locale => locale, :raise => true)
61
61
  end
62
62
 
63
- format = resolve(locale, object, format, options)
63
+ # format = resolve(locale, object, format, options)
64
64
  format = format.to_s.gsub(/%[aAbBp]/) do |match|
65
65
  case match
66
66
  when '%a' then I18n.t(:"date.abbr_day_names", :locale => locale, :format => format)[object.wday]
@@ -108,16 +108,16 @@ module I18n
108
108
  # nested translations hash. Splits keys or scopes containing dots
109
109
  # into multiple keys, i.e. <tt>currency.format</tt> is regarded the same as
110
110
  # <tt>%w(currency format)</tt>.
111
- def lookup(locale, key, scope = [], separator = nil)
111
+ def lookup(locale, key, scope = [], options = {})
112
112
  return unless key
113
113
  init_translations unless initialized?
114
- keys = I18n.send(:normalize_translation_keys, locale, key, scope, separator)
114
+ keys = I18n.normalize_keys(locale, key, scope, options[:separator])
115
115
  keys.inject(translations) do |result, key|
116
116
  key = key.to_sym
117
117
  return nil unless result.is_a?(Hash) && result.has_key?(key)
118
118
  result = result[key]
119
- result = resolve(locale, key, result, :separator => separator) if result.is_a?(Symbol)
120
- result
119
+ result = resolve(locale, key, result, options) if result.is_a?(Symbol)
120
+ String === result ? result.dup : result
121
121
  end
122
122
  end
123
123
 
@@ -142,6 +142,7 @@ module I18n
142
142
  # given options. If it is a Proc then it will be evaluated. All other
143
143
  # subjects will be returned directly.
144
144
  def resolve(locale, object, subject, options = nil)
145
+ return subject if options[:resolve] == false
145
146
  case subject
146
147
  when Symbol
147
148
  I18n.translate(subject, (options || {}).merge(:locale => locale, :raise => true))
@@ -176,7 +177,7 @@ module I18n
176
177
  # the <tt>{{...}}</tt> key in a string (once for the string and once for the
177
178
  # interpolation).
178
179
  def interpolate(locale, string, values = {})
179
- return string unless string.is_a?(String) && !values.empty?
180
+ return string unless string.is_a?(::String) && !values.empty?
180
181
 
181
182
  preserve_encoding(string) do
182
183
  s = string.gsub(INTERPOLATION_SYNTAX_PATTERN) do
@@ -192,7 +193,7 @@ module I18n
192
193
 
193
194
  values.each do |key, value|
194
195
  value = value.call(values) if interpolate_lambda?(value, s, key)
195
- value = value.to_s unless value.is_a?(String)
196
+ value = value.to_s unless value.is_a?(::String)
196
197
  values[key] = value
197
198
  end
198
199
 
@@ -227,7 +228,7 @@ module I18n
227
228
  def load_file(filename)
228
229
  type = File.extname(filename).tr('.', '').downcase
229
230
  raise UnknownFileType.new(type, filename) unless respond_to?(:"load_#{type}")
230
- data = send :"load_#{type}", filename # TODO raise a meaningful exception if this does not yield a Hash
231
+ data = send(:"load_#{type}", filename) # TODO raise a meaningful exception if this does not yield a Hash
231
232
  data.each { |locale, d| merge_translations(locale, d) }
232
233
  end
233
234
 
@@ -245,13 +246,19 @@ module I18n
245
246
 
246
247
  # Deep merges the given translations hash with the existing translations
247
248
  # for the given locale
248
- def merge_translations(locale, data)
249
+ def merge_translations(locale, data, options = {})
249
250
  locale = locale.to_sym
250
251
  translations[locale] ||= {}
252
+ separator = options[:separator] || I18n.default_separator
253
+ data = unwind_keys(data, separator)
251
254
  data = deep_symbolize_keys(data)
252
255
 
253
256
  # deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809
254
- merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
257
+ merger = proc do |key, v1, v2|
258
+ # TODO should probably be:
259
+ # raise TypeError.new("can't merge #{v1.inspect} and #{v2.inspect}") unless Hash === v1 && Hash === v2
260
+ Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : (v2 || v1)
261
+ end
255
262
  translations[locale].merge!(data, &merger)
256
263
  end
257
264
  end