has_many_translations 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
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
+