From 283a3e9ba97bfcf86541d079f85da7791c74f3ba Mon Sep 17 00:00:00 2001 From: Shaun McDonald Date: Wed, 27 May 2009 15:39:14 +0000 Subject: [PATCH] Add Globalize2 so that we get some nice fall backs to other languages when a translation is missing in the requested language. --- vendor/plugins/globalize2/.gitignore | 4 + vendor/plugins/globalize2/LICENSE | 21 + vendor/plugins/globalize2/README.textile | 202 ++++++++ .../globalize2/generators/db_backend.rb | 0 .../templates/db_backend_migration.rb | 25 + vendor/plugins/globalize2/init.rb | 10 + .../globalize2/lib/globalize/backend/chain.rb | 102 ++++ .../lib/globalize/backend/pluralizing.rb | 37 ++ .../lib/globalize/backend/static.rb | 60 +++ .../i18n/missing_translations_log_handler.rb | 41 ++ .../missing_translations_raise_handler.rb | 27 ++ .../globalize2/lib/globalize/load_path.rb | 63 +++ .../lib/globalize/locale/fallbacks.rb | 63 +++ .../lib/globalize/locale/language_tag.rb | 81 ++++ .../lib/globalize/model/active_record.rb | 38 ++ .../globalize/model/active_record/adapter.rb | 96 ++++ .../model/active_record/translated.rb | 154 ++++++ .../globalize2/lib/globalize/translation.rb | 32 ++ vendor/plugins/globalize2/lib/locale/root.yml | 3 + .../lib/rails_edge_load_path_patch.rb | 40 ++ vendor/plugins/globalize2/notes.textile | 51 ++ .../globalize2/test/backends/chained_test.rb | 175 +++++++ .../test/backends/pluralizing_test.rb | 63 +++ .../globalize2/test/backends/static_test.rb | 143 ++++++ .../globalize2/test/data/locale/all.yml | 2 + .../globalize2/test/data/locale/de-DE.yml | 2 + .../globalize2/test/data/locale/en-US.yml | 2 + .../test/data/locale/en-US/module.yml | 2 + .../test/data/locale/fi-FI/module.yml | 2 + .../globalize2/test/data/locale/root.yml | 0 .../test/data/no_globalize_schema.rb | 11 + vendor/plugins/globalize2/test/data/post.rb | 24 + vendor/plugins/globalize2/test/data/schema.rb | 39 ++ .../test/i18n/missing_translations_test.rb | 36 ++ .../plugins/globalize2/test/load_path_test.rb | 49 ++ .../globalize2/test/locale/fallbacks_test.rb | 154 ++++++ .../test/locale/language_tag_test.rb | 130 +++++ .../model/active_record/migration_test.rb | 73 +++ .../active_record/sti_translated_test.rb | 75 +++ .../model/active_record/translated_test.rb | 458 ++++++++++++++++++ vendor/plugins/globalize2/test/test_helper.rb | 26 + .../globalize2/test/translation_test.rb | 54 +++ 42 files changed, 2670 insertions(+) create mode 100644 vendor/plugins/globalize2/.gitignore create mode 100644 vendor/plugins/globalize2/LICENSE create mode 100644 vendor/plugins/globalize2/README.textile create mode 100644 vendor/plugins/globalize2/generators/db_backend.rb create mode 100644 vendor/plugins/globalize2/generators/templates/db_backend_migration.rb create mode 100644 vendor/plugins/globalize2/init.rb create mode 100644 vendor/plugins/globalize2/lib/globalize/backend/chain.rb create mode 100644 vendor/plugins/globalize2/lib/globalize/backend/pluralizing.rb create mode 100644 vendor/plugins/globalize2/lib/globalize/backend/static.rb create mode 100644 vendor/plugins/globalize2/lib/globalize/i18n/missing_translations_log_handler.rb create mode 100644 vendor/plugins/globalize2/lib/globalize/i18n/missing_translations_raise_handler.rb create mode 100644 vendor/plugins/globalize2/lib/globalize/load_path.rb create mode 100644 vendor/plugins/globalize2/lib/globalize/locale/fallbacks.rb create mode 100644 vendor/plugins/globalize2/lib/globalize/locale/language_tag.rb create mode 100644 vendor/plugins/globalize2/lib/globalize/model/active_record.rb create mode 100644 vendor/plugins/globalize2/lib/globalize/model/active_record/adapter.rb create mode 100644 vendor/plugins/globalize2/lib/globalize/model/active_record/translated.rb create mode 100644 vendor/plugins/globalize2/lib/globalize/translation.rb create mode 100644 vendor/plugins/globalize2/lib/locale/root.yml create mode 100644 vendor/plugins/globalize2/lib/rails_edge_load_path_patch.rb create mode 100644 vendor/plugins/globalize2/notes.textile create mode 100644 vendor/plugins/globalize2/test/backends/chained_test.rb create mode 100644 vendor/plugins/globalize2/test/backends/pluralizing_test.rb create mode 100644 vendor/plugins/globalize2/test/backends/static_test.rb create mode 100644 vendor/plugins/globalize2/test/data/locale/all.yml create mode 100644 vendor/plugins/globalize2/test/data/locale/de-DE.yml create mode 100644 vendor/plugins/globalize2/test/data/locale/en-US.yml create mode 100644 vendor/plugins/globalize2/test/data/locale/en-US/module.yml create mode 100644 vendor/plugins/globalize2/test/data/locale/fi-FI/module.yml create mode 100644 vendor/plugins/globalize2/test/data/locale/root.yml create mode 100644 vendor/plugins/globalize2/test/data/no_globalize_schema.rb create mode 100644 vendor/plugins/globalize2/test/data/post.rb create mode 100644 vendor/plugins/globalize2/test/data/schema.rb create mode 100644 vendor/plugins/globalize2/test/i18n/missing_translations_test.rb create mode 100644 vendor/plugins/globalize2/test/load_path_test.rb create mode 100644 vendor/plugins/globalize2/test/locale/fallbacks_test.rb create mode 100644 vendor/plugins/globalize2/test/locale/language_tag_test.rb create mode 100644 vendor/plugins/globalize2/test/model/active_record/migration_test.rb create mode 100644 vendor/plugins/globalize2/test/model/active_record/sti_translated_test.rb create mode 100644 vendor/plugins/globalize2/test/model/active_record/translated_test.rb create mode 100644 vendor/plugins/globalize2/test/test_helper.rb create mode 100644 vendor/plugins/globalize2/test/translation_test.rb diff --git a/vendor/plugins/globalize2/.gitignore b/vendor/plugins/globalize2/.gitignore new file mode 100644 index 000000000..24f36d5e7 --- /dev/null +++ b/vendor/plugins/globalize2/.gitignore @@ -0,0 +1,4 @@ +doc +spec/spec/db/* +vendor +NOTES \ No newline at end of file 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..dbd72883e --- /dev/null +++ b/vendor/plugins/globalize2/README.textile @@ -0,0 +1,202 @@ +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://rails-i18n.org. and adds model translations as well as a bunch of other useful features, such as Locale fallbacks (RFC4647 compliant) and automatic loading of Locale data from defined directory/file locations. + +Globalize2 is much more lightweight and modular than its predecessor was. Content translations in Globalize2 use default ActiveRecord features and do not limit any functionality any more. + +All features and tools in Globalize2 are implemented in the most unobstrusive and loosely-coupled way possible, so you can pick whatever features or tools you need for your application and combine them with other tools from other libraries or plugins. + +h2. Requirements + +Rails 2.2 (currently Rails edge) + +h2. Installation + +To install Globalize2 with its default setup just use: + +

+script/plugin install git://github.com/joshmh/globalize2.git
+
+ +This will: + +* activate model translations +* set I18n.load_path to an instance of Globalize::LoadPath +* set I18n.backend to an instance of Globalize::Backend::Static + +h2. Configuration + +You might want to add additional configuration to an initializer, e.g. config/initializers/globalize.rb + +h2. Model translations + +Model translations (or content translations) allow you to translate your models' attribute values. E.g. + +

+class Post < ActiveRecord::Base
+  translates :title, :text
+end
+
+ +Allows you to values for the attributes :title and :text per locale: + +

+I18n.locale = :en
+post.title # Globalize2 rocks!
+
+I18n.locale = :he
+post.title # גלובאלייז2 שולט!
+
+ +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: + +

+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
+
+ +Note that the ActiveRecord model @Post@ must already exist and have a @translates@ directive listing the translated fields. + +h2. Globalize::Backend::Static + +Globalize2 ships with a Static backend that builds on the Simple backend from the I18n library (which is shipped with Rails) and adds the following features: + +* It uses locale fallbacks when looking up translation data. +* It returns an instance of Globalize::Translation::Static instead of a plain Ruby String as a translation. +* It allows to hook in custom pluralization logic as lambdas. + +h2. Custom pluralization logic + +The Simple backend has its pluralization algorithm baked in hardcoded. This algorithm is only suitable for English and other languages that have the same pluralization rules. It is not suitable for, e.g., Czech though. + +To add custom pluralization logic to Globalize' Static backend you can do something like this: + +

+@backend.add_pluralizer :cz, lambda{|c| 
+  c == 1 ? :one : (2..4).include?(c) ? :few : :other 
+}
+
+ +h2. Locale Fallbacks + +Globalize2 ships with a Locale fallback tool which extends the I18n module to hold a fallbacks instance which is set to an instance of Globalize::Locale::Fallbacks by default but can be swapped with a different implementation. + +Globalize2 fallbacks will compute a number of other locales for a given locale. For example: + +

+I18n.fallbacks[:"es-MX"] # => [:"es-MX", :es, :"en-US", :en]
+
+ +Globalize2 fallbacks always fall back to + +* all parents of a given locale (e.g. :es for :"es-MX"), +* then to the fallbacks' default locales and all of their parents and +* finally to the :root locale. + +The default locales are set to [:"en-US"] by default but can be set to something else. The root locale is a concept borrowed from "CLDR":http://unicode.org and makes sense for storing common locale data which works as a last default fallback (e.g. "ltr" for bidi directions). + +One can additionally add any number of additional fallback locales manually. These will be added before the default locales to the fallback chain. For example: + +

+fb = I18n.fallbacks
+
+fb.map :ca => :"es-ES"
+fb[:ca] # => [:ca, :"es-ES", :es, :"en-US", :en]
+
+fb.map :"ar-PS" => :"he-IL"
+fb[:"ar-PS"] # => [:"ar-PS", :ar, :"he-IL", :he, :"en-US", :en]
+fb[:"ar-EG"] # => [:"ar-EG", :ar, :"en-US", :en]
+
+fb.map :sms => [:"se-FI", :"fi-FI"]
+fb[:sms] # => [:sms, :"se-FI", :se, :"fi-FI", :fi, :"en-US", :en]
+
+ +h2. Globalize::LoadPath + +Globalize2 replaces the plain Ruby array that is set to I18n.load_path by default through an instance of Globalize::LoadPath. + +This object can be populated with both paths to files and directories. If a path to a directory is added to it it will look up all locale data files present in that directory enforcing the following convention: + +

+I18n.load_path << "#{RAILS_ROOT}/lib/locales"
+
+# will load all the following files if present:
+lib/locales/all.yml
+lib/locales/fr.yml
+lib/locales/fr/*.yaml
+lib/locales/ru.yml
+lib/locales/ru/*.yaml
+...
+
+ +One can also specify which locales are used. By default this is set to "*" meaning that files for all locales are added. To define that only files for the locale :es are added one can specify: + +

+I18n.load_path.locales = [:es]
+
+ +One can also specify which file extensions are used. By default this is set to ['rb', 'yml'] so plain Ruby and YAML files are added if found. To define that only *.sql files are added one can specify: + +

+I18n.load_path.extensions = ['sql']
+
+ +Note that Globalize::LoadPath "expands" a directory to its contained file paths immediately when you add it to the load_path. Thus, if you change the locales or extensions settings in the middle of your application the change won't be applied to already added file paths. + + +h2. Globalize::Translation classes + +Globalize2's Static backend as well as Globalize2 model translations return instances of Globalize::Translation classes (instead of plain Ruby Strings). These are simple and lightweight value objects that carry some additional meta data about the translation and how it was looked up. + +Model translations return instances of Globalize::Translation::Attribute, the Static backend returns instances of Globalize::Translation::Static. + +For example: + +

+I18n.locale = :de
+
+# Translation::Attribute
+title = Post.first.title  # assuming that no translation can be found:
+title.locale              # => :en
+title.requested_locale    # => :de 
+title.fallback?           # => true
+
+# Translation::Static
+rails = I18n.t :rails     # assuming that no translation can be found:
+rails.locale              # => :en
+rails.requested_locale    # => :de 
+rails.fallback?           # => true
+rails.options             # returns the options passed to #t
+rails.plural_key          # returns the plural_key (e.g. :one, :other)
+rails.original            # returns the original translation with no values 
+                          # interpolated to it (e.g. "Hi {{name}}!")
+
+ +h2. Missing Translations Log Handler + +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 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 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..d4513a5c7 --- /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/init.rb b/vendor/plugins/globalize2/init.rb new file mode 100644 index 000000000..7b5428ecf --- /dev/null +++ b/vendor/plugins/globalize2/init.rb @@ -0,0 +1,10 @@ +require 'rails_edge_load_path_patch.rb' unless I18n.respond_to?(:load_path) + +ActiveRecord::Base.send :include, Globalize::Model::ActiveRecord::Translated + +I18n.backend = Globalize::Backend::Static.new + +I18n.load_path = Globalize::LoadPath.new I18n.load_path +I18n.load_path << "#{File.dirname(__FILE__)}/lib/locale" +I18n.load_path << "#{RAILS_ROOT}/lib/locale" + diff --git a/vendor/plugins/globalize2/lib/globalize/backend/chain.rb b/vendor/plugins/globalize2/lib/globalize/backend/chain.rb new file mode 100644 index 000000000..bb8679ecb --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize/backend/chain.rb @@ -0,0 +1,102 @@ +module I18n + class << self + def chain_backends(*args) + self.backend = Globalize::Backend::Chain.new(*args) + end + end +end + +module Globalize + module Backend + class Chain + def initialize(*args) + add(*args) unless args.empty? + end + + # Change this to a) accept any number of backends and b) accept classes. + # When classes are passed instantiate them and add the instances as backends. + # Return the added backends from #add. + # + # Add an initialize method that accepts the same arguments and passes them + # to #add, so we could: + # I18n.backend = Globalize::Backend::Chain.new(Globalize::Backend::Foo, Globalize::Backend::Bar) + # Globalize::Backend::Chain.new(:foo, :bar) + # Globalize.chain_backends :foo, :bar + def add(*backends) + backends.each do |backend| + backend = Globalize::Backend.const_get(backend.to_s.capitalize) if backend.is_a? Symbol + backend = backend.new if backend.is_a? Class + self.backends << backend + end + end + + def load_translations(*args) + backends.each{|backend| backend.load_translations(*args) } + end + + # For defaults: + # Never pass any default option to the backends but instead implement our own default + # mechanism (e.g. symbols as defaults would need to be passed to the whole chain to + # be translated). + # + # For namespace lookup: + # Only return if the result is not a hash OR count is not present, otherwise merge them. + # So in effect the count variable would control whether we have a namespace lookup or a + # pluralization going on. + # + # Exceptions: + # Make sure that we catch MissingTranslationData exceptions and raise + # one in the end when no translation was found at all. + # + # For bulk translation: + # If the key is an array we need to call #translate for each of the + # keys and collect the results. + + def translate(locale, key, options = {}) + raise I18n::InvalidLocale.new(locale) if locale.nil? + return key.map{|k| translate locale, k, options } if key.is_a? Array + + default = options.delete(:default) + result = backends.inject({}) do |namespace, backend| + begin + translation = backend.translate(locale.to_sym, key, options) + if namespace_lookup?(translation, options) + namespace.merge! translation + elsif translation + return translation + end + rescue I18n::MissingTranslationData + end + end + result || default(locale, default, options) || raise(I18n::MissingTranslationData.new(locale, key, options)) + end + + def localize(locale, object, format = :default) + backends.each do |backend| + result = backend.localize(locale, object, format) and return result + end + end + + protected + def backends + @backends ||= [] + end + + def default(locale, default, options = {}) + case default + when String then default + when Symbol then translate locale, default, options + when Array then default.each do |obj| + result = default(locale, obj, options.dup) and return result + end and nil + end + rescue I18n::MissingTranslationData + nil + end + + def namespace_lookup?(result, options) + result.is_a?(Hash) and not options.has_key?(:count) + end + end + end +end \ No newline at end of file diff --git a/vendor/plugins/globalize2/lib/globalize/backend/pluralizing.rb b/vendor/plugins/globalize2/lib/globalize/backend/pluralizing.rb new file mode 100644 index 000000000..80016f208 --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize/backend/pluralizing.rb @@ -0,0 +1,37 @@ +require 'i18n/backend/simple' + +module Globalize + module Backend + class Pluralizing < I18n::Backend::Simple + def pluralize(locale, entry, count) + return entry unless entry.is_a?(Hash) and count + key = :zero if count == 0 && entry.has_key?(:zero) + key ||= pluralizer(locale).call(count) + raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key) + translation entry[key], :plural_key => key + end + + def add_pluralizer(locale, pluralizer) + pluralizers[locale.to_sym] = pluralizer + end + + def pluralizer(locale) + pluralizers[locale.to_sym] || default_pluralizer + end + + protected + def default_pluralizer + pluralizers[:en] + end + + def pluralizers + @pluralizers ||= { :en => lambda{|n| n == 1 ? :one : :other } } + end + + # Overwrite this method to return something other than a String + def translation(string, attributes) + string + end + end + end +end \ No newline at end of file diff --git a/vendor/plugins/globalize2/lib/globalize/backend/static.rb b/vendor/plugins/globalize2/lib/globalize/backend/static.rb new file mode 100644 index 000000000..fb9e1fe2a --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize/backend/static.rb @@ -0,0 +1,60 @@ +require 'globalize/backend/pluralizing' +require 'globalize/locale/fallbacks' +require 'globalize/translation' + +module Globalize + module Backend + class Static < Pluralizing + def initialize(*args) + add(*args) unless args.empty? + end + + def translate(locale, key, options = {}) + result, default, fallback = nil, options.delete(:default), nil + I18n.fallbacks[locale].each do |fallback| + begin + result = super(fallback, key, options) and break + rescue I18n::MissingTranslationData + end + end + result ||= default locale, default, options + + attrs = {:requested_locale => locale, :locale => fallback, :key => key, :options => options} + translation(result, attrs) || raise(I18n::MissingTranslationData.new(locale, key, options)) + end + + protected + + alias :orig_interpolate :interpolate unless method_defined? :orig_interpolate + def interpolate(locale, string, values = {}) + result = orig_interpolate(locale, string, values) + translation = translation(string) + translation.nil? ? result : translation.replace(result) + end + + def translation(result, meta = nil) + return unless result + + case result + when Numeric + result + when String + result = Translation::Static.new(result) unless result.is_a? Translation::Static + result.set_meta meta + result + when Hash + Hash[*result.map do |key, value| + [key, translation(value, meta)] + end.flatten] + when Array + result.map do |value| + translation(value, meta) + end + else + result + # raise "unexpected translation type: #{result.inspect}" + end + end + end + end +end \ No newline at end of file diff --git a/vendor/plugins/globalize2/lib/globalize/i18n/missing_translations_log_handler.rb b/vendor/plugins/globalize2/lib/globalize/i18n/missing_translations_log_handler.rb new file mode 100644 index 000000000..3f06ac24f --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize/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 \ No newline at end of file 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 000000000..e32be2801 --- /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/load_path.rb b/vendor/plugins/globalize2/lib/globalize/load_path.rb new file mode 100644 index 000000000..a49825b3a --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize/load_path.rb @@ -0,0 +1,63 @@ +# Locale load_path and Locale loading support. +# +# To use this include the Globalize::LoadPath::I18n module to I18n like this: +# +# I18n.send :include, Globalize::LoadPath::I18n +# +# Clients can add load_paths using: +# +# I18n.load_path.add load_path, 'rb', 'yml' # pass any number of extensions like this +# I18n.load_path << 'path/to/dir' # usage without an extension, defaults to 'yml' +# +# And load locale data using either of: +# +# I18n.load_locales 'en-US', 'de-DE' +# I18n.load_locale 'en-US' +# +# This will lookup all files named like: +# +# 'path/to/dir/all.yml' +# 'path/to/dir/en-US.yml' +# 'path/to/dir/en-US/*.yml' +# +# The filenames will be passed to I18n.load_translations which delegates to +# the backend. So the actual behaviour depends on the implementation of the +# backend. I18n::Backend::Simple will be able to read YAML and plain Ruby +# files. See the documentation for I18n.load_translations for details. + +module Globalize + class LoadPath < Array + def extensions + @extensions ||= ['rb', 'yml'] + end + attr_writer :extensions + + def locales + @locales ||= ['*'] + end + attr_writer :locales + + def <<(path) + push path + end + + def push(*paths) + super(*paths.map{|path| filenames(path) }.flatten.uniq.sort) + end + + protected + + def filenames(path) + return [path] if File.file? path + patterns(path).map{|pattern| Dir[pattern] } + end + + def patterns(path) + locales.map do |locale| + extensions.map do |extension| + %W(#{path}/all.#{extension} #{path}/#{locale}.#{extension} #{path}/#{locale}/**/*.#{extension}) + end + end.flatten.uniq + end + end +end \ No newline at end of file diff --git a/vendor/plugins/globalize2/lib/globalize/locale/fallbacks.rb b/vendor/plugins/globalize2/lib/globalize/locale/fallbacks.rb new file mode 100644 index 000000000..c4acd57a8 --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize/locale/fallbacks.rb @@ -0,0 +1,63 @@ +require 'globalize/locale/language_tag' + +module I18n + @@fallbacks = nil + + class << self + # Returns the current fallbacks. Defaults to +Globalize::Locale::Fallbacks+. + def fallbacks + @@fallbacks ||= Globalize::Locale::Fallbacks.new + end + + # Sets the current fallbacks. Used to set a custom fallbacks instance. + def fallbacks=(fallbacks) + @@fallbacks = fallbacks + end + end +end + +module Globalize + module Locale + class Fallbacks < Hash + def initialize(*defaults) + @map = {} + map defaults.pop if defaults.last.is_a?(Hash) + + defaults = [I18n.default_locale.to_sym] if defaults.empty? + self.defaults = defaults + end + + def defaults=(defaults) + @defaults = defaults.map{|default| compute(default, false) }.flatten << :root + end + attr_reader :defaults + + def [](tag) + tag = tag.to_sym + has_key?(tag) ? fetch(tag) : store(tag, compute(tag)) + end + + def map(mappings) + mappings.each do |from, to| + from, to = from.to_sym, Array(to) + to.each do |to| + @map[from] ||= [] + @map[from] << to.to_sym + end + end + end + + protected + + def compute(tags, include_defaults = true) + result = Array(tags).collect do |tag| + tags = LanguageTag::tag(tag.to_sym).parents(true).map! {|t| t.to_sym } + tags.each{|tag| tags += compute(@map[tag]) if @map[tag] } + tags + end.flatten + result.push *defaults if include_defaults + result.uniq + end + end + end +end diff --git a/vendor/plugins/globalize2/lib/globalize/locale/language_tag.rb b/vendor/plugins/globalize2/lib/globalize/locale/language_tag.rb new file mode 100644 index 000000000..d9aae54f9 --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize/locale/language_tag.rb @@ -0,0 +1,81 @@ +# for specifications see http://en.wikipedia.org/wiki/IETF_language_tag +# +# SimpleParser does not implement advanced usages such as grandfathered tags + +module Globalize + module Locale + module Rfc4646 + SUBTAGS = [:language, :script, :region, :variant, :extension, :privateuse, :grandfathered] + FORMATS = {:language => :downcase, :script => :capitalize, :region => :upcase, :variant => :downcase} + end + + class LanguageTag < Struct.new(*Rfc4646::SUBTAGS) + class << self + def parser + @@parser ||= SimpleParser + end + + def parser=(parser) + @@parser = parser + end + + def tag(tag) + matches = parser.match(tag) + new *matches if matches + end + end + + Rfc4646::FORMATS.each do |name, format| + define_method(name) { self[name].send(format) unless self[name].nil? } + end + + def to_sym + to_s.to_sym + end + + def to_s + @tag ||= to_a.compact.join("-") + end + + def to_a + members.collect {|attr| self.send(attr) } + end + + def parent + segs = to_a.compact + segs.length < 2 ? nil : LanguageTag.tag(segs[0..(segs.length-2)].join('-')) + end + + def parents(include_self = true) + result, parent = [], self.dup + result << parent if include_self + while parent = parent.parent + result << parent + end + result + end + + module SimpleParser + PATTERN = %r{\A(?: + ([a-z]{2,3}(?:(?:-[a-z]{3}){0,3})?|[a-z]{4}|[a-z]{5,8}) # language + (?:-([a-z]{4}))? # script + (?:-([a-z]{2}|\d{3}))? # region + (?:-([0-9a-z]{5,8}|\d[0-9a-z]{3}))* # variant + (?:-([0-9a-wyz](?:-[0-9a-z]{2,8})+))* # extension + (?:-(x(?:-[0-9a-z]{1,8})+))?| # privateuse subtag + (x(?:-[0-9a-z]{1,8})+)| # privateuse tag + /* ([a-z]{1,3}(?:-[0-9a-z]{2,8}){1,2}) */ # grandfathered + )\z}xi + + class << self + def match(tag) + c = PATTERN.match(tag.to_s).captures + c[0..4] << (c[5].nil? ? c[6] : c[5]) << c[7] # TODO c[7] is grandfathered, throw a NotImplemented exception here? + rescue + false + end + end + end + end + end +end 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 000000000..96458425b --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize/model/active_record.rb @@ -0,0 +1,38 @@ +require 'globalize/translation' +require 'globalize/locale/fallbacks' +require 'globalize/model/active_record/adapter' +require 'globalize/model/active_record/translated' + +module Globalize + module Model + module ActiveRecord + class << self + def create_proxy_class(klass) + Object.const_set "#{klass.name}Translation", Class.new(::ActiveRecord::Base){ + belongs_to "#{klass.name.underscore}".intern + + def locale + read_attribute(:locale).to_sym + end + + def locale=(locale) + write_attribute(:locale, locale.to_s) + end + } + end + + def define_accessors(klass, attr_names) + attr_names.each do |attr_name| + klass.send :define_method, attr_name, lambda { + globalize.fetch self.class.locale, attr_name + } + klass.send :define_method, "#{attr_name}=", lambda {|val| + globalize.stash self.class.locale, attr_name, val + self[attr_name] = val + } + end + end + end + end + end +end \ 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 000000000..93355b87f --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize/model/active_record/adapter.rb @@ -0,0 +1,96 @@ +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] ||= {} + self[locale][attr_name] + end + + def write(locale, attr_name, value) + locale = locale.to_sym + self[locale] ||= {} + self[locale][attr_name] = value + end + end + + 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 + 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 + end + end + + def stash(locale, attr_name, value) + @stash.write locale, attr_name, value + @cache.write locale, attr_name, value + end + + def update_translations! + @stash.each do |locale, attrs| + translation = @record.globalize_translations.find_or_initialize_by_locale(locale.to_s) + attrs.each{|attr_name, value| translation[attr_name] = value } + translation.save! + end + @stash.clear + end + + # Clears the cache + def clear + @cache.clear + @stash.clear + end + + private + + def fetch_attribute(locale, attr_name) + fallbacks = I18n.fallbacks[locale].map{|tag| tag.to_s}.map(&:to_sym) + + # If the translations were included with + # :include => globalize_translations + # there is no need to query them again. + unless @record.globalize_translations.loaded? + translations = @record.globalize_translations.by_locales(fallbacks) + else + translations = @record.globalize_translations + end + result, requested_locale = nil, locale + + # Walk through the fallbacks, starting with the current locale itself, and moving + # to the next best choice, until we find a match. + # 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) + end + if result + locale = fallback + break + end + end + result && Translation::Attribute.new(result, :locale => locale, :requested_locale => requested_locale) + end + end + end +end 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 000000000..f8fb230ac --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize/model/active_record/translated.rb @@ -0,0 +1,154 @@ +module Globalize + module Model + + class MigrationError < StandardError; end + class UntranslatedMigrationField < MigrationError; end + class MigrationMissingTranslatedField < MigrationError; end + class BadMigrationFieldType < MigrationError; end + + module ActiveRecord + module Translated + def self.included(base) + base.extend ActMethods + end + + module ActMethods + def translates(*attr_names) + options = attr_names.extract_options! + options[:translated_attributes] = attr_names + + # Only set up once per class + unless included_modules.include? InstanceMethods + class_inheritable_accessor :globalize_options, :globalize_proxy + + include InstanceMethods + extend ClassMethods + + self.globalize_proxy = Globalize::Model::ActiveRecord.create_proxy_class(self) + has_many( + :globalize_translations, + :class_name => globalize_proxy.name, + :extend => Extensions, + :dependent => :delete_all, + :foreign_key => class_name.foreign_key + ) + + after_save :update_globalize_record + end + + self.globalize_options = options + Globalize::Model::ActiveRecord.define_accessors(self, attr_names) + + # Import any callbacks that have been defined by extensions to Globalize2 + # and run them. + 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 + # and they'll be called at the end of the translates class method. + module Callbacks + end + + # Extension to the has_many :globalize_translations association + module Extensions + def by_locales(locales) + find :all, :conditions => { :locale => locales.map(&:to_s) } + end + end + + module ClassMethods + 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 (?)", + 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| + raise MigrationMissingTranslatedField, "Missing translated field #{f}" unless fields[f] + end + fields.each do |name, type| + unless translated_fields.member? name + raise UntranslatedMigrationField, "Can't migrate untranslated field: #{name}" + end + unless [ :string, :text ].member? type + raise BadMigrationFieldType, "Bad field type for #{name}, should be :string or :text" + end + end + translation_table_name = self.name.underscore + '_translations' + self.connection.create_table(translation_table_name) do |t| + t.references self.table_name.singularize + t.string :locale + fields.each do |name, type| + t.column name, type + end + t.timestamps + end + end + + def drop_translation_table! + 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(options = nil) + 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 + + super options + end + + def globalize + @globalize ||= Adapter.new self + end + + def update_globalize_record + globalize.update_translations! + end + + def translated_locales + globalize_translations.scoped(:select => 'DISTINCT locale').map {|gt| gt.locale.to_sym } + end + + def set_translations options + options.keys.each do |key| + + translation = globalize_translations.find_by_locale(key.to_s) || + globalize_translations.build(:locale => key.to_s) + translation.update_attributes!(options[key]) + end + end + + end + end + end + end +end \ No newline at end of file diff --git a/vendor/plugins/globalize2/lib/globalize/translation.rb b/vendor/plugins/globalize2/lib/globalize/translation.rb new file mode 100644 index 000000000..a80afcd7f --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize/translation.rb @@ -0,0 +1,32 @@ +module Globalize + # Translations are simple value objects that carry some context information + # alongside the actual translation string. + + class Translation < String + class Attribute < Translation + attr_accessor :requested_locale, :locale, :key + end + + class Static < Translation + attr_accessor :requested_locale, :locale, :key, :options, :plural_key, :original + + def initialize(string, meta = nil) + self.original = string + super + end + end + + def initialize(string, meta = nil) + set_meta meta + super string + end + + def fallback? + locale.to_sym != requested_locale.to_sym + end + + def set_meta(meta) + meta.each {|name, value| send :"#{name}=", value } if meta + end + end +end \ No newline at end of file diff --git a/vendor/plugins/globalize2/lib/locale/root.yml b/vendor/plugins/globalize2/lib/locale/root.yml new file mode 100644 index 000000000..2ec2b3bf3 --- /dev/null +++ b/vendor/plugins/globalize2/lib/locale/root.yml @@ -0,0 +1,3 @@ +root: + bidi: + direction: left-to-right \ No newline at end of file diff --git a/vendor/plugins/globalize2/lib/rails_edge_load_path_patch.rb b/vendor/plugins/globalize2/lib/rails_edge_load_path_patch.rb new file mode 100644 index 000000000..e6f90d81b --- /dev/null +++ b/vendor/plugins/globalize2/lib/rails_edge_load_path_patch.rb @@ -0,0 +1,40 @@ +module I18n + @@load_path = nil + @@default_locale = :'en-US' + + class << self + def load_path + @@load_path ||= [] + end + + def load_path=(load_path) + @@load_path = load_path + end + end +end + +I18n::Backend::Simple.module_eval do + def initialized? + @initialized ||= false + end + + protected + + def init_translations + load_translations(*I18n.load_path) + @initialized = true + end + + def lookup(locale, key, scope = []) + return unless key + init_translations unless initialized? + keys = I18n.send :normalize_translation_keys, locale, key, scope + keys.inject(translations){|result, k| result[k.to_sym] or return nil } + end +end + +rails_dir = File.expand_path "#{File.dirname(__FILE__)}/../../../rails/" +paths = %w(actionpack/lib/action_view/locale/en-US.yml + activerecord/lib/active_record/locale/en-US.yml + activesupport/lib/active_support/locale/en-US.yml) +paths.each{|path| I18n.load_path << "#{rails_dir}/#{path}" } diff --git a/vendor/plugins/globalize2/notes.textile b/vendor/plugins/globalize2/notes.textile new file mode 100644 index 000000000..b686f4113 --- /dev/null +++ b/vendor/plugins/globalize2/notes.textile @@ -0,0 +1,51 @@ +Stopped DB Backend in the middle, here's where we left off: + +h1. Some Notes + +* Started doing the migration generator in generators/db_backend.rb +* Translation keys will be in dotted string format +* Question: Do we need a plural_key column, or can we build it in to the dotted key? +* We will probably have to code the following methods from scratch, to optimize db calls: +** translate +** localize +** pluralize +* We should refactor @interpolation@ code so that it can be included into backend code without inheriting SimpleBackend +** Rationale: interpolation is something done entirely after a string is fetched from the data store +** Alternately, it could be done from within the I18n module + +h1. Schema + +There will be two db tables. + +# globalize_translations will have: locale, key, translation, created_at, updated_at. +# globalize_translations_map will have: key, translation_id. + +globalize_translations_map will let us easily fetch entire sub-trees of namespaces. +However, this table may not be necessary, as it may be feasible to just use key LIKE "some.namespace.%". + +h1. Caching + +We'll almost certainly want to implement caching in the backend. Should probably be a customized +implementation based on the Rails caching mechanism, to support memcached, etc. + +h1. Queries + +We'll want to pull in lots of stuff at once and return a single translation based on some +quick Ruby selection. The query will look something like this: + +
+
+SELECT * FROM globalize_translations
+WHERE locale in () AND
+key IN (key, default_key)
+
+
+ +The Ruby code would then pick the first translation that satisfies a fallback, in fallback order. +Of course, the records with the supplied key would take precedence of those with the default key. + +h1. Misc + +We should revisit the :zero plural code. On the one hand it's certainly useful for +many apps in many languages. On the other hand it's not mentioned in CLDR, and not a real +concept in language pluralization. Right now, I'm feeling it's still a good idea to keep it in. diff --git a/vendor/plugins/globalize2/test/backends/chained_test.rb b/vendor/plugins/globalize2/test/backends/chained_test.rb new file mode 100644 index 000000000..bb0b3e056 --- /dev/null +++ b/vendor/plugins/globalize2/test/backends/chained_test.rb @@ -0,0 +1,175 @@ +require File.join( File.dirname(__FILE__), '..', 'test_helper' ) +require 'globalize/backend/chain' + +module Globalize + module Backend + class Dummy + def translate(locale, key, options = {}) + end + end + end +end + +class ChainedTest < ActiveSupport::TestCase + + test "instantiates a chained backend and sets test as backend" do + assert_nothing_raised { I18n.chain_backends } + assert_instance_of Globalize::Backend::Chain, I18n.backend + end + + test "passes all given arguments to the chained backends #initialize method" do + Globalize::Backend::Chain.expects(:new).with(:spec, :simple) + I18n.chain_backends :spec, :simple + end + + test "passes all given arguments to #add assuming that they are backends" do + # no idea how to spec that + end +end + +class AddChainedTest < ActiveSupport::TestCase + def setup + I18n.backend = Globalize::Backend::Chain.new + end + + test "accepts an instance of a backend" do + assert_nothing_raised { I18n.backend.add Globalize::Backend::Dummy.new } + assert_instance_of Globalize::Backend::Dummy, I18n.backend.send(:backends).first + end + + test "accepts a class and instantiates the backend" do + assert_nothing_raised { I18n.backend.add Globalize::Backend::Dummy } + assert_instance_of Globalize::Backend::Dummy, I18n.backend.send(:backends).first + end + + test "accepts a symbol, constantizes test as a backend class and instantiates the backend" do + assert_nothing_raised { I18n.backend.add :dummy } + assert_instance_of Globalize::Backend::Dummy, I18n.backend.send(:backends).first + end + + test "accepts any number of backend instances, classes or symbols" do + assert_nothing_raised { I18n.backend.add Globalize::Backend::Dummy.new, Globalize::Backend::Dummy, :dummy } + assert_instance_of Globalize::Backend::Dummy, I18n.backend.send(:backends).first + assert_equal [ Globalize::Backend::Dummy, Globalize::Backend::Dummy, Globalize::Backend::Dummy ], + I18n.backend.send(:backends).map{|backend| backend.class } + end + +end + +class TranslateChainedTest < ActiveSupport::TestCase + def setup + I18n.locale = :en + I18n.backend = Globalize::Backend::Chain.new + @first_backend = I18n::Backend::Simple.new + @last_backend = I18n::Backend::Simple.new + I18n.backend.add @first_backend + I18n.backend.add @last_backend + end + + test "delegates #translate to all backends in the order they were added" do + @first_backend.expects(:translate).with(:en, :foo, {}) + @last_backend.expects(:translate).with(:en, :foo, {}) + I18n.translate :foo + end + + test "returns the result from #translate from the first backend if test's not nil" do + @first_backend.store_translations :en, {:foo => 'foo from first backend'} + @last_backend.store_translations :en, {:foo => 'foo from last backend'} + result = I18n.translate :foo + assert_equal 'foo from first backend', result + end + + test "returns the result from #translate from the second backend if the first one returned nil" do + @first_backend.store_translations :en, {} + @last_backend.store_translations :en, {:foo => 'foo from last backend'} + result = I18n.translate :foo + assert_equal 'foo from last backend', result + end + + test "looks up a namespace from all backends and merges them (if a result is a hash and no count option is present)" do + @first_backend.store_translations :en, {:foo => {:bar => 'bar from first backend'}} + @last_backend.store_translations :en, {:foo => {:baz => 'baz from last backend'}} + result = I18n.translate :foo + assert_equal( {:bar => 'bar from first backend', :baz => 'baz from last backend'}, result ) + end + + test "raises a MissingTranslationData exception if no translation was found" do + assert_raise( I18n::MissingTranslationData ) { I18n.translate :not_here, :raise => true } + end + + test "raises an InvalidLocale exception if the locale is nil" do + assert_raise( I18n::InvalidLocale ) { Globalize::Backend::Chain.new.translate nil, :foo } + end + + test "bulk translates a number of keys from different backends" do + @first_backend.store_translations :en, {:foo => 'foo from first backend'} + @last_backend.store_translations :en, {:bar => 'bar from last backend'} + result = I18n.translate [:foo, :bar] + assert_equal( ['foo from first backend', 'bar from last backend'], result ) + end + + test "still calls #translate on all the backends" do + @last_backend.expects :translate + I18n.translate :not_here, :default => 'default' + end + + test "returns a given default string when no backend returns a translation" do + result = I18n.translate :not_here, :default => 'default' + assert_equal 'default', result + end + +end + +class CustomLocalizeBackend < I18n::Backend::Simple + def localize(locale, object, format = :default) + "result from custom localize backend" if locale == 'custom' + end +end + +class LocalizeChainedTest < ActiveSupport::TestCase + def setup + I18n.locale = :en + I18n.backend = Globalize::Backend::Chain.new + @first_backend = CustomLocalizeBackend.new + @last_backend = I18n::Backend::Simple.new + I18n.backend.add @first_backend + I18n.backend.add @last_backend + @time = Time.now + end + + test "delegates #localize to all backends in the order they were added" do + @first_backend.expects(:localize).with(:en, @time, :default) + @last_backend.expects(:localize).with(:en, @time, :default) + I18n.localize @time + end + + test "returns the result from #localize from the first backend if test's not nil" do + @last_backend.expects(:localize).never + result = I18n.localize @time, :locale => 'custom' + assert_equal 'result from custom localize backend', result + end + + test "returns the result from #localize from the second backend if the first one returned nil" do + @last_backend.expects(:localize).returns "value from last backend" + result = I18n.localize @time + assert_equal 'value from last backend', result + end +end + +class NamespaceChainedTest < ActiveSupport::TestCase + def setup + @backend = Globalize::Backend::Chain.new + end + + test "returns false if the given result is not a Hash" do + assert !@backend.send(:namespace_lookup?, 'foo', {}) + end + + test "returns false if a count option is present" do + assert !@backend.send(:namespace_lookup?, {:foo => 'foo'}, {:count => 1}) + end + + test "returns true if the given result is a Hash AND no count option is present" do + assert @backend.send(:namespace_lookup?, {:foo => 'foo'}, {}) + end +end diff --git a/vendor/plugins/globalize2/test/backends/pluralizing_test.rb b/vendor/plugins/globalize2/test/backends/pluralizing_test.rb new file mode 100644 index 000000000..7445e3ffd --- /dev/null +++ b/vendor/plugins/globalize2/test/backends/pluralizing_test.rb @@ -0,0 +1,63 @@ +require File.join( File.dirname(__FILE__), '..', 'test_helper' ) +require 'globalize/backend/pluralizing' + +class PluralizingTest < ActiveSupport::TestCase + def setup + @backend = Globalize::Backend::Pluralizing.new + @cz_pluralizer = lambda{|c| c == 1 ? :one : (2..4).include?(c) ? :few : :other } + end + + test "#pluralizer returns the pluralizer for a given locale if defined" do + assert_instance_of Proc, @backend.pluralizer(:en) + end + + test "#pluralizer returns the default pluralizer if no pluralizer is defined for the given locale" do + assert_equal @backend.pluralizer(:en), @backend.pluralizer(:de) + end + + test "#add_pluralizer allows to store a pluralizer per locale" do + assert_nothing_raised { @backend.add_pluralizer(:cz, @cz_pluralizer) } + assert_equal @cz_pluralizer, @backend.pluralizer(:cz) + end + +end + +class PluralizePluralizingTest < ActiveSupport::TestCase + def setup + @backend = Globalize::Backend::Pluralizing.new + @cz_pluralizer = lambda{|c| c == 1 ? :one : (2..4).include?(c) ? :few : :other } + @backend.store_translations :en, :foo => {:one => 'one en foo', :other => 'many en foos'} + @backend.store_translations :cz, :foo => {:one => 'one cz foo', :few => 'few cz foos', :other => 'many cz foos'} + end + + test "looks up the :one translation when count is 1" do + assert_equal 'one en foo', @backend.translate(:en, :foo, :count => 1) + end + + test "looks up the :other translation when count is 2" do + assert_equal 'many en foos', @backend.translate(:en, :foo, :count => 2) + end +end + +class CzPluralizingTest < ActiveSupport::TestCase + def setup + @backend = Globalize::Backend::Pluralizing.new + @cz_pluralizer = lambda{|c| c == 1 ? :one : (2..4).include?(c) ? :few : :other } + @backend.store_translations :en, :foo => {:one => 'one en foo', :other => 'many en foos'} + @backend.store_translations :cz, :foo => {:one => 'one cz foo', :few => 'few cz foos', :other => 'many cz foos'} + @backend.add_pluralizer(:cz, @cz_pluralizer) + end + + test "looks up the :one translation when count is 1 (:cz)" do + assert_equal 'one cz foo', @backend.translate(:cz, :foo, :count => 1) + end + + test "looks up the :few translation when count is 2 (:cz)" do + assert_equal 'few cz foos', @backend.translate(:cz, :foo, :count => 2) + end + + test "looks up the :other translation when count is 5 (:cz)" do + assert_equal 'many cz foos', @backend.translate(:cz, :foo, :count => 5) + end + +end diff --git a/vendor/plugins/globalize2/test/backends/static_test.rb b/vendor/plugins/globalize2/test/backends/static_test.rb new file mode 100644 index 000000000..133e5477c --- /dev/null +++ b/vendor/plugins/globalize2/test/backends/static_test.rb @@ -0,0 +1,143 @@ +require File.join( File.dirname(__FILE__), '..', 'test_helper' ) +require 'globalize/backend/static' +require 'globalize/translation' +require 'action_view' +include ActionView::Helpers::NumberHelper + +I18n.locale = :'en-US' # Need to set this, since I18n defaults to 'en' + +class StaticTest < ActiveSupport::TestCase + def setup + I18n.backend = Globalize::Backend::Static.new + translations = {:"en-US" => {:foo => "foo in en-US", :boz => 'boz', :buz => {:bum => 'bum'}}, + :"en" => {:bar => "bar in en"}, + :"de-DE" => {:baz => "baz in de-DE"}, + :"de" => {:boo => "boo in de", :number => { :currency => { :format => { :unit => '€', :format => '%n %u'}}}}} + translations.each do |locale, data| + I18n.backend.store_translations locale, data + end + I18n.fallbacks.map :"de-DE" => :"en-US", :he => :en + end + + test "returns an instance of Translation:Static" do + translation = I18n.translate :foo + assert_instance_of Globalize::Translation::Static, translation + end + + test "returns the translation in en-US if present" do + assert_equal "foo in en-US", I18n.translate(:foo, :locale => :"en-US") + end + + test "returns the translation in en if en-US is not present" do + assert_equal "bar in en", I18n.translate(:bar, :locale => :"en-US") + end + + test "returns the translation in de-DE if present" do + assert_equal "baz in de-DE", I18n.translate(:baz, :locale => :"de-DE") + end + + test "returns the translation in de if de-DE is not present" do + assert_equal "boo in de", I18n.translate(:boo, :locale => :"de-DE") + end + + test "returns the translation in en-US if none of de-DE and de are present" do + assert_equal "foo in en-US", I18n.translate(:foo, :locale => :"de-DE") + end + + test "returns the translation in en if none of de-DE, de and en-US are present" do + assert_equal "bar in en", I18n.translate(:bar, :locale => :"de-DE") + end + + test "returns the translation in en if none in he is present" do + assert_equal "bar in en", I18n.translate(:bar, :locale => :he) + end + + test "returns the given default String when the key is not present for any locale" do + assert_equal "default", I18n.translate(:missing, :default => "default") + end + + test "returns the fallback translation for the key if present for a fallback locale" do + I18n.backend.store_translations :de, :non_default => "non_default in de" + assert_equal "non_default in de", I18n.translate(:non_default, :default => "default", :locale => :"de-DE") + end + + test "returns an array of translations" do + assert_instance_of Array, I18n.translate([:foo, :boz]) + end + + test "returns an array of instances of Translation::Static" do + assert_equal [Globalize::Translation::Static], I18n.translate([:foo, :boz]).map(&:class).uniq + end + + test "returns a hash of translations" do + assert_instance_of Hash, I18n.translate(:"buz") + end + + test "returns an array of translations 2" do + assert_equal [Globalize::Translation::Static], I18n.translate(:"buz").values.map(&:class) + end + + test "returns currency properly formated" do + currency = number_to_currency(10) + assert_equal "$10.00", currency + end + + test "returns currency properly formated for locale" do + currency = number_to_currency(10, :locale => :'de') + assert_equal "10.000 €", currency + end + + test "returns currency properly formated from parameters" do + currency = number_to_currency(10, :format => "%n %u", :unit => '€') + assert_equal "10.00 €", currency + end + + test "makes sure interpolation does not break even with False as string" do + assert_equal "translation missing: en, support, array, skip_last_comma", I18n.translate(:"support.array.skip_last_comma") + end +end + +class TranslationStaticTest < ActiveSupport::TestCase + def setup + I18n.backend = Globalize::Backend::Static.new + translations = { + :greeting => "Hi {{name}}", + :messages => { :one => "You have one message.", :other => "You have {{count}} messages."} + } + I18n.backend.store_translations :"en", translations + end + + def greeting + I18n.translate :greeting, :locale => :"en-US", :name => "Joshua" + end + + test "stores the actual locale" do + assert_equal :en, greeting.locale + end + + test "stores the requested locale" do + assert_equal :'en-US', greeting.requested_locale + end + + test "stores the requested key" do + assert_equal :greeting, greeting.key + end + + test "stores the options given to #translate" do + assert_equal( {:name => "Joshua"}, greeting.options ) + end + + test "stores the original translation before test was interpolated" do + assert_equal "Hi {{name}}", greeting.original + end + + test "stores the plural_key :one if pluralized as such" do + message = I18n.translate :messages, :locale => :"en-US", :count => 1 + assert_equal :one, message.plural_key + end + + test "stores the plural_key :other if pluralized as such" do + messages = I18n.translate :messages, :locale => :"en-US", :count => 2 + assert_equal :other, messages.plural_key + end +end diff --git a/vendor/plugins/globalize2/test/data/locale/all.yml b/vendor/plugins/globalize2/test/data/locale/all.yml new file mode 100644 index 000000000..ee4fb4a4a --- /dev/null +++ b/vendor/plugins/globalize2/test/data/locale/all.yml @@ -0,0 +1,2 @@ +en-US: + from-all-file: From the "all" file. diff --git a/vendor/plugins/globalize2/test/data/locale/de-DE.yml b/vendor/plugins/globalize2/test/data/locale/de-DE.yml new file mode 100644 index 000000000..d4c468ed3 --- /dev/null +++ b/vendor/plugins/globalize2/test/data/locale/de-DE.yml @@ -0,0 +1,2 @@ +de-DE: + from-locale-file: Aus der Locale Datei. \ No newline at end of file diff --git a/vendor/plugins/globalize2/test/data/locale/en-US.yml b/vendor/plugins/globalize2/test/data/locale/en-US.yml new file mode 100644 index 000000000..866b171af --- /dev/null +++ b/vendor/plugins/globalize2/test/data/locale/en-US.yml @@ -0,0 +1,2 @@ +en-US: + from-locale-file: From the locale file. diff --git a/vendor/plugins/globalize2/test/data/locale/en-US/module.yml b/vendor/plugins/globalize2/test/data/locale/en-US/module.yml new file mode 100644 index 000000000..6655e9bf0 --- /dev/null +++ b/vendor/plugins/globalize2/test/data/locale/en-US/module.yml @@ -0,0 +1,2 @@ +en-US: + from-locale-dir: From the locale directory. diff --git a/vendor/plugins/globalize2/test/data/locale/fi-FI/module.yml b/vendor/plugins/globalize2/test/data/locale/fi-FI/module.yml new file mode 100644 index 000000000..62d00b1f4 --- /dev/null +++ b/vendor/plugins/globalize2/test/data/locale/fi-FI/module.yml @@ -0,0 +1,2 @@ +fi-FI: + from-locale-dir: Locale hakemistosta. \ No newline at end of file diff --git a/vendor/plugins/globalize2/test/data/locale/root.yml b/vendor/plugins/globalize2/test/data/locale/root.yml new file mode 100644 index 000000000..e69de29bb 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..7cfaf69d3 --- /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/post.rb b/vendor/plugins/globalize2/test/data/post.rb new file mode 100644 index 000000000..6673dc446 --- /dev/null +++ b/vendor/plugins/globalize2/test/data/post.rb @@ -0,0 +1,24 @@ +class Post < ActiveRecord::Base + translates :subject, :content + validates_presence_of :subject +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 \ No newline at end of file diff --git a/vendor/plugins/globalize2/test/data/schema.rb b/vendor/plugins/globalize2/test/data/schema.rb new file mode 100644 index 000000000..8d076aeb9 --- /dev/null +++ b/vendor/plugins/globalize2/test/data/schema.rb @@ -0,0 +1,39 @@ +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 :translated_comment_translations, :force => true do |t| + t.string :locale + t.references :comment + t.string :subject + t.text :content + end + +end \ No newline at end of file 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..8641d57f8 --- /dev/null +++ b/vendor/plugins/globalize2/test/i18n/missing_translations_test.rb @@ -0,0 +1,36 @@ +require File.join( File.dirname(__FILE__), '..', 'test_helper' ) +require 'globalize/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/load_path_test.rb b/vendor/plugins/globalize2/test/load_path_test.rb new file mode 100644 index 000000000..ff009b387 --- /dev/null +++ b/vendor/plugins/globalize2/test/load_path_test.rb @@ -0,0 +1,49 @@ +require File.join( File.dirname(__FILE__), 'test_helper' ) +require 'globalize/load_path' + +class LoadPathTest < ActiveSupport::TestCase + def setup + @plugin_dir = "#{File.dirname(__FILE__)}/.." + @locale_dir = "#{File.dirname(__FILE__)}/data/locale" + @load_path = Globalize::LoadPath.new + end + + test "returns glob patterns for all locales and ruby + yaml files by default" do + patterns = %w(locales/all.rb + locales/*.rb + locales/*/**/*.rb + locales/all.yml + locales/*.yml + locales/*/**/*.yml) + assert_equal patterns, @load_path.send(:patterns, 'locales') + end + + test "returns the glob patterns for registered locales and extensions" do + @load_path.locales = [:en, :de] + @load_path.extensions = [:sql] + patterns = %w(locales/all.sql + locales/en.sql + locales/en/**/*.sql + locales/de.sql + locales/de/**/*.sql) + assert_equal patterns, @load_path.send(:patterns, 'locales') + end + + test "expands paths using yml as a default file extension" do + @load_path << @locale_dir + expected = %w(all.yml de-DE.yml en-US.yml en-US/module.yml fi-FI/module.yml root.yml) + assert_equal expected, @load_path.map{|path| path.sub("#{@locale_dir}\/", '')} + end + + test "appends new paths to the collection so earlier collected paths preceed later collected ones" do + @load_path.locales = [:root] + @load_path << "#{@plugin_dir}/lib/locale" + @load_path << @locale_dir + + expected = %W(#{@plugin_dir}/lib/locale/root.yml + #{@locale_dir}/all.yml + #{@locale_dir}/root.yml) + assert_equal expected, @load_path + end + +end diff --git a/vendor/plugins/globalize2/test/locale/fallbacks_test.rb b/vendor/plugins/globalize2/test/locale/fallbacks_test.rb new file mode 100644 index 000000000..304d3da07 --- /dev/null +++ b/vendor/plugins/globalize2/test/locale/fallbacks_test.rb @@ -0,0 +1,154 @@ +require File.join( File.dirname(__FILE__), '..', 'test_helper' ) +require 'globalize/locale/fallbacks' + +include Globalize::Locale +I18n.default_locale = :'en-US' # This has to be set explicitly, no longer default for I18n + +class FallbacksTest < ActiveSupport::TestCase + def setup + I18n.fallbacks = Fallbacks.new + end + + def teardown + I18n.default_locale = :'en-US' + end + + test "#[] caches computed results" do + I18n.fallbacks['en'] + assert_equal( { :en => [:en, :"en-US", :root] }, I18n.fallbacks ) + end + + test "#defaults always reflect the I18n.default_locale if no default has been set manually" do + I18n.default_locale = :'en-US' + assert_equal( [:'en-US', :en, :root], I18n.fallbacks.defaults ) + end + + test "#defaults always reflect a manually passed default locale if any" do + I18n.fallbacks = Fallbacks.new(:'fi-FI') + assert_equal( [:'fi-FI', :fi, :root], I18n.fallbacks.defaults ) + I18n.default_locale = :'de-DE' + assert_equal( [:'fi-FI', :fi, :root], I18n.fallbacks.defaults ) + end + + test "#defaults allows to set multiple defaults" do + I18n.fallbacks = Fallbacks.new(:'fi-FI', :'se-FI') + assert_equal( [:'fi-FI', :fi, :'se-FI', :se, :root], I18n.fallbacks.defaults ) + end +end + +class NoMappingFallbacksTest < ActiveSupport::TestCase + def setup + @fallbacks = Fallbacks.new(:'en-US') + end + + test "returns [:es, :en-US, :root] for :es" do + assert_equal [:es, :"en-US", :en, :root], @fallbacks[:es] + end + + test "returns [:es-ES, :es, :en-US, :root] for :es-ES" do + assert_equal [:"es-ES", :es, :"en-US", :en, :root], @fallbacks[:"es-ES"] + end + + test "returns [:es-MX, :es, :en-US, :root] for :es-MX" do + assert_equal [:"es-MX", :es, :"en-US", :en, :root], @fallbacks[:"es-MX"] + end + + test "returns [:es-Latn-ES, :es-Latn, :es, :en-US, :root] for :es-Latn-ES" do + assert_equal [:"es-Latn-ES", :"es-Latn", :es, :"en-US", :en, :root], @fallbacks[:'es-Latn-ES'] + end + + test "returns [:en, :en-US, :root] for :en" do + assert_equal [:en, :"en-US", :root], @fallbacks[:en] + end + + test "returns [:en-US, :en, :root] for :en-US (special case: locale == default)" do + assert_equal [:"en-US", :en, :root], @fallbacks[:"en-US"] + end +end + +class CaMappingFallbacksTest < ActiveSupport::TestCase + # Most people who speak Catalan also live in Spain, so test is safe to assume + # that they also speak Spanish as spoken in Spain. + def setup + @fallbacks = Fallbacks.new(:'en-US') + @fallbacks.map :ca => :"es-ES" + end + + test "returns [:ca, :es-ES, :es, :en-US, :root] for :ca" do + assert_equal [:ca, :"es-ES", :es, :"en-US", :en, :root], @fallbacks[:ca] + end + + test "returns [:ca-ES, :ca, :es-ES, :es, :en-US, :root] for :ca-ES" do + assert_equal [:"ca-ES", :ca, :"es-ES", :es, :"en-US", :en, :root], @fallbacks[:"ca-ES"] + end +end + +class ArMappingFallbacksTest < ActiveSupport::TestCase + # People who speak Arabic as spoken in Palestine often times also speak + # Hebrew as spoken in Israel. However test is in no way safe to assume that + # everybody who speaks Arabic also speaks Hebrew. + def setup + @fallbacks = Fallbacks.new(:'en-US') + @fallbacks.map :"ar-PS" => :"he-IL" + end + + test "returns [:ar, :en-US, :root] for :ar" do + assert_equal [:ar, :"en-US", :en, :root], @fallbacks[:ar] + end + + test "returns [:ar-EG, :ar, :en-US, :root] for :ar-EG" do + assert_equal [:"ar-EG", :ar, :"en-US", :en, :root], @fallbacks[:"ar-EG"] + end + + test "returns [:ar-PS, :ar, :he-IL, :he, :en-US, :root] for :ar-PS" do + assert_equal [:"ar-PS", :ar, :"he-IL", :he, :"en-US", :en, :root], @fallbacks[:"ar-PS"] + end +end + +class SmsMappingFallbacksTest < ActiveSupport::TestCase + # Sami people live in several scandinavian countries. In Finnland many people + # know Swedish and Finnish. Thus, test can be assumed that Sami living in + # Finnland also speak Swedish and Finnish. + def setup + @fallbacks = Fallbacks.new(:'en-US') + @fallbacks.map :sms => [:"se-FI", :"fi-FI"] + end + + test "returns [:sms-FI, :sms, :se-FI, :se, :fi-FI, :fi, :en-US, :root] for :sms-FI" do + assert_equal [:"sms-FI", :sms, :"se-FI", :se, :"fi-FI", :fi, :"en-US", :en, :root], @fallbacks[:"sms-FI"] + end +end + +class DeAtMappingFallbacksTest < ActiveSupport::TestCase + def setup + @fallbacks = Fallbacks.new(:'en-US') + @fallbacks.map :"de-AT" => :"de-DE" + end + + test "returns [:de, :en-US, :root] for de" do + assert_equal [:de, :"en-US", :en, :root], @fallbacks[:"de"] + end + + test "returns [:de-DE, :de, :en-US, :root] for de-DE" do + assert_equal [:"de-DE", :de, :"en-US", :en, :root], @fallbacks[:"de-DE"] + end + + test "returns [:de-AT, :de, :de-DE, :en-US, :root] for de-AT" do + assert_equal [:"de-AT", :de, :"de-DE", :"en-US", :en, :root], @fallbacks[:"de-AT"] + end +end + +class DeMappingFallbacksTest < ActiveSupport::TestCase + def setup + @fallbacks = Fallbacks.new(:'en-US') + @fallbacks.map :de => :en, :he => :en + end + + test "returns [:de, :en, :root] for :de" do + assert_equal [:de, :en, :"en-US", :root], @fallbacks[:de] + end + + test "returns [:he, :en, :root] for :de" do + assert_equal [:he, :en, :"en-US", :root], @fallbacks[:he] + end +end diff --git a/vendor/plugins/globalize2/test/locale/language_tag_test.rb b/vendor/plugins/globalize2/test/locale/language_tag_test.rb new file mode 100644 index 000000000..2448af12c --- /dev/null +++ b/vendor/plugins/globalize2/test/locale/language_tag_test.rb @@ -0,0 +1,130 @@ +require File.join( File.dirname(__FILE__), '..', 'test_helper' ) +require 'globalize/locale/language_tag' + +include Globalize::Locale + +class LanguageTagTest < ActiveSupport::TestCase + test "given a valid tag 'de' returns an LanguageTag from #tag" do + assert_instance_of LanguageTag, LanguageTag.tag('de') + end + + test "given a valid tag 'de' returns an array of subtags" do + assert_equal ['de', nil, nil, nil, nil, nil, nil], LanguageTag::SimpleParser.match('de') + end + + test "given a valid tag 'de-DE' returns an array of subtags" do + assert_equal ['de', nil, 'DE', nil, nil, nil, nil], LanguageTag::SimpleParser.match('de-DE') + end + + test "given a valid lowercase tag 'de-latn-de-variant-x-phonebk' returns an array of subtags" do + assert_equal ['de', 'latn', 'de', 'variant', nil, 'x-phonebk', nil], + LanguageTag::SimpleParser.match('de-latn-de-variant-x-phonebk') + end + + test "given a valid uppercase tag 'DE-LATN-DE-VARIANT-X-PHONEBK' returns an array of subtags" do + assert_equal ['DE', 'LATN', 'DE', 'VARIANT', nil, 'X-PHONEBK', nil], + LanguageTag::SimpleParser.match('DE-LATN-DE-VARIANT-X-PHONEBK') + end + + test "given an invalid tag 'a-DE' test returns false" do + assert !LanguageTag::SimpleParser.match('a-DE') + end + + test "given an invalid tag 'de-419-DE' test returns false" do + assert !LanguageTag::SimpleParser.match('de-419-DE') + end +end + +class DeLatnLanguageTagTest < ActiveSupport::TestCase + def setup + subtags = %w(de Latn DE variant a-ext x-phonebk i-klingon) + @tag = LanguageTag.new *subtags + end + + test "returns 'de' as the language subtag in lowercase" do + assert_equal 'de', @tag.language + end + + test "returns 'Latn' as the script subtag in titlecase" do + assert_equal 'Latn', @tag.script + end + + test "returns 'DE' as the region subtag in uppercase" do + assert_equal 'DE', @tag.region + end + + test "returns 'variant' as the variant subtag in lowercase" do + assert_equal 'variant', @tag.variant + end + + test "returns 'a-ext' as the extension subtag" do + assert_equal 'a-ext', @tag.extension + end + + test "returns 'x-phonebk' as the privateuse subtag" do + assert_equal 'x-phonebk', @tag.privateuse + end + + test "returns 'i-klingon' as the grandfathered subtag" do + assert_equal 'i-klingon', @tag.grandfathered + end + + test "returns a formatted tag string from #to_s" do + assert_equal 'de-Latn-DE-variant-a-ext-x-phonebk-i-klingon', @tag.to_s + end + + test "returns an array containing the formatted subtags from #to_a" do + assert_equal %w(de Latn DE variant a-ext x-phonebk i-klingon), @tag.to_a + end +end + +class InheritanceLanguageTagTest < ActiveSupport::TestCase + test "returns 'de-Latn-DE-variant-a-ext-x-phonebk' as the parent of 'de-Latn-DE-variant-a-ext-x-phonebk-i-klingon'" do + tag = LanguageTag.new *%w(de Latn DE variant a-ext x-phonebk i-klingon) + assert_equal 'de-Latn-DE-variant-a-ext-x-phonebk', tag.parent.to_s + end + + test "returns 'de-Latn-DE-variant-a-ext' as the parent of 'de-Latn-DE-variant-a-ext-x-phonebk'" do + tag = LanguageTag.new *%w(de Latn DE variant a-ext x-phonebk) + assert_equal 'de-Latn-DE-variant-a-ext', tag.parent.to_s + end + + test "returns 'de-Latn-DE-variant' as the parent of 'de-Latn-DE-variant-a-ext'" do + tag = LanguageTag.new *%w(de Latn DE variant a-ext) + assert_equal 'de-Latn-DE-variant', tag.parent.to_s + end + + test "returns 'de-Latn-DE' as the parent of 'de-Latn-DE-variant'" do + tag = LanguageTag.new *%w(de Latn DE variant) + assert_equal 'de-Latn-DE', tag.parent.to_s + end + + test "returns 'de-Latn' as the parent of 'de-Latn-DE'" do + tag = LanguageTag.new *%w(de Latn DE) + assert_equal 'de-Latn', tag.parent.to_s + end + + test "returns 'de' as the parent of 'de-Latn'" do + tag = LanguageTag.new *%w(de Latn) + assert_equal 'de', tag.parent.to_s + end + + # TODO RFC4647 says: "If no language tag matches the request, the "default" value is returned." + # where should we set the default language? + # test "returns '' as the parent of 'de'" do + # tag = LanguageTag.new *%w(de) + # assert_equal '', tag.parent.to_s + # end + + test "returns an array of 5 parents for 'de-Latn-DE-variant-a-ext-x-phonebk-i-klingon'" do + parents = %w(de-Latn-DE-variant-a-ext-x-phonebk-i-klingon + de-Latn-DE-variant-a-ext-x-phonebk + de-Latn-DE-variant-a-ext + de-Latn-DE-variant + de-Latn-DE + de-Latn + de) + tag = LanguageTag.new *%w(de Latn DE variant a-ext x-phonebk i-klingon) + assert_equal parents, tag.parents.map{|tag| tag.to_s} + end +end diff --git a/vendor/plugins/globalize2/test/model/active_record/migration_test.rb b/vendor/plugins/globalize2/test/model/active_record/migration_test.rb new file mode 100644 index 000000000..c539fb6e3 --- /dev/null +++ b/vendor/plugins/globalize2/test/model/active_record/migration_test.rb @@ -0,0 +1,73 @@ +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 MigrationTest < ActiveSupport::TestCase + def setup + reset_db! File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'data', 'no_globalize_schema.rb')) + end + + test 'globalize table added' do + assert !Post.connection.table_exists?( :post_translations ) + Post.create_translation_table! :subject => :string, :content => :text + assert Post.connection.table_exists?( :post_translations ) + 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 ) + Post.create_translation_table! :subject => :string, :content => :text + assert Post.connection.table_exists?( :post_translations ) + Post.drop_translation_table! + assert !Post.connection.table_exists?( :post_translations ) + end + + test 'exception on untranslated field inputs' do + assert_raise Globalize::Model::UntranslatedMigrationField do + Post.create_translation_table! :subject => :string, :content => :text, :bogus => :string + end + end + + test 'exception on missing field inputs' do + assert_raise Globalize::Model::MigrationMissingTranslatedField do + Post.create_translation_table! :content => :text + end + end + + test 'exception on bad input type' do + assert_raise Globalize::Model::BadMigrationFieldType do + Post.create_translation_table! :subject => :string, :content => :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 + +end \ No newline at end of file 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 000000000..14d7d0f95 --- /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 new file mode 100644 index 000000000..3e9ea00ab --- /dev/null +++ b/vendor/plugins/globalize2/test/model/active_record/translated_test.rb @@ -0,0 +1,458 @@ +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 TranslatedTest < ActiveSupport::TestCase + def setup + I18n.locale = :'en-US' + I18n.fallbacks.clear + reset_db! File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'data', 'schema.rb')) + ActiveRecord::Base.locale = nil + end + + def teardown + I18n.fallbacks.clear + end + + test "modifiying translated fields" do + post = Post.create :subject => 'foo' + assert_equal 'foo', post.subject + post.subject = 'bar' + assert_equal 'bar', post.subject + end + + test "modifiying translated fields while switching locales" do + post = Post.create :subject => 'foo' + assert_equal 'foo', post.subject + I18n.locale = :'de-DE' + post.subject = 'bar' + assert_equal 'bar', post.subject + I18n.locale = :'en-US' + assert_equal 'foo', post.subject + I18n.locale = :'de-DE' + post.subject = 'bar' + end + + test "has post_translations" do + post = Post.create + assert_nothing_raised { post.globalize_translations } + end + + test "has German post_translations" do + I18n.locale = :de + post = Post.create :subject => 'foo' + assert_equal 1, post.globalize_translations.size + I18n.locale = :en + assert_equal 1, post.globalize_translations.size + end + + test "returns the value passed to :subject" do + post = Post.new + assert_equal 'foo', (post.subject = 'foo') + end + + test "translates subject and content into en-US" do + post = Post.create :subject => 'foo', :content => 'bar' + assert_equal 'foo', post.subject + assert_equal 'bar', post.content + assert post.save + post.reload + assert_equal 'foo', post.subject + assert_equal 'bar', post.content + end + + test "finds a German post" do + post = Post.create :subject => 'foo (en)', :content => 'bar' + I18n.locale = 'de-DE' + post = Post.first + post.subject = 'baz (de)' + post.save + assert_equal 'baz (de)', Post.first.subject + I18n.locale = :'en-US' + assert_equal 'foo (en)', Post.first.subject + end + + test "saves an English post and loads test correctly" do + assert_nil Post.first + 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 "updates an attribute" do + post = Post.create :subject => 'foo', :content => 'bar' + post.update_attribute :subject, 'baz' + 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 + + post = Post.new :subject => 'foo' + assert post.save + end + + test "returns the value for the correct locale, after locale switching" do + post = Post.create :subject => 'foo' + I18n.locale = 'de-DE' + post.subject = 'bar' + post.save + I18n.locale = 'en-US' + post = Post.first + assert_equal 'foo', post.subject + I18n.locale = 'de-DE' + assert_equal 'bar', post.subject + 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 "returns the value for the correct locale, after locale switching, without saving" do + post = Post.create :subject => 'foo' + I18n.locale = 'de-DE' + post.subject = 'bar' + I18n.locale = 'en-US' + assert_equal 'foo', post.subject + I18n.locale = 'de-DE' + assert_equal 'bar', post.subject + end + + test "saves all locales, even after locale switching" do + post = Post.new :subject => 'foo' + I18n.locale = 'de-DE' + post.subject = 'bar' + I18n.locale = 'he-IL' + post.subject = 'baz' + post.save + I18n.locale = 'en-US' + post = Post.first + assert_equal 'foo', post.subject + I18n.locale = 'de-DE' + assert_equal 'bar', post.subject + I18n.locale = 'he-IL' + assert_equal 'baz', post.subject + 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 "returns nil if no translations are found" do + post = Post.new :subject => 'foo' + assert_equal 'foo', post.subject + assert_nil post.content + end + + test "returns nil if no translations are found; reloaded" do + post = Post.create :subject => 'foo' + post = Post.first + assert_equal 'foo', post.subject + assert_nil post.content + end + + test "works with associations" do + blog = Blog.create + post1 = blog.posts.create :subject => 'foo' + I18n.locale = 'de-DE' + post2 = blog.posts.create :subject => 'bar' + assert_equal 2, blog.posts.size + I18n.locale = 'en-US' + assert_equal 'foo', blog.posts.first.subject + assert_nil blog.posts.last.subject + I18n.locale = 'de-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 '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 '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 + + test "including globalize_translations" do + I18n.locale = :de + Post.create :subject => "Foo1", :content => "Bar1" + Post.create :subject => "Foo2", :content => "Bar2" + + class << Post + def tranlsations_included + self.all(:include => :globalize_translations) + end + end + + default = Post.all.map {|x| [x.subject, x.content]} + with_include = Post.tranlsations_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.globalize_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.globalize_translations.size + 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. +# 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/test_helper.rb b/vendor/plugins/globalize2/test/test_helper.rb new file mode 100644 index 000000000..956b352fe --- /dev/null +++ b/vendor/plugins/globalize2/test/test_helper.rb @@ -0,0 +1,26 @@ +require 'rubygems' +require 'test/unit' +require 'active_support' +require 'active_support/test_case' +require 'mocha' + +$LOAD_PATH << File.expand_path( File.dirname(__FILE__) + '/../lib' ) + +class ActiveSupport::TestCase + 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 schema_path + end + end + + def assert_member(item, arr) + assert_block "Item #{item} is not in array #{arr}" do + arr.member? item + end + end +end \ No newline at end of file diff --git a/vendor/plugins/globalize2/test/translation_test.rb b/vendor/plugins/globalize2/test/translation_test.rb new file mode 100644 index 000000000..4b52bb10f --- /dev/null +++ b/vendor/plugins/globalize2/test/translation_test.rb @@ -0,0 +1,54 @@ +require File.join( File.dirname(__FILE__), 'test_helper' ) +require 'globalize/translation' + +class TranslationTest < ActiveSupport::TestCase + include Globalize + + def setup + @translation = Translation::Static.new 'foo', :locale => :'en-US' + end + + test "responds to fallback?" do + assert @translation.respond_to?( :fallback? ) + end + + test "returns true when :locale and :requested_locale are not equal" do + @translation.requested_locale = :'de-DE' + assert @translation.fallback? + end + + test "returns false when :locale and :requested_locale are equal" do + @translation.requested_locale = :'en-US' + assert !@translation.fallback? + end + + test "has the attribute :locale" do + assert @translation.respond_to?( :locale ) + end + + test "has the attribute :requested_locale" do + assert @translation.respond_to?( :requested_locale ) + end + + test "has the attribute :options" do + assert @translation.respond_to?( :options ) + end + + test "has the attribute :plural_key" do + assert @translation.respond_to?( :plural_key ) + end + + test "has the attribute :original" do + assert @translation.respond_to?( :original ) + end + + test "Translation::Attribute has the attribute :locale" do + translation = Translation::Attribute.new 'foo' + assert translation.respond_to?( :locale ) + end + + test "Translation::Attribute has the attribute :requested_locale" do + translation = Translation::Attribute.new 'foo' + assert translation.respond_to?( :requested_locale ) + end +end -- 2.39.5