ember-rails-i18n 0.0.1

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 (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
+ }