twitter_cldr 1.5.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (203) hide show
  1. data/Gemfile +32 -0
  2. data/History.txt +78 -0
  3. data/README.md +72 -62
  4. data/Rakefile +22 -0
  5. data/js/lib/compiler.rb +40 -0
  6. data/js/lib/mustache/bundle.coffee +14 -0
  7. data/js/lib/mustache/calendars/datetime.coffee +240 -0
  8. data/js/lib/mustache/calendars/timespan.coffee +52 -0
  9. data/js/lib/mustache/plurals/rules.coffee +14 -0
  10. data/js/lib/renderers/base.rb +18 -0
  11. data/js/lib/renderers/bundle.rb +18 -0
  12. data/js/lib/renderers/calendars/datetime_renderer.rb +34 -0
  13. data/js/lib/renderers/calendars/timespan_renderer.rb +39 -0
  14. data/js/lib/renderers/plurals/rules/plural_rules_compiler.rb +89 -0
  15. data/js/lib/renderers/plurals/rules/plural_rules_renderer.rb +26 -0
  16. data/js/lib/twitter_cldr_js.rb +85 -0
  17. data/js/spec/js/calendars/datetime_spec.js +418 -0
  18. data/js/spec/js/calendars/timespan_spec.js +91 -0
  19. data/js/spec/js/plurals/plural_rules_spec.js +28 -0
  20. data/js/spec/js/support/jasmine.yml +8 -0
  21. data/js/spec/rb/renderers/plurals/plural_rules_compiler_spec.rb +52 -0
  22. data/js/spec/rb/spec_helper.rb +13 -0
  23. data/lib/twitter_cldr.rb +2 -1
  24. data/lib/twitter_cldr/collation.rb +2 -1
  25. data/lib/twitter_cldr/collation/collator.rb +49 -31
  26. data/lib/twitter_cldr/collation/{sort_key.rb → sort_key_builder.rb} +31 -8
  27. data/lib/twitter_cldr/collation/trie.rb +116 -24
  28. data/lib/twitter_cldr/collation/trie_builder.rb +54 -28
  29. data/lib/twitter_cldr/collation/trie_with_fallback.rb +55 -0
  30. data/lib/twitter_cldr/core_ext/array.rb +14 -1
  31. data/lib/twitter_cldr/core_ext/calendars/datetime.rb +8 -2
  32. data/lib/twitter_cldr/core_ext/calendars/timespan.rb +5 -5
  33. data/lib/twitter_cldr/formatters/calendars/timespan_formatter.rb +10 -10
  34. data/lib/twitter_cldr/formatters/plurals/rules.rb +3 -5
  35. data/lib/twitter_cldr/resources.rb +11 -0
  36. data/lib/twitter_cldr/resources/import.rb +12 -0
  37. data/lib/twitter_cldr/resources/import/tailoring.rb +193 -0
  38. data/lib/twitter_cldr/{shared/resources.rb → resources/loader.rb} +17 -4
  39. data/lib/twitter_cldr/shared.rb +0 -1
  40. data/lib/twitter_cldr/tokenizers/base.rb +9 -9
  41. data/lib/twitter_cldr/tokenizers/calendars/datetime_tokenizer.rb +0 -4
  42. data/lib/twitter_cldr/tokenizers/calendars/timespan_tokenizer.rb +21 -7
  43. data/lib/twitter_cldr/utils.rb +11 -0
  44. data/lib/twitter_cldr/version.rb +1 -1
  45. data/resources/collation/tailoring/af.yml +3 -0
  46. data/resources/collation/tailoring/ar.yml +21 -0
  47. data/resources/collation/tailoring/ca.yml +9 -0
  48. data/resources/collation/tailoring/cs.yml +25 -0
  49. data/resources/collation/tailoring/da.yml +59 -0
  50. data/resources/collation/tailoring/de.yml +3 -0
  51. data/resources/collation/tailoring/el.yml +3 -0
  52. data/resources/collation/tailoring/en.yml +3 -0
  53. data/resources/collation/tailoring/es.yml +5 -0
  54. data/resources/collation/tailoring/eu.yml +3 -0
  55. data/resources/collation/tailoring/fa.yml +73 -0
  56. data/resources/collation/tailoring/fi.yml +61 -0
  57. data/resources/collation/tailoring/fil.yml +11 -0
  58. data/resources/collation/tailoring/fr.yml +3 -0
  59. data/resources/collation/tailoring/he.yml +3 -0
  60. data/resources/collation/tailoring/hi.yml +7 -0
  61. data/resources/collation/tailoring/hu.yml +125 -0
  62. data/resources/collation/tailoring/id.yml +3 -0
  63. data/resources/collation/tailoring/it.yml +3 -0
  64. data/resources/collation/tailoring/ja.yml +14647 -0
  65. data/resources/collation/tailoring/ko.yml +14953 -0
  66. data/resources/collation/tailoring/ms.yml +3 -0
  67. data/resources/collation/tailoring/nb.yml +59 -0
  68. data/resources/collation/tailoring/nl.yml +3 -0
  69. data/resources/collation/tailoring/pl.yml +37 -0
  70. data/resources/collation/tailoring/pt.yml +3 -0
  71. data/resources/collation/tailoring/ru.yml +3 -0
  72. data/resources/collation/tailoring/sv.yml +63 -0
  73. data/resources/collation/tailoring/th.yml +19 -0
  74. data/resources/collation/tailoring/tr.yml +27 -0
  75. data/resources/collation/tailoring/uk.yml +5 -0
  76. data/resources/collation/tailoring/ur.yml +163 -0
  77. data/resources/collation/tailoring/zh-Hant.yml +3 -0
  78. data/resources/collation/tailoring/zh.yml +149 -0
  79. data/resources/custom/locales/af/units.yml +19 -0
  80. data/resources/custom/locales/ar/units.yml +35 -0
  81. data/resources/custom/locales/ca/units.yml +19 -0
  82. data/resources/custom/locales/cs/units.yml +23 -0
  83. data/resources/custom/locales/da/units.yml +19 -0
  84. data/resources/custom/locales/de/units.yml +19 -0
  85. data/resources/custom/locales/el/units.yml +19 -0
  86. data/resources/custom/locales/en/units.yml +18 -0
  87. data/resources/custom/locales/es/units.yml +19 -0
  88. data/resources/custom/locales/eu/units.yml +19 -0
  89. data/resources/custom/locales/fa/units.yml +15 -0
  90. data/resources/custom/locales/fi/units.yml +19 -0
  91. data/resources/custom/locales/fil/units.yml +19 -0
  92. data/resources/custom/locales/fr/units.yml +19 -0
  93. data/resources/custom/locales/he/units.yml +19 -0
  94. data/resources/custom/locales/hi/units.yml +19 -0
  95. data/resources/custom/locales/hu/units.yml +15 -0
  96. data/resources/custom/locales/id/units.yml +15 -0
  97. data/resources/custom/locales/it/units.yml +19 -0
  98. data/resources/custom/locales/ja/units.yml +15 -0
  99. data/resources/custom/locales/ko/units.yml +15 -0
  100. data/resources/custom/locales/ms/units.yml +15 -0
  101. data/resources/custom/locales/nb/units.yml +19 -0
  102. data/resources/custom/locales/nl/units.yml +19 -0
  103. data/resources/custom/locales/pl/units.yml +23 -0
  104. data/resources/custom/locales/pt/units.yml +19 -0
  105. data/resources/custom/locales/ru/units.yml +27 -0
  106. data/resources/custom/locales/sv/units.yml +19 -0
  107. data/resources/custom/locales/th/units.yml +15 -0
  108. data/resources/custom/locales/tr/units.yml +15 -0
  109. data/resources/custom/locales/uk/units.yml +27 -0
  110. data/resources/custom/locales/ur/units.yml +19 -0
  111. data/resources/custom/locales/zh-Hant/units.yml +15 -0
  112. data/resources/custom/locales/zh/units.yml +15 -0
  113. data/resources/locales/af/units.yml +112 -65
  114. data/resources/locales/ar/units.yml +196 -126
  115. data/resources/locales/ca/units.yml +112 -70
  116. data/resources/locales/cs/units.yml +140 -91
  117. data/resources/locales/da/units.yml +98 -56
  118. data/resources/locales/de/units.yml +112 -70
  119. data/resources/locales/el/units.yml +119 -84
  120. data/resources/locales/en/units.yml +84 -42
  121. data/resources/locales/es/units.yml +112 -70
  122. data/resources/locales/eu/units.yml +105 -68
  123. data/resources/locales/fa/units.yml +98 -63
  124. data/resources/locales/fi/units.yml +112 -70
  125. data/resources/locales/fil/units.yml +98 -56
  126. data/resources/locales/fr/units.yml +112 -70
  127. data/resources/locales/he/units.yml +98 -56
  128. data/resources/locales/hi/units.yml +98 -56
  129. data/resources/locales/hu/units.yml +84 -49
  130. data/resources/locales/id/units.yml +84 -49
  131. data/resources/locales/it/units.yml +98 -56
  132. data/resources/locales/ja/units.yml +84 -49
  133. data/resources/locales/ko/units.yml +84 -49
  134. data/resources/locales/ms/units.yml +112 -63
  135. data/resources/locales/nb/units.yml +106 -64
  136. data/resources/locales/nl/units.yml +98 -56
  137. data/resources/locales/pl/units.yml +181 -112
  138. data/resources/locales/pt/units.yml +112 -70
  139. data/resources/locales/ru/units.yml +168 -112
  140. data/resources/locales/sv/units.yml +112 -70
  141. data/resources/locales/th/units.yml +84 -49
  142. data/resources/locales/tr/units.yml +84 -49
  143. data/resources/locales/uk/units.yml +168 -112
  144. data/resources/locales/ur/units.yml +112 -63
  145. data/resources/locales/zh-Hant/units.yml +84 -49
  146. data/resources/locales/zh/units.yml +84 -49
  147. data/spec/collation/collation_spec.rb +1 -1
  148. data/spec/collation/collator_spec.rb +120 -48
  149. data/spec/collation/sort_key_builder_spec.rb +80 -0
  150. data/spec/collation/tailoring_spec.rb +137 -0
  151. data/spec/collation/tailoring_tests/af.txt +321 -0
  152. data/spec/collation/tailoring_tests/ar.txt +188 -0
  153. data/spec/collation/tailoring_tests/ca.txt +446 -0
  154. data/spec/collation/tailoring_tests/cs.txt +273 -0
  155. data/spec/collation/tailoring_tests/da.txt +293 -0
  156. data/spec/collation/tailoring_tests/de.txt +414 -0
  157. data/spec/collation/tailoring_tests/el.txt +228 -0
  158. data/spec/collation/tailoring_tests/en.txt +399 -0
  159. data/spec/collation/tailoring_tests/es.txt +402 -0
  160. data/spec/collation/tailoring_tests/eu.txt +183 -0
  161. data/spec/collation/tailoring_tests/fa.txt +263 -0
  162. data/spec/collation/tailoring_tests/fi.txt +389 -0
  163. data/spec/collation/tailoring_tests/fil.txt +279 -0
  164. data/spec/collation/tailoring_tests/fr.txt +363 -0
  165. data/spec/collation/tailoring_tests/he.txt +167 -0
  166. data/spec/collation/tailoring_tests/hi.txt +230 -0
  167. data/spec/collation/tailoring_tests/hu.txt +773 -0
  168. data/spec/collation/tailoring_tests/id.txt +171 -0
  169. data/spec/collation/tailoring_tests/it.txt +231 -0
  170. data/spec/collation/tailoring_tests/ja.txt +4287 -0
  171. data/spec/collation/tailoring_tests/ko.txt +1761 -0
  172. data/spec/collation/tailoring_tests/ms.txt +531 -0
  173. data/spec/collation/tailoring_tests/nb.txt +375 -0
  174. data/spec/collation/tailoring_tests/nl.txt +273 -0
  175. data/spec/collation/tailoring_tests/pl.txt +225 -0
  176. data/spec/collation/tailoring_tests/pt.txt +405 -0
  177. data/spec/collation/tailoring_tests/ru.txt +213 -0
  178. data/spec/collation/tailoring_tests/sv.txt +353 -0
  179. data/spec/collation/tailoring_tests/th.txt +239 -0
  180. data/spec/collation/tailoring_tests/tr.txt +414 -0
  181. data/spec/collation/tailoring_tests/uk.txt +218 -0
  182. data/spec/collation/tailoring_tests/ur.txt +284 -0
  183. data/spec/collation/tailoring_tests/zh-Hant.txt +626 -0
  184. data/spec/collation/tailoring_tests/zh.txt +717 -0
  185. data/spec/collation/trie_builder_spec.rb +131 -51
  186. data/spec/collation/trie_spec.rb +301 -26
  187. data/spec/collation/trie_with_fallback_spec.rb +41 -0
  188. data/spec/core_ext/array_spec.rb +46 -3
  189. data/spec/core_ext/calendars/date_spec.rb +24 -24
  190. data/spec/core_ext/calendars/datetime_spec.rb +7 -0
  191. data/spec/core_ext/calendars/time_spec.rb +2 -2
  192. data/spec/formatters/calendars/timespan_formatter_spec.rb +47 -18
  193. data/spec/formatters/plurals/rules_spec.rb +3 -11
  194. data/spec/readme_spec.rb +15 -15
  195. data/spec/resources/loader_spec.rb +94 -0
  196. data/spec/spec_helper.rb +6 -0
  197. data/spec/tokenizers/calendars/timespan_tokenizer_spec.rb +1 -1
  198. data/spec/twitter_cldr_spec.rb +3 -3
  199. data/spec/utils_spec.rb +38 -0
  200. data/twitter_cldr.gemspec +25 -0
  201. metadata +156 -110
  202. data/spec/collation/sort_key_spec.rb +0 -56
  203. data/spec/shared/resources_spec.rb +0 -75
