has_many_translations 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
22
+ *.db
data/README.rdoc ADDED
@@ -0,0 +1,16 @@
1
+ = has_many_translations
2
+
3
+ Makes models speak in tongues!
4
+
5
+ <tt>has_many_translations</tt>[http://github.com/Artforge/has_many_translations]
6
+
7
+ Installing from source
8
+
9
+ 1) cd /[YOUR SOURCE DIRECTORY]/has_many_translations/
10
+
11
+ 2) git pull
12
+
13
+ 3) rake build
14
+
15
+ 4) sudo gem install pkg/has_many_translations-0.2.x.gem (where x is latest version)
16
+
data/Rakefile ADDED
@@ -0,0 +1,48 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rcov/rcovtask'
5
+ require 'rake/rdoctask'
6
+
7
+ begin
8
+ require 'jeweler'
9
+ Jeweler::Tasks.new do |g|
10
+ g.name = 'has_many_translations'
11
+ g.summary = %(Makes models' speak in tongues)
12
+ g.description = %(Keep a DRY multilingual translation of your ActiveRecord models' textual attributes)
13
+ g.email = 'mjording@openogotham.com'
14
+ g.homepage = 'http://github.com/opengotham/has_many_translations'
15
+ g.authors = %w(opengotham)
16
+ g.add_dependency 'activerecord', '>= 2.1.0'
17
+ g.add_development_dependency 'shoulda'
18
+ g.add_development_dependency 'mocha'
19
+ g.add_runtime_dependency 'opengotham-rtranslate'
20
+ g.add_runtime_dependency 'activequeue'
21
+ g.add_runtime_dependency 'settingslogic'
22
+ end
23
+ Jeweler::GemcutterTasks.new
24
+ rescue LoadError
25
+ puts 'Jeweler (or a dependency) not available. Install it with: gem install jeweler'
26
+ end
27
+
28
+ Rake::TestTask.new do |t|
29
+ t.libs = %w(test)
30
+ t.pattern = 'test/**/*_test.rb'
31
+ end
32
+
33
+ Rcov::RcovTask.new do |t|
34
+ t.libs = %w(test)
35
+ t.pattern = 'test/**/*_test.rb'
36
+ end
37
+
38
+ task :test => :check_dependencies
39
+ task :default => :test
40
+
41
+ Rake::RDocTask.new do |r|
42
+ version = File.exist?('VERSION') ? File.read('VERSION') : nil
43
+ r.rdoc_dir = 'rdoc'
44
+ r.title = ['has_many_translations', version].compact.join(' ')
45
+ r.options << '--line-numbers' << '--inline-source'
46
+ r.rdoc_files.include('README*')
47
+ r.rdoc_files.include('lib/**/*.rb')
48
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.3.3
@@ -0,0 +1,10 @@
1
+ class HasManyTranslationsGenerator < Rails::Generator::Base
2
+ def manifest
3
+ record do |m|
4
+ m.migration_template 'migration.rb', File.join('db', 'migrate'), :migration_file_name => 'create_translations'
5
+
6
+ m.directory File.join('config', 'initializers')
7
+ m.template 'initializer.rb', File.join('config', 'initializers', 'has_many_translations.rb')
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ HasManyTranslations.configure do |config|
2
+ # Place any global options here. For example, in order to specify your own translations model to use
3
+ # throughout the application, simply specify:
4
+ #
5
+ # config.class_name = "MyCustomVersion"
6
+ #
7
+ # Any options passed to the "has_translations" method in the model itself will override this global
8
+ # configuration.
9
+ end
@@ -0,0 +1,33 @@
1
+ class CreateTranslations < ActiveRecord::Migration
2
+ def self.up #
3
+ create_table :translation_specs do |t|
4
+ t.belongs_to :translated, :polymorphic => true
5
+ t.string :codes
6
+ end
7
+ add_index :translation_specs, :codes
8
+ add_index :translation_specs, [:translated_id, :translated_type]
9
+
10
+ create_table :translations do |t|
11
+ t.belongs_to :translated, :polymorphic => true
12
+ t.string :attribute
13
+ t.text :value
14
+ t.string :locale_code
15
+ t.string :locale_name
16
+ t.string :origin_locale_code
17
+ t.boolean :machine_translation
18
+ t.timestamps
19
+ end
20
+ add_index :translations, [:locale_code, :attribute]
21
+ add_index :translations, [:translated_id, :translated_type]
22
+
23
+ change_table :users do |t|
24
+ add_column :users, :prefered_language, :string
25
+ end
26
+ end
27
+
28
+ def self.down
29
+ drop_table :translation_spec
30
+ drop_table :translations
31
+ remove_column :users, :prefered_language
32
+ end
33
+ end
@@ -0,0 +1,75 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{has_many_translations}
8
+ s.version = "0.3.3"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["opengotham"]
12
+ s.date = %q{2010-06-02}
13
+ s.description = %q{Keep a DRY multilingual translation of your ActiveRecord models' textual attributes}
14
+ s.email = %q{mjording@openogotham.com}
15
+ s.extra_rdoc_files = [
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "README.rdoc",
21
+ "Rakefile",
22
+ "VERSION",
23
+ "generators/has_many_translations/has_many_translations_generator.rb",
24
+ "generators/has_many_translations/templates/initializer.rb",
25
+ "generators/has_many_translations/templates/migration.rb",
26
+ "has_many_translations.gemspec",
27
+ "init.rb",
28
+ "lib/has_many_translations.rb",
29
+ "lib/has_many_translations/configuration.rb",
30
+ "lib/has_many_translations/control.rb",
31
+ "lib/has_many_translations/creation.rb",
32
+ "lib/has_many_translations/hmt_settings.rb",
33
+ "lib/has_many_translations/options.rb",
34
+ "lib/has_many_translations/translated.rb",
35
+ "lib/has_many_translations/translation.rb",
36
+ "lib/has_many_translations/translation_jobs.rb",
37
+ "lib/has_many_translations/translations.rb",
38
+ "lib/translation_spec.rb",
39
+ "tasks/has_many_translations_tasks.rake"
40
+ ]
41
+ s.homepage = %q{http://github.com/opengotham/has_many_translations}
42
+ s.rdoc_options = ["--charset=UTF-8"]
43
+ s.require_paths = ["lib"]
44
+ s.rubygems_version = %q{1.3.7}
45
+ s.summary = %q{Makes models' speak in tongues}
46
+
47
+ if s.respond_to? :specification_version then
48
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
49
+ s.specification_version = 3
50
+
51
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
52
+ s.add_runtime_dependency(%q<activerecord>, [">= 2.1.0"])
53
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
54
+ s.add_development_dependency(%q<mocha>, [">= 0"])
55
+ s.add_runtime_dependency(%q<opengotham-rtranslate>, [">= 0"])
56
+ s.add_runtime_dependency(%q<activequeue>, [">= 0"])
57
+ s.add_runtime_dependency(%q<settingslogic>, [">= 0"])
58
+ else
59
+ s.add_dependency(%q<activerecord>, [">= 2.1.0"])
60
+ s.add_dependency(%q<shoulda>, [">= 0"])
61
+ s.add_dependency(%q<mocha>, [">= 0"])
62
+ s.add_dependency(%q<opengotham-rtranslate>, [">= 0"])
63
+ s.add_dependency(%q<activequeue>, [">= 0"])
64
+ s.add_dependency(%q<settingslogic>, [">= 0"])
65
+ end
66
+ else
67
+ s.add_dependency(%q<activerecord>, [">= 2.1.0"])
68
+ s.add_dependency(%q<shoulda>, [">= 0"])
69
+ s.add_dependency(%q<mocha>, [">= 0"])
70
+ s.add_dependency(%q<opengotham-rtranslate>, [">= 0"])
71
+ s.add_dependency(%q<activequeue>, [">= 0"])
72
+ s.add_dependency(%q<settingslogic>, [">= 0"])
73
+ end
74
+ end
75
+
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__), 'lib', 'has_many_translations')
@@ -0,0 +1,27 @@
1
+ module HasManyTranslations
2
+
3
+ module Configuration
4
+ def configure
5
+ yield Configuration
6
+ end
7
+
8
+ class << self
9
+ # Simply stores a hash of options given to the +configure+ block.
10
+ def options
11
+ @options ||= {}
12
+ end
13
+
14
+ # If given a setter method name, will assign the first argument to the +options+ hash with
15
+ # the method name (sans "=") as the key. If given a getter method name, will attempt to
16
+ # a value from the +options+ hash for that key. If the key doesn't exist, defers to +super+.
17
+ def method_missing(symbol, *args)
18
+ if (method = symbol.to_s).sub!(/\=$/, '')
19
+ options[method.to_sym] = args.first
20
+ else
21
+ options.fetch(method.to_sym, super)
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,49 @@
1
+ module HasManyTranslations
2
+
3
+ module Control
4
+
5
+ def self.included(base) # :nodoc:
6
+ base.class_eval do
7
+ include InstanceMethods
8
+ alias_method_chain :create_translation?, :control
9
+ alias_method_chain :update_translation?, :control
10
+ end
11
+ end
12
+
13
+ module InstanceMethods
14
+ def skip_translation
15
+ with_translation_flag(:skip_translation) do
16
+ yield if block_given?
17
+ save
18
+ end
19
+ end
20
+
21
+ def skip_translation!
22
+ with_version_flag(:skip_translation) do
23
+ yield if block_given?
24
+ save!
25
+ end
26
+ end
27
+
28
+ def skip_translation?
29
+ !!@skip_translation
30
+ end
31
+
32
+ private
33
+ # Used for each control block, the +with_version_flag+ method sets a given variable to
34
+ # true and then executes the given block, ensuring that the variable is returned to a nil
35
+ # value before returning. This is useful to be certain that one of the control flag
36
+ # instance variables isn't inadvertently left in the "on" position by execution within the
37
+ # block raising an exception.
38
+ def with_translation_flag(flag)
39
+ begin
40
+ instance_variable_set("@#{flag}", true)
41
+ yield
42
+ ensure
43
+ instance_variable_set("@#{flag}", nil)
44
+ end
45
+ end
46
+
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,219 @@
1
+ require 'rtranslate'
2
+ module HasManyTranslations
3
+ # Adds the functionality necessary for translation actions on a has_translations instance of
4
+ # ActiveRecord::Base.
5
+ module Creation
6
+ def self.included(base) # :nodoc:
7
+ base.class_eval do
8
+ extend ClassMethods
9
+ include InstanceMethods
10
+ before_update :update_translation?
11
+
12
+ after_save :update_translations!
13
+ class << self
14
+ alias_method_chain :prepare_translated_options, :creation
15
+ end
16
+ end
17
+ end
18
+
19
+ # Class methods added to ActiveRecord::Base to facilitate the creation of new translations.
20
+ module ClassMethods
21
+ #@translator = Translate::RTranslate.new
22
+ # Overrides the basal +prepare_has_translations_options+ method defined in HasManyTranslations::Options
23
+ # to extract the <tt>:only</tt> and <tt>:except</tt> options into +has_many_translations_options+.
24
+ def prepare_translated_options_with_creation(options)
25
+ self.columns.map{|c|c.type == :string || c.type == :text ? c.name : nil}.compact.each{|name|
26
+ #alias_method "#{name}_before_translation", name.to_sym
27
+ #unless try(name)
28
+ define_method name, lambda { |*args|
29
+ #
30
+ unless self.translations.blank? || self.translations.first.origin_locale_code == self.hmt_locale || read_attribute(name.to_sym).nil?
31
+ trans = self.translations.first(:conditions => {:locale_code => self.hmt_locale, :attribute => name})
32
+ val = trans.nil? ? read_attribute(name.to_sym) : trans.value
33
+ #self.hmt_locale
34
+ else
35
+ #self.id
36
+ read_attribute(name.to_sym)
37
+ #try(name)
38
+ end
39
+ #HasManyTranslations.fetch(args.first || self.class.locale || I18n.locale, name)
40
+ }
41
+
42
+ alias_method "#{name}_before_type_cast", name
43
+
44
+ }
45
+
46
+ result = prepare_translated_options_without_creation(options)
47
+
48
+ self.has_many_translations_options[:only] = Array(options.delete(:only)).map(&:to_s).uniq if options[:only]
49
+ self.has_many_translations_options[:except] = Array(options.delete(:except)).map(&:to_s).uniq if options[:except]
50
+ #self.has_many_translations_options[:locales] = Array(options.delete(:locales)).map(&:to_s).uniq if options[:locales]
51
+ result
52
+ end
53
+
54
+ end
55
+
56
+ # Instance methods that determine whether to save a translation and actually perform the save.
57
+ module InstanceMethods
58
+
59
+ #private
60
+ #attr_accessor :translator
61
+ #@translator = Translate::RTranslate.new
62
+ if defined? Settings
63
+ @translator.key = Settings.google_api_key
64
+ end
65
+ def allowed_locales
66
+ t = TranslationSpec.first(:conditions => {:translated_id => self.id, :translated_type => self.class.to_s})
67
+ t.blank? ? nil : t.codes.split(',').map{|c| c.to_sym}
68
+ end
69
+ def locales=(codes)
70
+ t = TranslationSpec.first(:conditions => {:translated_id => self.id, :translated_type => self.class.to_s})
71
+ unless t.blank?
72
+ t.update_attribute('codes', codes.map{|c|c.to_s}.join(','))
73
+ else
74
+ TranslationSpec.create(:translated_id => self.id, :translated_type => self.class.to_s, :codes => codes.map{|c|c.to_s}.join(','))
75
+ end
76
+ end
77
+ def localize=(loc)
78
+ @locale = loc
79
+ end
80
+
81
+
82
+ # def hmt_default_locale
83
+ # return default_locale.to_sym if respond_to?(:default_locale)
84
+ # return self.class.default_locale.to_sym if self.class.respond_to?(:default_locale)
85
+ # I18n.default_locale
86
+ # end
87
+ def hmt_locale
88
+ @hmt_locale = respond_to?(:locale) ? self.locale.to_s : self.class.respond_to?(:locale) ? self.class.locale.to_s : I18n.locale.to_s
89
+
90
+ end
91
+
92
+ # Returns whether a new translation should be created upon updating the parent record.
93
+ def create_translation?
94
+ #determine if locale parameter is supported by this translated
95
+ # find out if we have a table created for all locales
96
+ # glob I18n.available_locales with whatever we use for the "study" available_locales
97
+ # I18n.available_locales.include?
98
+ #!translation_changes.blank?
99
+ true
100
+ end
101
+ def create_translation_for_locale?(locale)
102
+ #determine if locale parameter is supported by this translated
103
+ # find out if we have a table created for all locales
104
+ # glob I18n.available_locales with whatever we use for the "study" available_locales
105
+ # I18n.available_locales.include?
106
+ locales = Google::Language::Languages.keys & I18n.available_locales.map{|l|l.to_s}
107
+ locales.include?(locales)
108
+ end
109
+
110
+ # Creates a new translation upon updating the parent record.
111
+ def create_translation
112
+
113
+ translation.create(translation_attributes)
114
+ #reset_translation_changes
115
+ #reset_translation
116
+ end
117
+
118
+ # Returns whether the last translation should be updated upon updating the parent record.
119
+ # This method is overridden in HasManyTranslations::Control to account for a control block that
120
+ # merges changes onto the previous translation.
121
+ def update_translations!
122
+ #translated_columns.each do |attrib|
123
+ self.locales.each do |loc|
124
+ # put this in a option check blog to determine if the job should be queued?
125
+ queue_translation(loc)
126
+ #ActiveQueue::Queue.enqueue(TranslationJobs::AutoTranslateJob,{:translated_id => self.id,:translated_type => self.type, :origin_locale => self.hmt_locale, :destination_locale => loc.to_s})
127
+ #update_all_attributes_translation(loc, self.hmt_locale)
128
+ end
129
+ #end
130
+ end
131
+
132
+ def update_translation?
133
+ unless self.translations.blank? || self.translations.first.origin_locale_code == self.hmt_locale
134
+ dirty_translations = self.translations.all(:conditions => {:translated_id => self.id, :locale_code => self.hmt_locale})
135
+ dirty_translations.each do |dt|
136
+ dt.value = try(dt.attribute)
137
+ dt.save
138
+ end
139
+ return false
140
+ end
141
+ end
142
+
143
+ def update_all_attributes_translation(loc, origin_locale)
144
+ self.translated_columns.each do |attrib|
145
+ update_translation(attrib, loc, origin_locale)
146
+ end
147
+ end
148
+ # Updates the last translation's changes by appending the current translation changes.
149
+ def update_translation(attrib, loc, origin_locale)
150
+ unless translations.first(:conditions => {:attribute => attrib, :locale_code => loc.to_s})
151
+ update_translation!(attrib, loc, origin_locale.to_s)
152
+ end
153
+ end
154
+
155
+ def update_translation!(attrib, loc, origin_locale, options = {})
156
+ @translator ||= Translate::RTranslate.new
157
+ if defined? HmtSettings
158
+ @translator.key = HmtSettings.google_api_key
159
+ end
160
+ translation_val = @translator.translate(try(attrib), :from => origin_locale.to_s, :to => loc.to_s)
161
+ translations.create(:attribute => attrib, :locale_code => loc.to_s, :value => translation_val, :locale_name => Google::Language::Languages[loc.to_s], :machine_translation => true, :origin_locale_code => origin_locale ) unless translation_val.nil? || translation_val.match('Error: ')
162
+ end
163
+
164
+
165
+ # Returns an array of column names that should be included in the translation
166
+ # If <tt>has_many_translations_options[:only]</tt> is specified, only those columns
167
+ # will be translationed. Otherwise, if <tt>has_many_translations_options[:except]</tt> is specified,
168
+ # all columns will be translationed other than those specified. Without either option, the
169
+ # default is to translation all text & string columns. At any rate, the four "automagic" timestamp
170
+ # columns maintained by Rails are never translationed.
171
+ def translated_columns
172
+ textual_columns = self.class.columns.map{|c|c.type == :string || c.type == :text ? c.name : nil}.compact
173
+ textual_columns = self.has_many_translations_options[:only] ? textual_columns & self.has_many_translations_options[:only] : textual_columns
174
+ textual_columns = self.has_many_translations_options[:except] ? textual_columns - self.has_many_translations_options[:except] : textual_columns
175
+ return textual_columns
176
+
177
+ end
178
+ def queue_translation(loc)
179
+ #ActiveQueue::Queue.enqueue(TranslationJobs::AutoTranslateJob,{ :translated_id => self.id, :translated_type => self.class.to_s, :origin_locale => self.hmt_locale, :destination_locale => loc })
180
+ ActiveQueue::Job.new(:val => { :translated_id => self.id, :translated_type => self.class.to_s, :origin_locale => self.hmt_locale, :destination_locale => loc },:job_klass => "TranslationJobs::AutoTranslateJob",:adapter => "resque").enqueue
181
+ #ActiveQueue::Job.new(:value => TranslationJobs::AutoTranslateJob.new(:translated_id => self.id, :translated_type => self.class.to_s, :origin_locale => self.hmt_locale, :destination_locale => loc), :adapter => "resque", :queue_name => :file_queue).enqueue
182
+ end
183
+ def queue_translations
184
+ self.locales.each do |loc|
185
+ queue_translation(loc)
186
+ end
187
+ # Resque.enqueue(TranslationJobs::MachineTranslationJob.new(self.id, self.type))
188
+ #ActiveQueue::Queue.enqueue(TranslationJobs::MachineTranslationJob,{:translated_id => self.id,:translated_type => self.type, :origin_locale => self.hmt_locale})
189
+ #Delayed::Job.enqueue(TranslationJobs::MachineTranslationJob.new({ :translated_id => self.id,:translated_type => self.class.to_s, :origin_locale => self.hmt_locale.to_s })
190
+ #job = TranslationJobs::MachineTranslationJob.new(self.id, self.type, self.hmt_locale)
191
+ end
192
+ def locales
193
+
194
+ if allowed_locales
195
+ retloc = allowed_locales.map{|l|l.to_s}
196
+ elsif super_locales.present?
197
+ super_locales.each do |sloc|
198
+ retloc.nil? ? retloc = eval("self.#{sloc}.locales") : retloc | eval("self.#{sloc}.locales")
199
+ end
200
+ else
201
+ retloc = has_many_translations_options[:locales] && I18n && Google ? has_many_translations_options[:locales] & Google::Language::Languages.keys : Google::Language::Languages.keys & I18n.available_locales.map{|l|l.to_s}
202
+ end
203
+ return retloc
204
+ # I18n.available_locales.map(&:to_s)
205
+ end
206
+
207
+ def super_locales
208
+ if I18n && Google
209
+ self.class.reflect_on_all_associations(:belongs_to).map{|a|eval("#{a.name.to_s.capitalize}.translated?") ? a.name.to_s : nil}.compact
210
+ end
211
+ end
212
+ # Specifies the attributes used during translation creation. This is separated into its own
213
+ # method so that it can be overridden by the HasManyTranslations::Users feature.
214
+ # def translation_attributes
215
+ # {:changes => translation_changes, :number => last_translation + 1}
216
+ # end
217
+ end
218
+ end
219
+ end
@@ -0,0 +1,4 @@
1
+ class HmtSettings < Settingslogic
2
+ source "#{Rails.root}/config/settings.yml"
3
+ namespace Rails.env
4
+ end
@@ -0,0 +1,48 @@
1
+ module HasManyTranslations
2
+ # Provides +has_translations+ options conversion and cleanup.
3
+
4
+ module Options
5
+
6
+ def self.included(base) # :nodoc:
7
+ base.class_eval do
8
+ extend ClassMethods
9
+ end
10
+ end
11
+
12
+ # Class methods that provide preparation of options passed to the +has_translations+ method.
13
+ module ClassMethods
14
+ # The +prepare_has_translations_options+ method has three purposes:
15
+ # 1. Populate the provided options with default values where needed
16
+ # 2. Prepare options for use with the +has_many+ association
17
+ # 3. Save user-configurable options in a class-level variable
18
+ #
19
+ # Options are given priority in the following order:
20
+ # 1. Those passed directly to the +translated+ method
21
+ # 2. Those specified in an initializer +configure+ block
22
+ # 3. Default values specified in +prepare_has_translations_options+
23
+ #
24
+ # The method is overridden in feature modules that require specific options outside the
25
+ # standard +has_many+ associations.
26
+ def prepare_translated_options(options)
27
+ options.symbolize_keys!
28
+ options.reverse_merge!(Configuration.options)
29
+ options.reverse_merge!(
30
+ :class_name => 'HasManyTranslations::Translation',
31
+ :dependent => :delete_all
32
+ )
33
+ class_inheritable_accessor :has_many_translations_options
34
+ class_inheritable_accessor :translator
35
+ self.translator = Translate::RTranslate.new
36
+ if defined? HmtSettings
37
+ self.translator.key = HmtSettings.google_api_key
38
+ end
39
+ self.has_many_translations_options = options.dup
40
+
41
+ options.merge!(
42
+ :as => :translated,
43
+ :extend => Array(options[:extend]).unshift(Translations)
44
+ )
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,36 @@
1
+ module HasManyTranslations
2
+ # Simply adds a flag to determine whether a model class is has_translations.
3
+ module Translated
4
+
5
+ def self.extended(base) # :nodoc:
6
+ base.class_eval do
7
+ class << self
8
+ alias_method_chain :translated, :flag
9
+ end
10
+ end
11
+ end
12
+ # Overrides the +translated?+ method to first define the +translated?+ class method before
13
+ # deferring to the original +translated+.
14
+ def translated_with_flag(*args)
15
+ translated_without_flag(*args)
16
+
17
+ class << self
18
+
19
+ def translated?
20
+ true
21
+ end
22
+
23
+ end
24
+ end
25
+
26
+ # For all ActiveRecord::Base models that do not call the +translated?+ method, the +has_translations?+
27
+ # method will return false.
28
+ def translated?
29
+ false
30
+ end
31
+
32
+
33
+
34
+
35
+ end
36
+ end
@@ -0,0 +1,11 @@
1
+ module HasManyTranslations
2
+ # The ActiveRecord model representing translations.
3
+ class Translation < ActiveRecord::Base
4
+ # Associate polymorphically with the parent record.
5
+ belongs_to :translated, :polymorphic => true
6
+ def initial?
7
+ number == 1
8
+ end
9
+ end
10
+ end
11
+
@@ -0,0 +1,33 @@
1
+
2
+ module TranslationJobs
3
+ class MachineTranslationJob
4
+ attr_accessor :translated_id, :translated_type
5
+ def initialize(options)
6
+ @translated_id = options["translated_id"] || options[:translated_id]
7
+ @translated_type = options["translated_type"] || options[:translated_type]
8
+ end
9
+ def perform
10
+ translatable = Kernel.const_get(@translated_type).find(@translated_id)
11
+ translatable.update_translations!
12
+
13
+ end
14
+ end
15
+
16
+ class AutoTranslateJob
17
+ attr_accessor :translated_id, :translated_type, :origin_locale, :destination_locale
18
+
19
+ def initialize(options)
20
+ @translated_id = options["translated_id"]||options[:translated_id]
21
+ @translated_type = options["translated_type"]||options[:translated_type]
22
+ @origin_locale = options["origin_locale"]||options[:origin_locale]
23
+ @destination_locale = options["destination_locale"]|| options[:destination_locale]
24
+ end
25
+
26
+ def perform(options = nil)
27
+ translatable = Kernel.const_get(@translated_type).find(@translated_id)
28
+ translatable.update_all_attributes_translation(@destination_locale, @origin_locale)
29
+ end
30
+
31
+
32
+ end
33
+ end
@@ -0,0 +1,19 @@
1
+ module HasManyTranslations
2
+ # An extension module for the +has_many+ association with translations.
3
+ module Translations
4
+ # Returns all translations for given language.
5
+
6
+ def by_lang(lang)
7
+ all(:conditions => "#{aliased_table_name}.locale_code eq '#{lang}'")
8
+ end
9
+
10
+ # def by_locale(locale)
11
+ # first(:conditions => { :locale => locale.to_s })
12
+ # end
13
+ #
14
+ # def by_locales(locales)
15
+ # all(:conditions => { :locale => locales.map(&:to_s) })
16
+ # end
17
+ end
18
+
19
+ end
@@ -0,0 +1,37 @@
1
+ Dir[File.join(File.dirname(__FILE__), 'has_many_translations', '*.rb')].each{|f| require f }
2
+
3
+ require 'rtranslate'
4
+ require 'activequeue'
5
+
6
+ # The base module that gets included in ActiveRecord::Base. See the documentation for
7
+ # HasManyTranslations::ClassMethods for more useful information.
8
+ module HasManyTranslations
9
+
10
+
11
+ def self.included(base) # :nodoc:
12
+ base.class_eval do
13
+ extend ClassMethods
14
+ extend Translated
15
+ end
16
+ end
17
+
18
+ module ClassMethods
19
+ def translated(options = {}, &block)
20
+ return if translated?
21
+
22
+ include Options
23
+ include TranslationJobs
24
+ include Creation
25
+ include Translations
26
+ prepare_translated_options(options)
27
+ has_many :translations, options, &block
28
+
29
+ end
30
+
31
+ end
32
+
33
+ extend Configuration
34
+
35
+ end
36
+
37
+ ActiveRecord::Base.send(:include, HasManyTranslations)
@@ -0,0 +1,3 @@
1
+ class TranslationSpec < ActiveRecord::Base
2
+ belongs_to :translated, :polymorphic => true
3
+ end
@@ -0,0 +1,7 @@
1
+ namespace :has_many_traanslations do
2
+ desc "Install new locale."
3
+ task :install_locale do
4
+ true
5
+ end
6
+
7
+ end
metadata ADDED
@@ -0,0 +1,172 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: has_many_translations
3
+ version: !ruby/object:Gem::Version
4
+ hash: 21
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 3
9
+ - 3
10
+ version: 0.3.3
11
+ platform: ruby
12
+ authors:
13
+ - opengotham
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-06-02 00:00:00 -04:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: activerecord
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 11
30
+ segments:
31
+ - 2
32
+ - 1
33
+ - 0
34
+ version: 2.1.0
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: shoulda
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 3
46
+ segments:
47
+ - 0
48
+ version: "0"
49
+ type: :development
50
+ version_requirements: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ name: mocha
53
+ prerelease: false
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ hash: 3
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ type: :development
64
+ version_requirements: *id003
65
+ - !ruby/object:Gem::Dependency
66
+ name: opengotham-rtranslate
67
+ prerelease: false
68
+ requirement: &id004 !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ hash: 3
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ type: :runtime
78
+ version_requirements: *id004
79
+ - !ruby/object:Gem::Dependency
80
+ name: activequeue
81
+ prerelease: false
82
+ requirement: &id005 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ hash: 3
88
+ segments:
89
+ - 0
90
+ version: "0"
91
+ type: :runtime
92
+ version_requirements: *id005
93
+ - !ruby/object:Gem::Dependency
94
+ name: settingslogic
95
+ prerelease: false
96
+ requirement: &id006 !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ hash: 3
102
+ segments:
103
+ - 0
104
+ version: "0"
105
+ type: :runtime
106
+ version_requirements: *id006
107
+ description: Keep a DRY multilingual translation of your ActiveRecord models' textual attributes
108
+ email: mjording@openogotham.com
109
+ executables: []
110
+
111
+ extensions: []
112
+
113
+ extra_rdoc_files:
114
+ - README.rdoc
115
+ files:
116
+ - .gitignore
117
+ - README.rdoc
118
+ - Rakefile
119
+ - VERSION
120
+ - generators/has_many_translations/has_many_translations_generator.rb
121
+ - generators/has_many_translations/templates/initializer.rb
122
+ - generators/has_many_translations/templates/migration.rb
123
+ - has_many_translations.gemspec
124
+ - init.rb
125
+ - lib/has_many_translations.rb
126
+ - lib/has_many_translations/configuration.rb
127
+ - lib/has_many_translations/control.rb
128
+ - lib/has_many_translations/creation.rb
129
+ - lib/has_many_translations/hmt_settings.rb
130
+ - lib/has_many_translations/options.rb
131
+ - lib/has_many_translations/translated.rb
132
+ - lib/has_many_translations/translation.rb
133
+ - lib/has_many_translations/translation_jobs.rb
134
+ - lib/has_many_translations/translations.rb
135
+ - lib/translation_spec.rb
136
+ - tasks/has_many_translations_tasks.rake
137
+ has_rdoc: true
138
+ homepage: http://github.com/opengotham/has_many_translations
139
+ licenses: []
140
+
141
+ post_install_message:
142
+ rdoc_options:
143
+ - --charset=UTF-8
144
+ require_paths:
145
+ - lib
146
+ required_ruby_version: !ruby/object:Gem::Requirement
147
+ none: false
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ hash: 3
152
+ segments:
153
+ - 0
154
+ version: "0"
155
+ required_rubygems_version: !ruby/object:Gem::Requirement
156
+ none: false
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ hash: 3
161
+ segments:
162
+ - 0
163
+ version: "0"
164
+ requirements: []
165
+
166
+ rubyforge_project:
167
+ rubygems_version: 1.3.7
168
+ signing_key:
169
+ specification_version: 3
170
+ summary: Makes models' speak in tongues
171
+ test_files: []
172
+