twitter_cldr 1.0.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 (180) hide show
  1. data/LICENSE +177 -0
  2. data/NOTICE +26 -0
  3. data/README.md +83 -0
  4. data/Rakefile +36 -0
  5. data/lib/ext/calendars/date.rb +20 -0
  6. data/lib/ext/calendars/datetime.rb +36 -0
  7. data/lib/ext/calendars/time.rb +20 -0
  8. data/lib/ext/localized_object.rb +15 -0
  9. data/lib/ext/numbers/bignum.rb +3 -0
  10. data/lib/ext/numbers/fixnum.rb +3 -0
  11. data/lib/ext/numbers/float.rb +3 -0
  12. data/lib/ext/numbers/localized_number.rb +53 -0
  13. data/lib/ext/strings/symbol.rb +17 -0
  14. data/lib/formatters/base.rb +36 -0
  15. data/lib/formatters/calendars/date_formatter.rb +9 -0
  16. data/lib/formatters/calendars/datetime_formatter.rb +217 -0
  17. data/lib/formatters/calendars/time_formatter.rb +9 -0
  18. data/lib/formatters/numbers/currency_formatter.rb +25 -0
  19. data/lib/formatters/numbers/decimal_formatter.rb +22 -0
  20. data/lib/formatters/numbers/helpers/base.rb +18 -0
  21. data/lib/formatters/numbers/helpers/fraction.rb +29 -0
  22. data/lib/formatters/numbers/helpers/integer.rb +46 -0
  23. data/lib/formatters/numbers/number_formatter.rb +48 -0
  24. data/lib/formatters/numbers/percent_formatter.rb +18 -0
  25. data/lib/formatters/plurals/rules.rb +34 -0
  26. data/lib/shared/currencies.rb +33 -0
  27. data/lib/shared/languages.rb +48 -0
  28. data/lib/shared/resources.rb +45 -0
  29. data/lib/shared/timezones.rb +1 -0
  30. data/lib/tokenizers/base.rb +112 -0
  31. data/lib/tokenizers/calendars/date_tokenizer.rb +24 -0
  32. data/lib/tokenizers/calendars/datetime_tokenizer.rb +46 -0
  33. data/lib/tokenizers/calendars/time_tokenizer.rb +24 -0
  34. data/lib/tokenizers/key_path.rb +30 -0
  35. data/lib/tokenizers/numbers/number_tokenizer.rb +50 -0
  36. data/lib/tokenizers/token.rb +17 -0
  37. data/lib/twitter_cldr.rb +104 -0
  38. data/lib/version.rb +3 -0
  39. data/resources/ar/calendars.yml +145 -0
  40. data/resources/ar/languages.yml +498 -0
  41. data/resources/ar/numbers.yml +35 -0
  42. data/resources/ar/plurals.yml +1 -0
  43. data/resources/da/calendars.yml +157 -0
  44. data/resources/da/languages.yml +508 -0
  45. data/resources/da/numbers.yml +31 -0
  46. data/resources/da/plurals.yml +1 -0
  47. data/resources/de/calendars.yml +152 -0
  48. data/resources/de/languages.yml +508 -0
  49. data/resources/de/numbers.yml +31 -0
  50. data/resources/de/plurals.yml +1 -0
  51. data/resources/en/calendars.yml +145 -0
  52. data/resources/en/languages.yml +510 -0
  53. data/resources/en/numbers.yml +31 -0
  54. data/resources/en/plurals.yml +1 -0
  55. data/resources/es/calendars.yml +145 -0
  56. data/resources/es/languages.yml +508 -0
  57. data/resources/es/numbers.yml +30 -0
  58. data/resources/es/plurals.yml +1 -0
  59. data/resources/fa/calendars.yml +150 -0
  60. data/resources/fa/languages.yml +484 -0
  61. data/resources/fa/numbers.yml +30 -0
  62. data/resources/fa/plurals.yml +1 -0
  63. data/resources/fi/calendars.yml +176 -0
  64. data/resources/fi/languages.yml +508 -0
  65. data/resources/fi/numbers.yml +31 -0
  66. data/resources/fi/plurals.yml +1 -0
  67. data/resources/fil/calendars.yml +159 -0
  68. data/resources/fil/languages.yml +115 -0
  69. data/resources/fil/numbers.yml +31 -0
  70. data/resources/fil/plurals.yml +1 -0
  71. data/resources/fr/calendars.yml +149 -0
  72. data/resources/fr/languages.yml +508 -0
  73. data/resources/fr/numbers.yml +31 -0
  74. data/resources/fr/plurals.yml +1 -0
  75. data/resources/he/calendars.yml +145 -0
  76. data/resources/he/languages.yml +266 -0
  77. data/resources/he/numbers.yml +31 -0
  78. data/resources/he/plurals.yml +1 -0
  79. data/resources/hi/calendars.yml +144 -0
  80. data/resources/hi/languages.yml +505 -0
  81. data/resources/hi/numbers.yml +31 -0
  82. data/resources/hi/plurals.yml +1 -0
  83. data/resources/hu/calendars.yml +145 -0
  84. data/resources/hu/languages.yml +508 -0
  85. data/resources/hu/numbers.yml +30 -0
  86. data/resources/hu/plurals.yml +1 -0
  87. data/resources/id/calendars.yml +145 -0
  88. data/resources/id/languages.yml +506 -0
  89. data/resources/id/numbers.yml +30 -0
  90. data/resources/id/plurals.yml +1 -0
  91. data/resources/it/calendars.yml +164 -0
  92. data/resources/it/languages.yml +503 -0
  93. data/resources/it/numbers.yml +30 -0
  94. data/resources/it/plurals.yml +1 -0
  95. data/resources/ja/calendars.yml +157 -0
  96. data/resources/ja/languages.yml +502 -0
  97. data/resources/ja/numbers.yml +30 -0
  98. data/resources/ja/plurals.yml +1 -0
  99. data/resources/ko/calendars.yml +133 -0
  100. data/resources/ko/languages.yml +505 -0
  101. data/resources/ko/numbers.yml +30 -0
  102. data/resources/ko/plurals.yml +1 -0
  103. data/resources/ms/calendars.yml +145 -0
  104. data/resources/ms/languages.yml +54 -0
  105. data/resources/ms/numbers.yml +30 -0
  106. data/resources/ms/plurals.yml +1 -0
  107. data/resources/nl/calendars.yml +145 -0
  108. data/resources/nl/languages.yml +508 -0
  109. data/resources/nl/numbers.yml +31 -0
  110. data/resources/nl/plurals.yml +1 -0
  111. data/resources/no/calendars.yml +122 -0
  112. data/resources/no/languages.yml +508 -0
  113. data/resources/no/numbers.yml +30 -0
  114. data/resources/no/plurals.yml +1 -0
  115. data/resources/pl/calendars.yml +161 -0
  116. data/resources/pl/languages.yml +504 -0
  117. data/resources/pl/numbers.yml +31 -0
  118. data/resources/pl/plurals.yml +1 -0
  119. data/resources/pt/calendars.yml +145 -0
  120. data/resources/pt/languages.yml +508 -0
  121. data/resources/pt/numbers.yml +31 -0
  122. data/resources/pt/plurals.yml +1 -0
  123. data/resources/ru/calendars.yml +176 -0
  124. data/resources/ru/languages.yml +508 -0
  125. data/resources/ru/numbers.yml +30 -0
  126. data/resources/ru/plurals.yml +1 -0
  127. data/resources/shared/currencies.yml +451 -0
  128. data/resources/sv/calendars.yml +145 -0
  129. data/resources/sv/languages.yml +508 -0
  130. data/resources/sv/numbers.yml +31 -0
  131. data/resources/sv/plurals.yml +1 -0
  132. data/resources/th/calendars.yml +145 -0
  133. data/resources/th/languages.yml +507 -0
  134. data/resources/th/numbers.yml +30 -0
  135. data/resources/th/plurals.yml +1 -0
  136. data/resources/tr/calendars.yml +145 -0
  137. data/resources/tr/languages.yml +508 -0
  138. data/resources/tr/numbers.yml +30 -0
  139. data/resources/tr/plurals.yml +1 -0
  140. data/resources/ur/calendars.yml +133 -0
  141. data/resources/ur/languages.yml +81 -0
  142. data/resources/ur/numbers.yml +31 -0
  143. data/resources/ur/plurals.yml +1 -0
  144. data/resources/zh/calendars.yml +169 -0
  145. data/resources/zh/languages.yml +506 -0
  146. data/resources/zh/numbers.yml +30 -0
  147. data/resources/zh/plurals.yml +1 -0
  148. data/resources/zh-Hant/calendars.yml +141 -0
  149. data/resources/zh-Hant/languages.yml +409 -0
  150. data/resources/zh-Hant/numbers.yml +30 -0
  151. data/spec/ext/calendars/date_spec.rb +45 -0
  152. data/spec/ext/calendars/datetime_spec.rb +43 -0
  153. data/spec/ext/calendars/time_spec.rb +45 -0
  154. data/spec/ext/numbers/bignum_spec.rb +19 -0
  155. data/spec/ext/numbers/fixnum_spec.rb +19 -0
  156. data/spec/ext/numbers/float_spec.rb +19 -0
  157. data/spec/ext/numbers/localized_number_spec.rb +53 -0
  158. data/spec/ext/strings/symbol_spec.rb +23 -0
  159. data/spec/formatters/base_spec.rb +12 -0
  160. data/spec/formatters/calendars/datetime_formatter_spec.rb +324 -0
  161. data/spec/formatters/numbers/currency_formatter_spec.rb +27 -0
  162. data/spec/formatters/numbers/decimal_formatter_spec.rb +30 -0
  163. data/spec/formatters/numbers/helpers/fraction_spec.rb +22 -0
  164. data/spec/formatters/numbers/helpers/integer_spec.rb +99 -0
  165. data/spec/formatters/numbers/number_formatter_spec.rb +79 -0
  166. data/spec/formatters/numbers/percent_formatter_spec.rb +12 -0
  167. data/spec/formatters/plurals/rules_spec.rb +73 -0
  168. data/spec/shared/currencies_spec.rb +55 -0
  169. data/spec/shared/languages_spec.rb +82 -0
  170. data/spec/shared/resources_spec.rb +44 -0
  171. data/spec/spec_helper.rb +31 -0
  172. data/spec/tokenizers/base_spec.rb +134 -0
  173. data/spec/tokenizers/calendars/date_tokenizer_spec.rb +36 -0
  174. data/spec/tokenizers/calendars/datetime_tokenizer_spec.rb +52 -0
  175. data/spec/tokenizers/calendars/time_tokenizer_spec.rb +34 -0
  176. data/spec/tokenizers/key_path_spec.rb +44 -0
  177. data/spec/tokenizers/numbers/number_tokenizer_spec.rb +60 -0
  178. data/spec/tokenizers/token_spec.rb +18 -0
  179. data/spec/twitter_cldr_spec.rb +53 -0
  180. metadata +293 -0