@@ -0,0 +1,14 @@
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}}}
@@ -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,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,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
@@ -0,0 +1,89 @@
1
+ # encoding: UTF-8
2
+
3
+ # Copyright 2012 Twitter, Inc
4
+ # http://www.apache.org/licenses/LICENSE-2.0
5
+
6
+ require 'ruby_parser'
7
+
8
+ module TwitterCldr
9
+ module Js
10
+ module Renderers
11
+ module PluralRules
12
+
13
+ class PluralRulesCompiler
14
+
15
+ class << self
16
+ def rule_to_js(rule_code)
17
+ tree = RubyParser.new.parse(rule_code).to_a
18
+ "function(n) { return #{statement_list(tree)} }"
19
+ end
20
+
21
+ protected
22
+
23
+ def statement_list(tree)
24
+ if tree.first == :block
25
+ tree[1..-1].map { |sub_tree| send(:"_#{sub_tree.first}", sub_tree) }.join(" ")
26
+ else
27
+ send(:"_#{tree.first}", tree)
28
+ end
29
+ end
30
+
31
+ def _if(tree)
32
+ result = "(function() { if (#{statement_list(tree[1])}) { return #{statement_list(tree[2])} }"
33
+ result << " else { return #{statement_list(tree[3])} }" if tree[3]
34
+ "#{result} })();"
35
+ end
36
+
37
+ def _lvar(tree)
38
+ tree.first.to_s
39
+ end
40
+
41
+ def _call(tree)
42
+ case tree[2]
43
+ when :==, :%, :<, :> # special operators that actually resolve to method calls
44
+ "#{statement_list(tree[1])} #{tree[2]} #{statement_list(tree[3])}"
45
+ when :include?
46
+ "#{statement_list(tree[1])}.indexOf(#{statement_list(tree[3])}) >= 0"
47
+ else
48
+ # this should be the only case where tree[1] might be nil (i.e. the method was not called on any object)
49
+ call = tree[1] ? "#{statement_list(tree[1])}.#{tree[2]}" : tree[2].to_s
50
+ arglist = statement_list(tree[3])
51
+ arglist == "" ? call : "#{call}(#{arglist})"
52
+ end
53
+ end
54
+
55
+ def _arglist(tree)
56
+ tree[1..-1].map { |arg| statement_list(arg) }.join(", ")
57
+ end
58
+
59
+ def _lit(tree)
60
+ if tree[1].is_a?(Symbol) || tree[1].is_a?(String)
61
+ "\"#{tree[1]}\""
62
+ else
63
+ tree[1]
64
+ end
65
+ end
66
+
67
+ def _array(tree)
68
+ "[#{tree[1..-1].map { |arg| statement_list(arg) }.join(", ")}]"
69
+ end
70
+
71
+ def _not(tree)
72
+ "!(#{statement_list(tree[1])})"
73
+ end
74
+
75
+ def _and(tree)
76
+ "#{statement_list(tree[1])} && #{statement_list(tree[2])}"
77
+ end
78
+
79
+ def _or(tree)
80
+ "#{statement_list(tree[1])} || #{statement_list(tree[2])}"
81
+ end
82
+ end
83
+
84
+ end
85
+
86
+ end
87
+ end
88
+ end
89
+ end