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
data/.gitignore ADDED
@@ -0,0 +1,25 @@
1
+ Gemfile.lock
2
+ spec/database.log
3
+ # rcov generated
4
+ coverage
5
+ coverage.data
6
+
7
+ # rdoc generated
8
+ rdoc
9
+
10
+ # yard generated
11
+ doc
12
+ .yardoc
13
+ .rvmrc
14
+ # bundler
15
+ .bundle
16
+
17
+ # jeweler generated
18
+ pkg
19
+
20
+
21
+ *.swp
22
+ tmp
23
+
24
+ spec/test_app/log/*.log
25
+ spec/test_app/db/*.db
data/Gemfile CHANGED
@@ -1,19 +1,3 @@
1
- source "http://rubygems.org"
1
+ source :rubygems
2
+ gemspec
2
3
 
3
- gem "lolita", ">=3.2.0.rc.3"
4
- group :development do
5
- gem "shoulda", ">= 0"
6
- gem "bundler", "~> 1.0.0"
7
- gem "jeweler", "~> 1.5.2"
8
- gem "rcov", ">= 0"
9
- end
10
-
11
- group :test do
12
- gem "rails", "~>3.1.0"
13
- gem "rspec","~>2.6.0"
14
- gem "rspec-rails", "~>2.6.0"
15
- gem "webmock", "~> 1.7.6"
16
- gem "sqlite3"
17
- gem "ffaker"
18
- gem 'ruby-debug19', :require => 'ruby-debug'
19
- end
data/README.md CHANGED
@@ -3,13 +3,12 @@
3
3
 
4
4
  ### Install
5
5
 
6
- gem "lolita"
7
6
  gem "lolita-translation"
8
7
 
9
8
  ### Usage
10
9
 
11
10
  1. Add `include Lolita::Translation` in your model.
12
- 2. Call `translations :title, :body` in your model and pass column names to translate.
11
+ 2. Call `translate :title, :body` in your model and pass column names to translate.
13
12
  3. Add `Article.sync_translation_table!` to your `db/seeds.rb` and run it.
14
13
 
15
14
  #### What it does?
data/Rakefile CHANGED
@@ -1,53 +1,5 @@
1
1
  require 'rubygems'
2
2
  require 'bundler'
3
- begin
4
- Bundler.setup(:default, :development)
5
- rescue Bundler::BundlerError => e
6
- $stderr.puts e.message
7
- $stderr.puts "Run `bundle install` to install missing gems"
8
- exit e.status_code
9
- end
10
- require 'rake'
11
3
 
12
- require 'jeweler'
13
- Jeweler::Tasks.new do |gem|
14
- # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
- gem.name = "lolita-translation"
16
- gem.homepage = "http://github.com/ithouse/lolita-translations"
17
- gem.license = "MIT"
18
- gem.summary = %Q{Lolita models translation plugin}
19
- gem.description = %Q{Translates models in Lolita}
20
- gem.email = "support@ithouse.lv"
21
- gem.authors = ["ITHouse", "Gatis Tomsons", "Arturs Meisters"]
22
- # Include your dependencies below. Runtime dependencies are required when using your gem,
23
- # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
24
- # gem.add_runtime_dependency 'jabber4r', '> 0.1'
25
- # gem.add_development_dependency 'rspec', '> 1.2.3'
26
- end
27
- Jeweler::RubygemsDotOrgTasks.new
4
+ Bundler::GemHelper.install_tasks
28
5
 
29
- require 'rake/testtask'
30
- Rake::TestTask.new(:test) do |test|
31
- test.libs << 'lib' << 'spec'
32
- test.pattern = 'spec/**/*_spec.rb'
33
- test.verbose = true
34
- end
35
-
36
- require 'rcov/rcovtask'
37
- Rcov::RcovTask.new do |test|
38
- test.libs << 'spec'
39
- test.pattern = 'spec/**/*_spec.rb'
40
- test.verbose = true
41
- end
42
-
43
- task :default => :test
44
-
45
- require 'rake/rdoctask'
46
- Rake::RDocTask.new do |rdoc|
47
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
-
49
- rdoc.rdoc_dir = 'rdoc'
50
- rdoc.title = "lolita-translation #{version}"
51
- rdoc.rdoc_files.include('README*')
52
- rdoc.rdoc_files.include('lib/**/*.rb')
53
- end
@@ -2,9 +2,10 @@ $(function(){
2
2
  $(".tab-language-switch li").live("click",function(){
3
3
  $(".tab-language-switch li").removeClass("active")
4
4
  $(this).addClass("active");
5
- var locale = $(this).attr("data-locale")
6
- var tab_name = $(this).attr("data-tab")
5
+ var locale = $(this).data("locale")
6
+ var tab_name = $(this).data("tab")
7
7
  $(".tab-content .language-wrap").hide(0)
8
- $("#"+locale+"_attributes_for_"+tab_name).show(0)
8
+ $("#"+locale+"_for_"+tab_name).show(0)
9
+ resize_all_tinymce_editors()
9
10
  })
10
11
  })
