ruby-cldr 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. data/LICENSE +20 -0
  2. data/README.textile +104 -0
  3. data/Rakefile +18 -0
  4. data/TODO +68 -0
  5. data/VERSION +1 -0
  6. data/cldr.thor +5 -0
  7. data/lib/cldr/data/base.rb +66 -0
  8. data/lib/cldr/data/calendars/gregorian.rb +124 -0
  9. data/lib/cldr/data/calendars.rb +12 -0
  10. data/lib/cldr/data/currencies.rb +26 -0
  11. data/lib/cldr/data/delimiters.rb +21 -0
  12. data/lib/cldr/data/languages.rb +17 -0
  13. data/lib/cldr/data/numbers.rb +60 -0
  14. data/lib/cldr/data/plurals/cldr_grammar.treetop +50 -0
  15. data/lib/cldr/data/plurals/grammar.rb +536 -0
  16. data/lib/cldr/data/plurals/rules.rb +113 -0
  17. data/lib/cldr/data/plurals.rb +39 -0
  18. data/lib/cldr/data/territories.rb +17 -0
  19. data/lib/cldr/data/timezones.rb +25 -0
  20. data/lib/cldr/data/units.rb +25 -0
  21. data/lib/cldr/data.rb +34 -0
  22. data/lib/cldr/download.rb +20 -0
  23. data/lib/cldr/export/ruby.rb +16 -0
  24. data/lib/cldr/export/yaml.rb +39 -0
  25. data/lib/cldr/export.rb +69 -0
  26. data/lib/cldr/format/currency.rb +11 -0
  27. data/lib/cldr/format/date.rb +144 -0
  28. data/lib/cldr/format/datetime/base.rb +32 -0
  29. data/lib/cldr/format/datetime.rb +28 -0
  30. data/lib/cldr/format/decimal/base.rb +18 -0
  31. data/lib/cldr/format/decimal/fraction.rb +28 -0
  32. data/lib/cldr/format/decimal/integer.rb +46 -0
  33. data/lib/cldr/format/decimal/number.rb +44 -0
  34. data/lib/cldr/format/decimal.rb +32 -0
  35. data/lib/cldr/format/percent.rb +11 -0
  36. data/lib/cldr/format/time.rb +71 -0
  37. data/lib/cldr/format.rb +113 -0
  38. data/lib/cldr/thor.rb +33 -0
  39. data/lib/cldr.rb +7 -0
  40. data/lib/core_ext/hash/deep_merge.rb +7 -0
  41. data/lib/core_ext/hash/deep_stringify_keys.rb +11 -0
  42. data/lib/core_ext/hash/symbolize_keys.rb +10 -0
  43. data/lib/core_ext/string/camelize.rb +5 -0
  44. data/lib/core_ext/string/underscore.rb +9 -0
  45. data/test/all.rb +3 -0
  46. data/test/data/all.rb +3 -0
  47. data/test/data/calendars_test.rb +149 -0
  48. data/test/data/currencies_test.rb +47 -0
  49. data/test/data/delimiters_test.rb +31 -0
  50. data/test/data/languages_test.rb +67 -0
  51. data/test/data/numbers_test.rb +61 -0
  52. data/test/data/plurals_test.rb +132 -0
  53. data/test/data/territories_test.rb +51 -0
  54. data/test/data/timezones_test.rb +56 -0
  55. data/test/data/units_test.rb +36 -0
  56. data/test/export_test.rb +57 -0
  57. data/test/formats/all.rb +3 -0
  58. data/test/formats/datetime/all.rb +3 -0
  59. data/test/formats/datetime/date_test.rb +31 -0
  60. data/test/formats/datetime/datetime_test.rb +18 -0
  61. data/test/formats/datetime/day_test.rb +41 -0
  62. data/test/formats/datetime/hour_test.rb +79 -0
  63. data/test/formats/datetime/minute_test.rb +25 -0
  64. data/test/formats/datetime/month_test.rb +76 -0
  65. data/test/formats/datetime/period_test.rb +20 -0
  66. data/test/formats/datetime/quarter_test.rb +118 -0
  67. data/test/formats/datetime/second_test.rb +80 -0
  68. data/test/formats/datetime/time_test.rb +33 -0
  69. data/test/formats/datetime/timezone_test.rb +23 -0
  70. data/test/formats/datetime/year_test.rb +57 -0
  71. data/test/formats/decimal/fraction_test.rb +17 -0
  72. data/test/formats/decimal/integer_test.rb +67 -0
  73. data/test/formats/decimal/number_test.rb +77 -0
  74. data/test/formats/decimal_test.rb +19 -0
  75. data/test/formats/format_test.rb +66 -0
  76. data/test/formats/rails_compat/all.rb +3 -0
  77. data/test/formats/rails_compat/format_integer_test.rb +56 -0
  78. data/test/formats/rails_compat/format_number_test.rb +134 -0
  79. data/test/test_helper.rb +5 -0
  80. metadata +169 -0
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Sven Fuchs
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.textile ADDED
@@ -0,0 +1,104 @@
1
+ h1. Ruby library for exporting and using data from CLDR
2
+
3
+ CLDR ("Common Locale Data Repository":http://cldr.unicode.org) contains tons of high-quality locale data such as formatting rules for dates, times, numbers, currencies as well as language, country, calendar-specific names etc.
4
+
5
+ For localizing applications in Ruby we'll obviously be able to use this incredibly comprehensive and well-maintained resource.
6
+
7
+ This library is a first stab at that goal. You can:
8
+
9
+ * export CLDR data to YAML and Ruby formatted files which are supposed to be usable in an "I18n":http://github.com/svenfuchs/i18n context but might be usable elsewhere, too.
10
+ * use CLDR compliant formatters for the following types: number, percentage, currency, date, time, datetime.
11
+
12
+ h2. Requirements
13
+
14
+ * Ruby 1.9 (if you want well-ordered Hashes to be exported)
15
+ * Thor
16
+
17
+ h2. Installation
18
+
19
+ <pre>
20
+ gem install cldr (not there, yet. install locally)
21
+ thor install http://github.com/svenfuchs/cldr/raw/master/cldr.thor --as=cldr
22
+ </pre>
23
+
24
+ h2. Export
25
+
26
+ The following command will export all known components from all locales to the target directory ./data/[locale]/[component].{yml,rb}:
27
+
28
+ <pre>
29
+ $ thor cldr:export
30
+ </pre>
31
+
32
+ You can also optionally specify locales and/or components to export as well as the target directory:
33
+
34
+ <pre>
35
+ $ thor cldr:export --locales de fr en --components numbers plurals --target=./tmp/export
36
+ </pre>
37
+
38
+ This will export the components :numbers and :plurals from the locales :de, :fr and :en to the same target directory.
39
+
40
+ Also note that CLDR natively builds on a locale fallback concept where all locales eventually fall back to a :root locale. E.g. the :de-AT locale only contains a single format for numbers, which means that an application is supposed to use other formats from the :de locale (fallback). Particular bits of information are only present in the :root locale where all locales fall back to eventually.
41
+
42
+ By default this library just exports data that is present in CLDR for a given locale. If you do not want to use locale fallbacks in your application you'll need to "flatten" locale fallbacks and merge the data during export time. To do that you can use the --merge option:
43
+
44
+ <pre>
45
+ $ thor cldr:export --merge
46
+ </pre>
47
+
48
+ h2. Formatters
49
+
50
+ The library includes a bunch of formatter classes that can be used to format Ruby objects like Numerics, Date, Time, DateTime etc. using the format information provided by CLDR.
51
+
52
+ E.g.:
53
+
54
+ <pre>
55
+ options = { :decimal => ',', :group => ' ' }
56
+ format = Cldr::Format::Numeric.new('#,##0.##', options)
57
+ format.apply(1234.567)
58
+ # => "1 234,57"
59
+
60
+ calendar = Cldr::Data::Calendars.new(:de)[:calendars][:gregorian]
61
+ format = Cldr::Format::Date.new('EEEE, d. MMMM y', calendar)
62
+ format.apply(Date.new(2010, 1, 11))
63
+ # => "Montag, 11. Januar 2010"
64
+
65
+ calendar = Cldr::Data::Calendars.new(:de)[:calendars][:gregorian]
66
+ format = Cldr::Format::Time.new('HH:mm:ss z', calendar)
67
+ format.apply(Time.utc(2010, 1, 1, 13, 12, 11))
68
+ # => "13:12:11 UTC"
69
+ </pre>
70
+
71
+ In order to make these things easier to use the library provides a bunch of helpers defined in the module Cldr::Format. (This module is supposed to work as an extension to the Simple backend in the I18n gem but is included here to suggest a common API to formatters and make development easier for usecases outside of the I18n gem. If you want to include this module somewhere else you have to implement a few abstract methods to provide translations.)
72
+
73
+ E.g.:
74
+
75
+ <pre>
76
+ format(:de, 123456.78)
77
+ # => "123.456,78"
78
+
79
+ format(:de, 123456.78, :as => :percent)
80
+ # => "123.457 %"
81
+
82
+ format(:de, 123456.78, :currency => 'EUR')
83
+ # => "123.456,78 EUR"
84
+
85
+ format(:de, Date.new(2010, 1, 1), :format => :full)
86
+ # => "Freitag, 1. Januar 2010"
87
+
88
+ format(:de, Time.utc(2010, 1, 1, 13, 15, 17), :format => :long)
89
+ # => "13:15:17 UTC"
90
+
91
+ format(:de, DateTime.new(2010, 11, 12, 13, 14, 15), :format => :long)
92
+ # => "12. November 2010 13:14:15 +00:00"
93
+
94
+ format(:de, DateTime.new(2010, 11, 12, 13, 14, 15), :date_format => :long, :time_format => :short)
95
+ # => "12. November 2010 13:14"
96
+ </pre>
97
+
98
+ h2. Resources
99
+
100
+ For additional information on CLDR plural rules see:
101
+
102
+ * "http://unicode.org/draft/reports/tr35/tr35.html#Language_Plural_Rules":http://unicode.org/draft/reports/tr35/tr35.html#Language_Plural_Rules
103
+ * "http://www.unicode.org/cldr/data/charts/supplemental/language_plural_rules.html":http://www.unicode.org/cldr/data/charts/supplemental/language_plural_rules.html
104
+
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "ruby-cldr"
8
+ gem.summary = %Q{Ruby library for exporting and using data from CLDR }
9
+ gem.description = %Q{Ruby library for exporting and using data from CLDR, see http://cldr.unicode.org}
10
+ gem.email = "svenfuchs@artweb-design.de"
11
+ gem.homepage = "http://github.com/svenfuchs/ruby-cldr"
12
+ gem.authors = ["Sven Fuchs"]
13
+ gem.files = FileList["*.thor", "[A-Z]*", "{lib,test}/**/*"]
14
+ end
15
+ Jeweler::GemcutterTasks.new
16
+ rescue LoadError
17
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
18
+ end
data/TODO ADDED
@@ -0,0 +1,68 @@
1
+ - during export resolve links if :merge => true
2
+ - make sense of timezone data
3
+ - hook into Rails' select_month and DateTime helpers
4
+
5
+ extract:
6
+
7
+ - territoryContainment (groups territories)
8
+ - languageData (maps languages/scripts to territories)
9
+ - territoryInfo (?)
10
+ - calendarData
11
+ - weekData
12
+
13
+ what do the following tags in supplementalMetadata mean?
14
+ - variable
15
+ - defaultContent
16
+
17
+
18
+ Instead of exporting YAML, maybe by default export Ruby classes:
19
+
20
+ module Cldr
21
+ module Data
22
+ class De::Numbers
23
+ def currency_format
24
+ "#,##0.00 ¤"
25
+ end
26
+
27
+ def symbols
28
+ { ... }
29
+ end
30
+ end
31
+
32
+ class De::Calendars::Gregorian
33
+ def months(context, type)
34
+ case context
35
+ when :format
36
+ case type
37
+ when :wide
38
+ { :sat => "Samstag", :sun => "Sonntag", :mon => "Montag", ...}
39
+ end
40
+ when :'stand-alone'
41
+ case type
42
+ when :narrow
43
+ { ... }
44
+ else
45
+ months(:format, :wide)
46
+ end
47
+ end
48
+ end
49
+
50
+ def date_format(type)
51
+ case type
52
+ when :full
53
+ "EEEE, d. MMMM y"
54
+ when :medium
55
+ "dd.MM.yyyy"
56
+ else
57
+ date_format(:medium)
58
+ end
59
+ end
60
+ end
61
+
62
+ class DeAt::Numbers < De::Numbers
63
+ end
64
+
65
+ class DeAt::Calendars::Gregorian < De::Calendars::Gregorian
66
+ end
67
+ end
68
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
data/cldr.thor ADDED
@@ -0,0 +1,5 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/lib')
2
+
3
+ require 'rubygems'
4
+ require 'thor'
5
+ require 'cldr/thor'
@@ -0,0 +1,66 @@
1
+ require 'core_ext/string/underscore'
2
+ require 'core_ext/hash/deep_merge'
3
+ require 'nokogiri'
4
+
5
+ class Cldr
6
+ module Data
7
+ class Base < Hash
8
+ attr_reader :locale
9
+
10
+ def initialize(*args)
11
+ hash = args.last.is_a?(Hash) ? args.pop : {}
12
+ @locale = args.pop.to_sym unless args.empty?
13
+ end
14
+
15
+ def []=(keys, value)
16
+ return if value.nil? || value.respond_to?(:empty?) && value.empty?
17
+
18
+ keys = keys.to_s.split('.')
19
+ last_key = keys.pop.to_sym
20
+
21
+ target = keys.inject(self) { |target, key| target[key.to_sym] || target.store(key.to_sym, {}) }
22
+ target.store(last_key, value)
23
+ end
24
+
25
+ def update(hash)
26
+ hash.each { |key, value| self[key] = value }
27
+ end
28
+
29
+ protected
30
+
31
+ def plural?(node)
32
+ !!node.attribute('count')
33
+ end
34
+
35
+ def draft?(node)
36
+ draft = node.attribute('draft')
37
+ draft && draft.value == 'unconfirmed'
38
+ end
39
+
40
+ def name(node)
41
+ node.name.underscore
42
+ end
43
+
44
+ def count(node)
45
+ node.attribute('count').value
46
+ end
47
+
48
+ def select(*sources)
49
+ doc.xpath(xpath(sources))
50
+ end
51
+
52
+ def xpath(sources)
53
+ path = sources.map { |source| source.respond_to?(:path) ? source.path : source }.join('/')
54
+ path =~ /^\/?\/ldml/ ? path : "//ldml/#{path}"
55
+ end
56
+
57
+ def doc
58
+ @doc ||= Nokogiri::XML(File.read(path))
59
+ end
60
+
61
+ def path
62
+ @path ||= "#{Cldr::Data.dir}/main/#{locale.to_s.gsub('-', '_')}.xml"
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,124 @@
1
+ class Cldr
2
+ module Data
3
+ class Calendars
4
+ class Gregorian < Base
5
+ def initialize(locale)
6
+ super
7
+ update(
8
+ :months => contexts('month'),
9
+ :days => contexts('day'),
10
+ :eras => contexts('era'),
11
+ :quarters => contexts('quarter'),
12
+ :periods => periods,
13
+ :fields => fields,
14
+ :'formats.date' => formats('date'),
15
+ :'formats.time' => formats('time'),
16
+ :'formats.datetime' => formats('dateTime')
17
+ )
18
+ end
19
+
20
+ def calendar
21
+ @calendar ||= select('dates/calendars/calendar[@type="gregorian"]').first
22
+ end
23
+
24
+ def contexts(kind)
25
+ select(calendar, "#{kind}s/#{kind}Context").inject({}) do |result, node|
26
+ context = node.attribute('type').value.to_sym
27
+ result[context] = widths(node, kind, context)
28
+ result
29
+ end
30
+ end
31
+
32
+ def widths(node, kind, context)
33
+ select(node, "#{kind}Width").inject({}) do |result, node|
34
+ width = node.attribute('type').value.to_sym
35
+ result[width] = elements(node, kind, context, width)
36
+ result
37
+ end
38
+ end
39
+
40
+ def elements(node, kind, context, width)
41
+ aliased = select(node, 'alias').first
42
+ if aliased
43
+ xpath_to_key(aliased.attribute('path').value, kind, context, width)
44
+ else
45
+ select(node, kind).inject({}) do |result, node|
46
+ key = node.attribute('type').value
47
+ key = key =~ /^\d*$/ ? key.to_i : key.to_sym
48
+ result[key] = node.content
49
+ result
50
+ end
51
+ end
52
+ end
53
+
54
+ def xpath_to_key(xpath, kind, context, width)
55
+ kind = (xpath =~ %r(/([^\/]*)Width) && $1) || kind
56
+ context = (xpath =~ %r(Context\[@type='([^\/]*)'\]) && $1) || context
57
+ width = (xpath =~ %r(Width\[@type='([^\/]*)'\]) && $1) || width
58
+ :"calendars.gregorian.#{kind}s.#{context}.#{width}"
59
+ end
60
+
61
+ def xpath_width
62
+ end
63
+
64
+ def periods
65
+ am = select(calendar, "am").first
66
+ pm = select(calendar, "pm").first
67
+
68
+ result = {}
69
+ result[:am] = am.content if am
70
+ result[:pm] = pm.content if pm
71
+ result
72
+ end
73
+
74
+ def eras
75
+ base_path = calendar.path.gsub('/ldml/', '') + '/eras'
76
+ keys = select("#{base_path}/*").map { |node| node.name }
77
+
78
+ eras = keys.inject([]) do |result, name|
79
+ path = "#{base_path}/#{name}/*"
80
+ key = name.gsub('era', '').gsub(/s$/, '').downcase.to_sym
81
+ result << extract(path, :key => lambda { |node| node.attribute('type').value.to_i rescue 0 },
82
+ :value => lambda { |node| { key => node.content } })
83
+ end
84
+ eras.inject({}) { |result, data| result.deep_merge(data) }
85
+ end
86
+
87
+ def formats(type)
88
+ formats = select(calendar, "#{type}Formats/#{type}FormatLength").inject({}) do |result, node|
89
+ key = node.attribute('type').value.to_sym rescue :format
90
+ result[key] = pattern(node, type)
91
+ result
92
+ end
93
+ if default = default_format(type)
94
+ formats = default.merge(formats)
95
+ end
96
+ formats
97
+ end
98
+
99
+ def default_format(type)
100
+ if node = select(calendar, "#{type}Formats/default").first
101
+ key = node.attribute('choice').value.to_sym
102
+ { :default => :"calendars.gregorian.formats.#{type.downcase}.#{key}" }
103
+ end
104
+ end
105
+
106
+ def pattern(node, type)
107
+ select(node, "#{type}Format/pattern").inject({}) do |result, node|
108
+ result[:pattern] = node.content
109
+ result
110
+ end
111
+ end
112
+
113
+ def fields
114
+ select(calendar, "fields/field").inject({}) do |result, node|
115
+ key = node.attribute('type').value.to_sym
116
+ name = node.xpath('displayName').first
117
+ result[key] = name.content if name
118
+ result
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,12 @@
1
+ class Cldr
2
+ module Data
3
+ class Calendars < Base
4
+ autoload :Gregorian, 'cldr/data/calendars/gregorian'
5
+
6
+ def initialize(locale)
7
+ super
8
+ self['calendars.gregorian'] = Gregorian.new(locale)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,26 @@
1
+ class Cldr
2
+ module Data
3
+ class Currencies < Base
4
+ def initialize(locale)
5
+ super
6
+ self[:currencies] = currencies
7
+ end
8
+
9
+ def currencies
10
+ select('numbers/currencies/*').inject({}) do |result, node|
11
+ currency = self.currency(node)
12
+ result[node.attribute('type').value.to_sym] = currency unless currency.empty?
13
+ result
14
+ end
15
+ end
16
+
17
+ def currency(node)
18
+ select(node, 'displayName').inject({}) do |result, node|
19
+ count = node.attribute('count') ? node.attribute('count').value.to_sym : :one
20
+ result[count] = node.content unless draft?(node)
21
+ result
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,21 @@
1
+ class Cldr
2
+ module Data
3
+ class Delimiters < Base
4
+ def initialize(locale)
5
+ super
6
+ self[:'delimiters.quotes.default'] = quotes('quotation')
7
+ self[:'delimiters.quotes.alternate'] = quotes('alternateQuotation')
8
+ end
9
+
10
+ def quotes(type)
11
+ start = select("delimiters/#{type}Start").first
12
+ end_ = select("delimiters/#{type}End").first
13
+
14
+ result = {}
15
+ result[:start] = start.content if start
16
+ result[:end] = end_.content if end_
17
+ result
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ class Cldr
2
+ module Data
3
+ class Languages < Base
4
+ def initialize(locale)
5
+ super
6
+ self[:languages] = languages
7
+ end
8
+
9
+ def languages
10
+ @languages ||= select('localeDisplayNames/languages/language').inject({}) do |result, node|
11
+ result[node.attribute('type').value.gsub('_', '-').to_sym] = node.content unless draft?(node)
12
+ result
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,60 @@
1
+ class Cldr
2
+ module Data
3
+ class Numbers < Base
4
+ def initialize(locale)
5
+ super
6
+ self[:'numbers.symbols'] = symbols
7
+ self[:'numbers.formats'] = {
8
+ :decimal => {
9
+ :patterns => {
10
+ :default => format('decimal')
11
+ }
12
+ },
13
+ :scientific => {
14
+ :patterns => {
15
+ :default => format('scientific')
16
+ }
17
+ },
18
+ :percent => {
19
+ :patterns => {
20
+ :default => format('percent')
21
+ }
22
+ },
23
+ :currency => {
24
+ :patterns => {
25
+ :default => format('currency')
26
+ }
27
+ },
28
+ }
29
+ self[:'numbers.formats.currency.unit'] = unit
30
+ end
31
+
32
+ def currency
33
+ currency = format('currency')
34
+ currency.update(:unit => unit) unless unit.empty?
35
+ currency
36
+ end
37
+
38
+ def symbols
39
+ select('numbers/symbols/*').inject({}) do |result, node|
40
+ result[name(node).to_sym] = node.content unless draft?(node)
41
+ result
42
+ end
43
+ end
44
+
45
+ def format(type)
46
+ select("numbers/#{type}Formats/#{type}FormatLength/#{type}Format/pattern").inject({}) do |result, node|
47
+ node.content unless draft?(node)
48
+ end
49
+ end
50
+
51
+ def unit
52
+ @unit ||= select("numbers/currencyFormats/unitPattern").inject({}) do |result, node|
53
+ count = node.attribute('count').value rescue 'one'
54
+ result[count] = node.content
55
+ result
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,50 @@
1
+ # http://unicode.org/draft/reports/tr35/tr35.html#Language_Plural_Rules
2
+ #
3
+ # condition = and_condition ('or' and_condition)*
4
+ # and_condition = relation ('and' relation)*
5
+ # relation = is_relation | in_relation | within_relation | 'n' <EOL>
6
+ # is_relation = expr 'is' ('not')? value
7
+ # in_relation = expr ('not')? 'in' range
8
+ # within_relation = expr ('not')? 'within' range
9
+ # expr = 'n' ('mod' value)?
10
+ # value = digit+
11
+ # digit = 0|1|2|3|4|5|6|7|8|9
12
+ # range = value'..'value
13
+
14
+ grammar CldrPluralGrammar
15
+ rule or_condition
16
+ and_condition (" or " and_condition)?
17
+ end
18
+
19
+ rule and_condition
20
+ relation (" and " relation)?
21
+ end
22
+
23
+ rule relation
24
+ is_relation / in_relation / within_relation / "n"
25
+ end
26
+
27
+ rule is_relation
28
+ expr " is " "not "? value
29
+ end
30
+
31
+ rule in_relation
32
+ expr " not"? " in " range
33
+ end
34
+
35
+ rule within_relation
36
+ expr " not"? " within " range
37
+ end
38
+
39
+ rule expr
40
+ "n" (" mod " value)?
41
+ end
42
+
43
+ rule range
44
+ value ".." value
45
+ end
46
+
47
+ rule value
48
+ [0-9]*
49
+ end
50
+ end