Skip to content

Commit

Permalink
add and adapt Globalize2 fallback implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
Sven Fuchs committed Jul 12, 2009
1 parent 32ddc80 commit 1b37a30
Show file tree
Hide file tree
Showing 15 changed files with 753 additions and 43 deletions.
18 changes: 18 additions & 0 deletions lib/i18n/backend/fallbacks.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
require 'i18n/backend/simple'
require 'i18n/locale/fallbacks'

module I18n
module Backend
module Fallbacks
def translate(locale, key, options = {})
I18n.fallbacks[locale].each do |fallback|
begin
result = super(fallback, key, options) and return result
rescue I18n::MissingTranslationData
end
end
raise(I18n::MissingTranslationData.new(locale, key, options))
end
end
end
end
75 changes: 75 additions & 0 deletions lib/i18n/locale/fallbacks.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
require 'i18n/locale/tag'

module I18n
@@fallbacks = nil

class << self
# Returns the current fallbacks implementation. Defaults to +I18n::Locale::Fallbacks+.
def fallbacks
@@fallbacks ||= I18n::Locale::Fallbacks.new
end

# Sets the current fallbacks implementation. Use this to set a differen fallbacks implementation.
def fallbacks=(fallbacks)
@@fallbacks = fallbacks
end

# Locale tag factory. Uses I18n::Locale::Tag by default.
def tag(tag)
tags.tag(tag.to_sym)
end

def tags
@@tags ||= I18n::Locale::Tag
end

def tags=(tag_class)
@@tags = tag_class
end
end

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
end
attr_reader :defaults

def [](locale)
raise InvalidLocale.new(locale) if locale.nil?
locale = locale.to_sym
has_key?(locale) ? fetch(locale) : store(locale, compute(locale))
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 = I18n.tag(tag).self_and_parents.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
26 changes: 26 additions & 0 deletions lib/i18n/locale/tag.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# for specifications see http://en.wikipedia.org/wiki/IETF_language_tag
#
# SimpleParser does not implement advanced usages such as grandfathered tags

require 'i18n/locale/tag/basic'
require 'i18n/locale/tag/rfc4646'

module I18n
module Locale
module Tag
class << self
def implementation
@@implementation ||= Rfc4646
end

def implementation=(implementation)
@@implementation = implementation
end

def tag(tag)
implementation.tag(tag)
end
end
end
end
end
39 changes: 39 additions & 0 deletions lib/i18n/locale/tag/basic.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
require 'i18n/locale/tag/parents'

module I18n
module Locale
module Tag
class Basic
class << self
def tag(tag)
new(tag)
end
end

include Parents

attr_reader :tag

def initialize(*tag)
@tag = tag.join('-').to_sym
end

def subtags
@subtags = tag.to_s.split('-').map { |subtag| subtag.to_s }
end

def to_sym
tag
end

def to_s
tag.to_s
end

def to_a
subtags
end
end
end
end
end
22 changes: 22 additions & 0 deletions lib/i18n/locale/tag/parents.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module I18n
module Locale
module Tag
module Parents
def parent
@parent ||= begin
segs = to_a.compact
segs.length > 1 ? self.class.tag(*segs[0..(segs.length-2)].join('-')) : nil
end
end

def self_and_parents
@self_and_parents ||= [self] + parents
end

def parents
@parents ||= ([parent] + (parent ? parent.parents : [])).compact
end
end
end
end
end
71 changes: 71 additions & 0 deletions lib/i18n/locale/tag/rfc4646.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# for specifications see http://en.wikipedia.org/wiki/IETF_language_tag
#
# Rfc4646::Parser does not implement advanced usages such as grandfathered tags

require 'i18n/locale/tag/parents'

module I18n
module Locale
module Tag
RFC4646_SUBTAGS = [ :language, :script, :region, :variant, :extension, :privateuse, :grandfathered ]
RFC4646_FORMATS = { :language => :downcase, :script => :capitalize, :region => :upcase, :variant => :downcase }

class Rfc4646 < Struct.new(*RFC4646_SUBTAGS)
class << self
def parser
@@parser ||= Rfc4646::Parser
end

def parser=(parser)
@@parser = parser
end

def tag(tag)
matches = parser.match(tag)
new(*matches) if matches
end
end

include Parents

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

module Parser
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
end
59 changes: 59 additions & 0 deletions test/backend/fallbacks/api_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
require 'i18n/backend/fallbacks'

# class I18nFallbacksBackendApiBasicsTest < Test::Unit::TestCase
# include Tests::Backend::Simple::Setup::Base
# include Tests::Backend::Fallbacks::Setup
# include Tests::Backend::Api::Basics
# end

class I18nFallbacksBackendApiTranslateTest < Test::Unit::TestCase
include Tests::Backend::Simple::Setup::Base
include Tests::Backend::Fallbacks::Setup
include Tests::Backend::Api::Translation
end

# class I18nFallbacksBackendApiInterpolateTest < Test::Unit::TestCase
# include Tests::Backend::Simple::Setup::Base
# include Tests::Backend::Fallbacks::Setup
# include Tests::Backend::Api::Interpolation
# end
#
# class I18nFallbacksBackendApiLambdaTest < Test::Unit::TestCase
# include Tests::Backend::Simple::Setup::Base
# include Tests::Backend::Fallbacks::Setup
# include Tests::Backend::Api::Lambda
# end
#
# class I18nFallbacksBackendApiTranslateLinkedTest < Test::Unit::TestCase
# include Tests::Backend::Simple::Setup::Base
# include Tests::Backend::Fallbacks::Setup
# include Tests::Backend::Api::Link
# end
#
# class I18nFallbacksBackendApiPluralizationTest < Test::Unit::TestCase
# include Tests::Backend::Simple::Setup::Base
# include Tests::Backend::Fallbacks::Setup
# include Tests::Backend::Api::Pluralization
# end

# class I18nFallbacksBackendApiLocalizeDateTest < Test::Unit::TestCase
# include Tests::Backend::Fallbacks::Setup::Localization
# include Tests::Backend::Api::Localization::Date
# end
#
# class I18nFallbacksBackendApiLocalizeDateTimeTest < Test::Unit::TestCase
# include Tests::Backend::Fallbacks::Setup::Localization
# include Tests::Backend::Api::Localization::DateTime
# end
#
# class I18nFallbacksBackendApiLocalizeTimeTest < Test::Unit::TestCase
# include Tests::Backend::Fallbacks::Setup::Localization
# include Tests::Backend::Api::Localization::Time
# end
#
# class I18nFallbacksBackendApiLocalizeLambdaTest < Test::Unit::TestCase
# include Tests::Backend::Fallbacks::Setup::Localization
# include Tests::Backend::Api::Localization::Lambda
# end

14 changes: 14 additions & 0 deletions test/backend/fallbacks/setup.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module Tests
module Backend
module Fallbacks
module Setup
def setup
super
class << I18n.backend
include I18n::Backend::Fallbacks
end
end
end
end
end
end
Loading

0 comments on commit 1b37a30

Please sign in to comment.