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,56 @@
1
+ module Lolita
2
+ module Translation
3
+
4
+ class Migrator
5
+
6
+ attr_reader :klass,:config
7
+
8
+ def initialize(base_class)
9
+ @klass = base_class
10
+ @config = @klass.translations_configuration
11
+ end
12
+
13
+ def migrate
14
+ raise StandardError, "#{self.class} must implement this method"
15
+ end
16
+
17
+ class << self
18
+ def create(klass)
19
+ if active_record?(klass)
20
+ Lolita::Translation::Migrators::ActiveRecordMigrator.new(klass)
21
+ elsif mongoid?(klass)
22
+ Lolita::Translation::Migrators::MongoidMigrator.new(klass)
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def active_record?(klass)
29
+ Lolita::Translation::Utils.active_record_class?(klass)
30
+ end
31
+
32
+ def mongoid?(klass)
33
+ Lolita::Translation::Utils.mongoid_class?(klass)
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def switch_stdout
40
+ begin
41
+ out = StringIO.new
42
+ $stdout = out
43
+ yield
44
+ ensure
45
+ $stdout = STDOUT
46
+ end
47
+ end
48
+
49
+ end
50
+
51
+
52
+ end
53
+ end
54
+
55
+ require 'lolita-translation/migrators/active_record_migrator'
56
+ require 'lolita-translation/migrators/mongoid_migrator'
@@ -0,0 +1,93 @@
1
+ require 'lolita-translation/migrator'
2
+ module Lolita
3
+ module Translation
4
+ module Migrators
5
+ class ActiveRecordMigrator < Lolita::Translation::Migrator
6
+
7
+ def migrate
8
+ switch_stdout do
9
+ unless table_exist?
10
+ create_table
11
+ add_indexes
12
+ reset_class_column_information
13
+ else
14
+ if change_table
15
+ reset_class_column_information
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def create_table
24
+ ActiveRecord::Migration.create_table config.table_name do |t|
25
+ t.integer config.association_key, :null => false
26
+ t.string :locale, :null => false, :limit => 5
27
+ config.attributes.each do |attr|
28
+ if col = column(attr)
29
+ t.send(col.type, attr)
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ def change_table
36
+ removed_columns.inject(false) do |result,attribute|
37
+ ActiveRecord::Migration.remove_column(config.table_name, attribute)
38
+ true
39
+ end ||
40
+ config.attributes.inject(false) do |result, attribute|
41
+ if !translations_column(attribute)
42
+ if col = column(attribute)
43
+ ActiveRecord::Migration.add_column(config.table_name, attribute, col.type)
44
+ result = true
45
+ end
46
+ end
47
+ result
48
+ end
49
+ end
50
+
51
+ def add_indexes
52
+ ActiveRecord::Migration.add_index(
53
+ config.table_name,
54
+ [config.association_key, :locale], {
55
+ :unique => true,
56
+ :name => "#{config.table_name}_comb"
57
+ }
58
+ )
59
+ ActiveRecord::Migration.add_index(
60
+ config.table_name,
61
+ config.association_key,{
62
+ :name => "#{config.table_name}_sim"
63
+ }
64
+ )
65
+ end
66
+
67
+ def content_columns
68
+ config.translation_class.column_names - ["id", "locale", config.association_key.to_s]
69
+ end
70
+
71
+ def removed_columns
72
+ content_columns - config.attributes.map{|a| a.to_s }
73
+ end
74
+ def reset_class_column_information
75
+ config.translation_class.reset_column_information
76
+ end
77
+
78
+ def table_exist?
79
+ ActiveRecord::Migration.table_exists?(config.table_name)
80
+ end
81
+
82
+ def column(name)
83
+ klass.columns_hash[name.to_s]
84
+ end
85
+
86
+ def translations_column(name)
87
+ config.translation_class.columns_hash[name.to_s]
88
+ end
89
+ end
90
+
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,81 @@
1
+ require 'lolita-translation/migrator'
2
+
3
+ module Lolita
4
+ module Translation
5
+ module Migrators
6
+ class MongidMigrator
7
+
8
+ def migrate
9
+ if collection_exist?
10
+ create_collection_struct
11
+ add_indexes
12
+ else
13
+ change_collection_struct
14
+ end
15
+ unless translations_class.fields["locale"]
16
+
17
+ else
18
+
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def create_collection_struct
25
+ orig_config = config
26
+
27
+ config.translations_class.class_eval do
28
+ field(orig_config.association_key, :type => Integer)
29
+ field :locale, :type => String
30
+ orig_config.attributes.each do |attribute|
31
+ if col = field(attribute)
32
+ field col.name, :type => col.type
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ def change_collection_struct
39
+ config.attributes.each do |attribute|
40
+ unless translations_field(attribute)
41
+ if col = field(attribute)
42
+ config.translations_class.field(col.name, :type => col.type)
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ def add_indexes
49
+ orig_config = config
50
+
51
+ config.translations_class.class_eval do
52
+ index(
53
+ [
54
+ [ orig_config.association_key, Mongo::ASCENDING ],
55
+ [ :locale, Mongo::ASCENDING ]
56
+ ],
57
+ unique: true, background: true
58
+ )
59
+ index( orig_config.association_key, Mongo::ASCENDING, background: true)
60
+ end
61
+ end
62
+
63
+ def collection_exist?
64
+ config.translations_class.fields["locale"]
65
+ end
66
+
67
+ def field(name)
68
+ klass.fields.detect do |field|
69
+ field.name.to_s == name.to_s
70
+ end
71
+ end
72
+
73
+ def translations_field(name)
74
+ config.translations_class.fields.detect do |field|
75
+ field.name.to_s == name.to_s
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,57 @@
1
+ module Lolita
2
+ module Translation
3
+
4
+ module ORM
5
+
6
+ module ClassMethods
7
+ def translate *args, &block
8
+ @translations_configuration ||= Lolita::Translation::Configuration.new(self,*args,&block)
9
+ end
10
+
11
+ def translations_configuration
12
+ unless @translations_configuration
13
+ raise Lolita::Translation::ConfigurationNotInitializedError.new(self)
14
+ else
15
+ @translations_configuration
16
+ end
17
+ end
18
+
19
+ def sync_translation_table!
20
+ migrator = Lolita::Translation::Migrator.create(self)
21
+ migrator.migrate
22
+ end
23
+
24
+ end
25
+
26
+ module InstanceMethods
27
+
28
+ def translations_configuration
29
+ self.class.translations_configuration
30
+ end
31
+
32
+ def translation_record
33
+ @translation_record ||= Lolita::Translation::Record.new(self, translations_configuration)
34
+ end
35
+
36
+ def original_locale
37
+ translation_record.default_locale
38
+ end
39
+
40
+ def original_locale=(value)
41
+ translation_record.default_locale = value
42
+ end
43
+
44
+ def build_nested_translations
45
+ translation_record.build_nested_translations
46
+ end
47
+
48
+ def in(locale,&block)
49
+ translation_record.in(locale,&block)
50
+ end
51
+
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+ end
@@ -2,40 +2,15 @@ module LolitaTranslation
2
2
  class Engine < Rails::Engine
