4ce4c751ae11f8ae70fefbb41f2319adcfd27d03
[packages/precise/mcollective.git] / lib / mcollective / vendor / i18n / lib / i18n / locale / tag / rfc4646.rb
1 # RFC 4646/47 compliant Locale tag implementation that parses locale tags to
2 # subtags such as language, script, region, variant etc.
3 #
4 # For more information see by http://en.wikipedia.org/wiki/IETF_language_tag
5 #
6 # Rfc4646::Parser does not implement grandfathered tags.
7
8 module I18n
9   module Locale
10     module Tag
11       RFC4646_SUBTAGS = [ :language, :script, :region, :variant, :extension, :privateuse, :grandfathered ]
12       RFC4646_FORMATS = { :language => :downcase, :script => :capitalize, :region => :upcase, :variant => :downcase }
13
14       class Rfc4646 < Struct.new(*RFC4646_SUBTAGS)
15         class << self
16           # Parses the given tag and returns a Tag instance if it is valid.
17           # Returns false if the given tag is not valid according to RFC 4646.
18           def tag(tag)
19             matches = parser.match(tag)
20             new(*matches) if matches
21           end
22
23           def parser
24             @@parser ||= Rfc4646::Parser
25           end
26
27           def parser=(parser)
28             @@parser = parser
29           end
30         end
31
32         include Parents
33
34         RFC4646_FORMATS.each do |name, format|
35           define_method(name) { self[name].send(format) unless self[name].nil? }
36         end
37
38         def to_sym
39           to_s.to_sym
40         end
41
42         def to_s
43           @tag ||= to_a.compact.join("-")
44         end
45
46         def to_a
47           members.collect { |attr| self.send(attr) }
48         end
49
50         module Parser
51           PATTERN = %r{\A(?:
52             ([a-z]{2,3}(?:(?:-[a-z]{3}){0,3})?|[a-z]{4}|[a-z]{5,8}) # language
53             (?:-([a-z]{4}))?                                        # script
54             (?:-([a-z]{2}|\d{3}))?                                  # region
55             (?:-([0-9a-z]{5,8}|\d[0-9a-z]{3}))*                     # variant
56             (?:-([0-9a-wyz](?:-[0-9a-z]{2,8})+))*                   # extension
57             (?:-(x(?:-[0-9a-z]{1,8})+))?|                           # privateuse subtag
58             (x(?:-[0-9a-z]{1,8})+)|                                 # privateuse tag
59             /* ([a-z]{1,3}(?:-[0-9a-z]{2,8}){1,2}) */               # grandfathered
60             )\z}xi
61
62           class << self
63             def match(tag)
64               c = PATTERN.match(tag.to_s).captures
65               c[0..4] << (c[5].nil? ? c[6] : c[5])  << c[7] # TODO c[7] is grandfathered, throw a NotImplemented exception here?
66             rescue
67               false
68             end
69           end
70         end
71       end
72     end
73   end
74 end