i18n 1.0.1 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +54 -13
  3. data/lib/i18n.rb +53 -27
  4. data/lib/i18n/backend.rb +1 -0
  5. data/lib/i18n/backend/base.rb +36 -9
  6. data/lib/i18n/backend/cache.rb +2 -5
  7. data/lib/i18n/backend/cache_file.rb +36 -0
  8. data/lib/i18n/backend/chain.rb +28 -0
  9. data/lib/i18n/backend/gettext.rb +2 -0
  10. data/lib/i18n/backend/key_value.rb +27 -0
  11. data/lib/i18n/backend/memoize.rb +6 -0
  12. data/lib/i18n/backend/simple.rb +22 -6
  13. data/lib/i18n/config.rb +17 -1
  14. data/lib/i18n/core_ext/hash.rb +42 -24
  15. data/lib/i18n/exceptions.rb +20 -15
  16. data/lib/i18n/interpolate/ruby.rb +5 -3
  17. data/lib/i18n/locale/fallbacks.rb +1 -1
  18. data/lib/i18n/tests/interpolation.rb +1 -1
  19. data/lib/i18n/tests/localization/date.rb +28 -6
  20. data/lib/i18n/tests/localization/date_time.rb +27 -6
  21. data/lib/i18n/tests/localization/time.rb +26 -4
  22. data/lib/i18n/version.rb +1 -1
  23. metadata +24 -58
  24. data/gemfiles/Gemfile.rails-3.2.x +0 -10
  25. data/gemfiles/Gemfile.rails-4.0.x +0 -10
  26. data/gemfiles/Gemfile.rails-4.1.x +0 -10
  27. data/gemfiles/Gemfile.rails-4.2.x +0 -10
  28. data/gemfiles/Gemfile.rails-5.0.x +0 -10
  29. data/gemfiles/Gemfile.rails-5.1.x +0 -10
  30. data/gemfiles/Gemfile.rails-master +0 -10
  31. data/lib/i18n/core_ext/kernel/suppress_warnings.rb +0 -8
  32. data/lib/i18n/core_ext/string/interpolate.rb +0 -9
  33. data/test/api/all_features_test.rb +0 -58
  34. data/test/api/cascade_test.rb +0 -28
  35. data/test/api/chain_test.rb +0 -24
  36. data/test/api/fallbacks_test.rb +0 -30
  37. data/test/api/key_value_test.rb +0 -24
  38. data/test/api/memoize_test.rb +0 -56
  39. data/test/api/override_test.rb +0 -42
  40. data/test/api/pluralization_test.rb +0 -30
  41. data/test/api/simple_test.rb +0 -28
  42. data/test/backend/cache_test.rb +0 -109
  43. data/test/backend/cascade_test.rb +0 -86
  44. data/test/backend/chain_test.rb +0 -122
  45. data/test/backend/exceptions_test.rb +0 -36
  46. data/test/backend/fallbacks_test.rb +0 -219
  47. data/test/backend/interpolation_compiler_test.rb +0 -118
  48. data/test/backend/key_value_test.rb +0 -61
  49. data/test/backend/memoize_test.rb +0 -79
  50. data/test/backend/metadata_test.rb +0 -48
  51. data/test/backend/pluralization_test.rb +0 -45
  52. data/test/backend/simple_test.rb +0 -103
  53. data/test/backend/transliterator_test.rb +0 -84
  54. data/test/core_ext/hash_test.rb +0 -36
  55. data/test/gettext/api_test.rb +0 -214
  56. data/test/gettext/backend_test.rb +0 -92
  57. data/test/i18n/exceptions_test.rb +0 -117
  58. data/test/i18n/gettext_plural_keys_test.rb +0 -20
  59. data/test/i18n/interpolate_test.rb +0 -91
  60. data/test/i18n/load_path_test.rb +0 -34
  61. data/test/i18n/middleware_test.rb +0 -24
  62. data/test/i18n_test.rb +0 -462
  63. data/test/locale/fallbacks_test.rb +0 -133
  64. data/test/locale/tag/rfc4646_test.rb +0 -143
  65. data/test/locale/tag/simple_test.rb +0 -32
  66. data/test/run_all.rb +0 -20
  67. data/test/test_data/locales/de.po +0 -82
  68. data/test/test_data/locales/en.rb +0 -3
  69. data/test/test_data/locales/en.yml +0 -3
  70. data/test/test_data/locales/invalid/empty.yml +0 -0
  71. data/test/test_data/locales/invalid/syntax.yml +0 -4
  72. data/test/test_data/locales/plurals.rb +0 -113
  73. data/test/test_helper.rb +0 -61
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6abb11703c717406a1a4e5df13e88679656a3bb798cd0141e4ef9961fed64056
4
- data.tar.gz: 1e633332f63054b3919c887a853a1bb4348025550531bf3f499a924a1b37acf5
3
+ metadata.gz: 2b03b84d726d3cafa7ea2ecaa6f258cb911696c338cb32c769f71b6d62ca5fb5
4
+ data.tar.gz: 7a489bf447e9fedee8fd043cc8ba324c0afc0c34701fbfeff5f15b1c1f4fa6b4
5
5
  SHA512:
6
- metadata.gz: 6fe991afffcec28225b53932a1977c6c30ee6f8a79a0256380a552f25ca6d0bffd3b21452d8177529d97aac9f880e1296072804942c0b99a379ecfeb6c8ca446
7
- data.tar.gz: b8a7625539fe9e5c0c49b0a85a3bce54c1fb46e68ed4910870aee8c6f37afb589888b3ba87a6786e4364021a831619874f796a38eea6d0e6b285f67e232b3926
6
+ metadata.gz: 534659c40a8df9eb3fd9a123b779de0f1b66471ecd3fb35e2083128193f51aeea95df6aad06039b6309932a6efb3426c525a8759e70c1104754fdd921732d6cd
7
+ data.tar.gz: caddebe447a797be3dde1607e74d826588ee13ee1317c6abfbb08cbd8a22d79a6aa10a84d3fd21fa45ca9348317aa0e0aafe1c408d4e1c989fbee7f09cd87606
data/README.md CHANGED
@@ -1,12 +1,55 @@
1
1
  # Ruby I18n
2
2
 
3
- [![Build Status](https://api.travis-ci.org/svenfuchs/i18n.svg?branch=master)](https://travis-ci.org/svenfuchs/i18n)
3
+ [![Build Status](https://api.travis-ci.org/ruby-i18n/i18n.svg?branch=master)](https://travis-ci.org/ruby-i18n/i18n)
4
4
 
5
5
  Ruby Internationalization and localization solution.
6
6
 
7
- [See the Rails Guide](http://guides.rubyonrails.org/i18n.html) for an example of its usage. (Note: This library can be used independently from Rails.)
7
+ Currently maintained by @radar.
8
8
 
9
- Features:
9
+ ## Usage
10
+
11
+ ### Rails
12
+
13
+ You will most commonly use this library within a Rails app.
14
+
15
+ [See the Rails Guide](http://guides.rubyonrails.org/i18n.html) for an example of its usage.
16
+
17
+ ### Ruby (without Rails)
18
+
19
+ If you want to use this library without Rails, you can simply add `i18n` to your `Gemfile`:
20
+
21
+ ```ruby
22
+ gem 'i18n'
23
+ ```
24
+
25
+ Then configure I18n with some translations, and a default locale:
26
+
27
+ ```ruby
28
+ I18n.load_path << Dir[File.expand_path("config/locales") + "/*.yml"]
29
+ I18n.default_locale = :en # (note that `en` is already the default!)
30
+ ```
31
+
32
+ A simple translation file in your project might live at `config/locales/en.yml` and look like:
33
+
34
+ ```yml
35
+ en:
36
+ test: "This is a test"
37
+ ```
38
+
39
+ You can then access this translation by doing:
40
+
41
+ ```ruby
42
+ I18n.t(:test)
43
+ ```
44
+
45
+ You can switch locales in your project by setting `I18n.locale` to a different value:
46
+
47
+ ```ruby
48
+ I18n.locale = :de
49
+ I18n.t(:test) # => "Dies ist ein Test"
50
+ ```
51
+
52
+ ## Features
10
53
 
11
54
  * translation and localization
12
55
  * interpolation of values to translations (Ruby 1.9 compatible syntax)
@@ -19,27 +62,21 @@ Features:
19
62
  * custom exception handlers
20
63
  * extensible architecture with a swappable backend
21
64
 
22
- Pluggable features:
65
+ ## Pluggable Features
23
66
 
24
67
  * Cache
25
68
  * Pluralization: lambda pluralizers stored as translation data
26
69
  * Locale fallbacks, RFC4647 compliant (optionally: RFC4646 locale validation)
27
- * [Gettext support](https://github.com/svenfuchs/i18n/wiki/Gettext)
70
+ * [Gettext support](https://github.com/ruby-i18n/i18n/wiki/Gettext)
28
71
  * Translation metadata
29
72
 
30
- Alternative backends:
73
+ ## Alternative Backend
31
74
 
32
75
  * Chain
33
76
  * ActiveRecord (optionally: ActiveRecord::Missing and ActiveRecord::StoreProcs)
34
77
  * KeyValue (uses active_support/json and cannot store procs)
35
78
 
36
- For more information and lots of resources see [the 'Resources' page on the wiki](https://github.com/svenfuchs/i18n/wiki/Resources).
37
-
38
- ## Installation
39
-
40
- ```
41
- gem install i18n
42
- ```
79
+ For more information and lots of resources see [the 'Resources' page on the wiki](https://github.com/ruby-i18n/i18n/wiki/Resources).
43
80
 
44
81
  ## Tests
45
82
 
@@ -67,6 +104,10 @@ the API definition test methods in test/api/tests.
67
104
  All other test cases (e.g. as defined in test/backend, test/core_ext) etc.
68
105
  follow the usual test setup and should be easy to grok.
69
106
 
107
+ ## More Documentation
108
+
109
+ Additional documentation can be found here: https://github.com/svenfuchs/i18n/wiki
110
+
70
111
  ## Authors
71
112
 
72
113
  * [Sven Fuchs](http://www.artweb-design.de)
@@ -69,6 +69,13 @@ module I18n
69
69
  config.backend.reload!
70
70
  end
71
71
 
72
+ # Tells the backend to load translations now. Used in situations like the
73
+ # Rails production environment. Backends can implement whatever strategy
74
+ # is useful.
75
+ def eager_load!
76
+ config.backend.eager_load!
77
+ end
78
+
72
79
  # Translates, pluralizes and interpolates a given key using a given locale,
73
80
  # scope, and default, as well as interpolation values.
74
81
  #
@@ -169,15 +176,13 @@ module I18n
169
176
  # from the argument values passed to #translate. Therefor your lambdas should
170
177
  # always return the same translations/values per unique combination of argument
171
178
  # values.
172
- def translate(*args)
173
- options = args.last.is_a?(Hash) ? args.pop.dup : {}
174
- key = args.shift
175
- backend = config.backend
176
- locale = options.delete(:locale) || config.locale
177
- handling = options.delete(:throw) && :throw || options.delete(:raise) && :raise # TODO deprecate :raise
178
-
179
+ def translate(key = nil, *, throw: false, raise: false, locale: nil, **options) # TODO deprecate :raise
180
+ locale ||= config.locale
181
+ raise Disabled.new('t') if locale == false
179
182
  enforce_available_locales!(locale)
180
183
 
184
+ backend = config.backend
185
+
181
186
  result = catch(:exception) do
182
187
  if key.is_a?(Array)
183
188
  key.map { |k| backend.translate(locale, k, options) }
@@ -185,7 +190,12 @@ module I18n
185
190
  backend.translate(locale, key, options)
186
191
  end
187
192
  end
188
- result.is_a?(MissingTranslation) ? handle_exception(handling, result, locale, key, options) : result
193
+
194
+ if result.is_a?(MissingTranslation)
195
+ handle_exception((throw && :throw || raise && :raise), result, locale, key, options)
196
+ else
197
+ result
198
+ end
189
199
  end
190
200
  alias :t :translate
191
201
 
@@ -197,7 +207,9 @@ module I18n
197
207
  alias :t! :translate!
198
208
 
199
209
  # Returns true if a translation exists for a given key, otherwise returns false.
200
- def exists?(key, locale = config.locale)
210
+ def exists?(key, _locale = nil, locale: _locale)
211
+ locale ||= config.locale
212
+ raise Disabled.new('exists?') if locale == false
201
213
  raise I18n::ArgumentError if key.is_a?(String) && key.empty?
202
214
  config.backend.exists?(locale, key)
203
215
  end
@@ -253,37 +265,40 @@ module I18n
253
265
  # I18n.transliterate("Jürgen") # => "Juergen"
254
266
  # I18n.transliterate("Jürgen", :locale => :en) # => "Jurgen"
255
267
  # I18n.transliterate("Jürgen", :locale => :de) # => "Juergen"
256
- def transliterate(*args)
257
- options = args.pop.dup if args.last.is_a?(Hash)
258
- key = args.shift
259
- locale = options && options.delete(:locale) || config.locale
260
- handling = options && (options.delete(:throw) && :throw || options.delete(:raise) && :raise)
261
- replacement = options && options.delete(:replacement)
268
+ def transliterate(key, *, throw: false, raise: false, locale: nil, replacement: nil, **options)
269
+ locale ||= config.locale
270
+ raise Disabled.new('transliterate') if locale == false
262
271
  enforce_available_locales!(locale)
272
+
263
273
  config.backend.transliterate(locale, key, replacement)
264
274
  rescue I18n::ArgumentError => exception
265
- handle_exception(handling, exception, locale, key, options || {})
275
+ handle_exception((throw && :throw || raise && :raise), exception, locale, key, options)
266
276
  end
267
277
 
268
278
  # Localizes certain objects, such as dates and numbers to local formatting.
269
- def localize(object, options = nil)
270
- options = options ? options.dup : {}
271
- locale = options.delete(:locale) || config.locale
272
- format = options.delete(:format) || :default
279
+ def localize(object, locale: nil, format: nil, **options)
280
+ locale ||= config.locale
281
+ raise Disabled.new('l') if locale == false
273
282
  enforce_available_locales!(locale)
283
+
284
+ format ||= :default
274
285
  config.backend.localize(locale, object, format, options)
275
286
  end
276
287
  alias :l :localize
277
288
 
278
289
  # Executes block with given I18n.locale set.
279
290
  def with_locale(tmp_locale = nil)
280
- if tmp_locale
291
+ if tmp_locale == nil
292
+ yield
293
+ else
281
294
  current_locale = self.locale
282
- self.locale = tmp_locale
295
+ self.locale = tmp_locale
296
+ begin
297
+ yield
298
+ ensure
299
+ self.locale = current_locale
300
+ end
283
301
  end
284
- yield
285
- ensure
286
- self.locale = current_locale if tmp_locale
287
302
  end
288
303
 
289
304
  # Merges the given locale, key and scope into a single array of keys.
@@ -307,7 +322,7 @@ module I18n
307
322
 
308
323
  # Raises an InvalidLocale exception when the passed locale is not available.
309
324
  def enforce_available_locales!(locale)
310
- if config.enforce_available_locales
325
+ if locale != false && config.enforce_available_locales
311
326
  raise I18n::InvalidLocale.new(locale) if !locale_available?(locale)
312
327
  end
313
328
  end
@@ -362,7 +377,18 @@ module I18n
362
377
  else
363
378
  keys = key.to_s.split(separator)
364
379
  keys.delete('')
365
- keys.map! { |k| k.to_sym }
380
+ keys.map! do |k|
381
+ case k
382
+ when /\A[-+]?[1-9]\d*\z/ # integer
383
+ k.to_i
384
+ when 'true'
385
+ true
386
+ when 'false'
387
+ false
388
+ else
389
+ k.to_sym
390
+ end
391
+ end
366
392
  keys
367
393
  end
368
394
  end
@@ -5,6 +5,7 @@ module I18n
5
5
  autoload :Base, 'i18n/backend/base'
6
6
  autoload :InterpolationCompiler, 'i18n/backend/interpolation_compiler'
7
7
  autoload :Cache, 'i18n/backend/cache'
8
+ autoload :CacheFile, 'i18n/backend/cache_file'
8
9
  autoload :Cascade, 'i18n/backend/cascade'
9
10
  autoload :Chain, 'i18n/backend/chain'
10
11
  autoload :Fallbacks, 'i18n/backend/fallbacks'
@@ -1,16 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'yaml'
4
+ require 'json'
4
5
  require 'i18n/core_ext/hash'
5
- require 'i18n/core_ext/kernel/suppress_warnings'
6
6
 
7
7
  module I18n
8
8
  module Backend
9
9
  module Base
10
+ using I18n::HashRefinements
10
11
  include I18n::Backend::Transliterator
11
12
 
12
13
  # Accepts a list of paths to translation files. Loads translations from
13
- # plain Ruby (*.rb) or YAML files (*.yml). See #load_rb and #load_yml
14
+ # plain Ruby (*.rb), YAML files (*.yml), or JSON files (*.json). See #load_rb, #load_yml, and #load_json
14
15
  # for details.
15
16
  def load_translations(*filenames)
16
17
  filenames = I18n.load_path if filenames.empty?
@@ -94,10 +95,19 @@ module I18n
94
95
  end
95
96
 
96
97
  def reload!
98
+ eager_load! if eager_loaded?
99
+ end
100
+
101
+ def eager_load!
102
+ @eager_loaded = true
97
103
  end
98
104
 
99
105
  protected
100
106
 
107
+ def eager_loaded?
108
+ @eager_loaded ||= false
109
+ end
110
+
101
111
  # The method which actually looks up for the translation in the store.
102
112
  def lookup(locale, key, scope = [], options = EMPTY_HASH)
103
113
  raise NotImplementedError
@@ -234,18 +244,35 @@ module I18n
234
244
  raise InvalidLocaleData.new(filename, e.inspect)
235
245
  end
236
246
  end
247
+ alias_method :load_yaml, :load_yml
248
+
249
+ # Loads a JSON translations file. The data must have locales as
250
+ # toplevel keys.
251
+ def load_json(filename)
252
+ begin
253
+ ::JSON.parse(File.read(filename))
254
+ rescue TypeError, StandardError => e
255
+ raise InvalidLocaleData.new(filename, e.inspect)
256
+ end
257
+ end
237
258
 
238
259
  def translate_localization_format(locale, object, format, options)
239
- format.to_s.gsub(/%[aAbBpP]/) do |match|
260
+ format.to_s.gsub(/%(|\^)[aAbBpP]/) do |match|
240
261
  case match
241
- when '%a' then I18n.t(:"date.abbr_day_names", :locale => locale, :format => format)[object.wday]
242
- when '%A' then I18n.t(:"date.day_names", :locale => locale, :format => format)[object.wday]
243
- when '%b' then I18n.t(:"date.abbr_month_names", :locale => locale, :format => format)[object.mon]
244
- when '%B' then I18n.t(:"date.month_names", :locale => locale, :format => format)[object.mon]
245
- when '%p' then I18n.t(:"time.#{object.hour < 12 ? :am : :pm}", :locale => locale, :format => format).upcase if object.respond_to? :hour
246
- when '%P' then I18n.t(:"time.#{object.hour < 12 ? :am : :pm}", :locale => locale, :format => format).downcase if object.respond_to? :hour
262
+ when '%a' then I18n.t!(:"date.abbr_day_names", :locale => locale, :format => format)[object.wday]
263
+ when '%^a' then I18n.t!(:"date.abbr_day_names", :locale => locale, :format => format)[object.wday].upcase
264
+ when '%A' then I18n.t!(:"date.day_names", :locale => locale, :format => format)[object.wday]
265
+ when '%^A' then I18n.t!(:"date.day_names", :locale => locale, :format => format)[object.wday].upcase
266
+ when '%b' then I18n.t!(:"date.abbr_month_names", :locale => locale, :format => format)[object.mon]
267
+ when '%^b' then I18n.t!(:"date.abbr_month_names", :locale => locale, :format => format)[object.mon].upcase
268
+ when '%B' then I18n.t!(:"date.month_names", :locale => locale, :format => format)[object.mon]
269
+ when '%^B' then I18n.t!(:"date.month_names", :locale => locale, :format => format)[object.mon].upcase
270
+ when '%p' then I18n.t!(:"time.#{object.hour < 12 ? :am : :pm}", :locale => locale, :format => format).upcase if object.respond_to? :hour
271
+ when '%P' then I18n.t!(:"time.#{object.hour < 12 ? :am : :pm}", :locale => locale, :format => format).downcase if object.respond_to? :hour
247
272
  end
248
273
  end
274
+ rescue MissingTranslationData => e
275
+ e.message
249
276
  end
250
277
 
251
278
  def pluralization_key(entry, count)
@@ -100,16 +100,13 @@ module I18n
100
100
 
101
101
  def cache_key(locale, key, options)
102
102
  # This assumes that only simple, native Ruby values are passed to I18n.translate.
103
- "i18n/#{I18n.cache_namespace}/#{locale}/#{digest_item(key)}/#{USE_INSPECT_HASH ? digest_item(options.inspect) : digest_item(options)}"
103
+ "i18n/#{I18n.cache_namespace}/#{locale}/#{digest_item(key)}/#{digest_item(options)}"
104
104
  end
105
105
 
106
106
  private
107
- # In Ruby < 1.9 the following is true: { :foo => 1, :bar => 2 }.hash == { :foo => 2, :bar => 1 }.hash
108
- # Therefore we must use the hash of the inspect string instead to avoid cache key colisions.
109
- USE_INSPECT_HASH = RUBY_VERSION <= "1.9"
110
107
 
111
108
  def digest_item(key)
112
- I18n.cache_key_digest ? I18n.cache_key_digest.hexdigest(key.to_s) : key.hash
109
+ I18n.cache_key_digest ? I18n.cache_key_digest.hexdigest(key.to_s) : key.to_s.hash
113
110
  end
114
111
  end
115
112
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest/sha2'
4
+
5
+ module I18n
6
+ module Backend
7
+ # Overwrites the Base load_file method to cache loaded file contents.
8
+ module CacheFile
9
+ # Optionally provide path_roots array to normalize filename paths,
10
+ # to make the cached i18n data portable across environments.
11
+ attr_accessor :path_roots
12
+
13
+ protected
14
+
15
+ # Track loaded translation files in the `i18n.load_file` scope,
16
+ # and skip loading the file if its contents are still up-to-date.
17
+ def load_file(filename)
18
+ initialized = !respond_to?(:initialized?) || initialized?
19
+ key = I18n::Backend::Flatten.escape_default_separator(normalized_path(filename))
20
+ old_mtime, old_digest = initialized && lookup(:i18n, key, :load_file)
21
+ return if (mtime = File.mtime(filename).to_i) == old_mtime ||
22
+ (digest = Digest::SHA2.file(filename).hexdigest) == old_digest
23
+ super
24
+ store_translations(:i18n, load_file: { key => [mtime, digest] })
25
+ end
26
+
27
+ # Translate absolute filename to relative path for i18n key.
28
+ def normalized_path(file)
29
+ return file unless path_roots
30
+ path = path_roots.find(&file.method(:start_with?)) ||
31
+ raise(InvalidLocaleData.new(file, 'outside expected path roots'))
32
+ file.sub(path, path_roots.index(path).to_s)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -17,6 +17,8 @@ module I18n
17
17
  # The implementation assumes that all backends added to the Chain implement
18
18
  # a lookup method with the same API as Simple backend does.
19
19
  class Chain
20
+ using I18n::HashRefinements
21
+
20
22
  module Implementation
21
23
  include Base
22
24
 
@@ -26,10 +28,23 @@ module I18n
26
28
  self.backends = backends
27
29
  end
28
30
 
31
+ def initialized?
32
+ backends.all? do |backend|
33
+ backend.instance_eval do
34
+ return false unless initialized?
35
+ end
36
+ end
37
+ true
38
+ end
39
+
29
40
  def reload!
30
41
  backends.each { |backend| backend.reload! }
31
42
  end
32
43
 
44
+ def eager_load!
45
+ backends.each { |backend| backend.eager_load! }
46
+ end
47
+
33
48
  def store_translations(locale, data, options = EMPTY_HASH)
34
49
  backends.first.store_translations(locale, data, options)
35
50
  end
@@ -74,6 +89,19 @@ module I18n
74
89
  end
75
90
 
76
91
  protected
92
+ def init_translations
93
+ backends.each do |backend|
94
+ backend.send(:init_translations)
95
+ end
96
+ end
97
+
98
+ def translations
99
+ backends.first.instance_eval do
100
+ init_translations unless initialized?
101
+ translations
102
+ end
103
+ end
104
+
77
105
  def namespace_lookup?(result, options)
78
106
  result.is_a?(Hash) && !options.has_key?(:count)
79
107
  end