globalize2 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.
Files changed (47) hide show
  1. data/.gitignore +4 -0
  2. data/LICENSE +21 -0
  3. data/README.textile +202 -0
  4. data/Rakefile +39 -0
  5. data/VERSION +1 -0
  6. data/generators/db_backend.rb +0 -0
  7. data/generators/templates/db_backend_migration.rb +25 -0
  8. data/globalize2.gemspec +100 -0
  9. data/init.rb +8 -0
  10. data/lib/globalize/backend/chain.rb +102 -0
  11. data/lib/globalize/backend/pluralizing.rb +37 -0
  12. data/lib/globalize/backend/static.rb +61 -0
  13. data/lib/globalize/i18n/missing_translations_log_handler.rb +41 -0
  14. data/lib/globalize/i18n/missing_translations_raise_handler.rb +27 -0
  15. data/lib/globalize/load_path.rb +63 -0
  16. data/lib/globalize/locale/fallbacks.rb +63 -0
  17. data/lib/globalize/locale/language_tag.rb +81 -0
  18. data/lib/globalize/model/active_record.rb +56 -0
  19. data/lib/globalize/model/active_record/adapter.rb +100 -0
  20. data/lib/globalize/model/active_record/translated.rb +174 -0
  21. data/lib/globalize/translation.rb +32 -0
  22. data/lib/locale/root.yml +3 -0
  23. data/lib/rails_edge_load_path_patch.rb +40 -0
  24. data/notes.textile +51 -0
  25. data/test/all.rb +2 -0
  26. data/test/backends/chained_test.rb +175 -0
  27. data/test/backends/pluralizing_test.rb +63 -0
  28. data/test/backends/static_test.rb +147 -0
  29. data/test/data/locale/all.yml +2 -0
  30. data/test/data/locale/de-DE.yml +2 -0
  31. data/test/data/locale/en-US.yml +2 -0
  32. data/test/data/locale/en-US/module.yml +2 -0
  33. data/test/data/locale/fi-FI/module.yml +2 -0
  34. data/test/data/locale/root.yml +0 -0
  35. data/test/data/models.rb +40 -0
  36. data/test/data/no_globalize_schema.rb +11 -0
  37. data/test/data/schema.rb +39 -0
  38. data/test/i18n/missing_translations_test.rb +36 -0
  39. data/test/load_path_test.rb +49 -0
  40. data/test/locale/fallbacks_test.rb +154 -0
  41. data/test/locale/language_tag_test.rb +130 -0
  42. data/test/model/active_record/migration_test.rb +123 -0
  43. data/test/model/active_record/sti_translated_test.rb +75 -0
  44. data/test/model/active_record/translated_test.rb +487 -0
  45. data/test/test_helper.rb +36 -0
  46. data/test/translation_test.rb +54 -0
  47. metadata +116 -0
