lolita-translation 0.3.3 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. data/.gitignore +25 -0
  2. data/Gemfile +2 -18
  3. data/README.md +1 -2
  4. data/Rakefile +1 -49
  5. data/app/assets/javascripts/lolita/translation/application.js +4 -3
  6. data/app/assets/stylesheets/lolita/translation/application.css +7 -1
  7. data/app/views/components/lolita/translation/_assets.html.haml +4 -0
  8. data/app/views/components/lolita/translation/_language_wrap.html.haml +2 -0
  9. data/app/views/components/lolita/translation/_switch.html.haml +4 -0
  10. data/lib/lolita-translation.rb +40 -33
  11. data/lib/lolita-translation/builder/abstract_builder.rb +103 -0
  12. data/lib/lolita-translation/builder/active_record_builder.rb +106 -0
  13. data/lib/lolita-translation/builder/mongoid_builder.rb +0 -0
  14. data/lib/lolita-translation/configuration.rb +41 -166
  15. data/lib/lolita-translation/errors.rb +15 -0
  16. data/lib/lolita-translation/locale.rb +32 -0
  17. data/lib/lolita-translation/locales.rb +62 -0
  18. data/lib/lolita-translation/lolita/component_hooks.rb +49 -0
  19. data/lib/lolita-translation/lolita/tab_extension.rb +113 -0
  20. data/lib/lolita-translation/migrator.rb +56 -0
  21. data/lib/lolita-translation/migrators/active_record_migrator.rb +93 -0
  22. data/lib/lolita-translation/migrators/mongoid_migrator.rb +81 -0
  23. data/lib/lolita-translation/orm/mixin.rb +57 -0
  24. data/lib/lolita-translation/rails.rb +6 -31
  25. data/lib/lolita-translation/record.rb +220 -0
  26. data/lib/lolita-translation/translated_string.rb +11 -0
  27. data/lib/lolita-translation/translation_class_builder.rb +59 -0
  28. data/lib/lolita-translation/utils.rb +13 -0
  29. data/lib/lolita-translation/version.rb +32 -0
  30. data/lib/tasks/lolita_translation.rake +14 -0
  31. data/lolita-translation.gemspec +24 -71
  32. data/spec/ar_schema.rb +90 -0
  33. data/spec/header.rb +14 -0
  34. data/spec/integrations/active_record_integration_spec.rb +218 -0
  35. data/spec/lolita-translation/builder/abstract_builder_spec.rb +67 -0
  36. data/spec/lolita-translation/builder/active_record_builder_spec.rb +40 -0
  37. data/spec/lolita-translation/configuration_spec.rb +72 -0
  38. data/spec/lolita-translation/locale_spec.rb +25 -0
  39. data/spec/lolita-translation/locales_spec.rb +31 -0
  40. data/spec/lolita-translation/lolita/tab_extension_spec.rb +61 -0
  41. data/spec/lolita-translation/migrator_spec.rb +42 -0
  42. data/spec/lolita-translation/migrators/active_record_migrator_spec.rb +50 -0
  43. data/spec/lolita-translation/orm/mixin_spec.rb +52 -0
  44. data/spec/lolita-translation/record_spec.rb +112 -0
  45. data/spec/lolita-translation/translation_class_builder_spec.rb +62 -0
  46. data/spec/lolita_translation_spec.rb +16 -0
  47. data/spec/rails_helper.rb +6 -0
  48. data/spec/requests/record_language_switch_spec.rb +16 -0
  49. data/spec/requests/record_saving_spec.rb +63 -0
  50. data/spec/spec_helper.rb +38 -90
  51. data/spec/tasks/lolita_translation_spec.rb +32 -0
  52. data/spec/test_app/app/controllers/application_controller.rb +3 -0
  53. data/spec/test_app/app/models/category.rb +6 -0
  54. data/spec/test_app/app/models/post.rb +8 -0
  55. data/spec/test_app/config/application.rb +24 -0
  56. data/spec/test_app/config/boot.rb +11 -0
  57. data/spec/test_app/config/database.yml +3 -0
  58. data/spec/test_app/config/enviroment.rb +5 -0
  59. data/spec/test_app/config/enviroments/development.rb +44 -0
  60. data/spec/test_app/config/initializers/lolita_translation.rb +4 -0
  61. data/spec/test_app/config/initializers/token.rb +7 -0
  62. data/spec/test_app/config/routes.rb +4 -0
  63. data/spec/test_app/db/.gitkeep +0 -0
  64. data/spec/test_app/log/.gitkeep +0 -0
  65. metadata +193 -46
  66. data/.document +0 -5
  67. data/VERSION +0 -1
  68. data/app/views/components/lolita/translation/_assets.html.erb +0 -7
  69. data/app/views/components/lolita/translation/_language_wrap.html.erb +0 -4
  70. data/app/views/components/lolita/translation/_switch.html.erb +0 -8
  71. data/lib/generators/lolita_translation/USAGE +0 -8
  72. data/lib/generators/lolita_translation/has_translations_generator.rb +0 -8
  73. data/lib/lolita-translation/model.rb +0 -100
  74. data/lib/lolita-translation/modules.rb +0 -130
  75. data/lib/lolita-translation/string.rb +0 -19
  76. data/lib/tasks/has_translations_tasks.rake +0 -4
  77. data/spec/has_translations_spec.rb +0 -43
