globalize3 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +37 -57
- data/Rakefile +1 -1
- data/lib/globalize.rb +27 -4
- data/lib/globalize/active_record/act_macro.rb +45 -20
- data/lib/globalize/active_record/adapter.rb +4 -3
- data/lib/globalize/active_record/class_methods.rb +39 -5
- data/lib/globalize/active_record/instance_methods.rb +31 -18
- data/lib/globalize/active_record/migration.rb +23 -7
- data/lib/globalize/active_record/translation.rb +8 -3
- data/lib/globalize3/version.rb +1 -1
- data/lib/patches/active_record/uniqueness_validator.rb +55 -0
- metadata +123 -132
- data/README.textile +0 -205
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
globalize3 (0.
|
4
|
+
globalize3 (0.3.0)
|
5
5
|
activemodel (>= 3.0.0)
|
6
6
|
activerecord (>= 3.0.0)
|
7
7
|
paper_trail (~> 2)
|
@@ -9,93 +9,73 @@ PATH
|
|
9
9
|
GEM
|
10
10
|
remote: http://rubygems.org/
|
11
11
|
specs:
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
actionpack (3.2.1)
|
16
|
-
activemodel (= 3.2.1)
|
17
|
-
activesupport (= 3.2.1)
|
12
|
+
actionpack (3.2.9)
|
13
|
+
activemodel (= 3.2.9)
|
14
|
+
activesupport (= 3.2.9)
|
18
15
|
builder (~> 3.0.0)
|
19
16
|
erubis (~> 2.7.0)
|
20
|
-
journey (~> 1.0.
|
17
|
+
journey (~> 1.0.4)
|
21
18
|
rack (~> 1.4.0)
|
22
|
-
rack-cache (~> 1.
|
19
|
+
rack-cache (~> 1.2)
|
23
20
|
rack-test (~> 0.6.1)
|
24
|
-
sprockets (~> 2.1
|
25
|
-
activemodel (3.2.
|
26
|
-
activesupport (= 3.2.
|
21
|
+
sprockets (~> 2.2.1)
|
22
|
+
activemodel (3.2.9)
|
23
|
+
activesupport (= 3.2.9)
|
27
24
|
builder (~> 3.0.0)
|
28
|
-
activerecord (3.2.
|
29
|
-
activemodel (= 3.2.
|
30
|
-
activesupport (= 3.2.
|
31
|
-
arel (~> 3.0.
|
25
|
+
activerecord (3.2.9)
|
26
|
+
activemodel (= 3.2.9)
|
27
|
+
activesupport (= 3.2.9)
|
28
|
+
arel (~> 3.0.2)
|
32
29
|
tzinfo (~> 0.3.29)
|
33
|
-
|
34
|
-
activemodel (= 3.2.1)
|
35
|
-
activesupport (= 3.2.1)
|
36
|
-
activesupport (3.2.1)
|
30
|
+
activesupport (3.2.9)
|
37
31
|
i18n (~> 0.6)
|
38
32
|
multi_json (~> 1.0)
|
39
|
-
arel (3.0.
|
40
|
-
builder (3.0.
|
33
|
+
arel (3.0.2)
|
34
|
+
builder (3.0.4)
|
41
35
|
database_cleaner (0.5.2)
|
42
36
|
erubis (2.7.0)
|
43
37
|
hike (1.2.1)
|
44
|
-
i18n (0.6.
|
45
|
-
journey (1.0.
|
46
|
-
json (1.
|
47
|
-
mail (2.4.1)
|
48
|
-
i18n (>= 0.4.0)
|
49
|
-
mime-types (~> 1.16)
|
50
|
-
treetop (~> 1.4.8)
|
38
|
+
i18n (0.6.1)
|
39
|
+
journey (1.0.4)
|
40
|
+
json (1.7.5)
|
51
41
|
metaclass (0.0.1)
|
52
|
-
|
53
|
-
mocha (0.10.3)
|
42
|
+
mocha (0.12.3)
|
54
43
|
metaclass (~> 0.0.1)
|
55
|
-
multi_json (1.0
|
56
|
-
paper_trail (2.6.
|
57
|
-
|
44
|
+
multi_json (1.5.0)
|
45
|
+
paper_trail (2.6.4)
|
46
|
+
activerecord (~> 3.0)
|
47
|
+
railties (~> 3.0)
|
58
48
|
pathname_local (0.0.2)
|
59
|
-
polyglot (0.3.3)
|
60
49
|
rack (1.4.1)
|
61
|
-
rack-cache (1.
|
50
|
+
rack-cache (1.2)
|
62
51
|
rack (>= 0.4)
|
63
52
|
rack-ssl (1.3.2)
|
64
53
|
rack
|
65
|
-
rack-test (0.6.
|
54
|
+
rack-test (0.6.2)
|
66
55
|
rack (>= 1.0)
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
activerecord (= 3.2.1)
|
71
|
-
activeresource (= 3.2.1)
|
72
|
-
activesupport (= 3.2.1)
|
73
|
-
bundler (~> 1.0)
|
74
|
-
railties (= 3.2.1)
|
75
|
-
railties (3.2.1)
|
76
|
-
actionpack (= 3.2.1)
|
77
|
-
activesupport (= 3.2.1)
|
56
|
+
railties (3.2.9)
|
57
|
+
actionpack (= 3.2.9)
|
58
|
+
activesupport (= 3.2.9)
|
78
59
|
rack-ssl (~> 1.3.2)
|
79
60
|
rake (>= 0.8.7)
|
80
61
|
rdoc (~> 3.4)
|
81
|
-
thor (
|
82
|
-
rake (0.
|
62
|
+
thor (>= 0.14.6, < 2.0)
|
63
|
+
rake (10.0.3)
|
83
64
|
rdoc (3.12)
|
84
65
|
json (~> 1.4)
|
85
|
-
sprockets (2.
|
66
|
+
sprockets (2.2.2)
|
86
67
|
hike (~> 1.2)
|
68
|
+
multi_json (~> 1.0)
|
87
69
|
rack (~> 1.0)
|
88
70
|
tilt (~> 1.1, != 1.3.0)
|
89
|
-
sqlite3 (1.3.
|
71
|
+
sqlite3 (1.3.6)
|
90
72
|
test_declarative (0.0.5)
|
91
|
-
thor (0.
|
73
|
+
thor (0.16.0)
|
92
74
|
tilt (1.3.3)
|
93
|
-
|
94
|
-
polyglot
|
95
|
-
polyglot (>= 0.3.1)
|
96
|
-
tzinfo (0.3.31)
|
75
|
+
tzinfo (0.3.35)
|
97
76
|
|
98
77
|
PLATFORMS
|
78
|
+
java
|
99
79
|
ruby
|
100
80
|
|
101
81
|
DEPENDENCIES
|
data/Rakefile
CHANGED
data/lib/globalize.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'active_record'
|
2
2
|
require 'patches/active_record/xml_attribute_serializer'
|
3
3
|
require 'patches/active_record/query_method'
|
4
|
+
require 'patches/active_record/uniqueness_validator'
|
4
5
|
|
5
6
|
module Globalize
|
6
7
|
autoload :ActiveRecord, 'globalize/active_record'
|
@@ -29,12 +30,20 @@ module Globalize
|
|
29
30
|
end
|
30
31
|
end
|
31
32
|
|
32
|
-
def fallbacks
|
33
|
+
def fallbacks=(locales)
|
34
|
+
set_fallbacks(locales)
|
35
|
+
end
|
36
|
+
|
37
|
+
def i18n_fallbacks?
|
33
38
|
I18n.respond_to?(:fallbacks)
|
34
39
|
end
|
35
40
|
|
36
|
-
def fallbacks(
|
37
|
-
|
41
|
+
def fallbacks(for_locale = self.locale)
|
42
|
+
read_fallbacks[for_locale] || default_fallbacks(for_locale)
|
43
|
+
end
|
44
|
+
|
45
|
+
def default_fallbacks(for_locale = self.locale)
|
46
|
+
i18n_fallbacks? ? I18n.fallbacks[for_locale] : [for_locale.to_sym]
|
38
47
|
end
|
39
48
|
|
40
49
|
protected
|
@@ -44,7 +53,21 @@ module Globalize
|
|
44
53
|
end
|
45
54
|
|
46
55
|
def set_locale(locale)
|
47
|
-
Thread.current[:globalize_locale] = locale.to_sym
|
56
|
+
Thread.current[:globalize_locale] = locale.try(:to_sym)
|
57
|
+
end
|
58
|
+
|
59
|
+
def read_fallbacks
|
60
|
+
Thread.current[:fallbacks] || HashWithIndifferentAccess.new
|
61
|
+
end
|
62
|
+
|
63
|
+
def set_fallbacks(locales)
|
64
|
+
fallback_hash = HashWithIndifferentAccess.new
|
65
|
+
|
66
|
+
locales.each do |key, value|
|
67
|
+
fallback_hash[key] = value.presence || [key]
|
68
|
+
end if locales.present?
|
69
|
+
|
70
|
+
Thread.current[:fallbacks] = fallback_hash
|
48
71
|
end
|
49
72
|
end
|
50
73
|
end
|
@@ -2,37 +2,62 @@ module Globalize
|
|
2
2
|
module ActiveRecord
|
3
3
|
module ActMacro
|
4
4
|
def translates(*attr_names)
|
5
|
-
return if translates?
|
6
5
|
|
7
6
|
options = attr_names.extract_options!
|
8
|
-
|
7
|
+
attr_names = attr_names.map(&:to_sym)
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
self.fallbacks_for_empty_translations = options[:fallbacks_for_empty_translations]
|
9
|
+
unless translates?
|
10
|
+
options[:table_name] ||= "#{table_name.singularize}_translations"
|
11
|
+
options[:foreign_key] ||= class_name.foreign_key
|
14
12
|
|
15
|
-
|
16
|
-
|
13
|
+
class_attribute :translated_attribute_names, :translation_options, :fallbacks_for_empty_translations
|
14
|
+
self.translated_attribute_names = []
|
15
|
+
self.translation_options = options
|
16
|
+
self.fallbacks_for_empty_translations = options[:fallbacks_for_empty_translations]
|
17
17
|
|
18
|
-
|
18
|
+
include InstanceMethods
|
19
|
+
extend ClassMethods, Migration
|
19
20
|
|
20
|
-
|
21
|
-
:foreign_key => class_name.foreign_key,
|
22
|
-
:dependent => :destroy,
|
23
|
-
:extend => HasManyExtensions
|
21
|
+
translation_class.table_name = options[:table_name] if translation_class.table_name.blank?
|
24
22
|
|
25
|
-
|
26
|
-
|
23
|
+
has_many :translations, :class_name => translation_class.name,
|
24
|
+
:foreign_key => options[:foreign_key],
|
25
|
+
:dependent => :destroy,
|
26
|
+
:extend => HasManyExtensions
|
27
27
|
|
28
|
-
|
29
|
-
|
28
|
+
after_create :save_translations!
|
29
|
+
after_update :save_translations!
|
30
30
|
|
31
|
-
|
32
|
-
|
31
|
+
if options[:versioning]
|
32
|
+
::ActiveRecord::Base.extend(Globalize::Versioning::PaperTrail)
|
33
|
+
|
34
|
+
translation_class.has_paper_trail
|
35
|
+
delegate :version, :versions, :to => :translation
|
36
|
+
end
|
37
|
+
|
38
|
+
translation_class.instance_eval %{
|
39
|
+
attr_accessible :#{(attr_names | [:locale]).join(', :')}
|
40
|
+
}
|
41
|
+
|
42
|
+
# detect and apply serialization
|
43
|
+
attr_names.each do |attr_name|
|
44
|
+
serializer = self.serialized_attributes[attr_name.to_s]
|
45
|
+
|
46
|
+
if serializer.present?
|
47
|
+
if defined?(::ActiveRecord::Coders::YAMLColumn) &&
|
48
|
+
serializer.is_a?(::ActiveRecord::Coders::YAMLColumn)
|
49
|
+
|
50
|
+
serializer = serializer.object_class
|
51
|
+
end
|
52
|
+
|
53
|
+
translation_class.send :serialize, attr_name, serializer
|
54
|
+
end
|
55
|
+
end
|
33
56
|
end
|
34
57
|
|
35
|
-
|
58
|
+
new_attr_names = attr_names - translated_attribute_names
|
59
|
+
new_attr_names.each { |attr_name| translated_attr_accessor(attr_name) }
|
60
|
+
self.translated_attribute_names += new_attr_names
|
36
61
|
end
|
37
62
|
|
38
63
|
def class_name
|
@@ -20,14 +20,15 @@ module Globalize
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def fetch(locale, name)
|
23
|
-
|
24
|
-
value = fetch_stash(fallback, name)
|
23
|
+
record.globalize_fallbacks(locale).each do |fallback|
|
24
|
+
value = stash.contains?(fallback, name) ? fetch_stash(fallback, name) : fetch_attribute(fallback, name)
|
25
25
|
|
26
26
|
unless fallbacks_for?(value)
|
27
27
|
set_metadata(value, :locale => fallback, :requested_locale => locale)
|
28
28
|
return value
|
29
29
|
end
|
30
30
|
end
|
31
|
+
|
31
32
|
return nil
|
32
33
|
end
|
33
34
|
|
@@ -74,7 +75,7 @@ module Globalize
|
|
74
75
|
end
|
75
76
|
|
76
77
|
def fetch_attribute(locale, name)
|
77
|
-
translation = record.translation_for(locale)
|
78
|
+
translation = record.translation_for(locale, false)
|
78
79
|
return translation && translation.send(name)
|
79
80
|
end
|
80
81
|
|
@@ -45,7 +45,7 @@ module Globalize
|
|
45
45
|
klass = self.const_set(:Translation, Class.new(Globalize::ActiveRecord::Translation))
|
46
46
|
end
|
47
47
|
|
48
|
-
klass.belongs_to name.underscore.gsub('/', '_')
|
48
|
+
klass.belongs_to name.underscore.gsub('/', '_').to_sym, :class_name => self.name
|
49
49
|
klass
|
50
50
|
end
|
51
51
|
end
|
@@ -70,7 +70,7 @@ module Globalize
|
|
70
70
|
|
71
71
|
def supported_on_missing?(method_id)
|
72
72
|
return super unless RUBY_VERSION < '1.9' || respond_to?(:translated_attribute_names)
|
73
|
-
match = ::ActiveRecord::DynamicFinderMatch.match(method_id) || ::ActiveRecord::DynamicScopeMatch.match(method_id)
|
73
|
+
match = defined?(::ActiveRecord::DynamicFinderMatch) && (::ActiveRecord::DynamicFinderMatch.match(method_id) || ::ActiveRecord::DynamicScopeMatch.match(method_id))
|
74
74
|
return false if match.nil?
|
75
75
|
|
76
76
|
attribute_names = match.attribute_names.map(&:to_sym)
|
@@ -98,12 +98,46 @@ module Globalize
|
|
98
98
|
scope = scope.send(:"scoped_by_#{unt}", arguments[index])
|
99
99
|
end
|
100
100
|
|
101
|
-
|
102
|
-
|
103
|
-
|
101
|
+
if defined?(::ActiveRecord::DynamicFinderMatch) && match.is_a?(::ActiveRecord::DynamicFinderMatch)
|
102
|
+
if match.instantiator? and scope.blank?
|
103
|
+
return scope.find_or_instantiator_by_attributes match, attribute_names, *arguments, &block
|
104
|
+
end
|
105
|
+
match_finder_method = match.finder.to_s
|
106
|
+
match_finder_method << "!" if match.bang? && ::ActiveRecord::VERSION::STRING >= "3.1.0"
|
107
|
+
return scope.send(match_finder_method).tap do |found|
|
108
|
+
found.is_a?(Array) ? found.map { |f| f.translations.reload } : found.translations.reload unless found.nil?
|
109
|
+
end
|
110
|
+
end
|
104
111
|
return scope
|
105
112
|
end
|
106
113
|
|
114
|
+
def find_or_instantiator_by_attributes(match, attributes, *args)
|
115
|
+
options = args.size > 1 && args.last(2).all?{ |a| a.is_a?(Hash) } ? args.extract_options! : {}
|
116
|
+
protected_attributes_for_create, unprotected_attributes_for_create = {}, {}
|
117
|
+
args.each_with_index do |arg, i|
|
118
|
+
if arg.is_a?(Hash)
|
119
|
+
protected_attributes_for_create = args[i].with_indifferent_access
|
120
|
+
else
|
121
|
+
unprotected_attributes_for_create[attributes[i]] = args[i]
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
record = if ::ActiveRecord::VERSION::STRING < "3.1.0"
|
126
|
+
new do |r|
|
127
|
+
r.send(:attributes=, protected_attributes_for_create, true) unless protected_attributes_for_create.empty?
|
128
|
+
r.send(:attributes=, unprotected_attributes_for_create, false) unless unprotected_attributes_for_create.empty?
|
129
|
+
end
|
130
|
+
else
|
131
|
+
new(protected_attributes_for_create, options) do |r|
|
132
|
+
r.assign_attributes(unprotected_attributes_for_create, :without_protection => true)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
yield(record) if block_given?
|
136
|
+
record.send(match.bang? ? :save! : :save) if match.instantiator.eql?(:create)
|
137
|
+
|
138
|
+
record
|
139
|
+
end
|
140
|
+
|
107
141
|
protected
|
108
142
|
|
109
143
|
def translated_attr_accessor(name)
|
@@ -37,19 +37,16 @@ module Globalize
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def write_attribute(name, value, options = {})
|
40
|
-
# raise 'y' if value.nil? # TODO.
|
41
|
-
|
42
40
|
if translated?(name)
|
43
41
|
# Deprecate old use of locale
|
44
42
|
unless options.is_a?(Hash)
|
45
43
|
warn "[DEPRECATION] passing 'locale' as #{options.inspect} is deprecated. Please use {:locale => #{options.inspect}} instead."
|
46
44
|
options = {:locale => options}
|
47
45
|
end
|
48
|
-
options = {:locale =>
|
46
|
+
options = {:locale => Globalize.locale}.merge(options)
|
49
47
|
attribute_will_change! name.to_s
|
50
|
-
|
51
|
-
|
52
|
-
globalize.write(the_locale, name, value)
|
48
|
+
|
49
|
+
globalize.write(options[:locale], name, value)
|
53
50
|
else
|
54
51
|
super(name, value)
|
55
52
|
end
|
@@ -64,7 +61,11 @@ module Globalize
|
|
64
61
|
|
65
62
|
options = {:translated => true, :locale => nil}.merge(options)
|
66
63
|
if self.class.translated?(name) and options[:translated]
|
67
|
-
globalize.fetch(options[:locale] || Globalize.locale, name)
|
64
|
+
if (value = globalize.fetch(options[:locale] || Globalize.locale, name))
|
65
|
+
value
|
66
|
+
elsif respond_to?(:serialized_attributes) && serialized_attributes.has_key?(name.to_s)
|
67
|
+
super(name)
|
68
|
+
end
|
68
69
|
else
|
69
70
|
super(name)
|
70
71
|
end
|
@@ -97,12 +98,17 @@ module Globalize
|
|
97
98
|
def set_translations(options)
|
98
99
|
options.keys.each do |locale|
|
99
100
|
translation = translation_for(locale) ||
|
100
|
-
|
101
|
-
|
101
|
+
translations.build(:locale => locale.to_s)
|
102
|
+
|
103
|
+
options[locale].each do |key, value|
|
104
|
+
translation.send :"#{key}=", value
|
105
|
+
end
|
106
|
+
translation.save
|
102
107
|
end
|
103
108
|
end
|
104
109
|
|
105
110
|
def reload(options = nil)
|
111
|
+
translation_caches.clear
|
106
112
|
translated_attribute_names.each { |name| @attributes.delete(name.to_s) }
|
107
113
|
globalize.reset
|
108
114
|
super(options)
|
@@ -125,20 +131,27 @@ module Globalize
|
|
125
131
|
translation_for(::Globalize.locale)
|
126
132
|
end
|
127
133
|
|
128
|
-
def translation_for(locale)
|
129
|
-
|
130
|
-
unless @translation_caches[locale]
|
134
|
+
def translation_for(locale, build_if_missing = true)
|
135
|
+
unless translation_caches[locale]
|
131
136
|
# Fetch translations from database as those in the translation collection may be incomplete
|
132
137
|
_translation = translations.detect{|t| t.locale.to_s == locale.to_s}
|
133
|
-
_translation ||= translations.with_locale(locale).first
|
134
|
-
_translation ||= translations.build(:locale => locale)
|
135
|
-
|
138
|
+
_translation ||= translations.with_locale(locale).first unless translations.loaded?
|
139
|
+
_translation ||= translations.build(:locale => locale) if build_if_missing
|
140
|
+
translation_caches[locale] = _translation if _translation
|
136
141
|
end
|
137
|
-
|
142
|
+
translation_caches[locale]
|
143
|
+
end
|
144
|
+
|
145
|
+
def translation_caches
|
146
|
+
@translation_caches ||= {}
|
147
|
+
end
|
148
|
+
|
149
|
+
def globalize_fallbacks(locale)
|
150
|
+
Globalize.fallbacks(locale)
|
138
151
|
end
|
139
152
|
|
140
153
|
def rollback
|
141
|
-
|
154
|
+
translation_caches[::Globalize.locale] = translation.previous_version
|
142
155
|
end
|
143
156
|
|
144
157
|
protected
|
@@ -159,7 +172,7 @@ module Globalize
|
|
159
172
|
|
160
173
|
def save_translations!
|
161
174
|
globalize.save_translations!
|
162
|
-
|
175
|
+
translation_caches.clear
|
163
176
|
end
|
164
177
|
|
165
178
|
def with_given_locale(attributes, &block)
|
@@ -10,7 +10,8 @@ module Globalize
|
|
10
10
|
end
|
11
11
|
|
12
12
|
delegate :create_translation_table!, :drop_translation_table!,
|
13
|
-
:translation_index_name, :
|
13
|
+
:translation_index_name, :translation_locale_index_name,
|
14
|
+
:to => :globalize_migrator
|
14
15
|
|
15
16
|
class Migrator
|
16
17
|
include Globalize::ActiveRecord::Exceptions
|
@@ -58,7 +59,13 @@ module Globalize
|
|
58
59
|
connection.create_table(translations_table_name) do |t|
|
59
60
|
t.references table_name.sub(/^#{table_name_prefix}/, '').singularize
|
60
61
|
t.string :locale
|
61
|
-
fields.each
|
62
|
+
fields.each do |name, options|
|
63
|
+
if options.is_a? Hash
|
64
|
+
t.column name, options.delete(:type), options
|
65
|
+
else
|
66
|
+
t.column name, options
|
67
|
+
end
|
68
|
+
end
|
62
69
|
t.timestamps
|
63
70
|
end
|
64
71
|
end
|
@@ -72,7 +79,8 @@ module Globalize
|
|
72
79
|
# index for select('DISTINCT locale') call in translation.rb
|
73
80
|
connection.add_index(
|
74
81
|
translations_table_name,
|
75
|
-
:locale
|
82
|
+
:locale,
|
83
|
+
:name => translation_locale_index_name
|
76
84
|
)
|
77
85
|
end
|
78
86
|
|
@@ -112,9 +120,13 @@ module Globalize
|
|
112
120
|
end
|
113
121
|
|
114
122
|
def validate_translated_fields
|
115
|
-
fields.each do |name,
|
123
|
+
fields.each do |name, options|
|
116
124
|
raise BadFieldName.new(name) unless valid_field_name?(name)
|
117
|
-
|
125
|
+
if options.is_a? Hash
|
126
|
+
raise BadFieldType.new(name, options[:type]) unless valid_field_type?(name, options[:type])
|
127
|
+
else
|
128
|
+
raise BadFieldType.new(name, options) unless valid_field_type?(name, options)
|
129
|
+
end
|
118
130
|
end
|
119
131
|
end
|
120
132
|
|
@@ -131,9 +143,13 @@ module Globalize
|
|
131
143
|
end
|
132
144
|
|
133
145
|
def translation_index_name
|
134
|
-
# FIXME what's the max size of an index name?
|
135
146
|
index_name = "index_#{translations_table_name}_on_#{table_name.singularize}_id"
|
136
|
-
index_name.size <
|
147
|
+
index_name.size < connection.index_name_length ? index_name : "index_#{Digest::SHA1.hexdigest(index_name)}"
|
148
|
+
end
|
149
|
+
|
150
|
+
def translation_locale_index_name
|
151
|
+
index_name = "index_#{translations_table_name}_on_locale"
|
152
|
+
index_name.size < connection.index_name_length ? index_name : "index_#{Digest::SHA1.hexdigest(index_name)}"
|
137
153
|
end
|
138
154
|
|
139
155
|
def clear_schema_cache!
|
@@ -1,6 +1,10 @@
|
|
1
1
|
module Globalize
|
2
2
|
module ActiveRecord
|
3
3
|
class Translation < ::ActiveRecord::Base
|
4
|
+
|
5
|
+
attr_accessible :locale
|
6
|
+
validates :locale, :presence => true
|
7
|
+
|
4
8
|
class << self
|
5
9
|
# Sometimes ActiveRecord queries .table_exists? before the table name
|
6
10
|
# has even been set which results in catastrophic failure.
|
@@ -12,7 +16,7 @@ module Globalize
|
|
12
16
|
# Avoid using "IN" with SQL queries when only using one locale.
|
13
17
|
locales = locales.flatten.map(&:to_s)
|
14
18
|
locales = locales.first if locales.one?
|
15
|
-
where
|
19
|
+
where :locale => locales
|
16
20
|
end
|
17
21
|
alias with_locale with_locales
|
18
22
|
|
@@ -22,11 +26,12 @@ module Globalize
|
|
22
26
|
end
|
23
27
|
|
24
28
|
def locale
|
25
|
-
read_attribute
|
29
|
+
_locale = read_attribute :locale
|
30
|
+
_locale.present? ? _locale.to_sym : _locale
|
26
31
|
end
|
27
32
|
|
28
33
|
def locale=(locale)
|
29
|
-
write_attribute
|
34
|
+
write_attribute :locale, locale.to_s
|
30
35
|
end
|
31
36
|
end
|
32
37
|
end
|
data/lib/globalize3/version.rb
CHANGED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'active_record/validations/uniqueness.rb'
|
2
|
+
|
3
|
+
ActiveRecord::Validations::UniquenessValidator.class_eval do
|
4
|
+
def validate_each_with_translations(record, attribute, value)
|
5
|
+
klass = record.class
|
6
|
+
if klass.translates? && klass.translated?(attribute)
|
7
|
+
if methods.include?(:build_relation) || respond_to?(:build_relation)
|
8
|
+
finder_class = klass.translation_class
|
9
|
+
table = finder_class.arel_table
|
10
|
+
|
11
|
+
relation = build_relation(finder_class, table, attribute, value).and(table[:locale].eq(Globalize.locale))
|
12
|
+
relation = relation.and(table[klass.reflect_on_association(:translations).foreign_key].not_eq(record.send(:id))) if record.persisted?
|
13
|
+
|
14
|
+
# TODO: add scope with translated attributes
|
15
|
+
if options[:scope]
|
16
|
+
ActiveRecord::Base.logger.warn("WARNING: Globalize3 does not currently support `scope` option on uniqueness validation for translated attributes.")
|
17
|
+
end
|
18
|
+
|
19
|
+
if finder_class.unscoped.where(relation).exists?
|
20
|
+
record.errors.add(attribute, :taken, options.except(:case_sensitive, :scope).merge(:value => value))
|
21
|
+
end
|
22
|
+
else
|
23
|
+
finder_class = klass.translation_class
|
24
|
+
table = finder_class.unscoped
|
25
|
+
|
26
|
+
table_name = finder_class.quoted_table_name
|
27
|
+
|
28
|
+
if value && klass.serialized_attributes.key?(attribute.to_s)
|
29
|
+
value = YAML.dump value
|
30
|
+
end
|
31
|
+
|
32
|
+
sql, params = mount_sql_and_params(finder_class, table_name, attribute, value)
|
33
|
+
|
34
|
+
relation = table.where(sql, *params).where(:locale => Globalize.locale)
|
35
|
+
|
36
|
+
Array.wrap(options[:scope]).each do |scope_item|
|
37
|
+
scope_value = record.send(scope_item)
|
38
|
+
relation = relation.where(scope_item => scope_value)
|
39
|
+
end
|
40
|
+
|
41
|
+
if record.persisted?
|
42
|
+
fk = klass.reflect_on_association(:translations).options[:foreign_key]
|
43
|
+
relation = relation.where(finder_class.arel_table[fk].not_eq(record.send(:id)))
|
44
|
+
end
|
45
|
+
|
46
|
+
if relation.exists?
|
47
|
+
record.errors.add(attribute, :taken, options.except(:case_sensitive, :scope).merge(:value => value))
|
48
|
+
end
|
49
|
+
end
|
50
|
+
else
|
51
|
+
validate_each_without_translations(record, attribute, value)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
alias_method_chain :validate_each, :translations
|
55
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,10 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: globalize3
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 2
|
9
|
-
- 0
|
10
|
-
version: 0.2.0
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Sven Fuchs
|
14
9
|
- Joshua Harvey
|
15
10
|
- Clemens Kofler
|
@@ -19,136 +14,142 @@ authors:
|
|
19
14
|
autorequire:
|
20
15
|
bindir: bin
|
21
16
|
cert_chain: []
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
- !ruby/object:Gem::Dependency
|
17
|
+
date: 2012-12-20 00:00:00.000000000 Z
|
18
|
+
dependencies:
|
19
|
+
- !ruby/object:Gem::Dependency
|
26
20
|
name: activerecord
|
27
21
|
prerelease: false
|
28
|
-
requirement:
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
hash: 7
|
34
|
-
segments:
|
35
|
-
- 3
|
36
|
-
- 0
|
37
|
-
- 0
|
22
|
+
requirement: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
38
26
|
version: 3.0.0
|
27
|
+
none: false
|
39
28
|
type: :runtime
|
40
|
-
version_requirements:
|
41
|
-
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 3.0.0
|
34
|
+
none: false
|
35
|
+
- !ruby/object:Gem::Dependency
|
42
36
|
name: activemodel
|
43
37
|
prerelease: false
|
44
|
-
requirement:
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
- !ruby/object:Gem::Version
|
49
|
-
hash: 7
|
50
|
-
segments:
|
51
|
-
- 3
|
52
|
-
- 0
|
53
|
-
- 0
|
38
|
+
requirement: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ! '>='
|
41
|
+
- !ruby/object:Gem::Version
|
54
42
|
version: 3.0.0
|
43
|
+
none: false
|
55
44
|
type: :runtime
|
56
|
-
version_requirements:
|
57
|
-
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ! '>='
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 3.0.0
|
50
|
+
none: false
|
51
|
+
- !ruby/object:Gem::Dependency
|
58
52
|
name: paper_trail
|
59
53
|
prerelease: false
|
60
|
-
requirement:
|
61
|
-
|
62
|
-
requirements:
|
54
|
+
requirement: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
63
56
|
- - ~>
|
64
|
-
- !ruby/object:Gem::Version
|
65
|
-
|
66
|
-
|
67
|
-
- 2
|
68
|
-
version: "2"
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '2'
|
59
|
+
none: false
|
69
60
|
type: :runtime
|
70
|
-
version_requirements:
|
71
|
-
|
61
|
+
version_requirements: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ~>
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '2'
|
66
|
+
none: false
|
67
|
+
- !ruby/object:Gem::Dependency
|
72
68
|
name: database_cleaner
|
73
69
|
prerelease: false
|
74
|
-
requirement:
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
- !ruby/object:Gem::Version
|
79
|
-
hash: 15
|
80
|
-
segments:
|
81
|
-
- 0
|
82
|
-
- 5
|
83
|
-
- 2
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - '='
|
73
|
+
- !ruby/object:Gem::Version
|
84
74
|
version: 0.5.2
|
75
|
+
none: false
|
85
76
|
type: :development
|
86
|
-
version_requirements:
|
87
|
-
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - '='
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: 0.5.2
|
82
|
+
none: false
|
83
|
+
- !ruby/object:Gem::Dependency
|
88
84
|
name: mocha
|
89
85
|
prerelease: false
|
90
|
-
requirement:
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
segments:
|
97
|
-
- 0
|
98
|
-
version: "0"
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ! '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
none: false
|
99
92
|
type: :development
|
100
|
-
version_requirements:
|
101
|
-
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ! '>='
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
none: false
|
99
|
+
- !ruby/object:Gem::Dependency
|
102
100
|
name: pathname_local
|
103
101
|
prerelease: false
|
104
|
-
requirement:
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
segments:
|
111
|
-
- 0
|
112
|
-
version: "0"
|
102
|
+
requirement: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - ! '>='
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
none: false
|
113
108
|
type: :development
|
114
|
-
version_requirements:
|
115
|
-
|
109
|
+
version_requirements: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ! '>='
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
114
|
+
none: false
|
115
|
+
- !ruby/object:Gem::Dependency
|
116
116
|
name: test_declarative
|
117
117
|
prerelease: false
|
118
|
-
requirement:
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
segments:
|
125
|
-
- 0
|
126
|
-
version: "0"
|
118
|
+
requirement: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ! '>='
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
none: false
|
127
124
|
type: :development
|
128
|
-
version_requirements:
|
129
|
-
|
125
|
+
version_requirements: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - ! '>='
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '0'
|
130
|
+
none: false
|
131
|
+
- !ruby/object:Gem::Dependency
|
130
132
|
name: sqlite3
|
131
133
|
prerelease: false
|
132
|
-
requirement:
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
segments:
|
139
|
-
- 0
|
140
|
-
version: "0"
|
134
|
+
requirement: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ! '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
none: false
|
141
140
|
type: :development
|
142
|
-
version_requirements:
|
143
|
-
|
141
|
+
version_requirements: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ! '>='
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
none: false
|
147
|
+
description: Rails I18n de-facto standard library for ActiveRecord 3 model/data translation.
|
144
148
|
email: nobody@globalize-rails.org
|
145
149
|
executables: []
|
146
|
-
|
147
150
|
extensions: []
|
148
|
-
|
149
151
|
extra_rdoc_files: []
|
150
|
-
|
151
|
-
files:
|
152
|
+
files:
|
152
153
|
- lib/globalize/active_record/act_macro.rb
|
153
154
|
- lib/globalize/active_record/adapter.rb
|
154
155
|
- lib/globalize/active_record/attributes.rb
|
@@ -166,45 +167,35 @@ files:
|
|
166
167
|
- lib/i18n/missing_translations_log_handler.rb
|
167
168
|
- lib/i18n/missing_translations_raise_handler.rb
|
168
169
|
- lib/patches/active_record/query_method.rb
|
170
|
+
- lib/patches/active_record/uniqueness_validator.rb
|
169
171
|
- lib/patches/active_record/xml_attribute_serializer.rb
|
170
172
|
- Gemfile
|
171
173
|
- Gemfile.lock
|
172
174
|
- LICENSE
|
173
175
|
- Rakefile
|
174
|
-
- README.textile
|
175
176
|
homepage: http://github.com/svenfuchs/globalize3
|
176
177
|
licenses: []
|
177
|
-
|
178
178
|
post_install_message:
|
179
179
|
rdoc_options: []
|
180
|
-
|
181
|
-
require_paths:
|
180
|
+
require_paths:
|
182
181
|
- lib
|
183
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
182
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
183
|
+
requirements:
|
184
|
+
- - ! '>='
|
185
|
+
- !ruby/object:Gem::Version
|
186
|
+
version: '0'
|
184
187
|
none: false
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
- 0
|
191
|
-
version: "0"
|
192
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
188
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
189
|
+
requirements:
|
190
|
+
- - ! '>='
|
191
|
+
- !ruby/object:Gem::Version
|
192
|
+
version: '0'
|
193
193
|
none: false
|
194
|
-
requirements:
|
195
|
-
- - ">="
|
196
|
-
- !ruby/object:Gem::Version
|
197
|
-
hash: 3
|
198
|
-
segments:
|
199
|
-
- 0
|
200
|
-
version: "0"
|
201
194
|
requirements: []
|
202
|
-
|
203
|
-
|
204
|
-
rubygems_version: 1.8.17
|
195
|
+
rubyforge_project: ! '[none]'
|
196
|
+
rubygems_version: 1.8.24
|
205
197
|
signing_key:
|
206
198
|
specification_version: 3
|
207
|
-
summary:
|
199
|
+
summary: Rails I18n de-facto standard library for ActiveRecord 3 model/data translation
|
208
200
|
test_files: []
|
209
|
-
|
210
201
|
has_rdoc:
|
data/README.textile
DELETED
@@ -1,205 +0,0 @@
|
|
1
|
-
h1. Globalize3
|
2
|
-
|
3
|
-
Globalize3 is the successor of Globalize for Rails. Globalize is targeted at ActiveRecord 3. It is compatible with and builds on the new "I18n API in Ruby on Rails":http://guides.rubyonrails.org/i18n.html and adds model translations to ActiveRecord.
|
4
|
-
|
5
|
-
Globalize3 is much more lightweight and compatible than its predecessor Globalize for Rails was. Model translations in Globalize3 use default ActiveRecord features and do not limit any ActiveRecord functionality any more.
|
6
|
-
|
7
|
-
h2. Requirements
|
8
|
-
|
9
|
-
ActiveRecord > 3.0.0
|
10
|
-
I18n
|
11
|
-
|
12
|
-
h2. Installation
|
13
|
-
|
14
|
-
To install Globalize3 with its default setup just use:
|
15
|
-
|
16
|
-
<pre><code>
|
17
|
-
$ gem install globalize3
|
18
|
-
</code></pre>
|
19
|
-
|
20
|
-
h2. Model translations
|
21
|
-
|
22
|
-
Model translations allow you to translate your models' attribute values. E.g.
|
23
|
-
|
24
|
-
<pre><code>
|
25
|
-
class Post < ActiveRecord::Base
|
26
|
-
translates :title, :text
|
27
|
-
end
|
28
|
-
</code></pre>
|
29
|
-
|
30
|
-
Allows you to translate the attributes :title and :text per locale:
|
31
|
-
|
32
|
-
<pre><code>
|
33
|
-
I18n.locale = :en
|
34
|
-
post.title # => Globalize3 rocks!
|
35
|
-
|
36
|
-
I18n.locale = :he
|
37
|
-
post.title # => גלובאלייז2 שולט!
|
38
|
-
</code></pre>
|
39
|
-
|
40
|
-
In order to make this work, you'll need to add the appropriate translation tables. Globalize3 comes with a handy helper method to help you do this. It's called @create_translation_table!@. Here's an example:
|
41
|
-
|
42
|
-
<em>Note that if you're using rails ~> 3.1.0.rc migrations has only the <tt>change</tt> instance method</em>
|
43
|
-
|
44
|
-
h3. Rails 3.0
|
45
|
-
|
46
|
-
<pre><code>
|
47
|
-
class CreatePosts < ActiveRecord::Migration
|
48
|
-
def self.up
|
49
|
-
create_table :posts do |t|
|
50
|
-
t.timestamps
|
51
|
-
end
|
52
|
-
Post.create_translation_table! :title => :string, :text => :text
|
53
|
-
end
|
54
|
-
def self.down
|
55
|
-
drop_table :posts
|
56
|
-
Post.drop_translation_table!
|
57
|
-
end
|
58
|
-
end
|
59
|
-
</code></pre>
|
60
|
-
|
61
|
-
h3. Rails ~> 3.1.0.rc
|
62
|
-
|
63
|
-
<em>Do not use the change method</em>
|
64
|
-
|
65
|
-
<pre><code>
|
66
|
-
class CreatePosts < ActiveRecord::Migration
|
67
|
-
def up
|
68
|
-
create_table :posts do |t|
|
69
|
-
t.timestamps
|
70
|
-
end
|
71
|
-
Post.create_translation_table! :title => :string, :text => :text
|
72
|
-
end
|
73
|
-
def down
|
74
|
-
drop_table :posts
|
75
|
-
Post.drop_translation_table!
|
76
|
-
end
|
77
|
-
end
|
78
|
-
</code></pre>
|
79
|
-
|
80
|
-
Note that the ActiveRecord model @Post@ must already exist and have a @translates@ directive listing the translated fields.
|
81
|
-
|
82
|
-
h2. Migrating existing data to and from the translated version
|
83
|
-
|
84
|
-
As well as creating a translation table, you can also use @create_translation_table!@ to migrate across any
|
85
|
-
existing data to the default locale. This can also operate in reverse to restore any translations from the default locale
|
86
|
-
back to the model when you don't want to use a translation table anymore using @drop_translation_table!@
|
87
|
-
|
88
|
-
This feature makes use of @untranslated_attributes@ which allows access to the model's attributes as they were before
|
89
|
-
the translation was applied. Here's an example (which assumes you already have a model called @Post@ and its table exists):
|
90
|
-
|
91
|
-
<pre><code>
|
92
|
-
class TranslatePosts < ActiveRecord::Migration
|
93
|
-
def self.up
|
94
|
-
Post.create_translation_table!({
|
95
|
-
:title => :string,
|
96
|
-
:text => :text
|
97
|
-
}, {
|
98
|
-
:migrate_data => true
|
99
|
-
})
|
100
|
-
end
|
101
|
-
def self.down
|
102
|
-
Post.drop_translation_table! :migrate_data => true
|
103
|
-
end
|
104
|
-
end
|
105
|
-
</code></pre>
|
106
|
-
|
107
|
-
h2. Versioning with Globalize3
|
108
|
-
|
109
|
-
Globalize3 nicely integrates with
|
110
|
-
"paper_trail":https://github.com/airblade/paper_trail. To add versioning
|
111
|
-
support to your model, you'll want to add the <code>:versioning => true</code>
|
112
|
-
option to your call to <code>translates</code>. An example from our test suite:
|
113
|
-
|
114
|
-
<pre><code>
|
115
|
-
translates :title, :content, :published, :published_at, :versioning => true
|
116
|
-
</code></pre>
|
117
|
-
|
118
|
-
You will also need to have already generated the versions table that paper_trail
|
119
|
-
expects. See the paper_trail README for more details.
|
120
|
-
|
121
|
-
Also, please see the tests in test/globalize3/versioning_test.rb for some current gotchas.
|
122
|
-
|
123
|
-
h2. I18n fallbacks for empty translations
|
124
|
-
|
125
|
-
It is possible to enable fallbacks for empty translations. It will depend on the configuration setting you have set for I18n translations in your Rails config.
|
126
|
-
|
127
|
-
You can enable them by adding the next line to @config/application.rb@ (or only @config/environments/production.rb@ if you only want them in production)
|
128
|
-
|
129
|
-
<pre><code>config.i18n.fallbacks = true</code></pre>
|
130
|
-
|
131
|
-
By default, globalize3 will only use fallbacks when your translation model does not exist or the translation value for the item you've requested is @nil@. However it is possible to also use fallbacks for @blank@ translations by adding @:fallbacks_for_empty_translations => true@ to the @translates@ method.
|
132
|
-
|
133
|
-
<pre><code>
|
134
|
-
class Post < ActiveRecord::Base
|
135
|
-
translates :title, :name
|
136
|
-
end
|
137
|
-
|
138
|
-
puts post.translations.inspect
|
139
|
-
# => [#<Post::Translation id: 1, post_id: 1, locale: "en", title: "Globalize3 rocks!", name: "Globalize3">, #<Post::Translation id: 2, post_id: 1, locale: "nl", title: '', name: nil>]
|
140
|
-
|
141
|
-
I18n.locale = :en
|
142
|
-
post.title # => 'Globalize3 rocks!'
|
143
|
-
post.name # => 'Globalize3'
|
144
|
-
|
145
|
-
I18n.locale = :nl
|
146
|
-
post.title # => ''
|
147
|
-
post.name # => 'Globalize3'
|
148
|
-
</code></pre>
|
149
|
-
<pre><code>
|
150
|
-
class Post < ActiveRecord::Base
|
151
|
-
translates :title, :name, :fallbacks_for_empty_translations => true
|
152
|
-
end
|
153
|
-
|
154
|
-
puts post.translations.inspect
|
155
|
-
# => [#<Post::Translation id: 1, post_id: 1, locale: "en", title: "Globalize3 rocks!", name: "Globalize3">, #<Post::Translation id: 2, post_id: 1, locale: "nl", title: '', name: nil>]
|
156
|
-
|
157
|
-
I18n.locale = :en
|
158
|
-
post.title # => 'Globalize3 rocks!'
|
159
|
-
post.name # => 'Globalize3'
|
160
|
-
|
161
|
-
I18n.locale = :nl
|
162
|
-
post.title # => 'Globalize3 rocks!'
|
163
|
-
post.name # => 'Globalize3'
|
164
|
-
</code></pre>
|
165
|
-
|
166
|
-
|
167
|
-
h2. Scoping objects by those with translations
|
168
|
-
|
169
|
-
To only return objects that have a translation for the given locale we can use the `with_translations` scope. This will only return records that have a translations for the passed in locale.
|
170
|
-
|
171
|
-
<pre><code>
|
172
|
-
|
173
|
-
Post.with_translations('en') # => [#<Post::Translation id: 1, post_id: 1, locale: "en", title: "Globalize3 rocks!", name: "Globalize3">, #<Post::Translation id: 2, post_id: 1, locale: "nl", title: '', name: nil>]
|
174
|
-
|
175
|
-
Post.with_translations(I18n.locale) # => [#<Post::Translation id: 1, post_id: 1, locale: "en", title: "Globalize3 rocks!", name: "Globalize3">, #<Post::Translation id: 2, post_id: 1, locale: "nl", title: '', name: nil>]
|
176
|
-
|
177
|
-
Post.with_translations('de') # => []
|
178
|
-
|
179
|
-
</code></pre>
|
180
|
-
|
181
|
-
h2. Changes since Globalize2
|
182
|
-
|
183
|
-
* `translation_table_name` was renamed to `translations_table_name`
|
184
|
-
* `available_locales` has been removed. please use `translated_locales`
|
185
|
-
|
186
|
-
h2. Migration from Globalize for Rails (version 1)
|
187
|
-
|
188
|
-
See this script by Tomasz Stachewicz: http://gist.github.com/120867
|
189
|
-
|
190
|
-
h2. Alternative Solutions
|
191
|
-
|
192
|
-
* "Veger's fork":http://github.com/veger/globalize2 - uses default AR schema for the default locale, delegates to the translations table for other locales only
|
193
|
-
* "TranslatableColumns":http://github.com/iain/translatable_columns - have multiple languages of the same attribute in a model (Iain Hecker)
|
194
|
-
* "localized_record":http://github.com/glennpow/localized_record - allows records to have localized attributes without any modifications to the database (Glenn Powell)
|
195
|
-
* "model_translations":http://github.com/janne/model_translations - Minimal implementation of Globalize2 style model translations (Jan Andersson)
|
196
|
-
|
197
|
-
h2. Related solutions
|
198
|
-
|
199
|
-
* "globalize2_versioning":http://github.com/joshmh/globalize2_versioning - acts_as_versioned style versioning for globalize2 (Joshua Harvey)
|
200
|
-
* "i18n_multi_locales_validations":http://github.com/ZenCocoon/i18n_multi_locales_validations - multi-locales attributes validations to validates attributes from globalize2 translations models (Sébastien Grosjean)
|
201
|
-
* "globalize2 Demo App":http://github.com/svenfuchs/globalize2-demo - demo application for globalize2 (Sven Fuchs)</li>
|
202
|
-
* "migrate_from_globalize1":http://gist.github.com/120867 - migrate model translations from Globalize1 to globalize2 (Tomasz Stachewicz)</li>
|
203
|
-
* "easy_globalize2_accessors":http://github.com/astropanic/easy_globalize2_accessors - easily access (read and write) globalize2-translated fields (astropanic, Tomasz Stachewicz)</li>
|
204
|
-
* "globalize2-easy-translate":http://github.com/bsamman/globalize2-easy-translate - adds methods to easily access or set translated attributes to your model (bsamman)</li>
|
205
|
-
* "batch_translations":http://github.com/alvarezrilla/batch_translations - allow saving multiple globalize2 translations in the same request (Jose Alvarez Rilla)</li>
|