ember-rails-i18n 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +339 -0
  5. data/README.md +64 -0
  6. data/Rakefile +1 -0
  7. data/ember-rails-i18n.gemspec +26 -0
  8. data/lib/ember-rails-i18n.rb +15 -0
  9. data/lib/ember-rails-i18n/helper.rb +29 -0
  10. data/lib/ember-rails-i18n/version.rb +3 -0
  11. data/lib/javascripts/moment.js +2489 -0
  12. data/lib/javascripts/moment_locale/ar-ma.js +56 -0
  13. data/lib/javascripts/moment_locale/ar.js +56 -0
  14. data/lib/javascripts/moment_locale/bg.js +86 -0
  15. data/lib/javascripts/moment_locale/br.js +107 -0
  16. data/lib/javascripts/moment_locale/bs.js +139 -0
  17. data/lib/javascripts/moment_locale/ca.js +66 -0
  18. data/lib/javascripts/moment_locale/cs.js +155 -0
  19. data/lib/javascripts/moment_locale/cv.js +59 -0
  20. data/lib/javascripts/moment_locale/cy.js +77 -0
  21. data/lib/javascripts/moment_locale/da.js +56 -0
  22. data/lib/javascripts/moment_locale/de.js +71 -0
  23. data/lib/javascripts/moment_locale/el.js +79 -0
  24. data/lib/javascripts/moment_locale/en-au.js +62 -0
  25. data/lib/javascripts/moment_locale/en-ca.js +59 -0
  26. data/lib/javascripts/moment_locale/en-gb.js +63 -0
  27. data/lib/javascripts/moment_locale/eo.js +65 -0
  28. data/lib/javascripts/moment_locale/es.js +75 -0
  29. data/lib/javascripts/moment_locale/et.js +76 -0
  30. data/lib/javascripts/moment_locale/eu.js +60 -0
  31. data/lib/javascripts/moment_locale/fa.js +97 -0
  32. data/lib/javascripts/moment_locale/fi.js +103 -0
  33. data/lib/javascripts/moment_locale/fo.js +56 -0
  34. data/lib/javascripts/moment_locale/fr-ca.js +54 -0
  35. data/lib/javascripts/moment_locale/fr.js +58 -0
  36. data/lib/javascripts/moment_locale/gl.js +71 -0
  37. data/lib/javascripts/moment_locale/he.js +77 -0
  38. data/lib/javascripts/moment_locale/hi.js +105 -0
  39. data/lib/javascripts/moment_locale/hr.js +140 -0
  40. data/lib/javascripts/moment_locale/hu.js +105 -0
  41. data/lib/javascripts/moment_locale/hy-am.js +113 -0
  42. data/lib/javascripts/moment_locale/id.js +67 -0
  43. data/lib/javascripts/moment_locale/is.js +124 -0
  44. data/lib/javascripts/moment_locale/it.js +59 -0
  45. data/lib/javascripts/moment_locale/ja.js +58 -0
  46. data/lib/javascripts/moment_locale/ka.js +108 -0
  47. data/lib/javascripts/moment_locale/km.js +55 -0
  48. data/lib/javascripts/moment_locale/ko.js +63 -0
  49. data/lib/javascripts/moment_locale/lb.js +160 -0
  50. data/lib/javascripts/moment_locale/lt.js +118 -0
  51. data/lib/javascripts/moment_locale/lv.js +77 -0
  52. data/lib/javascripts/moment_locale/mk.js +86 -0
  53. data/lib/javascripts/moment_locale/ml.js +64 -0
  54. data/lib/javascripts/moment_locale/mr.js +104 -0
  55. data/lib/javascripts/moment_locale/ms-my.js +66 -0
  56. data/lib/javascripts/moment_locale/nb.js +57 -0
  57. data/lib/javascripts/moment_locale/ne.js +105 -0
  58. data/lib/javascripts/moment_locale/nl.js +67 -0
  59. data/lib/javascripts/moment_locale/nn.js +56 -0
  60. data/lib/javascripts/moment_locale/pl.js +98 -0
  61. data/lib/javascripts/moment_locale/pt-br.js +56 -0
  62. data/lib/javascripts/moment_locale/pt.js +60 -0
  63. data/lib/javascripts/moment_locale/ro.js +72 -0
  64. data/lib/javascripts/moment_locale/ru.js +163 -0
  65. data/lib/javascripts/moment_locale/sk.js +156 -0
  66. data/lib/javascripts/moment_locale/sl.js +144 -0
  67. data/lib/javascripts/moment_locale/sq.js +61 -0
  68. data/lib/javascripts/moment_locale/sr-cyr.js +106 -0
  69. data/lib/javascripts/moment_locale/sr.js +106 -0
  70. data/lib/javascripts/moment_locale/sv.js +63 -0
  71. data/lib/javascripts/moment_locale/ta.js +112 -0
  72. data/lib/javascripts/moment_locale/th.js +58 -0
  73. data/lib/javascripts/moment_locale/tl-ph.js +58 -0
  74. data/lib/javascripts/moment_locale/tr.js +93 -0
  75. data/lib/javascripts/moment_locale/tzm-la.js +55 -0
  76. data/lib/javascripts/moment_locale/tzm.js +55 -0
  77. data/lib/javascripts/moment_locale/uk.js +157 -0
  78. data/lib/javascripts/moment_locale/uz.js +55 -0
  79. data/lib/javascripts/moment_locale/vi.js +62 -0
  80. data/lib/javascripts/moment_locale/zh-cn.js +108 -0
  81. data/lib/javascripts/moment_locale/zh-tw.js +84 -0
  82. data/vendor/assets/javascripts/locales/i18n.js +598 -0
  83. data/vendor/assets/javascripts/locales/test.js.erb +3 -0
  84. metadata +182 -0
