From f4c73763e5b3d65f3377fb1238a94122a1c272a4 Mon Sep 17 00:00:00 2001 From: hukl Date: Wed, 25 Feb 2009 22:37:22 +0100 Subject: updated globalize2 --- .../globalize2/lib/globalize/backend/static.rb | 3 +- .../i18n/missing_translations_raise_handler.rb | 27 +++++++ .../lib/globalize/model/active_record.rb | 6 +- .../lib/globalize/model/active_record/adapter.rb | 13 +++- .../globalize/model/active_record/translated.rb | 48 +++++++++--- vendor/plugins/globalize2/test/data/post.rb | 7 ++ .../test/model/active_record/migration_test.rb | 2 +- .../model/active_record/sti_translated_test.rb | 75 +++++++++++++++++++ .../test/model/active_record/translated_test.rb | 85 +++++++++++++++++++++- vendor/plugins/globalize2/test/test_helper.rb | 4 +- 10 files changed, 251 insertions(+), 19 deletions(-) create mode 100644 vendor/plugins/globalize2/lib/globalize/i18n/missing_translations_raise_handler.rb create mode 100644 vendor/plugins/globalize2/test/model/active_record/sti_translated_test.rb diff --git a/vendor/plugins/globalize2/lib/globalize/backend/static.rb b/vendor/plugins/globalize2/lib/globalize/backend/static.rb index 3903517..fb9e1fe 100644 --- a/vendor/plugins/globalize2/lib/globalize/backend/static.rb +++ b/vendor/plugins/globalize2/lib/globalize/backend/static.rb @@ -51,7 +51,8 @@ module Globalize translation(value, meta) end else - raise "unexpected translation type: #{result.inspect}" + result + # raise "unexpected translation type: #{result.inspect}" end end end diff --git a/vendor/plugins/globalize2/lib/globalize/i18n/missing_translations_raise_handler.rb b/vendor/plugins/globalize2/lib/globalize/i18n/missing_translations_raise_handler.rb new file mode 100644 index 0000000..e32be28 --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize/i18n/missing_translations_raise_handler.rb @@ -0,0 +1,27 @@ +# A simple exception handler that behaves like the default exception handler +# but also raises on missing translations. +# +# Useful for identifying missing translations during testing. +# +# E.g. +# +# require 'globalize/i18n/missing_translations_raise_handler +# I18n.exception_handler = :missing_translations_raise_handler +module I18n + class << self + def missing_translations_raise_handler(exception, locale, key, options) + raise exception + end + end + +# self.exception_handler = :missing_translations_raise_handler +end + +I18n.exception_handler = :missing_translations_raise_handler + +ActionView::Helpers::TranslationHelper.module_eval do + def translate(key, options = {}) + I18n.translate(key, options) + end + alias :t :translate +end diff --git a/vendor/plugins/globalize2/lib/globalize/model/active_record.rb b/vendor/plugins/globalize2/lib/globalize/model/active_record.rb index 450729c..9645842 100644 --- a/vendor/plugins/globalize2/lib/globalize/model/active_record.rb +++ b/vendor/plugins/globalize2/lib/globalize/model/active_record.rb @@ -6,7 +6,7 @@ require 'globalize/model/active_record/translated' module Globalize module Model module ActiveRecord - class << self + class << self def create_proxy_class(klass) Object.const_set "#{klass.name}Translation", Class.new(::ActiveRecord::Base){ belongs_to "#{klass.name.underscore}".intern @@ -24,10 +24,10 @@ module Globalize def define_accessors(klass, attr_names) attr_names.each do |attr_name| klass.send :define_method, attr_name, lambda { - globalize.fetch I18n.locale, attr_name + globalize.fetch self.class.locale, attr_name } klass.send :define_method, "#{attr_name}=", lambda {|val| - globalize.stash I18n.locale, attr_name, val + globalize.stash self.class.locale, attr_name, val self[attr_name] = val } end diff --git a/vendor/plugins/globalize2/lib/globalize/model/active_record/adapter.rb b/vendor/plugins/globalize2/lib/globalize/model/active_record/adapter.rb index 12d7564..d1c8db8 100644 --- a/vendor/plugins/globalize2/lib/globalize/model/active_record/adapter.rb +++ b/vendor/plugins/globalize2/lib/globalize/model/active_record/adapter.rb @@ -1,6 +1,12 @@ module Globalize module Model class AttributeStash < Hash + def contains?(locale, attr_name) + locale = locale.to_sym + self[locale] ||= {} + self[locale].has_key? attr_name + end + def read(locale, attr_name) locale = locale.to_sym self[locale] ||= {} @@ -17,13 +23,16 @@ module Globalize class Adapter def initialize(record) @record = record + + # TODO what exactly are the roles of cache and stash @cache = AttributeStash.new @stash = AttributeStash.new end def fetch(locale, attr_name) # locale = I18n.locale - @cache.read(locale, attr_name) || begin + is_cached = @cache.contains?(locale, attr_name) + is_cached ? @cache.read(locale, attr_name) : begin value = fetch_attribute locale, attr_name @cache.write locale, attr_name, value if value && value.locale == locale value @@ -47,6 +56,7 @@ module Globalize # Clears the cache def clear @cache.clear + @stash.clear end private @@ -61,6 +71,7 @@ module Globalize # Check the @globalize_set_translations cache first to see if we've just changed the # attribute and not saved yet. fallbacks.each do |fallback| + # TODO should we be checking stash or just cache? result = @stash.read(fallback, attr_name) || begin translation = translations.detect {|tr| tr.locale == fallback } translation && translation.send(attr_name) diff --git a/vendor/plugins/globalize2/lib/globalize/model/active_record/translated.rb b/vendor/plugins/globalize2/lib/globalize/model/active_record/translated.rb index 710cde5..c7ae9e9 100644 --- a/vendor/plugins/globalize2/lib/globalize/model/active_record/translated.rb +++ b/vendor/plugins/globalize2/lib/globalize/model/active_record/translated.rb @@ -19,18 +19,16 @@ module Globalize # Only set up once per class unless included_modules.include? InstanceMethods - class_inheritable_accessor :globalize_options + class_inheritable_accessor :globalize_options, :globalize_proxy + include InstanceMethods extend ClassMethods + alias_method_chain :reload, :globalize - proxy_class = Globalize::Model::ActiveRecord.create_proxy_class(self) - has_many :globalize_translations, :class_name => proxy_class.name, :extend => Extensions + self.globalize_proxy = Globalize::Model::ActiveRecord.create_proxy_class(self) + has_many :globalize_translations, :class_name => globalize_proxy.name, :extend => Extensions - after_save :update_globalize_record - - def i18n_attr(attribute_name) - self.name.underscore + "_translations.#{attribute_name}" - end + after_save :update_globalize_record end self.globalize_options = options @@ -41,6 +39,14 @@ module Globalize extend Callbacks Callbacks.instance_methods.each {|cb| send cb } end + + def locale=(locale) + @@locale = locale + end + + def locale + (defined?(@@locale) && @@locale) || I18n.locale + end end # Dummy Callbacks module. Extensions to Globalize2 can insert methods into here @@ -59,13 +65,13 @@ module Globalize def method_missing(method, *args) if method.to_s =~ /^find_by_(\w+)$/ && globalize_options[:translated_attributes].include?($1.to_sym) find(:first, :joins => :globalize_translations, - :conditions => [i18n_attr($1)+" = ? AND "+i18n_attr('locale')+" IN (?)", + :conditions => [ "#{i18n_attr($1)} = ? AND #{i18n_attr('locale')} IN (?)", args.first,I18n.fallbacks[I18n.locale].map{|tag| tag.to_s}]) else super end end - + def create_translation_table!(fields) translated_fields = self.globalize_options[:translated_attributes] translated_fields.each do |f| @@ -94,9 +100,27 @@ module Globalize translation_table_name = self.name.underscore + '_translations' self.connection.drop_table translation_table_name end + + private + + def i18n_attr(attribute_name) + self.base_class.name.underscore + "_translations.#{attribute_name}" + end end module InstanceMethods + def reload_with_globalize + globalize.clear + + # clear all globalized attributes + # TODO what's the best way to handle this? + self.class.globalize_options[:translated_attributes].each do |attr| + @attributes.delete attr.to_s + end + + reload_without_globalize + end + def globalize @globalize ||= Adapter.new self end @@ -104,6 +128,10 @@ module Globalize def update_globalize_record globalize.update_translations! end + + def translated_locales + globalize_translations.scoped(:select => 'DISTINCT locale').map {|gt| gt.locale.to_sym } + end end end end diff --git a/vendor/plugins/globalize2/test/data/post.rb b/vendor/plugins/globalize2/test/data/post.rb index 20a2495..fdfb7c0 100644 --- a/vendor/plugins/globalize2/test/data/post.rb +++ b/vendor/plugins/globalize2/test/data/post.rb @@ -6,3 +6,10 @@ end class Blog < ActiveRecord::Base has_many :posts, :order => 'id ASC' end + +class Parent < ActiveRecord::Base + translates :content +end + +class Child < Parent +end \ No newline at end of file diff --git a/vendor/plugins/globalize2/test/model/active_record/migration_test.rb b/vendor/plugins/globalize2/test/model/active_record/migration_test.rb index 09804c7..c539fb6 100644 --- a/vendor/plugins/globalize2/test/model/active_record/migration_test.rb +++ b/vendor/plugins/globalize2/test/model/active_record/migration_test.rb @@ -10,7 +10,7 @@ require File.join( File.dirname(__FILE__), '..', '..', 'data', 'post' ) class MigrationTest < ActiveSupport::TestCase def setup - reset_db! 'no_globalize_schema' + reset_db! File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'data', 'no_globalize_schema.rb')) end test 'globalize table added' do diff --git a/vendor/plugins/globalize2/test/model/active_record/sti_translated_test.rb b/vendor/plugins/globalize2/test/model/active_record/sti_translated_test.rb new file mode 100644 index 0000000..14d7d0f --- /dev/null +++ b/vendor/plugins/globalize2/test/model/active_record/sti_translated_test.rb @@ -0,0 +1,75 @@ +require File.join( File.dirname(__FILE__), '..', '..', 'test_helper' ) +require 'active_record' +require 'globalize/model/active_record' + +# Hook up model translation +ActiveRecord::Base.send(:include, Globalize::Model::ActiveRecord::Translated) + +# Load Post model +require File.join( File.dirname(__FILE__), '..', '..', 'data', 'post' ) + +class StiTranslatedTest < ActiveSupport::TestCase + def setup + I18n.locale = :'en-US' + I18n.fallbacks.clear + reset_db! File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'data', 'schema.rb')) + end + + def teardown + I18n.fallbacks.clear + end + + test "works with simple dynamic finders" do + foo = Child.create :content => 'foo' + Child.create :content => 'bar' + child = Child.find_by_content('foo') + assert_equal foo, child + end + + test 'change attribute on globalized model' do + child = Child.create :content => 'foo' + assert_equal [], child.changed + child.content = 'bar' + assert_equal [ 'content' ], child.changed + child.content = 'baz' + assert_member 'content', child.changed + end + + test 'change attribute on globalized model after locale switching' do + child = Child.create :content => 'foo' + assert_equal [], child.changed + child.content = 'bar' + I18n.locale = :de + assert_equal [ 'content' ], child.changed + end + + test 'fallbacks with lots of locale switching' do + I18n.fallbacks.map :'de-DE' => [ :'en-US' ] + child = Child.create :content => 'foo' + + I18n.locale = :'de-DE' + assert_equal 'foo', child.content + + I18n.locale = :'en-US' + child.update_attribute :content, 'bar' + + I18n.locale = :'de-DE' + assert_equal 'bar', child.content + end + + test "saves all locales, even after locale switching" do + child = Child.new :content => 'foo' + I18n.locale = 'de-DE' + child.content = 'bar' + I18n.locale = 'he-IL' + child.content = 'baz' + child.save + I18n.locale = 'en-US' + child = Child.first + assert_equal 'foo', child.content + I18n.locale = 'de-DE' + assert_equal 'bar', child.content + I18n.locale = 'he-IL' + assert_equal 'baz', child.content + end +end \ No newline at end of file diff --git a/vendor/plugins/globalize2/test/model/active_record/translated_test.rb b/vendor/plugins/globalize2/test/model/active_record/translated_test.rb index ec507e0..6bb7b26 100644 --- a/vendor/plugins/globalize2/test/model/active_record/translated_test.rb +++ b/vendor/plugins/globalize2/test/model/active_record/translated_test.rb @@ -12,7 +12,8 @@ class TranslatedTest < ActiveSupport::TestCase def setup I18n.locale = :'en-US' I18n.fallbacks.clear - reset_db! + reset_db! File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'data', 'schema.rb')) + ActiveRecord::Base.locale = nil end def teardown @@ -92,6 +93,13 @@ class TranslatedTest < ActiveSupport::TestCase assert_equal 'baz', Post.first.subject end + test "update_attributes failure" do + post = Post.create :subject => 'foo', :content => 'bar' + assert !post.update_attributes( { :subject => '' } ) + assert_nil post.reload.attributes['subject'] + assert_equal 'foo', post.subject + end + test "validates presence of :subject" do post = Post.new assert !post.save @@ -255,6 +263,81 @@ class TranslatedTest < ActiveSupport::TestCase I18n.locale = :'de-DE' assert_equal 'bar', post.subject end + + test 'reload' do + post = Post.create :subject => 'foo', :content => 'bar' + post.subject = 'baz' + assert_equal 'foo', post.reload.subject + end + + test 'complex writing and stashing' do + post = Post.create :subject => 'foo', :content => 'bar' + post.subject = nil + assert_nil post.subject + assert !post.valid? + end + + test 'translated class locale setting' do + assert ActiveRecord::Base.respond_to?(:locale) + assert_equal :'en-US', I18n.locale + assert_equal :'en-US', ActiveRecord::Base.locale + I18n.locale = :de + assert_equal :de, I18n.locale + assert_equal :de, ActiveRecord::Base.locale + ActiveRecord::Base.locale = :es + assert_equal :de, I18n.locale + assert_equal :es, ActiveRecord::Base.locale + I18n.locale = :fr + assert_equal :fr, I18n.locale + assert_equal :es, ActiveRecord::Base.locale + end + + test "untranslated class responds to locale" do + assert Blog.respond_to?(:locale) + end + + test "to ensure locales in different classes are the same" do + ActiveRecord::Base.locale = :de + assert_equal :de, ActiveRecord::Base.locale + assert_equal :de, Parent.locale + Parent.locale = :es + assert_equal :es, ActiveRecord::Base.locale + assert_equal :es, Parent.locale + end + + test "attribute saving goes by content locale and not global locale" do + ActiveRecord::Base.locale = :de + assert_equal :'en-US', I18n.locale + Post.create :subject => 'foo' + assert_equal :de, Post.first.globalize_translations.first.locale + end + + test "attribute loading goes by content locale and not global locale" do + post = Post.create :subject => 'foo' + assert_equal :'en-US', ActiveRecord::Base.locale + ActiveRecord::Base.locale = :de + assert_equal :'en-US', I18n.locale + post.update_attribute :subject, 'foo [de]' + assert_equal 'foo [de]', Post.first.subject + ActiveRecord::Base.locale = :'en-US' + assert_equal 'foo', Post.first.subject + end + + test "access content locale before setting" do + Globalize::Model::ActiveRecord::Translated::ActMethods.class_eval "remove_class_variable(:@@locale)" + assert_nothing_raised { ActiveRecord::Base.locale } + end + + test "translated_locales" do + Post.locale = :de + post = Post.create :subject => 'foo' + Post.locale = :es + post.update_attribute :subject, 'bar' + Post.locale = :fr + post.update_attribute :subject, 'baz' + assert_equal [ :de, :es, :fr ], post.translated_locales + assert_equal [ :de, :es, :fr ], Post.first.translated_locales + end end # TODO should validate_presence_of take fallbacks into account? maybe we need diff --git a/vendor/plugins/globalize2/test/test_helper.rb b/vendor/plugins/globalize2/test/test_helper.rb index 58b047d..956b352 100644 --- a/vendor/plugins/globalize2/test/test_helper.rb +++ b/vendor/plugins/globalize2/test/test_helper.rb @@ -7,14 +7,14 @@ require 'mocha' $LOAD_PATH << File.expand_path( File.dirname(__FILE__) + '/../lib' ) class ActiveSupport::TestCase - def reset_db!( schema = 'schema' ) + def reset_db!( schema_path ) ::ActiveRecord::Migration.verbose = false # Quiet down the migration engine ::ActiveRecord::Base.establish_connection({ :adapter => 'sqlite3', :dbfile => ':memory:' }) ::ActiveRecord::Base.silence do - load File.expand_path(File.join(File.dirname(__FILE__), 'data', schema + '.rb')) + load schema_path end end -- cgit v1.3