@@ -15,7 +15,7 @@ class Locale < Node
1515 @extension = '.xml' . freeze
1616 @prefix = 'locales-' . freeze
1717
18- @tag_pattern = /^[a-z]{2}(-[A-Z]{ 2})?|-[A-Z ]{2}$/
18+ @tag_pattern = /^[a-z]{2}(-[a-z]{4})?(-[a-z]{ 2})?|-[a-z ]{2}$/i
1919
2020 # Default languages/regions.
2121 # Auto-detection is based on these lists.
@@ -29,25 +29,30 @@ class Locale < Node
2929 AT de BR pt CA en CH de GB en TW zh
3030 } . map ( &:to_sym ) ] ) . freeze
3131
32+ @scripts = Hash [ *%w{
33+ sr Latn
34+ } . map ( &:to_sym ) ] . freeze
35+
3236
3337 class << self
3438 include Loader
3539
3640 attr_accessor :default
37- attr_reader :languages , :regions
41+ attr_reader :languages , :regions , :scripts
3842
3943 def load ( input = nil )
4044 input ||= Locale . default
4145 input = normalize input if input . to_s =~ @tag_pattern
4246 super ( input )
4347 end
4448
45- # Normalizes an IETF tag; adds a language's default region or a
46- # region's default language.
49+ # Normalizes an IETF tag; adds default language, region, script.
4750 #
4851 # @example
4952 # Locale.normalize("en") #-> "en-US"
5053 # Locale.normalize("-BR") #-> "pt-BR"
54+ # Locale.normalize("de-at") #-> "de-AT"
55+ # Locale.normalize("sr") #-> "sr-Latn-RS"
5156 #
5257 # @raise [ArgumentError] if the passed-in string is no IETF tag
5358 #
@@ -56,15 +61,32 @@ def load(input = nil)
5661 def normalize ( tag )
5762 tag = tag . to_s . strip
5863
59- raise ArgumentError , "not a valid IETF tag: #{ tag . inspect } " unless
60- tag =~ @tag_pattern
64+ unless tag =~ @tag_pattern
65+ raise ArgumentError , "unsupported IETF tag: #{ tag . inspect } "
66+ end
67+
68+ language , *rs = tag . split ( /-/ )
69+ region , script = rs . reverse
6170
62- language , region = tag . split ( /-/ )
71+ if language . nil? || language . empty?
72+ language = languages [ region . to_sym ]
73+ else
74+ language . downcase!
75+ end
6376
64- return [ language , regions [ language . to_sym ] ] . compact . join ( '-' ) if region . nil?
65- return [ languages [ region . to_sym ] , region ] . join ( '-' ) if language . empty?
77+ if region . nil?
78+ region = regions [ language . to_sym ]
79+ else
80+ region . upcase!
81+ end
82+
83+ if script . nil?
84+ script = scripts [ language . to_sym ]
85+ else
86+ script . capitalize!
87+ end
6688
67- tag
89+ [ language , script , region ] . compact . join ( '-' )
6890 end
6991 end
7092
@@ -78,7 +100,7 @@ def normalize(tag)
78100
79101 has_language
80102
81- attr_accessor :region
103+ attr_accessor :region , :script
82104
83105 alias_child :metadata , :info
84106 alias_child :dates , :date
@@ -181,14 +203,15 @@ def legacy?
181203 #
182204 # @return [self]
183205 def set ( locale )
184- @language , @region = Locale . normalize ( locale ) . split ( /-/ ) . map ( &:to_sym )
206+ @language , *rs = Locale . normalize ( locale ) . split ( /-/ ) . map ( &:to_sym )
207+ @region , @script = rs . reverse
185208 self
186209 end
187210
188- # Sets the locale's language and region to nil.
211+ # Sets the locale's language, script and region to nil.
189212 # @return [self]
190213 def clear
191- @language , @region = nil
214+ @language , @script , @ region = nil
192215 self
193216 end
194217
@@ -414,11 +437,12 @@ def reverse_merge(other)
414437 end
415438
416439
417- # Locales are sorted first by language, then by region; sort order is
418- # alphabetical with the following exceptions: the default locale is
419- # prioritised; in case of a language match the default region of that
420- # language will be prioritised (e.g., de-DE will come before de-AT even
421- # though the alphabetical order would be different).
440+ # Locales are sorted first by language, then by region and script;
441+ # sort order is alphabetical with the following exceptions:
442+ # the default locale is prioritised; in case of a language match
443+ # the default region of that language will be prioritised (e.g.,
444+ # de-DE will come before de-AT even though the alphabetical order
445+ # would be different).
422446 #
423447 # @param other [Locale] the locale used for comparison
424448 # @return [1,0,-1,nil] the result of the comparison
@@ -427,7 +451,7 @@ def <=>(other)
427451 when !other . is_a? ( Locale )
428452 nil
429453 when [ language , region ] == [ other . language , other . region ]
430- 0
454+ script <=> other . script
431455 when default?
432456 -1
433457 when other . default?
@@ -448,7 +472,7 @@ def <=>(other)
448472
449473 # @return [String] the Locale's IETF tag
450474 def to_s
451- [ language , region ] . compact . join ( '-' )
475+ [ language , script , region ] . compact . join ( '-' )
452476 end
453477
454478 # @return [String] a string representation of the Locale
0 commit comments