ruby-cldr 0.1.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +53 -0
  3. data/Gemfile +1 -1
  4. data/Gemfile.lock +56 -46
  5. data/README.textile +8 -0
  6. data/Rakefile +2 -2
  7. data/VERSION +1 -1
  8. data/lib/cldr/download.rb +1 -1
  9. data/lib/cldr/export.rb +74 -16
  10. data/lib/cldr/export/data.rb +34 -21
  11. data/lib/cldr/export/data/aliases.rb +47 -0
  12. data/lib/cldr/export/data/base.rb +4 -0
  13. data/lib/cldr/export/data/characters.rb +30 -0
  14. data/lib/cldr/export/data/country_codes.rb +29 -0
  15. data/lib/cldr/export/data/currencies.rb +13 -3
  16. data/lib/cldr/export/data/fields.rb +60 -0
  17. data/lib/cldr/export/data/languages.rb +1 -1
  18. data/lib/cldr/export/data/likely_subtags.rb +29 -0
  19. data/lib/cldr/export/data/numbers.rb +48 -6
  20. data/lib/cldr/export/data/parent_locales.rb +23 -0
  21. data/lib/cldr/export/data/plural_rules.rb +70 -0
  22. data/lib/cldr/export/data/plurals/rules.rb +12 -1
  23. data/lib/cldr/export/data/rbnf.rb +12 -4
  24. data/lib/cldr/export/data/region_currencies.rb +45 -0
  25. data/lib/cldr/export/data/segments_root.rb +61 -0
  26. data/lib/cldr/export/data/subdivisions.rb +35 -0
  27. data/lib/cldr/export/data/territories.rb +1 -1
  28. data/lib/cldr/export/data/territories_containment.rb +30 -0
  29. data/lib/cldr/export/data/timezones.rb +18 -2
  30. data/lib/cldr/export/data/transforms.rb +76 -0
  31. data/lib/cldr/export/data/variables.rb +42 -0
  32. data/lib/cldr/export/yaml.rb +5 -21
  33. data/lib/cldr/thor.rb +2 -2
  34. data/ruby-cldr.gemspec +157 -0
  35. data/test/export/data/calendars_test.rb +102 -52
  36. data/test/export/data/country_codes_test.rb +21 -0
  37. data/test/export/data/currencies_test.rb +40 -26
  38. data/test/export/data/languages_test.rb +69 -51
  39. data/test/export/data/numbers_test.rb +61 -62
  40. data/test/export/data/plurals_test.rb +10 -3
  41. data/test/export/data/subdivisions_test.rb +33 -0
  42. data/test/export/data/territories_containment_test.rb +10 -0
  43. data/test/export/data/territories_test.rb +12 -5
  44. data/test/export/data/timezones_test.rb +5 -8
  45. data/test/export_test.rb +57 -5
  46. data/test/format/time_test.rb +5 -5
  47. metadata +51 -33
@@ -0,0 +1,47 @@
1
+ module Cldr
2
+ module Export
3
+ module Data
4
+ class Aliases < Base
5
+
6
+ # only these aliases will be exported
7
+ ALIAS_TAGS = %w(languageAlias territoryAlias)
8
+
9
+ def initialize
10
+ super(nil)
11
+ update(:aliases => aliases)
12
+ end
13
+
14
+ private
15
+
16
+ def aliases
17
+ ALIAS_TAGS.inject({}) do |ret, alias_tag|
18
+ ret[alias_tag.sub('Alias', '')] = alias_for(alias_tag)
19
+ ret
20
+ end
21
+ end
22
+
23
+ def alias_for(alias_tag)
24
+ doc.xpath("//alias/#{alias_tag}").inject({}) do |ret, alias_data|
25
+ if replacement_attr = alias_data.attribute('replacement')
26
+ replacement = replacement_attr.value
27
+
28
+ if replacement.include?(' ')
29
+ replacement = replacement.split(' ')
30
+ end
31
+
32
+ type = alias_data.attribute('type').value
33
+ ret[type] = replacement
34
+ end
35
+
36
+ ret
37
+ end
38
+ end
39
+
40
+ def path
41
+ @path ||= "#{Cldr::Export::Data.dir}/supplemental/supplementalMetadata.xml"
42
+ end
43
+
44
+ end
45
+ end
46
+ end
47
+ end
@@ -31,6 +31,10 @@ module Cldr
31
31
  draft && draft.value == 'unconfirmed'
