module I18n
module Backend
# "Продвинутый" бекэнд для I18n.
#
# Наследует Simple бекэнд и полностью с ним совместим. Добаляет поддержку
# для отдельностоящих/контекстных названий дней недели и месяцев.
# Также позволяет каждому языку использовать собственные правила плюрализации,
# объявленные как Proc (lambda).
#
#
# Advanced I18n backend.
#
# Extends Simple backend. Allows usage of "standalone" keys
# for DateTime localization and usage of user-defined Proc (lambda) pluralization
# methods in translation tables.
class Advanced < Simple
LOCALIZE_ABBR_MONTH_NAMES_MATCH = /(%d|%e)?(\s*)(%b)/
LOCALIZE_MONTH_NAMES_MATCH = /(%d|%e)?(\s*)(%B)/
LOCALIZE_STANDALONE_ABBR_DAY_NAMES_MATCH = /^%a/
LOCALIZE_STANDALONE_DAY_NAMES_MATCH = /^%A/
# 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').
#
#
# Метод отличается от localize в Simple бекэнде поддержкой
# отдельностоящих/контекстных названий дней недели и месяцев.
#
#
# Note that it differs from localize in Simple< backend by checking for
# "standalone" month name/day name keys in translation and using them if available.
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'
# TODO only translate these if format is a String?
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
# TODO only translate these if the format string is actually present
# TODO check which format strings are present, then bulk translate then, then replace them
if lookup(locale, :"date.standalone_abbr_day_names")
format.gsub!(LOCALIZE_STANDALONE_ABBR_DAY_NAMES_MATCH,
translate(locale, :"date.standalone_abbr_day_names")[object.wday])
end
format.gsub!(/%a/, translate(locale, :"date.abbr_day_names")[object.wday])
if lookup(locale, :"date.standalone_day_names")
format.gsub!(LOCALIZE_STANDALONE_DAY_NAMES_MATCH,
translate(locale, :"date.standalone_day_names")[object.wday])
end
format.gsub!(/%A/, translate(locale, :"date.day_names")[object.wday])
if lookup(locale, :"date.standalone_abbr_month_names")
format.gsub!(LOCALIZE_ABBR_MONTH_NAMES_MATCH) do
$1 ? $1 + $2 + translate(locale, :"date.abbr_month_names")[object.mon] :
$2 + translate(locale, :"date.standalone_abbr_month_names")[object.mon]
end
else
format.gsub!(/%b/, translate(locale, :"date.abbr_month_names")[object.mon])
end
if lookup(locale, :"date.standalone_month_names")
format.gsub!(LOCALIZE_MONTH_NAMES_MATCH) do
$1 ? $1 + $2 + translate(locale, :"date.month_names")[object.mon] :
$2 + translate(locale, :"date.standalone_month_names")[object.mon]
end
else
format.gsub!(/%B/, translate(locale, :"date.month_names")[object.mon])
end
format.gsub!(/%p/, translate(locale, :"time.#{object.hour < 12 ? :am : :pm}")) if object.respond_to? :hour
object.strftime(format)
end
protected
# Использует правила плюрализации из таблицы переводов для языка (если присутствуют),
# иначе использует правило плюрализации по умолчанию (английский язык).
#
# Пример задания правила в таблице переводов:
#
# store_translations :'en-US', {
# :pluralize => lambda { |n| n == 1 ? :one : :other }
# }
#
# Правило должно возвращать один из символов для таблицы переводов:
# :zero, :one, :two, :few, :many, :other
#
#
# Picks a pluralization rule specified in translation tables for a language or
# uses default pluralization rules.
#
# This is how pluralization rules are defined in translation tables, English
# language for example:
#
# store_translations :'en-US', {
# :pluralize => lambda { |n| n == 1 ? :one : :other }
# }
#
# Rule must return a symbol to use with pluralization, it must be one of:
# :zero, :one, :two, :few, :many, :other
def pluralize(locale, entry, count)
return entry unless entry.is_a?(Hash) and count
key = :zero if count == 0 && entry.has_key?(:zero)
locale_pluralize = lookup(locale, :pluralize)
if locale_pluralize && locale_pluralize.respond_to?(:call)
key ||= locale_pluralize.call(count)
else
key ||= default_pluralizer(count)
end
raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key)
entry[key]
end
# Default pluralizer, used if pluralization rule is not defined in translations.
#
# Uses 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.
def default_pluralizer(count)
count == 1 ? :one : :other
end
end
end
end