@@ -3,7 +3,7 @@
3
3
  overflow: hidden;
4
4
  list-style: none;
5
5
  margin-right: 25px;
6
- top: 28px;
6
+ margin-top: -10px;
7
7
  position: relative;
8
8
  }
9
9
  .tab-language-switch li{
@@ -17,3 +17,9 @@
17
17
  font-weight: bold;
18
18
  cursor:default;
19
19
  }
20
+ .language-wrap{
21
+ display:none;
22
+ }
23
+ .language-wrap.active{
24
+ display:block;
25
+ }
@@ -0,0 +1,4 @@
1
+ - content_for :script do
2
+ = javascript_include_tag 'lolita/translation/application.js'
3
+ - content_for :style do
4
+ = stylesheet_link_tag 'lolita/translation/application.css', :media => 'screen, projection'
@@ -0,0 +1,2 @@
1
+ .language-wrap{ :id => "#{translation_locale}_for_#{tab.name}", :class => active && "active"}
2
+ = content
@@ -0,0 +1,4 @@
1
+ %ul{:class => "tab-language-switch", :id => "#{tab.name}_language_switch"}
2
+ - resource.translations_configuration.locales.by_resource_locale(resource).each do |locale|
3
+ %li{ :class => resource.original_locale.to_s == locale.name.to_s && "active" || "", :"data-locale" => locale.short_name, :"data-tab" => tab.name}= locale.humanized_short_name
4
+ .clear
@@ -1,46 +1,53 @@
1
-
1
+ $:<<File.dirname(__FILE__) unless $:.include?(File.dirname(__FILE__))
2
2
  require 'lolita'
3
- require 'lolita-translation/string.rb'
4
- require 'lolita-translation/modules'
5
- require 'lolita-translation/model'
6
- require 'lolita-translation/configuration'
7
- if Lolita.rails3?
8
- require 'lolita-translation/rails'
9
- end
3
+
10
4
 
11
5
  module Lolita
6
+ # Lolita::Translation is module for all classes and module for data translation in Lolita.
7
+ # It have #locales method, that is is used to get all configured locales or all available locales.
12
8
  module Translation
13
9
 
14
- def self.included(base_class)
15
- base_class.extend(Lolita::Translation::SingletonMethods)
10
+ def self.locales
11
+ unless @locales
12
+ defined_locales = Lolita.locales.any? && Lolita.locales || ::I18n.available_locales
13
+ @locales = Lolita::Translation::Locales.new(defined_locales)
14
+ end
15
+ @locales
16
16
  end
17
17
 
18
- class << self
19
- # Determine whether tab is translatable. When there is one or more fields in tab, that are defined with #translates.
20
- def translatable?(tab)
21
- fields = tab.fields.reject{|field|
22
- field.dbi!=tab.dbi
23
- }
24
- tab.dbi.klass.respond_to?(:translation_attrs) &&
25
- tab.dbi.klass.respond_to?(:translations) && (fields.map(&:name) & tab.dbi.klass.translation_attrs).any?
18
+ def self.load!
19
+ load_base!
20
+ load_orm!
21
+ load_lolita_extensions!
22
+ if Lolita.rails3?
23
+ load_rails_engine!
26
24
  end