@@ -0,0 +1,11 @@
1
+ class TranslatedString < String
2
+ def initialize(str, translation_record, attribute_name)
3
+ @translation_record = translation_record
4
+ @attribute_name = attribute_name
5
+ super(str)
6
+ end
7
+
8
+ def in(locale)
9
+ @translation_record.translated_attribute(@attribute_name, :locale => locale)
10
+ end
11
+ end
@@ -0,0 +1,59 @@
1
+ require 'lolita-translation/builder/active_record_builder'
2
+ require 'lolita-translation/builder/mongoid_builder'
3
+ require 'lolita-translation/utils'
4
+
5
+ module Lolita
6
+ module Translation
7
+
8
+ # Create ORM class for translations. For Post class it will create PostTranslation class,
9
+ # for News it will create NewsTranslation and so on
10
+ class TranslationClassBuilder
11
+
12
+ attr_reader :klass
13
+
14
+ def initialize(base_class, configuration = nil)
15
+ @klass = base_class
16
+ @configuration = configuration
17
+ detect_builder_class
18
+ end
19
+
20
+ def builder_available?
21
+ !!@builder_class
22
+ end
23
+
24
+ def builder
25
+ @builder ||= @builder_class && @builder_class.new(klass, @configuration)
26
+ end
27
+
28
+ def build_class
29
+ if builder
30
+ builder.build
31
+ builder.klass
32
+ else
33
+ raise Lolita::Translation::NoBuilderForClassError.new(klass)
34
+ end
35
+ end
36
+
37
+ def override_attributes(attributes)
38
+ if builder
39
+ builder.override_klass_attributes(attributes)
40
+ else
41
+ raise Lolita::Translation::NoBuilderForClassError.new(klass)
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def detect_builder_class
48
+ @builder_class ||= if Lolita::Translation::Utils.active_record_class?(klass)
49
+ Lolita::Translation::Builder::ActiveRecordBuilder
50
+ elsif Lolita::Translation::Utils.mongoid_class?(klass)
51
+ Lolita::Translation::Builder::MongoidBuilder
52
+ else
53
+ nil
54
+ end
55
+ end
56
+ end
57
+
58
+ end
59
+ end
@@ -0,0 +1,13 @@
1
+ module Lolita
2
+ module Translation
3
+ module Utils
4
+ def self.mongoid_class?(klass)
5
+ defined?(Mongoid::Document) && klass.ancestors.include?(Mongoid::Document)
6
+ end
7
+
8
+ def self.active_record_class?(klass)
9
+ defined?(ActiveRecord::Base) && klass.ancestors.include?(ActiveRecord::Base)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,32 @@
1
+ module Lolita
2
+ module Translation
3
+ module Version
4
+ MAJOR = 0
5
+ MINOR = 5
6
+ PATCH = 0
7
+ BUILD = nil
8
+
9
+ STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.')
10
+
11
+ def self.to_s
12
+ STRING
13
+ end
14
+
15
+ def self.major
16
+ MAJOR
17
+ end
18
+
19
+ def self.minor
20
+ MINOR
21
+ end
22
+
23
+ def self.patch
24
+ PATCH
25
+ end
26
+
27
+ def self.build
28
+ BUILD
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,14 @@
1
+ require 'lolita-translation'
2
+ require 'rake'
3
+
4
+ namespace :lolita_translation do
5
+ desc "Synca all tables at once"
6
+ task :sync_tables do
7
+ Lolita.mappings.each do |k,mapping|
8
+ klass = mapping.to
9
+ if klass && klass.respond_to?(:sync_translation_table!)
10
+ klass.sync_translation_table!
11
+ end
12
+ end
13
+ end
14
+ end
@@ -1,83 +1,36 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
1
  # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "lolita-translation/version"
