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.
- data/Gemfile +32 -0
- data/History.txt +78 -0
- data/README.md +72 -62
- data/Rakefile +22 -0
- data/js/lib/compiler.rb +40 -0
- data/js/lib/mustache/bundle.coffee +14 -0
- data/js/lib/mustache/calendars/datetime.coffee +240 -0
- data/js/lib/mustache/calendars/timespan.coffee +52 -0
- data/js/lib/mustache/plurals/rules.coffee +14 -0
- data/js/lib/renderers/base.rb +18 -0
- data/js/lib/renderers/bundle.rb +18 -0
- data/js/lib/renderers/calendars/datetime_renderer.rb +34 -0
- data/js/lib/renderers/calendars/timespan_renderer.rb +39 -0
- data/js/lib/renderers/plurals/rules/plural_rules_compiler.rb +89 -0
- data/js/lib/renderers/plurals/rules/plural_rules_renderer.rb +26 -0
- data/js/lib/twitter_cldr_js.rb +85 -0
- data/js/spec/js/calendars/datetime_spec.js +418 -0
- data/js/spec/js/calendars/timespan_spec.js +91 -0
- data/js/spec/js/plurals/plural_rules_spec.js +28 -0
- data/js/spec/js/support/jasmine.yml +8 -0
- data/js/spec/rb/renderers/plurals/plural_rules_compiler_spec.rb +52 -0
- data/js/spec/rb/spec_helper.rb +13 -0
- data/lib/twitter_cldr.rb +2 -1
- data/lib/twitter_cldr/collation.rb +2 -1
- data/lib/twitter_cldr/collation/collator.rb +49 -31
- data/lib/twitter_cldr/collation/{sort_key.rb → sort_key_builder.rb} +31 -8
- data/lib/twitter_cldr/collation/trie.rb +116 -24
- data/lib/twitter_cldr/collation/trie_builder.rb +54 -28
- data/lib/twitter_cldr/collation/trie_with_fallback.rb +55 -0
- data/lib/twitter_cldr/core_ext/array.rb +14 -1
- data/lib/twitter_cldr/core_ext/calendars/datetime.rb +8 -2
- data/lib/twitter_cldr/core_ext/calendars/timespan.rb +5 -5
- data/lib/twitter_cldr/formatters/calendars/timespan_formatter.rb +10 -10
- data/lib/twitter_cldr/formatters/plurals/rules.rb +3 -5
- data/lib/twitter_cldr/resources.rb +11 -0
- data/lib/twitter_cldr/resources/import.rb +12 -0
- data/lib/twitter_cldr/resources/import/tailoring.rb +193 -0
- data/lib/twitter_cldr/{shared/resources.rb → resources/loader.rb} +17 -4
- data/lib/twitter_cldr/shared.rb +0 -1
- data/lib/twitter_cldr/tokenizers/base.rb +9 -9
- data/lib/twitter_cldr/tokenizers/calendars/datetime_tokenizer.rb +0 -4
- data/lib/twitter_cldr/tokenizers/calendars/timespan_tokenizer.rb +21 -7
- data/lib/twitter_cldr/utils.rb +11 -0
- data/lib/twitter_cldr/version.rb +1 -1
- data/resources/collation/tailoring/af.yml +3 -0
- data/resources/collation/tailoring/ar.yml +21 -0
- data/resources/collation/tailoring/ca.yml +9 -0
- data/resources/collation/tailoring/cs.yml +25 -0
- data/resources/collation/tailoring/da.yml +59 -0
- data/resources/collation/tailoring/de.yml +3 -0
- data/resources/collation/tailoring/el.yml +3 -0
- data/resources/collation/tailoring/en.yml +3 -0
- data/resources/collation/tailoring/es.yml +5 -0
- data/resources/collation/tailoring/eu.yml +3 -0
- data/resources/collation/tailoring/fa.yml +73 -0
- data/resources/collation/tailoring/fi.yml +61 -0
- data/resources/collation/tailoring/fil.yml +11 -0
- data/resources/collation/tailoring/fr.yml +3 -0
- data/resources/collation/tailoring/he.yml +3 -0
- data/resources/collation/tailoring/hi.yml +7 -0
- data/resources/collation/tailoring/hu.yml +125 -0
- data/resources/collation/tailoring/id.yml +3 -0
- data/resources/collation/tailoring/it.yml +3 -0
- data/resources/collation/tailoring/ja.yml +14647 -0
- data/resources/collation/tailoring/ko.yml +14953 -0
- data/resources/collation/tailoring/ms.yml +3 -0
- data/resources/collation/tailoring/nb.yml +59 -0
- data/resources/collation/tailoring/nl.yml +3 -0
- data/resources/collation/tailoring/pl.yml +37 -0
- data/resources/collation/tailoring/pt.yml +3 -0
- data/resources/collation/tailoring/ru.yml +3 -0
- data/resources/collation/tailoring/sv.yml +63 -0
- data/resources/collation/tailoring/th.yml +19 -0
- data/resources/collation/tailoring/tr.yml +27 -0
- data/resources/collation/tailoring/uk.yml +5 -0
- data/resources/collation/tailoring/ur.yml +163 -0
- data/resources/collation/tailoring/zh-Hant.yml +3 -0
- data/resources/collation/tailoring/zh.yml +149 -0
- data/resources/custom/locales/af/units.yml +19 -0
- data/resources/custom/locales/ar/units.yml +35 -0
- data/resources/custom/locales/ca/units.yml +19 -0
- data/resources/custom/locales/cs/units.yml +23 -0
- data/resources/custom/locales/da/units.yml +19 -0
- data/resources/custom/locales/de/units.yml +19 -0
- data/resources/custom/locales/el/units.yml +19 -0
- data/resources/custom/locales/en/units.yml +18 -0
- data/resources/custom/locales/es/units.yml +19 -0
- data/resources/custom/locales/eu/units.yml +19 -0
- data/resources/custom/locales/fa/units.yml +15 -0
- data/resources/custom/locales/fi/units.yml +19 -0
- data/resources/custom/locales/fil/units.yml +19 -0
- data/resources/custom/locales/fr/units.yml +19 -0
- data/resources/custom/locales/he/units.yml +19 -0
- data/resources/custom/locales/hi/units.yml +19 -0
- data/resources/custom/locales/hu/units.yml +15 -0
- data/resources/custom/locales/id/units.yml +15 -0
- data/resources/custom/locales/it/units.yml +19 -0
- data/resources/custom/locales/ja/units.yml +15 -0
- data/resources/custom/locales/ko/units.yml +15 -0
- data/resources/custom/locales/ms/units.yml +15 -0
- data/resources/custom/locales/nb/units.yml +19 -0
- data/resources/custom/locales/nl/units.yml +19 -0
- data/resources/custom/locales/pl/units.yml +23 -0
- data/resources/custom/locales/pt/units.yml +19 -0
- data/resources/custom/locales/ru/units.yml +27 -0
- data/resources/custom/locales/sv/units.yml +19 -0
- data/resources/custom/locales/th/units.yml +15 -0
- data/resources/custom/locales/tr/units.yml +15 -0
- data/resources/custom/locales/uk/units.yml +27 -0
- data/resources/custom/locales/ur/units.yml +19 -0
- data/resources/custom/locales/zh-Hant/units.yml +15 -0
- data/resources/custom/locales/zh/units.yml +15 -0
- data/resources/locales/af/units.yml +112 -65
- data/resources/locales/ar/units.yml +196 -126
- data/resources/locales/ca/units.yml +112 -70
- data/resources/locales/cs/units.yml +140 -91
- data/resources/locales/da/units.yml +98 -56
- data/resources/locales/de/units.yml +112 -70
- data/resources/locales/el/units.yml +119 -84
- data/resources/locales/en/units.yml +84 -42
- data/resources/locales/es/units.yml +112 -70
- data/resources/locales/eu/units.yml +105 -68
- data/resources/locales/fa/units.yml +98 -63
- data/resources/locales/fi/units.yml +112 -70
- data/resources/locales/fil/units.yml +98 -56
- data/resources/locales/fr/units.yml +112 -70
- data/resources/locales/he/units.yml +98 -56
- data/resources/locales/hi/units.yml +98 -56
- data/resources/locales/hu/units.yml +84 -49
- data/resources/locales/id/units.yml +84 -49
- data/resources/locales/it/units.yml +98 -56
- data/resources/locales/ja/units.yml +84 -49
- data/resources/locales/ko/units.yml +84 -49
- data/resources/locales/ms/units.yml +112 -63
- data/resources/locales/nb/units.yml +106 -64
- data/resources/locales/nl/units.yml +98 -56
- data/resources/locales/pl/units.yml +181 -112
- data/resources/locales/pt/units.yml +112 -70
- data/resources/locales/ru/units.yml +168 -112
- data/resources/locales/sv/units.yml +112 -70
- data/resources/locales/th/units.yml +84 -49
- data/resources/locales/tr/units.yml +84 -49
- data/resources/locales/uk/units.yml +168 -112
- data/resources/locales/ur/units.yml +112 -63
- data/resources/locales/zh-Hant/units.yml +84 -49
- data/resources/locales/zh/units.yml +84 -49
- data/spec/collation/collation_spec.rb +1 -1
- data/spec/collation/collator_spec.rb +120 -48
- data/spec/collation/sort_key_builder_spec.rb +80 -0
- data/spec/collation/tailoring_spec.rb +137 -0
- data/spec/collation/tailoring_tests/af.txt +321 -0
- data/spec/collation/tailoring_tests/ar.txt +188 -0
- data/spec/collation/tailoring_tests/ca.txt +446 -0
- data/spec/collation/tailoring_tests/cs.txt +273 -0
- data/spec/collation/tailoring_tests/da.txt +293 -0
- data/spec/collation/tailoring_tests/de.txt +414 -0
- data/spec/collation/tailoring_tests/el.txt +228 -0
- data/spec/collation/tailoring_tests/en.txt +399 -0
- data/spec/collation/tailoring_tests/es.txt +402 -0
- data/spec/collation/tailoring_tests/eu.txt +183 -0
- data/spec/collation/tailoring_tests/fa.txt +263 -0
- data/spec/collation/tailoring_tests/fi.txt +389 -0
- data/spec/collation/tailoring_tests/fil.txt +279 -0
- data/spec/collation/tailoring_tests/fr.txt +363 -0
- data/spec/collation/tailoring_tests/he.txt +167 -0
- data/spec/collation/tailoring_tests/hi.txt +230 -0
- data/spec/collation/tailoring_tests/hu.txt +773 -0
- data/spec/collation/tailoring_tests/id.txt +171 -0
- data/spec/collation/tailoring_tests/it.txt +231 -0
- data/spec/collation/tailoring_tests/ja.txt +4287 -0
- data/spec/collation/tailoring_tests/ko.txt +1761 -0
- data/spec/collation/tailoring_tests/ms.txt +531 -0
- data/spec/collation/tailoring_tests/nb.txt +375 -0
- data/spec/collation/tailoring_tests/nl.txt +273 -0
- data/spec/collation/tailoring_tests/pl.txt +225 -0
- data/spec/collation/tailoring_tests/pt.txt +405 -0
- data/spec/collation/tailoring_tests/ru.txt +213 -0
- data/spec/collation/tailoring_tests/sv.txt +353 -0
- data/spec/collation/tailoring_tests/th.txt +239 -0
- data/spec/collation/tailoring_tests/tr.txt +414 -0
- data/spec/collation/tailoring_tests/uk.txt +218 -0
- data/spec/collation/tailoring_tests/ur.txt +284 -0
- data/spec/collation/tailoring_tests/zh-Hant.txt +626 -0
- data/spec/collation/tailoring_tests/zh.txt +717 -0
- data/spec/collation/trie_builder_spec.rb +131 -51
- data/spec/collation/trie_spec.rb +301 -26
- data/spec/collation/trie_with_fallback_spec.rb +41 -0
- data/spec/core_ext/array_spec.rb +46 -3
- data/spec/core_ext/calendars/date_spec.rb +24 -24
- data/spec/core_ext/calendars/datetime_spec.rb +7 -0
- data/spec/core_ext/calendars/time_spec.rb +2 -2
- data/spec/formatters/calendars/timespan_formatter_spec.rb +47 -18
- data/spec/formatters/plurals/rules_spec.rb +3 -11
- data/spec/readme_spec.rb +15 -15
- data/spec/resources/loader_spec.rb +94 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/tokenizers/calendars/timespan_tokenizer_spec.rb +1 -1
- data/spec/twitter_cldr_spec.rb +3 -3
- data/spec/utils_spec.rb +38 -0
- data/twitter_cldr.gemspec +25 -0
- metadata +156 -110
- data/spec/collation/sort_key_spec.rb +0 -56
- 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
|