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,112 @@
1
+ require 'header'
2
+ require File.expand_path("lib/lolita-translation/record")
3
+
4
+ describe Lolita::Translation::Record do
5
+ let(:klass) { Lolita::Translation::Record }
6
+
7
+ describe Lolita::Translation::Record::AbstractRecord do
8
+ let(:abr_klass){ Lolita::Translation::Record::AbstractRecord }
9
+
10
+ it "should have orm_record attributes" do
11
+ some_obj = double("some_obj")
12
+ rec = abr_klass.new(some_obj)
13
+ rec.orm_record.should eq(some_obj)
14
+ end
15
+
16
+ it "should have #locale" do
17
+ rec = abr_klass.new(double)
18
+ rec.locale.should eq(::I18n.locale)
19
+ end
20
+ end
21
+
22
+ describe Lolita::Translation::Record::ARRecord do
23
+ let(:ar_klass){ Lolita::Translation::Record::ARRecord }
24
+ before(:each) do
25
+ ar_klass.any_instance.stub(:locale_field).and_return("default_locale")
26
+ end
27
+
28
+ it "should return default locale from db if there is field defined or system default locale" do
29
+ ar_record = double("ar")
30
+ ar_class = double("AR")
31
+ ar_record.stub(:class).and_return(ar_class)
32
+ ar_class.stub(:column_names).and_return(["name","default_locale"])
33
+ ar_record.stub(:attributes).and_return({"default_locale" => :en})
34
+ rec = ar_klass.new(ar_record)
35
+ rec.locale.should eq(:en)
36
+ end
37
+
38
+ it "should use default locale when there isn't field for that" do
39
+ I18n.default_locale = :lv
40
+ ar_record = double("ar")
41
+ ar_class = double("AR")
42
+ ar_record.stub(:class).and_return(ar_class)
43
+ ar_class.stub(:column_names).and_return(["name"])
44
+ ar_record.stub(:attributes).and_return({"name" => "Name"})
45
+ rec = ar_klass.new(ar_record)
46
+ rec.locale.should eq(:lv)
47
+ end
48
+
49
+ it "should retrun default locale when locale column is blank" do
50
+ I18n.default_locale = :ru
51
+ ar_record = double("ar")
52
+ ar_class = double("AR")
53
+ ar_record.stub(:class).and_return(ar_class)
54
+ ar_class.stub(:column_names).and_return(["name"])
55
+ ar_record.stub(:attributes).and_return({"name" => "Name", "default_locale" => ""})
56
+ rec = ar_klass.new(ar_record)
57
+ rec.locale.should eq(:ru)
58
+ end
59
+ end
60
+
61
+ it "should have original record" do
62
+ some_obj = double
63
+ klass.new(some_obj).original_record.should eq(some_obj)
64
+ end
65
+
66
+ it "should have default locale" do
67
+ some_obj = double
68
+ klass.new(some_obj).default_locale.should eq(::I18n.locale)
69
+ end
70
+
71
+ it "should build nested translations" do
72
+ ::I18n.available_locales = [:lv,:ru]
73
+ I18n.locale = :lv
74
+ rec = double("record")
75
+ rec.stub(:id).and_return(1)
76
+
77
+ translations = double("translations")
78
+ translations.should_receive(:build).with({:locale => "ru"})
79
+ rec.stub(:translations).and_return(translations)
80
+
81
+ obj = klass.new(rec)
82
+ obj.build_nested_translations
83
+ end
84
+
85
+ describe "#in" do
86
+ let(:rec){double("record")}
87
+
88
+ before(:each) do
89
+ ::I18n.available_locales = [:lv,:ru,:en]
90
+ I18n.locale = :lv
91
+ end
92
+
93
+ it "should switch record #defaut_locale to given value" do
94
+ obj = klass.new(rec)
95
+ obj.orm_wrapper.should_receive(:attribute).with(:name)
96
+ obj.attribute(:name)
97
+ obj.in(:ru)
98
+ obj.orm_wrapper.should_receive(:translated_attribute).with(:name, :locale => :ru)
99
+ obj.attribute(:name)
100
+ end
101
+
102
+ it "should switch record locale within block and back after block" do
103
+ obj = klass.new(rec)
104
+ obj.in(:ru) do
105
+ obj.orm_wrapper.should_receive(:translated_attribute).with(:name, :locale => :ru)
106
+ obj.attribute(:name)
107
+ end
108
+ obj.orm_wrapper.should_receive(:attribute).with(:name)
109
+ obj.attribute(:name)
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,62 @@
1
+ require 'header'
2
+ require File.expand_path("lib/lolita-translation/translation_class_builder")
3
+ require File.expand_path("lib/lolita-translation/errors")
4
+ require 'ar_schema'
5
+
6
+ describe Lolita::Translation::TranslationClassBuilder do
7
+ let(:klass){ Lolita::Translation::TranslationClassBuilder }
8
+ let(:some_class){ Class.new }
9
+
10
+ it "should have @klass attribute" do
11
+ klass.new(some_class).klass.should eq(some_class)
12
+ end
13
+
14
+ context "ActiveRecord" do
15
+ let(:ar_klass){ Lolita::Translation::Builder::ActiveRecordBuilder }
16
+
17
+ def stub_create_klass
18
+ ar_klass.any_instance.stub(:create_klass).and_return(true)
19
+ end
20
+
21
+ it "should validate if there are concrete builder availabe" do
22
+ klass.new(some_class).builder_available?.should be_false
23
+ klass.new(Class.new(ActiveRecord::Base)).builder_available?.should be_true
24
+ end
25
+
26
+ it "should have builder when there is builder class available" do
27
+ stub_create_klass
28
+ klass.new(some_class).builder.should be_nil
29
+ klass.new(Class.new(ActiveRecord::Base)).builder.should be_kind_of(Lolita::Translation::Builder::ActiveRecordBuilder)
30
+ end
31
+
32
+ it "should raise error when #build_class is called for unsupported builder" do
33
+ expect{
34
+ obj = klass.new(some_class)
35
+ obj.build_class
36
+ }.to raise_error(Lolita::Translation::NoBuilderForClassError)
37
+ end
38
+
39
+ it "should override attributes to base class" do
40
+ stub_create_klass
41
+ obj = klass.new(Class.new(ActiveRecord::Base))
42
+ obj.builder.should_receive(:override_klass_attributes)
43
+ obj.override_attributes :name
44
+ end
45
+
46
+ it "should raise error when no builder to use for #override_attributes" do
47
+ stub_create_klass
48
+ obj = klass.new(some_class)
49
+ expect{
50
+ obj.override_attributes :name
51
+ }.to raise_error(Lolita::Translation::NoBuilderForClassError)
52
+ end
53
+
54
+ it "should build concrete class when #build is called" do
55
+ stub_create_klass
56
+ obj = klass.new(Class.new(ActiveRecord::Base))
57
+ obj.builder.should_receive(:build).and_return(true)
58
+ obj.build_class
59
+ end
60
+ end
61
+
62
+ end
@@ -0,0 +1,16 @@
1
+ require 'header'
2
+ require File.expand_path("lib/lolita-translation")
3
+
4
+ describe Lolita::Translation do
5
+ it "configuration is loded" do
6
+ defined?(Lolita::Translation::Configuration).should_not be_nil
7
+ end
8
+
9
+ it "translation class builder is loaded" do
10
+ defined?(Lolita::Translation::TranslationClassBuilder).should_not be_nil
11
+ end
12
+
13
+ it "orm mixin is loaded" do
14
+ defined?(Lolita::Translation::ORM).should_not be_nil
15
+ end
16
+ end
@@ -0,0 +1,6 @@
1
+ require 'rails'
2
+ require File.expand_path("spec/test_app/config/enviroment")
3
+ require "rspec/rails"
4
+ require 'capybara/rails'
5
+ require 'capybara/rspec'
6
+ Capybara.default_driver = :webkit
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ if USE_RAILS
4
+ describe "In order to translate resource As system user I want to switch from original resource to translations" do
5
+
6
+ it "As user in resource create form I see language switch and current language is active and I can switch to other languages" do
7
+ visit "/lolita/posts/new"
8
+ language_selector_text = page.find(".tab-language-switch").text
9
+ ::I18n.available_locales.each do |locale|
10
+ language_selector_text.should match(/#{locale.to_s.capitalize}/)
11
+ end
12
+
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+
3
+ describe "In order to internationalize all content I can enter information in any language and translate to any other language" do
4
+
5
+ def click_save_btn
6
+ save_btn = page.find("button[data-type='save&close']")
7
+ save_btn.click
8
+ end
9
+
10
+ def create_category options = {}
11
+ default_options = {:name => "name", :default_locale => ::I18n.locale}
12
+ Category.create!(default_options.merge(options))
13
+ end
14
+
15
+ it "As user I can enter information in same language as system uses and resource will be stored in that language" do
16
+ visit "/lolita/posts/new"
17
+ fill_in "post_title", :with => "lv-title"
18
+ fill_in "post_body", :with => "lv-body"
19
+ click_save_btn
20
+ page.should have_content("lv-title")
21
+ page.should have_content("lv-body")
22
+ end
23
+
24
+ it "As user I can enter information in language that I am using currently and original resource will be save in that language" do
25
+ visit "/lolita/posts/new?locale=ru"
26
+ fill_in "post_title", :with => "ru-title"
27
+ fill_in "post_body", :with => "ru-body"
28
+ click_save_btn
29
+ visit "/lolita/posts?locale=lv"
30
+ page.should have_content("ru-title")
31
+ page.should have_content("ru-body")
32
+ end
33
+
34
+ it "As user I can open previously saved resource, in different language than mine, and resource will be shown in resource original language and I will see that" do
35
+ I18n.locale = :ru
36
+ category = create_category(:name => "ru-name")
37
+ visit("/lolita/categories/#{category.id}/edit?locale=lv")
38
+ page.should have_selector(".tab-language-switch li.active", :text => "Ru")
39
+ ru_content = page.find(".language-wrap.active")
40
+ ru_content.should be_visible
41
+ end
42
+
43
+ it "As user I can open previously saved resource, in different language than mine, and change original information and that information will be save in original resource" do
44
+ I18n.locale = :ru
45
+ category = create_category(:name => "ru-name")
46
+ visit("/lolita/categories/#{category.id}/edit?locale=lv")
47
+ page.fill_in "category_name", :with => "changed-ru-name"
48
+ click_save_btn
49
+ visit("/lolita/categories/#{category.id}/edit?locale=en")
50
+ name_inp = page.find("#category_name")
51
+ name_inp.value.should eq("changed-ru-name")
52
+ end
53
+
54
+ it "As user I can open previously saved resource, in different language than mine, and change information for my language, and it will be saved as translation", :js => true do
55
+ I18n.locale = :ru
56
+ category = create_category(:name => "ru-name")
57
+ visit("/lolita/categories/#{category.id}/edit?locale=lv")
58
+ page.execute_script(%Q{$(".tab-language-switch li[data-locale='lv']").click()})
59
+ page.fill_in("Name",:with => "lv-name")
60
+ click_save_btn
61
+ page.should have_content("lv-name")
62
+ end
63
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,108 +1,56 @@
1
1
  # encoding: utf-8
2
- require 'rubygems'
3
- require 'bundler'
4
- begin
5
- Bundler.setup(:default, :test)
6
- rescue Bundler::BundlerError => e
7
- $stderr.puts e.message
8
- $stderr.puts "Run `bundle install` to install missing gems"
9
- exit e.status_code
10
- end
11
- require 'active_record'
12
- require 'active_support'
13
- require 'logger'
14
- require 'ffaker'
15
- require File.expand_path('lib/lolita-translation')
2
+ # Now there are support only for "active_record"
3
+ ENV["ORM"] = "active_record"
4
+ # Set this to true if you want to launch rails application
5
+ USE_RAILS = true
6
+ # Set this true to use debugger, if your ruby version supports debugger.
7
+ USE_DEBUGGER = true
8
+ # Set this to true to see HTML code coverage report
9
+ SHOW_REPORT = false
16
10
 
17
- ActiveRecord::Base.logger = Logger.new(File.open("#{File.dirname(__FILE__)}/database.log", 'w+'))
18
- ActiveRecord::Base.establish_connection({ :database => ":memory:", :adapter => 'sqlite3', :timeout => 500 })
19
-
20
- # setup I18n
21
- I18n.available_locales = [:en,:lv,:ru,:fr]
22
- I18n.default_locale = :en
23
- I18n.locale = :en
24
11
 
25
- # Add models
26
- ActiveRecord::Schema.define do
27
- create_table :news, :force => true do |t|
28
- t.string :title
29
- t.string :slug
30
- t.text :body
31
- t.integer :category_id
32
- t.integer :trx_id
33
- end
34
- create_table :categories, :force => true do |t|
35
- t.string :name
36
- t.string :desc
37
- t.integer :trx_id
38
- end
39
- create_table :groups, :force => true do |t|
40
- t.string :name
41
- end
42
- create_table :categories_groups, :force => true, :id => false do |t|
43
- t.integer :category_id
44
- t.integer :group_id
45
- end
46
- create_table :meta_datas, :force => true do |t|
47
- t.string :title
48
- t.string :url
49
- t.string :keywords
50
- t.text :description
51
- t.string :metaable_type
52
- t.integer :metaable_id
53
- end
12
+ require 'header'
13
+ if USE_RAILS
14
+ require 'rails_helper'
54
15
  end
55
16
 
56
- class News < ActiveRecord::Base
57
- include Lolita::Translation
58
- belongs_to :category, :dependent => :destroy
59
- has_one :meta_data, :as => :metaable, :dependent => :destroy
60
- translations :title, :body
17
+ if ENV["ORM"] == "active_record"
18
+ require 'ar_schema'
61
19
  end
62
20
 
63
- class Category < ActiveRecord::Base
64
- include Lolita::Translation
65
- has_many :news
66
- has_and_belongs_to_many :groups
67
- translations :name
21
+ if USE_DEBUGGER
22
+ require 'debugger'
68
23
  end
69
24
 
70
- class Group < ActiveRecord::Base
71
- include Lolita::Translation
72
- has_and_belongs_to_many :categories
73
- translations :name
74
- end
25
+ require 'logger'
26
+ require 'ffaker'
27
+ require File.expand_path('lib/lolita-translation')
75
28
 
76
- class MetaData < ActiveRecord::Base
77
- set_table_name :meta_datas
78
- include Lolita::Translation
79
- belongs_to :metaable, :polymorphic => true
80
- translations :title, :url, :keywords, :description
81
- end
82
29
 
83
- # build translation tables
30
+ # setup I18n
31
+ I18n.available_locales = [:en,:lv,:ru,:fr]
32
+ I18n.default_locale = :lv
33
+ I18n.locale = :en
34
+ Lolita.locales = I18n.available_locales
84
35
 
85
- News.sync_translation_table!
86
- Category.sync_translation_table!
87
- Group.sync_translation_table!
88
- MetaData.sync_translation_table!
89
36
 
90
- # this is included in Lolita by default
91
- class ::Hash
92
- # converts all keys to symbols, but RECURSIVE
93
- def symbolize_keys!
94
- each do |k,v|
95
- sym = k.respond_to?(:to_sym) ? k.to_sym : k
96
- self[sym] = Hash === v ? v.symbolize_keys! : v
97
- delete(k) unless k == sym
37
+ RSpec.configure do |config|
38
+ config.before(:each) do
39
+ if ENV["ORM"] == "active_record"
40
+ ::ARSchema.clean!
98
41
  end
99
- self
42
+ config.treat_symbols_as_metadata_keys_with_true_values = true
43
+ config.mock_with :rspec
100
44
  end
101
45
  end
102
- RSpec.configure do |config|
103
- config.before(:each) do
104
- News.delete_all
105
- Category.delete_all
106
- MetaData.delete_all
46
+
47
+ at_exit do
48
+ if ::USE_RAILS
49
+ if File.exist?(File.expand_path("spec/test_app/db/lolita-translation.db"))
50
+ File.delete(File.expand_path("spec/test_app/db/lolita-translation.db"))
51
+ end
52
+ end
53
+ if ::SHOW_REPORT
54
+ CoverMe.complete!
107
55
  end
108
56
  end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+ require 'ar_schema'
3
+ ARSchema.connect!
4
+
5
+ describe "lolita_translation:sync_tables" do
6
+ def translations
7
+ ActiveRecord::Base.connection.tables.reject{|tn| !tn.match(/translations/)}.sort
8
+ end
9
+
10
+ before(:each) do
11
+ Object.send(:remove_const,:Comment) rescue nil
12
+ c_class = Class.new(ActiveRecord::Base)
13
+ Object.const_set(:Comment,c_class)
14
+ c_class.class_eval do
15
+ include Lolita::Translation
16
+ translate :body
17
+ end
18
+ ActiveRecord::Base.connection.execute("DROP TABLE comments_translations") rescue nil
19
+ end
20
+
21
+ after(:each) do
22
+ Object.send(:remove_const,:Comment) rescue nil
23
+ end
24
+
25
+ it "should create translation tables for all lolita mappings" do
26
+ translations.should eq(%w(categories_translations posts_translations products_translations).sort)
27
+ Lolita.mappings[:comment] = Lolita::Mapping.new(:comments)
28
+ load(File.expand_path("lib/tasks/lolita_translation.rake"))
29
+ Rake.application["lolita_translation:sync_tables"].invoke()
30
+ translations.should eq(%w(categories_translations posts_translations comments_translations products_translations).sort)
31
+ end
32
+ end