5
4
 
6
5
  Gem::Specification.new do |s|
7
- s.name = "lolita-translation"
8
- s.version = "0.3.3"
6
+ s.name = "lolita-translation"
7
+ s.version = Lolita::Translation::Version.to_s
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["ITHouse (Latvia) and Arturs Meisters"]
10
+ s.email = "support@ithouse.lv"
11
+ s.homepage = "http://github.com/ithouse/lolita-translation"
12
+ s.summary = %q{Lolita extension that add multilanguate support to Lolita.}
13
+ s.description = %q{Lolita extension that allow users to change language and translate DB data.}
9
14
 
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["ITHouse", "Gatis Tomsons", "Arturs Meisters"]
12
- s.date = "2011-12-20"
13
- s.description = "Translates models in Lolita"
14
- s.email = "support@ithouse.lv"
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE.txt",
17
17
  "README.md"
18
18
  ]
19
- s.files = [
20
- ".document",
21
- ".rspec",
22
- "Gemfile",
23
- "LICENSE.txt",
24
- "README.md",
25
- "Rakefile",
26
- "VERSION",
27
- "app/assets/.gitkeep",
28
- "app/assets/javascripts/.gitkeep",
29
- "app/assets/javascripts/lolita/translation/application.js",
30
- "app/assets/stylesheets/lolita/translation/application.css",
31
- "app/views/components/lolita/translation/_assets.html.erb",
32
- "app/views/components/lolita/translation/_language_wrap.html.erb",
33
- "app/views/components/lolita/translation/_switch.html.erb",
34
- "config/locales/en.yml",
35
- "config/locales/lv.yml",
36
- "lib/generators/lolita_translation/USAGE",
37
- "lib/generators/lolita_translation/has_translations_generator.rb",
38
- "lib/lolita-translation.rb",
39
- "lib/lolita-translation/configuration.rb",
40
- "lib/lolita-translation/model.rb",
41
- "lib/lolita-translation/modules.rb",
42
- "lib/lolita-translation/rails.rb",
43
- "lib/lolita-translation/string.rb",
44
- "lib/tasks/has_translations_tasks.rake",
45
- "lolita-translation.gemspec",
46
- "spec/has_translations_spec.rb",
47
- "spec/spec_helper.rb"
48
- ]
49
- s.homepage = "http://github.com/ithouse/lolita-translations"
50
19
  s.licenses = ["MIT"]
51
- s.require_paths = ["lib"]
52
- s.rubygems_version = "1.8.10"
53
- s.summary = "Lolita models translation plugin"
54
- s.test_files = [
55
- "spec/has_translations_spec.rb",
56
- "spec/spec_helper.rb"
57
- ]
58
20
 
59
- if s.respond_to? :specification_version then
60
- s.specification_version = 3
21
+ s.add_runtime_dependency(%q<lolita>, ["~> 3.2.0.rc.9"])
61
22
 
62
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
63
- s.add_runtime_dependency(%q<lolita>, [">= 3.2.0.rc.3"])
64
- s.add_development_dependency(%q<shoulda>, [">= 0"])
65
- s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
66
- s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
67
- s.add_development_dependency(%q<rcov>, [">= 0"])
68
- else
69
- s.add_dependency(%q<lolita>, [">= 3.2.0.rc.3"])
70
- s.add_dependency(%q<shoulda>, [">= 0"])
71
- s.add_dependency(%q<bundler>, ["~> 1.0.0"])
72
- s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
73
- s.add_dependency(%q<rcov>, [">= 0"])
74
- end
75
- else
76
- s.add_dependency(%q<lolita>, [">= 3.2.0.rc.3"])
77
- s.add_dependency(%q<shoulda>, [">= 0"])
78
- s.add_dependency(%q<bundler>, ["~> 1.0.0"])
79
- s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
80
- s.add_dependency(%q<rcov>, [">= 0"])
81
- end
82
- end
23
+ s.add_development_dependency(%q<rails>, ["~> 3.2.3"])
24
+ s.add_development_dependency(%q<rspec>, ["~> 2.9.0"])
25
+ s.add_development_dependency(%q<rspec-rails>, ["~> 2.9.0"])
26
+ s.add_development_dependency(%q<ffaker>, ["~> 1"])
27
+ s.add_development_dependency(%q<capybara>, ["~> 1.1.2"])
28
+ s.add_development_dependency(%q<capybara-webkit>, ["~> 0.11.0"])
29
+ s.add_development_dependency(%q<cover_me>, ["~> 1.2.0"])
30
+ s.add_development_dependency(%q<sqlite3>, ["~> 1.3.6"])
31
+ s.add_development_dependency(%q<debugger>,[">0"])
83
32
 