@@ -0,0 +1,84 @@
1
+ // moment.js language configuration
2
+ // language : traditional chinese (zh-tw)
3
+ // author : Ben : https://github.com/ben-lin
4
+
5
+ (function (factory) {
6
+ if (typeof define === 'function' && define.amd) {
7
+ define(['moment'], factory); // AMD
8
+ } else if (typeof exports === 'object') {
9
+ module.exports = factory(require('../moment')); // Node
10
+ } else {
11
+ factory(window.moment); // Browser global
12
+ }
13
+ }(function (moment) {
14
+ return moment.lang('zh-tw', {
15
+ months : "一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),
16
+ monthsShort : "1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),
17
+ weekdays : "星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),
18
+ weekdaysShort : "週日_週一_週二_週三_週四_週五_週六".split("_"),
19
+ weekdaysMin : "日_一_二_三_四_五_六".split("_"),
20
+ longDateFormat : {
21
+ LT : "Ah點mm",
22
+ L : "YYYY年MMMD日",
23
+ LL : "YYYY年MMMD日",
24
+ LLL : "YYYY年MMMD日LT",
25
+ LLLL : "YYYY年MMMD日ddddLT",
26
+ l : "YYYY年MMMD日",
27
+ ll : "YYYY年MMMD日",
28
+ lll : "YYYY年MMMD日LT",
29
+ llll : "YYYY年MMMD日ddddLT"
30
+ },
31
+ meridiem : function (hour, minute, isLower) {
32
+ var hm = hour * 100 + minute;
33
+ if (hm < 900) {
34
+ return "早上";
35
+ } else if (hm < 1130) {
36
+ return "上午";
37
+ } else if (hm < 1230) {
38
+ return "中午";
39
+ } else if (hm < 1800) {
40
+ return "下午";
41
+ } else {
42
+ return "晚上";
43
+ }
44
+ },
45
+ calendar : {
46
+ sameDay : '[今天]LT',
47
+ nextDay : '[明天]LT',
48
+ nextWeek : '[下]ddddLT',
49
+ lastDay : '[昨天]LT',
50
+ lastWeek : '[上]ddddLT',
51
+ sameElse : 'L'
52
+ },
53
+ ordinal : function (number, period) {
54
+ switch (period) {
55
+ case "d" :
56
+ case "D" :
57
+ case "DDD" :
58
+ return number + "日";
59
+ case "M" :
60
+ return number + "月";
61
+ case "w" :
62
+ case "W" :
63
+ return number + "週";
64
+ default :
65
+ return number;
66
+ }
67
+ },
68
+ relativeTime : {
69
+ future : "%s內",
70
+ past : "%s前",
71
+ s : "幾秒",
72
+ m : "一分鐘",
73
+ mm : "%d分鐘",
74
+ h : "一小時",
75
+ hh : "%d小時",
76
+ d : "一天",
77
+ dd : "%d天",
78
+ M : "一個月",
79
+ MM : "%d個月",
80
+ y : "一年",
81
+ yy : "%d年"
82
+ }
83
+ });
84
+ }));
@@ -0,0 +1,598 @@
1
+ /*global I18n:true */
2
+
3
+ // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
4
+ if (!Array.prototype.indexOf) {
5
+ Array.prototype.indexOf = function (searchElement, fromIndex) {
6
+ if ( this === undefined || this === null ) {
7
+ throw new TypeError( '"this" is null or not defined' );
8
+ }
9
+
10
+ var length = this.length >>> 0; // Hack to convert object.length to a UInt32
11
+
12
+ fromIndex = +fromIndex || 0;
13
+
14
+ if (Math.abs(fromIndex) === Infinity) {
15
+ fromIndex = 0;
16
+ }
17
+
18
+ if (fromIndex < 0) {
19
+ fromIndex += length;
20
+ if (fromIndex < 0) {
21
+ fromIndex = 0;
22
+ }
23
+ }
24
+
25
+ for (;fromIndex < length; fromIndex++) {
26
+ if (this[fromIndex] === searchElement) {
27
+ return fromIndex;
28
+ }
29
+ }
30
+
31
+ return -1;
32
+ };
33
+ }
34
+
35
+ // Instantiate the object
36
+ var I18n = I18n || {};
37
+
38
+ // Set default locale to english
39
+ I18n.defaultLocale = "en";
40
+
41
+ // Set default handling of translation fallbacks to false
42
+ I18n.fallbacks = false;
43
+
44
+ // Set default separator
45
+ I18n.defaultSeparator = ".";
46
+
47
+ // Set current locale to null
48
+ I18n.locale = null;
49
+
50
+ // Set the placeholder format. Accepts `{{placeholder}}` and `%{placeholder}`.
51
+ I18n.PLACEHOLDER = /(?:\{\{|%\{)(.*?)(?:\}\}?)/gm;
52
+
53
+ I18n.fallbackRules = {};
54
+
55
+ I18n.pluralizationRules = {
56
+ en: function(n) {
57
+ return n === 0 ? ["zero", "none", "other"] : n === 1 ? "one" : "other";
58
+ },
59
+ "zh_CN": function(n) {
60
+ return n === 0 ? ["zero", "none", "other"] : "other";
61
+ },
62
+ "zh_TW": function(n) {
63
+ return n === 0 ? ["zero", "none", "other"] : "other";
64
+ }
65
+ };
66
+
67
+ I18n.getFallbacks = function(locale) {
68
+ if (locale === I18n.defaultLocale) {
69
+ return [];
70
+ } else if (!I18n.fallbackRules[locale]) {
71
+ var rules = [],
72
+ components = locale.split("-");
73
+
74
+ for (var l = 1; l < components.length; l++) {
75
+ rules.push(components.slice(0, l).join("-"));
76
+ }
77
+
78
+ rules.push(I18n.defaultLocale);
79
+
80
+ I18n.fallbackRules[locale] = rules;
81
+ }
82
+
83
+ return I18n.fallbackRules[locale];
84
+ };
85
+
86
+ I18n.isValidNode = function(obj, node, undefined) {
87
+ return obj[node] !== null && obj[node] !== undefined;
88
+ };
89
+
90
+ I18n.lookup = function(scope, options) {
91
+ options = options || {};
92
+ var lookupInitialScope = scope,
93
+ translations = this.prepareOptions(I18n.translations),
94
+ locale = options.locale || I18n.currentLocale(),
95
+ messages = translations[locale] || {},
96
+ currentScope;
97
+
98
+ options = this.prepareOptions(options);
99
+
100
+ if (typeof scope === "object") {
101
+ scope = scope.join(this.defaultSeparator);
102
+ }
103
+
104
+ if (options.scope) {
105
+ scope = options.scope.toString() + this.defaultSeparator + scope;
106
+ }
107
+
108
+ scope = scope.split(this.defaultSeparator);
109
+
110
+ while (messages && scope.length > 0) {
111
+ currentScope = scope.shift();
112
+ messages = messages[currentScope];
113
+ }
114
+
115
+ if (!messages) {
116
+ if (I18n.fallbacks) {
117
+ var fallbacks = this.getFallbacks(locale);
118
+ for (var fallback = 0; fallback < fallbacks.length; fallbacks++) {
119
+ messages = I18n.lookup(lookupInitialScope, this.prepareOptions({locale: fallbacks[fallback]}, options));
120
+ if (messages) {
121
+ break;
122
+ }
123
+ }
124
+ }
125
+
126
+ if (!messages && this.isValidNode(options, "defaultValue")) {
127
+ messages = options.defaultValue;
128
+ }
129
+ }
130
+
131
+ return messages;
132
+ };
133
+
134
+ // Merge serveral hash options, checking if value is set before
135
+ // overwriting any value. The precedence is from left to right.
136
+ //
137
+ // I18n.prepareOptions({name: "John Doe"}, {name: "Mary Doe", role: "user"});
138
+ // #=> {name: "John Doe", role: "user"}
139
+ //
140
+ I18n.prepareOptions = function() {
141
+ var options = {},
142
+ opts,
143
+ count = arguments.length;
144
+
145
+ for (var i = 0; i < count; i++) {
146
+ opts = arguments[i];
147
+
148
+ if (!opts) {
149
+ continue;
150
+ }
151
+
152
+ for (var key in opts) {
153
+ if (!this.isValidNode(options, key)) {
154
+ options[key] = opts[key];
155
+ }
156
+ }
157
+ }
158
+
159
+ return options;
160
+ };
161
+
162
+ I18n.interpolate = function(message, options) {
163
+ options = this.prepareOptions(options);
164
+ var matches = message.match(this.PLACEHOLDER),
165
+ placeholder,
166
+ value,
167
+ name;
168
+
169
+ if (!matches) {
170
+ return message;
171
+ }
172
+
173
+ for (var i = 0; placeholder = matches[i]; i++) {
174
+ name = placeholder.replace(this.PLACEHOLDER, "$1");
175
+
176
+ value = options[name];
177
+
178
+ if (!this.isValidNode(options, name)) {
179
+ value = "[missing " + placeholder + " value]";
180
+ }
181
+
182
+ var regex = new RegExp(placeholder.replace(/\{/gm, "\\{").replace(/\}/gm, "\\}"));
183
+ message = message.replace(regex, value);
184
+ }
185
+
186
+ return message;
187
+ };
188
+
189
+ I18n.translate = function(scope, options) {
190
+ options = this.prepareOptions(options);
191
+ var translation = this.lookup(scope, options);
192
+
193
+ try {
194
+ if (typeof translation === "object") {
195
+ if (typeof options.count === "number") {
196
+ return this.pluralize(options.count, scope, options);
197
+ } else {
198
+ return translation;
199
+ }
200
+ } else {
201
+ return this.interpolate(translation, options);
202
+ }
203
+ } catch (error) {
204
+ return this.missingTranslation(scope);
205
+ }
206
+ };
207
+
208
+ I18n.localize = function(scope, value) {
209
+ switch (scope) {
210
+ case "currency":
211
+ return this.toCurrency(value);
212
+ case "number":
213
+ scope = this.lookup("number.format");
214
+ return this.toNumber(value, scope);
215
+ case "percentage":
216
+ return this.toPercentage(value);
217
+ default:
218
+ if (scope.match(/^(date|time)/)) {
219
+ return this.toTime(scope, value);
220
+ } else {
221
+ return value.toString();
222
+ }
223
+ }
224
+ };
225
+
226
+ I18n.parseDate = function(date) {
227
+ var matches, convertedDate;
228
+
229
+ // we have a date, so just return it.
230
+ if (typeof date === "object") {
231
+ return date;
232
+ }
233
+
234
+ // it matches the following formats:
235
+ // yyyy-mm-dd
236
+ // yyyy-mm-dd[ T]hh:mm::ss
237
+ // yyyy-mm-dd[ T]hh:mm::ss
238
+ // yyyy-mm-dd[ T]hh:mm::ssZ
239
+ // yyyy-mm-dd[ T]hh:mm::ss+0000
240
+ //
241
+ matches = date.toString().match(/(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2}):(\d{2}))?(Z|\+0000)?/);
242
+
243
+ if (matches) {
244
+ for (var i = 1; i <= 6; i++) {
245
+ matches[i] = parseInt(matches[i], 10) || 0;
246
+ }
247
+
248
+ // month starts on 0
249
+ matches[2] -= 1;
250
+
251
+ if (matches[7]) {
252
+ convertedDate = new Date(Date.UTC(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6]));
253
+ } else {
254
+ convertedDate = new Date(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6]);
255
+ }
256
+ } else if (typeof date === "number") {
257
+ // UNIX timestamp
258
+ convertedDate = new Date();
259
+ convertedDate.setTime(date);
260
+ } else if (date.match(/\d+ \d+:\d+:\d+ [+-]\d+ \d+/)) {
261
+ // a valid javascript format with timezone info
262
+ convertedDate = new Date();
263
+ convertedDate.setTime(Date.parse(date));
264
+ } else {
265
+ // an arbitrary javascript string
266
+ convertedDate = new Date();
267
+ convertedDate.setTime(Date.parse(date));
268
+ }
269
+
270
+ return convertedDate;
271
+ };
272
+
273
+ I18n.toTime = function(scope, d) {
274
+ var date = this.parseDate(d),
275
+ format = this.lookup(scope);
276
+
277
+ if (date.toString().match(/invalid/i)) {
278
+ return date.toString();
279
+ }
280
+
281
+ if (!format) {
282
+ return date.toString();
283
+ }
284
+
285
+ return this.strftime(date, format);
286
+ };
287
+
288
+ I18n.strftime = function(date, format) {
289
+ var options = this.lookup("date");
290
+
291
+ if (!options) {
292
+ return date.toString();
293
+ }
294
+
295
+ options.meridian = options.meridian || ["AM", "PM"];
296
+
297
+ var weekDay = date.getDay(),
298
+ day = date.getDate(),
299
+ year = date.getFullYear(),
300
+ month = date.getMonth() + 1,
301
+ hour = date.getHours(),
302
+ hour12 = hour,
303
+ meridian = hour > 11 ? 1 : 0,
304
+ secs = date.getSeconds(),
305
+ mins = date.getMinutes(),
306
+ offset = date.getTimezoneOffset(),
307
+ absOffsetHours = Math.floor(Math.abs(offset / 60)),
308
+ absOffsetMinutes = Math.abs(offset) - (absOffsetHours * 60),
309
+ timezoneoffset = (offset > 0 ? "-" : "+") + (absOffsetHours.toString().length < 2 ? "0" + absOffsetHours : absOffsetHours) + (absOffsetMinutes.toString().length < 2 ? "0" + absOffsetMinutes : absOffsetMinutes);
310
+
311
+ if (hour12 > 12) {
312
+ hour12 = hour12 - 12;
313
+ } else if (hour12 === 0) {
314
+ hour12 = 12;
315
+ }
316
+
317
+ var padding = function(n) {
318
+ var s = "0" + n.toString();
319
+ return s.substr(s.length - 2);
320
+ };
321
+
322
+ var f = format;
323
+ f = f.replace("%a", options.abbr_day_names[weekDay]);
324
+ f = f.replace("%A", options.day_names[weekDay]);
325
+ f = f.replace("%b", options.abbr_month_names[month]);
326
+ f = f.replace("%B", options.month_names[month]);
327
+ f = f.replace("%d", padding(day));
328
+ f = f.replace("%e", day);
329
+ f = f.replace("%-d", day);
330
+ f = f.replace("%H", padding(hour));
331
+ f = f.replace("%-H", hour);
332
+ f = f.replace("%I", padding(hour12));
333
+ f = f.replace("%-I", hour12);
334
+ f = f.replace("%m", padding(month));
335
+ f = f.replace("%-m", month);
336
+ f = f.replace("%M", padding(mins));
337
+ f = f.replace("%-M", mins);
338
+ f = f.replace("%p", options.meridian[meridian]);
339
+ f = f.replace("%S", padding(secs));
340
+ f = f.replace("%-S", secs);
341
+ f = f.replace("%w", weekDay);
342
+ f = f.replace("%y", padding(year));
343
+ f = f.replace("%-y", padding(year).replace(/^0+/, ""));
344
+ f = f.replace("%Y", year);
345
+ f = f.replace("%z", timezoneoffset);
346
+
347
+ return f;
348
+ };
349
+
350
+ I18n.toNumber = function(number, options) {
351
+ options = this.prepareOptions(
352
+ options,
353
+ this.lookup("number.format"),
354
+ {precision: 3, separator: ".", delimiter: ",", strip_insignificant_zeros: false}
355
+ );
356
+
357
+ var negative = number < 0,
358
+ string = Math.abs(number).toFixed(options.precision).toString(),
359
+ parts = string.split("."),
360
+ precision,
361
+ buffer = [],
362
+ formattedNumber;
363
+
364
+ number = parts[0];
365
+ precision = parts[1];
366
+
367
+ while (number.length > 0) {
368
+ buffer.unshift(number.substr(Math.max(0, number.length - 3), 3));
369
+ number = number.substr(0, number.length -3);
370
+ }
371
+
372
+ formattedNumber = buffer.join(options.delimiter);
373
+
374
+ if (options.precision > 0) {
375
+ formattedNumber += options.separator + parts[1];
376
+ }
377
+
378
+ if (negative) {
379
+ formattedNumber = "-" + formattedNumber;
380
+ }
381
+
382
+ if (options.strip_insignificant_zeros) {
383
+ var regex = {
384
+ separator: new RegExp(options.separator.replace(/\./, "\\.") + "$"),
385
+ zeros: /0+$/
386
+ };
387
+
388
+ formattedNumber = formattedNumber
389
+ .replace(regex.zeros, "")
390
+ .replace(regex.separator, "")
391
+ ;
392
+ }
393
+
394
+ return formattedNumber;
395
+ };
396
+
397
+ I18n.toCurrency = function(number, options) {
398
+ options = this.prepareOptions(
399
+ options,
400
+ this.lookup("number.currency.format"),
401
+ this.lookup("number.format"),
402
+ {unit: "$", precision: 2, format: "%u%n", delimiter: ",", separator: "."}
403
+ );
404
+
405
+ number = this.toNumber(number, options);
406
+ number = options.format
407
+ .replace("%u", options.unit)
408
+ .replace("%n", number)
409
+ ;
410
+
411
+ return number;
412
+ };
413
+
414
+ I18n.toHumanSize = function(number, options) {
415
+ var kb = 1024,
416
+ size = number,
417
+ iterations = 0,
418
+ unit,
419
+ precision;
420
+
421
+ while (size >= kb && iterations < 4) {
422
+ size = size / kb;
423
+ iterations += 1;
424
+ }
425
+
426
+ if (iterations === 0) {
427
+ unit = this.t("number.human.storage_units.units.byte", {count: size});
428
+ precision = 0;
429
+ } else {
430
+ unit = this.t("number.human.storage_units.units." + [null, "kb", "mb", "gb", "tb"][iterations]);
431
+ precision = (size - Math.floor(size) === 0) ? 0 : 1;
432
+ }
433
+
434
+ options = this.prepareOptions(
435
+ options,
436
+ {precision: precision, format: "%n%u", delimiter: ""}
437
+ );
438
+
439
+ number = this.toNumber(size, options);
440
+ number = options.format
441
+ .replace("%u", unit)
442
+ .replace("%n", number)
443
+ ;
444
+
445
+ return number;
446
+ };
447
+
448
+ I18n.toPercentage = function(number, options) {
449
+ options = this.prepareOptions(
450
+ options,
451
+ this.lookup("number.percentage.format"),
452
+ this.lookup("number.format"),
453
+ {precision: 3, separator: ".", delimiter: ""}
454
+ );
455
+
456
+ number = this.toNumber(number, options);
457
+ return number + "%";
458
+ };
459
+
460
+ I18n.pluralizer = function(locale) {
461
+ var pluralizer = this.pluralizationRules[locale];
462
+ if (pluralizer !== undefined) return pluralizer;
463
+ return this.pluralizationRules["en"];
464
+ };
465
+
466
+ I18n.findAndTranslateValidNode = function(keys, translation) {
467
+ for (var i = 0; i < keys.length; i++) {
468
+ var key = keys[i];
469
+ if (this.isValidNode(translation, key)) return translation[key];
470
+ }
471
+ return null;
472
+ };
473
+
474
+ I18n.pluralize = function(count, scope, options) {
475
+ var translation;
476
+
477
+ try { translation = this.lookup(scope, options); } catch (error) {}
478
+ if (!translation) { return this.missingTranslation(scope); }
479
+
480
+ options = this.prepareOptions(options);
481
+ options.count = count.toString();
482
+
483
+ var pluralizer = this.pluralizer(this.currentLocale());
484
+ var key = pluralizer(Math.abs(count));
485
+ var keys = ((typeof key === "object") && (key instanceof Array)) ? key : [key];
486
+
487
+ var message = this.findAndTranslateValidNode(keys, translation);
488
+ if (message == null) message = this.missingTranslation(scope, keys[0]);
489
+
490
+ return this.interpolate(message, options);
491
+ };
492
+
493
+ I18n.missingTranslation = function(scope, key) {
494
+ var message = '[' + this.currentLocale() + "." + scope;
495
+ if (key) { message += "." + key; }
496
+ return message + ']';
497
+ };
498
+
499
+ I18n.currentLocale = function() {
500
+ return (I18n.locale || I18n.defaultLocale);
501
+ };
502
+
503
+ // shortcuts
504
+ I18n.t = I18n.translate;
505
+ I18n.l = I18n.localize;
506
+ I18n.p = I18n.pluralize;
507
+
508
+ /**
509
+ Default format for storage units
510
+ **/
511
+ var oldI18ntoHumanSize = I18n.toHumanSize;
512
+ I18n.toHumanSize = function(number, options) {
513
+ options = options || {};
514
+ options.format = I18n.t("number.human.storage_units.format");
515
+ return oldI18ntoHumanSize.apply(this, [number, options]);
516
+ };
517
+
518
+ /**
519
+ * Ember I18n helpers
520
+ */
521
+ if (typeof(Ember) !== "undefined") {
522
+ I18n.normalizeHash = function(hash, hashTypes) {
523
+ for (var prop in hash) {
524
+ if (hashTypes[prop] === 'ID') {
525
+ hash[prop + 'Binding'] = hash[prop];
526
+ delete hash[prop];
527
+ }
528
+ }
529
+ };
530
+
531
+ Ember.View.reopenClass({
532
+ registerHelper: function(helperName, helperClass) {
533
+ Ember.Handlebars.registerHelper(helperName, function(options) {
534
+ var hash = options.hash,
535
+ types = options.hashTypes;
536
+
537
+ I18n.normalizeHash(hash, types);
538
+ return Ember.Handlebars.helpers.view.call(this, helperClass, options);
539
+ });
540
+ },
541
+
542
+ renderIfChanged: function() {
543
+ var args = Array.prototype.slice.call(arguments, 0);
544
+ args.unshift(function () { this.rerender(); });
545
+ return Ember.observer.apply(this, args);
546
+ }
547
+ });
548
+
549
+ /**
550
+ Look up a translation for an i18n key in our dictionary.
551
+
552
+ @method i18n
553
+ @for Handlebars
554
+ **/
555
+ Ember.Handlebars.registerHelper('i18n', function(property, options) {
556
+ // Resolve any properties
557
+ var params = options.hash,
558
+ self = this;
559
+
560
+ _.each(params, function(value, key) {
561
+ params[key] = Em.Handlebars.get(self, value, options);
562
+ });
563
+
564
+ return I18n.t(property, params);
565
+ });
566
+
567
+ /**
568
+ Bound version of i18n helper.
569
+ **/
570
+ Ember.Handlebars.registerBoundHelper("boundI18n", function(property, options) {
571
+ return new Handlebars.SafeString(I18n.t(property, options.hash));
572
+ });
573
+
574
+ /**
575
+ Set up an i18n binding that will update as a count changes, complete with pluralization.
576
+
577
+ @method countI18n
578
+ @for Handlebars
579
+ **/
580
+ Ember.Handlebars.registerHelper('countI18n', function(key, options) {
581
+ var view = Ember.View.extend({
582
+ tagName: 'span',
583
+ shouldRerender: Ember.View.renderIfChanged('count'),
584
+
585
+ render: function(buffer) {
586
+ buffer.push(I18n.t(key, { count: this.get('count') }));
587
+ }
588
+
589
+ });
590
+ return Ember.Handlebars.helpers.view.call(this, view, options);
591
+ });
592
+
593
+ if (Ember.EXTEND_PROTOTYPES) {
594
+ String.prototype.i18n = function(options) {
595
+ return I18n.t(String(this), options);
596
+ };
597
+ }
598
+ }