diff options
| author | hukl <hukl@eight.local> | 2009-02-07 15:50:40 +0100 |
|---|---|---|
| committer | hukl <hukl@eight.local> | 2009-02-07 15:50:40 +0100 |
| commit | 36a2f1f3c085dd81171cf7d8220770d4ff921ab3 (patch) | |
| tree | 5ded15331b192bf428af4c94d46d1abb28ef0690 /vendor/plugins/globalize2/lib | |
| parent | ce9645d0092d42c7bf8781378181ffbd4ff3d088 (diff) | |
added globalize2 plugin as well as some modifications
which use the new translation facilities.
backend mostly.
Diffstat (limited to 'vendor/plugins/globalize2/lib')
13 files changed, 747 insertions, 0 deletions
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 0000000..bb8679e --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize/backend/chain.rb | |||
| @@ -0,0 +1,102 @@ | |||
| 1 | module I18n | ||
| 2 | class << self | ||
| 3 | def chain_backends(*args) | ||
| 4 | self.backend = Globalize::Backend::Chain.new(*args) | ||
| 5 | end | ||
| 6 | end | ||
| 7 | end | ||
| 8 | |||
| 9 | module Globalize | ||
| 10 | module Backend | ||
| 11 | class Chain | ||
| 12 | def initialize(*args) | ||
| 13 | add(*args) unless args.empty? | ||
| 14 | end | ||
| 15 | |||
| 16 | # Change this to a) accept any number of backends and b) accept classes. | ||
| 17 | # When classes are passed instantiate them and add the instances as backends. | ||
| 18 | # Return the added backends from #add. | ||
| 19 | # | ||
| 20 | # Add an initialize method that accepts the same arguments and passes them | ||
| 21 | # to #add, so we could: | ||
| 22 | # I18n.backend = Globalize::Backend::Chain.new(Globalize::Backend::Foo, Globalize::Backend::Bar) | ||
| 23 | # Globalize::Backend::Chain.new(:foo, :bar) | ||
| 24 | # Globalize.chain_backends :foo, :bar | ||
| 25 | def add(*backends) | ||
| 26 | backends.each do |backend| | ||
| 27 | backend = Globalize::Backend.const_get(backend.to_s.capitalize) if backend.is_a? Symbol | ||
| 28 | backend = backend.new if backend.is_a? Class | ||
| 29 | self.backends << backend | ||
| 30 | end | ||
| 31 | end | ||
| 32 | |||
| 33 | def load_translations(*args) | ||
| 34 | backends.each{|backend| backend.load_translations(*args) } | ||
| 35 | end | ||
| 36 | |||
| 37 | # For defaults: | ||
| 38 | # Never pass any default option to the backends but instead implement our own default | ||
| 39 | # mechanism (e.g. symbols as defaults would need to be passed to the whole chain to | ||
| 40 | # be translated). | ||
| 41 | # | ||
| 42 | # For namespace lookup: | ||
| 43 | # Only return if the result is not a hash OR count is not present, otherwise merge them. | ||
| 44 | # So in effect the count variable would control whether we have a namespace lookup or a | ||
| 45 | # pluralization going on. | ||
| 46 | # | ||
| 47 | # Exceptions: | ||
| 48 | # Make sure that we catch MissingTranslationData exceptions and raise | ||
| 49 | # one in the end when no translation was found at all. | ||
| 50 | # | ||
| 51 | # For bulk translation: | ||
| 52 | # If the key is an array we need to call #translate for each of the | ||
| 53 | # keys and collect the results. | ||
| 54 | |||
| 55 | def translate(locale, key, options = {}) | ||
| 56 | raise I18n::InvalidLocale.new(locale) if locale.nil? | ||
| 57 | return key.map{|k| translate locale, k, options } if key.is_a? Array | ||
| 58 | |||
| 59 | default = options.delete(:default) | ||
| 60 | result = backends.inject({}) do |namespace, backend| | ||
| 61 | begin | ||
| 62 | translation = backend.translate(locale.to_sym, key, options) | ||
| 63 | if namespace_lookup?(translation, options) | ||
| 64 | namespace.merge! translation | ||
| 65 | elsif translation | ||
| 66 | return translation | ||
| 67 | end | ||
| 68 | rescue I18n::MissingTranslationData | ||
| 69 | end | ||
| 70 | end | ||
| 71 | result || default(locale, default, options) || raise(I18n::MissingTranslationData.new(locale, key, options)) | ||
| 72 | end | ||
| 73 | |||
| 74 | def localize(locale, object, format = :default) | ||
| 75 | backends.each do |backend| | ||
| 76 | result = backend.localize(locale, object, format) and return result | ||
| 77 | end | ||
| 78 | end | ||
| 79 | |||
| 80 | protected | ||
| 81 | def backends | ||
| 82 | @backends ||= [] | ||
| 83 | end | ||
| 84 | |||
| 85 | def default(locale, default, options = {}) | ||
| 86 | case default | ||
| 87 | when String then default | ||
| 88 | when Symbol then translate locale, default, options | ||
| 89 | when Array then default.each do |obj| | ||
| 90 | result = default(locale, obj, options.dup) and return result | ||
| 91 | end and nil | ||
| 92 | end | ||
| 93 | rescue I18n::MissingTranslationData | ||
| 94 | nil | ||
| 95 | end | ||
| 96 | |||
| 97 | def namespace_lookup?(result, options) | ||
| 98 | result.is_a?(Hash) and not options.has_key?(:count) | ||
| 99 | end | ||
| 100 | end | ||
| 101 | end | ||
| 102 | 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 0000000..80016f2 --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize/backend/pluralizing.rb | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | require 'i18n/backend/simple' | ||
| 2 | |||
| 3 | module Globalize | ||
| 4 | module Backend | ||
| 5 | class Pluralizing < I18n::Backend::Simple | ||
| 6 | def pluralize(locale, entry, count) | ||
| 7 | return entry unless entry.is_a?(Hash) and count | ||
| 8 | key = :zero if count == 0 && entry.has_key?(:zero) | ||
| 9 | key ||= pluralizer(locale).call(count) | ||
| 10 | raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key) | ||
| 11 | translation entry[key], :plural_key => key | ||
| 12 | end | ||
| 13 | |||
| 14 | def add_pluralizer(locale, pluralizer) | ||
| 15 | pluralizers[locale.to_sym] = pluralizer | ||
| 16 | end | ||
| 17 | |||
| 18 | def pluralizer(locale) | ||
| 19 | pluralizers[locale.to_sym] || default_pluralizer | ||
| 20 | end | ||
| 21 | |||
| 22 | protected | ||
| 23 | def default_pluralizer | ||
| 24 | pluralizers[:en] | ||
| 25 | end | ||
| 26 | |||
| 27 | def pluralizers | ||
| 28 | @pluralizers ||= { :en => lambda{|n| n == 1 ? :one : :other } } | ||
| 29 | end | ||
| 30 | |||
| 31 | # Overwrite this method to return something other than a String | ||
| 32 | def translation(string, attributes) | ||
| 33 | string | ||
| 34 | end | ||
| 35 | end | ||
| 36 | end | ||
| 37 | 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 0000000..3903517 --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize/backend/static.rb | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | require 'globalize/backend/pluralizing' | ||
| 2 | require 'globalize/locale/fallbacks' | ||
| 3 | require 'globalize/translation' | ||
| 4 | |||
| 5 | module Globalize | ||
| 6 | module Backend | ||
| 7 | class Static < Pluralizing | ||
| 8 | def initialize(*args) | ||
| 9 | add(*args) unless args.empty? | ||
| 10 | end | ||
| 11 | |||
| 12 | def translate(locale, key, options = {}) | ||
| 13 | result, default, fallback = nil, options.delete(:default), nil | ||
| 14 | I18n.fallbacks[locale].each do |fallback| | ||
| 15 | begin | ||
| 16 | result = super(fallback, key, options) and break | ||
| 17 | rescue I18n::MissingTranslationData | ||
| 18 | end | ||
| 19 | end | ||
| 20 | result ||= default locale, default, options | ||
| 21 | |||
| 22 | attrs = {:requested_locale => locale, :locale => fallback, :key => key, :options => options} | ||
| 23 | translation(result, attrs) || raise(I18n::MissingTranslationData.new(locale, key, options)) | ||
| 24 | end | ||
| 25 | |||
| 26 | protected | ||
| 27 | |||
| 28 | alias :orig_interpolate :interpolate unless method_defined? :orig_interpolate | ||
| 29 | def interpolate(locale, string, values = {}) | ||
| 30 | result = orig_interpolate(locale, string, values) | ||
| 31 | translation = translation(string) | ||
| 32 | translation.nil? ? result : translation.replace(result) | ||
| 33 | end | ||
| 34 | |||
| 35 | def translation(result, meta = nil) | ||
| 36 | return unless result | ||
| 37 | |||
| 38 | case result | ||
| 39 | when Numeric | ||
| 40 | result | ||
| 41 | when String | ||
| 42 | result = Translation::Static.new(result) unless result.is_a? Translation::Static | ||
| 43 | result.set_meta meta | ||
| 44 | result | ||
| 45 | when Hash | ||
| 46 | Hash[*result.map do |key, value| | ||
| 47 | [key, translation(value, meta)] | ||
| 48 | end.flatten] | ||
| 49 | when Array | ||
| 50 | result.map do |value| | ||
| 51 | translation(value, meta) | ||
| 52 | end | ||
| 53 | else | ||
| 54 | raise "unexpected translation type: #{result.inspect}" | ||
| 55 | end | ||
| 56 | end | ||
| 57 | end | ||
| 58 | end | ||
| 59 | 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 0000000..3f06ac2 --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize/i18n/missing_translations_log_handler.rb | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | # A simple exception handler that behaves like the default exception handler | ||
| 2 | # but additionally logs missing translations to a given log. | ||
| 3 | # | ||
| 4 | # Useful for identifying missing translations during testing. | ||
| 5 | # | ||
| 6 | # E.g. | ||
| 7 | # | ||
| 8 | # require 'globalize/i18n/missing_translations_log_handler | ||
| 9 | # I18n.missing_translations_logger = RAILS_DEFAULT_LOGGER | ||
| 10 | # I18n.exception_handler = :missing_translations_log_handler | ||
| 11 | # | ||
| 12 | # To set up a different log file: | ||
| 13 | # | ||
| 14 | # logger = Logger.new("#{RAILS_ROOT}/log/missing_translations.log") | ||
| 15 | # I18n.missing_translations_logger = logger | ||
| 16 | |||
| 17 | module I18n | ||
| 18 | @@missing_translations_logger = nil | ||
| 19 | |||
| 20 | class << self | ||
| 21 | def missing_translations_logger | ||
| 22 | @@missing_translations_logger ||= begin | ||
| 23 | require 'logger' unless defined?(Logger) | ||
| 24 | Logger.new(STDOUT) | ||
| 25 | end | ||
| 26 | end | ||
| 27 | |||
| 28 | def missing_translations_logger=(logger) | ||
| 29 | @@missing_translations_logger = logger | ||
| 30 | end | ||
| 31 | |||
| 32 | def missing_translations_log_handler(exception, locale, key, options) | ||
| 33 | if MissingTranslationData === exception | ||
| 34 | missing_translations_logger.warn(exception.message) | ||
| 35 | return exception.message | ||
| 36 | else | ||
| 37 | raise exception | ||
| 38 | end | ||
| 39 | end | ||
| 40 | end | ||
| 41 | end \ No newline at end of file | ||
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 0000000..a49825b --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize/load_path.rb | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | # Locale load_path and Locale loading support. | ||
| 2 | # | ||
| 3 | # To use this include the Globalize::LoadPath::I18n module to I18n like this: | ||
| 4 | # | ||
| 5 | # I18n.send :include, Globalize::LoadPath::I18n | ||
| 6 | # | ||
| 7 | # Clients can add load_paths using: | ||
| 8 | # | ||
| 9 | # I18n.load_path.add load_path, 'rb', 'yml' # pass any number of extensions like this | ||
| 10 | # I18n.load_path << 'path/to/dir' # usage without an extension, defaults to 'yml' | ||
| 11 | # | ||
| 12 | # And load locale data using either of: | ||
| 13 | # | ||
| 14 | # I18n.load_locales 'en-US', 'de-DE' | ||
| 15 | # I18n.load_locale 'en-US' | ||
| 16 | # | ||
| 17 | # This will lookup all files named like: | ||
| 18 | # | ||
| 19 | # 'path/to/dir/all.yml' | ||
| 20 | # 'path/to/dir/en-US.yml' | ||
| 21 | # 'path/to/dir/en-US/*.yml' | ||
| 22 | # | ||
| 23 | # The filenames will be passed to I18n.load_translations which delegates to | ||
| 24 | # the backend. So the actual behaviour depends on the implementation of the | ||
| 25 | # backend. I18n::Backend::Simple will be able to read YAML and plain Ruby | ||
| 26 | # files. See the documentation for I18n.load_translations for details. | ||
| 27 | |||
| 28 | module Globalize | ||
| 29 | class LoadPath < Array | ||
| 30 | def extensions | ||
| 31 | @extensions ||= ['rb', 'yml'] | ||
| 32 | end | ||
| 33 | attr_writer :extensions | ||
| 34 | |||
| 35 | def locales | ||
| 36 | @locales ||= ['*'] | ||
| 37 | end | ||
| 38 | attr_writer :locales | ||
| 39 | |||
| 40 | def <<(path) | ||
| 41 | push path | ||
| 42 | end | ||
| 43 | |||
| 44 | def push(*paths) | ||
| 45 | super(*paths.map{|path| filenames(path) }.flatten.uniq.sort) | ||
| 46 | end | ||
| 47 | |||
| 48 | protected | ||
| 49 | |||
| 50 | def filenames(path) | ||
| 51 | return [path] if File.file? path | ||
| 52 | patterns(path).map{|pattern| Dir[pattern] } | ||
| 53 | end | ||
| 54 | |||
| 55 | def patterns(path) | ||
| 56 | locales.map do |locale| | ||
| 57 | extensions.map do |extension| | ||
| 58 | %W(#{path}/all.#{extension} #{path}/#{locale}.#{extension} #{path}/#{locale}/**/*.#{extension}) | ||
| 59 | end | ||
| 60 | end.flatten.uniq | ||
| 61 | end | ||
| 62 | end | ||
| 63 | 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 0000000..c4acd57 --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize/locale/fallbacks.rb | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | require 'globalize/locale/language_tag' | ||
| 2 | |||
| 3 | module I18n | ||
| 4 | @@fallbacks = nil | ||
| 5 | |||
| 6 | class << self | ||
| 7 | # Returns the current fallbacks. Defaults to +Globalize::Locale::Fallbacks+. | ||
| 8 | def fallbacks | ||
| 9 | @@fallbacks ||= Globalize::Locale::Fallbacks.new | ||
| 10 | end | ||
| 11 | |||
| 12 | # Sets the current fallbacks. Used to set a custom fallbacks instance. | ||
| 13 | def fallbacks=(fallbacks) | ||
| 14 | @@fallbacks = fallbacks | ||
| 15 | end | ||
| 16 | end | ||
| 17 | end | ||
| 18 | |||
| 19 | module Globalize | ||
| 20 | module Locale | ||
| 21 | class Fallbacks < Hash | ||
| 22 | def initialize(*defaults) | ||
| 23 | @map = {} | ||
| 24 | map defaults.pop if defaults.last.is_a?(Hash) | ||
| 25 | |||
| 26 | defaults = [I18n.default_locale.to_sym] if defaults.empty? | ||
| 27 | self.defaults = defaults | ||
| 28 | end | ||
| 29 | |||
| 30 | def defaults=(defaults) | ||
| 31 | @defaults = defaults.map{|default| compute(default, false) }.flatten << :root | ||
| 32 | end | ||
| 33 | attr_reader :defaults | ||
| 34 | |||
| 35 | def [](tag) | ||
| 36 | tag = tag.to_sym | ||
| 37 | has_key?(tag) ? fetch(tag) : store(tag, compute(tag)) | ||
| 38 | end | ||
| 39 | |||
| 40 | def map(mappings) | ||
| 41 | mappings.each do |from, to| | ||
| 42 | from, to = from.to_sym, Array(to) | ||
| 43 | to.each do |to| | ||
| 44 | @map[from] ||= [] | ||
| 45 | @map[from] << to.to_sym | ||
| 46 | end | ||
| 47 | end | ||
| 48 | end | ||
| 49 | |||
| 50 | protected | ||
| 51 | |||
| 52 | def compute(tags, include_defaults = true) | ||
| 53 | result = Array(tags).collect do |tag| | ||
| 54 | tags = LanguageTag::tag(tag.to_sym).parents(true).map! {|t| t.to_sym } | ||
| 55 | tags.each{|tag| tags += compute(@map[tag]) if @map[tag] } | ||
| 56 | tags | ||
| 57 | end.flatten | ||
| 58 | result.push *defaults if include_defaults | ||
| 59 | result.uniq | ||
| 60 | end | ||
| 61 | end | ||
| 62 | end | ||
| 63 | 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 0000000..d9aae54 --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize/locale/language_tag.rb | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | # for specifications see http://en.wikipedia.org/wiki/IETF_language_tag | ||
| 2 | # | ||
| 3 | # SimpleParser does not implement advanced usages such as grandfathered tags | ||
| 4 | |||
| 5 | module Globalize | ||
| 6 | module Locale | ||
| 7 | module Rfc4646 | ||
| 8 | SUBTAGS = [:language, :script, :region, :variant, :extension, :privateuse, :grandfathered] | ||
| 9 | FORMATS = {:language => :downcase, :script => :capitalize, :region => :upcase, :variant => :downcase} | ||
| 10 | end | ||
| 11 | |||
| 12 | class LanguageTag < Struct.new(*Rfc4646::SUBTAGS) | ||
| 13 | class << self | ||
| 14 | def parser | ||
| 15 | @@parser ||= SimpleParser | ||
| 16 | end | ||
| 17 | |||
| 18 | def parser=(parser) | ||
| 19 | @@parser = parser | ||
| 20 | end | ||
| 21 | |||
| 22 | def tag(tag) | ||
| 23 | matches = parser.match(tag) | ||
| 24 | new *matches if matches | ||
| 25 | end | ||
| 26 | end | ||
| 27 | |||
| 28 | Rfc4646::FORMATS.each do |name, format| | ||
| 29 | define_method(name) { self[name].send(format) unless self[name].nil? } | ||
| 30 | end | ||
| 31 | |||
| 32 | def to_sym | ||
| 33 | to_s.to_sym | ||
| 34 | end | ||
| 35 | |||
| 36 | def to_s | ||
| 37 | @tag ||= to_a.compact.join("-") | ||
| 38 | end | ||
| 39 | |||
| 40 | def to_a | ||
| 41 | members.collect {|attr| self.send(attr) } | ||
| 42 | end | ||
| 43 | |||
| 44 | def parent | ||
| 45 | segs = to_a.compact | ||
| 46 | segs.length < 2 ? nil : LanguageTag.tag(segs[0..(segs.length-2)].join('-')) | ||
| 47 | end | ||
| 48 | |||
| 49 | def parents(include_self = true) | ||
| 50 | result, parent = [], self.dup | ||
| 51 | result << parent if include_self | ||
| 52 | while parent = parent.parent | ||
| 53 | result << parent | ||
| 54 | end | ||
| 55 | result | ||
| 56 | end | ||
| 57 | |||
| 58 | module SimpleParser | ||
| 59 | PATTERN = %r{\A(?: | ||
| 60 | ([a-z]{2,3}(?:(?:-[a-z]{3}){0,3})?|[a-z]{4}|[a-z]{5,8}) # language | ||
| 61 | (?:-([a-z]{4}))? # script | ||
| 62 | (?:-([a-z]{2}|\d{3}))? # region | ||
| 63 | (?:-([0-9a-z]{5,8}|\d[0-9a-z]{3}))* # variant | ||
| 64 | (?:-([0-9a-wyz](?:-[0-9a-z]{2,8})+))* # extension | ||
| 65 | (?:-(x(?:-[0-9a-z]{1,8})+))?| # privateuse subtag | ||
| 66 | (x(?:-[0-9a-z]{1,8})+)| # privateuse tag | ||
| 67 | /* ([a-z]{1,3}(?:-[0-9a-z]{2,8}){1,2}) */ # grandfathered | ||
| 68 | )\z}xi | ||
| 69 | |||
| 70 | class << self | ||
| 71 | def match(tag) | ||
| 72 | c = PATTERN.match(tag.to_s).captures | ||
| 73 | c[0..4] << (c[5].nil? ? c[6] : c[5]) << c[7] # TODO c[7] is grandfathered, throw a NotImplemented exception here? | ||
| 74 | rescue | ||
| 75 | false | ||
| 76 | end | ||
| 77 | end | ||
| 78 | end | ||
| 79 | end | ||
| 80 | end | ||
| 81 | 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 0000000..450729c --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize/model/active_record.rb | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | require 'globalize/translation' | ||
| 2 | require 'globalize/locale/fallbacks' | ||
| 3 | require 'globalize/model/active_record/adapter' | ||
| 4 | require 'globalize/model/active_record/translated' | ||
| 5 | |||
| 6 | module Globalize | ||
| 7 | module Model | ||
| 8 | module ActiveRecord | ||
| 9 | class << self | ||
| 10 | def create_proxy_class(klass) | ||
| 11 | Object.const_set "#{klass.name}Translation", Class.new(::ActiveRecord::Base){ | ||
| 12 | belongs_to "#{klass.name.underscore}".intern | ||
| 13 | |||
| 14 | def locale | ||
| 15 | read_attribute(:locale).to_sym | ||
| 16 | end | ||
| 17 | |||
| 18 | def locale=(locale) | ||
| 19 | write_attribute(:locale, locale.to_s) | ||
| 20 | end | ||
| 21 | } | ||
| 22 | end | ||
| 23 | |||
| 24 | def define_accessors(klass, attr_names) | ||
| 25 | attr_names.each do |attr_name| | ||
| 26 | klass.send :define_method, attr_name, lambda { | ||
| 27 | globalize.fetch I18n.locale, attr_name | ||
| 28 | } | ||
| 29 | klass.send :define_method, "#{attr_name}=", lambda {|val| | ||
| 30 | globalize.stash I18n.locale, attr_name, val | ||
| 31 | self[attr_name] = val | ||
| 32 | } | ||
| 33 | end | ||
| 34 | end | ||
| 35 | end | ||
| 36 | end | ||
| 37 | end | ||
| 38 | 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 0000000..12d7564 --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize/model/active_record/adapter.rb | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | module Globalize | ||
| 2 | module Model | ||
| 3 | class AttributeStash < Hash | ||
| 4 | def read(locale, attr_name) | ||
| 5 | locale = locale.to_sym | ||
| 6 | self[locale] ||= {} | ||
| 7 | self[locale][attr_name] | ||
| 8 | end | ||
| 9 | |||
| 10 | def write(locale, attr_name, value) | ||
| 11 | locale = locale.to_sym | ||
| 12 | self[locale] ||= {} | ||
| 13 | self[locale][attr_name] = value | ||
| 14 | end | ||
| 15 | end | ||
| 16 | |||
| 17 | class Adapter | ||
| 18 | def initialize(record) | ||
| 19 | @record = record | ||
| 20 | @cache = AttributeStash.new | ||
| 21 | @stash = AttributeStash.new | ||
| 22 | end | ||
| 23 | |||
| 24 | def fetch(locale, attr_name) | ||
| 25 | # locale = I18n.locale | ||
| 26 | @cache.read(locale, attr_name) || begin | ||
| 27 | value = fetch_attribute locale, attr_name | ||
| 28 | @cache.write locale, attr_name, value if value && value.locale == locale | ||
| 29 | value | ||
| 30 | end | ||
| 31 | end | ||
| 32 | |||
| 33 | def stash(locale, attr_name, value) | ||
| 34 | @stash.write locale, attr_name, value | ||
| 35 | @cache.write locale, attr_name, value | ||
| 36 | end | ||
| 37 | |||
| 38 | def update_translations! | ||
| 39 | @stash.each do |locale, attrs| | ||
| 40 | translation = @record.globalize_translations.find_or_initialize_by_locale(locale.to_s) | ||
| 41 | attrs.each{|attr_name, value| translation[attr_name] = value } | ||
| 42 | translation.save! | ||
| 43 | end | ||
| 44 | @stash.clear | ||
| 45 | end | ||
| 46 | |||
| 47 | # Clears the cache | ||
| 48 | def clear | ||
| 49 | @cache.clear | ||
| 50 | end | ||
| 51 | |||
| 52 | private | ||
| 53 | |||
| 54 | def fetch_attribute(locale, attr_name) | ||
| 55 | fallbacks = I18n.fallbacks[locale].map{|tag| tag.to_s}.map(&:to_sym) | ||
| 56 | translations = @record.globalize_translations.by_locales(fallbacks) | ||
| 57 | result, requested_locale = nil, locale | ||
| 58 | |||
| 59 | # Walk through the fallbacks, starting with the current locale itself, and moving | ||
| 60 | # to the next best choice, until we find a match. | ||
| 61 | # Check the @globalize_set_translations cache first to see if we've just changed the | ||
| 62 | # attribute and not saved yet. | ||
| 63 | fallbacks.each do |fallback| | ||
| 64 | result = @stash.read(fallback, attr_name) || begin | ||
| 65 | translation = translations.detect {|tr| tr.locale == fallback } | ||
| 66 | translation && translation.send(attr_name) | ||
| 67 | end | ||
| 68 | if result | ||
| 69 | locale = fallback | ||
| 70 | break | ||
| 71 | end | ||
| 72 | end | ||
| 73 | result && Translation::Attribute.new(result, :locale => locale, :requested_locale => requested_locale) | ||
| 74 | end | ||
| 75 | end | ||
| 76 | end | ||
| 77 | 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 0000000..710cde5 --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize/model/active_record/translated.rb | |||
| @@ -0,0 +1,111 @@ | |||
| 1 | module Globalize | ||
| 2 | module Model | ||
| 3 | |||
| 4 | class MigrationError < StandardError; end | ||
| 5 | class UntranslatedMigrationField < MigrationError; end | ||
| 6 | class MigrationMissingTranslatedField < MigrationError; end | ||
| 7 | class BadMigrationFieldType < MigrationError; end | ||
| 8 | |||
| 9 | module ActiveRecord | ||
| 10 | module Translated | ||
| 11 | def self.included(base) | ||
| 12 | base.extend ActMethods | ||
| 13 | end | ||
| 14 | |||
| 15 | module ActMethods | ||
| 16 | def translates(*attr_names) | ||
| 17 | options = attr_names.extract_options! | ||
| 18 | options[:translated_attributes] = attr_names | ||
| 19 | |||
| 20 | # Only set up once per class | ||
| 21 | unless included_modules.include? InstanceMethods | ||
| 22 | class_inheritable_accessor :globalize_options | ||
| 23 | include InstanceMethods | ||
| 24 | extend ClassMethods | ||
| 25 | |||
| 26 | proxy_class = Globalize::Model::ActiveRecord.create_proxy_class(self) | ||
| 27 | has_many :globalize_translations, :class_name => proxy_class.name, :extend => Extensions | ||
| 28 | |||
| 29 | after_save :update_globalize_record | ||
| 30 | |||
| 31 | def i18n_attr(attribute_name) | ||
| 32 | self.name.underscore + "_translations.#{attribute_name}" | ||
| 33 | end | ||
| 34 | end | ||
| 35 | |||
| 36 | self.globalize_options = options | ||
| 37 | Globalize::Model::ActiveRecord.define_accessors(self, attr_names) | ||
| 38 | |||
| 39 | # Import any callbacks that have been defined by extensions to Globalize2 | ||
| 40 | # and run them. | ||
| 41 | extend Callbacks | ||
| 42 | Callbacks.instance_methods.each {|cb| send cb } | ||
| 43 | end | ||
| 44 | end | ||
| 45 | |||
| 46 | # Dummy Callbacks module. Extensions to Globalize2 can insert methods into here | ||
| 47 | # and they'll be called at the end of the translates class method. | ||
| 48 | module Callbacks | ||
| 49 | end | ||
| 50 | |||
| 51 | # Extension to the has_many :globalize_translations association | ||
| 52 | module Extensions | ||
| 53 | def by_locales(locales) | ||
| 54 | find :all, :conditions => { :locale => locales.map(&:to_s) } | ||
| 55 | end | ||
| 56 | end | ||
| 57 | |||
| 58 | module ClassMethods | ||
| 59 | def method_missing(method, *args) | ||
| 60 | if method.to_s =~ /^find_by_(\w+)$/ && globalize_options[:translated_attributes].include?($1.to_sym) | ||
| 61 | find(:first, :joins => :globalize_translations, | ||
| 62 | :conditions => [i18n_attr($1)+" = ? AND "+i18n_attr('locale')+" IN (?)", | ||
| 63 | args.first,I18n.fallbacks[I18n.locale].map{|tag| tag.to_s}]) | ||
| 64 | else | ||
| 65 | super | ||
| 66 | end | ||
| 67 | end | ||
| 68 | |||
| 69 | def create_translation_table!(fields) | ||
| 70 | translated_fields = self.globalize_options[:translated_attributes] | ||
| 71 | translated_fields.each do |f| | ||
| 72 | raise MigrationMissingTranslatedField, "Missing translated field #{f}" unless fields[f] | ||
| 73 | end | ||
| 74 | fields.each do |name, type| | ||
| 75 | unless translated_fields.member? name | ||
| 76 | raise UntranslatedMigrationField, "Can't migrate untranslated field: #{name}" | ||
| 77 | end | ||
| 78 | unless [ :string, :text ].member? type | ||
| 79 | raise BadMigrationFieldType, "Bad field type for #{name}, should be :string or :text" | ||
| 80 | end | ||
| 81 | end | ||
| 82 | translation_table_name = self.name.underscore + '_translations' | ||
| 83 | self.connection.create_table(translation_table_name) do |t| | ||
| 84 | t.references self.table_name.singularize | ||
| 85 | t.string :locale | ||
| 86 | fields.each do |name, type| | ||
| 87 | t.column name, type | ||
| 88 | end | ||
| 89 | t.timestamps | ||
| 90 | end | ||
| 91 | end | ||
| 92 | |||
| 93 | def drop_translation_table! | ||
| 94 | translation_table_name = self.name.underscore + '_translations' | ||
| 95 | self.connection.drop_table translation_table_name | ||
| 96 | end | ||
| 97 | end | ||
| 98 | |||
| 99 | module InstanceMethods | ||
| 100 | def globalize | ||
| 101 | @globalize ||= Adapter.new self | ||
| 102 | end | ||
| 103 | |||
| 104 | def update_globalize_record | ||
| 105 | globalize.update_translations! | ||
| 106 | end | ||
| 107 | end | ||
| 108 | end | ||
| 109 | end | ||
| 110 | end | ||
| 111 | 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 0000000..a80afcd --- /dev/null +++ b/vendor/plugins/globalize2/lib/globalize/translation.rb | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | module Globalize | ||
| 2 | # Translations are simple value objects that carry some context information | ||
| 3 | # alongside the actual translation string. | ||
| 4 | |||
| 5 | class Translation < String | ||
| 6 | class Attribute < Translation | ||
| 7 | attr_accessor :requested_locale, :locale, :key | ||
| 8 | end | ||
| 9 | |||
| 10 | class Static < Translation | ||
| 11 | attr_accessor :requested_locale, :locale, :key, :options, :plural_key, :original | ||
| 12 | |||
| 13 | def initialize(string, meta = nil) | ||
| 14 | self.original = string | ||
| 15 | super | ||
| 16 | end | ||
| 17 | end | ||
| 18 | |||
| 19 | def initialize(string, meta = nil) | ||
| 20 | set_meta meta | ||
| 21 | super string | ||
| 22 | end | ||
| 23 | |||
| 24 | def fallback? | ||
| 25 | locale.to_sym != requested_locale.to_sym | ||
| 26 | end | ||
| 27 | |||
| 28 | def set_meta(meta) | ||
| 29 | meta.each {|name, value| send :"#{name}=", value } if meta | ||
| 30 | end | ||
| 31 | end | ||
| 32 | 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 0000000..2ec2b3b --- /dev/null +++ b/vendor/plugins/globalize2/lib/locale/root.yml | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | root: | ||
| 2 | bidi: | ||
| 3 | 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 0000000..e6f90d8 --- /dev/null +++ b/vendor/plugins/globalize2/lib/rails_edge_load_path_patch.rb | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | module I18n | ||
| 2 | @@load_path = nil | ||
| 3 | @@default_locale = :'en-US' | ||
| 4 | |||
| 5 | class << self | ||
| 6 | def load_path | ||
| 7 | @@load_path ||= [] | ||
| 8 | end | ||
| 9 | |||
| 10 | def load_path=(load_path) | ||
| 11 | @@load_path = load_path | ||
| 12 | end | ||
| 13 | end | ||
| 14 | end | ||
| 15 | |||
| 16 | I18n::Backend::Simple.module_eval do | ||
| 17 | def initialized? | ||
| 18 | @initialized ||= false | ||
| 19 | end | ||
| 20 | |||
| 21 | protected | ||
| 22 | |||
| 23 | def init_translations | ||
| 24 | load_translations(*I18n.load_path) | ||
| 25 | @initialized = true | ||
| 26 | end | ||
| 27 | |||
| 28 | def lookup(locale, key, scope = []) | ||
| 29 | return unless key | ||
| 30 | init_translations unless initialized? | ||
| 31 | keys = I18n.send :normalize_translation_keys, locale, key, scope | ||
| 32 | keys.inject(translations){|result, k| result[k.to_sym] or return nil } | ||
| 33 | end | ||
| 34 | end | ||
| 35 | |||
| 36 | rails_dir = File.expand_path "#{File.dirname(__FILE__)}/../../../rails/" | ||
| 37 | paths = %w(actionpack/lib/action_view/locale/en-US.yml | ||
| 38 | activerecord/lib/active_record/locale/en-US.yml | ||
| 39 | activesupport/lib/active_support/locale/en-US.yml) | ||
| 40 | paths.each{|path| I18n.load_path << "#{rails_dir}/#{path}" } | ||
