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.
- data/.gitignore +25 -0
- data/Gemfile +2 -18
- data/README.md +1 -2
- data/Rakefile +1 -49
- data/app/assets/javascripts/lolita/translation/application.js +4 -3
- data/app/assets/stylesheets/lolita/translation/application.css +7 -1
- data/app/views/components/lolita/translation/_assets.html.haml +4 -0
- data/app/views/components/lolita/translation/_language_wrap.html.haml +2 -0
- data/app/views/components/lolita/translation/_switch.html.haml +4 -0
- data/lib/lolita-translation.rb +40 -33
- data/lib/lolita-translation/builder/abstract_builder.rb +103 -0
- data/lib/lolita-translation/builder/active_record_builder.rb +106 -0
- data/lib/lolita-translation/builder/mongoid_builder.rb +0 -0
- data/lib/lolita-translation/configuration.rb +41 -166
- data/lib/lolita-translation/errors.rb +15 -0
- data/lib/lolita-translation/locale.rb +32 -0
- data/lib/lolita-translation/locales.rb +62 -0
- data/lib/lolita-translation/lolita/component_hooks.rb +49 -0
- data/lib/lolita-translation/lolita/tab_extension.rb +113 -0
- data/lib/lolita-translation/migrator.rb +56 -0
- data/lib/lolita-translation/migrators/active_record_migrator.rb +93 -0
- data/lib/lolita-translation/migrators/mongoid_migrator.rb +81 -0
- data/lib/lolita-translation/orm/mixin.rb +57 -0
- data/lib/lolita-translation/rails.rb +6 -31
- data/lib/lolita-translation/record.rb +220 -0
- data/lib/lolita-translation/translated_string.rb +11 -0
- data/lib/lolita-translation/translation_class_builder.rb +59 -0
- data/lib/lolita-translation/utils.rb +13 -0
- data/lib/lolita-translation/version.rb +32 -0
- data/lib/tasks/lolita_translation.rake +14 -0
- data/lolita-translation.gemspec +24 -71
- data/spec/ar_schema.rb +90 -0
- data/spec/header.rb +14 -0
- data/spec/integrations/active_record_integration_spec.rb +218 -0
- data/spec/lolita-translation/builder/abstract_builder_spec.rb +67 -0
- data/spec/lolita-translation/builder/active_record_builder_spec.rb +40 -0
- data/spec/lolita-translation/configuration_spec.rb +72 -0
- data/spec/lolita-translation/locale_spec.rb +25 -0
- data/spec/lolita-translation/locales_spec.rb +31 -0
- data/spec/lolita-translation/lolita/tab_extension_spec.rb +61 -0
- data/spec/lolita-translation/migrator_spec.rb +42 -0
- data/spec/lolita-translation/migrators/active_record_migrator_spec.rb +50 -0
- data/spec/lolita-translation/orm/mixin_spec.rb +52 -0
- data/spec/lolita-translation/record_spec.rb +112 -0
- data/spec/lolita-translation/translation_class_builder_spec.rb +62 -0
- data/spec/lolita_translation_spec.rb +16 -0
- data/spec/rails_helper.rb +6 -0
- data/spec/requests/record_language_switch_spec.rb +16 -0
- data/spec/requests/record_saving_spec.rb +63 -0
- data/spec/spec_helper.rb +38 -90
- data/spec/tasks/lolita_translation_spec.rb +32 -0
- data/spec/test_app/app/controllers/application_controller.rb +3 -0
- data/spec/test_app/app/models/category.rb +6 -0
- data/spec/test_app/app/models/post.rb +8 -0
- data/spec/test_app/config/application.rb +24 -0
- data/spec/test_app/config/boot.rb +11 -0
- data/spec/test_app/config/database.yml +3 -0
- data/spec/test_app/config/enviroment.rb +5 -0
- data/spec/test_app/config/enviroments/development.rb +44 -0
- data/spec/test_app/config/initializers/lolita_translation.rb +4 -0
- data/spec/test_app/config/initializers/token.rb +7 -0
- data/spec/test_app/config/routes.rb +4 -0
- data/spec/test_app/db/.gitkeep +0 -0
- data/spec/test_app/log/.gitkeep +0 -0
- metadata +193 -46
- data/.document +0 -5
- data/VERSION +0 -1
- data/app/views/components/lolita/translation/_assets.html.erb +0 -7
- data/app/views/components/lolita/translation/_language_wrap.html.erb +0 -4
- data/app/views/components/lolita/translation/_switch.html.erb +0 -8
- data/lib/generators/lolita_translation/USAGE +0 -8
- data/lib/generators/lolita_translation/has_translations_generator.rb +0 -8
- data/lib/lolita-translation/model.rb +0 -100
- data/lib/lolita-translation/modules.rb +0 -130
- data/lib/lolita-translation/string.rb +0 -19
- data/lib/tasks/has_translations_tasks.rake +0 -4
- 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
|
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 `
|
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
|
-
|
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).
|
6
|
-
var tab_name = $(this).
|
5
|
+
var locale = $(this).data("locale")
|
6
|
+
var tab_name = $(this).data("tab")
|
7
7
|
$(".tab-content .language-wrap").hide(0)
|
8
|
-
$("#"+locale+"
|
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:
|
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
|
+
%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
|
data/lib/lolita-translation.rb
CHANGED
@@ -1,46 +1,53 @@
|
|
1
|
-
|
1
|
+
$:<<File.dirname(__FILE__) unless $:.include?(File.dirname(__FILE__))
|
2
2
|
require 'lolita'
|
3
|
-
|
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.
|
15
|
-
|
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
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
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
|