3
3
 
4
4
  end
5
- end
6
-
7
- Lolita::Hooks.component(:"/lolita/configuration/tab/form").before do
8
- tab = self.component_locals[:tab]
9
- if Lolita::Translation.translatable?(tab)
10
- self.send(:render_component,"lolita/translation",:switch, :tab => tab)
11
- end
12
- end
13
5
 
14
- Lolita::Hooks.component(:"/lolita/configuration/tab/fields").after do
15
- tab = self.component_locals[:tab]
16
- if Lolita::Translation.translatable?(tab)
17
- self.render_component Lolita::Translation.create_translations_nested_form(self.resource,tab)
18
- end
19
- end
6
+ class Railtie < Rails::Railtie
7
+ railtie_name :lolita_translation
20
8
 
21
- Lolita::Hooks.component(:"/lolita/configuration/tab/fields").around do
22
- tab = self.component_locals[:tab]
23
- if Lolita::Translation.translatable?(tab)
24
- self.send(:render_component,"lolita/translation",:language_wrap,:tab => tab, :content => let_content)
25
- else
26
- let_content
9
+ rake_tasks do
10
+ load "tasks/lolita_translation.rake"
11
+ end
27
12
  end
28
- end
29
13
 
30
- Lolita::Hooks.component(:"/lolita/configuration/nested_form/fields").around do
31
- tab = self.component_locals[:nested_form].parent
32
- if Lolita::Translation.translatable?(tab)
33
- self.send(:render_component,"lolita/translation",:language_wrap, :tab => tab, :content => let_content)
34
- else
35
- let_content
36
- end
37
14
  end
38
15
 
