summaryrefslogtreecommitdiff
path: root/vendor/plugins/globalize2/lib/globalize/model
diff options
context:
space:
mode:
authorhukl <hukl@eight.local>2009-02-07 15:50:40 +0100
committerhukl <hukl@eight.local>2009-02-07 15:50:40 +0100
commit36a2f1f3c085dd81171cf7d8220770d4ff921ab3 (patch)
tree5ded15331b192bf428af4c94d46d1abb28ef0690 /vendor/plugins/globalize2/lib/globalize/model
parentce9645d0092d42c7bf8781378181ffbd4ff3d088 (diff)
added globalize2 plugin as well as some modifications
which use the new translation facilities. backend mostly.
Diffstat (limited to 'vendor/plugins/globalize2/lib/globalize/model')
-rw-r--r--vendor/plugins/globalize2/lib/globalize/model/active_record.rb38
-rw-r--r--vendor/plugins/globalize2/lib/globalize/model/active_record/adapter.rb77
-rw-r--r--vendor/plugins/globalize2/lib/globalize/model/active_record/translated.rb111
3 files changed, 226 insertions, 0 deletions
diff --git a/vendor/plugins/globalize2/lib/globalize/model/active_record.rb b/vendor/plugins/globalize2/lib/globalize/model/active_record.rb
new file mode 100644
index 0000000..450729c
--- /dev/null
+++ b/vendor/plugins/globalize2/lib/globalize/model/active_record.rb
@@ -0,0 +1,38 @@
1require 'globalize/translation'
2require 'globalize/locale/fallbacks'
3require 'globalize/model/active_record/adapter'
4require 'globalize/model/active_record/translated'
5
6module Globalize
7 module Model
8 module ActiveRecord
9 class << self
10 def create_proxy_class(klass)
11 Object.const_set "#{klass.name}Translation", Class.new(::ActiveRecord::Base){
12 belongs_to "#{klass.name.underscore}".intern
13
14 def locale
15 read_attribute(:locale).to_sym
16 end
17
18 def locale=(locale)
19 write_attribute(:locale, locale.to_s)
20 end
21 }
22 end
23
24 def define_accessors(klass, attr_names)
25 attr_names.each do |attr_name|
26 klass.send :define_method, attr_name, lambda {
27 globalize.fetch I18n.locale, attr_name
28 }
29 klass.send :define_method, "#{attr_name}=", lambda {|val|
30 globalize.stash I18n.locale, attr_name, val
31 self[attr_name] = val
32 }
33 end
34 end
35 end
36 end
37 end
38end \ No newline at end of file
diff --git a/vendor/plugins/globalize2/lib/globalize/model/active_record/adapter.rb b/vendor/plugins/globalize2/lib/globalize/model/active_record/adapter.rb
new file mode 100644
index 0000000..12d7564
--- /dev/null
+++ b/vendor/plugins/globalize2/lib/globalize/model/active_record/adapter.rb
@@ -0,0 +1,77 @@
1module Globalize
2 module Model
3 class AttributeStash < Hash
4 def read(locale, attr_name)
5 locale = locale.to_sym
6 self[locale] ||= {}
7 self[locale][attr_name]
8 end
9
10 def write(locale, attr_name, value)
11 locale = locale.to_sym
12 self[locale] ||= {}
13 self[locale][attr_name] = value
14 end
15 end
16
17 class Adapter
18 def initialize(record)
19 @record = record
20 @cache = AttributeStash.new
21 @stash = AttributeStash.new
22 end
23
24 def fetch(locale, attr_name)
25 # locale = I18n.locale
26 @cache.read(locale, attr_name) || begin
27 value = fetch_attribute locale, attr_name
28 @cache.write locale, attr_name, value if value && value.locale == locale
29 value
30 end
31 end
32
33 def stash(locale, attr_name, value)
34 @stash.write locale, attr_name, value
35 @cache.write locale, attr_name, value
36 end
37
38 def update_translations!
39 @stash.each do |locale, attrs|
40 translation = @record.globalize_translations.find_or_initialize_by_locale(locale.to_s)
41 attrs.each{|attr_name, value| translation[attr_name] = value }
42 translation.save!
43 end
44 @stash.clear
45 end
46
47 # Clears the cache
48 def clear
49 @cache.clear
50 end
51
52 private
53
54 def fetch_attribute(locale, attr_name)
55 fallbacks = I18n.fallbacks[locale].map{|tag| tag.to_s}.map(&:to_sym)
56 translations = @record.globalize_translations.by_locales(fallbacks)
57 result, requested_locale = nil, locale
58
59 # Walk through the fallbacks, starting with the current locale itself, and moving
60 # to the next best choice, until we find a match.
61 # Check the @globalize_set_translations cache first to see if we've just changed the
62 # attribute and not saved yet.
63 fallbacks.each do |fallback|
64 result = @stash.read(fallback, attr_name) || begin
65 translation = translations.detect {|tr| tr.locale == fallback }
66 translation && translation.send(attr_name)
67 end
68 if result
69 locale = fallback
70 break
71 end
72 end
73 result && Translation::Attribute.new(result, :locale => locale, :requested_locale => requested_locale)
74 end
75 end
76 end
77end
diff --git a/vendor/plugins/globalize2/lib/globalize/model/active_record/translated.rb b/vendor/plugins/globalize2/lib/globalize/model/active_record/translated.rb
new file mode 100644
index 0000000..710cde5
--- /dev/null
+++ b/vendor/plugins/globalize2/lib/globalize/model/active_record/translated.rb
@@ -0,0 +1,111 @@
1module Globalize
2 module Model
3
4 class MigrationError < StandardError; end
5 class UntranslatedMigrationField < MigrationError; end
6 class MigrationMissingTranslatedField < MigrationError; end
7 class BadMigrationFieldType < MigrationError; end
8
9 module ActiveRecord
10 module Translated
11 def self.included(base)
12 base.extend ActMethods
13 end
14
15 module ActMethods
16 def translates(*attr_names)
17 options = attr_names.extract_options!
18 options[:translated_attributes] = attr_names
19
20 # Only set up once per class
21 unless included_modules.include? InstanceMethods
22 class_inheritable_accessor :globalize_options
23 include InstanceMethods
24 extend ClassMethods
25
26 proxy_class = Globalize::Model::ActiveRecord.create_proxy_class(self)
27 has_many :globalize_translations, :class_name => proxy_class.name, :extend => Extensions
28
29 after_save :update_globalize_record
30
31 def i18n_attr(attribute_name)
32 self.name.underscore + "_translations.#{attribute_name}"
33 end
34 end
35
36 self.globalize_options = options
37 Globalize::Model::ActiveRecord.define_accessors(self, attr_names)
38
39 # Import any callbacks that have been defined by extensions to Globalize2
40 # and run them.
41 extend Callbacks
42 Callbacks.instance_methods.each {|cb| send cb }
43 end
44 end
45
46 # Dummy Callbacks module. Extensions to Globalize2 can insert methods into here
47 # and they'll be called at the end of the translates class method.
48 module Callbacks
49 end
50
51 # Extension to the has_many :globalize_translations association
52 module Extensions
53 def by_locales(locales)
54 find :all, :conditions => { :locale => locales.map(&:to_s) }
55 end
56 end
57
58 module ClassMethods
59 def method_missing(method, *args)
60 if method.to_s =~ /^find_by_(\w+)$/ && globalize_options[:translated_attributes].include?($1.to_sym)
61 find(:first, :joins => :globalize_translations,
62 :conditions => [i18n_attr($1)+" = ? AND "+i18n_attr('locale')+" IN (?)",
63 args.first,I18n.fallbacks[I18n.locale].map{|tag| tag.to_s}])
64 else
65 super
66 end
67 end
68
69 def create_translation_table!(fields)
70 translated_fields = self.globalize_options[:translated_attributes]
71 translated_fields.each do |f|
72 raise MigrationMissingTranslatedField, "Missing translated field #{f}" unless fields[f]
73 end
74 fields.each do |name, type|
75 unless translated_fields.member? name
76 raise UntranslatedMigrationField, "Can't migrate untranslated field: #{name}"
77 end
78 unless [ :string, :text ].member? type
79 raise BadMigrationFieldType, "Bad field type for #{name}, should be :string or :text"
80 end
81 end
82 translation_table_name = self.name.underscore + '_translations'
83 self.connection.create_table(translation_table_name) do |t|
84 t.references self.table_name.singularize
85 t.string :locale
86 fields.each do |name, type|
87 t.column name, type
88 end
89 t.timestamps
90 end
91 end
92
93 def drop_translation_table!
94 translation_table_name = self.name.underscore + '_translations'
95 self.connection.drop_table translation_table_name
96 end
97 end
98
99 module InstanceMethods
100 def globalize
101 @globalize ||= Adapter.new self
102 end
103
104 def update_globalize_record
105 globalize.update_translations!
106 end
107 end
108 end
109 end
110 end
111end \ No newline at end of file