33
+ s.files = `git ls-files`.split("\n")
34
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
35
+ s.require_paths = ["lib"]
36
+ end
data/spec/ar_schema.rb ADDED
@@ -0,0 +1,90 @@
1
+ require 'active_record'
2
+
3
+ # Override connection method, to load schema on demand when there is no tables in, this allow to solve problems
4
+ # when there are different connection between rspec and capybara::session. This does not work well when data is stored
5
+ # in memory, because connection is lost in some way.
6
+ class ActiveRecord::Base
7
+ def self.connection
8
+ temp_c = retrieve_connection
9
+ if temp_c.tables.empty? && !::ARSchema.loading
10
+ ::ARSchema.load_schema
11
+ end
12
+ temp_c
13
+ end
14
+ end
15
+
16
+ # Is used to load schema and clean data from table when there is any.
17
+ # Schema load is called from overrided ActiveRecord::Base.connection method.
18
+ class ARSchema
19
+ cattr_accessor :loading, :connection
20
+ @@loading = false
21
+ @connection = false
22
+
23
+ def self.connect!
24
+ unless ActiveRecord::Base.connected?
25
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
26
+ end
27
+ end
28
+
29
+ def self.clean!
30
+ [:products,:products_translations,:categories,:categories_translations, :posts, :posts_translations].each do |table_name|
31
+ begin
32
+ if ActiveRecord::Base.connection.execute("SELECT count(*) FROM #{table_name}")[0]["count(*)"] > 0
33
+ ActiveRecord::Base.connection.execute("DELETE FROM #{table_name}")
34
+ end
35
+ rescue Exception => e
36
+ puts "Error: #{e}"
37
+ end
38
+ end
39
+ end
40
+
41
+ def self.load_schema
42
+ # Add models
43
+ ActiveRecord::Schema.define do
44
+ ::ARSchema.loading = true
45
+ create_table :products, :force => true do |t|
46
+ t.string :name
47
+ t.text :description
48
+ t.integer :price
49
+ t.integer :category_id
50
+ end
51
+
52
+ create_table :products_translations, :force => true do |t|
53
+ t.string :name
54
+ t.text :description
55
+ t.integer :product_id
56
+ t.string :locale
57
+ end
58
+
59
+ create_table :categories, :force => true do |t|
60
+ t.string :name
61
+ t.string :default_locale
62
+ end
63
+
64
+ create_table :categories_translations, :force => true do |t|
65
+ t.string :name
66
+ t.integer :category_id
67
+ t.string :locale
68
+ end
69
+
70
+ create_table :posts, :force => true do |t|
71
+ t.string :title
72
+ t.string :body
73
+ t.integer :views
74
+ end
75
+
76
+ create_table :posts_translations, :force => true do |t|
77
+ t.string :title
78
+ t.string :body
79
+ t.integer :post_id
80
+ t.string :locale
81
+ end
82
+
83
+ create_table :comments, :force => true do |t|
84
+ t.text :body
85
+ t.string :commenter
86
+ end
87
+ ::ARSchema.loading = false
88
+ end
89
+ end
90
+ end
data/spec/header.rb ADDED
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'cover_me'
4
+
5
+ CoverMe.config do |c|
6
+ # where is your project's root:
7
+ c.project.root = File.expand_path("../lolita-translation") # => "Rails.root" (default)
8
+
9
+ # what files are you interested in coverage for:
10
+ c.file_pattern = [
11
+ /(#{CoverMe.config.project.root}\/app\/.+\.rb)/i,
12
+ /(#{CoverMe.config.project.root}\/lib\/.+\.rb)/i
13
+ ]
14
+ end
@@ -0,0 +1,218 @@
1
+ require 'spec_helper'
2
+ require 'ar_schema'
3
+
4
+ ARSchema.connect!
5
+
6
+ describe "Integration with ActiveRecord" do
7
+ before(:each) do
8
+ ActiveRecord::Base.connection.execute("DELETE FROM categories")
9
+ ActiveRecord::Base.connection.execute("DELETE FROM products")
10
+ end
11
+ context "configuration defination" do
12
+
13
+ before(:each) do
14
+ Object.send(:remove_const, :Product) rescue nil
15
+ klass = Class.new(ActiveRecord::Base)
16
+ Object.const_set(:Product,klass)
17
+ end
18
+
19
+ it "should have class method for translation configuration" do
20
+ Product.class_eval do
21
+ include Lolita::Translation
22
+ end
23
+
24
+ Product.should.respond_to?(:translations)
25
+ Product.should.respond_to?(:translate)
26
+ end
27
+
28
+ it "should create configuration when class is loaded with field names to translate" do
29
+ Product.class_eval do
30
+ include Lolita::Translation
31
+ translate :name, :description
32
+ end
33
+ Product.translations_configuration.should be_kind_of(Lolita::Translation::Configuration)
34
+ end
35
+
36
+ it "should accept block and yield configuration" do
37
+ block_called = false
38
+ Product.class_eval do
39
+ include Lolita::Translation
40
+ translate :name, :description do |conf|
41
+ block_called = true
42
+ end
43
+ end
44
+ block_called.should be_true
45
+ end
46
+ end
47
+
48
+ context "record" do
49
+ let(:category){Category.create(:name => "category_name", :default_locale => "en")}
50
+
51
+ before(:each) do
52
+ Object.send(:remove_const, :Category) rescue nil
53
+ klass = Class.new(ActiveRecord::Base)
54
+ Object.const_set(:Category,klass)
55
+ Category.class_eval do
56
+ include Lolita::Translation
57
+ translate :name
58
+ end
59
+ end
60
+
61
+ it "validation should fail when no location is given, but class accepts translation locale" do
62
+ category = Category.create(:name => Faker::Name.first_name, :default_locale => "")
63
+ category.errors.keys.should include(:default_locale)
64
+ end
65
+
66
+ it "should have default locale" do
67
+ category = Category.create(:name => Faker::Name.first_name, :default_locale => "en")
68
+ I18n.default_locale = :lv
69
+ category.original_locale.should eq("en")
70
+ end
71
+
72
+ it "should have translations" do
73
+ category.translations.should be_empty
74
+ category.update_attributes(:name => "updated",:translations_attributes => [{:name => "translation-lv", :locale => "lv"}])
75
+ category.errors.should be_empty
76
+ category.translations.reload.should have(1).item
77
+ end
78
+
79
+ it "should return translatable attribute in current locale" do
80
+ I18n.default_locale = :lv
81
+ I18n.locale = :lv
82
+ category.name.should eq("category_name")
83
+ I18n.locale = :en
84
+ category.name.should eq("category_name")
85
+ category.update_attributes(:name => "updated",:translations_attributes => [{:name => "translation-lv", :locale => "lv"}])
86
+ I18n.locale = :lv
87
+ category.name.should eq("translation-lv")
88
+ I18n.locale = :ru
89
+ category.name.should eq("updated")
90
+ end
91
+
92
+ it "should switch attribute to different locale" do
93
+ category.name.should eq("category_name")
94
+ category.update_attributes(:translations_attributes => [{:name => "translation-lv", :locale => "lv"}])
95
+ category.name.in(:lv).should eq("translation-lv")
96
+ end
97
+ end
98
+
99
+ context "saving" do
100
+ let(:category){Category.create(:name => "category_name", :default_locale => :en)}
101
+ let(:product){ Product.create(:name => "product_name", :description => "product_description") }
102
+
103
+ before(:each) do
104
+ I18n.locale = :en
105
+ I18n.default_locale = :lv
106
+ Object.send(:remove_const, :Category) rescue nil
107
+ Object.send(:remove_const, :Product) rescue nil
108
+ klass = Class.new(ActiveRecord::Base)
109
+ Object.const_set(:Category,klass)
110
+ product_klass = Class.new(ActiveRecord::Base)
111
+ Object.const_set(:Product,product_klass)
112
+ Category.class_eval do
113
+ include Lolita::Translation
114
+ translate :name
115
+ end
116
+ Product.class_eval do
117
+ include Lolita::Translation
118
+ translate :name, :description
119
+ end
120
+ end
121
+
122
+ it "should create translations for object" do
123
+ new_cat = Category.create({
124
+ :name => "cat_name",
125
+ :original_locale => :en,
126
+ :translations_attributes => [
127
+ {:name => "translation-lv", :locale => "lv"},
128
+ {:name => "translation-fr", :locale => "fr"}
129
+ ]
130
+ })
131
+ new_cat.errors.should be_empty
132
+ new_cat.translations.should have(2).items
133
+ end
134
+
135
+ it "should save translation as nested attributes" do
136
+ category.translations.should be_empty
137
+ category.update_attributes(:translations_attributes => [
138
+ {:name => "translation-lv", :locale => "lv"},
139
+ {:name => "translation-fr", :locale => "fr"}
140
+ ])
141
+ category.translations.reload
142
+ category.translations.should have(2).items
143
+ end
144
+
145
+ it "should save locale for record if it accepts it" do
146
+ I18n.locale = :lv
147
+ category.original_locale.should eq(:en)
148
+ product.original_locale.should eq(:lv)
149
+ end
150
+
151
+ it "should not save translation for record default locale" do
152
+ category.translations.should be_empty
153
+ category.update_attributes(:translations_attributes => [
154
+ { :name => "translation2-lv", :locale => "lv"},
155
+ { :name => "translation2-en", :locale => "en"}
156
+ ])
157
+ category.errors.keys.should include(:"translations.locale")
158
+ end
159
+
160
+ it "translation record should be associated with original record" do
161
+ transl1 = CategoryTranslation.new(:name => "translation-lv", :locale => "lv")
162
+ transl1.category = category
163
+ transl1.save
164
+ transl1.errors.should be_empty
165
+ transl2 = CategoryTranslation.create(:name => "translation-fr", :locale => "fr")
166
+ transl2.update_attributes(:name => "updated-translation-fr")
167
+ transl2.errors.keys.should include(:"category")
168
+ end
169
+
170
+ it "should validate that locale is presented" do
171
+ transl1 = CategoryTranslation.new(:name => "translation-lv")
172
+ transl1.category = category
173
+ transl1.save
174
+ transl1.errors.keys.should eq([:"locale"])
175
+ end
176
+
177
+ it "should validate that locale is unique for each original record" do
178
+ transl1 = category.translations.create(:name => "translation-lv", :locale => "lv")
179
+ transl2 = category.translations.create(:name => "translation-lv", :locale => "lv")
180
+ transl1.errors.should be_empty
181
+ transl2.errors.keys.should eq([:"locale"])
182
+ end
183
+
184
+ it "should use default locale for records without default locale field" do
185
+ product.update_attributes(:translations_attributes => [
186
+ { :name => "product_name-ru", :locale => "ru"}
187
+ ])
188
+ product.name.should eq("product_name")
189
+ I18n.locale = :ru
190
+ product.name.should eq("product_name-ru")
191
+ I18n.locale = :en
192
+ product.name.should eq("product_name")
193
+ end
194
+ end
195
+
196
+ context "migrating" do
197
+ before(:each) do
198
+ Object.send(:remove_const,:Comment) rescue nil
199
+ c_class = Class.new(ActiveRecord::Base)
200
+ Object.const_set(:Comment,c_class)
201
+ c_class.class_eval do
202
+ include Lolita::Translation
203
+ translate :body
204
+ end
205
+ ActiveRecord::Base.connection.execute("DROP TABLE comments_translations") rescue nil
206
+ end
207
+
208
+ after(:each) do
209
+ Object.send(:remove_const,:Comment) rescue nil
210
+ end
211
+
212
+ it "should sync translation table through migrations" do
213
+ ActiveRecord::Base.connection.tables.should_not include("comments_translations")
214
+ Comment.sync_translation_table!
215
+ ActiveRecord::Base.connection.tables.should include("comments_translations")
216
+ end
217
+ end
218
+ end