1 # encoding: utf-8
2
3 # I18n locale fallbacks are useful when you want your application to use
4 # translations from other locales when translations for the current locale are
5 # missing. E.g. you might want to use :en translations when translations in
6 # your applications main locale :de are missing.
7 #
8 # To enable locale fallbacks you can simply include the Fallbacks module to
9 # the Simple backend - or whatever other backend you are using:
10 #
11 # I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
12 module I18n
13 @@fallbacks = nil
14
15 class << self
16 # Returns the current fallbacks implementation. Defaults to +I18n::Locale::Fallbacks+.
17 def fallbacks
18 @@fallbacks ||= I18n::Locale::Fallbacks.new
19 end
20
21 # Sets the current fallbacks implementation. Use this to set a different fallbacks implementation.
22 def fallbacks=(fallbacks)
23 @@fallbacks = fallbacks
24 end
25 end
26
27 module Backend
28 module Fallbacks
29 # Overwrites the Base backend translate method so that it will try each
30 # locale given by I18n.fallbacks for the given locale. E.g. for the
31 # locale :"de-DE" it might try the locales :"de-DE", :de and :en
32 # (depends on the fallbacks implementation) until it finds a result with
33 # the given options. If it does not find any result for any of the
34 # locales it will then raise a MissingTranslationData exception as
35 # usual.
36 #
37 # The default option takes precedence over fallback locales
38 # only when it's not a String. When default contains String it
39 # is evaluated after fallback locales.
40 def translate(locale, key, options = {})
41 default = extract_string_default!(options) if options[:default]
42
43 I18n.fallbacks[locale].each do |fallback|
44 begin
45 result = super(fallback, key, options)
46 return result unless result.nil?
47 rescue I18n::MissingTranslationData
48 end
49 end
50
51 return super(locale, nil, options.merge(:default => default)) if default
52 raise(I18n::MissingTranslationData.new(locale, key, options))
53 end
54
55 def extract_string_default!(options)
56 defaults = Array(options[:default])
57 if index = find_first_string_default(defaults)
58 options[:default] = defaults[0, index]
59 defaults[index]
60 end
61 end
62
63 def find_first_string_default(defaults)
64 defaults.each_index { |ix| return ix if String === defaults[ix] }
65 nil
66 end
67 end
68 end
69 end