diff options
Diffstat (limited to 'vendor/plugins/globalize2')
28 files changed, 1886 insertions, 0 deletions
diff --git a/vendor/plugins/globalize2/LICENSE b/vendor/plugins/globalize2/LICENSE new file mode 100644 index 000000000..94a6b8160 --- /dev/null +++ b/vendor/plugins/globalize2/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2008, 2009 Joshua Harvey + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.
\ No newline at end of file diff --git a/vendor/plugins/globalize2/README.textile b/vendor/plugins/globalize2/README.textile new file mode 100644 index 000000000..e47e9bf37 --- /dev/null +++ b/vendor/plugins/globalize2/README.textile @@ -0,0 +1,86 @@ +h1. Globalize2 + +Globalize2 is the successor of Globalize for Rails. + +It is compatible with and builds on the new "I18n api in Ruby on Rails":http://guides.rubyonrails.org/i18n.html. and adds model translations to ActiveRecord. + +Globalize2 is much more lightweight and compatible than its predecessor was. Model translations in Globalize2 use default ActiveRecord features and do not limit any ActiveRecord functionality any more. + +h2. Requirements + +ActiveRecord +I18n + +(or Rails > 2.2) + +h2. Installation + +To install Globalize2 with its default setup just use: + +<pre><code> +script/plugin install git://github.com/joshmh/globalize2.git +</code></pre> + +h2. Model translations + +Model translations allow you to translate your models' attribute values. E.g. + +<pre><code> +class Post < ActiveRecord::Base + translates :title, :text +end +</code></pre> + +Allows you to values for the attributes :title and :text per locale: + +<pre><code> +I18n.locale = :en +post.title # => Globalize2 rocks! + +I18n.locale = :he +post.title # => גלובאלייז2 שולט! +</code></pre> + +In order to make this work, you'll need to add the appropriate translation tables. Globalize2 comes with a handy helper method to help you do this. It's called @create_translation_table!@. Here's an example: + +<pre><code> +class CreatePosts < ActiveRecord::Migration + def self.up + create_table :posts do |t| + t.timestamps + end + Post.create_translation_table! :title => :string, :text => :text + end + def self.down + drop_table :posts + Post.drop_translation_table! + end +end +</code></pre> + +Note that the ActiveRecord model @Post@ must already exist and have a @translates@ directive listing the translated fields. + +h2. Migration from Globalize + +See this script by Tomasz Stachewicz: http://gist.github.com/120867 + +h2. Changes since Globalize2 v0.1.0 + +* The association globalize_translations has been renamed to translations. + +h2. Alternative Solutions + +* "Veger's fork":http://github.com/veger/globalize2 - uses default AR schema for the default locale, delegates to the translations table for other locales only +* "TranslatableColumns":http://github.com/iain/translatable_columns - have multiple languages of the same attribute in a model (Iain Hecker) +* "localized_record":http://github.com/glennpow/localized_record - allows records to have localized attributes without any modifications to the database (Glenn Powell) +* "model_translations":http://github.com/janne/model_translations - Minimal implementation of Globalize2 style model translations (Jan Andersson) + +h2. Related solutions + +* "globalize2_versioning":http://github.com/joshmh/globalize2_versioning - acts_as_versioned style versioning for Globalize2 (Joshua Harvey) +* "i18n_multi_locales_validations":http://github.com/ZenCocoon/i18n_multi_locales_validations - multi-locales attributes validations to validates attributes from Globalize2 translations models (Sébastien Grosjean) +* "Globalize2 Demo App":http://github.com/svenfuchs/globalize2-demo - demo application for Globalize2 (Sven Fuchs)</li> +* "migrate_from_globalize1":http://gist.github.com/120867 - migrate model translations from Globalize1 to Globalize2 (Tomasz Stachewicz)</li> +* "easy_globalize2_accessors":http://github.com/astropanic/easy_globalize2_accessors - easily access (read and write) globalize2-translated fields (astropanic, Tomasz Stachewicz)</li> +* "globalize2-easy-translate":http://github.com/bsamman/globalize2-easy-translate - adds methods to easily access or set translated attributes to your model (bsamman)</li> +* "batch_translations":http://github.com/alvarezrilla/batch_translations - allow saving multiple Globalize2 translations in the same request (Jose Alvarez Rilla)</li> diff --git a/vendor/plugins/globalize2/Rakefile b/vendor/plugins/globalize2/Rakefile new file mode 100644 index 000000000..bc35dada4 --- /dev/null +++ b/vendor/plugins/globalize2/Rakefile @@ -0,0 +1,39 @@ +require 'rake' +require 'rake/testtask' +require 'rake/rdoctask' + +desc 'Default: run unit tests.' +task :default => :test + +desc 'Test the globalize2 plugin.' +Rake::TestTask.new(:test) do |t| + t.libs << 'lib' + t.pattern = 'test/**/*_test.rb' + t.verbose = true +end + +desc 'Generate documentation for the globalize2 plugin.' +Rake::RDocTask.new(:rdoc) do |rdoc| + rdoc.rdoc_dir = 'rdoc' + rdoc.title = 'Globalize2' + rdoc.options << '--line-numbers' << '--inline-source' + rdoc.rdoc_files.include('README') + rdoc.rdoc_files.include('lib/**/*.rb') +end + +begin + require 'jeweler' + Jeweler::Tasks.new do |s| + s.name = "globalize2" + s.summary = "Rails I18n: de-facto standard library for ActiveRecord data translation" + s.description = "Rails I18n: de-facto standard library for ActiveRecord data translation" + s.email = "joshmh@gmail.com" + s.homepage = "http://github.com/joshmh/globalize2" + # s.rubyforge_project = '' + s.authors = ["Sven Fuchs, Joshua Harvey, Clemens Kofler, John-Paul Bader"] + # s.add_development_dependency '' + end + Jeweler::GemcutterTasks.new +rescue LoadError + puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com" +end diff --git a/vendor/plugins/globalize2/VERSION b/vendor/plugins/globalize2/VERSION new file mode 100644 index 000000000..0c62199f1 --- /dev/null +++ b/vendor/plugins/globalize2/VERSION @@ -0,0 +1 @@ +0.2.1 diff --git a/vendor/plugins/globalize2/generators/db_backend.rb b/vendor/plugins/globalize2/generators/db_backend.rb new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vendor/plugins/globalize2/generators/db_backend.rb diff --git a/vendor/plugins/globalize2/generators/templates/db_backend_migration.rb b/vendor/plugins/globalize2/generators/templates/db_backend_migration.rb new file mode 100644 index 000000000..0f0261113 --- /dev/null +++ b/vendor/plugins/globalize2/generators/templates/db_backend_migration.rb @@ -0,0 +1,25 @@ +class ActsAsTaggableMigration < ActiveRecord::Migration + def self.up + create_table :globalize_translations do |t| + t.string :locale, :null => false + t.string :key, :null => false + t.string :translation + t.timestamps + end + +# TODO: FINISH DOING MIGRATION -- stopped in the middle + + create_table :globalize_translations_map do |t| + t.string :key, :null => false + t.integer :translation_id, :null => false + end + + add_index :taggings, :tag_id + add_index :taggings, [:taggable_id, :taggable_type] + end + + def self.down + drop_table :globalize_translations + drop_table :tags + end +end diff --git a/vendor/plugins/globalize2/globalize2.gemspec b/vendor/plugins/globalize2/globalize2.gemspec new file mode 100644 index 000000000..89021115e --- /dev/null +++ b/vendor/plugins/globalize2/globalize2.gemspec @@ -0,0 +1,81 @@ +# Generated by jeweler +# DO NOT EDIT THIS FILE DIRECTLY +# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command +# -*- encoding: utf-8 -*- + +Gem::Specification.new do |s| + s.name = %q{globalize2} + s.version = "0.2.0" + + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + s.authors = ["Sven Fuchs, Joshua Harvey, Clemens Kofler, John-Paul Bader"] + s.date = %q{2010-04-22} + s.description = %q{Rails I18n: de-facto standard library for ActiveRecord data translation} + s.email = %q{joshmh@gmail.com} + s.extra_rdoc_files = [ + "LICENSE", + "README.textile" + ] + s.files = [ + ".gitignore", + "LICENSE", + "README.textile", + "Rakefile", + "VERSION", + "generators/db_backend.rb", + "generators/templates/db_backend_migration.rb", + "globalize2.gemspec", + "init.rb", + "lib/globalize.rb", + "lib/globalize/active_record.rb", + "lib/globalize/active_record/adapter.rb", + "lib/globalize/active_record/attributes.rb", + "lib/globalize/active_record/migration.rb", + "lib/i18n/missing_translations_log_handler.rb", + "lib/i18n/missing_translations_raise_handler.rb", + "test/active_record/fallbacks_test.rb", + "test/active_record/migration_test.rb", + "test/active_record/sti_translated_test.rb", + "test/active_record/translates_test.rb", + "test/active_record/translation_class_test.rb", + "test/active_record/validation_tests.rb", + "test/active_record_test.rb", + "test/all.rb", + "test/data/models.rb", + "test/data/no_globalize_schema.rb", + "test/data/schema.rb", + "test/i18n/missing_translations_test.rb", + "test/test_helper.rb" + ] + s.homepage = %q{http://github.com/joshmh/globalize2} + s.rdoc_options = ["--charset=UTF-8"] + s.require_paths = ["lib"] + s.rubygems_version = %q{1.3.6} + s.summary = %q{Rails I18n: de-facto standard library for ActiveRecord data translation} + s.test_files = [ + "test/active_record/fallbacks_test.rb", + "test/active_record/migration_test.rb", + "test/active_record/sti_translated_test.rb", + "test/active_record/translates_test.rb", + "test/active_record/translation_class_test.rb", + "test/active_record/validation_tests.rb", + "test/active_record_test.rb", + "test/all.rb", + "test/data/models.rb", + "test/data/no_globalize_schema.rb", + "test/data/schema.rb", + "test/i18n/missing_translations_test.rb", + "test/test_helper.rb" + ] + + if s.respond_to? :specification_version then + current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION + s.specification_version = 3 + + if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then + else + end + else + end +end + diff --git a/vendor/plugins/globalize2/init.rb b/vendor/plugins/globalize2/init.rb new file mode 100644 index 000000000..a4089251b --- /dev/null +++ b/vendor/plugins/globalize2/init.rb @@ -0,0 +1 @@ +require 'globalize' diff --git a/vendor/plugins/globalize2/lib/globalize.rb b/vendor/plugins/globalize2/lib/globalize.rb new file mode 100644 index 000000000..67c1878ec --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize.rb @@ -0,0 +1,15 @@ +module Globalize + autoload :ActiveRecord, 'globalize/active_record' + + class << self + def fallbacks? + I18n.respond_to?(:fallbacks) + end + + def fallbacks(locale) + fallbacks? ? I18n.fallbacks[locale] : [locale.to_sym] + end + end +end + +ActiveRecord::Base.send(:include, Globalize::ActiveRecord) diff --git a/vendor/plugins/globalize2/lib/globalize/active_record.rb b/vendor/plugins/globalize2/lib/globalize/active_record.rb new file mode 100644 index 000000000..2915a5737 --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize/active_record.rb @@ -0,0 +1,229 @@ +module Globalize + class MigrationError < StandardError; end + class MigrationMissingTranslatedField < MigrationError; end + class BadMigrationFieldType < MigrationError; end + + module ActiveRecord + autoload :Adapter, 'globalize/active_record/adapter' + autoload :Attributes, 'globalize/active_record/attributes' + autoload :Migration, 'globalize/active_record/migration' + + def self.included(base) + base.extend ActMacro + end + + class << self + def build_translation_class(target, options) + options[:table_name] ||= "#{target.table_name.singularize}_translations" + + klass = target.const_defined?(:Translation) ? + target.const_get(:Translation) : + target.const_set(:Translation, Class.new(::ActiveRecord::Base)) + + klass.class_eval do + set_table_name(options[:table_name]) + belongs_to target.name.underscore.gsub('/', '_') + def locale; read_attribute(:locale).to_sym; end + def locale=(locale); write_attribute(:locale, locale.to_s); end + end + + klass + end + end + + module ActMacro + def locale + (defined?(@@locale) && @@locale) + end + + def locale=(locale) + @@locale = locale + end + + def translates(*attr_names) + return if translates? + options = attr_names.extract_options! + + class_inheritable_accessor :translation_class, :translated_attribute_names + class_inheritable_writer :required_attributes + self.translation_class = ActiveRecord.build_translation_class(self, options) + self.translated_attribute_names = attr_names.map(&:to_sym) + + include InstanceMethods + extend ClassMethods, Migration + + after_save :save_translations! + has_many :translations, :class_name => translation_class.name, + :foreign_key => class_name.foreign_key, + :dependent => :delete_all, + :extend => HasManyExtensions + + named_scope :with_translations, lambda { |locale| + conditions = required_attributes.map do |attribute| + "#{quoted_translation_table_name}.#{attribute} IS NOT NULL" + end + conditions << "#{quoted_translation_table_name}.locale = ?" + { :include => :translations, :conditions => [conditions.join(' AND '), locale] } + } + + attr_names.each { |attr_name| translated_attr_accessor(attr_name) } + end + + def translates? + included_modules.include?(InstanceMethods) + end + end + + module HasManyExtensions + def by_locale(locale) + first(:conditions => { :locale => locale.to_s }) + end + + def by_locales(locales) + all(:conditions => { :locale => locales.map(&:to_s) }) + end + end + + module ClassMethods + delegate :set_translation_table_name, :to => :translation_class + + def with_locale(locale) + previous_locale, self.locale = self.locale, locale + result = yield + self.locale = previous_locale + result + end + + def translation_table_name + translation_class.table_name + end + + def quoted_translation_table_name + translation_class.quoted_table_name + end + + def required_attributes + @required_attributes ||= reflect_on_all_validations.select do |validation| + validation.macro == :validates_presence_of && translated_attribute_names.include?(validation.name) + end.map(&:name) + end + + def respond_to?(method, *args, &block) + method.to_s =~ /^find_by_(\w+)$/ && translated_attribute_names.include?($1.to_sym) || super + end + + def method_missing(method, *args) + if method.to_s =~ /^find_by_(\w+)$/ && translated_attribute_names.include?($1.to_sym) + find_first_by_translated_attr_and_locales($1, args.first) + elsif method.to_s =~ /^find_all_by_(\w+)$/ && translated_attribute_names.include?($1.to_sym) + find_all_by_translated_attr_and_locales($1, args.first) + else + super + end + end + + protected + + def find_first_by_translated_attr_and_locales(name, value) + query = "#{translated_attr_name(name)} = ? AND #{translated_attr_name('locale')} IN (?)" + locales = Globalize.fallbacks(locale || I18n.locale).map(&:to_s) + find( + :first, + :joins => :translations, + :conditions => [query, value, locales], + :readonly => false + ) + end + + def find_all_by_translated_attr_and_locales(name, value) + query = "#{translated_attr_name(name)} = ? AND #{translated_attr_name('locale')} IN (?)" + locales = Globalize.fallbacks(locale || I18n.locale).map(&:to_s) + find( + :all, + :joins => :translations, + :conditions => [query, value, locales], + :readonly => false + ) + end + + def translated_attr_accessor(name) + define_method "#{name}=", lambda { |value| + globalize.write(self.class.locale || I18n.locale, name, value) + self[name] = value + } + define_method name, lambda { |*args| + globalize.fetch(args.first || self.class.locale || I18n.locale, name) + } + alias_method "#{name}_before_type_cast", name + end + + def translated_attr_name(name) + "#{translation_class.table_name}.#{name}" + end + end + + module InstanceMethods + def globalize + @globalize ||= Adapter.new self + end + + def attributes + self.attribute_names.inject({}) do |attrs, name| + attrs[name] = read_attribute(name) || + (globalize.fetch(I18n.locale, name) rescue nil) + attrs + end + end + + def attributes=(attributes, *args) + if attributes.respond_to?(:delete) && locale = attributes.delete(:locale) + self.class.with_locale(locale) { super } + else + super + end + end + + def attribute_names + translated_attribute_names.map(&:to_s) + super + end + + def available_locales + translations.scoped(:select => 'DISTINCT locale').map(&:locale) + end + + def translated_locales + translations.map(&:locale) + end + + def translated_attributes + translated_attribute_names.inject({}) do |attributes, name| + attributes.merge(name => send(name)) + end + end + + def set_translations(options) + options.keys.each do |locale| + translation = translations.find_by_locale(locale.to_s) || + translations.build(:locale => locale.to_s) + translation.update_attributes!(options[locale]) + end + end + + def reload(options = nil) + translated_attribute_names.each { |name| @attributes.delete(name.to_s) } + globalize.reset + super(options) + end + + protected + + def save_translations! + globalize.save_translations! + end + end + end +end + +def globalize_write(name, value) + globalize.write(self.class.locale || I18n.locale, name, value) +end diff --git a/vendor/plugins/globalize2/lib/globalize/active_record/adapter.rb b/vendor/plugins/globalize2/lib/globalize/active_record/adapter.rb new file mode 100644 index 000000000..12f89ec01 --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize/active_record/adapter.rb @@ -0,0 +1,80 @@ +module Globalize + module ActiveRecord + class Adapter + # The cache caches attributes that already were looked up for read access. + # The stash keeps track of new or changed values that need to be saved. + attr_reader :record, :cache, :stash + + def initialize(record) + @record = record + @cache = Attributes.new + @stash = Attributes.new + end + + def fetch(locale, attr_name) + cache.contains?(locale, attr_name) ? + cache.read(locale, attr_name) : + cache.write(locale, attr_name, fetch_attribute(locale, attr_name)) + end + + def write(locale, attr_name, value) + stash.write(locale, attr_name, value) + cache.write(locale, attr_name, value) + end + + def save_translations! + stash.each do |locale, attrs| + translation = record.translations.find_or_initialize_by_locale(locale.to_s) + attrs.each { |attr_name, value| translation[attr_name] = value } + translation.save! + end + stash.clear + end + + def reset + cache.clear + # stash.clear + end + + protected + + def fetch_translation(locale) + locale = locale.to_sym + record.translations.loaded? ? record.translations.detect { |t| t.locale == locale } : + record.translations.by_locale(locale) + end + + def fetch_translations(locale) + # only query if not already included with :include => translations + record.translations.loaded? ? record.translations : + record.translations.by_locales(Globalize.fallbacks(locale)) + end + + def fetch_attribute(locale, attr_name) + translations = fetch_translations(locale) + value, requested_locale = nil, locale + + Globalize.fallbacks(locale).each do |fallback| + translation = translations.detect { |t| t.locale == fallback } + value = translation && translation.send(attr_name) + locale = fallback && break if value + end + + set_metadata(value, :locale => locale, :requested_locale => requested_locale) + value + end + + def set_metadata(object, metadata) + if object.respond_to?(:translation_metadata) + object.translation_metadata.merge!(meta_data) + end + end + + def translation_metadata_accessor(object) + return if obj.respond_to?(:translation_metadata) + class << object; attr_accessor :translation_metadata end + object.translation_metadata ||= {} + end + end + end +end diff --git a/vendor/plugins/globalize2/lib/globalize/active_record/attributes.rb b/vendor/plugins/globalize2/lib/globalize/active_record/attributes.rb new file mode 100644 index 000000000..7bd923ce2 --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize/active_record/attributes.rb @@ -0,0 +1,25 @@ +# Helper class for storing values per locale. Used by Globalize::Adapter +# to stash and cache attribute values. +module Globalize + module ActiveRecord + class Attributes < Hash + def [](locale) + locale = locale.to_sym + self[locale] = {} unless has_key?(locale) + self.fetch(locale) + end + + def contains?(locale, attr_name) + self[locale].has_key?(attr_name) + end + + def read(locale, attr_name) + self[locale][attr_name] + end + + def write(locale, attr_name, value) + self[locale][attr_name] = value + end + end + end +end diff --git a/vendor/plugins/globalize2/lib/globalize/active_record/migration.rb b/vendor/plugins/globalize2/lib/globalize/active_record/migration.rb new file mode 100644 index 000000000..fa63aed8c --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize/active_record/migration.rb @@ -0,0 +1,44 @@ +module Globalize + module ActiveRecord + module Migration + def create_translation_table!(fields) + translated_attribute_names.each do |f| + raise MigrationMissingTranslatedField, "Missing translated field #{f}" unless fields[f] + end + + fields.each do |name, type| + if translated_attribute_names.include?(name) && ![:string, :text].include?(type) + raise BadMigrationFieldType, "Bad field type for #{name}, should be :string or :text" + end + end + + self.connection.create_table(translation_table_name) do |t| + t.references table_name.sub(/^#{table_name_prefix}/, "").singularize + t.string :locale + fields.each do |name, type| + t.column name, type + end + t.timestamps + end + + self.connection.add_index( + translation_table_name, + "#{table_name.sub(/^#{table_name_prefix}/, "").singularize}_id", + :name => translation_index_name + ) + end + + def translation_index_name + require 'digest/sha1' + # FIXME what's the max size of an index name? + index_name = "index_#{translation_table_name}_on_#{self.table_name.singularize}_id" + index_name.size < 50 ? index_name : "index_#{Digest::SHA1.hexdigest(index_name)}" + end + + def drop_translation_table! + self.connection.remove_index(translation_table_name, :name => translation_index_name) rescue nil + self.connection.drop_table(translation_table_name) + end + end + end +end diff --git a/vendor/plugins/globalize2/lib/i18n/missing_translations_log_handler.rb b/vendor/plugins/globalize2/lib/i18n/missing_translations_log_handler.rb new file mode 100644 index 000000000..24c10890a --- /dev/null +++ b/vendor/plugins/globalize2/lib/i18n/missing_translations_log_handler.rb @@ -0,0 +1,41 @@ +# A simple exception handler that behaves like the default exception handler +# but additionally logs missing translations to a given log. +# +# Useful for identifying missing translations during testing. +# +# E.g. +# +# require 'globalize/i18n/missing_translations_log_handler' +# I18n.missing_translations_logger = RAILS_DEFAULT_LOGGER +# I18n.exception_handler = :missing_translations_log_handler +# +# To set up a different log file: +# +# logger = Logger.new("#{RAILS_ROOT}/log/missing_translations.log") +# I18n.missing_translations_logger = logger + +module I18n + @@missing_translations_logger = nil + + class << self + def missing_translations_logger + @@missing_translations_logger ||= begin + require 'logger' unless defined?(Logger) + Logger.new(STDOUT) + end + end + + def missing_translations_logger=(logger) + @@missing_translations_logger = logger + end + + def missing_translations_log_handler(exception, locale, key, options) + if MissingTranslationData === exception + missing_translations_logger.warn(exception.message) + return exception.message + else + raise exception + end + end + end +end diff --git a/vendor/plugins/globalize2/lib/i18n/missing_translations_raise_handler.rb b/vendor/plugins/globalize2/lib/i18n/missing_translations_raise_handler.rb new file mode 100644 index 000000000..18237b151 --- /dev/null +++ b/vendor/plugins/globalize2/lib/i18n/missing_translations_raise_handler.rb @@ -0,0 +1,25 @@ +# 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 +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/test/active_record/fallbacks_test.rb b/vendor/plugins/globalize2/test/active_record/fallbacks_test.rb new file mode 100644 index 000000000..449ec8b2b --- /dev/null +++ b/vendor/plugins/globalize2/test/active_record/fallbacks_test.rb @@ -0,0 +1,102 @@ +require File.expand_path(File.dirname(__FILE__) + '/../test_helper') +require File.expand_path(File.dirname(__FILE__) + '/../data/models') + +if I18n.respond_to?(:fallbacks) + class TranslatedTest < ActiveSupport::TestCase + def setup + I18n.locale = :'en-US' + I18n.fallbacks.clear + reset_db! + ActiveRecord::Base.locale = nil + end + + def teardown + I18n.fallbacks.clear + end + + test "keeping one field in new locale when other field is changed" do + I18n.fallbacks.map 'de-DE' => [ 'en-US' ] + post = Post.create :subject => 'foo' + I18n.locale = 'de-DE' + post.content = 'bar' + assert_equal 'foo', post.subject + end + + test "modifying non-required field in a new locale" do + I18n.fallbacks.map 'de-DE' => [ 'en-US' ] + post = Post.create :subject => 'foo' + I18n.locale = 'de-DE' + post.content = 'bar' + assert post.save + end + + test "resolves a simple fallback" do + I18n.locale = 'de-DE' + post = Post.create :subject => 'foo' + I18n.locale = 'de' + post.subject = 'baz' + post.content = 'bar' + post.save + I18n.locale = 'de-DE' + assert_equal 'foo', post.subject + assert_equal 'bar', post.content + end + + test "resolves a simple fallback without reloading" do + I18n.locale = 'de-DE' + post = Post.new :subject => 'foo' + I18n.locale = 'de' + post.subject = 'baz' + post.content = 'bar' + I18n.locale = 'de-DE' + assert_equal 'foo', post.subject + assert_equal 'bar', post.content + end + + test "resolves a complex fallback without reloading" do + I18n.fallbacks.map 'de' => %w(en he) + I18n.locale = 'de' + post = Post.new + I18n.locale = 'en' + post.subject = 'foo' + I18n.locale = 'he' + post.subject = 'baz' + post.content = 'bar' + I18n.locale = 'de' + assert_equal 'foo', post.subject + assert_equal 'bar', post.content + end + + test 'fallbacks with lots of locale switching' do + I18n.fallbacks.map :'de-DE' => [ :'en-US' ] + post = Post.create :subject => 'foo' + + I18n.locale = :'de-DE' + assert_equal 'foo', post.subject + + I18n.locale = :'en-US' + post.update_attribute :subject, 'bar' + + I18n.locale = :'de-DE' + assert_equal 'bar', post.subject + 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 + end +end + +# TODO should validate_presence_of take fallbacks into account? maybe we need +# an extra validation call, or more options for validate_presence_of. + diff --git a/vendor/plugins/globalize2/test/active_record/migration_test.rb b/vendor/plugins/globalize2/test/active_record/migration_test.rb new file mode 100644 index 000000000..359d811f0 --- /dev/null +++ b/vendor/plugins/globalize2/test/active_record/migration_test.rb @@ -0,0 +1,118 @@ +require File.expand_path(File.dirname(__FILE__) + '/../test_helper') +require File.expand_path(File.dirname(__FILE__) + '/../data/models') + +class MigrationTest < ActiveSupport::TestCase + def setup + reset_db! + Post.drop_translation_table! + end + + test 'globalize table added' do + assert !Post.connection.table_exists?(:post_translations) + assert !Post.connection.index_exists?(:post_translations, :post_id) + + Post.create_translation_table!(:subject => :string, :content => :text) + assert Post.connection.table_exists?(:post_translations) + assert Post.connection.index_exists?(:post_translations, :post_id) + + columns = Post.connection.columns(:post_translations) + assert locale = columns.detect { |c| c.name == 'locale' } + assert_equal :string, locale.type + assert subject = columns.detect { |c| c.name == 'subject' } + assert_equal :string, subject.type + assert content = columns.detect { |c| c.name == 'content' } + assert_equal :text, content.type + assert post_id = columns.detect { |c| c.name == 'post_id' } + assert_equal :integer, post_id.type + assert created_at = columns.detect { |c| c.name == 'created_at' } + assert_equal :datetime, created_at.type + assert updated_at = columns.detect { |c| c.name == 'updated_at' } + assert_equal :datetime, updated_at.type + end + + test 'globalize table dropped' do + assert !Post.connection.table_exists?( :post_translations ) + assert !Post.connection.index_exists?( :post_translations, :post_id ) + Post.create_translation_table! :subject => :string, :content => :text + assert Post.connection.table_exists?( :post_translations ) + assert Post.connection.index_exists?( :post_translations, :post_id ) + Post.drop_translation_table! + assert !Post.connection.table_exists?( :post_translations ) + assert !Post.connection.index_exists?( :post_translations, :post_id ) + end + + test 'exception on missing field inputs' do + assert_raise Globalize::MigrationMissingTranslatedField do + Post.create_translation_table! :content => :text + end + end + + test 'exception on bad input type' do + assert_raise Globalize::BadMigrationFieldType do + Post.create_translation_table! :subject => :string, :content => :integer + end + end + + test "exception on bad input type isn't raised for untranslated fields" do + assert_nothing_raised do + Post.create_translation_table! :subject => :string, :content => :string, :views_count => :integer + end + end + + test 'create_translation_table! should not be called on non-translated models' do + assert_raise NoMethodError do + Blog.create_translation_table! :name => :string + end + end + + test 'drop_translation_table! should not be called on non-translated models' do + assert_raise NoMethodError do + Blog.drop_translation_table! + end + end + + test "translation_index_name returns a readable index name when it's not longer than 50 characters" do + assert_equal 'index_post_translations_on_post_id', Post.send(:translation_index_name) + end + + test "translation_index_name returns a hashed index name when it's longer than 50 characters" do + class UltraLongModelNameWithoutProper < ActiveRecord::Base + translates :foo + end + name = UltraLongModelNameWithoutProper.send(:translation_index_name) + assert_match /^index_[a-z0-9]{40}$/, name + end + + test 'globalize table added when table has long name' do + UltraLongModelNameWithoutProper.create_translation_table!( + :subject => :string, :content => :text + ) + + assert UltraLongModelNameWithoutProper.connection.table_exists?( + :ultra_long_model_name_without_proper_translations + ) + assert UltraLongModelNameWithoutProper.connection.index_exists?( + :ultra_long_model_name_without_proper_translations, + :name => UltraLongModelNameWithoutProper.send( + :translation_index_name + ) + ) + end + + test 'globalize table dropped when table has long name' do + UltraLongModelNameWithoutProper.drop_translation_table! + UltraLongModelNameWithoutProper.create_translation_table!( + :subject => :string, :content => :text + ) + UltraLongModelNameWithoutProper.drop_translation_table! + + assert !UltraLongModelNameWithoutProper.connection.table_exists?( + :ultra_long_model_name_without_proper_translations + ) + assert !UltraLongModelNameWithoutProper.connection.index_exists?( + :ultra_long_model_name_without_proper_translations, + :ultra_long_model_name_without_proper_id + ) + end + +end diff --git a/vendor/plugins/globalize2/test/active_record/sti_translated_test.rb b/vendor/plugins/globalize2/test/active_record/sti_translated_test.rb new file mode 100644 index 000000000..f529b8d6e --- /dev/null +++ b/vendor/plugins/globalize2/test/active_record/sti_translated_test.rb @@ -0,0 +1,49 @@ +require File.expand_path(File.dirname(__FILE__) + '/../test_helper') +require File.expand_path(File.dirname(__FILE__) + '/../data/models') + +class StiTranslatedTest < ActiveSupport::TestCase + def setup + I18n.locale = :'en-US' + reset_db! + 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 "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 diff --git a/vendor/plugins/globalize2/test/active_record/translates_test.rb b/vendor/plugins/globalize2/test/active_record/translates_test.rb new file mode 100644 index 000000000..1831063fb --- /dev/null +++ b/vendor/plugins/globalize2/test/active_record/translates_test.rb @@ -0,0 +1,96 @@ +require File.expand_path(File.dirname(__FILE__) + '/../test_helper') +require File.expand_path(File.dirname(__FILE__) + '/../data/models') + +class TranslatesTest < ActiveSupport::TestCase + def setup + I18n.locale = nil + ActiveRecord::Base.locale = nil + reset_db! + end + + test 'defines a :locale accessors on ActiveRecord::Base' do + ActiveRecord::Base.locale = :de + assert_equal :de, ActiveRecord::Base.locale + end + + test 'the :locale reader on ActiveRecord::Base does not default to I18n.locale (anymore)' do + I18n.locale = :en + assert_nil ActiveRecord::Base.locale + end + + test 'ActiveRecord::Base.with_locale temporarily sets the given locale and yields the block' do + I18n.locale = :en + post = Post.with_locale(:de) do + Post.create!(:subject => 'Titel', :content => 'Inhalt') + end + assert_nil Post.locale + assert_equal :en, I18n.locale + + I18n.locale = :de + assert_equal 'Titel', post.subject + end + + test 'translation_class returns the Translation class' do + assert_equal Post::Translation, Post.translation_class + end + + test 'defines a has_many association on the model class' do + assert_has_many Post, :translations + end + + test 'defines a scope for retrieving locales that have complete translations' do + post = Post.create!(:subject => 'subject', :content => 'content') + assert_equal [:en], post.translated_locales + end + + test 'sets the given attributes to translated_attribute_names' do + assert_equal [:subject, :content], Post.translated_attribute_names + end + + test 'defines accessors for the translated attributes' do + post = Post.new + assert post.respond_to?(:subject) + assert post.respond_to?(:subject=) + end + + test 'attribute reader without arguments will use the current locale on ActiveRecord::Base or I18n' do + post = Post.with_locale(:de) do + Post.create!(:subject => 'Titel', :content => 'Inhalt') + end + I18n.locale = :de + assert_equal 'Titel', post.subject + + I18n.locale = :en + ActiveRecord::Base.locale = :de + assert_equal 'Titel', post.subject + end + + test 'attribute reader when passed a locale will use the given locale' do + post = Post.with_locale(:de) do + Post.create!(:subject => 'Titel', :content => 'Inhalt') + end + assert_equal 'Titel', post.subject(:de) + end + + test 'attribute reader will use the current locale on ActiveRecord::Base or I18n' do + post = Post.with_locale(:en) do + Post.create!(:subject => 'title', :content => 'content') + end + I18n.locale = :de + post.subject = 'Titel' + assert_equal 'Titel', post.subject + + ActiveRecord::Base.locale = :en + post.subject = 'title' + assert_equal 'title', post.subject + end + + test "find_by_xx records have writable attributes" do + Post.create :subject => "change me" + p = Post.find_by_subject("change me") + p.subject = "changed" + assert_nothing_raised(ActiveRecord::ReadOnlyRecord) do + p.save + end + end +end diff --git a/vendor/plugins/globalize2/test/active_record/translation_class_test.rb b/vendor/plugins/globalize2/test/active_record/translation_class_test.rb new file mode 100644 index 000000000..1628416d7 --- /dev/null +++ b/vendor/plugins/globalize2/test/active_record/translation_class_test.rb @@ -0,0 +1,30 @@ +require File.expand_path(File.dirname(__FILE__) + '/../test_helper') +require File.expand_path(File.dirname(__FILE__) + '/../data/models') + +class TranlationClassTest < ActiveSupport::TestCase + def setup + reset_db! + end + + test 'defines a Translation class nested in the model class' do + assert Post.const_defined?(:Translation) + end + + test 'defines a belongs_to association' do + assert_belongs_to Post::Translation, :post + end + + test 'defines a reader for :locale that always returns a symbol' do + post = Post::Translation.new + post.write_attribute('locale', 'de') + assert_equal :de, post.locale + end + + test 'defines a write for :locale that always writes a string' do + post = Post::Translation.new + post.locale = :de + assert_equal 'de', post.read_attribute('locale') + end +end + + diff --git a/vendor/plugins/globalize2/test/active_record/validation_tests.rb b/vendor/plugins/globalize2/test/active_record/validation_tests.rb new file mode 100644 index 000000000..0148fa384 --- /dev/null +++ b/vendor/plugins/globalize2/test/active_record/validation_tests.rb @@ -0,0 +1,75 @@ +require File.expand_path(File.dirname(__FILE__) + '/../test_helper') +require File.expand_path(File.dirname(__FILE__) + '/../data/models') + +class ValidationTest < ActiveSupport::TestCase + def setup + reset_db! + end + + def teardown + Validatee.instance_variable_set(:@validate_callbacks, CallbackChain.new) + end + + test "validates_presence_of" do + Validatee.class_eval { validates_presence_of :string } + assert !Validatee.new.valid? + assert Validatee.new(:string => 'foo').valid? + end + + test "validates_confirmation_of" do + Validatee.class_eval { validates_confirmation_of :string } + assert !Validatee.new(:string => 'foo', :string_confirmation => 'bar').valid? + assert Validatee.new(:string => 'foo', :string_confirmation => 'foo').valid? + end + + test "validates_acceptance_of" do + Validatee.class_eval { validates_acceptance_of :string, :accept => '1' } + assert !Validatee.new(:string => '0').valid? + assert Validatee.new(:string => '1').valid? + end + + test "validates_length_of (:is)" do + Validatee.class_eval { validates_length_of :string, :is => 1 } + assert !Validatee.new(:string => 'aa').valid? + assert Validatee.new(:string => 'a').valid? + end + + test "validates_format_of" do + Validatee.class_eval { validates_format_of :string, :with => /^\d+$/ } + assert !Validatee.new(:string => 'a').valid? + assert Validatee.new(:string => '1').valid? + end + + test "validates_inclusion_of" do + Validatee.class_eval { validates_inclusion_of :string, :in => %(a) } + assert !Validatee.new(:string => 'b').valid? + assert Validatee.new(:string => 'a').valid? + end + + test "validates_exclusion_of" do + Validatee.class_eval { validates_exclusion_of :string, :in => %(b) } + assert !Validatee.new(:string => 'b').valid? + assert Validatee.new(:string => 'a').valid? + end + + test "validates_numericality_of" do + Validatee.class_eval { validates_numericality_of :string } + assert !Validatee.new(:string => 'a').valid? + assert Validatee.new(:string => '1').valid? + end + + # This doesn't pass and Rails' validates_uniqueness_of implementation doesn't + # seem to be extensible easily. One can work around that by either defining + # a custom validation on the Validatee model itself, or by using validates_uniqueness_of + # on Validatee::Translation. + # + # test "validates_uniqueness_of" do + # Validatee.class_eval { validates_uniqueness_of :string } + # Validatee.create!(:string => 'a') + # assert !Validatee.new(:string => 'a').valid? + # assert Validatee.new(:string => 'b').valid? + # end + + # test "validates_associated" do + # end +end
\ No newline at end of file diff --git a/vendor/plugins/globalize2/test/active_record_test.rb b/vendor/plugins/globalize2/test/active_record_test.rb new file mode 100644 index 000000000..38e247e17 --- /dev/null +++ b/vendor/plugins/globalize2/test/active_record_test.rb @@ -0,0 +1,467 @@ +require File.expand_path(File.dirname(__FILE__) + '/test_helper') +require File.expand_path(File.dirname(__FILE__) + '/data/models') + +# Higher level tests. + +class ActiveRecordTest < ActiveSupport::TestCase + def setup + I18n.locale = :en + reset_db! + ActiveRecord::Base.locale = nil + end + + def assert_translated(locale, record, names, expected) + I18n.locale = locale + assert_equal Array(expected), Array(names).map { |name| record.send(name) } + end + + test "a translated record has translations" do + assert_equal [], Post.new.translations + end + + test "saves a translated version of the record for each locale" do + post = Post.create(:subject => 'title') + I18n.locale = :de + post.update_attributes(:subject => 'Titel') + + assert_equal 2, post.translations.size + assert_equal %w(de en), post.translations.map(&:locale).map(&:to_s).sort + assert_equal %w(Titel title), post.translations.map(&:subject).sort + end + + test "a translated record has German translations" do + I18n.locale = :de + post = Post.create(:subject => 'foo') + assert_equal 1, post.translations.size + assert_equal [:de], post.translations.map { |t| t.locale } + end + + test "modifiying translated fields while switching locales" do + post = Post.create(:subject => 'title', :content => 'content') + assert_equal %w(title content), [post.subject, post.content] + + I18n.locale = :de + post.subject, post.content = 'Titel', 'Inhalt' + + assert_translated(:de, post, [:subject, :content], %w(Titel Inhalt)) + assert_translated(:en, post, [:subject, :content], %w(title content)) + assert_translated(:de, post, [:subject, :content], %w(Titel Inhalt)) + + post.save + post.reload + + assert_translated(:en, post, [:subject, :content], %w(title content)) + assert_translated(:de, post, [:subject, :content], %w(Titel Inhalt)) + end + + test "attribute writers do return their argument" do + value = Post.new.subject = 'foo' + assert_equal 'foo', value + end + + test "update_attribute succeeds with valid values" do + post = Post.create(:subject => 'foo', :content => 'bar') + post.update_attribute(:subject, 'baz') + assert_equal 'baz', Post.first.subject + end + + test "update_attributes fails with invalid values" do + post = Post.create(:subject => 'foo', :content => 'bar') + assert !post.update_attributes(:subject => '') + assert_not_nil post.reload.attributes['subject'] + assert_equal 'foo', post.subject + end + + test "passing the locale to create uses the given locale" do + post = Post.create(:subject => 'Titel', :content => 'Inhalt', :locale => :de) + assert_equal :en, I18n.locale + assert_nil ActiveRecord::Base.locale + + I18n.locale = :de + assert_equal 'Titel', post.subject + end + + test "passing the locale to attributes= uses the given locale" do + post = Post.create(:subject => 'title', :content => 'content') + post.update_attributes(:subject => 'Titel', :content => 'Inhalt', :locale => :de) + post.reload + + assert_equal :en, I18n.locale + assert_nil ActiveRecord::Base.locale + + assert_equal 'title', post.subject + I18n.locale = :de + assert_equal 'Titel', post.subject + end + + test 'reload works' do + post = Post.create(:subject => 'foo', :content => 'bar') + post.subject = 'baz' + post.reload + assert_equal 'foo', post.subject + end + + test "returns nil if no translations are found (unsaved record)" do + post = Post.new(:subject => 'foo') + assert_equal 'foo', post.subject + assert_nil post.content + end + + test "returns nil if no translations are found (saved record)" do + post = Post.create(:subject => 'foo') + post.reload + assert_equal 'foo', post.subject + assert_nil post.content + end + + test "finds a German post" do + post = Post.create(:subject => 'foo (en)', :content => 'bar') + I18n.locale = :de + post = Post.first + post.subject = 'baz (de)' + post.save + assert_equal 'baz (de)', Post.first.subject + I18n.locale = :en + assert_equal 'foo (en)', Post.first.subject + end + + test "saves an English post and loads correctly" do + post = Post.create(:subject => 'foo', :content => 'bar') + assert post.save + post = Post.first + assert_equal 'foo', post.subject + assert_equal 'bar', post.content + end + + test "returns the value for the correct locale, after locale switching" do + post = Post.create(:subject => 'foo') + I18n.locale = :de + post.subject = 'bar' + post.save + I18n.locale = :en + post = Post.first + assert_equal 'foo', post.subject + I18n.locale = :de + assert_equal 'bar', post.subject + end + + test "returns the value for the correct locale, after locale switching, without saving" do + post = Post.create :subject => 'foo' + I18n.locale = :de + post.subject = 'bar' + I18n.locale = :en + assert_equal 'foo', post.subject + I18n.locale = :de + assert_equal 'bar', post.subject + end + + test "saves all locales, even after locale switching" do + post = Post.new :subject => 'foo' + I18n.locale = :de + post.subject = 'bar' + I18n.locale = :he + post.subject = 'baz' + post.save + I18n.locale = :en + post = Post.first + assert_equal 'foo', post.subject + I18n.locale = :de + assert_equal 'bar', post.subject + I18n.locale = :he + assert_equal 'baz', post.subject + end + + test "works with associations" do + blog = Blog.create + post1 = blog.posts.create(:subject => 'foo') + + I18n.locale = :de + post2 = blog.posts.create(:subject => 'bar') + assert_equal 2, blog.posts.size + + I18n.locale = :en + assert_equal 'foo', blog.posts.first.subject + assert_nil blog.posts.last.subject + + I18n.locale = :de + assert_equal 'bar', blog.posts.last.subject + end + + test "works with simple dynamic finders" do + foo = Post.create(:subject => 'foo') + Post.create(:subject => 'bar') + post = Post.find_by_subject('foo') + assert_equal foo, post + end + + test 'change attribute on globalized model' do + post = Post.create(:subject => 'foo', :content => 'bar') + assert_equal [], post.changed + post.subject = 'baz' + assert_equal ['subject'], post.changed + post.content = 'quux' + assert_member 'subject', post.changed + assert_member 'content', post.changed + end + + test 'change attribute on globalized model after locale switching' do + post = Post.create(:subject => 'foo', :content => 'bar') + assert_equal [], post.changed + post.subject = 'baz' + I18n.locale = :de + assert_equal ['subject'], post.changed + end + + test 'complex writing and stashing' do + post = Post.create(:subject => 'foo', :content => 'bar') + post.subject = nil + assert_nil post.subject + assert !post.valid? + post.subject = 'stashed_foo' + assert_equal 'stashed_foo', post.subject + end + + test 'translated class locale setting' do + assert ActiveRecord::Base.respond_to?(:locale) + assert_equal :en, I18n.locale + assert_nil ActiveRecord::Base.locale + + I18n.locale = :de + assert_equal :de, I18n.locale + assert_nil 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, I18n.locale + Post.create :subject => 'foo' + assert_equal :de, Post.first.translations.first.locale + end + + test "attribute loading goes by content locale and not global locale" do + post = Post.create(:subject => 'foo') + assert_nil ActiveRecord::Base.locale + + ActiveRecord::Base.locale = :de + assert_equal :en, I18n.locale + post.update_attribute(:subject, 'foo [de]') + assert_equal 'foo [de]', Post.first.subject + + ActiveRecord::Base.locale = :en + assert_equal 'foo', Post.first.subject + end + + test "access content locale before setting" do + Globalize::ActiveRecord::ActMacro.class_eval "remove_class_variable(:@@locale)" + assert_nothing_raised { ActiveRecord::Base.locale } + end + + test "available_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.available_locales + assert_equal [:de, :es, :fr], Post.first.available_locales + end + + test "saving record correctly after post-save reload" do + reloader = Reloader.create(:content => 'foo') + assert_equal 'foo', reloader.content + end + + test "including translations" do + I18n.locale = :de + Post.create(:subject => "Foo1", :content => "Bar1") + Post.create(:subject => "Foo2", :content => "Bar2") + + class << Post + def translations_included + self.all(:include => :translations) + end + end + + default = Post.all.map { |x| [x.subject, x.content] } + with_include = Post.translations_included.map { |x| [x.subject, x.content] } + assert_equal default, with_include + end + + test "setting multiple translations at once with options hash" do + Post.locale = :de + post = Post.create(:subject => "foo1", :content => "foo1") + Post.locale = :en + post.update_attributes(:subject => "bar1", :content => "bar1") + + options = { :de => {:subject => "foo2", :content => "foo2"}, + :en => {:subject => "bar2", :content => "bar2"} } + post.set_translations options + post.reload + + assert ["bar2", "bar2"], [post.subject, post.content] + Post.locale = :de + assert ["foo2", "foo2"], [post.subject, post.content] + end + + test "setting only one translation with set_translations" do + Post.locale = :de + post = Post.create(:subject => "foo1", :content => "foo1") + Post.locale = :en + post.update_attributes(:subject => "bar1", :content => "bar1") + + options = { :en => { :subject => "bar2", :content => "bar2" } } + post.set_translations options + post.reload + + assert ["bar2", "bar2"], [post.subject, post.content] + Post.locale = :de + assert ["foo1", "foo1"], [post.subject, post.content] + end + + test "setting only selected attributes with set_translations" do + Post.locale = :de + post = Post.create(:subject => "foo1", :content => "foo1") + Post.locale = :en + post.update_attributes(:subject => "bar1", :content => "bar1") + + options = { :de => { :content => "foo2" }, :en => { :subject => "bar2" } } + post.set_translations options + post.reload + + assert ["bar2", "bar1"], [post.subject, post.content] + Post.locale = :de + assert ["foo1", "foo2"], [post.subject, post.content] + end + + test "setting invalid attributes raises ArgumentError" do + Post.locale = :de + post = Post.create(:subject => "foo1", :content => "foo1") + Post.locale = :en + post.update_attributes(:subject => "bar1", :content => "bar1") + + options = { :de => {:fake => "foo2"} } + exception = assert_raise(ActiveRecord::UnknownAttributeError) do + post.set_translations options + end + assert_equal "unknown attribute: fake", exception.message + end + + test "reload accepting find options" do + p = Post.create(:subject => "Foo", :content => "Bar") + assert p.reload(:readonly => true, :lock => true) + assert_raise(ArgumentError) { p.reload(:foo => :bar) } + end + + test "dependent destroy of translation" do + p = Post.create(:subject => "Foo", :content => "Bar") + assert_equal 1, PostTranslation.count + p.destroy + assert_equal 0, PostTranslation.count + end + + test "translating subclass of untranslated comment model" do + translated_comment = TranslatedComment.create(:post => @post) + assert_nothing_raised { translated_comment.translations } + end + + test "modifiying translated comments works as expected" do + I18n.locale = :en + translated_comment = TranslatedComment.create(:post => @post, :content => 'foo') + assert_equal 'foo', translated_comment.content + + I18n.locale = :de + translated_comment.content = 'bar' + assert translated_comment.save + assert_equal 'bar', translated_comment.content + + I18n.locale = :en + assert_equal 'foo', translated_comment.content + + assert_equal 2, translated_comment.translations.size + end + + test "can create a proxy class for a namespaced model" do + assert_nothing_raised do + module Foo + module Bar + class Baz < ActiveRecord::Base + translates :bumm + end + end + end + end + end + + test "attribute translated before type cast" do + Post.locale = :en + post = Post.create(:subject => 'foo', :content => 'bar') + Post.locale = :de + post.update_attribute(:subject, "German foo") + assert_equal 'German foo', post.subject_before_type_cast + Post.locale = :en + assert_equal 'foo', post.subject_before_type_cast + end + + test "don't override existing translation class" do + assert PostTranslation.new.respond_to?(:existing_method) + end + + test "has_many and named scopes work with globalize" do + blog = Blog.create + assert_nothing_raised { blog.posts.foobar } + end + + test "required_attribuets don't include non-translated attributes" do + validations = [ + stub(:name => :name, :macro => :validates_presence_of), + stub(:name => :email, :macro => :validates_presence_of) + ] + User.expects(:reflect_on_all_validations => validations) + assert_equal [:name], User.required_attributes + end + + test "attribute_names returns translated and regular attribute names" do + Post.create :subject => "foo", :content => "bar" + assert_equal Post.last.attribute_names.sort, %w[blog_id content id subject] + end + + test "attributes returns translated and regular attributes" do + Post.create :subject => "foo", :content => "bar" + assert_equal Post.last.attributes.keys.sort, %w[blog_id content id subject] + end + + test "to_xml includes translated fields" do + Post.create :subject => "foo", :content => "bar" + assert Post.last.to_xml =~ /subject/ + assert Post.last.to_xml =~ /content/ + end +end + +# TODO error checking for fields that exist in main table, don't exist in +# proxy table, aren't strings or text +# +# TODO allow finding by translated attributes in conditions? +# TODO generate advanced dynamic finders? diff --git a/vendor/plugins/globalize2/test/all.rb b/vendor/plugins/globalize2/test/all.rb new file mode 100644 index 000000000..ff467a176 --- /dev/null +++ b/vendor/plugins/globalize2/test/all.rb @@ -0,0 +1,2 @@ +files = Dir[File.dirname(__FILE__) + '/**/*_test.rb'] +files.each { |file| require file }
\ No newline at end of file diff --git a/vendor/plugins/globalize2/test/data/models.rb b/vendor/plugins/globalize2/test/data/models.rb new file mode 100644 index 000000000..5408d6e23 --- /dev/null +++ b/vendor/plugins/globalize2/test/data/models.rb @@ -0,0 +1,56 @@ +#require 'ruby2ruby' +#require 'parse_tree' +#require 'parse_tree_extensions' +#require 'pp' + +class PostTranslation < ActiveRecord::Base + def existing_method ; end +end + +class Post < ActiveRecord::Base + translates :subject, :content + validates_presence_of :subject + named_scope :foobar, :conditions => { :title => "foobar" } +end + +class Blog < ActiveRecord::Base + has_many :posts, :order => 'id ASC' +end + +class Parent < ActiveRecord::Base + translates :content +end + +class Child < Parent +end + +class Comment < ActiveRecord::Base + validates_presence_of :content + belongs_to :post +end + +class TranslatedComment < Comment + translates :content +end + +class UltraLongModelNameWithoutProper < ActiveRecord::Base + translates :subject, :content + validates_presence_of :subject +end + +class Reloader < Parent + after_create :do_reload + + def do_reload + reload + end +end + +class Validatee < ActiveRecord::Base + translates :string +end + +class User < ActiveRecord::Base + translates :name + validates_presence_of :name, :email +end diff --git a/vendor/plugins/globalize2/test/data/no_globalize_schema.rb b/vendor/plugins/globalize2/test/data/no_globalize_schema.rb new file mode 100644 index 000000000..379455ddb --- /dev/null +++ b/vendor/plugins/globalize2/test/data/no_globalize_schema.rb @@ -0,0 +1,11 @@ +# This schema creates tables without columns for the translated fields +ActiveRecord::Schema.define do + create_table :blogs, :force => true do |t| + t.string :name + end + + create_table :posts, :force => true do |t| + t.references :blog + end +end + diff --git a/vendor/plugins/globalize2/test/data/schema.rb b/vendor/plugins/globalize2/test/data/schema.rb new file mode 100644 index 000000000..910dd0855 --- /dev/null +++ b/vendor/plugins/globalize2/test/data/schema.rb @@ -0,0 +1,55 @@ +ActiveRecord::Schema.define do + create_table :blogs, :force => true do |t| + t.string :description + end + + create_table :posts, :force => true do |t| + t.references :blog + end + + create_table :post_translations, :force => true do |t| + t.string :locale + t.references :post + t.string :subject + t.text :content + end + + create_table :parents, :force => true do |t| + end + + create_table :parent_translations, :force => true do |t| + t.string :locale + t.references :parent + t.text :content + t.string :type + end + + create_table :comments, :force => true do |t| + t.references :post + end + + create_table :comment_translations, :force => true do |t| + t.string :locale + t.references :comment + t.string :subject + t.text :content + end + + create_table :validatees, :force => true do |t| + end + + create_table :validatee_translations, :force => true do |t| + t.string :locale + t.references :validatee + t.string :string + end + + create_table :users, :force => true do |t| + t.string :email + end + + create_table :users_translations, :force => true do |t| + t.references :user + t.string :name + end +end diff --git a/vendor/plugins/globalize2/test/i18n/missing_translations_test.rb b/vendor/plugins/globalize2/test/i18n/missing_translations_test.rb new file mode 100644 index 000000000..5d0ecd6fc --- /dev/null +++ b/vendor/plugins/globalize2/test/i18n/missing_translations_test.rb @@ -0,0 +1,36 @@ +require File.dirname(__FILE__) + '/../test_helper' +require 'i18n/missing_translations_log_handler' + +class MissingTranslationsTest < ActiveSupport::TestCase + test "defines I18n.missing_translations_logger accessor" do + assert I18n.respond_to?(:missing_translations_logger) + end + + test "defines I18n.missing_translations_logger= writer" do + assert I18n.respond_to?(:missing_translations_logger=) + end +end + +class TestLogger < String + def warn(msg) self.concat msg; end +end + +class LogMissingTranslationsTest < ActiveSupport::TestCase + def setup + @locale, @key, @options = :en, :foo, {} + @exception = I18n::MissingTranslationData.new(@locale, @key, @options) + + @logger = TestLogger.new + I18n.missing_translations_logger = @logger + end + + test "still returns the exception message for MissingTranslationData exceptions" do + result = I18n.send(:missing_translations_log_handler, @exception, @locale, @key, @options) + assert_equal 'translation missing: en, foo', result + end + + test "logs the missing translation to I18n.missing_translations_logger" do + I18n.send(:missing_translations_log_handler, @exception, @locale, @key, @options) + assert_equal 'translation missing: en, foo', @logger + end +end diff --git a/vendor/plugins/globalize2/test/test_helper.rb b/vendor/plugins/globalize2/test/test_helper.rb new file mode 100644 index 000000000..99a5d3950 --- /dev/null +++ b/vendor/plugins/globalize2/test/test_helper.rb @@ -0,0 +1,76 @@ +$LOAD_PATH << File.expand_path( File.dirname(__FILE__) + '/../lib' ) + +require 'rubygems' +require 'test/unit' +require 'active_record' +require 'active_support' +require 'active_support/test_case' +require 'mocha' +require 'globalize' +# require 'validation_reflection' + +config = { :adapter => 'sqlite3', :database => ':memory:' } +ActiveRecord::Base.establish_connection(config) + +class ActiveSupport::TestCase + def reset_db!(schema_path = nil) + schema_path ||= File.expand_path(File.dirname(__FILE__) + '/data/schema.rb') + ActiveRecord::Migration.verbose = false + ActiveRecord::Base.silence { load(schema_path) } + end + + def assert_member(item, array) + assert_block "Item #{item} is not in array #{array}" do + array.member?(item) + end + end + + def assert_belongs_to(model, associated) + assert model.reflect_on_all_associations(:belongs_to).detect { |association| + association.name.to_s == associated.to_s + } + end + + def assert_has_many(model, associated) + assert model.reflect_on_all_associations(:has_many).detect { |association| + association.name.to_s == associated.to_s + } + end +end + +module ActiveRecord + module ConnectionAdapters + class AbstractAdapter + def index_exists?(table_name, column_name) + indexes(table_name).any? { |index| index.name == index_name(table_name, column_name) } + end + end + end +end + +# module ActiveRecord +# class BaseWithoutTable < Base +# self.abstract_class = true +# +# def create_or_update +# errors.empty? +# end +# +# class << self +# def columns() +# @columns ||= [] +# end +# +# def column(name, sql_type = nil, default = nil, null = true) +# columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type.to_s, null) +# reset_column_information +# end +# +# # Do not reset @columns +# def reset_column_information +# read_methods.each { |name| undef_method(name) } +# @column_names = @columns_hash = @content_columns = @dynamic_methods_hash = @read_methods = nil +# end +# end +# end +# end
\ No newline at end of file |