25
+ end
27
26
 
28
- # Create nested form configuration for views.
29
- def create_translations_nested_form(resource,tab)
30
- resource.build_nested_translations
31
- nested_form = Lolita::Configuration::NestedForm.new(tab,:translations)
32
- nested_form.expandable = false
33
- nested_form.field_style = :normal
34
-
35
- fields = tab.fields.reject{|field|
36
- !resource.class.translation_attrs.include?(field.name.to_sym)
37
- }
38
- fields << Lolita::Configuration::Factory::Field.add(nested_form.dbi,:locale,:hidden)
39
- nested_form.fields=fields
40
- nested_form
41
- end
27
+ def self.load_base!
28
+ require 'lolita-translation/version'
29
+ require 'lolita-translation/errors'
30
+ require 'lolita-translation/utils'
31
+ require 'lolita-translation/configuration'
32
+ require 'lolita-translation/locales'
33
+ require 'lolita-translation/translation_class_builder'
34
+ require 'lolita-translation/record'
35
+ end
36
+
37
+ def self.load_orm!
38
+ require 'lolita-translation/migrator'
39
+ require 'lolita-translation/orm/mixin'
40
+ end
41
+
42
+ def self.load_lolita_extensions!
43
+ require 'lolita-translation/lolita/tab_extension'
44
+ end
45
+
46
+ def self.load_rails_engine!
47
+ require 'lolita-translation/rails'
42
48
  end
49
+
43
50
  end
44
51
  end
45
52
 
