lib/csl/locale.rb in csl-1.0.0.pre10 vs lib/csl/locale.rb in csl-1.0.0.pre11
- old
+ new
@@ -5,73 +5,95 @@
#
class Locale < Node
types << CSL::Info
include Comparable
-
+
@default = 'en-US'.freeze
- @root = File.expand_path('../../../vendor/locales', __FILE__).freeze
+ @root = '/usr/local/share/csl/locales'.freeze
@extension = '.xml'.freeze
@prefix = 'locales-'.freeze
+ @tag_pattern = /^[a-z]{2}(-[A-Z]{2})?|-[A-Z]{2}$/
# Default languages/regions.
# Auto-detection is based on these lists.
@regions = Hash[*%w{
af ZA ar AR bg BG ca AD cs CZ da DK de DE el GR en US es ES et EE fa IR
fr FR he IL hu HU is IS it IT ja JP km KH ko KR mn MN nb NO nl NL nn NO
pl PL pt PT ro RO ru RU sk SK sl SI sr RS sv SE th TH tr TR uk UA vi VN
- zh CN zh TW
+ zh CN
}.map(&:to_sym)].freeze
@languages = @regions.invert.merge(Hash[*%w{
- AT de BR pt CA en CH de GB en
+ AT de BR pt CA en CH de GB en TW zh
}.map(&:to_sym)]).freeze
class << self
include Loader
attr_accessor :default
attr_reader :languages, :regions
- def parse(data)
- node = CSL.parse!(data, self)
-
- raise ParseError, "root node is not a locale: #{node.inspect}" unless
- node.is_a?(self)
-
- node
- end
-
def load(input = Locale.default)
+ input = normalize input if input.to_s =~ tag_pattern
super
end
+
+ # Normalizes an IETF tag; adds a language's default region or a
+ # region's default language.
+ #
+ # @example
+ # Locale.normalize("en") #-> "en-US"
+ # Locale.normalize("-BR") #-> "pt-BR"
+ #
+ # @raise [ArgumentError] if the passed-in string is no IETF tag
+ #
+ # @param tag [String] an IETF tag to be normalized
+ # @return [String] the normalized IETF tag
+ def normalize(tag)
+ tag = tag.to_s.strip
+
+ raise ArgumentError, "not a valid IETF tag: #{tag.inspect}" unless
+ tag =~ tag_pattern
+
+ language, region = tag.split(/-/)
+
+ return [language, regions[language.to_sym]].compact.join('-') if region.nil?
+ return [languages[region.to_sym], region].join('-') if language.empty?
+
+ tag
+ end
+
+ private
+
+ attr_reader :tag_pattern
end
attr_defaults :version => Schema.version, :xmlns => Schema.namespace
attr_struct :xmlns, :version
attr_children :'style-options', :info, :date, :terms
has_language
-
+
attr_accessor :region
alias_child :metadata, :info
alias_child :dates, :date
alias_child :options, :style_options
- private :attributes
+ protected :attributes
undef_method :[]=
# @example
# Locale.new #-> default
# Locale.new('en') #-> American English
- # Locale.new('en', :'punctuation-in-quote' => fales) #-> with style-options
+ # Locale.new('en', :'punctuation-in-quote' => false) #-> with style-options
# Locale.new(:lang => 'en-GB', :version => '1.0') #-> British English
#
# Returns a new locale. In the first form, the language/regions is set
# to the default language and region. In the second form the
# language/region is set by the passed-in IETF tag. The third form
@@ -88,11 +110,11 @@
locale = arguments[0].delete(:lang) ||
arguments[0].delete(:'xml:lang') || Locale.default
attributes, options = arguments
else
- attributes, locale, options = {}, arguments
+ attributes, locale, options = {}, *arguments
end
when 2
attributes, locale, options = {}, *arguments
else
raise ArgumentError, "wrong number of arguments (#{arguments.length} for 0..2)"
@@ -107,14 +129,14 @@
end
yield self if block_given?
end
- # TODO
- # def initialize_copy(other)
- # @options = other.options.dup
- # end
+ def initialize_copy(other)
+ super
+ @language, @region = other.language, other.region
+ end
def added_to(node)
raise ValidationError, "not allowed to add locale to #{node.nodename}" unless
node.nodename == 'style'
@@ -160,25 +182,11 @@
# it consists of either a language or region tag (or both), separated
# by a hyphen.
#
# @return [self]
def set(locale)
- language, region = locale.to_s.scan(/([a-z]{2})?(?:-([A-Z]{2}))?/)[0].map do |tag|
- tag.respond_to?(:to_sym) ? tag.to_sym : nil
- end
-
- case
- when language && region
- @language, @region = language, region
- when language
- @language, @region = language, Locale.regions[language]
- when region
- @language, @region = Locale.languages[region], region
- else
- raise ArgumentError, "not a valid locale string: #{locale.inspect}"
- end
-
+ @language, @region = Locale.normalize(locale).split(/-/).map(&:to_sym)
self
end
# Sets the locale's language and region to nil.
# @return [self]
@@ -244,10 +252,26 @@
def valid?
validate.empty?
end
+ # @return [Locale]
+ def merge(*others)
+ deep_copy.merge!(*others)
+ end
+
+ # @return [self]
+ def merge!(*others)
+ others.each do |other|
+ merge_options other
+ merge_dates other
+ end
+
+ self
+ end
+
+
# Locales are sorted first by language, then by region; sort order is
# alphabetical with the following exceptions: the default locale is
# prioritised; in case of a language match the default region of that
# language will be prioritised (e.g., de-DE will come before de-AT even
# though the alphabetical order would be different).
@@ -300,8 +324,40 @@
def preamble
Schema.preamble.dup
end
+ # @param other [Locale] an other locale whose options should be merged
+ # @return [self]
+ def merge_options(other)
+ return self unless other.has_options?
+
+ if has_options?
+ options.attributes.merge! other.options.attributes
+ else
+ add_child other.options.dup
+ end
+
+ self
+ end
+
+ # @param other [Locale] an other locale whose date nodes should be merged
+ # @return [self]
+ def merge_dates(other)
+ return self unless other.has_dates?
+
+ if has_dates?
+ other.each_date do |date|
+ delete_children each_date.select { |d| d[:form] == date[:form] }
+ add_child date.deep_copy
+ end
+ else
+ other.each_date do |date|
+ add_child date.deep_copy
+ end
+ end
+
+ self
+ end
end
end
\ No newline at end of file