easy_translatable 0.0.7 → 0.1.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 +4 -4
- data/README.md +20 -0
- data/lib/translatable/active_record/adapter.rb +43 -0
- data/lib/translatable/active_record/attributes.rb +27 -0
- data/lib/translatable/active_record/class_methods.rb +42 -0
- data/lib/translatable/active_record/instance_methods.rb +99 -0
- data/lib/translatable/active_record/macro.rb +96 -0
- data/lib/translatable/active_record/translate.rb +5 -58
- data/lib/translatable/active_record.rb +5 -0
- data/lib/translatable/default.rb +3 -55
- data/lib/translatable/version.rb +1 -1
- data/lib/translatable.rb +57 -0
- metadata +7 -2
- data/lib/translatable/config.rb +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b058f1009620ef66e0eb9a2425af27841e3f4d61
|
4
|
+
data.tar.gz: 97066aa3b7af92612aff25f95896be71a0f70174
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 29f96b7b1d821caafea24001ba52d15350527d3df865819a60b17cfafea5fa2aab40459c04be70935b624597ed8f90b68905c79ba2703474d72e9fc63625259e
|
7
|
+
data.tar.gz: 40ddc1c5111c3b3d1ac02bf2d75d87e8349e24d043b0b345b361a28e804e227f122aa17f30e2c833eda46090b4e74b8dca7b929df4bc6084da11ea80b135444e
|
data/README.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# Translatable
|
2
|
+
|
3
|
+
## Requirements
|
4
|
+
|
5
|
+
* ActiveRecord 3.2
|
6
|
+
* I18n
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
To install just use:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
gem install easy_translatable
|
14
|
+
```
|
15
|
+
|
16
|
+
When using bundler put this in your Gemfile:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
gem 'easy_translatable', '~> 0.1.0'
|
20
|
+
```
|
@@ -0,0 +1,43 @@
|
|
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)
|
25
|
+
value = stash_contains?(locale, name) ? fetch_stash(locale, name) : fetch_attribute(locale, name)
|
26
|
+
|
27
|
+
return value
|
28
|
+
end
|
29
|
+
|
30
|
+
def write(locale, name, value)
|
31
|
+
stash.write(locale, name, value)
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
def fetch_attribute(locale, name)
|
37
|
+
translation = record.translation_for(locale, name, false)
|
38
|
+
return translation && translation.send(:value)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
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,42 @@
|
|
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
|
+
translated_attribute_names.include?(name.to_sym)
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
def translated_attr_accessor(name)
|
15
|
+
define_method(:"#{name}=") do |value|
|
16
|
+
write_attribute(name, value)
|
17
|
+
end
|
18
|
+
define_method(name) do |*args|
|
19
|
+
self.read_attribute(name, {:locale => args.detect {|a| !a.is_a? Hash }})
|
20
|
+
end
|
21
|
+
alias_method :"#{name}_before_type_cast", name
|
22
|
+
end
|
23
|
+
|
24
|
+
def locale_from(args)
|
25
|
+
args.detect {|a| !a.is_a? Hash }
|
26
|
+
end
|
27
|
+
|
28
|
+
def translations_accessor(name)
|
29
|
+
define_method(:"#{name}_translations") do
|
30
|
+
translations.each_with_object(HashWithIndifferentAccess.new) do |translation, result|
|
31
|
+
result[translation.locale] = translation.send(name)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
define_method(:"#{name}_translations=") do |value|
|
35
|
+
value.each do |(locale, value)|
|
36
|
+
write_attribute name, value, :locale => locale
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,99 @@
|
|
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
|
+
# only Rails > 3.1.x compatibility
|
12
|
+
base.class_eval %{
|
13
|
+
def attributes=(attributes, *args)
|
14
|
+
with_given_locale(attributes) { super }
|
15
|
+
end
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
#def write_attribute(name, value, options = {})
|
21
|
+
# if translated?(name)
|
22
|
+
# options = {:locale => Translatable.locale}.merge(options)
|
23
|
+
#
|
24
|
+
# # Dirty tracking, paraphrased from
|
25
|
+
# # ActiveRecord::AttributeMethods::Dirty#write_attribute.
|
26
|
+
# name_str = name.to_s
|
27
|
+
# if attribute_changed?(name_str)
|
28
|
+
# # If there's already a change, delete it if this undoes the change.
|
29
|
+
# old = changed_attributes[name_str]
|
30
|
+
# changed_attributes.delete(name_str) if value == old
|
31
|
+
# else
|
32
|
+
# # If there's not a change yet, record it.
|
33
|
+
# old = globalize.fetch(options[:locale], name)
|
34
|
+
# old = old.clone if old.duplicable?
|
35
|
+
# changed_attributes[name_str] = old if value != old
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# translatable.write(options[:locale], name, value)
|
39
|
+
# else
|
40
|
+
# super(name, value)
|
41
|
+
# end
|
42
|
+
#end
|
43
|
+
|
44
|
+
def translate
|
45
|
+
@translate_me = true
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
def translate?
|
50
|
+
!@translate_me.nil? && @translate_me = true
|
51
|
+
end
|
52
|
+
|
53
|
+
def read_attribute(name, options = {})
|
54
|
+
options = {:translated => true, :locale => nil}.merge(options)
|
55
|
+
if translated?(name) and options[:translated]
|
56
|
+
if translate? && (value = translatable.fetch(options[:locale] || Translatable.locale, name))
|
57
|
+
value
|
58
|
+
else
|
59
|
+
super(name)
|
60
|
+
end
|
61
|
+
else
|
62
|
+
super(name)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def translated?(name)
|
67
|
+
self.class.translated?(name)
|
68
|
+
end
|
69
|
+
|
70
|
+
def translation_for(locale, name, build_if_missing = false)
|
71
|
+
unless translation_caches["#{locale}_#{name}"]
|
72
|
+
# Fetch translations from database as those in the translation collection may be incomplete
|
73
|
+
_translation = translations.detect{|t| t.locale.to_s == locale.to_s && t.key.to_s == name.to_s }
|
74
|
+
_translation ||= translations.build(:locale => locale) if build_if_missing
|
75
|
+
translation_caches["#{locale}_#{name}"] = _translation if _translation
|
76
|
+
end
|
77
|
+
translation_caches["#{locale}_#{name}"]
|
78
|
+
end
|
79
|
+
|
80
|
+
def translation_caches
|
81
|
+
@translation_caches ||= {}
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
def with_given_locale(attributes, &block)
|
86
|
+
attributes.symbolize_keys! if attributes.respond_to?(:symbolize_keys!)
|
87
|
+
|
88
|
+
locale = respond_to?(:locale=) ? attributes.try(:[], :locale) :
|
89
|
+
attributes.try(:delete, :locale)
|
90
|
+
|
91
|
+
if locale
|
92
|
+
Translatable.with_locale(locale, &block)
|
93
|
+
else
|
94
|
+
yield
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
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
|
+
translation_class.instance_eval %{
|
15
|
+
attr_accessible :#{attr_names.join(', :')}
|
16
|
+
}
|
17
|
+
|
18
|
+
attr_names.each do |attr_name|
|
19
|
+
# Detect and apply serialization.
|
20
|
+
serializer = self.serialized_attributes[attr_name.to_s]
|
21
|
+
if serializer.present?
|
22
|
+
if defined?(::ActiveRecord::Coders::YAMLColumn) &&
|
23
|
+
serializer.is_a?(::ActiveRecord::Coders::YAMLColumn)
|
24
|
+
|
25
|
+
serializer = serializer.object_class
|
26
|
+
end
|
27
|
+
|
28
|
+
translation_class.send :serialize, attr_name, serializer
|
29
|
+
end
|
30
|
+
|
31
|
+
# Create accessors for the attribute.
|
32
|
+
translated_attr_accessor(attr_name)
|
33
|
+
translations_accessor(attr_name)
|
34
|
+
|
35
|
+
# Add attribute to the list.
|
36
|
+
self.translated_attribute_names << attr_name
|
37
|
+
end
|
38
|
+
|
39
|
+
Translatable.add_translatable self
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def class_name
|
45
|
+
@class_name ||= begin
|
46
|
+
class_name = table_name[table_name_prefix.length..-(table_name_suffix.length + 1)].downcase.camelize
|
47
|
+
pluralize_table_names ? class_name.singularize : class_name
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def translatable?
|
52
|
+
included_modules.include?(InstanceMethods)
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
def setup_translatable!(options)
|
57
|
+
options[:table_name] ||= Translatable.translation_class.table_name
|
58
|
+
options[:foreign_key] ||= 'record_id'
|
59
|
+
options[:conditions] ||= ''
|
60
|
+
|
61
|
+
class_attribute :translated_attribute_names, :translation_options, :fallbacks_for_empty_translations
|
62
|
+
self.translated_attribute_names = []
|
63
|
+
self.translation_options = options
|
64
|
+
self.fallbacks_for_empty_translations = options[:fallbacks_for_empty_translations]
|
65
|
+
|
66
|
+
# Alias original relation method so we can safely override it in ClassMethods.
|
67
|
+
#class << self
|
68
|
+
# alias relation_without_globalize relation
|
69
|
+
#end
|
70
|
+
|
71
|
+
include InstanceMethods
|
72
|
+
extend ClassMethods
|
73
|
+
|
74
|
+
translation_class.table_name = options[:table_name]
|
75
|
+
|
76
|
+
has_many :translations, :class_name => translation_class.name,
|
77
|
+
:foreign_key => options[:foreign_key],
|
78
|
+
:conditions => options[:conditions],
|
79
|
+
:dependent => :destroy,
|
80
|
+
:extend => HasManyExtensions,
|
81
|
+
:autosave => false
|
82
|
+
|
83
|
+
#after_create :save_translations!
|
84
|
+
#after_update :save_translations!
|
85
|
+
|
86
|
+
translation_class.instance_eval %{ attr_accessible :lang }
|
87
|
+
end
|
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
|
@@ -1,66 +1,13 @@
|
|
1
1
|
module Translatable
|
2
2
|
module ActiveRecord
|
3
3
|
module Translate
|
4
|
-
def translate(lang, *attr_names)
|
5
4
|
|
6
|
-
|
7
|
-
|
5
|
+
# Ask for translations
|
6
|
+
def translate
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
else
|
13
|
-
to_translate = attr_names
|
14
|
-
q = self
|
15
|
-
end
|
16
|
-
|
17
|
-
index = 0
|
18
|
-
to_translate.each do |attr|
|
19
|
-
|
20
|
-
if is_in_scope? attr
|
21
|
-
index += 1
|
22
|
-
if Translatable::Config.list[model].include?(attr.to_s)
|
23
|
-
q = q.joins("LEFT JOIN snippets sn#{index} ON sn#{index}.record_id = #{model}.id AND sn#{index}.scope = '#{model}' AND sn#{index}.group_id = #{model}.group_id AND sn#{index}.lang = '#{lang}' AND sn#{index}.key = '#{attr}'").
|
24
|
-
select("COALESCE(sn#{index}.value, '') AS #{attr}")
|
25
|
-
else
|
26
|
-
q = q.select("#{model}.#{attr}")
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
q.scoped
|
33
|
-
else
|
34
|
-
self.scoped
|
35
|
-
end
|
36
|
-
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
def has_select_values?
|
42
|
-
self.scoped.select_values.length > 0
|
43
|
-
end
|
44
|
-
|
45
|
-
def is_in_scope?(attr)
|
46
|
-
|
47
|
-
if has_select_values?
|
48
|
-
select_values = self.scoped.select_values.map { |one|
|
49
|
-
if one.is_a?(String)
|
50
|
-
one.split(',').map(&:lstrip).map(&:rstrip)
|
51
|
-
elsif one.is_a?(Symbol)
|
52
|
-
one.to_s
|
53
|
-
end
|
54
|
-
}.flatten
|
55
|
-
is_present = select_values.reject{ |value| !value.is_a?(String) || !value.split('.').last == '*' && !value.split('.').last == attr }
|
56
|
-
if is_present.nil?
|
57
|
-
false
|
58
|
-
else
|
59
|
-
is_present.length > 0
|
60
|
-
end
|
61
|
-
else
|
62
|
-
true
|
63
|
-
end
|
8
|
+
q = self.scoped
|
9
|
+
q.map(&:translate)
|
10
|
+
q
|
64
11
|
|
65
12
|
end
|
66
13
|
|
@@ -1,3 +1,8 @@
|
|
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__
|
1
6
|
require File.expand_path '../active_record/translate.rb', __FILE__
|
2
7
|
|
3
8
|
module Translatable
|
data/lib/translatable/default.rb
CHANGED
@@ -1,57 +1,5 @@
|
|
1
|
-
require
|
1
|
+
require 'active_record'
|
2
2
|
require File.expand_path '../active_record.rb', __FILE__
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
include Singleton
|
8
|
-
attr_accessor :models, :clicrdv_models
|
9
|
-
|
10
|
-
CLICRDV_TYPES = %w(model customfield preprosition)
|
11
|
-
|
12
|
-
def self.is_a_customfield?(str)
|
13
|
-
str.match(/\Acustomfields/)
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.is_a_preposition?(str)
|
17
|
-
str.match(/\Apreposition/)
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.is_an_ar_model?(str)
|
21
|
-
is_it = false
|
22
|
-
begin
|
23
|
-
model = str.singularize.camelize.constantize
|
24
|
-
is_it = true if model.superclass.name == 'ActiveRecord::Base' && str != 'customfields'
|
25
|
-
rescue NameError
|
26
|
-
end
|
27
|
-
is_it
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.type str
|
31
|
-
if is_model str
|
32
|
-
'model'
|
33
|
-
elsif is_customfield str
|
34
|
-
'customfield'
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
# Get all translatables models
|
39
|
-
# @param array of things to translate
|
40
|
-
# @return an array of three elements : ARModels, Customfields and Preprositions
|
41
|
-
def self.clicrdv_models(hash=nil)
|
42
|
-
if hash.nil? || hash.empty?
|
43
|
-
process_me = Config.list
|
44
|
-
else
|
45
|
-
process_me = hash
|
46
|
-
end
|
47
|
-
# Don't remove the v in the block parameters |k,v| this because of Ruby 1.8.7
|
48
|
-
ar_models = process_me.reject{ |k,v| !is_an_ar_model?(k) }
|
49
|
-
customfields = process_me.reject{ |k,v| !is_a_customfield?(k) }
|
50
|
-
prepositions = process_me.reject{ |k,v| !is_a_preposition?(k) }
|
51
|
-
|
52
|
-
[ar_models, customfields, prepositions]
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
ActiveRecord::Base.extend(Translatable::ActiveRecord::Translate)
|
4
|
+
ActiveRecord::Base.extend(Translatable::ActiveRecord::Translate)
|
5
|
+
ActiveRecord::Base.extend(Translatable::ActiveRecord::Macro)
|
data/lib/translatable/version.rb
CHANGED
data/lib/translatable.rb
CHANGED
@@ -1 +1,58 @@
|
|
1
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
|
+
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
|
+
set_locale(locale)
|
20
|
+
result = yield(locale)
|
21
|
+
set_locale(previous_locale)
|
22
|
+
result
|
23
|
+
end
|
24
|
+
|
25
|
+
def translation_class_name=(klass)
|
26
|
+
@@translation_class = klass.constantize
|
27
|
+
end
|
28
|
+
def translation_class
|
29
|
+
@@translation_class ||= nil
|
30
|
+
end
|
31
|
+
|
32
|
+
# Hash of models that are translatable (values are the attrs)
|
33
|
+
def list
|
34
|
+
@@translatable ||= Hash.new
|
35
|
+
end
|
36
|
+
|
37
|
+
def add_translatable(klass)
|
38
|
+
if @@translatable.has_key? klass.name
|
39
|
+
klass.translated_attribute_names.each do |attr|
|
40
|
+
@@translatable[klass.name] << attr unless @@translatable[klass.name].include?(attr)
|
41
|
+
end
|
42
|
+
else
|
43
|
+
@@translatable[klass.name] = klass.translated_attribute_names
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
protected
|
48
|
+
|
49
|
+
def read_locale
|
50
|
+
Thread.current[:translatable_locale]
|
51
|
+
end
|
52
|
+
|
53
|
+
def set_locale(locale)
|
54
|
+
Thread.current[:translatable_locale] = locale.try(:to_sym)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: easy_translatable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul Bonaud
|
@@ -60,10 +60,15 @@ executables: []
|
|
60
60
|
extensions: []
|
61
61
|
extra_rdoc_files: []
|
62
62
|
files:
|
63
|
+
- README.md
|
63
64
|
- lib/translatable.rb
|
64
65
|
- lib/translatable/active_record.rb
|
66
|
+
- lib/translatable/active_record/adapter.rb
|
67
|
+
- lib/translatable/active_record/attributes.rb
|
68
|
+
- lib/translatable/active_record/class_methods.rb
|
69
|
+
- lib/translatable/active_record/instance_methods.rb
|
70
|
+
- lib/translatable/active_record/macro.rb
|
65
71
|
- lib/translatable/active_record/translate.rb
|
66
|
-
- lib/translatable/config.rb
|
67
72
|
- lib/translatable/default.rb
|
68
73
|
- lib/translatable/version.rb
|
69
74
|
homepage: http://rubygems.org/gems/single_translatable
|