/
fallbacks.rb
108 lines (94 loc) · 4.2 KB
/
fallbacks.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# frozen_string_literal: true
# I18n locale fallbacks are useful when you want your application to use
# translations from other locales when translations for the current locale are
# missing. E.g. you might want to use :en translations when translations in
# your applications main locale :de are missing.
#
# To enable locale fallbacks you can simply include the Fallbacks module to
# the Simple backend - or whatever other backend you are using:
#
# I18n::Backend::Simple.include(I18n::Backend::Fallbacks)
module I18n
@@fallbacks = nil
class << self
# Returns the current fallbacks implementation. Defaults to +I18n::Locale::Fallbacks+.
def fallbacks
@@fallbacks ||= I18n::Locale::Fallbacks.new
Thread.current[:i18n_fallbacks] || @@fallbacks
end
# Sets the current fallbacks implementation. Use this to set a different fallbacks implementation.
def fallbacks=(fallbacks)
@@fallbacks = fallbacks.is_a?(Array) ? I18n::Locale::Fallbacks.new(fallbacks) : fallbacks
Thread.current[:i18n_fallbacks] = @@fallbacks
end
end
module Backend
module Fallbacks
# Overwrites the Base backend translate method so that it will try each
# locale given by I18n.fallbacks for the given locale. E.g. for the
# locale :"de-DE" it might try the locales :"de-DE", :de and :en
# (depends on the fallbacks implementation) until it finds a result with
# the given options. If it does not find any result for any of the
# locales it will then throw MissingTranslation as usual.
#
# The default option takes precedence over fallback locales only when
# it's a Symbol. When the default contains a String, Proc or Hash
# it is evaluated last after all the fallback locales have been tried.
def translate(locale, key, options = EMPTY_HASH)
return super unless options.fetch(:fallback, true)
return super if options[:fallback_in_progress]
default = extract_non_symbol_default!(options) if options[:default]
fallback_options = options.merge(:fallback_in_progress => true, fallback_original_locale: locale)
I18n.fallbacks[locale].each do |fallback|
begin
catch(:exception) do
result = super(fallback, key, fallback_options)
unless result.nil?
on_fallback(locale, fallback, key, options) if locale.to_s != fallback.to_s
return result
end
end
rescue I18n::InvalidLocale
# we do nothing when the locale is invalid, as this is a fallback anyways.
end
end
return if options.key?(:default) && options[:default].nil?
return super(locale, nil, options.merge(:default => default)) if default
throw(:exception, I18n::MissingTranslation.new(locale, key, options))
end
def resolve(locale, object, subject, options = EMPTY_HASH)
return subject if options[:resolve] == false
return super unless subject.is_a?(Symbol)
result = catch(:exception) do
options.delete(:fallback_in_progress)
I18n.translate(subject, **options.merge(locale: options[:fallback_original_locale], throw: true))
end
result unless result.is_a?(MissingTranslation)
end
def extract_non_symbol_default!(options)
defaults = [options[:default]].flatten
first_non_symbol_default = defaults.detect{|default| !default.is_a?(Symbol)}
if first_non_symbol_default
options[:default] = defaults[0, defaults.index(first_non_symbol_default)]
end
return first_non_symbol_default
end
def exists?(locale, key, options = EMPTY_HASH)
return super unless options.fetch(:fallback, true)
I18n.fallbacks[locale].each do |fallback|
begin
return true if super(fallback, key)
rescue I18n::InvalidLocale
# we do nothing when the locale is invalid, as this is a fallback anyways.
end
end
false
end
private
# Overwrite on_fallback to add specified logic when the fallback succeeds.
def on_fallback(_original_locale, _fallback_locale, _key, _optoins)
nil
end
end
end
end