i18n-js-pika 3.0.0.rc6
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.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/CHANGELOG.md +13 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +52 -0
- data/README.md +326 -0
- data/Rakefile +13 -0
- data/app/assets/javascripts/i18n/filtered.js.erb +2 -0
- data/app/assets/javascripts/i18n/shims.js +93 -0
- data/app/assets/javascripts/i18n/translations.js +3 -0
- data/app/assets/javascripts/i18n.js +690 -0
- data/i18n-js.gemspec +27 -0
- data/lib/i18n/js/engine.rb +22 -0
- data/lib/i18n/js/middleware.rb +59 -0
- data/lib/i18n/js/version.rb +12 -0
- data/lib/i18n/js.rb +162 -0
- data/lib/i18n-js.rb +1 -0
- data/lib/tasks/export.rake +8 -0
- data/package.json +11 -0
- data/spec/fixtures/custom_path.yml +4 -0
- data/spec/fixtures/default.yml +4 -0
- data/spec/fixtures/js_file_per_locale.yml +3 -0
- data/spec/fixtures/locales.yml +76 -0
- data/spec/fixtures/multiple_conditions.yml +5 -0
- data/spec/fixtures/multiple_files.yml +6 -0
- data/spec/fixtures/no_config.yml +2 -0
- data/spec/fixtures/no_scope.yml +3 -0
- data/spec/fixtures/simple_scope.yml +4 -0
- data/spec/i18n_js_spec.rb +139 -0
- data/spec/js/currency.spec.js +60 -0
- data/spec/js/current_locale.spec.js +19 -0
- data/spec/js/dates.spec.js +222 -0
- data/spec/js/defaults.spec.js +23 -0
- data/spec/js/interpolation.spec.js +28 -0
- data/spec/js/jasmine/MIT.LICENSE +20 -0
- data/spec/js/jasmine/jasmine-html.js +190 -0
- data/spec/js/jasmine/jasmine.css +166 -0
- data/spec/js/jasmine/jasmine.js +2476 -0
- data/spec/js/jasmine/jasmine_favicon.png +0 -0
- data/spec/js/localization.spec.js +41 -0
- data/spec/js/numbers.spec.js +142 -0
- data/spec/js/placeholder.spec.js +24 -0
- data/spec/js/pluralization.spec.js +105 -0
- data/spec/js/prepare_options.spec.js +41 -0
- data/spec/js/specs.html +46 -0
- data/spec/js/translate.spec.js +120 -0
- data/spec/js/translations.js +120 -0
- data/spec/spec_helper.rb +41 -0
- metadata +196 -0
@@ -0,0 +1,690 @@
|
|
1
|
+
// I18n.js
|
2
|
+
// =======
|
3
|
+
//
|
4
|
+
// This small library provides the Rails I18n API on the Javascript.
|
5
|
+
// You don't actually have to use Rails (or even Ruby) to use I18n.js.
|
6
|
+
// Just make sure you export all translations in an object like this:
|
7
|
+
//
|
8
|
+
// I18n.translations.en = {
|
9
|
+
// hello: "Hello World"
|
10
|
+
// };
|
11
|
+
//
|
12
|
+
// See tests for specific formatting like numbers and dates.
|
13
|
+
//
|
14
|
+
;(function(I18n){
|
15
|
+
"use strict";
|
16
|
+
|
17
|
+
// Just cache the Array#slice function.
|
18
|
+
var slice = Array.prototype.slice;
|
19
|
+
|
20
|
+
// Apply number padding.
|
21
|
+
var padding = function(number) {
|
22
|
+
return ("0" + number.toString()).substr(-2);
|
23
|
+
};
|
24
|
+
|
25
|
+
// Set default days/months translations.
|
26
|
+
var DAYS_AND_MONTHS = {
|
27
|
+
day_names: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
|
28
|
+
, abbr_day_names: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
|
29
|
+
, month_names: [null, "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
|
30
|
+
, abbr_month_names: [null, "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
|
31
|
+
};
|
32
|
+
|
33
|
+
// Set default number format.
|
34
|
+
var NUMBER_FORMAT = {
|
35
|
+
precision: 3
|
36
|
+
, separator: "."
|
37
|
+
, delimiter: ","
|
38
|
+
, strip_insignificant_zeros: false
|
39
|
+
};
|
40
|
+
|
41
|
+
// Set default currency format.
|
42
|
+
var CURRENCY_FORMAT = {
|
43
|
+
unit: "$"
|
44
|
+
, precision: 2
|
45
|
+
, format: "%u%n"
|
46
|
+
, delimiter: ","
|
47
|
+
, separator: "."
|
48
|
+
};
|
49
|
+
|
50
|
+
// Set default percentage format.
|
51
|
+
var PERCENTAGE_FORMAT = {
|
52
|
+
precision: 3
|
53
|
+
, separator: "."
|
54
|
+
, delimiter: ""
|
55
|
+
};
|
56
|
+
|
57
|
+
// Set default size units.
|
58
|
+
var SIZE_UNITS = [null, "kb", "mb", "gb", "tb"];
|
59
|
+
|
60
|
+
// Set meridian.
|
61
|
+
var MERIDIAN = ["AM", "PM"];
|
62
|
+
|
63
|
+
I18n.reset = function() {
|
64
|
+
// Set default locale. This locale will be used when fallback is enabled and
|
65
|
+
// the translation doesn't exist in a particular locale.
|
66
|
+
this.defaultLocale = "en";
|
67
|
+
|
68
|
+
// Set the current locale to `en`.
|
69
|
+
this.locale = "en";
|
70
|
+
|
71
|
+
// Set the translation key separator.
|
72
|
+
this.defaultSeparator = ".";
|
73
|
+
|
74
|
+
// Set the placeholder format. Accepts `{{placeholder}}` and `%{placeholder}`.
|
75
|
+
this.placeholder = /(?:\{\{|%\{)(.*?)(?:\}\}?)/gm;
|
76
|
+
|
77
|
+
// Set if engine should fallback to the default locale when a translation
|
78
|
+
// is missing.
|
79
|
+
this.fallbacks = false;
|
80
|
+
|
81
|
+
// Set the default translation object.
|
82
|
+
this.translations = {};
|
83
|
+
};
|
84
|
+
|
85
|
+
// Return a list of all locales that must be tried before returning the
|
86
|
+
// missing translation message. By default, this will consider the inline option,
|
87
|
+
// current locale and fallback locale.
|
88
|
+
//
|
89
|
+
// I18n.locales.get("de-DE");
|
90
|
+
// // ["de-DE", "de", "en"]
|
91
|
+
//
|
92
|
+
// You can define custom rules for any locale. Just make sure you return a array
|
93
|
+
// containing all locales.
|
94
|
+
//
|
95
|
+
// // Default the Wookie locale to English.
|
96
|
+
// I18n.locales["wk"] = function(locale) {
|
97
|
+
// return ["en"];
|
98
|
+
// };
|
99
|
+
//
|
100
|
+
I18n.locales = {};
|
101
|
+
|
102
|
+
// Retrieve locales based on inline locale, current locale or default to
|
103
|
+
// I18n's detection.
|
104
|
+
I18n.locales.get = function(locale) {
|
105
|
+
var result = this[locale] || this[I18n.locale] || this["default"];
|
106
|
+
|
107
|
+
if (typeof(result) === "function") {
|
108
|
+
result = result(locale);
|
109
|
+
}
|
110
|
+
|
111
|
+
if (result instanceof Array === false) {
|
112
|
+
result = [result];
|
113
|
+
}
|
114
|
+
|
115
|
+
return result;
|
116
|
+
};
|
117
|
+
|
118
|
+
// The default locale list.
|
119
|
+
I18n.locales["default"] = function(locale) {
|
120
|
+
var locales = []
|
121
|
+
, list = []
|
122
|
+
, countryCode
|
123
|
+
, count
|
124
|
+
;
|
125
|
+
|
126
|
+
// Handle the inline locale option that can be provided to
|
127
|
+
// the `I18n.t` options.
|
128
|
+
if (locale) {
|
129
|
+
locales.push(locale);
|
130
|
+
}
|
131
|
+
|
132
|
+
// Add the current locale to the list.
|
133
|
+
if (!locale && I18n.locale) {
|
134
|
+
locales.push(I18n.locale);
|
135
|
+
}
|
136
|
+
|
137
|
+
// Add the default locale if fallback strategy is enabled.
|
138
|
+
if (I18n.fallbacks && I18n.defaultLocale) {
|
139
|
+
locales.push(I18n.defaultLocale);
|
140
|
+
}
|
141
|
+
|
142
|
+
// Compute each locale with its country code.
|
143
|
+
// So this will return an array containing both
|
144
|
+
// `de-DE` and `de` locales.
|
145
|
+
locales.forEach(function(locale){
|
146
|
+
countryCode = locale.split("-")[0];
|
147
|
+
|
148
|
+
if (!~list.indexOf(locale)) {
|
149
|
+
list.push(locale);
|
150
|
+
}
|
151
|
+
|
152
|
+
if (I18n.fallbacks && countryCode && countryCode !== locale && !~list.indexOf(countryCode)) {
|
153
|
+
list.push(countryCode);
|
154
|
+
}
|
155
|
+
});
|
156
|
+
|
157
|
+
// No locales set? English it is.
|
158
|
+
if (!locales.length) {
|
159
|
+
locales.push("en");
|
160
|
+
}
|
161
|
+
|
162
|
+
return list;
|
163
|
+
};
|
164
|
+
|
165
|
+
// Hold pluralization rules.
|
166
|
+
I18n.pluralization = {};
|
167
|
+
|
168
|
+
// Return the pluralizer for a specific locale.
|
169
|
+
// If no specify locale is found, then I18n's default will be used.
|
170
|
+
I18n.pluralization.get = function(locale) {
|
171
|
+
return this[locale] || this[I18n.locale] || this["default"];
|
172
|
+
};
|
173
|
+
|
174
|
+
// The default pluralizer rule.
|
175
|
+
// It detects the `zero`, `one`, and `other` scopes.
|
176
|
+
I18n.pluralization["default"] = function(count) {
|
177
|
+
switch (count) {
|
178
|
+
case 0: return ["zero", "other"];
|
179
|
+
case 1: return ["one"];
|
180
|
+
default: return ["other"];
|
181
|
+
}
|
182
|
+
};
|
183
|
+
|
184
|
+
// Reset all default attributes. This is specially useful
|
185
|
+
// while running tests.
|
186
|
+
I18n.reset();
|
187
|
+
|
188
|
+
// Return current locale. If no locale has been set, then
|
189
|
+
// the current locale will be the default locale.
|
190
|
+
I18n.currentLocale = function() {
|
191
|
+
return this.locale || this.defaultLocale;
|
192
|
+
};
|
193
|
+
|
194
|
+
// Check if value is different than undefined and null;
|
195
|
+
I18n.isSet = function(value) {
|
196
|
+
return value !== undefined && value !== null;
|
197
|
+
};
|
198
|
+
|
199
|
+
// Find and process the translation using the provided scope and options.
|
200
|
+
// This is used internally by some functions and should not be used as an
|
201
|
+
// public API.
|
202
|
+
I18n.lookup = function(scope, options) {
|
203
|
+
options = this.prepareOptions(options);
|
204
|
+
|
205
|
+
var locales = this.locales.get(options.locale)
|
206
|
+
, requestedLocale = locales[0]
|
207
|
+
, locale
|
208
|
+
, scopes
|
209
|
+
, translations
|
210
|
+
;
|
211
|
+
|
212
|
+
while (locales.length) {
|
213
|
+
locale = locales.shift();
|
214
|
+
scopes = scope.split(this.defaultSeparator);
|
215
|
+
translations = this.translations[locale];
|
216
|
+
|
217
|
+
if (!translations) {
|
218
|
+
continue;
|
219
|
+
}
|
220
|
+
|
221
|
+
while (scopes.length) {
|
222
|
+
translations = translations[scopes.shift()];
|
223
|
+
|
224
|
+
if (translations === undefined || translations === null) {
|
225
|
+
break;
|
226
|
+
}
|
227
|
+
}
|
228
|
+
|
229
|
+
if (translations !== undefined && translations !== null) {
|
230
|
+
return translations;
|
231
|
+
}
|
232
|
+
}
|
233
|
+
|
234
|
+
if (this.isSet(options.defaultValue)) {
|
235
|
+
return options.defaultValue;
|
236
|
+
}
|
237
|
+
};
|
238
|
+
|
239
|
+
// Merge serveral hash options, checking if value is set before
|
240
|
+
// overwriting any value. The precedence is from left to right.
|
241
|
+
//
|
242
|
+
// I18n.prepareOptions({name: "John Doe"}, {name: "Mary Doe", role: "user"});
|
243
|
+
// #=> {name: "John Doe", role: "user"}
|
244
|
+
//
|
245
|
+
I18n.prepareOptions = function() {
|
246
|
+
var args = slice.call(arguments)
|
247
|
+
, options = {}
|
248
|
+
, subject
|
249
|
+
;
|
250
|
+
|
251
|
+
while (args.length) {
|
252
|
+
subject = args.shift();
|
253
|
+
|
254
|
+
if (typeof(subject) != "object") {
|
255
|
+
continue;
|
256
|
+
}
|
257
|
+
|
258
|
+
for (var attr in subject) {
|
259
|
+
if (!subject.hasOwnProperty(attr)) {
|
260
|
+
continue;
|
261
|
+
}
|
262
|
+
|
263
|
+
if (this.isSet(options[attr])) {
|
264
|
+
continue;
|
265
|
+
}
|
266
|
+
|
267
|
+
options[attr] = subject[attr];
|
268
|
+
}
|
269
|
+
}
|
270
|
+
|
271
|
+
return options;
|
272
|
+
};
|
273
|
+
|
274
|
+
// Translate the given scope with the provided options.
|
275
|
+
I18n.translate = function(scope, options) {
|
276
|
+
options = this.prepareOptions(options);
|
277
|
+
var translation = this.lookup(scope, options);
|
278
|
+
|
279
|
+
if (translation === undefined || translation === null) {
|
280
|
+
return this.missingTranslation(scope);
|
281
|
+
}
|
282
|
+
|
283
|
+
if (typeof(translation) === "string") {
|
284
|
+
translation = this.interpolate(translation, options);
|
285
|
+
} else if (translation instanceof Object && this.isSet(options.count)) {
|
286
|
+
translation = this.pluralize(options.count, translation, options);
|
287
|
+
}
|
288
|
+
|
289
|
+
return translation;
|
290
|
+
};
|
291
|
+
|
292
|
+
// This function interpolates the all variables in the given message.
|
293
|
+
I18n.interpolate = function(message, options) {
|
294
|
+
options = this.prepareOptions(options);
|
295
|
+
var matches = message.match(this.placeholder)
|
296
|
+
, placeholder
|
297
|
+
, value
|
298
|
+
, name
|
299
|
+
, regex
|
300
|
+
;
|
301
|
+
|
302
|
+
if (!matches) {
|
303
|
+
return message;
|
304
|
+
}
|
305
|
+
|
306
|
+
while (matches.length) {
|
307
|
+
placeholder = matches.shift();
|
308
|
+
name = placeholder.replace(this.placeholder, "$1");
|
309
|
+
value = options[name];
|
310
|
+
|
311
|
+
if (!this.isSet(options[name])) {
|
312
|
+
value = this.missingPlaceholder(placeholder, message);
|
313
|
+
}
|
314
|
+
|
315
|
+
regex = new RegExp(placeholder.replace(/\{/gm, "\\{").replace(/\}/gm, "\\}"));
|
316
|
+
message = message.replace(regex, value);
|
317
|
+
}
|
318
|
+
|
319
|
+
return message;
|
320
|
+
};
|
321
|
+
|
322
|
+
// Pluralize the given scope using the `count` value.
|
323
|
+
// The pluralized translation may have other placeholders,
|
324
|
+
// which will be retrieved from `options`.
|
325
|
+
I18n.pluralize = function(count, scope, options) {
|
326
|
+
options = this.prepareOptions(options);
|
327
|
+
var translations, pluralizer, keys, key, message;
|
328
|
+
|
329
|
+
if (scope instanceof Object) {
|
330
|
+
translations = scope;
|
331
|
+
} else {
|
332
|
+
translations = this.lookup(scope, options);
|
333
|
+
}
|
334
|
+
|
335
|
+
if (!translations) {
|
336
|
+
return this.missingTranslation(scope);
|
337
|
+
}
|
338
|
+
|
339
|
+
pluralizer = this.pluralization.get(options.locale);
|
340
|
+
keys = pluralizer(Math.abs(count));
|
341
|
+
|
342
|
+
while (keys.length) {
|
343
|
+
key = keys.shift();
|
344
|
+
|
345
|
+
if (this.isSet(translations[key])) {
|
346
|
+
message = translations[key];
|
347
|
+
break;
|
348
|
+
}
|
349
|
+
}
|
350
|
+
|
351
|
+
options.count = String(count);
|
352
|
+
return this.interpolate(message, options);
|
353
|
+
};
|
354
|
+
|
355
|
+
// Return a missing translation message for the given parameters.
|
356
|
+
I18n.missingTranslation = function(scope) {
|
357
|
+
var message = '[missing "';
|
358
|
+
|
359
|
+
message += this.currentLocale() + ".";
|
360
|
+
message += slice.call(arguments).join(".");
|
361
|
+
message += '" translation]';
|
362
|
+
|
363
|
+
return message;
|
364
|
+
};
|
365
|
+
|
366
|
+
// Return a missing placeholder message for given parameters
|
367
|
+
I18n.missingPlaceholder = function(placeholder, message) {
|
368
|
+
return "[missing " + placeholder + " value]";
|
369
|
+
};
|
370
|
+
|
371
|
+
// Format number using localization rules.
|
372
|
+
// The options will be retrieved from the `number.format` scope.
|
373
|
+
// If this isn't present, then the following options will be used:
|
374
|
+
//
|
375
|
+
// - `precision`: `3`
|
376
|
+
// - `separator`: `"."`
|
377
|
+
// - `delimiter`: `","`
|
378
|
+
// - `strip_insignificant_zeros`: `false`
|
379
|
+
//
|
380
|
+
// You can also override these options by providing the `options` argument.
|
381
|
+
//
|
382
|
+
I18n.toNumber = function(number, options) {
|
383
|
+
options = this.prepareOptions(
|
384
|
+
options
|
385
|
+
, this.lookup("number.format")
|
386
|
+
, NUMBER_FORMAT
|
387
|
+
);
|
388
|
+
|
389
|
+
var negative = number < 0
|
390
|
+
, string = Math.abs(number).toFixed(options.precision).toString()
|
391
|
+
, parts = string.split(".")
|
392
|
+
, precision
|
393
|
+
, buffer = []
|
394
|
+
, formattedNumber
|
395
|
+
;
|
396
|
+
|
397
|
+
number = parts[0];
|
398
|
+
precision = parts[1];
|
399
|
+
|
400
|
+
while (number.length > 0) {
|
401
|
+
buffer.unshift(number.substr(Math.max(0, number.length - 3), 3));
|
402
|
+
number = number.substr(0, number.length -3);
|
403
|
+
}
|
404
|
+
|
405
|
+
formattedNumber = buffer.join(options.delimiter);
|
406
|
+
|
407
|
+
if (options.strip_insignificant_zeros && precision) {
|
408
|
+
precision = precision.replace(/0+$/, "");
|
409
|
+
}
|
410
|
+
|
411
|
+
if (options.precision > 0 && precision) {
|
412
|
+
formattedNumber += options.separator + precision;
|
413
|
+
}
|
414
|
+
|
415
|
+
if (negative) {
|
416
|
+
formattedNumber = "-" + formattedNumber;
|
417
|
+
}
|
418
|
+
|
419
|
+
return formattedNumber;
|
420
|
+
};
|
421
|
+
|
422
|
+
// Format currency with localization rules.
|
423
|
+
// The options will be retrieved from the `number.currency.format` and
|
424
|
+
// `number.format` scopes, in that order.
|
425
|
+
//
|
426
|
+
// Any missing option will be retrieved from the `I18n.toNumber` defaults and
|
427
|
+
// the following options:
|
428
|
+
//
|
429
|
+
// - `unit`: `"$"`
|
430
|
+
// - `precision`: `2`
|
431
|
+
// - `format`: `"%u%n"`
|
432
|
+
// - `delimiter`: `","`
|
433
|
+
// - `separator`: `"."`
|
434
|
+
//
|
435
|
+
// You can also override these options by providing the `options` argument.
|
436
|
+
//
|
437
|
+
I18n.toCurrency = function(number, options) {
|
438
|
+
options = this.prepareOptions(
|
439
|
+
options
|
440
|
+
, this.lookup("number.currency.format")
|
441
|
+
, this.lookup("number.format")
|
442
|
+
, CURRENCY_FORMAT
|
443
|
+
);
|
444
|
+
|
445
|
+
number = this.toNumber(number, options);
|
446
|
+
number = options.format
|
447
|
+
.replace("%u", options.unit)
|
448
|
+
.replace("%n", number)
|
449
|
+
;
|
450
|
+
|
451
|
+
return number;
|
452
|
+
};
|
453
|
+
|
454
|
+
// Localize several values.
|
455
|
+
// You can provide the following scopes: `currency`, `number`, or `percentage`.
|
456
|
+
// If you provide a scope that matches the `/^(date|time)/` regular expression
|
457
|
+
// then the `value` will be converted by using the `I18n.toTime` function.
|
458
|
+
//
|
459
|
+
// It will default to the value's `toString` function.
|
460
|
+
//
|
461
|
+
I18n.localize = function(scope, value) {
|
462
|
+
switch (scope) {
|
463
|
+
case "currency":
|
464
|
+
return this.toCurrency(value);
|
465
|
+
case "number":
|
466
|
+
scope = this.lookup("number.format");
|
467
|
+
return this.toNumber(value, scope);
|
468
|
+
case "percentage":
|
469
|
+
return this.toPercentage(value);
|
470
|
+
default:
|
471
|
+
if (scope.match(/^(date|time)/)) {
|
472
|
+
return this.toTime(scope, value);
|
473
|
+
} else {
|
474
|
+
return value.toString();
|
475
|
+
}
|
476
|
+
}
|
477
|
+
};
|
478
|
+
|
479
|
+
// Parse a given `date` string into a JavaScript Date object.
|
480
|
+
// This function is time zone aware.
|
481
|
+
//
|
482
|
+
// The following string formats are recognized:
|
483
|
+
//
|
484
|
+
// yyyy-mm-dd
|
485
|
+
// yyyy-mm-dd[ T]hh:mm::ss
|
486
|
+
// yyyy-mm-dd[ T]hh:mm::ss
|
487
|
+
// yyyy-mm-dd[ T]hh:mm::ssZ
|
488
|
+
// yyyy-mm-dd[ T]hh:mm::ss+0000
|
489
|
+
// yyyy-mm-dd[ T]hh:mm::ss+00:00
|
490
|
+
//
|
491
|
+
I18n.parseDate = function(date) {
|
492
|
+
var matches, convertedDate;
|
493
|
+
|
494
|
+
// we have a date, so just return it.
|
495
|
+
if (typeof(date) == "object") {
|
496
|
+
return date;
|
497
|
+
};
|
498
|
+
|
499
|
+
matches = date.toString().match(/(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2}):(\d{2}))?(Z|\+00:?00)?/);
|
500
|
+
|
501
|
+
if (matches) {
|
502
|
+
for (var i = 1; i <= 6; i++) {
|
503
|
+
matches[i] = parseInt(matches[i], 10) || 0;
|
504
|
+
}
|
505
|
+
|
506
|
+
// month starts on 0
|
507
|
+
matches[2] -= 1;
|
508
|
+
|
509
|
+
if (matches[7]) {
|
510
|
+
convertedDate = new Date(Date.UTC(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6]));
|
511
|
+
} else {
|
512
|
+
convertedDate = new Date(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6]);
|
513
|
+
}
|
514
|
+
} else if (typeof(date) == "number") {
|
515
|
+
// UNIX timestamp
|
516
|
+
convertedDate = new Date();
|
517
|
+
convertedDate.setTime(date);
|
518
|
+
} else if (date.match(/\d+ \d+:\d+:\d+ [+-]\d+ \d+/)) {
|
519
|
+
// a valid javascript format with timezone info
|
520
|
+
convertedDate = new Date();
|
521
|
+
convertedDate.setTime(Date.parse(date))
|
522
|
+
} else {
|
523
|
+
// an arbitrary javascript string
|
524
|
+
convertedDate = new Date();
|
525
|
+
convertedDate.setTime(Date.parse(date));
|
526
|
+
}
|
527
|
+
|
528
|
+
return convertedDate;
|
529
|
+
};
|
530
|
+
|
531
|
+
// Formats time according to the directives in the given format string.
|
532
|
+
// The directives begins with a percent (%) character. Any text not listed as a
|
533
|
+
// directive will be passed through to the output string.
|
534
|
+
//
|
535
|
+
// The accepted formats are:
|
536
|
+
//
|
537
|
+
// %a - The abbreviated weekday name (Sun)
|
538
|
+
// %A - The full weekday name (Sunday)
|
539
|
+
// %b - The abbreviated month name (Jan)
|
540
|
+
// %B - The full month name (January)
|
541
|
+
// %c - The preferred local date and time representation
|
542
|
+
// %d - Day of the month (01..31)
|
543
|
+
// %-d - Day of the month (1..31)
|
544
|
+
// %H - Hour of the day, 24-hour clock (00..23)
|
545
|
+
// %-H - Hour of the day, 24-hour clock (0..23)
|
546
|
+
// %I - Hour of the day, 12-hour clock (01..12)
|
547
|
+
// %-I - Hour of the day, 12-hour clock (1..12)
|
548
|
+
// %m - Month of the year (01..12)
|
549
|
+
// %-m - Month of the year (1..12)
|
550
|
+
// %M - Minute of the hour (00..59)
|
551
|
+
// %-M - Minute of the hour (0..59)
|
552
|
+
// %p - Meridian indicator (AM or PM)
|
553
|
+
// %S - Second of the minute (00..60)
|
554
|
+
// %-S - Second of the minute (0..60)
|
555
|
+
// %w - Day of the week (Sunday is 0, 0..6)
|
556
|
+
// %y - Year without a century (00..99)
|
557
|
+
// %-y - Year without a century (0..99)
|
558
|
+
// %Y - Year with century
|
559
|
+
// %z - Timezone offset (+0545)
|
560
|
+
//
|
561
|
+
I18n.strftime = function(date, format) {
|
562
|
+
var options = this.lookup("date");
|
563
|
+
|
564
|
+
if (!options) {
|
565
|
+
options = DAYS_AND_MONTHS;
|
566
|
+
}
|
567
|
+
|
568
|
+
if (!options.meridian) {
|
569
|
+
options.meridian = MERIDIAN;
|
570
|
+
}
|
571
|
+
|
572
|
+
var weekDay = date.getDay()
|
573
|
+
, day = date.getDate()
|
574
|
+
, year = date.getFullYear()
|
575
|
+
, month = date.getMonth() + 1
|
576
|
+
, hour = date.getHours()
|
577
|
+
, hour12 = hour
|
578
|
+
, meridian = hour > 11 ? 1 : 0
|
579
|
+
, secs = date.getSeconds()
|
580
|
+
, mins = date.getMinutes()
|
581
|
+
, offset = date.getTimezoneOffset()
|
582
|
+
, absOffsetHours = Math.floor(Math.abs(offset / 60))
|
583
|
+
, absOffsetMinutes = Math.abs(offset) - (absOffsetHours * 60)
|
584
|
+
, timezoneoffset = (offset > 0 ? "-" : "+") + (absOffsetHours.toString().length < 2 ? "0" + absOffsetHours : absOffsetHours) + (absOffsetMinutes.toString().length < 2 ? "0" + absOffsetMinutes : absOffsetMinutes)
|
585
|
+
;
|
586
|
+
|
587
|
+
if (hour12 > 12) {
|
588
|
+
hour12 = hour12 - 12;
|
589
|
+
} else if (hour12 === 0) {
|
590
|
+
hour12 = 12;
|
591
|
+
}
|
592
|
+
|
593
|
+
format = format.replace("%a", options.abbr_day_names[weekDay]);
|
594
|
+
format = format.replace("%A", options.day_names[weekDay]);
|
595
|
+
format = format.replace("%b", options.abbr_month_names[month]);
|
596
|
+
format = format.replace("%B", options.month_names[month]);
|
597
|
+
format = format.replace("%d", padding(day));
|
598
|
+
format = format.replace("%e", day);
|
599
|
+
format = format.replace("%-d", day);
|
600
|
+
format = format.replace("%H", padding(hour));
|
601
|
+
format = format.replace("%-H", hour);
|
602
|
+
format = format.replace("%I", padding(hour12));
|
603
|
+
format = format.replace("%-I", hour12);
|
604
|
+
format = format.replace("%m", padding(month));
|
605
|
+
format = format.replace("%-m", month);
|
606
|
+
format = format.replace("%M", padding(mins));
|
607
|
+
format = format.replace("%-M", mins);
|
608
|
+
format = format.replace("%p", options.meridian[meridian]);
|
609
|
+
format = format.replace("%S", padding(secs));
|
610
|
+
format = format.replace("%-S", secs);
|
611
|
+
format = format.replace("%w", weekDay);
|
612
|
+
format = format.replace("%y", padding(year));
|
613
|
+
format = format.replace("%-y", padding(year).replace(/^0+/, ""));
|
614
|
+
format = format.replace("%Y", year);
|
615
|
+
format = format.replace("%z", timezoneoffset);
|
616
|
+
|
617
|
+
return format;
|
618
|
+
};
|
619
|
+
|
620
|
+
// Convert the given dateString into a formatted date.
|
621
|
+
I18n.toTime = function(scope, dateString) {
|
622
|
+
var date = this.parseDate(dateString)
|
623
|
+
, format = this.lookup(scope)
|
624
|
+
;
|
625
|
+
|
626
|
+
if (date.toString().match(/invalid/i)) {
|
627
|
+
return date.toString();
|
628
|
+
}
|
629
|
+
|
630
|
+
if (!format) {
|
631
|
+
return date.toString();
|
632
|
+
}
|
633
|
+
|
634
|
+
return this.strftime(date, format);
|
635
|
+
};
|
636
|
+
|
637
|
+
// Convert a number into a formatted percentage value.
|
638
|
+
I18n.toPercentage = function(number, options) {
|
639
|
+
options = this.prepareOptions(
|
640
|
+
options
|
641
|
+
, this.lookup("number.percentage.format")
|
642
|
+
, this.lookup("number.format")
|
643
|
+
, PERCENTAGE_FORMAT
|
644
|
+
);
|
645
|
+
|
646
|
+
number = this.toNumber(number, options);
|
647
|
+
return number + "%";
|
648
|
+
};
|
649
|
+
|
650
|
+
// Convert a number into a readable size representation.
|
651
|
+
I18n.toHumanSize = function(number, options) {
|
652
|
+
var kb = 1024
|
653
|
+
, size = number
|
654
|
+
, iterations = 0
|
655
|
+
, unit
|
656
|
+
, precision
|
657
|
+
;
|
658
|
+
|
659
|
+
while (size >= kb && iterations < 4) {
|
660
|
+
size = size / kb;
|
661
|
+
iterations += 1;
|
662
|
+
}
|
663
|
+
|
664
|
+
if (iterations === 0) {
|
665
|
+
unit = this.t("number.human.storage_units.units.byte", {count: size});
|
666
|
+
precision = 0;
|
667
|
+
} else {
|
668
|
+
unit = this.t("number.human.storage_units.units." + SIZE_UNITS[iterations]);
|
669
|
+
precision = (size - Math.floor(size) === 0) ? 0 : 1;
|
670
|
+
}
|
671
|
+
|
672
|
+
options = this.prepareOptions(
|
673
|
+
options
|
674
|
+
, {precision: precision, format: "%n%u", delimiter: ""}
|
675
|
+
);
|
676
|
+
|
677
|
+
number = this.toNumber(size, options);
|
678
|
+
number = options.format
|
679
|
+
.replace("%u", unit)
|
680
|
+
.replace("%n", number)
|
681
|
+
;
|
682
|
+
|
683
|
+
return number;
|
684
|
+
};
|
685
|
+
|
686
|
+
// Set aliases, so we can save some typing.
|
687
|
+
I18n.t = I18n.translate;
|
688
|
+
I18n.l = I18n.localize;
|
689
|
+
I18n.p = I18n.pluralize;
|
690
|
+
})(typeof(exports) === "undefined" ? (this.I18n = {}) : exports);
|
data/i18n-js.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "i18n/js/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "i18n-js-pika"
|
7
|
+
s.version = I18n::JS::Version::STRING
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Nando Vieira", "PikachuEXE"]
|
10
|
+
s.email = ["fnando.vieira@gmail.com", "pikachuexe@gmail.com"]
|
11
|
+
s.homepage = "http://github.com/PikachuEXE/i18n-js-pika"
|
12
|
+
s.summary = "Forked version of original i18n-js. It's a small library to provide the Rails I18n translations on the Javascript."
|
13
|
+
s.description = "Forked version of original i18n-js. It contains some pull requests that are not pulled yet on the original repo. Switch back to the original one when it's ready."
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
|
20
|
+
s.license = 'MIT'
|
21
|
+
|
22
|
+
s.add_dependency "i18n"
|
23
|
+
s.add_development_dependency "activesupport"
|
24
|
+
s.add_development_dependency "rspec"
|
25
|
+
s.add_development_dependency "rake"
|
26
|
+
s.add_development_dependency "pry-meta"
|
27
|
+
end
|