32
32
  end
33
33
 
34
+ def alt?(node)
35
+ !node.attribute('alt').nil?
36
+ end
37
+
34
38
  def name(node)
35
39
  node.name.underscore
36
40
  end
@@ -0,0 +1,30 @@
1
+ module Cldr
2
+ module Export
3
+ module Data
4
+ class Characters < Base
5
+ def initialize(locale)
6
+ super
7
+ update(:characters => { :exemplars => exemplars })
8
+ end
9
+
10
+ def exemplars
11
+ select('/ldml/characters/exemplarCharacters').map do |node|
12
+ {
13
+ # remove enclosing brackets
14
+ characters: node.content[1..-2],
15
+ type: type_from(node)
16
+ }
17
+ end
18
+ end
19
+
20
+ protected
21
+
22
+ def type_from(node)
23
+ if attrib = node.attribute('type')
24
+ attrib.value
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,29 @@
1
+ module Cldr
2
+ module Export
3
+ module Data
4
+ class CountryCodes < Base
5
+ def initialize
6
+ super(nil)
7
+ update(:country_codes => country_codes)
8
+ end
9
+
10
+ private
11
+
12
+ def country_codes
13
+ doc.xpath("//codeMappings/*").each_with_object({}) do |node, hash|
14
+ if node.name == "territoryCodes"
15
+ type = node.attribute('type').to_s.to_sym
16
+ hash[type] = {}
17
+ hash[type]["numeric"] = node[:numeric] if node[:numeric]
18
+ hash[type]["alpha3"] = node[:alpha3] if node[:alpha3]
19
+ end
20
+ end
21
+ end
22
+
23
+ def path
24
+ @path ||= "#{Cldr::Export::Data.dir}/supplemental/supplementalData.xml"
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -17,17 +17,27 @@ module Cldr
17
17
 
18
18
  def currency(node)
19
19
  data = select(node, 'displayName').inject({}) do |result, node|
20
- count = node.attribute('count') ? node.attribute('count').value.to_sym : :one
21
- result[count] = node.content unless draft?(node)
20
+ unless draft?(node)
21
+ if node.attribute('count')
22
+ count = node.attribute('count').value.to_sym
23
+ result[count] = node.content
24
+ else
25
+ result[:one] = node.content if result[:one].nil?
26
+ result[:name] = node.content
27
+ end
28
+ end
29
+
22
30
  result
23
31
  end
24
32
 
25
33
  symbol = select(node, 'symbol')
34
+ narrow_symbol = symbol.select { |child_node| child_node.values.include?('narrow') }.first
26
35
  data[:symbol] = symbol.first.content if symbol.length > 0
36
+ data[:'narrow_symbol'] = narrow_symbol.content unless narrow_symbol.nil?
27
37
 
28
38
  data
29
39
  end
30
40
  end
31
41
  end
32
42
  end
33
- end
43
+ end
@@ -0,0 +1,60 @@
1
+ module Cldr
2
+ module Export
3
+ module Data
4
+ class Fields < Base
5
+ def initialize(locale)
6
+ super
7
+ update(:fields => fields)
8
+ end
9
+
10
+ private
11
+
12
+ def fields
13
+ select('dates/fields/field').each_with_object({}) do |field_node, ret|
14
+ type = field_node.attribute('type').value
15
+ ret[type] = field(field_node)
16
+ end
17
+ end
18
+
19
+ def field(field_node)
20
+ result = {}
21
+
22
+ unless (display_name = (field_node / 'displayName').text).empty?
23
+ result[:display_name] = display_name
24
+ end
25
+
26
+ unless (forms = relative_forms(field_node)).empty?
27
+ result[:relative] = forms
28
+ end
29
+
30
+ unless (forms = relative_time_forms(field_node)).empty?
31
+ result[:relative_time] = forms
32
+ end
33
+
34
+ result
35
+ end
36
+
37
+ def relative_forms(field_node)
38
+ (field_node / 'relative').each_with_object({}) do |relative_node, ret|
39
+ type = relative_node.attribute('type').value.to_i
40
+ ret[type] = relative_node.text
41
+ end
42
+ end
43
+
44
+ def relative_time_forms(field_node)
45
+ (field_node / 'relativeTime').each_with_object({}) do |relative_time_node, ret|
46
+ type = relative_time_node.attribute('type').value
47
+ ret[type] = relative_time_patterns(relative_time_node)
48
+ end
49
+ end
50
+
51
+ def relative_time_patterns(relative_time_node)
52
+ (relative_time_node / 'relativeTimePattern').each_with_object({}) do |relative_time_pattern_node, ret|
53
+ count = relative_time_pattern_node.attribute('count').value
54
+ ret[count] = relative_time_pattern_node.text
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -9,7 +9,7 @@ module Cldr
9
9
 
