twitter_cldr 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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