39
- Lolita::Hooks.component(:"/lolita/configuration/tabs/display").before do
40
- self.render_component "lolita/translation", :assets
41
- end
16
+ require 'lolita-translation/lolita/component_hooks.rb'
@@ -0,0 +1,220 @@
1
+ require 'i18n'
2
+ require 'lolita-translation/translated_string'
3
+ require 'lolita-translation/utils'
4
+
5
+ module Lolita
6
+ module Translation
7
+
8
+ class Record
9
+ class AbstractRecord
10
+ attr_reader :orm_record
11
+
12
+ def initialize(orm_record,configuration = nil)
13
+ @configuration = configuration
14
+ @orm_record = orm_record
15
+ end
16
+
17
+ def default_locale=(value)
18
+ nil
19
+ end
20
+
21
+ def locale
22
+ system_current_locale
23
+ end
24
+
25
+ def attribute name
26
+ nil
27
+ end
28
+
29
+ def translated_attribute name, options = {}
30
+ nil
31
+ end
32
+
33
+ def new_record?
34
+ nil
35
+ end
36
+
37
+ def association_key
38
+ nil
39
+ end
40
+
41
+ def has_translation_for?(locale)
42
+ nil
43
+ end
44
+
45
+ private
46
+
47
+ def adapter
48
+ Lolita::DBI::Base.create(orm_record.class)
49
+ end
50
+
51
+ def system_current_locale
52
+ ::I18n.locale
53
+ end
54
+
55
+ def system_default_locale
56
+ ::I18n.default_locale
57
+ end
58
+
59
+ def locale_field
60
+ @configuration && @configuration.locale_field_name.to_s
61
+ end
62
+
63
+ def translation_string(str,attr_name)
64
+ TranslatedString.new(str.to_s, self, attr_name)
65
+ end
66
+
67
+ def association_name
68
+ @configuration && @configuration.association_name
69
+ end
70
+
71
+ end
72
+
73
+ class ARRecord < AbstractRecord
74
+ def default_locale=(value)
75
+ if has_locale_column?
76
+ orm_record.send(:"#{locale_field}=",value)
77
+ else
78
+ super
79
+ end
80
+ end
81
+
82
+ def locale
83
+ if has_locale_column?
84
+ if value = orm_record.attributes[locale_field] and value.to_s.size > 0
85
+ value
86
+ else
87
+ super
88
+ end
89
+ else
90
+ system_default_locale
91
+ end
92
+ end
93
+
94
+ def attribute(name)
95
+ translation_string(orm_record.attributes[name.to_s],name)
96
+ end
97
+
98
+ def translated_attribute(name, options = {})
99
+ translation_record = find_translation_by_locale(options[:locale])
100
+ if translation_record and str = translation_string(translation_record.attributes[name.to_s],name) and str.size > 0
101
+ str
102
+ else
103
+ attribute(name)
104
+ end
105
+ end
106
+
107
+ def new_reocrd?
108
+ orm_record.new_record?
109
+ end
110
+
111
+ def association_key
112
+ association = adapter.reflect_on_association(association_name)
113
+ association.key
114
+ end
115
+
116
+ def has_translation_for?(locale)
117
+ !!find_translation_by_locale(locale)
118
+ end
119
+
120
+ private
121
+
122
+ def has_locale_column?
123
+ orm_record.class.column_names.include?(locale_field)
124
+ end
125
+
126
+ def translations
127
+ orm_record.translations
128
+ end
129
+
130
+ def find_translation_by_locale given_locale
131
+ translations.detect{|translation|
132
+ translation.locale.to_s == given_locale.to_s
133
+ }
134
+ end
135
+ end
136
+
137
+ class MongoidRecord < AbstractRecord
138
+
139
+ end
140
+
141
+ attr_reader :original_record, :default_locale, :orm_wrapper
142
+
143
+ def initialize(original_record, configuration = nil)
144
+ @configuration = configuration
145
+ @original_record = original_record
146
+ @orm_wrapper = get_orm_wrapper
147
+ @default_locale = @orm_wrapper.locale
148
+ @record_current_locale = nil
149
+ end
150
+
151
+ def attribute(name)
152
+ if default_locale.to_s == current_locale.to_s
153
+ @orm_wrapper.attribute(name)
154
+ else
155
+ @orm_wrapper.translated_attribute(name, :locale => current_locale)
156
+ end
157
+ end
158
+
159
+ def build_nested_translations
160
+ available_locales.each do |locale|
161
+ unless self.default_locale.to_s == locale.to_s
162
+ attributes = { :locale => locale.to_s }
163
+ original_record.translations.build(attributes) unless orm_wrapper.has_translation_for?(locale)
164
+ end
165
+ end
166
+ end
167
+
168
+ def default_locale=(value)
169
+ @orm_wrapper.default_locale = value
170
+ end
171
+
172
+ def in(locale)
173
+ old_locale = @record_current_locale
174
+ @record_current_locale = locale
175
+ if block_given?
176
+ yield
177
+ @record_current_locale = old_locale
178
+ end
179
+ end
180
+
181
+ def system_current_locale
182
+ ::I18n.locale
183
+ end
184
+
185
+ private
186
+
187
+ def available_locales
188
+ ::I18n.available_locales
189
+ end
190
+
191
+ def current_locale
192
+ @record_current_locale || system_current_locale
193
+ end
194
+
195
+ def get_orm_wrapper
196
+ if is_active_record?
197
+ ARRecord.new(original_record,@configuration)
198
+ elsif is_mongoid_record?
199
+ MongoidRecord.new(original_record,@configuration)
200
+ else
201
+ AbstractRecord.new(original_record,@configuration)
202
+ end
203
+ end
204
+
205
+ def is_mongoid_record?
206
+ Lolita::Translation::Utils.mongoid_class?(original_class)
207
+ end
208
+
209
+ def is_active_record?
210
+ Lolita::Translation::Utils.active_record_class?(original_class)
211
+ end
212
+
213
+ def original_class
214
+ original_record.class
215
+ end
216
+
217
+ end
218
+
219
+ end
220
+ end