10
10
  def languages
11
11
  @languages ||= select('localeDisplayNames/languages/language').inject({}) do |result, node|
12
- result[node.attribute('type').value.gsub('_', '-').to_sym] = node.content unless draft?(node)
12
+ result[node.attribute('type').value.gsub('_', '-').to_sym] = node.content unless draft?(node) or alt?(node)
13
13
  result
14
14
  end
15
15
  end
@@ -0,0 +1,29 @@
1
+ module Cldr
2
+ module Export
3
+ module Data
4
+ class LikelySubtags < Base
5
+
6
+ def initialize
7
+ super(nil)
8
+ update(:subtags => subtags)
9
+ end
10
+
11
+ private
12
+
13
+ def subtags
14
+ doc.xpath('//likelySubtag').inject({}) do |ret, subtag|
15
+ from = subtag.attribute('from').value
16
+ to = subtag.attribute('to').value
17
+ ret[from] = to
18
+ ret
19
+ end
20
+ end
21
+
22
+ def path
23
+ @path ||= "#{Cldr::Export::Data.dir}/supplemental/likelySubtags.xml"
24
+ end
25
+
26
+ end
27
+ end
28
+ end
29
+ end
@@ -44,13 +44,48 @@ module Cldr
44
44
  end
45
45
 
46
46
  def format(type)
47
- result = select("numbers/#{type}Formats/#{type}FormatLength/#{type}Format").inject({}) do |format_result, format_node|
48
- format_key = format_node.parent.attribute('type')
49
- format_result[format_key ? format_key.value : :default] = select(format_node, "pattern").inject({}) do |pattern_result, pattern_node|
50
- pattern_key = pattern_node.attribute('type')
51
- pattern_result[pattern_key ? pattern_key.value : :default] = pattern_node.content unless draft?(pattern_node)
52
- pattern_result
47
+ result = select("numbers/#{type}Formats/#{type}FormatLength").inject({}) do |format_result, format_length_node|
48
+ format_nodes = select(format_length_node, "#{type}Format")
49
+
50
+ format_key = format_length_node.attribute('type')
51
+ format_key = format_key ? format_key.value : :default
52
+
53
+ if format_nodes.size > 0
54
+ format_nodes.each do |format_node|
55
+ format_result[format_key] ||= select(format_node, "pattern").inject({}) do |pattern_result, pattern_node|
56
+ pattern_key_node = pattern_node.attribute('type')
57
+
58
+ pattern_count_node = pattern_node.attribute('count')
59
+
60
+ unless draft?(pattern_node)
61
+ pattern_key = pattern_key_node ? pattern_key_node.value : :default
62
+
63
+ if pattern_count_node
64
+ pattern_count = pattern_count_node.value
65
+
66
+ if pattern_result[pattern_key].nil?
67
+ pattern_result[pattern_key] ||= {}
68
+ elsif !pattern_result[pattern_key].is_a?(Hash)
69
+ raise "can't parse patterns with and without 'count' attribute in the same section"
70
+ end
71
+
72
+ pattern_result[pattern_key][pattern_count] = pattern_node.content
73
+ else
74
+ pattern_result[pattern_key] = pattern_node.content
75
+ end
76
+ end
77
+
78
+ pattern_result
79
+ end
80
+ end
81
+ else
82
+ aliased = select(format_length_node, 'alias').first
83
+
84
+ if aliased
85
+ format_result[format_key] = xpath_to_redirect(aliased.attribute('path').value)
86
+ end
53
87
  end
88
+
54
89
  format_result
55
90
  end
56
91
 
@@ -58,6 +93,13 @@ module Cldr
58
93
  result
59
94
  end
60
95
 
