lib/twitter_cldr/transforms/transform_id.rb
# encoding: UTF-8
# Copyright 2012 Twitter, Inc
# http://www.apache.org/licenses/LICENSE-2.0
module TwitterCldr
module Transforms
class InvalidTransformIdError < StandardError; end
class TransformId
CHAIN = [
:normal_fallback1, :normal_fallback2, :laddered_fallback1,
:normal_fallback3, :laddered_fallback2
]
class << self
def find(source_locale_or_str, target_locale_or_str)
source_locale = parse_locale(source_locale_or_str)
target_locale = parse_locale(target_locale_or_str)
source_chain = map_chain_for(source_locale)
target_chain = map_chain_for(target_locale)
variants = variants_for(source_locale, target_locale)
# add original locale strings to chain in case they aren't actually
# locales (think 'hiragana', etc)
source_chain << [source_locale_or_str.to_s]
target_chain << [target_locale_or_str.to_s]
find_in_chains(
source_chain, target_chain, variants
)
end
def parse(str)
if normalized = normalize(str)
new(*split(normalized))
else
raise InvalidTransformIdError,
"'#{str}' is not a valid transform id"
end
end
def split(str)
str.split(/[\-\/]/)
end
def join(source, target, variant = nil)
base = "#{source}-#{target}"
variant ? "#{base}/#{variant}" : base
end
def join_file_name(parts)
parts.compact.join('-')
end
def transform_id_map
@transform_id_map ||= TwitterCldr.get_resource(
*%w(shared transforms transform_id_map)
)
end
private
def parse_locale(locale_or_str)
case locale_or_str
when TwitterCldr::Shared::Locale
locale_or_str
else
TwitterCldr::Shared::Locale.parse(locale_or_str.to_s).maximize
end
end
def normalize(str)
source, target, variant = split(str)
normalization_index[
join(source, target, variant).downcase
]
end
def normalization_index
@index ||=
transform_id_map.each_with_object({}) do |(key, file), ret|
source, target, variant = split(key)
key = join(source, target, variant)
reverse_key = join(target, source, variant)
ret[key.downcase] = key
ret[reverse_key.downcase] = reverse_key
end
end
def find_in_chains(source_chain, target_chain, variants)
variants.each do |variant|
target_chain.each do |target|
source_chain.each do |source|
source_str = join_subtags(source, variant)
target_str = join_subtags(target, variant)
transform_id_str = join(source_str, target_str)
if Transformer.exists?(transform_id_str)
return parse(transform_id_str)
end
end
end
end
nil
end
def join_subtags(tags, variant)
tags.join('_').tap do |result|
result << "_#{variant}" if variant
end
end
def variants_for(source_locale, target_locale)
(source_locale.variants + target_locale.variants + [nil]).uniq
end
def map_chain_for(locale)
CHAIN.map { |link| send(link, locale) }
end
def normal_fallback1(locale)
[locale.language, locale.full_script, locale.region]
end
def normal_fallback2(locale)
[locale.language, locale.full_script]
end
def normal_fallback3(locale)
[locale.language]
end
def laddered_fallback1(locale)
[locale.language, locale.region]
end
def laddered_fallback2(locale)
[locale.full_script]
end
end
attr_reader :source, :target, :variant
def initialize(source, target, variant = nil)
@source = source
@target = target
@variant = variant
end
def has_variant?
!!variant
end
def reverse
self.class.new(target, source, variant)
end
def file_name
self.class.transform_id_map[to_s]
end
def to_s
self.class.join(source, target, variant)
end
end
end
end