clicrdv_easy_translatable 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +28 -0
- data/lib/translatable/active_record/adapter.rb +67 -0
- data/lib/translatable/active_record/attributes.rb +27 -0
- data/lib/translatable/active_record/class_methods.rb +60 -0
- data/lib/translatable/active_record/instance_methods.rb +195 -0
- data/lib/translatable/active_record/macro.rb +96 -0
- data/lib/translatable/active_record/relation.rb +31 -0
- data/lib/translatable/active_record/translate.rb +10 -0
- data/lib/translatable/active_record.rb +12 -0
- data/lib/translatable/default.rb +5 -0
- data/lib/translatable/version.rb +3 -0
- data/lib/translatable.rb +68 -0
- metadata +203 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 50704672bccd72c0179e2acd83114e675d7c2301c564ba81a011fa64ac6c3f8c
|
4
|
+
data.tar.gz: cf389801803b8822a553c465e9e0568dbbfb2b5a320626a600ced51181b94588
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 84a2c46f6ad7282664eaf750596f14a348e0a1a289fdac4dd0edb8deeed6af1d4b500a8b469f0614dd44492f4581818c01be9d96d12c1ab739414917078efed6
|
7
|
+
data.tar.gz: 7da00eed5cb246f1ace53df770e3887412c84854899a2189467d1c052467681239e883e7481227b07c4bebef643fbdce7776572853e12fa0cf35efc39f73c5a7
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2008, 2009, 2010 Sven Fuchs, Joshua Harvey, Clemens Kofler, John-Paul Bader, ClicRDV
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# Translatable [](http://badge.fury.io/rb/easy_translatable) [](https://codeclimate.com/github/clicrdv/translatable) [](https://travis-ci.org/clicrdv/translatable) [](https://coveralls.io/r/clicrdv/translatable)
|
2
|
+
## Requirements
|
3
|
+
|
4
|
+
* ActiveRecord 3.2
|
5
|
+
* I18n
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
To install just use:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem install easy_translatable
|
13
|
+
```
|
14
|
+
|
15
|
+
When using bundler put this in your Gemfile:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
gem 'easy_translatable', '~> 0.1.0'
|
19
|
+
```
|
20
|
+
|
21
|
+
## Todo
|
22
|
+
|
23
|
+
- cleanup
|
24
|
+
- doc
|
25
|
+
- migration/model for translation table
|
26
|
+
|
27
|
+
|
28
|
+
Copyright (c) 2008, 2009, 2010 Sven Fuchs, Joshua Harvey, Clemens Kofler, John-Paul Bader, ClicRDV
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Translatable
|
2
|
+
module ActiveRecord
|
3
|
+
class Adapter
|
4
|
+
# The cache caches attributes that already were looked up for read access.
|
5
|
+
# The stash keeps track of new or changed values that need to be saved.
|
6
|
+
attr_accessor :record, :stash, :translations
|
7
|
+
private :record=, :stash=
|
8
|
+
|
9
|
+
def initialize(record)
|
10
|
+
self.record = record
|
11
|
+
self.stash = Attributes.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def fetch_stash(locale, name)
|
15
|
+
value = stash.read(locale, name)
|
16
|
+
return value if value
|
17
|
+
return nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def stash_contains?(locale, name)
|
21
|
+
stash.contains?(locale, name)
|
22
|
+
end
|
23
|
+
|
24
|
+
def fetch(locale, name, value = nil)
|
25
|
+
value = stash_contains?(locale, name) ? fetch_stash(locale, name) : fetch_attribute(locale, name, value)
|
26
|
+
|
27
|
+
return value
|
28
|
+
end
|
29
|
+
|
30
|
+
def write(locale, name, value)
|
31
|
+
stash.write(locale, name, value)
|
32
|
+
end
|
33
|
+
|
34
|
+
def save_translations!
|
35
|
+
stash.reject {|locale, attrs| attrs.empty?}.each do |locale, attrs|
|
36
|
+
translations = record.translations_by_locale[locale]
|
37
|
+
attrs.each { |name, value|
|
38
|
+
translation = translations && translations[name] ||
|
39
|
+
record.translations.build(:locale => locale.to_s, :scope => record.class.table_name, :key => name)
|
40
|
+
translation['record_id'] = record.id
|
41
|
+
translation['value'] = value
|
42
|
+
translation.save!
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
reset
|
47
|
+
end
|
48
|
+
|
49
|
+
def reset
|
50
|
+
stash.clear
|
51
|
+
end
|
52
|
+
|
53
|
+
protected
|
54
|
+
|
55
|
+
def fetch_attribute(locale, name, value = nil)
|
56
|
+
if value.nil?
|
57
|
+
translation = record.translation_for(locale, name)
|
58
|
+
return translation && translation.send(:value)
|
59
|
+
else
|
60
|
+
translation = record.translation_for_serialized(locale, name, value)
|
61
|
+
return translation
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Helper class for storing values per locale. Used by Globalize::Adapter
|
2
|
+
# to stash and cache attribute values.
|
3
|
+
|
4
|
+
module Translatable
|
5
|
+
module ActiveRecord
|
6
|
+
class Attributes < Hash # TODO: Think about using HashWithIndifferentAccess ?
|
7
|
+
def [](locale)
|
8
|
+
locale = locale.to_sym
|
9
|
+
self[locale] = {} unless has_key?(locale)
|
10
|
+
self.fetch(locale)
|
11
|
+
end
|
12
|
+
|
13
|
+
def contains?(locale, name)
|
14
|
+
self[locale].has_key?(name.to_s)
|
15
|
+
end
|
16
|
+
|
17
|
+
def read(locale, name)
|
18
|
+
self[locale][name.to_s]
|
19
|
+
end
|
20
|
+
|
21
|
+
def write(locale, name, value)
|
22
|
+
#raise 'z' if value.nil? # TODO
|
23
|
+
self[locale][name.to_s] = value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Translatable
|
2
|
+
module ActiveRecord
|
3
|
+
module ClassMethods
|
4
|
+
def translation_class
|
5
|
+
Translatable.translation_class
|
6
|
+
end
|
7
|
+
|
8
|
+
def translated?(name)
|
9
|
+
included = translated_attribute_names.detect { |attr| attr.is_a?(Hash) ? attr.keys.include?(name.to_sym) : attr == name.to_sym }
|
10
|
+
!included.nil?
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
def translated_attr_accessor(name)
|
16
|
+
define_method(:"#{name}=") do |value|
|
17
|
+
write_attribute(name, value)
|
18
|
+
end
|
19
|
+
define_method(name) do |*args|
|
20
|
+
self.read_attribute(name, {:locale => args.detect {|a| !a.is_a? Hash }})
|
21
|
+
end
|
22
|
+
alias_method :"#{name}_before_type_cast", name
|
23
|
+
end
|
24
|
+
|
25
|
+
def locale_from(args)
|
26
|
+
args.detect {|a| !a.is_a? Hash }
|
27
|
+
end
|
28
|
+
|
29
|
+
def translations_accessor(name)
|
30
|
+
define_method(:"#{name}_translations") do
|
31
|
+
translations.each_with_object(HashWithIndifferentAccess.new) do |translation, result|
|
32
|
+
result[translation.locale] = translation.send(name)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
define_method(:"#{name}_translations=") do |value|
|
36
|
+
value.each do |(locale, value)|
|
37
|
+
write_attribute name, value, :locale => locale
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def condition_callback(attr_names, callback)
|
43
|
+
Proc.new { |rec|
|
44
|
+
attr_names.any? do |translatable_attr|
|
45
|
+
callback && rec.changes.keys.include?(translatable_attr.to_s)
|
46
|
+
end
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
%w(after_save before_save after_update before_update).each do |cb|
|
51
|
+
class_eval %{
|
52
|
+
def on_#{cb}_callback(attr_names, callback)
|
53
|
+
#{cb} callback, :if => condition_callback(attr_names, callback)
|
54
|
+
end
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,195 @@
|
|
1
|
+
module Translatable
|
2
|
+
module ActiveRecord
|
3
|
+
module InstanceMethods
|
4
|
+
delegate :translated_locales, :to => :translations
|
5
|
+
|
6
|
+
def translatable
|
7
|
+
@translatable ||= Adapter.new(self)
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.included(base)
|
11
|
+
# Maintian Rails 3.0.x compatibility ..
|
12
|
+
if base.method_defined?(:assign_attributes)
|
13
|
+
base.class_eval %{
|
14
|
+
def assign_attributes(attributes, *options)
|
15
|
+
with_given_locale(attributes) { super }
|
16
|
+
end
|
17
|
+
}
|
18
|
+
else
|
19
|
+
base.class_eval %{
|
20
|
+
def attributes=(attributes, *args)
|
21
|
+
with_given_locale(attributes) { super }
|
22
|
+
end
|
23
|
+
|
24
|
+
def update_attributes!(attributes, *args)
|
25
|
+
with_given_locale(attributes) { super }
|
26
|
+
end
|
27
|
+
|
28
|
+
def update_attributes(attributes, *args)
|
29
|
+
with_given_locale(attributes) { super }
|
30
|
+
end
|
31
|
+
}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Always call the super method, the attribute is translatable and we asked a translated model
|
36
|
+
def write_attribute(name, value, options = {}, &block)
|
37
|
+
if r_translated?(name) && translate?
|
38
|
+
options = {:locale => Translatable.locale}.merge(options)
|
39
|
+
|
40
|
+
# We don't want to track any changes, but save the new value in a translation hash
|
41
|
+
|
42
|
+
translatable.write(options[:locale], name, value)
|
43
|
+
else
|
44
|
+
super(name, value)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def translate
|
49
|
+
@translate_me = true
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
def end_translate
|
54
|
+
@translate_me = nil
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
def reload(options = nil)
|
59
|
+
@translate_me = false
|
60
|
+
translation_caches.clear
|
61
|
+
translated_attribute_names.each { |name| @attributes.reset(name.to_s) }
|
62
|
+
translatable.reset
|
63
|
+
super(options)
|
64
|
+
end
|
65
|
+
|
66
|
+
def save(*)
|
67
|
+
@translate_me = false
|
68
|
+
super
|
69
|
+
end
|
70
|
+
|
71
|
+
def translate?
|
72
|
+
!@translate_me.nil? && @translate_me
|
73
|
+
end
|
74
|
+
|
75
|
+
def read_attribute(name, options = {}, &block)
|
76
|
+
options = {:translated => true, :locale => Translatable.locale}.merge(options)
|
77
|
+
if r_translated?(name) and options[:translated]
|
78
|
+
serialized_value = super(name) if self.attributes.has_key?(name)
|
79
|
+
if translate? && (value = translatable.fetch(options[:locale] || Translatable.locale, name, serialized_value))
|
80
|
+
value
|
81
|
+
else
|
82
|
+
super(name)
|
83
|
+
end
|
84
|
+
else
|
85
|
+
super(name)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def r_translated?(name)
|
90
|
+
self.class.translated?(name)
|
91
|
+
end
|
92
|
+
|
93
|
+
def translated_attributes
|
94
|
+
translated_attribute_names.inject({}) do |attributes, name|
|
95
|
+
attributes.merge(name.to_s => translation.send(name))
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# This method is basically the method built into Rails
|
100
|
+
# but we have to pass {:translated => false}
|
101
|
+
def untranslated_attributes
|
102
|
+
attrs = {}
|
103
|
+
attribute_names.each do |name|
|
104
|
+
attrs[name] = read_attribute(name, {:translated => false})
|
105
|
+
end
|
106
|
+
attrs
|
107
|
+
end
|
108
|
+
|
109
|
+
def translation_for(locale, name, build_if_missing = false)
|
110
|
+
unless translation_caches["#{locale}_#{name}"]
|
111
|
+
# Fetch translations from database as those in the translation collection may be incomplete
|
112
|
+
_translation = translations.detect{|t| t.locale.to_s == locale.to_s && t.key.to_s == name.to_s }
|
113
|
+
_translation ||= translations.build(:locale => locale) if build_if_missing
|
114
|
+
translation_caches["#{locale}_#{name}"] = _translation if _translation
|
115
|
+
end
|
116
|
+
translation_caches["#{locale}_#{name}"]
|
117
|
+
end
|
118
|
+
|
119
|
+
# Fetch translations per keys in the form
|
120
|
+
# model_attr_serialized_attribute
|
121
|
+
# E.G.1: ```Model``` has attribute ```config``` which has a key ```auto_save```
|
122
|
+
# will have a translation key ```config_auto_save```
|
123
|
+
# E.G.2: ```Model``` has attribute ```config``` which is an array of ```user_id => ([0-9]+)```
|
124
|
+
# will have translations key containing the index: ```config_user_id_0```, ```config_user_id_1```...
|
125
|
+
def translation_for_serialized(locale, name, value, build_if_missing = false)
|
126
|
+
|
127
|
+
unless translation_caches["#{locale}_#{name}"]
|
128
|
+
engine = self.attributes.has_key?(name) ? nil : JSON
|
129
|
+
deserialized_value = engine.nil? ? value : engine.load(value)
|
130
|
+
|
131
|
+
only = self.translated_serialized_attributes[name.to_sym].map(&:to_s)
|
132
|
+
if only.empty?
|
133
|
+
regex_keys = /\A#{name.to_s}_([a-z_]+[a-z])(?:_([0-9]*))?\Z/
|
134
|
+
else
|
135
|
+
regex_keys = /\A#{name.to_s}_(#{only.join('|')})(?:_([0-9]*))?\Z/
|
136
|
+
end
|
137
|
+
# Fetch translations from database as those in the translation collection may be incomplete
|
138
|
+
_translations = translations.select{|t| t.locale.to_s == locale.to_s && t.key.to_s =~ regex_keys }
|
139
|
+
_translations.each do |t|
|
140
|
+
matched = t.key.match regex_keys
|
141
|
+
unless matched.nil?
|
142
|
+
if matched.size == 3
|
143
|
+
sub_attr = matched[1]
|
144
|
+
index = matched[2].to_i
|
145
|
+
value[index][sub_attr] = t.value if value.size > index && value[index].has_key?(sub_attr)
|
146
|
+
elsif matched.size == 3
|
147
|
+
sub_attr = matched[1]
|
148
|
+
value[sub_attr] = t.value if value.has_key?(sub_attr)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
translation_caches["#{locale}_#{name}"] = value
|
154
|
+
end
|
155
|
+
translation_caches["#{locale}_#{name}"]
|
156
|
+
end
|
157
|
+
|
158
|
+
def translation_caches
|
159
|
+
@translation_caches ||= {}
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
def with_given_locale(attributes, &block)
|
164
|
+
attributes.symbolize_keys! if attributes.respond_to?(:symbolize_keys!)
|
165
|
+
|
166
|
+
locale = respond_to?(:locale=) ? attributes.try(:[], :locale) :
|
167
|
+
attributes.try(:delete, :locale)
|
168
|
+
|
169
|
+
if locale && !respond_to?(:locale=)
|
170
|
+
already = translate?
|
171
|
+
translate unless translate?
|
172
|
+
Translatable.with_locale(locale, &block)
|
173
|
+
end_translate unless already
|
174
|
+
else
|
175
|
+
yield
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def translations_by_locale(&block)
|
180
|
+
translations.each_with_object(HashWithIndifferentAccess.new) do |t, hash|
|
181
|
+
hash[t.locale] ||= HashWithIndifferentAccess.new
|
182
|
+
hash[t.locale][t.key] = block_given? ? block.call(t) : t
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
protected
|
187
|
+
|
188
|
+
def save_translations!
|
189
|
+
translatable.save_translations!
|
190
|
+
translation_caches.clear
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Translatable
|
2
|
+
module ActiveRecord
|
3
|
+
module Macro
|
4
|
+
|
5
|
+
def translatable(*attr_names)
|
6
|
+
|
7
|
+
options = attr_names.extract_options!
|
8
|
+
setup_translatable!(options) unless translatable?
|
9
|
+
|
10
|
+
attr_names = attr_names.map(&:to_sym)
|
11
|
+
attr_names -= translated_attribute_names if defined?(translated_attribute_names)
|
12
|
+
|
13
|
+
if attr_names.present?
|
14
|
+
|
15
|
+
attr_names.each do |attr_name|
|
16
|
+
# Create accessors for the attribute.
|
17
|
+
translated_attr_accessor(attr_name)
|
18
|
+
translations_accessor(attr_name)
|
19
|
+
|
20
|
+
# Add attribute to the list.
|
21
|
+
self.translated_attribute_names << attr_name
|
22
|
+
if options[:only]
|
23
|
+
self.translated_serialized_attributes[attr_name] = options[:only] ? options[:only] : []
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
on_after_save_callback(attr_names, options[:after_save]) if options[:after_save]
|
28
|
+
on_before_save_callback(attr_names, options[:before_save]) if options[:before_save]
|
29
|
+
on_after_update_callback(attr_names, options[:after_update]) if options[:after_update]
|
30
|
+
on_before_update_callback(attr_names, options[:before_update]) if options[:before_update]
|
31
|
+
|
32
|
+
Translatable.add_translatable self
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def class_name
|
38
|
+
@class_name ||= begin
|
39
|
+
class_name = table_name[table_name_prefix.length..-(table_name_suffix.length + 1)].downcase.camelize
|
40
|
+
pluralize_table_names ? class_name.singularize : class_name
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def translatable?
|
45
|
+
included_modules.include?(InstanceMethods)
|
46
|
+
end
|
47
|
+
|
48
|
+
protected
|
49
|
+
def setup_translatable!(options)
|
50
|
+
options[:table_name] ||= Translatable.translation_class.table_name
|
51
|
+
options[:foreign_key] ||= 'record_id'
|
52
|
+
options[:conditions] ||= {}
|
53
|
+
options[:after_save] ||= false
|
54
|
+
options[:before_save] ||= false
|
55
|
+
|
56
|
+
class_attribute :translated_attribute_names, :translation_options, :fallbacks_for_empty_translations, :translated_serialized_attributes
|
57
|
+
self.translated_attribute_names = []
|
58
|
+
self.translation_options = options
|
59
|
+
self.fallbacks_for_empty_translations = options[:fallbacks_for_empty_translations]
|
60
|
+
self.translated_serialized_attributes = Hash.new
|
61
|
+
|
62
|
+
include InstanceMethods
|
63
|
+
extend ClassMethods
|
64
|
+
|
65
|
+
translation_class.table_name = options[:table_name]
|
66
|
+
|
67
|
+
has_many :translations, conditions(options), :class_name => translation_class.name,
|
68
|
+
:foreign_key => options[:foreign_key],
|
69
|
+
:dependent => :destroy,
|
70
|
+
:extend => HasManyExtensions,
|
71
|
+
:autosave => false
|
72
|
+
|
73
|
+
after_create :save_translations!
|
74
|
+
after_update :save_translations!
|
75
|
+
end
|
76
|
+
|
77
|
+
def conditions(options)
|
78
|
+
table_name = self.table_name
|
79
|
+
proc {
|
80
|
+
c = options[:conditions]
|
81
|
+
c = self.instance_eval(&c) if c.is_a?(Proc)
|
82
|
+
c.merge!(:scope => table_name, :locale => Translatable.locale)
|
83
|
+
|
84
|
+
where(c)
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
module HasManyExtensions
|
91
|
+
def find_or_initialize_by_locale(locale)
|
92
|
+
with_locale(locale.to_s).first || build(:locale => locale.to_s)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Translatable
|
2
|
+
module ActiveRecord
|
3
|
+
module Relation
|
4
|
+
def exec_queries
|
5
|
+
queries = super
|
6
|
+
|
7
|
+
return queries.map(&:translate) if @translate_records
|
8
|
+
|
9
|
+
queries
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def translate
|
15
|
+
@translate_records = true
|
16
|
+
|
17
|
+
self.eager_load(:translations)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class Railtie < Rails::Railtie
|
24
|
+
|
25
|
+
initializer "easy_translatable.configure_rails_initialization" do
|
26
|
+
ActiveSupport.on_load(:active_record) do
|
27
|
+
ActiveRecord::Relation.send :prepend, Translatable::ActiveRecord::Relation
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end if defined?(Rails)
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require File.expand_path '../active_record/class_methods.rb', __FILE__
|
2
|
+
require File.expand_path '../active_record/instance_methods.rb', __FILE__
|
3
|
+
require File.expand_path '../active_record/attributes.rb', __FILE__
|
4
|
+
require File.expand_path '../active_record/adapter.rb', __FILE__
|
5
|
+
require File.expand_path '../active_record/macro.rb', __FILE__
|
6
|
+
require File.expand_path '../active_record/translate.rb', __FILE__
|
7
|
+
require File.expand_path '../active_record/relation.rb', __FILE__
|
8
|
+
|
9
|
+
module Translatable
|
10
|
+
module ActiveRecord
|
11
|
+
end
|
12
|
+
end
|
data/lib/translatable.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'translatable/default.rb')
|
2
|
+
|
3
|
+
module Translatable
|
4
|
+
|
5
|
+
@@translatable ||= Hash.new
|
6
|
+
@@translation_class ||= nil
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def locale
|
10
|
+
read_locale || I18n.locale
|
11
|
+
end
|
12
|
+
|
13
|
+
def locale=(locale)
|
14
|
+
set_locale(locale)
|
15
|
+
end
|
16
|
+
|
17
|
+
def with_locale(locale, &block)
|
18
|
+
previous_locale = read_locale
|
19
|
+
begin
|
20
|
+
set_locale(locale)
|
21
|
+
result = yield(locale)
|
22
|
+
ensure
|
23
|
+
set_locale(previous_locale)
|
24
|
+
end
|
25
|
+
result
|
26
|
+
end
|
27
|
+
|
28
|
+
def translation_class_name=(klass)
|
29
|
+
@@translation_class = klass.constantize
|
30
|
+
end
|
31
|
+
def translation_class
|
32
|
+
@@translation_class ||= nil
|
33
|
+
end
|
34
|
+
|
35
|
+
# Hash of models that are translatable (values are the attrs)
|
36
|
+
def list
|
37
|
+
@@translatable ||= Hash.new
|
38
|
+
end
|
39
|
+
|
40
|
+
def add_translatable(klass)
|
41
|
+
if @@translatable.has_key? klass.name
|
42
|
+
klass.translated_attribute_names.each do |attr|
|
43
|
+
@@translatable[klass.name] << attr unless @@translatable[klass.name].include?(attr)
|
44
|
+
end
|
45
|
+
else
|
46
|
+
@@translatable[klass.name] = klass.translated_attribute_names
|
47
|
+
end
|
48
|
+
|
49
|
+
unless klass.translated_serialized_attributes.nil?
|
50
|
+
@@translatable[klass.name].map! do |attr|
|
51
|
+
serialized = klass.translated_serialized_attributes.reject{|k,v| k != attr}
|
52
|
+
serialized.empty? ? attr : serialized
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
protected
|
58
|
+
|
59
|
+
def read_locale
|
60
|
+
Thread.current[:translatable_locale]
|
61
|
+
end
|
62
|
+
|
63
|
+
def set_locale(locale)
|
64
|
+
Thread.current[:translatable_locale] = locale.try(:to_sym)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
metadata
ADDED
@@ -0,0 +1,203 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: clicrdv_easy_translatable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Paul Bonaud
|
8
|
+
- Charly Poly
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2022-03-08 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activesupport
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 6.1.3
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 6.1.3
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: database_cleaner
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 0.6.0
|
35
|
+
- - ">="
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 0.6.0
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - "~>"
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: 0.6.0
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.6.0
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: mocha
|
50
|
+
requirement: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: pathname_local
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
type: :development
|
70
|
+
prerelease: false
|
71
|
+
version_requirements: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
- !ruby/object:Gem::Dependency
|
77
|
+
name: test_declarative
|
78
|
+
requirement: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
type: :development
|
84
|
+
prerelease: false
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
- !ruby/object:Gem::Dependency
|
91
|
+
name: friendly_id
|
92
|
+
requirement: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
type: :development
|
98
|
+
prerelease: false
|
99
|
+
version_requirements: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
- !ruby/object:Gem::Dependency
|
105
|
+
name: sqlite3
|
106
|
+
requirement: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
type: :development
|
112
|
+
prerelease: false
|
113
|
+
version_requirements: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
- !ruby/object:Gem::Dependency
|
119
|
+
name: rake
|
120
|
+
requirement: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
type: :development
|
126
|
+
prerelease: false
|
127
|
+
version_requirements: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
- !ruby/object:Gem::Dependency
|
133
|
+
name: rdoc
|
134
|
+
requirement: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
type: :development
|
140
|
+
prerelease: false
|
141
|
+
version_requirements: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
- !ruby/object:Gem::Dependency
|
147
|
+
name: coveralls
|
148
|
+
requirement: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
type: :development
|
154
|
+
prerelease: false
|
155
|
+
version_requirements: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
description: Handle translations for AR models into a single table. And provide a
|
161
|
+
helper to select translated values.
|
162
|
+
email: paul.bonaud@clicrdv.com
|
163
|
+
executables: []
|
164
|
+
extensions: []
|
165
|
+
extra_rdoc_files: []
|
166
|
+
files:
|
167
|
+
- LICENSE
|
168
|
+
- README.md
|
169
|
+
- lib/translatable.rb
|
170
|
+
- lib/translatable/active_record.rb
|
171
|
+
- lib/translatable/active_record/adapter.rb
|
172
|
+
- lib/translatable/active_record/attributes.rb
|
173
|
+
- lib/translatable/active_record/class_methods.rb
|
174
|
+
- lib/translatable/active_record/instance_methods.rb
|
175
|
+
- lib/translatable/active_record/macro.rb
|
176
|
+
- lib/translatable/active_record/relation.rb
|
177
|
+
- lib/translatable/active_record/translate.rb
|
178
|
+
- lib/translatable/default.rb
|
179
|
+
- lib/translatable/version.rb
|
180
|
+
homepage: http://rubygems.org/gems/single_translatable
|
181
|
+
licenses:
|
182
|
+
- MIT
|
183
|
+
metadata: {}
|
184
|
+
post_install_message:
|
185
|
+
rdoc_options: []
|
186
|
+
require_paths:
|
187
|
+
- lib
|
188
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
189
|
+
requirements:
|
190
|
+
- - ">="
|
191
|
+
- !ruby/object:Gem::Version
|
192
|
+
version: '0'
|
193
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
194
|
+
requirements:
|
195
|
+
- - ">="
|
196
|
+
- !ruby/object:Gem::Version
|
197
|
+
version: '0'
|
198
|
+
requirements: []
|
199
|
+
rubygems_version: 3.2.3
|
200
|
+
signing_key:
|
201
|
+
specification_version: 4
|
202
|
+
summary: Handle translations for AR models into a single table
|
203
|
+
test_files: []
|