96
+ def xpath_to_redirect(xpath)
97
+ length = xpath[/(\w+)FormatLength/, 1]
98
+ type = xpath[/@type='(\w+)'/, 1]
99
+
100
+ :"numbers.formats.#{length}.patterns.#{type}"
101
+ end
102
+
61
103
  def number_system(type)
62
104
  node = select("numbers/#{type}Formats").first
63
105
  node.attribute('numberSystem').value rescue "latn"
@@ -0,0 +1,23 @@
1
+ require 'nokogiri'
2
+
3
+ module Cldr
4
+ module Export
5
+ module Data
6
+ class ParentLocales < Hash
7
+ def initialize(_ = nil)
8
+ path = File.join(Cldr::Export::Data.dir, 'supplemental', 'supplementalData.xml')
9
+ doc = File.open(path) { |file| Nokogiri::XML(file) }
10
+
11
+ doc.xpath('//parentLocales/parentLocale').each do |node|
12
+ parent = node.attr('parent')
13
+ locales = node.attr('locales').split(' ')
14
+
15
+ locales.each do |locale|
16
+ self[locale] = parent
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,70 @@
1
+ require 'nokogiri'
2
+
3
+ module Cldr
4
+ module Export
5
+ module Data
6
+ class PluralRules < Hash
7
+ attr_reader :locale
8
+
9
+ def initialize(locale)
10
+ find_rules(locale).each_pair do |rule_type, rule_data|
11
+ self[rule_type.to_sym] = rule_data.inject({}) do |ret, rule|
12
+ ret[rule.attributes['count'].text] = rule.text
13
+ ret
14
+ end
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def sources
21
+ @sources ||= ['plurals', 'ordinals'].inject({}) do |ret, source_name|
22
+ ret[source_name] = ::Nokogiri::XML(
23
+ File.read("#{Cldr::Export::Data.dir}/supplemental/#{source_name}.xml")
24
+ )
25
+ ret
26
+ end
27
+ end
28
+
29
+ def find_rules(locale)
30
+ locale = locale.to_s
31
+
32
+ sources.inject({}) do |ret, (file, source)|
33
+ # try to find exact match, then fall back
34
+ node = find_rules_for_exact_locale(locale, source) ||
35
+ find_rules_for_exact_locale(base_locale(locale), source) ||
36
+ find_rules_for_base_locale(locale, source) ||
37
+ find_rules_for_base_locale(base_locale(locale), source)
38
+
39
+ if node
40
+ name = (source / 'plurals').first.attributes['type'].value
41
+ ret[name] = node / 'pluralRule'
42
+ end
43
+
44
+ ret
45
+ end
46
+ end
47
+
48
+ def find_rules_for_exact_locale(locale, source)
49
+ (source / 'plurals/pluralRules').find do |node|
50
+ node.attributes['locales'].text
51
+ .split(' ').map(&:downcase)
52
+ .include?(locale.downcase)
53
+ end
54
+ end
55
+
56
+ def find_rules_for_base_locale(locale, source)
57
+ (source / 'plurals/pluralRules').find do |node|
58
+ node.attributes['locales'].text
59
+ .split(' ').map { |l| base_locale(l) }
60
+ .include?(locale.downcase)
61
+ end
62
+ end
63
+
64
+ def base_locale(locale)
65
+ locale.split(/[_-]/).first
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -57,6 +57,8 @@ module Cldr
57
57
  end
58
58
 
59
59
  def parse(code)
60
+ code = scrub_code(code)
61
+
60
62
  code = code.split('@').first.to_s
61
63
  operand = /(n|i|f|t|v|w)/i
62
64
  expr = /#{operand}(?:\s+(?:mod|%)\s+([\d]+))?/i
@@ -78,6 +80,15 @@ module Cldr
78
80
  raise "can not parse '#{code}'"
79
81
  end
80
82
  end
83
+
84
+ private
85
+
86
+ def scrub_code(code)
87
+ code
88
+ .gsub(/(n)%(\d+)/, '\1 % \2') # n%1000 -> n % 1000
89
+ .gsub(/(\d+)=(\d+)/, '\1 = \2') # 10=100-> 10 = 100
90
+ .gsub(/(n)!=(\d+)/, '\1 != \2') # n!=100 -> n != 100
91
+ end
81
92
  end
82
93
 
83
94
  attr_reader :locales
@@ -199,4 +210,4 @@ module Cldr
199
210
  end
200
211
  end
201
212
  end
202
- end
213
+ end