From a61e87aeb920e64ebfc79cfcbcee2508c900b4e2 Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Mon, 25 Aug 2008 11:20:24 +0200 Subject: [PATCH] update i18n gem --- .../lib/active_support/vendor/i18n-0.0.1/i18n.rb | 4 +- .../vendor/i18n-0.0.1/i18n/backend/simple.rb | 344 ++++++++++---------- 2 files changed, 173 insertions(+), 175 deletions(-) diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb index d4adbde..9e347d9 100755 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb @@ -9,14 +9,14 @@ require 'i18n/backend/simple' require 'i18n/exceptions' module I18n - @@backend = Backend::Simple + @@backend = nil @@default_locale = 'en-US' @@exception_handler = :default_exception_handler class << self # Returns the current backend. Defaults to +Backend::Simple+. def backend - @@backend + @@backend ||= Backend::Simple.new end # Sets the current backend. Used to set a custom backend. diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb index 917646f..a53f7fe 100644 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb @@ -2,194 +2,192 @@ require 'strscan' module I18n module Backend - module Simple - @@translations = {} + class Simple + # Allow client libraries to pass a block that populates the translation + # storage. Decoupled for backends like a db backend that persist their + # translations, so the backend can decide whether/when to yield or not. + def populate(&block) + yield + end + + # Accepts a list of paths to translation files. Loads translations from + # plain Ruby (*.rb) or YAML files (*.yml). See #load_rb and #load_yml + # for details. + def load_translations(*filenames) + filenames.each {|filename| load_file filename } + end - class << self - # Allow client libraries to pass a block that populates the translation - # storage. Decoupled for backends like a db backend that persist their - # translations, so the backend can decide whether/when to yield or not. - def populate(&block) - yield - end + # Stores translations for the given locale in memory. + # This uses a deep merge for the translations hash, so existing + # translations will be overwritten by new ones only at the deepest + # level of the hash. + def store_translations(locale, data) + merge_translations(locale, data) + end - # Accepts a list of paths to translation files. Loads translations from - # plain Ruby (*.rb) or YAML files (*.yml). See #load_rb and #load_yml - # for details. - def load_translations(*filenames) - filenames.each {|filename| load_file filename } - end - - # Stores translations for the given locale in memory. - # This uses a deep merge for the translations hash, so existing - # translations will be overwritten by new ones only at the deepest - # level of the hash. - def store_translations(locale, data) - merge_translations(locale, data) - end - - def translate(locale, key, options = {}) - raise InvalidLocale.new(locale) if locale.nil? - return key.map{|k| translate locale, k, options } if key.is_a? Array + def translate(locale, key, options = {}) + raise InvalidLocale.new(locale) if locale.nil? + return key.map{|k| translate locale, k, options } if key.is_a? Array - reserved = :scope, :default - count, scope, default = options.values_at(:count, *reserved) - options.delete(:default) - values = options.reject{|name, value| reserved.include? name } + reserved = :scope, :default + count, scope, default = options.values_at(:count, *reserved) + options.delete(:default) + values = options.reject{|name, value| reserved.include? name } - entry = lookup(locale, key, scope) || default(locale, default, options) || raise(I18n::MissingTranslationData.new(locale, key, options)) - entry = pluralize locale, entry, count - entry = interpolate locale, entry, values - entry - end + entry = lookup(locale, key, scope) || default(locale, default, options) || raise(I18n::MissingTranslationData.new(locale, key, options)) + entry = pluralize locale, entry, count + entry = interpolate locale, entry, values + entry + end + + # Acts the same as +strftime+, but returns a localized version of the + # formatted date string. Takes a key from the date/time formats + # translations as a format argument (e.g., :short in :'date.formats'). + def localize(locale, object, format = :default) + raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime) - # Acts the same as +strftime+, but returns a localized version of the - # formatted date string. Takes a key from the date/time formats - # translations as a format argument (e.g., :short in :'date.formats'). - def localize(locale, object, format = :default) - raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime) - - type = object.respond_to?(:sec) ? 'time' : 'date' - formats = translate(locale, :"#{type}.formats") - format = formats[format.to_sym] if formats && formats[format.to_sym] - # TODO raise exception unless format found? - format = format.to_s.dup + type = object.respond_to?(:sec) ? 'time' : 'date' + formats = translate(locale, :"#{type}.formats") + format = formats[format.to_sym] if formats && formats[format.to_sym] + # TODO raise exception unless format found? + format = format.to_s.dup - format.gsub!(/%a/, translate(locale, :"date.abbr_day_names")[object.wday]) - format.gsub!(/%A/, translate(locale, :"date.day_names")[object.wday]) - format.gsub!(/%b/, translate(locale, :"date.abbr_month_names")[object.mon]) - format.gsub!(/%B/, translate(locale, :"date.month_names")[object.mon]) - format.gsub!(/%p/, translate(locale, :"time.#{object.hour < 12 ? :am : :pm}")) if object.respond_to? :hour - object.strftime(format) - end - - protected - - # Looks up a translation from the translations hash. Returns nil if - # eiher key is nil, or locale, scope or key do not exist as a key in the - # nested translations hash. Splits keys or scopes containing dots - # into multiple keys, i.e. currency.format is regarded the same as - # %w(currency format). - def lookup(locale, key, scope = []) - return unless key - keys = I18n.send :normalize_translation_keys, locale, key, scope - keys.inject(@@translations){|result, k| result[k.to_sym] or return nil } - end + format.gsub!(/%a/, translate(locale, :"date.abbr_day_names")[object.wday]) + format.gsub!(/%A/, translate(locale, :"date.day_names")[object.wday]) + format.gsub!(/%b/, translate(locale, :"date.abbr_month_names")[object.mon]) + format.gsub!(/%B/, translate(locale, :"date.month_names")[object.mon]) + format.gsub!(/%p/, translate(locale, :"time.#{object.hour < 12 ? :am : :pm}")) if object.respond_to? :hour + object.strftime(format) + end + + protected - # Evaluates a default translation. - # If the given default is a String it is used literally. If it is a Symbol - # it will be translated with the given options. If it is an Array the first - # translation yielded will be returned. - # - # I.e., default(locale, [:foo, 'default']) will return +default+ if - # translate(locale, :foo) does not yield a result. - 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 MissingTranslationData - nil - end + def translations + @translations ||= {} + end - # Picks a translation from an array according to English pluralization - # rules. It will pick the first translation if count is not equal to 1 - # and the second translation if it is equal to 1. Other backends can - # implement more flexible or complex pluralization rules. - def pluralize(locale, entry, count) - return entry unless entry.is_a?(Hash) and count - # raise InvalidPluralizationData.new(entry, count) unless entry.is_a?(Hash) - key = :zero if count == 0 && entry.has_key?(:zero) - key ||= count == 1 ? :one : :many - raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key) - entry[key] + # Looks up a translation from the translations hash. Returns nil if + # eiher key is nil, or locale, scope or key do not exist as a key in the + # nested translations hash. Splits keys or scopes containing dots + # into multiple keys, i.e. currency.format is regarded the same as + # %w(currency format). + def lookup(locale, key, scope = []) + return unless key + keys = I18n.send :normalize_translation_keys, locale, key, scope + keys.inject(translations){|result, k| result[k.to_sym] or return nil } + end + + # Evaluates a default translation. + # If the given default is a String it is used literally. If it is a Symbol + # it will be translated with the given options. If it is an Array the first + # translation yielded will be returned. + # + # I.e., default(locale, [:foo, 'default']) will return +default+ if + # translate(locale, :foo) does not yield a result. + 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 - - # Interpolates values into a given string. - # - # interpolate "file {{file}} opened by \\{{user}}", :file => 'test.txt', :user => 'Mr. X' - # # => "file test.txt opened by {{user}}" - # - # Note that you have to double escape the \\ when you want to escape - # the {{...}} key in a string (once for the string and once for the - # interpolation). - def interpolate(locale, string, values = {}) - return string if !string.is_a?(String) - - string = string.gsub(/%d/, '{{count}}').gsub(/%s/, '{{value}}') - if string.respond_to?(:force_encoding) - original_encoding = string.encoding - string.force_encoding(Encoding::BINARY) - end - - s = StringScanner.new(string) - while s.skip_until(/\{\{/) - s.string[s.pos - 3, 1] = '' and next if s.pre_match[-1, 1] == '\\' - start_pos = s.pos - 2 - key = s.scan_until(/\}\}/)[0..-3] - end_pos = s.pos - 1 - - raise ReservedInterpolationKey.new(key, string) if %w(scope default).include?(key) - raise MissingInterpolationArgument.new(key, string) unless values.has_key? key.to_sym + rescue MissingTranslationData + nil + end + + # Picks a translation from an array according to English pluralization + # rules. It will pick the first translation if count is not equal to 1 + # and the second translation if it is equal to 1. Other backends can + # implement more flexible or complex pluralization rules. + def pluralize(locale, entry, count) + return entry unless entry.is_a?(Hash) and count + # raise InvalidPluralizationData.new(entry, count) unless entry.is_a?(Hash) + key = :zero if count == 0 && entry.has_key?(:zero) + key ||= count == 1 ? :one : :other + raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key) + entry[key] + end + + # Interpolates values into a given string. + # + # interpolate "file {{file}} opened by \\{{user}}", :file => 'test.txt', :user => 'Mr. X' + # # => "file test.txt opened by {{user}}" + # + # Note that you have to double escape the \\ when you want to escape + # the {{...}} key in a string (once for the string and once for the + # interpolation). + def interpolate(locale, string, values = {}) + return string if !string.is_a?(String) - s.string[start_pos..end_pos] = values[key.to_sym].to_s - s.unscan - end + string = string.gsub(/%d/, '{{count}}').gsub(/%s/, '{{value}}') + if string.respond_to?(:force_encoding) + original_encoding = string.encoding + string.force_encoding(Encoding::BINARY) + end + s = StringScanner.new(string) + + while s.skip_until(/\{\{/) + s.string[s.pos - 3, 1] = '' and next if s.pre_match[-1, 1] == '\\' + start_pos = s.pos - 2 + key = s.scan_until(/\}\}/)[0..-3] + end_pos = s.pos - 1 - result = s.string - result.force_encoding(original_encoding) if original_encoding - result - end + raise ReservedInterpolationKey.new(key, string) if %w(scope default).include?(key) + raise MissingInterpolationArgument.new(key, string) unless values.has_key? key.to_sym - # Loads a single translations file by delegating to #load_rb or - # #load_yml depending on the file extension and directly merges the - # data to the existing translations. Raises I18n::UnknownFileType - # for all other file extensions. - def load_file(filename) - type = File.extname(filename).tr('.', '').downcase - raise UnknownFileType.new(type, filename) unless respond_to? :"load_#{type}" - data = send :"load_#{type}", filename # TODO raise a meaningful exception if this does not yield a Hash - data.each do |locale, d| - merge_translations locale, d - end + s.string[start_pos..end_pos] = values[key.to_sym].to_s + s.unscan end - # Loads a plain Ruby translations file. eval'ing the file must yield - # a Hash containing translation data with locales as toplevel keys. - def load_rb(filename) - eval IO.read(filename), binding, filename - end - - # Loads a YAML translations file. The data must have locales as - # toplevel keys. - def load_yml(filename) - YAML::load IO.read(filename) - end - - # Deep merges the given translations hash with the existing translations - # for the given locale - def merge_translations(locale, data) - locale = locale.to_sym - @@translations[locale] ||= {} - data = deep_symbolize_keys data + result = s.string + result.force_encoding(original_encoding) if original_encoding + result + end + + # Loads a single translations file by delegating to #load_rb or + # #load_yml depending on the file extension and directly merges the + # data to the existing translations. Raises I18n::UnknownFileType + # for all other file extensions. + def load_file(filename) + type = File.extname(filename).tr('.', '').downcase + raise UnknownFileType.new(type, filename) unless respond_to? :"load_#{type}" + data = send :"load_#{type}", filename # TODO raise a meaningful exception if this does not yield a Hash + data.each{|locale, d| merge_translations locale, d } + end + + # Loads a plain Ruby translations file. eval'ing the file must yield + # a Hash containing translation data with locales as toplevel keys. + def load_rb(filename) + eval IO.read(filename), binding, filename + end + + # Loads a YAML translations file. The data must have locales as + # toplevel keys. + def load_yml(filename) + YAML::load IO.read(filename) + end + + # Deep merges the given translations hash with the existing translations + # for the given locale + def merge_translations(locale, data) + locale = locale.to_sym + translations[locale] ||= {} + data = deep_symbolize_keys data - # deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809 - merger = proc{|key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 } - @@translations[locale].merge! data, &merger - end - - # Return a new hash with all keys and nested keys converted to symbols. - def deep_symbolize_keys(hash) - hash.inject({}){|result, (key, value)| - value = deep_symbolize_keys(value) if value.is_a? Hash - result[(key.to_sym rescue key) || key] = value - result - } - end - end + # deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809 + merger = proc{|key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 } + translations[locale].merge! data, &merger + end + + # Return a new hash with all keys and nested keys converted to symbols. + def deep_symbolize_keys(hash) + hash.inject({}){|result, (key, value)| + value = deep_symbolize_keys(value) if value.is_a? Hash + result[(key.to_sym rescue key) || key] = value + result + } + end end end end -- 1.5.3.7