twitter_cldr_js 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 (73) hide show
  1. data/Gemfile +12 -0
  2. data/History.txt +3 -0
  3. data/LICENSE +177 -0
  4. data/NOTICE +120 -0
  5. data/README.md +161 -0
  6. data/Rakefile +66 -0
  7. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_af.js +887 -0
  8. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_ar.js +887 -0
  9. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_ca.js +887 -0
  10. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_cs.js +887 -0
  11. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_da.js +887 -0
  12. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_de.js +887 -0
  13. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_el.js +887 -0
  14. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_en.js +887 -0
  15. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_es.js +887 -0
  16. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_eu.js +887 -0
  17. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_fa.js +887 -0
  18. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_fi.js +887 -0
  19. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_fil.js +887 -0
  20. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_fr.js +887 -0
  21. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_he.js +887 -0
  22. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_hi.js +887 -0
  23. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_hu.js +887 -0
  24. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_id.js +887 -0
  25. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_it.js +887 -0
  26. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_ja.js +887 -0
  27. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_ko.js +887 -0
  28. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_msa.js +887 -0
  29. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_nl.js +887 -0
  30. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_no.js +887 -0
  31. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_pl.js +887 -0
  32. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_pt.js +887 -0
  33. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_ru.js +887 -0
  34. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_sv.js +887 -0
  35. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_th.js +887 -0
  36. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_tr.js +887 -0
  37. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_uk.js +887 -0
  38. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_ur.js +887 -0
  39. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_zh-cn.js +887 -0
  40. data/lib/assets/javascripts/twitter_cldr/twitter_cldr_zh-tw.js +887 -0
  41. data/lib/twitter_cldr/js/compiler.rb +49 -0
  42. data/lib/twitter_cldr/js/mustache/bundle.coffee +15 -0
  43. data/lib/twitter_cldr/js/mustache/calendars/datetime.coffee +240 -0
  44. data/lib/twitter_cldr/js/mustache/calendars/timespan.coffee +52 -0
  45. data/lib/twitter_cldr/js/mustache/numbers/numbers.coffee +179 -0
  46. data/lib/twitter_cldr/js/mustache/plurals/rules.coffee +14 -0
  47. data/lib/twitter_cldr/js/mustache/shared/currencies.coffee +27 -0
  48. data/lib/twitter_cldr/js/renderers/base.rb +18 -0
  49. data/lib/twitter_cldr/js/renderers/bundle.rb +18 -0
  50. data/lib/twitter_cldr/js/renderers/calendars/datetime_renderer.rb +34 -0
  51. data/lib/twitter_cldr/js/renderers/calendars/timespan_renderer.rb +39 -0
  52. data/lib/twitter_cldr/js/renderers/numbers/numbers_renderer.rb +31 -0
  53. data/lib/twitter_cldr/js/renderers/plurals/rules/plural_rules_compiler.rb +93 -0
  54. data/lib/twitter_cldr/js/renderers/plurals/rules/plural_rules_renderer.rb +26 -0
  55. data/lib/twitter_cldr/js/renderers/shared/currencies_renderer.rb +23 -0
  56. data/lib/twitter_cldr/js/renderers.rb +31 -0
  57. data/lib/twitter_cldr/js/tasks/tasks.rake +14 -0
  58. data/lib/twitter_cldr/js/tasks/tasks.rb +88 -0
  59. data/lib/twitter_cldr/js/version.rb +10 -0
  60. data/lib/twitter_cldr/js.rb +31 -0
  61. data/spec/js/calendars/datetime.spec.js +418 -0
  62. data/spec/js/calendars/timespan.spec.js +91 -0
  63. data/spec/js/numbers/currency.spec.js +34 -0
  64. data/spec/js/numbers/decimal.spec.js +24 -0
  65. data/spec/js/numbers/helpers/fraction.spec.js +23 -0
  66. data/spec/js/numbers/helpers/integer.spec.js +100 -0
  67. data/spec/js/numbers/number.spec.js +70 -0
  68. data/spec/js/numbers/percent.spec.js +22 -0
  69. data/spec/js/plurals/plural_rules.spec.js +28 -0
  70. data/spec/ruby/renderers/plurals/plural_rules_compiler_spec.rb +56 -0
  71. data/spec/ruby/spec_helper.rb +11 -0
  72. data/twitter_cldr_js.gemspec +34 -0
  73. metadata +224 -0