@@ -0,0 +1,130 @@
1
+ require File.join( File.dirname(__FILE__), '..', 'test_helper' )
2
+ require 'globalize/locale/language_tag'
3
+
4
+ include Globalize::Locale
5
+
6
+ class LanguageTagTest < ActiveSupport::TestCase
7
+ test "given a valid tag 'de' returns an LanguageTag from #tag" do
8
+ assert_instance_of LanguageTag, LanguageTag.tag('de')
9
+ end
10
+
11
+ test "given a valid tag 'de' returns an array of subtags" do
12
+ assert_equal ['de', nil, nil, nil, nil, nil, nil], LanguageTag::SimpleParser.match('de')
13
+ end
14
+
15
+ test "given a valid tag 'de-DE' returns an array of subtags" do
16
+ assert_equal ['de', nil, 'DE', nil, nil, nil, nil], LanguageTag::SimpleParser.match('de-DE')
17
+ end
18
+
19
+ test "given a valid lowercase tag 'de-latn-de-variant-x-phonebk' returns an array of subtags" do
20
+ assert_equal ['de', 'latn', 'de', 'variant', nil, 'x-phonebk', nil],
21
+ LanguageTag::SimpleParser.match('de-latn-de-variant-x-phonebk')
22
+ end
23
+
24
+ test "given a valid uppercase tag 'DE-LATN-DE-VARIANT-X-PHONEBK' returns an array of subtags" do
25
+ assert_equal ['DE', 'LATN', 'DE', 'VARIANT', nil, 'X-PHONEBK', nil],
26
+ LanguageTag::SimpleParser.match('DE-LATN-DE-VARIANT-X-PHONEBK')
27
+ end
28
+
29
+ test "given an invalid tag 'a-DE' test returns false" do
30
+ assert !LanguageTag::SimpleParser.match('a-DE')
31
+ end
32
+
33
+ test "given an invalid tag 'de-419-DE' test returns false" do
34
+ assert !LanguageTag::SimpleParser.match('de-419-DE')
35
+ end
36
+ end
37
+
38
+ class DeLatnLanguageTagTest < ActiveSupport::TestCase
39
+ def setup
40
+ subtags = %w(de Latn DE variant a-ext x-phonebk i-klingon)
41
+ @tag = LanguageTag.new *subtags
42
+ end
43
+
44
+ test "returns 'de' as the language subtag in lowercase" do
45
+ assert_equal 'de', @tag.language
46
+ end
47
+
48
+ test "returns 'Latn' as the script subtag in titlecase" do
49
+ assert_equal 'Latn', @tag.script
50
+ end
51
+
52
+ test "returns 'DE' as the region subtag in uppercase" do
53
+ assert_equal 'DE', @tag.region
54
+ end
55
+
56
+ test "returns 'variant' as the variant subtag in lowercase" do
57
+ assert_equal 'variant', @tag.variant
58
+ end
59
+
60
+ test "returns 'a-ext' as the extension subtag" do
61
+ assert_equal 'a-ext', @tag.extension
62
+ end
63
+
64
+ test "returns 'x-phonebk' as the privateuse subtag" do
65
+ assert_equal 'x-phonebk', @tag.privateuse
66
+ end
67
+
68
+ test "returns 'i-klingon' as the grandfathered subtag" do
69
+ assert_equal 'i-klingon', @tag.grandfathered
70
+ end
71
+
72
+ test "returns a formatted tag string from #to_s" do
73
+ assert_equal 'de-Latn-DE-variant-a-ext-x-phonebk-i-klingon', @tag.to_s
74
+ end
75
+
76
+ test "returns an array containing the formatted subtags from #to_a" do
77
+ assert_equal %w(de Latn DE variant a-ext x-phonebk i-klingon), @tag.to_a
78
+ end
79
+ end
80
+
81
+ class InheritanceLanguageTagTest < ActiveSupport::TestCase
82
+ test "returns 'de-Latn-DE-variant-a-ext-x-phonebk' as the parent of 'de-Latn-DE-variant-a-ext-x-phonebk-i-klingon'" do
83
+ tag = LanguageTag.new *%w(de Latn DE variant a-ext x-phonebk i-klingon)
84
+ assert_equal 'de-Latn-DE-variant-a-ext-x-phonebk', tag.parent.to_s
85
+ end
86
+
87
+ test "returns 'de-Latn-DE-variant-a-ext' as the parent of 'de-Latn-DE-variant-a-ext-x-phonebk'" do
88
+ tag = LanguageTag.new *%w(de Latn DE variant a-ext x-phonebk)
89
+ assert_equal 'de-Latn-DE-variant-a-ext', tag.parent.to_s
90
+ end
91
+
92
+ test "returns 'de-Latn-DE-variant' as the parent of 'de-Latn-DE-variant-a-ext'" do
93
+ tag = LanguageTag.new *%w(de Latn DE variant a-ext)
94
+ assert_equal 'de-Latn-DE-variant', tag.parent.to_s
95
+ end
96
+
97
+ test "returns 'de-Latn-DE' as the parent of 'de-Latn-DE-variant'" do
98
+ tag = LanguageTag.new *%w(de Latn DE variant)
99
+ assert_equal 'de-Latn-DE', tag.parent.to_s
100
+ end
101
+
102
+ test "returns 'de-Latn' as the parent of 'de-Latn-DE'" do
103
+ tag = LanguageTag.new *%w(de Latn DE)
104
+ assert_equal 'de-Latn', tag.parent.to_s
105
+ end
106
+
107
+ test "returns 'de' as the parent of 'de-Latn'" do
108
+ tag = LanguageTag.new *%w(de Latn)
109
+ assert_equal 'de', tag.parent.to_s
110
+ end
111
+
112
+ # TODO RFC4647 says: "If no language tag matches the request, the "default" value is returned."
113
+ # where should we set the default language?
114
+ # test "returns '' as the parent of 'de'" do
115
+ # tag = LanguageTag.new *%w(de)
116
+ # assert_equal '', tag.parent.to_s
117
+ # end
118
+
119
+ test "returns an array of 5 parents for 'de-Latn-DE-variant-a-ext-x-phonebk-i-klingon'" do
120
+ parents = %w(de-Latn-DE-variant-a-ext-x-phonebk-i-klingon
121
+ de-Latn-DE-variant-a-ext-x-phonebk
122
+ de-Latn-DE-variant-a-ext
123
+ de-Latn-DE-variant
124
+ de-Latn-DE
125
+ de-Latn
126
+ de)
127
+ tag = LanguageTag.new *%w(de Latn DE variant a-ext x-phonebk i-klingon)
128
+ assert_equal parents, tag.parents.map{|tag| tag.to_s}
129
+ end
130
+ end
@@ -0,0 +1,123 @@
1
+ require File.join( File.dirname(__FILE__), '..', '..', 'test_helper' )
2
+ require 'active_record'
3
+ require 'globalize/model/active_record'
4
+
5
+ # Hook up model translation
6
+ ActiveRecord::Base.send(:include, Globalize::Model::ActiveRecord::Translated)
7
+
8
+ # Load Post model
9
+ require File.join( File.dirname(__FILE__), '..', '..', 'data', 'models' )
10
+
11
+ class MigrationTest < ActiveSupport::TestCase
12
+ def setup
13
+ reset_db! File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'data', 'no_globalize_schema.rb'))
14
+ end
15
+
16
+ test 'globalize table added' do
17
+ assert !Post.connection.table_exists?( :post_translations )
18
+ assert !Post.connection.index_exists?( :post_translations, :post_id )
19
+ Post.create_translation_table! :subject => :string, :content => :text
20
+ assert Post.connection.table_exists?( :post_translations )
21
+ assert Post.connection.index_exists?( :post_translations, :post_id )
22
+ columns = Post.connection.columns( :post_translations )
23
+ assert locale = columns.detect {|c| c.name == 'locale' }
24
+ assert_equal :string, locale.type
25
+ assert subject = columns.detect {|c| c.name == 'subject' }
26
+ assert_equal :string, subject.type
27
+ assert content = columns.detect {|c| c.name == 'content' }
28
+ assert_equal :text, content.type
29
+ assert post_id = columns.detect {|c| c.name == 'post_id' }
30
+ assert_equal :integer, post_id.type
31
+ assert created_at = columns.detect {|c| c.name == 'created_at' }
32
+ assert_equal :datetime, created_at.type
33
+ assert updated_at = columns.detect {|c| c.name == 'updated_at' }
34
+ assert_equal :datetime, updated_at.type
35
+ end
36
+
37
+ test 'globalize table dropped' do
38
+ assert !Post.connection.table_exists?( :post_translations )
39
+ assert !Post.connection.index_exists?( :post_translations, :post_id )
40
+ Post.create_translation_table! :subject => :string, :content => :text
41
+ assert Post.connection.table_exists?( :post_translations )
42
+ assert Post.connection.index_exists?( :post_translations, :post_id )
43
+ Post.drop_translation_table!
44
+ assert !Post.connection.table_exists?( :post_translations )
45
+ assert !Post.connection.index_exists?( :post_translations, :post_id )
46
+ end
47
+
48
+ test 'exception on missing field inputs' do
49
+ assert_raise Globalize::Model::MigrationMissingTranslatedField do
50
+ Post.create_translation_table! :content => :text
51
+ end
52
+ end
53
+
54
+ test 'exception on bad input type' do
55
+ assert_raise Globalize::Model::BadMigrationFieldType do
56
+ Post.create_translation_table! :subject => :string, :content => :integer
57
+ end
58
+ end
59
+
60
+ test "exception on bad input type isn't raised for untranslated fields" do
61
+ assert_nothing_raised do
62
+ Post.create_translation_table! :subject => :string, :content => :string, :views_count => :integer
63
+ end
64
+ end
65
+
66
+ test 'create_translation_table! should not be called on non-translated models' do
67
+ assert_raise NoMethodError do
68
+ Blog.create_translation_table! :name => :string
69
+ end
70
+ end
71
+
72
+ test 'drop_translation_table! should not be called on non-translated models' do
73
+ assert_raise NoMethodError do
74
+ Blog.drop_translation_table!
75
+ end
76
+ end
77
+
78
+ test "translation_index_name returns a readable index name when it's not longer than 50 characters" do
79
+ assert_equal 'index_post_translations_on_post_id', Post.send(:translation_index_name)
80
+ end
81
+
82
+ test "translation_index_name returns a hashed index name when it's longer than 50 characters" do
83
+ class UltraLongModelNameWithoutProper < ActiveRecord::Base
84
+ translates :foo
85
+ end
86
+ name = UltraLongModelNameWithoutProper.send(:translation_index_name)
87
+ assert_match /^index_[a-z0-9]{40}$/, name
88
+ end
89
+
90
+ test 'globalize table added when table has long name' do
91
+ UltraLongModelNameWithoutProper.create_translation_table!(
92
+ :subject => :string, :content => :text
93
+ )
94
+
95
+ assert UltraLongModelNameWithoutProper.connection.table_exists?(
96
+ :ultra_long_model_name_without_proper_translations
97
+ )
98
+ assert UltraLongModelNameWithoutProper.connection.index_exists?(
99
+ :ultra_long_model_name_without_proper_translations,
100
+ :name => UltraLongModelNameWithoutProper.send(
101
+ :translation_index_name
102
+ )
103
+ )
104
+ end
105
+
106
+ test 'globalize table dropped when table has long name' do
107
+ UltraLongModelNameWithoutProper.create_translation_table!(
108
+ :subject => :string, :content => :text
109
+ )
110
+
111
+ UltraLongModelNameWithoutProper.drop_translation_table!
112
+
113
+ assert !UltraLongModelNameWithoutProper.connection.table_exists?(
114
+ :ultra_long_model_name_without_proper_translations
115
+ )
116
+
117
+ assert !UltraLongModelNameWithoutProper.connection.index_exists?(
118
+ :ultra_long_model_name_without_proper_translations,
119
+ :ultra_long_model_name_without_proper_id
120
+ )
121
+ end
122
+
123
+ end
@@ -0,0 +1,75 @@
1
+ require File.join( File.dirname(__FILE__), '..', '..', 'test_helper' )
2
+ require 'active_record'
3
+ require 'globalize/model/active_record'
4
+
5
+ # Hook up model translation
6
+ ActiveRecord::Base.send(:include, Globalize::Model::ActiveRecord::Translated)
7
+
8
+ # Load Post model
9
+ require File.join( File.dirname(__FILE__), '..', '..', 'data', 'models' )
10
+
11
+ class StiTranslatedTest < ActiveSupport::TestCase
12
+ def setup
13
+ I18n.locale = :'en-US'
14
+ I18n.fallbacks.clear
15
+ reset_db! File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'data', 'schema.rb'))
16
+ end
17
+
18
+ def teardown
19
+ I18n.fallbacks.clear
20
+ end
21
+
22
+ test "works with simple dynamic finders" do
23
+ foo = Child.create :content => 'foo'
24
+ Child.create :content => 'bar'
25
+ child = Child.find_by_content('foo')
26
+ assert_equal foo, child
27
+ end
28
+
29
+ test 'change attribute on globalized model' do
30
+ child = Child.create :content => 'foo'
31
+ assert_equal [], child.changed
32
+ child.content = 'bar'
33
+ assert_equal [ 'content' ], child.changed
34
+ child.content = 'baz'
35
+ assert_member 'content', child.changed
36
+ end
37
+
38
+ test 'change attribute on globalized model after locale switching' do
39
+ child = Child.create :content => 'foo'
40
+ assert_equal [], child.changed
41
+ child.content = 'bar'
42
+ I18n.locale = :de
43
+ assert_equal [ 'content' ], child.changed
44
+ end
45
+
46
+ test 'fallbacks with lots of locale switching' do
47
+ I18n.fallbacks.map :'de-DE' => [ :'en-US' ]
48
+ child = Child.create :content => 'foo'
49
+
50
+ I18n.locale = :'de-DE'
51
+ assert_equal 'foo', child.content
52
+
53
+ I18n.locale = :'en-US'
54
+ child.update_attribute :content, 'bar'
55
+
56
+ I18n.locale = :'de-DE'
57
+ assert_equal 'bar', child.content
58
+ end
59
+
60
+ test "saves all locales, even after locale switching" do
61
+ child = Child.new :content => 'foo'
62
+ I18n.locale = 'de-DE'
63
+ child.content = 'bar'
64
+ I18n.locale = 'he-IL'
65
+ child.content = 'baz'
66
+ child.save
67
+ I18n.locale = 'en-US'
68
+ child = Child.first
69
+ assert_equal 'foo', child.content
70
+ I18n.locale = 'de-DE'
71
+ assert_equal 'bar', child.content
72
+ I18n.locale = 'he-IL'
73
+ assert_equal 'baz', child.content
74
+ end
75
+ end
@@ -0,0 +1,487 @@
1
+ require File.join( File.dirname(__FILE__), '..', '..', 'test_helper' )
2
+ require 'active_record'
3
+ require 'globalize/model/active_record'
4
+
5
+ # Hook up model translation
6
+ ActiveRecord::Base.send(:include, Globalize::Model::ActiveRecord::Translated)
7
+
8
+ # Load Post model
9
+ require File.join( File.dirname(__FILE__), '..', '..', 'data', 'models' )
10
+
11
+ class TranslatedTest < ActiveSupport::TestCase
12
+ def setup
13
+ I18n.locale = :'en-US'
14
+ I18n.fallbacks.clear
15
+ reset_db! File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'data', 'schema.rb'))
16
+ ActiveRecord::Base.locale = nil
17
+ end
18
+
19
+ def teardown
20
+ I18n.fallbacks.clear
21
+ end
22
+
23
+ test "modifiying translated fields" do
24
+ post = Post.create :subject => 'foo'
25
+ assert_equal 'foo', post.subject
26
+ post.subject = 'bar'
27
+ assert_equal 'bar', post.subject
28
+ end
29
+
30
+ test "modifiying translated fields while switching locales" do
31
+ post = Post.create :subject => 'foo'
32
+ assert_equal 'foo', post.subject
33
+ I18n.locale = :'de-DE'
34
+ post.subject = 'bar'
35
+ assert_equal 'bar', post.subject
36
+ I18n.locale = :'en-US'
37
+ assert_equal 'foo', post.subject
38
+ I18n.locale = :'de-DE'
39
+ post.subject = 'bar'
40
+ end
41
+
42
+ test "has post_translations" do
43
+ post = Post.create
44
+ assert_nothing_raised { post.globalize_translations }
45
+ end
46
+
47
+ test "has German post_translations" do
48
+ I18n.locale = :de
49
+ post = Post.create :subject => 'foo'
50
+ assert_equal 1, post.globalize_translations.size
51
+ I18n.locale = :en
52
+ assert_equal 1, post.globalize_translations.size
53
+ end
54
+
55
+ test "returns the value passed to :subject" do
56
+ post = Post.new
57
+ assert_equal 'foo', (post.subject = 'foo')
58
+ end
59
+
60
+ test "translates subject and content into en-US" do
61
+ post = Post.create :subject => 'foo', :content => 'bar'
62
+ assert_equal 'foo', post.subject
63
+ assert_equal 'bar', post.content
64
+ assert post.save
65
+ post.reload
66
+ assert_equal 'foo', post.subject
67
+ assert_equal 'bar', post.content
68
+ end
69
+
70
+ test "finds a German post" do
71
+ post = Post.create :subject => 'foo (en)', :content => 'bar'
72
+ I18n.locale = 'de-DE'
73
+ post = Post.first
74
+ post.subject = 'baz (de)'
75
+ post.save
76
+ assert_equal 'baz (de)', Post.first.subject
77
+ I18n.locale = :'en-US'
78
+ assert_equal 'foo (en)', Post.first.subject
79
+ end
80
+
81
+ test "saves an English post and loads test correctly" do
82
+ assert_nil Post.first
83
+ post = Post.create :subject => 'foo', :content => 'bar'
84
+ assert post.save
85
+ post = Post.first
86
+ assert_equal 'foo', post.subject
87
+ assert_equal 'bar', post.content
88
+ end
89
+
90
+ test "updates an attribute" do
91
+ post = Post.create :subject => 'foo', :content => 'bar'
92
+ post.update_attribute :subject, 'baz'
93
+ assert_equal 'baz', Post.first.subject
94
+ end
95
+
96
+ test "update_attributes failure" do
97
+ post = Post.create :subject => 'foo', :content => 'bar'
98
+ assert !post.update_attributes( { :subject => '' } )
99
+ assert_nil post.reload.attributes['subject']
100
+ assert_equal 'foo', post.subject
101
+ end
102
+
103
+ test "validates presence of :subject" do
104
+ post = Post.new
105
+ assert !post.save
106
+
107
+ post = Post.new :subject => 'foo'
108
+ assert post.save
109
+ end
110
+
111
+ test "returns the value for the correct locale, after locale switching" do
112
+ post = Post.create :subject => 'foo'
113
+ I18n.locale = 'de-DE'
114
+ post.subject = 'bar'
115
+ post.save
116
+ I18n.locale = 'en-US'
117
+ post = Post.first
118
+ assert_equal 'foo', post.subject
119
+ I18n.locale = 'de-DE'
120
+ assert_equal 'bar', post.subject
121
+ end
122
+
123
+ test "keeping one field in new locale when other field is changed" do
124
+ I18n.fallbacks.map 'de-DE' => [ 'en-US' ]
125
+ post = Post.create :subject => 'foo'
126
+ I18n.locale = 'de-DE'
127
+ post.content = 'bar'
128
+ assert_equal 'foo', post.subject
129
+ end
130
+
131
+ test "modifying non-required field in a new locale" do
132
+ I18n.fallbacks.map 'de-DE' => [ 'en-US' ]
133
+ post = Post.create :subject => 'foo'
134
+ I18n.locale = 'de-DE'
135
+ post.content = 'bar'
136
+ assert post.save
137
+ end
138
+
139
+ test "returns the value for the correct locale, after locale switching, without saving" do
140
+ post = Post.create :subject => 'foo'
141
+ I18n.locale = 'de-DE'
142
+ post.subject = 'bar'
143
+ I18n.locale = 'en-US'
144
+ assert_equal 'foo', post.subject
145
+ I18n.locale = 'de-DE'
146
+ assert_equal 'bar', post.subject
147
+ end
148
+
149
+ test "saves all locales, even after locale switching" do
150
+ post = Post.new :subject => 'foo'
151
+ I18n.locale = 'de-DE'
152
+ post.subject = 'bar'
153
+ I18n.locale = 'he-IL'
154
+ post.subject = 'baz'
155
+ post.save
156
+ I18n.locale = 'en-US'
157
+ post = Post.first
158
+ assert_equal 'foo', post.subject
159
+ I18n.locale = 'de-DE'
160
+ assert_equal 'bar', post.subject
161
+ I18n.locale = 'he-IL'
162
+ assert_equal 'baz', post.subject
163
+ end
164
+
165
+ test "resolves a simple fallback" do
166
+ I18n.locale = 'de-DE'
167
+ post = Post.create :subject => 'foo'
168
+ I18n.locale = 'de'
169
+ post.subject = 'baz'
170
+ post.content = 'bar'
171
+ post.save
172
+ I18n.locale = 'de-DE'
173
+ assert_equal 'foo', post.subject
174
+ assert_equal 'bar', post.content
175
+ end
176
+
177
+ test "resolves a simple fallback without reloading" do
178
+ I18n.locale = 'de-DE'
179
+ post = Post.new :subject => 'foo'
180
+ I18n.locale = 'de'
181
+ post.subject = 'baz'
182
+ post.content = 'bar'
183
+ I18n.locale = 'de-DE'
184
+ assert_equal 'foo', post.subject
185
+ assert_equal 'bar', post.content
186
+ end
187
+
188
+ test "resolves a complex fallback without reloading" do
189
+ I18n.fallbacks.map 'de' => %w(en he)
190
+ I18n.locale = 'de'
191
+ post = Post.new
192
+ I18n.locale = 'en'
193
+ post.subject = 'foo'
194
+ I18n.locale = 'he'
195
+ post.subject = 'baz'
196
+ post.content = 'bar'
197
+ I18n.locale = 'de'
198
+ assert_equal 'foo', post.subject
199
+ assert_equal 'bar', post.content
200
+ end
201
+
202
+ test "returns nil if no translations are found" do
203
+ post = Post.new :subject => 'foo'
204
+ assert_equal 'foo', post.subject
205
+ assert_nil post.content
206
+ end
207
+
208
+ test "returns nil if no translations are found; reloaded" do
209
+ post = Post.create :subject => 'foo'
210
+ post = Post.first
211
+ assert_equal 'foo', post.subject
212
+ assert_nil post.content
213
+ end
214
+
215
+ test "works with associations" do
216
+ blog = Blog.create
217
+ post1 = blog.posts.create :subject => 'foo'
218
+ I18n.locale = 'de-DE'
219
+ post2 = blog.posts.create :subject => 'bar'
220
+ assert_equal 2, blog.posts.size
221
+ I18n.locale = 'en-US'
222
+ assert_equal 'foo', blog.posts.first.subject
223
+ assert_nil blog.posts.last.subject
224
+ I18n.locale = 'de-DE'
225
+ assert_equal 'bar', blog.posts.last.subject
226
+ end
227
+
228
+ test "works with simple dynamic finders" do
229
+ foo = Post.create :subject => 'foo'
230
+ Post.create :subject => 'bar'
231
+ post = Post.find_by_subject('foo')
232
+ assert_equal foo, post
233
+ end
234
+
235
+ test 'change attribute on globalized model' do
236
+ post = Post.create :subject => 'foo', :content => 'bar'
237
+ assert_equal [], post.changed
238
+ post.subject = 'baz'
239
+ assert_equal [ 'subject' ], post.changed
240
+ post.content = 'quux'
241
+ assert_member 'subject', post.changed
242
+ assert_member 'content', post.changed
243
+ end
244
+
245
+ test 'change attribute on globalized model after locale switching' do
246
+ post = Post.create :subject => 'foo', :content => 'bar'
247
+ assert_equal [], post.changed
248
+ post.subject = 'baz'
249
+ I18n.locale = :de
250
+ assert_equal [ 'subject' ], post.changed
251
+ end
252
+
253
+ test 'fallbacks with lots of locale switching' do
254
+ I18n.fallbacks.map :'de-DE' => [ :'en-US' ]
255
+ post = Post.create :subject => 'foo'
256
+
257
+ I18n.locale = :'de-DE'
258
+ assert_equal 'foo', post.subject
259
+
260
+ I18n.locale = :'en-US'
261
+ post.update_attribute :subject, 'bar'
262
+
263
+ I18n.locale = :'de-DE'
264
+ assert_equal 'bar', post.subject
265
+ end
266
+
267
+ test 'reload' do
268
+ post = Post.create :subject => 'foo', :content => 'bar'
269
+ post.subject = 'baz'
270
+ assert_equal 'foo', post.reload.subject
271
+ end
272
+
273
+ test 'complex writing and stashing' do
274
+ post = Post.create :subject => 'foo', :content => 'bar'
275
+ post.subject = nil
276
+ assert_nil post.subject
277
+ assert !post.valid?
278
+ end
279
+
280
+ test 'translated class locale setting' do
281
+ assert ActiveRecord::Base.respond_to?(:locale)
282
+ assert_equal :'en-US', I18n.locale
283
+ assert_equal :'en-US', ActiveRecord::Base.locale
284
+ I18n.locale = :de
285
+ assert_equal :de, I18n.locale
286
+ assert_equal :de, ActiveRecord::Base.locale
287
+ ActiveRecord::Base.locale = :es
288
+ assert_equal :de, I18n.locale
289
+ assert_equal :es, ActiveRecord::Base.locale
290
+ I18n.locale = :fr
291
+ assert_equal :fr, I18n.locale
292
+ assert_equal :es, ActiveRecord::Base.locale
293
+ end
294
+
295
+ test "untranslated class responds to locale" do
296
+ assert Blog.respond_to?(:locale)
297
+ end
298
+
299
+ test "to ensure locales in different classes are the same" do
300
+ ActiveRecord::Base.locale = :de
301
+ assert_equal :de, ActiveRecord::Base.locale
302
+ assert_equal :de, Parent.locale
303
+ Parent.locale = :es
304
+ assert_equal :es, ActiveRecord::Base.locale
305
+ assert_equal :es, Parent.locale
306
+ end
307
+
308
+ test "attribute saving goes by content locale and not global locale" do
309
+ ActiveRecord::Base.locale = :de
310
+ assert_equal :'en-US', I18n.locale
311
+ Post.create :subject => 'foo'
312
+ assert_equal :de, Post.first.globalize_translations.first.locale
313
+ end
314
+
315
+ test "attribute loading goes by content locale and not global locale" do
316
+ post = Post.create :subject => 'foo'
317
+ assert_equal :'en-US', ActiveRecord::Base.locale
318
+ ActiveRecord::Base.locale = :de
319
+ assert_equal :'en-US', I18n.locale
320
+ post.update_attribute :subject, 'foo [de]'
321
+ assert_equal 'foo [de]', Post.first.subject
322
+ ActiveRecord::Base.locale = :'en-US'
323
+ assert_equal 'foo', Post.first.subject
324
+ end
325
+
326
+ test "access content locale before setting" do
327
+ Globalize::Model::ActiveRecord::Translated::ActMethods.class_eval "remove_class_variable(:@@locale)"
328
+ assert_nothing_raised { ActiveRecord::Base.locale }
329
+ end
330
+
331
+ test "translated_locales" do
332
+ Post.locale = :de
333
+ post = Post.create :subject => 'foo'
334
+ Post.locale = :es
335
+ post.update_attribute :subject, 'bar'
336
+ Post.locale = :fr
337
+ post.update_attribute :subject, 'baz'
338
+ assert_equal [ :de, :es, :fr ], post.translated_locales
339
+ assert_equal [ :de, :es, :fr ], Post.first.translated_locales
340
+ end
341
+
342
+ test "saving record correctly after post-save reload" do
343
+ reloader = Reloader.create :content => 'foo'
344
+ assert_equal 'foo', reloader.content
345
+ end
346
+
347
+ test "including globalize_translations" do
348
+ I18n.locale = :de
349
+ Post.create :subject => "Foo1", :content => "Bar1"
350
+ Post.create :subject => "Foo2", :content => "Bar2"
351
+
352
+ class << Post
353
+ def tranlsations_included
354
+ self.all(:include => :globalize_translations)
355
+ end
356
+ end
357
+
358
+ default = Post.all.map {|x| [x.subject, x.content]}
359
+ with_include = Post.tranlsations_included.map {|x| [x.subject, x.content]}
360
+ assert_equal default, with_include
361
+ end
362
+
363
+ test "setting multiple translations at once with options hash" do
364
+ Post.locale = :de
365
+ post = Post.create :subject => "foo1", :content => "foo1"
366
+ Post.locale = :en
367
+ post.update_attributes( :subject => "bar1", :content => "bar1" )
368
+
369
+ options = { :de => {:subject => "foo2", :content => "foo2"},
370
+ :en => {:subject => "bar2", :content => "bar2"} }
371
+ post.set_translations options
372
+ post.reload
373
+
374
+ assert ["bar2", "bar2"], [post.subject, post.content]
375
+ Post.locale = :de
376
+ assert ["foo2", "foo2"], [post.subject, post.content]
377
+ end
378
+
379
+ test "setting only one translation with set_translations" do
380
+ Post.locale = :de
381
+ post = Post.create :subject => "foo1", :content => "foo1"
382
+ Post.locale = :en
383
+ post.update_attributes( :subject => "bar1", :content => "bar1" )
384
+
385
+ options = { :en => {:subject => "bar2", :content => "bar2"} }
386
+ post.set_translations options
387
+ post.reload
388
+
389
+ assert ["bar2", "bar2"], [post.subject, post.content]
390
+ Post.locale = :de
391
+ assert ["foo1", "foo1"], [post.subject, post.content]
392
+ end
393
+
394
+ test "setting only selected attributes with set_translations" do
395
+ Post.locale = :de
396
+ post = Post.create :subject => "foo1", :content => "foo1"
397
+ Post.locale = :en
398
+ post.update_attributes( :subject => "bar1", :content => "bar1" )
399
+
400
+ options = { :de => {:content => "foo2"}, :en => {:subject => "bar2"} }
401
+ post.set_translations options
402
+ post.reload
403
+
404
+ assert ["bar2", "bar1"], [post.subject, post.content]
405
+ Post.locale = :de
406
+ assert ["foo1", "foo2"], [post.subject, post.content]
407
+ end
408
+
409
+ test "setting invalid attributes raises ArgumentError" do
410
+ Post.locale = :de
411
+ post = Post.create :subject => "foo1", :content => "foo1"
412
+ Post.locale = :en
413
+ post.update_attributes( :subject => "bar1", :content => "bar1" )
414
+
415
+ options = { :de => {:fake => "foo2"} }
416
+ exception = assert_raise(ActiveRecord::UnknownAttributeError) do
417
+ post.set_translations options
418
+ end
419
+ assert_equal "unknown attribute: fake", exception.message
420
+ end
421
+
422
+ test "reload accepting find options" do
423
+ p = Post.create :subject => "Foo", :content => "Bar"
424
+ assert p.reload(:readonly => true, :lock => true)
425
+ assert_raise(ArgumentError) { p.reload(:foo => :bar) }
426
+ end
427
+
428
+ test "dependent destroy of translation" do
429
+ p = Post.create :subject => "Foo", :content => "Bar"
430
+ assert_equal 1, PostTranslation.count
431
+ p.destroy
432
+ assert_equal 0, PostTranslation.count
433
+ end
434
+
435
+ test "translating subclass of untranslated comment model" do
436
+ translated_comment = TranslatedComment.create(:post => @post)
437
+ assert_nothing_raised { translated_comment.globalize_translations }
438
+ end
439
+
440
+ test "modifiying translated comments works as expected" do
441
+ I18n.locale = :en
442
+ translated_comment = TranslatedComment.create(:post => @post, :content => 'foo')
443
+ assert_equal 'foo', translated_comment.content
444
+
445
+ I18n.locale = :de
446
+ translated_comment.content = 'bar'
447
+ assert translated_comment.save
448
+ assert_equal 'bar', translated_comment.content
449
+
450
+ I18n.locale = :en
451
+ assert_equal 'foo', translated_comment.content
452
+
453
+ assert_equal 2, translated_comment.globalize_translations.size
454
+ end
455
+
456
+ test "can create a proxy class for a namespaced model" do
457
+ module Foo
458
+ module Bar
459
+ class Baz < ActiveRecord::Base
460
+ translates :bumm
461
+ end
462
+ end
463
+ end
464
+ end
465
+
466
+ test "attribute translated before type cast" do
467
+ Post.locale = :en
468
+ post = Post.create :subject => 'foo', :content => 'bar'
469
+ Post.locale = :de
470
+ post.update_attribute :subject, "German foo"
471
+ assert_equal 'German foo', post.subject_before_type_cast
472
+ Post.locale = :en
473
+ assert_equal 'foo', post.subject_before_type_cast
474
+ end
475
+
476
+ test "don't override existing translation model" do
477
+ assert PostTranslation.new.respond_to?(:existing_method)
478
+ end
479
+ end
480
+
481
+ # TODO should validate_presence_of take fallbacks into account? maybe we need
482
+ # an extra validation call, or more options for validate_presence_of.
483
+ # TODO error checking for fields that exist in main table, don't exist in
484
+ # proxy table, aren't strings or text
485
+ #
486
+ # TODO allow finding by translated attributes in conditions?
487
+ # TODO generate advanced dynamic finders?