46
- Lolita.add_module Lolita::Translation
53
+ Lolita::Translation.load!
@@ -0,0 +1,103 @@
1
+ module Lolita
2
+ module Translation
3
+ module Builder
4
+
5
+ class AbstractBuilder
6
+ attr_reader :base_klass, :klass, :configuration
7
+
8
+ def initialize(base_class, configuration = nil, superclass = nil)
9
+ @superclass = superclass
10
+ @base_klass = base_class
11
+ @configuration = configuration
12
+ @klass = create_klass
13
+ end
14
+
15
+ def class_name
16
+ "#{@base_klass.to_s}Translation"
17
+ end
18
+
19
+ def build
20
+ implementation_warn
21
+ end
22
+
23
+ def association_name
24
+ @configuration && @configuration.demodulized_class_name
25
+ end
26
+
27
+ def association_key
28
+ @configuration && @configuration.association_key
29
+ end
30
+
31
+ def translations_association_name
32
+ @configuration && @configuration.association_name
33
+ end
34
+
35
+ def locale_field_name
36
+ @configuration && @configuration.locale_field_name
37
+ end
38
+
39
+ def table_name
40
+ @configuration && @configuration.table_name
41
+ end
42
+
43
+ def override_klass_attributes method_names
44
+ method_names.each do |method_name, attribute|
45
+ validate_attribute_method_and_attribute(method_name, attribute)
46
+ base_klass.instance_eval do
47
+ define_method(method_name) do
48
+ translation_record.attribute(attribute)
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def configuration_attributes
57
+ @configuration && @configuration.attributes
58
+ end
59
+
60
+ def validate_attribute_method_and_attribute(method_name, attribute)
61
+ raise ArgumentError.new("#{method_name} is not valid attribute reader name") unless method_name
62
+ raise ArgumentError.new("#{attribute} is not valid attribute name") unless attribute
63
+ end
64
+
65
+ def implementation_warn
66
+ warn("No implementation for #{self}")
67
+ end
68
+
69
+ def create_klass
70
+ new_klass = Class.new(@superclass || Object)
71
+ link_klass_with_constant(new_klass)
72
+ new_klass
73
+ end
74
+
75
+ def link_klass_with_constant(new_klass)
76
+ unless new_klass.name == self.class_name
77
+ name_parts = class_name.split("::")
78
+ new_class_name = name_parts.pop
79
+ parent_object = find_parent_object(Object,name_parts)
80
+ assign_class_to_constant(parent_object,new_class_name, new_klass)
81
+ end
82
+ end
83
+
84
+ def assign_class_to_constant parent_object, new_class_name, new_klass
85
+ new_class_name = new_class_name.to_sym
86
+ if parent_object.const_defined?(new_class_name)
87
+ parent_object.send(:remove_const,new_class_name)
88
+ end
89
+ parent_object.const_set(new_class_name.to_sym, new_klass)
90
+ end
91
+
92
+ def find_parent_object parent_object, name_parts
93
+ name_parts.each do |const_name|
94
+ parent_object = parent_object.const_get(const_name.to_sym)
95
+ end
96
+ parent_object
97
+ end
98
+
99
+ end
100
+
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,106 @@
1
+ require 'lolita-translation/builder/abstract_builder'
2
+
3
+ module Lolita
4
+ module Translation
5
+
6
+ module Builder
7
+ class ActiveRecordBuilder < Lolita::Translation::Builder::AbstractBuilder
8
+
9
+ def initialize base_klass, configuration = nil
10
+ super(base_klass,configuration, ActiveRecord::Base)
11
+ end
12
+
13
+ def build
14
+ add_ar_klass_class_methods
15
+ add_ar_klass_associations
16
+ add_ar_klass_validations
17
+ call_base_klass_class_methods
18
+ add_validations_to_base_klass
19
+ end
20
+
21
+ def override_klass_attributes(attributes)
22
+ add_ar_klass_attr_accessible(attributes + default_attributes)
23
+ expanded_attributes = attributes.inject({}){|hsh,attribute|
24
+ hsh[attribute] = attribute
25
+ hsh
26
+ }
27
+ super(expanded_attributes)
28
+ end
29
+
30
+ private
31
+
32
+ def default_attributes
33
+ [:locale]
34
+ end
35
+
36
+ def add_ar_klass_attr_accessible attributes
37
+ klass.class_eval do
38
+ attr_accessible :locale, *attributes
39
+ end
40
+ end
41
+
42
+ def add_ar_klass_associations
43
+ if self.configuration
44
+ klass.belongs_to association_name, :inverse_of => translations_association_name
45
+ end
46
+ end
47
+
48
+ def add_ar_klass_validations
49
+ if self.configuration
50
+ ar_translation_builder = self
51
+
52
+ klass.validates(:locale,{
53
+ :presence => true,
54
+ :uniqueness => {:scope => association_key},
55
+ })
56
+ klass.validates(association_name, :presence => true, :on => :update)
57
+ klass.validates_each(:locale) do |record, attr, value|
58
+ original_record = record.send(ar_translation_builder.association_name)
59
+ if original_record && original_record.original_locale.to_s == value.to_s
60
+ record.errors.add(attr, 'is used as default locale')
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ def add_ar_klass_class_methods
67
+ ar_translation_builder = self
68
+ klass.singleton_class.instance_eval do
69
+ define_method(:table_name) do
70
+ ar_translation_builder.table_name
71
+ end
72
+ end
73
+ end
74
+
75
+ def call_base_klass_class_methods
76
+ if self.configuration
77
+ base_klass.has_many(translations_association_name, {
78
+ :class_name => class_name,
79
+ :foreign_key => association_key,
80
+ :dependent => :destroy,
81
+ :inverse_of => association_name
82
+ })
83
+ base_klass.accepts_nested_attributes_for translations_association_name, :allow_destroy => true, :reject_if => nested_attributes_rejection_proc
84
+ end
85
+ end
86
+
87
+ def nested_attributes_rejection_proc
88
+ Proc.new{|attrs|
89
+ !configuration_attributes.detect{|attr| !attrs[attr].blank? }
90
+ }
91
+ end
92
+
93
+ def add_validations_to_base_klass
94
+ if base_klass.column_names.include?("default_locale")
95
+ base_klass.validates locale_field_name, :presence => true
96
+ base_klass.before_validation do
97
+ self.default_locale ||= self.translation_record.system_current_locale
98
+ end
99
+ end
100
+ end
101
+
102
+ end
103
+ end
104
+
105
+ end
106
+ end