@@ -0,0 +1,49 @@
1
+ # encoding: UTF-8
2
+
3
+ # Copyright 2012 Twitter, Inc
4
+ # http://www.apache.org/licenses/LICENSE-2.0
5
+
6
+ module TwitterCldr
7
+ module Js
8
+ class Compiler
9
+ attr_reader :locales
10
+
11
+ def initialize(options = {})
12
+ @locales = options[:locales] || TwitterCldr.supported_locales
13
+ @features = options[:features] || renderers.keys
14
+ end
15
+
16
+ def compile_each(options = {})
17
+ options[:minify] = true unless options.include?(:minify)
18
+
19
+ @locales.each do |locale|
20
+ contents = ""
21
+
22
+ @features.each do |feature|
23
+ renderer_const = renderers[feature]
24
+ contents << renderer_const.new(:locale => locale).render if renderer_const
25
+ end
26
+
27
+ bundle = TwitterCldr::Js::Renderers::Bundle.new
28
+ bundle[:contents] = contents
29
+ result = CoffeeScript.compile(bundle.render, :bare => true)
30
+ result = Uglifier.compile(result) if options[:minify]
31
+
32
+ yield result, TwitterCldr.twitter_locale(locale)
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def renderers
39
+ @renderers ||= {
40
+ :plural_rules => TwitterCldr::Js::Renderers::PluralRules::PluralRulesRenderer,
41
+ :timespan => TwitterCldr::Js::Renderers::Calendars::TimespanRenderer,
42
+ :datetime => TwitterCldr::Js::Renderers::Calendars::DateTimeRenderer,
43
+ :numbers => TwitterCldr::Js::Renderers::Numbers::NumbersRenderer,
44
+ :currencies => TwitterCldr::Js::Renderers::Shared::CurrenciesRenderer
45
+ }
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,15 @@
1
+ ###
2
+ // Copyright 2012 Twitter, Inc
3
+ // http://www.apache.org/licenses/LICENSE-2.0
4
+
5
+ // TwitterCLDR (JavaScript) v{{version}}
6
+ // Authors: Cameron Dutro [@camertron]
7
+ Kirill Lashuk [@KL_7]
8
+ portions by Sven Fuchs [@svenfuchs]
9
+ // Homepage: https://twitter.com
10
+ // Description: Provides date, time, number, and list formatting functionality for various Twitter-supported locales in Javascript.
11
+ ###
12
+
13
+ TwitterCldr = {}
14
+ {{{contents}}}
15
+ exports[key] = obj for key, obj of TwitterCldr if exports? # for node
@@ -0,0 +1,240 @@
1
+ # Copyright 2012 Twitter, Inc
2
+ # http://www.apache.org/licenses/LICENSE-2.0
3
+
4
+ TwitterCldr.DateTimeFormatter = class DateTimeFormatter
5
+ constructor: ->
6
+ @tokens = `{{{tokens}}}`
7
+ @calendar = `{{{calendar}}}`
8
+ @weekday_keys = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"]
9
+ @methods = # ignoring u, l, g, j, A
10
+ 'G': 'era'
11
+ 'y': 'year'
12
+ 'Y': 'year_of_week_of_year'
13
+ 'Q': 'quarter'
14
+ 'q': 'quarter_stand_alone'
15
+ 'M': 'month'
16
+ 'L': 'month_stand_alone'
17
+ 'w': 'week_of_year'
18
+ 'W': 'week_of_month'
19
+ 'd': 'day'
20
+ 'D': 'day_of_month'
21
+ 'F': 'day_of_week_in_month'
22
+ 'E': 'weekday'
23
+ 'e': 'weekday_local'
24
+ 'c': 'weekday_local_stand_alone'
25
+ 'a': 'period'
26
+ 'h': 'hour'
27
+ 'H': 'hour'
28
+ 'K': 'hour'
29
+ 'k': 'hour'
30
+ 'm': 'minute'
31
+ 's': 'second'
32
+ 'S': 'second_fraction'
33
+ 'z': 'timezone'
34
+ 'Z': 'timezone'
35
+ 'v': 'timezone_generic_non_location'
36
+ 'V': 'timezone_metazone'
37
+
38
+ format: (obj, options) ->
39
+ format_token = (token) =>
40
+ result = ""
41
+
42
+ switch token.type
43
+ when "pattern"
44
+ return this.result_for_token(token, obj)
45
+ else
46
+ if token.value.length > 0 && token.value[0] == "'" && token.value[token.value.length - 1] == "'"
47
+ return token.value.substring(1, token.value.length - 1)
48
+ else
49
+ return token.value
50
+
51
+ tokens = this.get_tokens(obj, options)
52
+ return (format_token(token) for token in tokens).join("")
53
+
54
+ get_tokens: (obj, options) ->
55
+ return @tokens[options.format || "date_time"][options.type || "default"]
56
+
57
+ result_for_token: (token, date) ->
58
+ return this[@methods[token.value[0]]](date, token.value, token.value.length)
59
+
60
+ era: (date, pattern, length) ->
61
+ switch length
62
+ when 1, 2, 3
63
+ choices = @calendar["eras"]["abbr"]
64
+ else
65
+ choices = @calendar["eras"]["name"]
66
+
67
+ index = if (date.getFullYear() < 0) then 0 else 1
68
+ return choices[index]
69
+
70
+ year: (date, pattern, length) ->
71
+ year = date.getFullYear().toString()
72
+
73
+ if length == 2
74
+ if year.length != 1
75
+ year = year.slice(-2)
76
+
77
+ if length > 1
78
+ year = ("0000" + year).slice(-length)
79
+
80
+ return year
81
+
82
+ year_of_week_of_year: (date, pattern, length) ->
83
+ throw 'not implemented'
84
+
85
+ day_of_week_in_month: (date, pattern, length) -> # e.g. 2nd Wed in July
86
+ throw 'not implemented'
87
+
88
+ quarter: (date, pattern, length) ->
89
+ # the bitwise OR is used here to truncate the decimal produced by the / 3
90
+ quarter = ((date.getMonth() / 3) | 0) + 1
91
+
92
+ switch length
93
+ when 1
94
+ return quarter.toString()
95
+ when 2
96
+ return ("0000" + quarter.toString()).slice(-length)
97
+ when 3
98
+ return @calendar.quarters.format.abbreviated[quarter]
99
+ when 4
100
+ return @calendar.quarters.format.wide[quarter]
101
+
102
+ quarter_stand_alone: (date, pattern, length) ->
103
+ quarter = (date.getMonth() - 1) / 3 + 1
104
+
105
+ switch length
106
+ when 1
107
+ return quarter.toString()
108
+ when 2
109
+ return ("0000" + quarter.toString()).slice(-length)
110
+ when 3
111
+ throw 'not yet implemented (requires cldr\'s "multiple inheritance")'
112
+ when 4
113
+ throw 'not yet implemented (requires cldr\'s "multiple inheritance")'
114
+ when 5
115
+ return @calendar.quarters['stand-alone'].narrow[quarter]
116
+
117
+ month: (date, pattern, length) ->
118
+ month_str = (date.getMonth() + 1).toString()
119
+
120
+ switch length
121
+ when 1
122
+ return month_str
123
+ when 2
124
+ return ("0000" + month_str).slice(-length)
125
+ when 3
126
+ return @calendar.months.format.abbreviated[month_str]
127
+ when 4
128
+ return @calendar.months.format.wide[month_str]
129
+ when 5
130
+ throw 'not yet implemented (requires cldr\'s "multiple inheritance")'
131
+ else
132
+ throw "Unknown date format"
133
+
134
+ month_stand_alone: (date, pattern, length) ->
135
+ switch length
136
+ when 1
137
+ return date.getMonth().toString()
138
+ when 2
139
+ return ("0000" + date.getMonth().toString()).slice(-length)
140
+ when 3
141
+ throw 'not yet implemented (requires cldr\'s "multiple inheritance")'
142
+ when 4
143
+ throw 'not yet implemented (requires cldr\'s "multiple inheritance")'
144
+ when 5
145
+ return @calendar.months['stand-alone'].narrow[date.month]
146
+ else
147
+ throw "Unknown date format"
148
+
149
+ day: (date, pattern, length) ->
150
+ switch length
151
+ when 1
152
+ return date.getDate().toString()
153
+ when 2
154
+ return ("0000" + date.getDate().toString()).slice(-length)
155
+
156
+ weekday: (date, pattern, length) ->
157
+ key = @weekday_keys[date.getDay()]
158
+
159
+ switch length
160
+ when 1, 2, 3
161
+ return @calendar.days.format.abbreviated[key]
162
+ when 4
163
+ return @calendar.days.format.wide[key]
164
+ when 5
165
+ return @calendar.days['stand-alone'].narrow[key]
166
+
167
+ weekday_local: (date, pattern, length) ->
168
+ # "Like E except adds a numeric value depending on the local starting day of the week"
169
+ # CLDR does not contain data as to which day is the first day of the week, so we will assume Monday (Ruby default)
170
+ switch length
171
+ when 1, 2
172
+ day = date.getDay()
173
+ return (if day == 0 then "7" else day.toString())
174
+ else
175
+ return this.weekday(date, pattern, length)
176
+
177
+ weekday_local_stand_alone: (date, pattern, length) ->
178
+ switch length
179
+ when 1
180
+ return this.weekday_local(date, pattern, length)
181
+ else
182
+ return this.weekday(date, pattern, length)
183
+
184
+ period: (time, pattern, length) ->
185
+ if time.getHours() > 11
186
+ return @calendar.periods.format.wide["pm"]
187
+ else
188
+ return @calendar.periods.format.wide["am"]
189
+
190
+ hour: (time, pattern, length) ->
191
+ hour = time.getHours()
192
+
193
+ switch pattern[0]
194
+ when 'h'
195
+ if hour > 12
196
+ hour = hour - 12
197
+ else if hour == 0
198
+ hour = 12
199
+ when 'K'
200
+ if hour > 11
201
+ hour = hour - 12
202
+ when 'k'
203
+ if hour == 0
204
+ hour = 24
205
+
206
+ if length == 1
207
+ return hour.toString()
208
+ else
209
+ return ("000000" + hour.toString()).slice(-length)
210
+
211
+ minute: (time, pattern, length) ->
212
+ if length == 1
213
+ return time.getMinutes().toString()
214
+ else
215
+ return ("000000" + time.getMinutes().toString()).slice(-length)
216
+
217
+ second: (time, pattern, length) ->
218
+ if length == 1
219
+ return time.getSeconds().toString()
220
+ else
221
+ return ("000000" + time.getSeconds().toString()).slice(-length)
222
+
223
+ second_fraction: (time, pattern, length) ->
224
+ if length > 6
225
+ throw 'can not use the S format with more than 6 digits'
226
+
227
+ return ("000000" + Math.round(Math.pow(time.getMilliseconds() * 100.0, 6 - length)).toString()).slice(-length)
228
+
229
+ timezone: (time, pattern, length) ->
230
+ hours = ("00" + (time.getTimezoneOffset() / 60).toString()).slice(-2)
231
+ minutes = ("00" + (time.getTimezoneOffset() % 60).toString()).slice(-2)
232
+
233
+ switch length
234
+ when 1, 2, 3
235
+ return "-" + hours + ":" + minutes
236
+ else
237
+ return "UTC -" + hours + ":" + minutes
238
+
239
+ timezone_generic_non_location: (time, pattern, length) ->
240
+ throw 'not yet implemented (requires timezone translation data")'
@@ -0,0 +1,52 @@
1
+ # Copyright 2012 Twitter, Inc
2
+ # http://www.apache.org/licenses/LICENSE-2.0
3
+
4
+ TwitterCldr.TimespanFormatter = class TimespanFormatter
5
+ constructor: ->
6
+ @default_type = "default"
7
+ @tokens = `{{{tokens}}}`
8
+ @time_in_seconds = {
9
+ "second": 1,
10
+ "minute": 60,
11
+ "hour": 3600,
12
+ "day": 86400,
13
+ "week": 604800,
14
+ "month": 2629743.83,
15
+ "year": 31556926
16
+ }
17
+
18
+ format: (seconds, options = {}) ->
19
+ options["direction"] ||= (if seconds < 0 then "ago" else "until")
20
+ options["unit"] = this.calculate_unit(Math.abs(seconds)) if options["unit"] is null or options["unit"] is undefined
21
+ options["type"] ||= @default_type
22
+ options["number"] = this.calculate_time(Math.abs(seconds), options["unit"])
23
+ number = this.calculate_time(Math.abs(seconds), options["unit"])
24
+ options["rule"] = TwitterCldr.PluralRules.rule_for(number)
25
+
26
+ strings = (token.value for token in @tokens[options["direction"]][options["unit"]][options["type"]][options["rule"]])
27
+ strings.join("").replace(/\{[0-9]\}/, number.toString())
28
+
29
+ calculate_unit: (seconds) ->
30
+ if seconds < 30
31
+ "second"
32
+ else if seconds < 2670
33
+ "minute"
34
+ else if seconds < 86369
35
+ "hour"
36
+ else if seconds < 604800
37
+ "day"
38
+ else if seconds < 2591969
39
+ "week"
40
+ else if seconds < 31556926
41
+ "month"
42
+ else
43
+ "year"
44
+
45
+ # 0 <-> 29 secs # => seconds
46
+ # 30 secs <-> 44 mins, 29 secs # => minutes
47
+ # 44 mins, 30 secs <-> 23 hrs, 59 mins, 29 secs # => hours
48
+ # 23 hrs, 59 mins, 29 secs <-> 29 days, 23 hrs, 59 mins, 29 secs # => days
49
+ # 29 days, 23 hrs, 59 mins, 29 secs <-> 1 yr minus 1 sec # => months
50
+ # 1 yr <-> max time or date # => years
51
+ calculate_time: (seconds, unit) ->
52
+ Math.round(seconds / @time_in_seconds[unit])
@@ -0,0 +1,179 @@
1
+ # Copyright 2012 Twitter, Inc
2
+ # http://www.apache.org/licenses/LICENSE-2.0
3
+
4
+ TwitterCldr.NumberFormatter = class NumberFormatter
5
+ constructor: ->
6
+ @all_tokens = `{{{tokens}}}`
7
+ @tokens = []
8
+ @symbols = `{{{symbols}}}`
9
+
10
+ @default_symbols =
11
+ 'group': ','
12
+ 'decimal': '.'
13
+ 'plus_sign': '+'
14
+ 'minus_sign': '-'
15
+
16
+ format: (number, options = {}) ->
17
+ opts = this.default_format_options_for(number)
18
+
19
+ for key, val of options
20
+ opts[key] = if options[key]? then options[key] else opts[key]
21
+
22
+ [prefix, suffix, integer_format, fraction_format] = this.partition_tokens(this.get_tokens(number, opts))
23
+ [int, fraction] = this.parse_number(number, opts)
24
+ result = integer_format.apply(parseFloat(int), opts)
25
+ result += fraction_format.apply(fraction, opts) if fraction
26
+ sign = if number < 0 && prefix != "-" then @symbols.minus_sign || @default_symbols.minus_sign else ""
27
+ "#{prefix}#{result}#{suffix}"
28
+
29
+ partition_tokens: (tokens) ->
30
+ [tokens[0] || "",
31
+ tokens[2] || "",
32
+ new IntegerHelper(tokens[1], @symbols),
33
+ new FractionHelper(tokens[1], @symbols)]
34
+
35
+ parse_number: (number, options = {}) ->
36
+ if options.precision?
37
+ precision = options.precision
38
+ else
39
+ precision = this.precision_from(number)
40
+
41
+ number = this.round_to(number, precision)
42
+ Math.abs(number).toFixed(precision).split(".")
43
+
44
+ precision_from: (num) ->
45
+ parts = num.toString().split(".")
46
+ if parts.length == 2 then parts[1].length else 0
47
+
48
+ round_to: (number, precision) ->
49
+ factor = Math.pow(10, precision)
50
+ Math.round(number * factor) / factor
51
+
52
+ get_tokens: ->
53
+ throw "get_tokens() not implemented - use a derived class like PercentFormatter."
54
+
55
+ TwitterCldr.PercentFormatter = class PercentFormatter extends NumberFormatter
56
+ constructor: (options = {}) ->
57
+ @default_percent_sign = "%"
58
+ super
59
+
60
+ format: (number, options = {}) ->
61
+ super(number, options).replace('¤', @symbols.percent_sign || @default_percent_sign)
62
+
63
+ default_format_options_for: (number) ->
64
+ precision: 0
65
+
66
+ get_tokens: (number, options) ->
67
+ if number < 0 then @all_tokens.percent.negative else @all_tokens.percent.positive
68
+
69
+ TwitterCldr.DecimalFormatter = class DecimalFormatter extends NumberFormatter
70
+ format: (number, options = {}) ->
71
+ try
72
+ super(number, options)
73
+ catch error
74
+ number
75
+
76
+ default_format_options_for: (number) ->
77
+ precision: this.precision_from(number)
78
+
79
+ get_tokens: (number, options = {}) ->
80
+ if number < 0 then @all_tokens.decimal.negative else @all_tokens.decimal.positive
81
+
82
+ TwitterCldr.CurrencyFormatter = class CurrencyFormatter extends NumberFormatter
83
+ constructor: (options = {}) ->
84
+ @default_currency_symbol = "$"
85
+ @default_precision = 2
86
+ super
87
+
88
+ format: (number, options = {}) ->
89
+ if options.currency
90
+ if TwitterCldr.Currencies?
91
+ currency = TwitterCldr.Currencies.for_code(options.currency)
92
+ currency ||= TwitterCldr.Currencies.for_country(options.currency)
93
+ currency ||= symbol: options.currency
94
+ else
95
+ currency = symbol: options.currency
96
+ else
97
+ currency = symbol: @default_currency_symbol
98
+
99
+ super(number, options).replace('¤', currency.symbol)
100
+
101
+ default_format_options_for: (number) ->
102
+ precision = this.precision_from(number)
103
+ if precision == 0 then precision = @default_precision
104
+ precision: precision
105
+
106
+ get_tokens: (number, options = {}) ->
107
+ if number < 0 then @all_tokens.currency.negative else @all_tokens.currency.positive
108
+
109
+ TwitterCldr.NumberFormatter.BaseHelper = class BaseHelper
110
+ interpolate: (string, value, orientation = "right") ->
111
+ value = value.toString()
112
+ length = value.length
113
+ start = if orientation == "left" then 0 else -length
114
+ string = (("#" for i in [0...length]).join("") + string).slice(-length) if string.length < length
115
+
116
+ if start < 0
117
+ string = string[0...(start + string.length)] + value
118
+ else
119
+ string = string[0...start] + value + string[(length)..-1]
120
+
121
+ string.replace(/#/g, "")
122
+
123
+ TwitterCldr.NumberFormatter.IntegerHelper = class IntegerHelper extends BaseHelper
124
+ constructor: (token, symbols = {}) ->
125
+ format = token.split('.')[0]
126
+ @format = this.prepare_format(format, symbols)
127
+ @groups = this.parse_groups(format)
128
+ @separator = symbols.group || ','
129
+
130
+ apply: (number, options = {}) ->
131
+ this.format_groups(this.interpolate(@format, parseInt(number)))
132
+
133
+ format_groups: (string) ->
134
+ return string if @groups.length == 0
135
+ tokens = []
136
+
137
+ cur_token = this.chop_group(string, @groups[0])
138
+ tokens.push(cur_token)
139
+ string = string[0...(string.length - cur_token.length)] if cur_token
140
+
141
+ while string.length > @groups[@groups.length - 1]
142
+ cur_token = this.chop_group(string, @groups[@groups.length - 1])
143
+ tokens.push(cur_token)
144
+ string = string[0...(string.length - cur_token.length)] if cur_token
145
+
146
+ tokens.push(string)
147
+ (token for token in tokens when token != null).reverse().join(@separator)
148
+
149
+ parse_groups: (format) ->
150
+ return [] unless index = format.lastIndexOf(',')
151
+ rest = format[0...index]
152
+ widths = [format.length - index - 1]
153
+ widths.push(rest.length - rest.lastIndexOf(',') - 1) if rest.lastIndexOf(',') > -1
154
+ widths = (width for width in widths when width != null) # compact
155
+ widths.reverse() # uniq
156
+ (widths[index] for index in [0...widths.length] when widths.indexOf(widths[index], index + 1) == -1).reverse()
157
+
158
+ chop_group: (string, size) ->
159
+ if string.length > size then string[-size..-1] else null
160
+
161
+ prepare_format: (format, symbols) ->
162
+ format.replace(",", "").replace("+", symbols.plus_sign).replace("-", symbols.minus_sign)
163
+
164
+ TwitterCldr.NumberFormatter.FractionHelper = class FractionHelper extends BaseHelper
165
+ constructor: (token, symbols = {}) ->
166
+ @format = if token then token.split('.').pop() else ""
167
+ @decimal = symbols.decimal || "."
168
+ @precision = @format.length
169
+
170
+ apply: (fraction, options = {}) ->
171
+ precision = if options.precision? then options.precision else @precision
172
+ if precision > 0
173
+ @decimal + this.interpolate(this.format_for(options), fraction, "left")
174
+ else
175
+ ""
176
+
177
+ format_for: (options) ->
178
+ precision = if options.precision? then options.precision else @precision
179
+ if precision then ("0" for i in [0...precision]).join("") else @format
@@ -0,0 +1,14 @@
1
+ # Copyright 2012 Twitter, Inc
2
+ # http://www.apache.org/licenses/LICENSE-2.0
3
+
4
+ TwitterCldr.PluralRules = class PluralRules
5
+ @rules = `{{{rules}}}`
6
+
7
+ @all: ->
8
+ return @rules.keys
9
+
10
+ @rule_for: (number) ->
11
+ try
12
+ return @rules.rule(number)
13
+ catch error
14
+ return "other"
@@ -0,0 +1,27 @@
1
+ # Copyright 2012 Twitter, Inc
2
+ # http://www.apache.org/licenses/LICENSE-2.0
3
+
4
+ TwitterCldr.Currencies = class Currencies
5
+ @currencies = `{{{currencies}}}`
6
+
7
+ @countries: ->
8
+ @names ||= (country_name for country_name, data of @currencies)
9
+
10
+ @currency_codes: ->
11
+ @codes ||= (data.code for country_name, data of @currencies)
12
+
13
+ @for_country: (country_name) ->
14
+ @currencies[country_name]
15
+
16
+ @for_code: (currency_code) ->
17
+ final = null
18
+ for country_name, data of @currencies
19
+ if data.code == currency_code
20
+ final =
21
+ country: country_name
22
+ code: data.code
23
+ symbol: data.symbol
24
+ currency: data.currency
25
+ break
26
+
27
+ final
@@ -0,0 +1,18 @@
1
+ # encoding: UTF-8
2
+
3
+ # Copyright 2012 Twitter, Inc
4
+ # http://www.apache.org/licenses/LICENSE-2.0
5
+
6
+ module TwitterCldr
7
+ module Js
8
+ module Renderers
9
+ class Base < Mustache
10
+
11
+ def initialize(options = {})
12
+ @locale = options[:locale]
13
+ end
14
+
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ # encoding: UTF-8
2
+
3
+ # Copyright 2012 Twitter, Inc
4
+ # http://www.apache.org/licenses/LICENSE-2.0
5
+
6
+ module TwitterCldr
7
+ module Js
8
+ module Renderers
9
+ class Bundle < Mustache
10
+ self.template_file = File.expand_path(File.join(File.dirname(__FILE__), "..", "mustache/bundle.coffee"))
11
+
12
+ def version
13
+ TwitterCldr::VERSION
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,34 @@
1
+ # encoding: UTF-8
2
+
3
+ # Copyright 2012 Twitter, Inc
4
+ # http://www.apache.org/licenses/LICENSE-2.0
5
+
6
+ module TwitterCldr
7
+ module Js
8
+ module Renderers
9
+ module Calendars
10
+ class DateTimeRenderer < TwitterCldr::Js::Renderers::Base
11
+ self.template_file = File.expand_path(File.join(File.dirname(__FILE__), "../..", "mustache/calendars/datetime.coffee"))
12
+
13
+ def tokens
14
+ tokens = {}
15
+ { :date_time => TwitterCldr::Tokenizers::DateTimeTokenizer,
16
+ :time => TwitterCldr::Tokenizers::TimeTokenizer,
17
+ :date => TwitterCldr::Tokenizers::DateTokenizer }.each_pair do |name, const|
18
+ tokenizer = const.new(:locale => @locale)
19
+ tokens[name] = const::VALID_TYPES.inject({}) do |ret, type|
20
+ ret[type] = tokenizer.tokens(:type => type).map(&:to_hash)
21
+ ret
22
+ end
23
+ end
24
+ tokens.to_json
25
+ end
26
+
27
+ def calendar
28
+ TwitterCldr::Tokenizers::DateTimeTokenizer.new(:locale => @locale).calendar.to_json
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,39 @@
1
+ # encoding: UTF-8
2
+
3
+ # Copyright 2012 Twitter, Inc
4
+ # http://www.apache.org/licenses/LICENSE-2.0
5
+
6
+ include TwitterCldr::Tokenizers
7
+ include TwitterCldr::Formatters
8
+
9
+ module TwitterCldr
10
+ module Js
11
+ module Renderers
12
+ module Calendars
13
+
14
+ class TimespanRenderer < TwitterCldr::Js::Renderers::Base
15
+ self.template_file = File.expand_path(File.join(File.dirname(__FILE__), "../..", "mustache/calendars/timespan.coffee"))
16
+
17
+ def tokens
18
+ tokenizer = TimespanTokenizer.new(:locale => @locale)
19
+ [:ago, :until, :none].inject({}) do |final, direction|
20
+ final[direction] = TimespanTokenizer::VALID_UNITS.inject({}) do |unit_hash, unit|
21
+ unit_hash[unit] = tokenizer.all_types_for(unit, direction).inject({}) do |type_hash, type|
22
+ type_hash[type] = Plurals::Rules.all_for(@locale).inject({}) do |rule_hash, rule|
23
+ rule_hash[rule] = tokenizer.tokens(:direction => direction, :unit => unit, :rule => rule, :type => type)
24
+ rule_hash
25
+ end
26
+ type_hash
27
+ end
28
+ unit_hash
29
+ end
30
+ final
31
+ end.to_json
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+ end
38
+ end
39
+ end