-
-
Notifications
You must be signed in to change notification settings - Fork 501
/
Copy pathinstance_methods.rb
218 lines (179 loc) · 6.27 KB
/
instance_methods.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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
module Globalize
module ActiveRecord
module InstanceMethods
delegate :translated_locales, :to => :translations
def globalize
@globalize ||= Adapter.new(self)
end
def attributes
super.merge(translated_attributes)
end
def attributes=(new_attributes, *options)
super unless new_attributes.respond_to?(:stringify_keys) && new_attributes.present?
attributes = new_attributes.stringify_keys
with_given_locale(attributes) { super(attributes.except("locale"), *options) }
end
def assign_attributes(new_attributes, *options)
super unless new_attributes.respond_to?(:stringify_keys) && new_attributes.present?
attributes = new_attributes.stringify_keys
with_given_locale(attributes) { super(attributes.except("locale"), *options) }
end
def write_attribute(name, value, *args, &block)
return super(name, value, *args, &block) unless translated?(name)
options = {:locale => Globalize.locale}.merge(args.first || {})
globalize.write(options[:locale], name, value)
end
def [](attr_name)
if translated?(attr_name)
read_attribute(attr_name)
else
read_attribute(attr_name) { |n| missing_attribute(n, caller) }
end
end
def read_attribute(name, options = {}, &block)
options = {:translated => true, :locale => nil}.merge(options)
return super(name, &block) unless options[:translated]
if translated?(name)
if !(value = globalize.fetch(options[:locale] || Globalize.locale, name)).nil?
value
else
super(name, &block)
end
else
super(name, &block)
end
end
def attribute_names
translated_attribute_names.map(&:to_s) + super
end
delegate :translated?, :to => :class
def translated_attributes
translated_attribute_names.inject({}) do |attributes, name|
attributes.merge(name.to_s => send(name))
end
end
# This method is basically the method built into Rails
# but we have to pass {:translated => false}
def untranslated_attributes
attribute_names.inject({}) do |attrs, name|
attrs[name] = read_attribute(name, {:translated => false}); attrs
end
end
def set_translations(options)
options.keys.each do |locale|
translation = translation_for(locale) ||
translations.build(:locale => locale.to_s)
options[locale].each do |key, value|
translation.send :"#{key}=", value
translation.globalized_model.send :"#{key}=", value
end
translation.save if persisted?
end
globalize.reset
end
def reload(options = nil)
translation_caches.clear
translated_attribute_names.each { |name| @attributes.reset(name.to_s) }
globalize.reset
super(options)
end
def initialize_dup(other)
@globalize = nil
@translation_caches = nil
super
other.each_locale_and_translated_attribute do |locale, name|
globalize.write(locale, name, other.globalize.fetch(locale, name) )
end
end
def translation
translation_for(::Globalize.locale)
end
def translation_for(locale, build_if_missing = true)
unless translation_caches[locale]
# Fetch translations from database as those in the translation collection may be incomplete
_translation = translations.detect{|t| t.locale.to_s == locale.to_s}
_translation ||= translations.with_locale(locale).first unless translations.loaded?
_translation ||= translations.build(:locale => locale) if build_if_missing
translation_caches[locale] = _translation if _translation
end
translation_caches[locale]
end
def translation_caches
@translation_caches ||= {}
end
def translations_by_locale
translations.each_with_object(HashWithIndifferentAccess.new) do |t, hash|
hash[t.locale] = block_given? ? yield(t) : t
end
end
def translated_attribute_by_locale(name)
translations_by_locale(&:"#{name}")
end
# Get available locales from translations association, without a separate distinct query
def available_locales
translations.map(&:locale).uniq
end
def globalize_fallbacks(locale)
Globalize.fallbacks(locale)
end
def save(*)
result = Globalize.with_locale(translation.locale || I18n.default_locale) do
without_fallbacks do
super
end
end
if result
globalize.clear_dirty
end
result
end
def column_for_attribute name
return super if translated_attribute_names.exclude?(name)
globalize.send(:column_for_attribute, name)
end
def cache_key
[super, translation.cache_key].join("/")
end
def changed?
changed_attributes.present? || translations.any?(&:changed?)
end
# need to access instance variable directly since changed_attributes
# is frozen as of Rails 4.2
def original_changed_attributes
@changed_attributes
end
protected
def each_locale_and_translated_attribute
used_locales.each do |locale|
translated_attribute_names.each do |name|
yield locale, name
end
end
end
def used_locales
locales = globalize.stash.keys.concat(globalize.stash.keys).concat(translations.translated_locales)
locales.uniq!
locales
end
def save_translations!
globalize.save_translations!
translation_caches.clear
end
def with_given_locale(_attributes, &block)
attributes = _attributes.stringify_keys
if locale = attributes.try(:delete, "locale")
Globalize.with_locale(locale, &block)
else
yield
end
end
def without_fallbacks
before = self.fallbacks_for_empty_translations
self.fallbacks_for_empty_translations = false
yield
ensure
self.fallbacks_for_empty_translations = before
end
end
end
end