ruby-cldr 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +8 -2
- data/Gemfile.lock +55 -5
- data/VERSION +1 -1
- data/lib/cldr/download.rb +15 -11
- data/lib/cldr/export.rb +64 -16
- data/lib/cldr/export/data.rb +18 -10
- data/lib/cldr/export/data/calendars/gregorian.rb +45 -22
- data/lib/cldr/export/data/currencies.rb +6 -1
- data/lib/cldr/export/data/currency_digits_and_rounding.rb +22 -0
- data/lib/cldr/export/data/layout.rb +22 -0
- data/lib/cldr/export/data/lists.rb +28 -0
- data/lib/cldr/export/data/metazones.rb +45 -0
- data/lib/cldr/export/data/numbering_systems.rb +41 -0
- data/lib/cldr/export/data/numbers.rb +9 -0
- data/lib/cldr/export/data/plurals.rb +8 -7
- data/lib/cldr/export/data/plurals/rules.rb +114 -31
- data/lib/cldr/export/data/rbnf.rb +64 -0
- data/lib/cldr/export/data/rbnf_root.rb +19 -0
- data/lib/cldr/export/data/timezones.rb +29 -6
- data/lib/cldr/export/data/units.rb +23 -6
- data/lib/cldr/export/data/windows_zones.rb +23 -0
- data/lib/cldr/export/yaml.rb +2 -1
- data/lib/cldr/format/datetime/base.rb +1 -1
- data/lib/cldr/format/time.rb +1 -1
- data/lib/cldr/thor.rb +1 -1
- data/lib/core_ext/string/camelize.rb +1 -1
- data/test/export/data/calendars_test.rb +23 -18
- data/test/export/data/currencies_test.rb +24 -24
- data/test/export/data/languages_test.rb +52 -48
- data/test/export/data/metazones_test.rb +17 -0
- data/test/export/data/numbers_test.rb +34 -3
- data/test/export/data/plurals_test.rb +133 -32
- data/test/export/data/territories_test.rb +22 -22
- data/test/export/data/timezones_test.rb +49 -26
- data/test/export/data/units_test.rb +16 -17
- data/test/export/data/windows_zones_test.rb +12 -0
- data/test/export_test.rb +4 -1
- data/test/format/date_test.rb +2 -2
- data/test/test_autotest.rb +1 -1
- metadata +94 -32
@@ -0,0 +1,22 @@
|
|
1
|
+
module Cldr
|
2
|
+
module Export
|
3
|
+
module Data
|
4
|
+
class Layout < Base
|
5
|
+
def initialize(locale)
|
6
|
+
super
|
7
|
+
update(:layout => layout)
|
8
|
+
end
|
9
|
+
|
10
|
+
def layout
|
11
|
+
result = { :orientation => { :character_order => nil } }
|
12
|
+
|
13
|
+
if node = select("layout/orientation/characterOrder/text()").first
|
14
|
+
result[:orientation][:character_order] = node.text
|
15
|
+
end
|
16
|
+
|
17
|
+
result
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Cldr
|
2
|
+
module Export
|
3
|
+
module Data
|
4
|
+
class Lists < Base
|
5
|
+
def initialize(locale)
|
6
|
+
super
|
7
|
+
update(:lists => lists)
|
8
|
+
end
|
9
|
+
|
10
|
+
def lists
|
11
|
+
select('listPatterns/listPattern').inject({}) do |list_pattern_ret, list_pattern|
|
12
|
+
pattern_type = if attribute = list_pattern.attribute('type')
|
13
|
+
attribute.value.to_sym
|
14
|
+
else
|
15
|
+
:default
|
16
|
+
end
|
17
|
+
|
18
|
+
list_pattern_ret[pattern_type] = select(list_pattern, 'listPatternPart').inject({}) do |part_ret, part|
|
19
|
+
part_ret[part.attribute('type').value.to_sym] = part.content
|
20
|
+
part_ret
|
21
|
+
end
|
22
|
+
list_pattern_ret
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
module Cldr
|
5
|
+
module Export
|
6
|
+
module Data
|
7
|
+
class Metazones < Hash
|
8
|
+
def initialize
|
9
|
+
path = "#{Cldr::Export::Data.dir}/supplemental/metaZones.xml"
|
10
|
+
doc = File.open(path) { |file| Nokogiri::XML(file) }
|
11
|
+
self[:timezones] = doc.xpath('//metaZones/metazoneInfo/timezone').inject({}) do |result, node|
|
12
|
+
timezone = node.attr('type').to_sym
|
13
|
+
result[timezone] = metazone(node.xpath('usesMetazone'))
|
14
|
+
result[timezone].sort_by! { |zone| [zone['from'] ? zone['from'] : DateTime.new, zone['to'] ? zone['to'] : DateTime.now] }
|
15
|
+
result
|
16
|
+
end
|
17
|
+
self[:primaryzones] = doc.xpath('//primaryZones/primaryZone').inject({}) do |result, node|
|
18
|
+
territory = node.attr('iso3166').to_sym
|
19
|
+
result[territory] = node.content
|
20
|
+
result
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
def metazone(nodes)
|
27
|
+
nodes.inject([]) do |result, node|
|
28
|
+
mzone = node.attr('mzone')
|
29
|
+
from = node.attr('from')
|
30
|
+
to = node.attr('to')
|
31
|
+
data = { 'metazone' => mzone }
|
32
|
+
data['from'] = parse_date(from) if from
|
33
|
+
data['to'] = parse_date(to) if to
|
34
|
+
result << data
|
35
|
+
result
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse_date(date)
|
40
|
+
DateTime.strptime(date + ' UTC', '%F %R %Z')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Cldr
|
4
|
+
module Export
|
5
|
+
module Data
|
6
|
+
class NumberingSystems < Base
|
7
|
+
|
8
|
+
def initialize(*args)
|
9
|
+
super(nil)
|
10
|
+
update(:numbering_systems => numbering_systems)
|
11
|
+
end
|
12
|
+
|
13
|
+
def numbering_systems
|
14
|
+
doc.xpath("supplementalData/numberingSystems/numberingSystem").inject({}) do |ret, numbering|
|
15
|
+
system_name = numbering.attribute("id").value
|
16
|
+
type = numbering.attribute("type").value
|
17
|
+
|
18
|
+
param = case type
|
19
|
+
when "numeric"
|
20
|
+
"digits"
|
21
|
+
when "algorithmic"
|
22
|
+
"rules"
|
23
|
+
end
|
24
|
+
|
25
|
+
ret[system_name] = {
|
26
|
+
:type => type,
|
27
|
+
param => numbering.attribute(param).value
|
28
|
+
}
|
29
|
+
|
30
|
+
ret
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def path
|
35
|
+
@path ||= "#{Cldr::Export::Data.dir}/supplemental/numberingSystems.xml"
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -9,15 +9,19 @@ module Cldr
|
|
9
9
|
:symbols => symbols,
|
10
10
|
:formats => {
|
11
11
|
:decimal => {
|
12
|
+
:number_system => number_system('decimal'),
|
12
13
|
:patterns => format('decimal')
|
13
14
|
},
|
14
15
|
:scientific => {
|
16
|
+
:number_system => number_system('scientific'),
|
15
17
|
:patterns => format('scientific')
|
16
18
|
},
|
17
19
|
:percent => {
|
20
|
+
:number_system => number_system('percent'),
|
18
21
|
:patterns => format('percent')
|
19
22
|
},
|
20
23
|
:currency => {
|
24
|
+
:number_system => number_system('currency'),
|
21
25
|
:patterns => format('currency'),
|
22
26
|
:unit => unit
|
23
27
|
}
|
@@ -54,6 +58,11 @@ module Cldr
|
|
54
58
|
result
|
55
59
|
end
|
56
60
|
|
61
|
+
def number_system(type)
|
62
|
+
node = select("numbers/#{type}Formats").first
|
63
|
+
node.attribute('numberSystem').value rescue "latn"
|
64
|
+
end
|
65
|
+
|
57
66
|
def unit
|
58
67
|
@unit ||= select("numbers/currencyFormats/unitPattern").inject({}) do |result, node|
|
59
68
|
count = node.attribute('count').value rescue 'one'
|
@@ -3,7 +3,7 @@ require 'fileutils'
|
|
3
3
|
module Cldr
|
4
4
|
module Export
|
5
5
|
module Data
|
6
|
-
class Plurals <
|
6
|
+
class Plurals < Hash
|
7
7
|
autoload :Grammar, 'cldr/export/data/plurals/grammar'
|
8
8
|
autoload :Parser, 'cldr/export/data/plurals/grammar'
|
9
9
|
autoload :Rules, 'cldr/export/data/plurals/rules'
|
@@ -20,18 +20,19 @@ module Cldr
|
|
20
20
|
File.read("#{Cldr::Export::Data.dir}/supplemental/plurals.xml")
|
21
21
|
end
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
attr_reader :locale
|
25
25
|
|
26
26
|
def initialize(locale)
|
27
27
|
@locale = locale
|
28
|
-
|
28
|
+
self.merge!(rule ? to_hash : {})
|
29
29
|
end
|
30
|
-
|
31
|
-
def
|
32
|
-
|
30
|
+
|
31
|
+
def to_hash
|
32
|
+
rule_rb = rule ? rule.to_ruby : nil
|
33
|
+
{ :keys => (rule || {}).keys, :rule => rule_rb }
|
33
34
|
end
|
34
|
-
|
35
|
+
|
35
36
|
def rule
|
36
37
|
@rule = Plurals.rules.rule(locale)
|
37
38
|
end
|
@@ -17,15 +17,15 @@ module Cldr
|
|
17
17
|
rules
|
18
18
|
end
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
def locales
|
22
22
|
@locales ||= map { |rule| rule.locales }.flatten.map(&:to_s).sort.map(&:to_sym)
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
def rule(locale)
|
26
26
|
detect { |rule| rule.locales.include?(locale.to_sym) }
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
def to_ruby(options = {})
|
30
30
|
namespaces = options[:namespaces] || [:i18n]
|
31
31
|
code = locales.map do |locale|
|
@@ -38,25 +38,44 @@ module Cldr
|
|
38
38
|
"{\n" + code + "\n}"
|
39
39
|
end
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
class Rule < Array
|
43
43
|
class << self
|
44
|
+
|
45
|
+
def parse_list(str)
|
46
|
+
values = []
|
47
|
+
ranges = []
|
48
|
+
str.split(',').each do |value|
|
49
|
+
parts = value.split('..')
|
50
|
+
if parts.count == 1
|
51
|
+
values << value.to_i
|
52
|
+
else
|
53
|
+
ranges << (parts.first.to_i..parts.last.to_i)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
[values, ranges]
|
57
|
+
end
|
58
|
+
|
44
59
|
def parse(code)
|
60
|
+
code = code.split('@').first.to_s
|
61
|
+
operand = /(n|i|f|t|v|w)/i
|
62
|
+
expr = /#{operand}(?:\s+(?:mod|%)\s+([\d]+))?/i
|
63
|
+
range = /(?:\d+\.\.\d+|\d+)/i
|
64
|
+
range_list = /(#{range}(?:\s*,\s*#{range})*)/i
|
45
65
|
case code
|
46
|
-
when /
|
47
|
-
code.split(/
|
48
|
-
when /
|
49
|
-
code.split(/
|
50
|
-
when
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
when /n/
|
66
|
+
when /or/i
|
67
|
+
code.split(/or/i).inject(Proposition.new('||')) { |rule, code| rule << parse(code) }
|
68
|
+
when /and/i
|
69
|
+
code.split(/and/i).inject(Proposition.new('&&')) { |rule, code| rule << parse(code) }
|
70
|
+
when /^\s*#{expr}\s+(?:is(\s+not)?|(not\s+)?in|(!)?=)\s+#{range_list}\s*$/i
|
71
|
+
list = parse_list($6)
|
72
|
+
Expression.new((list.first.count == 1 && list.last.count == 0) ? :is : :in, $2, !($3.nil? && $4.nil? && $5.nil?), (list.first.count == 1 && list.last.count == 0) ? list.first.first : list, $1)
|
73
|
+
when /^\s*#{expr}\s+(not\s+)?within\s+#{range_list}\s*$/i
|
74
|
+
Expression.new(:within, $2, !($3==nil), parse_list($4).last.first, $1)
|
75
|
+
when /^\s*$/
|
57
76
|
Expression.new
|
58
77
|
else
|
59
|
-
raise "can not parse #{code}"
|
78
|
+
raise "can not parse '#{code}'"
|
60
79
|
end
|
61
80
|
end
|
62
81
|
end
|
@@ -66,15 +85,19 @@ module Cldr
|
|
66
85
|
def initialize(locales)
|
67
86
|
@locales = locales.map { |locale| locale.gsub('_', '-').to_sym }
|
68
87
|
end
|
69
|
-
|
88
|
+
|
70
89
|
def keys
|
71
|
-
inject([]) { |keys, (key, code)| keys << key.to_sym }
|
90
|
+
inject([]) { |keys, (key, code)| keys << key.to_sym }
|
72
91
|
end
|
73
|
-
|
92
|
+
|
74
93
|
def to_ruby
|
75
|
-
@condition ||= 'lambda { |n| ' + reverse.inject(':other') do |result, (key, code)|
|
94
|
+
@condition ||= 'lambda { |n| n = n.respond_to?(:abs) ? n.abs : ((m = n.to_s)[0] == "-" ? m[1,m.length] : m); ' + reverse.inject(':other') do |result, (key, code)|
|
76
95
|
code = self.class.parse(code).to_ruby
|
77
|
-
|
96
|
+
if code
|
97
|
+
"#{code} ? :#{key} : #{result}"
|
98
|
+
else
|
99
|
+
':' << key.to_s
|
100
|
+
end
|
78
101
|
end + ' }'
|
79
102
|
end
|
80
103
|
end
|
@@ -85,30 +108,90 @@ module Cldr
|
|
85
108
|
end
|
86
109
|
|
87
110
|
def to_ruby
|
88
|
-
@ruby ||= map { |expr| expr.to_ruby }.join(" #{@type} ")
|
111
|
+
@ruby ||= '(' << map { |expr| expr.to_ruby }.join(" #{@type} ") << ')'
|
89
112
|
end
|
90
113
|
end
|
91
114
|
|
92
115
|
class Expression
|
93
|
-
attr_reader :operator, :operand, :mod, :negate
|
116
|
+
attr_reader :operator, :operand, :mod, :negate, :type
|
94
117
|
|
95
|
-
def initialize(operator = nil, mod = nil, negate = nil, operand = nil)
|
96
|
-
@operator, @mod, @negate, @operand = operator, mod, negate, operand
|
118
|
+
def initialize(operator = nil, mod = nil, negate = nil, operand = nil, type = nil)
|
119
|
+
@operator, @mod, @negate, @operand, @type = operator, mod, negate, operand, type
|
97
120
|
end
|
98
121
|
|
122
|
+
# Symbol Value
|
123
|
+
# n absolute value of the source number (integer and decimals).
|
124
|
+
# i integer digits of n.
|
125
|
+
# v number of visible fraction digits in n, with trailing zeros.
|
126
|
+
# w number of visible fraction digits in n, without trailing zeros.
|
127
|
+
# f visible fractional digits in n, with trailing zeros.
|
128
|
+
# t visible fractional digits in n, without trailing zeros.
|
129
|
+
#
|
130
|
+
# http://www.unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules
|
99
131
|
def to_ruby
|
100
132
|
@ruby ||= begin
|
101
|
-
|
102
|
-
|
133
|
+
return nil unless @operator
|
134
|
+
enclose = false
|
135
|
+
fraction = false
|
136
|
+
case @type
|
137
|
+
when 'i'
|
138
|
+
op = 'n.to_i'
|
139
|
+
when 'f'
|
140
|
+
op = '(f = n.to_s.split(".")[1]) ? f.to_i : 0'
|
141
|
+
enclose = true
|
142
|
+
when 't'
|
143
|
+
op = '(t = n.to_s.split(".")[1]) ? t.gsub(/0+$/, "").to_i : 0'
|
144
|
+
enclose = true
|
145
|
+
when 'v'
|
146
|
+
op = '(v = n.to_s.split(".")[1]) ? v.length : 0'
|
147
|
+
enclose = true
|
148
|
+
when 'w'
|
149
|
+
op = '(w = n.to_s.split(".")[1]) ? w.gsub(/0+$/, "").length : 0'
|
150
|
+
enclose = true
|
151
|
+
else
|
152
|
+
fraction = true
|
153
|
+
op = 'n.to_f'
|
154
|
+
end
|
155
|
+
if @mod
|
156
|
+
op = '(' << op << ')' if enclose
|
157
|
+
op << ' % ' << @mod.to_s
|
158
|
+
enclose = false
|
159
|
+
end
|
103
160
|
case @operator
|
104
161
|
when :is
|
105
|
-
op
|
162
|
+
op = '(' << op << ')' if enclose
|
163
|
+
op << (@negate ? ' != ' : ' == ') << @operand.to_s
|
106
164
|
when :in
|
107
|
-
|
165
|
+
values = @operand.first
|
166
|
+
ranges = @operand.last
|
167
|
+
prepend = (@negate ? '!' : '')
|
168
|
+
str = ''
|
169
|
+
bop = op
|
170
|
+
bop = '(' << bop << ')' if enclose || @mod
|
171
|
+
if values.count == 1
|
172
|
+
str = bop + (@negate ? ' != ' : ' == ') << values.first.to_s
|
173
|
+
elsif values.count > 1
|
174
|
+
str = prepend + "#{values.inspect}.include?(#{op})"
|
175
|
+
end
|
176
|
+
enclose = ranges.count > 1 || (values.count > 0 && ranges.count > 0)
|
177
|
+
if ranges.count > 0
|
178
|
+
str << ' || ' if values.count > 0
|
179
|
+
str << "((#{bop} % 1).zero? && " if fraction
|
180
|
+
str << '(' if ranges.count > 1
|
181
|
+
str << prepend + "(#{ranges.shift.inspect}).include?(#{op})"
|
182
|
+
ranges.each do |range|
|
183
|
+
str << ' || ' << prepend + "(#{range.inspect}).include?(#{op})"
|
184
|
+
end
|
185
|
+
str << ')' if ranges.count > 0
|
186
|
+
str << ')' if fraction
|
187
|
+
end
|
188
|
+
str = '(' << str << ')' if enclose
|
189
|
+
str
|
108
190
|
when :within
|
109
|
-
|
191
|
+
op = '(' << op << ')' if enclose || @mod
|
192
|
+
(@negate ? '!' : '') + "#{op}.between?(#{@operand.first}, #{@operand.last})"
|
110
193
|
else
|
111
|
-
|
194
|
+
raise "unknown operator '#{@operator}'"
|
112
195
|
end
|
113
196
|
end
|
114
197
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Cldr
|
4
|
+
module Export
|
5
|
+
module Data
|
6
|
+
class Rbnf < Base
|
7
|
+
|
8
|
+
def initialize(*args)
|
9
|
+
super
|
10
|
+
update(:rbnf => { :grouping => rule_groups })
|
11
|
+
end
|
12
|
+
|
13
|
+
def rule_groups
|
14
|
+
if File.exist?(path)
|
15
|
+
select("rbnf/rulesetGrouping").map do |grouping_node|
|
16
|
+
{
|
17
|
+
:type => grouping_node.attribute("type").value,
|
18
|
+
:ruleset => (grouping_node / "ruleset").map do |ruleset_node|
|
19
|
+
rule_set(ruleset_node)
|
20
|
+
end
|
21
|
+
}
|
22
|
+
end
|
23
|
+
else
|
24
|
+
{}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def rule_set(ruleset_node)
|
29
|
+
attrs = {
|
30
|
+
:type => ruleset_node.attribute("type").value,
|
31
|
+
:rules => (ruleset_node / "rbnfrule").map do |rule_node|
|
32
|
+
radix = if radix_attr = rule_node.attribute("radix")
|
33
|
+
radix_attr.value
|
34
|
+
else
|
35
|
+
nil
|
36
|
+
end
|
37
|
+
|
38
|
+
attrs = {
|
39
|
+
:value => rule_node.attribute("value").value,
|
40
|
+
:rule => fix_rule(rule_node.text)
|
41
|
+
}
|
42
|
+
|
43
|
+
attrs[:radix] = radix if radix
|
44
|
+
attrs
|
45
|
+
end
|
46
|
+
}
|
47
|
+
|
48
|
+
access = ruleset_node.attribute("access")
|
49
|
+
attrs[:access] = access.value if access
|
50
|
+
attrs
|
51
|
+
end
|
52
|
+
|
53
|
+
def fix_rule(rule)
|
54
|
+
rule.gsub(/\A'/, '').gsub("←", '<').gsub("→", '>')
|
55
|
+
end
|
56
|
+
|
57
|
+
def path
|
58
|
+
@path ||= "#{Cldr::Export::Data.dir}/rbnf/#{locale.to_s.gsub('-', '_')}.xml"
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|