lib/i18n/backend/simple.rb in lawrencepit-i18n-0.1.6 vs lib/i18n/backend/simple.rb in lawrencepit-i18n-0.2.0.1

- old
+ new

@@ -1,235 +1,23 @@ -require 'yaml' +# encoding: utf-8 -module I18n - module Backend - class Simple - RESERVED_KEYS = [:scope, :default, :separator] - MATCH = /(\\\\)?\{\{([^\}]+)\}\}/ +require 'i18n/backend/base' - # 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 +# Stub class for the Simple backend. The actual implementation is provided by +# the backend Base class. This makes it easier to extend the Simple backend's +# behaviour by including modules. E.g.: +# +# module I18n::Backend::Pluralization +# def pluralize(*args) +# # extended pluralization logic +# super +# end +# end +# +# I18n::Backend::Simple.send(:include, I18n::Backend::Pluralization) - # 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) - - count, scope, default, separator = options.values_at(:count, *RESERVED_KEYS) - values = options.reject { |name, value| RESERVED_KEYS.include?(name) } - - entry = lookup(locale, key, scope, separator) - entry = entry.nil? ? default(locale, key, default, options) : resolve(locale, key, entry, options) - - raise(I18n::MissingTranslationData.new(locale, key, options)) if entry.nil? - 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 (<em>e.g.</em>, <tt>:short</tt> in <tt>:'date.formats'</tt>). - def localize(locale, object, format = :default, options={}) - raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime) - - if Symbol === format - type = object.respond_to?(:sec) ? 'time' : 'date' - format = lookup(locale, :"#{type}.formats.#{format}") - end - - format = resolve(locale, object, format, options.merge(:raise => true)) - - # TODO only translate these if the format string is actually present - # TODO check which format strings are present, then bulk translate them, then replace them - - format.gsub!(/%a/, translate(locale, :"date.abbr_day_names", :format => format)[object.wday]) - format.gsub!(/%A/, translate(locale, :"date.day_names", :format => format)[object.wday]) - format.gsub!(/%b/, translate(locale, :"date.abbr_month_names", :format => format)[object.mon]) - format.gsub!(/%B/, translate(locale, :"date.month_names", :format => format)[object.mon]) - format.gsub!(/%p/, translate(locale, :"time.#{object.hour < 12 ? :am : :pm}", :format => format)) if object.respond_to?(:hour) - - object.strftime(format) - end - - def initialized? - @initialized ||= false - end - - # Returns an array of locales for which translations are available - def available_locales - init_translations unless initialized? - translations.keys - end - - def reload! - @initialized = false - @translations = nil - end - - protected - def init_translations - load_translations(*I18n.load_path.flatten) - @initialized = true - end - - def translations - @translations ||= {} - end - - # 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. <tt>currency.format</tt> is regarded the same as - # <tt>%w(currency format)</tt>. - def lookup(locale, key, scope = [], separator = nil) - return unless key - init_translations unless initialized? - keys = I18n.send(:normalize_translation_keys, locale, key, scope, separator) - keys.inject(translations) do |result, k| - if (x = result[k.to_sym]).nil? - return nil - else - x - end - end - end - - # Evaluates defaults. - # If given subject is an Array, it walks the array and returns the - # first translation that can be resolved. Otherwise it tries to resolve - # the translation directly. - def default(locale, object, subject, options = {}) - options = options.dup.reject { |key, value| key == :default } - case subject - when Array - subject.each do |subject| - result = resolve(locale, object, subject, options) and return result - end and nil - else - resolve(locale, object, subject, options) - end - end - - # Resolves a translation. - # If the given subject is a Symbol, it will be translated with the - # given options. If it is a Proc then it will be evaluated. All other - # subjects will be returned directly. - def resolve(locale, object, subject, options = {}) - case subject - when Symbol - translate(locale, subject, options) - when Proc - resolve(locale, object, subject.call(object, options), options = {}) - else - subject - end - 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 - - 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 <tt>\\</tt> when you want to escape - # the <tt>{{...}}</tt> key in a string (once for the string and once for the - # interpolation). - def interpolate(locale, string, values = {}) - return string unless string.is_a?(String) - - string.gsub!(MATCH) do - escaped, key = $1, $2.to_sym - - if escaped - key - elsif RESERVED_KEYS.include?(key) - raise ReservedInterpolationKey.new(key, string) - elsif !values.include?(key) - raise MissingInterpolationArgument.new(key, string) - else - values[key].to_s - end - end - string - 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 - - # Flatten the given array once - def flatten_once(array) - result = [] - for element in array # a little faster than each - result.push(*element) - end - result - end +module I18n + module Backend + class Simple < Base end end end \ No newline at end of file