@@ -0,0 +1,217 @@
1
+ # This class has been adapted from Sven Fuch's ruby-cldr gem
2
+ # See LICENSE for the accompanying license for his contributions
3
+
4
+ module TwitterCldr
5
+ module Formatters
6
+ class DateTimeFormatter < Base
7
+ WEEKDAY_KEYS = [:sun, :mon, :tue, :wed, :thu, :fri, :sat]
8
+ METHODS = { # ignoring u, l, g, j, A
9
+ 'G' => :era,
10
+ 'y' => :year,
11
+ 'Y' => :year_of_week_of_year,
12
+ 'Q' => :quarter,
13
+ 'q' => :quarter_stand_alone,
14
+ 'M' => :month,
15
+ 'L' => :month_stand_alone,
16
+ 'w' => :week_of_year,
17
+ 'W' => :week_of_month,
18
+ 'd' => :day,
19
+ 'D' => :day_of_month,
20
+ 'F' => :day_of_week_in_month,
21
+ 'E' => :weekday,
22
+ 'e' => :weekday_local,
23
+ 'c' => :weekday_local_stand_alone,
24
+ 'a' => :period,
25
+ 'h' => :hour,
26
+ 'H' => :hour,
27
+ 'K' => :hour,
28
+ 'k' => :hour,
29
+ 'm' => :minute,
30
+ 's' => :second,
31
+ 'S' => :second_fraction,
32
+ 'z' => :timezone,
33
+ 'Z' => :timezone,
34
+ 'v' => :timezone_generic_non_location,
35
+ 'V' => :timezone_metazone
36
+ }
37
+
38
+ def initialize(options = {})
39
+ @tokenizer = TwitterCldr::Tokenizers::DateTimeTokenizer.new(:locale => extract_locale(options))
40
+ end
41
+
42
+ def result_for_token(token, index, date)
43
+ self.send(METHODS[token.value[0].chr], date, token.value, token.value.size)
44
+ end
45
+
46
+ protected
47
+
48
+ def era(date, pattern, length)
49
+ raise 'not implemented'
50
+ end
51
+
52
+ def year(date, pattern, length)
53
+ year = date.year.to_s
54
+ year = year.length == 1 ? year : year[-2, 2] if length == 2
55
+ year = year.rjust(length, '0') if length > 1
56
+ year
57
+ end
58
+
59
+ def year_of_week_of_year(date, pattern, length)
60
+ raise 'not implemented'
61
+ end
62
+
63
+ def day_of_week_in_month(date, pattern, length) # e.g. 2nd Wed in July
64
+ raise 'not implemented'
65
+ end
66
+
67
+ def quarter(date, pattern, length)
68
+ quarter = (date.month.to_i - 1) / 3 + 1
69
+ case length
70
+ when 1
71
+ quarter.to_s
72
+ when 2
73
+ quarter.to_s.rjust(length, '0')
74
+ when 3
75
+ @tokenizer.calendar[:quarters][:format][:abbreviated][quarter]
76
+ when 4
77
+ @tokenizer.calendar[:quarters][:format][:wide][quarter]
78
+ end
79
+ end
80
+
81
+ def quarter_stand_alone(date, pattern, length)
82
+ quarter = (date.month.to_i - 1) / 3 + 1
83
+ case length
84
+ when 1
85
+ quarter.to_s
86
+ when 2
87
+ quarter.to_s.rjust(length, '0')
88
+ when 3
89
+ raise 'not yet implemented (requires cldr\'s "multiple inheritance")'
90
+ # @tokenizer.calendar[:quarters][:'stand-alone'][:abbreviated][key]
91
+ when 4
92
+ raise 'not yet implemented (requires cldr\'s "multiple inheritance")'
93
+ # @tokenizer.calendar[:quarters][:'stand-alone'][:wide][key]
94
+ when 5
95
+ @tokenizer.calendar[:quarters][:'stand-alone'][:narrow][quarter]
96
+ end
97
+ end
98
+
99
+ def month(date, pattern, length)
100
+ case length
101
+ when 1
102
+ date.month.to_s
103
+ when 2
104
+ date.month.to_s.rjust(length, '0')
105
+ when 3
106
+ @tokenizer.calendar[:months][:format][:abbreviated][date.month]
107
+ when 4
108
+ @tokenizer.calendar[:months][:format][:wide][date.month]
109
+ when 5
110
+ raise 'not yet implemented (requires cldr\'s "multiple inheritance")'
111
+ @tokenizer.calendar[:months][:format][:narrow][date.month]
112
+ else
113
+ # raise unknown date format
114
+ end
115
+ end
116
+
117
+ def month_stand_alone(date, pattern, length)
118
+ case length
119
+ when 1
120
+ date.month.to_s
121
+ when 2
122
+ date.month.to_s.rjust(length, '0')
123
+ when 3
124
+ raise 'not yet implemented (requires cldr\'s "multiple inheritance")'
125
+ @tokenizer.calendar[:months][:'stand-alone'][:abbreviated][date.month]
126
+ when 4
127
+ raise 'not yet implemented (requires cldr\'s "multiple inheritance")'
128
+ @tokenizer.calendar[:months][:'stand-alone'][:wide][date.month]
129
+ when 5
130
+ @tokenizer.calendar[:months][:'stand-alone'][:narrow][date.month]
131
+ else
132
+ # raise unknown date format
133
+ end
134
+ end
135
+
136
+ def day(date, pattern, length)
137
+ case length
138
+ when 1
139
+ date.day.to_s
140
+ when 2
141
+ date.day.to_s.rjust(length, '0')
142
+ end
143
+ end
144
+
145
+ def weekday(date, pattern, length)
146
+ key = WEEKDAY_KEYS[date.wday]
147
+ case length
148
+ when 1..3
149
+ @tokenizer.calendar[:days][:format][:abbreviated][key]
150
+ when 4
151
+ @tokenizer.calendar[:days][:format][:wide][key]
152
+ when 5
153
+ @tokenizer.calendar[:days][:'stand-alone'][:narrow][key]
154
+ end
155
+ end
156
+
157
+ def weekday_local(date, pattern, length)
158
+ # "Like E except adds a numeric value depending on the local starting day of the week"
159
+ raise 'not implemented (need to defer a country to lookup the local first day of week from weekdata)'
160
+ end
161
+
162
+ def weekday_local_stand_alone(date, pattern, length)
163
+ raise 'not implemented (need to defer a country to lookup the local first day of week from weekdata)'
164
+ end
165
+
166
+ def period(time, pattern, length)
167
+ @tokenizer.calendar[:periods][time.strftime('%p').downcase.to_sym]
168
+ end
169
+
170
+ def hour(time, pattern, length)
171
+ hour = time.hour
172
+ hour = case pattern[0, 1]
173
+ when 'h' # [1-12]
174
+ hour > 12 ? (hour - 12) : (hour == 0 ? 12 : hour)
175
+ when 'H' # [0-23]
176
+ hour
177
+ when 'K' # [0-11]
178
+ hour > 11 ? hour - 12 : hour
179
+ when 'k' # [1-24]
180
+ hour == 0 ? 24 : hour
181
+ end
182
+ length == 1 ? hour.to_s : hour.to_s.rjust(length, '0')
183
+ end
184
+
185
+ def minute(time, pattern, length)
186
+ length == 1 ? time.min.to_s : time.min.to_s.rjust(length, '0')
187
+ end
188
+
189
+ def second(time, pattern, length)
190
+ length == 1 ? time.sec.to_s : time.sec.to_s.rjust(length, '0')
191
+ end
192
+
193
+ def second_fraction(time, pattern, length)
194
+ raise 'can not use the S format with more than 6 digits' if length > 6
195
+ (time.usec.to_f / 10 ** (6 - length)).round.to_s.rjust(length, '0')
196
+ end
197
+
198
+ def timezone(time, pattern, length)
199
+ case length
200
+ when 1..3
201
+ time.zone
202
+ else
203
+ "UTC #{time.strftime("%z")}"
204
+ end
205
+ end
206
+
207
+ def timezone_generic_non_location(time, pattern, length)
208
+ raise 'not yet implemented (requires timezone translation data")'
209
+ end
210
+
211
+ def round_to(number, precision)
212
+ factor = 10 ** precision
213
+ (number * factor).round.to_f / factor
214
+ end
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,9 @@
1
+ module TwitterCldr
2
+ module Formatters
3
+ class TimeFormatter < DateTimeFormatter
4
+ def initialize(options = {})
5
+ @tokenizer = TwitterCldr::Tokenizers::TimeTokenizer.new(:locale => extract_locale(options))
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,25 @@
1
+ module TwitterCldr
2
+ module Formatters
3
+ class CurrencyFormatter < NumberFormatter
4
+ DEFAULT_FORMAT_OPTIONS = { :precision => 2 }
5
+ DEFAULT_CURRENCY_SYMBOL = "$"
6
+
7
+ def initialize(options = {})
8
+ @tokenizer = TwitterCldr::Tokenizers::NumberTokenizer.new(:locale => self.extract_locale(options), :type => :currency)
9
+ super
10
+ end
11
+
12
+ def format(number, options = {})
13
+ if options[:currency]
14
+ currency ||= TwitterCldr::Shared::Currencies.for_code(options[:currency])
15
+ currency ||= TwitterCldr::Shared::Currencies.for_country(options[:currency])
16
+ currency ||= { :symbol => options[:currency] }
17
+ else
18
+ currency = { :symbol => DEFAULT_CURRENCY_SYMBOL }
19
+ end
20
+
21
+ super(number, DEFAULT_FORMAT_OPTIONS.merge(options)).gsub('¤', currency[:symbol])
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,22 @@
1
+ module TwitterCldr
2
+ module Formatters
3
+ class DecimalFormatter < NumberFormatter
4
+ def initialize(options = {})
5
+ @tokenizer = TwitterCldr::Tokenizers::NumberTokenizer.new(:locale => self.extract_locale(options), :type => :decimal)
6
+ super
7
+ end
8
+
9
+ def format(number, options = {})
10
+ super(Float(number), options)
11
+ rescue TypeError, ArgumentError
12
+ number
13
+ end
14
+
15
+ protected
16
+
17
+ def get_tokens(obj, options = {})
18
+ obj.abs == obj ? @tokenizer.tokens(:sign => :positive) : @tokenizer.tokens(:sign => :negative)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,18 @@
1
+ module TwitterCldr
2
+ module Formatters
3
+ module Numbers
4
+ class Base
5
+ def interpolate(string, value, orientation = :right)
6
+ value = value.to_s
7
+ length = value.length
8
+ start, pad = orientation == :left ? [0, :rjust] : [-length, :ljust]
9
+
10
+ string = string.dup
11
+ string = string.ljust(length, '#') if string.length < length
12
+ string[start, length] = value
13
+ string.gsub('#', '')
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,29 @@
1
+ module TwitterCldr
2
+ module Formatters
3
+ module Numbers
4
+ class Fraction < Base
5
+ attr_reader :format, :decimal, :precision
6
+
7
+ def initialize(token, symbols = {})
8
+ @format = token ? token.value.split('.').pop : ''
9
+ @decimal = symbols[:decimal] || '.'
10
+ @precision = @format.length
11
+ end
12
+
13
+ def apply(fraction, options = {})
14
+ precision = options[:precision] || self.precision
15
+ if precision > 0
16
+ decimal + interpolate(format(options), fraction, :left)
17
+ else
18
+ ''
19
+ end
20
+ end
21
+
22
+ def format(options)
23
+ precision = options[:precision] || self.precision
24
+ precision ? '0' * precision : @format
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,46 @@
1
+ module TwitterCldr
2
+ module Formatters
3
+ module Numbers
4
+ class Integer < Base
5
+ attr_reader :format, :separator, :groups
6
+
7
+ def initialize(token, symbols = {})
8
+ format = token.value.split('.')[0]
9
+ @format = prepare_format(format, symbols)
10
+ @groups = parse_groups(format)
11
+ @separator = symbols[:group] || ','
12
+ end
13
+
14
+ def apply(number, options = {})
15
+ format_groups(interpolate(format, number.to_i))
16
+ end
17
+
18
+ def format_groups(string)
19
+ return string if groups.empty?
20
+ tokens = []
21
+ tokens << chop_group(string, groups.first)
22
+ tokens << chop_group(string, groups.last) while string.length > groups.last
23
+ tokens << string
24
+ tokens.compact.reverse.join(separator)
25
+ end
26
+
27
+ def parse_groups(format)
28
+ return [] unless index = format.rindex(',')
29
+ rest = format[0, index]
30
+ widths = [format.length - index - 1]
31
+ widths << rest.length - rest.rindex(',') - 1 if rest.rindex(',')
32
+ widths.compact.uniq
33
+ end
34
+
35
+ def chop_group(string, size)
36
+ string.slice!(-size, size) if string.length > size
37
+ end
38
+
39
+ def prepare_format(format, symbols)
40
+ signs = symbols.values_at(:plus_sign, :minus_sign)
41
+ format.tr(',', '').tr('+-', signs.join)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,48 @@
1
+ module TwitterCldr
2
+ module Formatters
3
+ class NumberFormatter < Base
4
+ attr_reader :symbols
5
+
6
+ DEFAULT_SYMBOLS = { :group => ',', :decimal => '.', :plus_sign => '+', :minus_sign => '-' }
7
+
8
+ def initialize(options = {})
9
+ @symbols = DEFAULT_SYMBOLS.merge(tokenizer.symbols)
10
+ end
11
+
12
+ def format(number, options = {})
13
+ opts = { :precision => precision_from(number) }.merge(options)
14
+ prefix, suffix, integer_format, fraction_format = *partition_tokens(self.get_tokens(number, opts))
15
+ int, fraction = parse_number(number, opts)
16
+
17
+ result = integer_format.apply(int, opts)
18
+ result << fraction_format.apply(fraction, opts) if fraction
19
+ "#{prefix.to_s}#{result}#{suffix.to_s}"
20
+ end
21
+
22
+ protected
23
+
24
+ def partition_tokens(tokens)
25
+ [tokens[0] || "",
26
+ tokens[2] || "",
27
+ Numbers::Integer.new(tokens[1], @tokenizer.symbols),
28
+ Numbers::Fraction.new(tokens[1], @tokenizer.symbols)]
29
+ end
30
+
31
+ def parse_number(number, options = {})
32
+ precision = options[:precision] || self.precision_from(number)
33
+ number = round_to(number, precision)
34
+ number.abs.to_s.split(".")
35
+ end
36
+
37
+ def round_to(number, precision)
38
+ factor = 10 ** precision
39
+ (number * factor).round.to_f / factor
40
+ end
41
+
42
+ def precision_from(num)
43
+ parts = num.to_s.split(".")
44
+ parts.size == 2 ? parts[1].size : 0
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,18 @@
1
+ module TwitterCldr
2
+ module Formatters
3
+ class PercentFormatter < NumberFormatter
4
+ DEFAULT_PERCENT_SIGN = "%"
5
+ DEFAULT_FORMAT_OPTIONS = { :precision => 0 }
6
+
7
+ def initialize(options = {})
8
+ @tokenizer = TwitterCldr::Tokenizers::NumberTokenizer.new(:locale => self.extract_locale(options), :type => :percent)
9
+ super
10
+ end
11
+
12
+ def format(number, options = {})
13
+ opts = DEFAULT_FORMAT_OPTIONS.merge(options)
14
+ super(number, opts).gsub('¤', @tokenizer.symbols[:percent_sign] || DEFAULT_PERCENT_SIGN)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,34 @@
1
+ module TwitterCldr
2
+ module Formatters
3
+ module Plurals
4
+ class Rules
5
+ class << self
6
+ def all
7
+ all_for(TwitterCldr::get_locale)
8
+ end
9
+
10
+ def all_for(locale)
11
+ locale = TwitterCldr.convert_locale(locale.to_sym)
12
+ get_resource(locale)[locale][:i18n][:plural][:keys]
13
+ rescue => e
14
+ []
15
+ end
16
+
17
+ def rule_for(number, locale = TwitterCldr::get_locale)
18
+ locale = TwitterCldr.convert_locale(locale.to_sym)
19
+ get_resource(locale)[locale][:i18n][:plural][:rule].call(number)
20
+ rescue => e
21
+ :other
22
+ end
23
+
24
+ protected
25
+
26
+ def get_resource(locale)
27
+ locale = TwitterCldr.convert_locale(locale)
28
+ eval(TwitterCldr.resources.resource_for(locale, "plurals")[locale])
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,33 @@
1
+ module TwitterCldr
2
+ module Shared
3
+ class Currencies
4
+ @@resource = TwitterCldr.resources.resource_for("shared", "currencies")[:shared][:currencies]
5
+
6
+ class << self
7
+ def countries
8
+ @@resource.map { |country_name, data| country_name.to_s }
9
+ end
10
+
11
+ def currency_codes
12
+ @@resource.map { |country_name, data| data[:code] }
13
+ end
14
+
15
+ def for_country(country_name)
16
+ @@resource[country_name.to_sym]
17
+ end
18
+
19
+ def for_code(currency_code)
20
+ final = nil
21
+ @@resource.each_pair do |country_name, data|
22
+ if data[:code] == currency_code
23
+ final = data.merge({ :country => country_name.to_s })
24
+ final.delete(:code)
25
+ break
26
+ end
27
+ end
28
+ final
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,48 @@
1
+ module TwitterCldr
2
+ module Shared
3
+ class Languages
4
+ class << self
5
+ def all
6
+ all_for(TwitterCldr::get_locale)
7
+ end
8
+
9
+ def all_for(code)
10
+ get_resource(TwitterCldr.convert_locale(code.to_sym))[:languages]
11
+ rescue => e
12
+ {}
13
+ end
14
+
15
+ def from_code(code)
16
+ from_code_for_locale(code, TwitterCldr::get_locale)
17
+ end
18
+
19
+ def from_code_for_locale(code, locale = TwitterCldr::get_locale)
20
+ get_resource(TwitterCldr.convert_locale(locale.to_sym))[:languages][TwitterCldr.convert_locale(code.to_sym)]
21
+ rescue => e
22
+ nil
23
+ end
24
+
25
+ def translate_language(language, source_locale = :en, dest_locale = TwitterCldr::get_locale)
26
+ source_locale = TwitterCldr.convert_locale(source_locale.to_sym)
27
+ lang_code = get_resource(source_locale)[:languages].select { |key, val| val.downcase == language.downcase }.flatten.first
28
+
29
+ if lang_code
30
+ dest_locale = TwitterCldr.convert_locale(dest_locale.to_sym)
31
+ get_resource(dest_locale)[:languages][lang_code.to_sym]
32
+ else
33
+ nil
34
+ end
35
+ rescue => e
36
+ nil
37
+ end
38
+
39
+ protected
40
+
41
+ def get_resource(locale)
42
+ locale = TwitterCldr.convert_locale(locale)
43
+ TwitterCldr.resources.resource_for(locale, "languages")[locale]
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,45 @@
1
+ module TwitterCldr
2
+ module Shared
3
+ class Resources
4
+ def initialize
5
+ @resources_by_locale = {}
6
+ end
7
+
8
+ def resource_for(locale, resource)
9
+ locale = locale.to_sym
10
+ unless @resources_by_locale.include?(locale)
11
+ @resources_by_locale[locale] = {}
12
+ end
13
+
14
+ unless @resources_by_locale[locale].include?(resource)
15
+ @resources_by_locale[locale][resource] = data_for(locale, resource)
16
+ end
17
+
18
+ @resources_by_locale[locale][resource]
19
+ end
20
+
21
+ protected
22
+
23
+ def data_for(locale, resource)
24
+ deep_symbolize_keys(YAML.load(File.read(TwitterCldr.get_resource_file(locale, resource))))
25
+ end
26
+
27
+ # adapted from: http://snippets.dzone.com/posts/show/11121 (first comment)
28
+ def deep_symbolize_keys(arg)
29
+ case arg
30
+ when Array then
31
+ arg.map { |elem| deep_symbolize_keys(elem) }
32
+ when Hash then
33
+ Hash[
34
+ arg.map do |key, value|
35
+ k = key.is_a?(String) ? key.to_sym : key
36
+ v = deep_symbolize_keys(value)
37
+ [k, v]
38
+ end]
39
+ else
40
+ arg
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1 @@
1
+ # not yet implemented