exvo_globalize 0.5.0 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/README.md +48 -14
- data/app/assets/javascripts/exvo_globalize_i18n.js +176 -18
- data/config/locales/pl.yml +2 -1
- data/lib/exvo_globalize/version.rb +1 -1
- data/spec/javascripts/exvo_globalize_i18n_spec.js +44 -5
- data/spec/javascripts/fixtures/translations.js +29 -3
- metadata +4 -4
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,26 @@
|
|
1
1
|
# Exvo Globalize
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
Rails gem providing universal I18n support for your application. Supports I18n of both your normal Ruby/Rails app (based on the i18n gem) as well as javascript using a custom i18n library.
|
4
|
+
|
5
|
+
Ruby/Rails features:
|
6
|
+
|
7
|
+
* additional database backed I18n backend to store the translations
|
8
|
+
* in-memory caching of database backed translations
|
9
|
+
* pluralization rules for 108 languages (`config/locales/plurals.rb`)
|
10
|
+
* localization rules for 51 languages (`config/locales/*.(yml|rb)`)
|
11
|
+
* locale fallback support (will search for translation using `I18n.default_locale` when not found using requested locale)
|
12
|
+
* web UI to view your application’s translations (`/globalize/translations`)
|
13
|
+
|
14
|
+
Javascript features:
|
15
|
+
|
16
|
+
* all translations defined in `config/locales/*` are available in javascript
|
17
|
+
* localization support for dates, times, numbers, currencies (localization rules are read from `config/locales/*.(yml|rb)`)
|
18
|
+
* locale fallback support (will search for translation using `I18n.default_locale` when not found using requested locale)
|
19
|
+
* global t() and l() helpers to translate and localize phrases, respectively
|
20
|
+
* does not depend on any other external javascript library
|
21
|
+
|
22
|
+
|
23
|
+
This gem also integrates your application with [Globalize](http://store.exvo.com/apps/shops/globalize/items/globalize-125). Globalize is a service for website owners, who want to translate their websites into multiple languages by using human (as opposed to machine/automatic) translators.
|
5
24
|
|
6
25
|
|
7
26
|
|
@@ -137,7 +156,7 @@ I18n.strftime(I18n.parseDate("<%= Time.now %>"), "%Y/%m/%d %H:%M")
|
|
137
156
|
|
138
157
|
// uses formats from `config/locale/en.yml` file
|
139
158
|
I18n.l("date.formats.default", "Wed Sep 14 12:03:11 +0200 2011")
|
140
|
-
=> "
|
159
|
+
=> "2011-09-14"
|
141
160
|
|
142
161
|
I18n.l("date.formats.long", "2011-09-14")
|
143
162
|
=> "September 14, 2011"
|
@@ -165,7 +184,7 @@ $ bundle exec rake globalize:translations:dump:ruby
|
|
165
184
|
|
166
185
|
## Globalize integration
|
167
186
|
|
168
|
-
In order to fully integrate this gem with Globalize, after installing it you need to register your application
|
187
|
+
In order to fully integrate this gem with Globalize, after installing it you need to [register your application](http://store.exvo.com/apps/shops/globalize/items/globalize-125) and order some translations (Globalize should automatically detect the gem installation and should let you choose the JSON translations option).
|
169
188
|
|
170
189
|
By default a link between your application and Globalize is established by using `request.host` by the gem. If your application’s main DNS record is a CNAME (as is the common case when using Heroku), you can set your application’s domain in the `config/initializers/exvo_globalize.rb` file:
|
171
190
|
|
@@ -185,16 +204,31 @@ http://yourawesomewebapp.com/globalize/translations
|
|
185
204
|
And pressing `Update translations`.
|
186
205
|
|
187
206
|
|
207
|
+
### Caveats
|
188
208
|
|
189
|
-
|
209
|
+
* Adding or changing any existing translations requires application restart for those new updated translations to be visible (it is because of the caching mechanism, which does not currently support cache-invalidation).
|
210
|
+
* Heroku considerations: updating translations from Globalize, when there are many translations in many different languages is a time consuming process. Unfortunately Heroku has a habit of silently killing web processes running longer than a specified period of time (typically 30s). When that happenes your translations will be only partially updated. Best way to deal with that is to update them from `heroku console` using this script:
|
211
|
+
|
212
|
+
```ruby
|
213
|
+
ENV["GLOBALIZE_USE_PRODUCTION_SERVER"] = "true"
|
190
214
|
|
191
|
-
|
215
|
+
@globalize_app = GlobalizeApp.new("your-applications-host-registered-at-globalize")
|
216
|
+
|
217
|
+
translations = @globalize_app.fetch_translations
|
218
|
+
I18n.backend.store_nested_translations(translations)
|
219
|
+
```
|
220
|
+
|
221
|
+
|
222
|
+
|
223
|
+
## Running the specs
|
224
|
+
|
225
|
+
Running specs via `Guard` is the recommended way:
|
192
226
|
|
193
227
|
```bash
|
194
228
|
$ bundle exec guard
|
195
229
|
```
|
196
230
|
|
197
|
-
But
|
231
|
+
But specs can be run separately as well:
|
198
232
|
|
199
233
|
```bash
|
200
234
|
$ bundle exec rspec spec
|
@@ -206,18 +240,18 @@ and
|
|
206
240
|
$ jasmine-headless-webkit -c
|
207
241
|
```
|
208
242
|
|
209
|
-
There is a great guide for setting up `jasmine-headless-webkit` in your OS if you have problems with it
|
210
|
-
http://johnbintz.github.com/jasmine-headless-webkit/
|
243
|
+
There is a [great guide](http://johnbintz.github.com/jasmine-headless-webkit/) for setting up `jasmine-headless-webkit` in your OS if you have problems with it.
|
211
244
|
|
212
245
|
|
213
246
|
|
214
247
|
## Copyrights
|
215
248
|
|
216
|
-
exvo_globalize is based on the following projects:
|
217
|
-
|
218
|
-
https://github.com/svenfuchs/
|
219
|
-
https://github.com/
|
220
|
-
https://github.com/
|
249
|
+
[exvo_globalize](https://github.com/Exvo/exvo_globalize/) is based on the following projects:
|
250
|
+
|
251
|
+
* [i18n](https://github.com/svenfuchs/i18n)
|
252
|
+
* [rails-i18n](https://github.com/svenfuchs/rails-i18n/)
|
253
|
+
* [babilu](https://github.com/toretore/babilu)
|
254
|
+
* [i18n-js](https://github.com/spider-network/i18n-js)
|
221
255
|
|
222
256
|
|
223
257
|
Copyright © 2011 Exvo.com Development BV, released under the MIT license
|
@@ -1,24 +1,39 @@
|
|
1
|
+
//
|
2
|
+
// exvo_globalize_i18n.js
|
3
|
+
// Version: 0.5.1
|
4
|
+
//
|
1
5
|
(function() {
|
2
6
|
|
3
7
|
I18n = {};
|
4
8
|
|
9
|
+
// Check if an Array contains an object
|
10
|
+
function isInArray(a, obj) {
|
11
|
+
var i = a.length;
|
12
|
+
while (i--) {
|
13
|
+
if (a[i] === obj) {
|
14
|
+
return true;
|
15
|
+
}
|
16
|
+
}
|
17
|
+
return false;
|
18
|
+
};
|
19
|
+
|
5
20
|
var interpolatePattern = /%\{([^}]+)\}/g;
|
6
21
|
|
7
22
|
// Replace %{foo} with obj.foo
|
8
|
-
function
|
23
|
+
I18n.interpolate = function(str, obj) {
|
9
24
|
return str.replace(interpolatePattern, function() {
|
10
25
|
return typeof obj[arguments[1]] == 'undefined' ? arguments[0] : obj[arguments[1]];
|
11
26
|
});
|
12
27
|
};
|
13
28
|
|
14
29
|
// Split "foo.bar" to ["foo", "bar"] if key is a string
|
15
|
-
function
|
30
|
+
I18n.keyToArray = function(key) {
|
16
31
|
if (!key) return [];
|
17
32
|
if (typeof key != "string") return key;
|
18
33
|
return key.split('.');
|
19
34
|
};
|
20
35
|
|
21
|
-
function
|
36
|
+
I18n.current_locale = function() {
|
22
37
|
return I18n.locale || I18n.defaultLocale;
|
23
38
|
};
|
24
39
|
|
@@ -70,14 +85,14 @@
|
|
70
85
|
} else {
|
71
86
|
opts = opts || {};
|
72
87
|
opts.defaultValue = opts.defaultValue || null;
|
73
|
-
key = keyToArray(opts.scope).concat(keyToArray(key));
|
74
|
-
var value = this.lookup(
|
88
|
+
key = I18n.keyToArray(opts.scope).concat(I18n.keyToArray(key));
|
89
|
+
var value = this.lookup(I18n.current_locale(), key, opts.defaultValue);
|
75
90
|
|
76
91
|
// fall back to I18n.default_locale for missing translations
|
77
92
|
if (value == null && I18n.locale != I18n.default_locale) value = this.lookup(I18n.default_locale, key, opts.defaultLocale);
|
78
93
|
|
79
94
|
if (typeof value != "string" && value) value = this.pluralize(value, opts.count);
|
80
|
-
if (typeof value == "string") value = interpolate(value, opts);
|
95
|
+
if (typeof value == "string") value = I18n.interpolate(value, opts);
|
81
96
|
if (value == null) value = this.missingTranslation(key)
|
82
97
|
return value;
|
83
98
|
}
|
@@ -104,7 +119,7 @@
|
|
104
119
|
if (defaults.length == 0) {
|
105
120
|
return null;
|
106
121
|
} else if (defaults[0].substr(0,1) == ':') {
|
107
|
-
return this.lookup(locale, keys.slice(0, keys.length - 1).concat(keyToArray(defaults[0].substr(1))), defaults.slice(1));
|
122
|
+
return this.lookup(locale, keys.slice(0, keys.length - 1).concat(I18n.keyToArray(defaults[0].substr(1))), defaults.slice(1));
|
108
123
|
} else {
|
109
124
|
return defaults[0];
|
110
125
|
}
|
@@ -116,7 +131,7 @@
|
|
116
131
|
case "currency":
|
117
132
|
return this.toCurrency(value);
|
118
133
|
case "number":
|
119
|
-
scope = this.lookup(
|
134
|
+
scope = this.lookup(I18n.current_locale(), ["number", "format"]);
|
120
135
|
return this.toNumber(value, scope);
|
121
136
|
case "percentage":
|
122
137
|
return this.toPercentage(value);
|
@@ -164,7 +179,7 @@
|
|
164
179
|
|
165
180
|
I18n.toTime = function(scope, d) {
|
166
181
|
var date = this.parseDate(d);
|
167
|
-
var format = this.lookup(
|
182
|
+
var format = this.lookup(I18n.current_locale(), I18n.keyToArray(scope));
|
168
183
|
|
169
184
|
if (date.toString().match(/invalid/i)) {
|
170
185
|
return date.toString();
|
@@ -178,14 +193,14 @@
|
|
178
193
|
};
|
179
194
|
|
180
195
|
I18n.strftime = function(date, format) {
|
181
|
-
var options = this.lookup(
|
196
|
+
var options = this.lookup(I18n.current_locale(), ["date"]);
|
182
197
|
|
183
198
|
if (!options) {
|
184
199
|
return date.toString();
|
185
200
|
}
|
186
201
|
|
187
202
|
// get meridian from ":time" i18n key
|
188
|
-
options.time = this.lookup(
|
203
|
+
options.time = this.lookup(I18n.current_locale(), ["time"]);
|
189
204
|
if (!options.time || !options.time.am || !options.time.pm) {
|
190
205
|
options.time = { am: "AM", pm: "PM" };
|
191
206
|
}
|
@@ -245,7 +260,7 @@
|
|
245
260
|
I18n.toNumber = function(number, options) {
|
246
261
|
options = this.prepareOptions(
|
247
262
|
options,
|
248
|
-
this.lookup(
|
263
|
+
this.lookup(I18n.current_locale(), ["number", "format"]),
|
249
264
|
{precision: 3, separator: ".", delimiter: ",", strip_insignificant_zeros: false}
|
250
265
|
);
|
251
266
|
|
@@ -290,8 +305,8 @@
|
|
290
305
|
I18n.toCurrency = function(number, options) {
|
291
306
|
options = this.prepareOptions(
|
292
307
|
options,
|
293
|
-
this.lookup(
|
294
|
-
this.lookup(
|
308
|
+
this.lookup(I18n.current_locale(), ["number", "currency", "format"]),
|
309
|
+
this.lookup(I18n.current_locale(), ["number", "format"]),
|
295
310
|
{unit: "$", precision: 2, format: "%u%n", delimiter: ",", separator: "."}
|
296
311
|
);
|
297
312
|
|
@@ -340,8 +355,8 @@
|
|
340
355
|
I18n.toPercentage = function(number, options) {
|
341
356
|
options = this.prepareOptions(
|
342
357
|
options,
|
343
|
-
this.lookup(
|
344
|
-
this.lookup(
|
358
|
+
this.lookup(I18n.current_locale(), ["number", "percentage", "format"]),
|
359
|
+
this.lookup(I18n.current_locale(), ["number", "format"]),
|
345
360
|
{precision: 3, separator: ".", delimiter: ""}
|
346
361
|
);
|
347
362
|
|
@@ -349,14 +364,157 @@
|
|
349
364
|
return number + "%";
|
350
365
|
};
|
351
366
|
|
367
|
+
// Pluralization function
|
352
368
|
I18n.pluralize = function(value, count) {
|
353
369
|
if (typeof count != 'number') return value;
|
354
|
-
return
|
370
|
+
return I18n.plurals[I18n.current_locale()](value, count);
|
355
371
|
};
|
356
372
|
|
373
|
+
// Default pluralization rules
|
374
|
+
I18n.default_pluralization_rule = function(value, count) {
|
375
|
+
return count == 1 ? value.one : value.other;
|
376
|
+
}
|
377
|
+
I18n.other_default_pluralization_rule = function(value, count) {
|
378
|
+
return count == 1 || count == 0 ? value.one : value.other;
|
379
|
+
}
|
380
|
+
|
381
|
+
// Pluralization Rules for each language
|
382
|
+
I18n.plurals = {
|
383
|
+
"af": I18n.default_pluralization_rule,
|
384
|
+
"am": I18n.other_default_pluralization_rule,
|
385
|
+
"ar": function(value, count) {
|
386
|
+
if (typeof count != 'number') return value;
|
387
|
+
return count == 0 ? value.zero : count == 1 ? value.one : count == 2 ? value.two : isInArray([3, 4, 5, 6, 7, 8, 9, 10], count % 100) ? value.few : isInArray([3, 4, 5, 6, 7, 8, 9, 10], count % 100) ? value.few : isInArray([11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99], count % 100) ? value.many : value.other;
|
388
|
+
},
|
389
|
+
"az": function(value, count) { return value.other; },
|
390
|
+
"be": function(value, count) {
|
391
|
+
return count % 10 == 1 && count % 100 != 11 ? value.one : isInArray([2,3,4], count % 10) && !isInArray([12,13,14], count % 100) ? value.few : count % 10 == 0 || isInArray([5,6,7,8,9], count % 10) || isInArray([11,12,13,14], count % 100) ? value.many : valye.other;
|
392
|
+
},
|
393
|
+
"bg": I18n.default_pluralization_rule,
|
394
|
+
"bh": I18n.default_pluralization_rule,
|
395
|
+
"bn": I18n.default_pluralization_rule,
|
396
|
+
"bo": function(value, count) { return value.other; },
|
397
|
+
"bs": function(value, count) {
|
398
|
+
return count % 10 == 1 && count % 100 != 11 ? value.one : isInArray([2,3,4], count % 10) && !isInArray([12,13,14], count % 100) ? value.few : count % 10 == 0 || isInArray([5,6,7,8,9], count % 10) || isInArray([11,12,13,14], count % 100) ? value.many : value.other;
|
399
|
+
},
|
400
|
+
"ca": I18n.default_pluralization_rule,
|
401
|
+
"cs": function(value, count) { return count == 1 ? value.one : isInArray([2,3,4], count) ? value.few : value.other; },
|
402
|
+
"cy": function(value, count) { return count == 1 ? value.one : count == 2 ? value.two : count == 8 || count == 11 ? value.many : value.other; },
|
403
|
+
"da": I18n.default_pluralization_rule,
|
404
|
+
"de": I18n.default_pluralization_rule,
|
405
|
+
"dz": function(value, count) { return value.other; },
|
406
|
+
"el": I18n.default_pluralization_rule,
|
407
|
+
"en": I18n.default_pluralization_rule,
|
408
|
+
"eo": I18n.default_pluralization_rule,
|
409
|
+
"es": I18n.default_pluralization_rule,
|
410
|
+
"et": I18n.default_pluralization_rule,
|
411
|
+
"eu": I18n.default_pluralization_rule,
|
412
|
+
"fa": function(value, count) { return value.other; },
|
413
|
+
"fi": I18n.default_pluralization_rule,
|
414
|
+
"fil": I18n.other_default_pluralization_rule,
|
415
|
+
"fo": I18n.default_pluralization_rule,
|
416
|
+
"fr": function(value, count) { return isInArray([0,1], count) ? value.one : value.other; },
|
417
|
+
"fur": I18n.default_pluralization_rule,
|
418
|
+
"fy": I18n.default_pluralization_rule,
|
419
|
+
"ga": function(value, count) { return count == 1 ? value.one : count == 2 ? value.two : value.other; },
|
420
|
+
"gl": I18n.default_pluralization_rule,
|
421
|
+
"gu": I18n.default_pluralization_rule,
|
422
|
+
"guw": I18n.other_default_pluralization_rule,
|
423
|
+
"ha": I18n.default_pluralization_rule,
|
424
|
+
"he": I18n.default_pluralization_rule,
|
425
|
+
"hi": I18n.other_default_pluralization_rule,
|
426
|
+
"hr": function(value, count) {
|
427
|
+
return count % 10 == 1 && count % 100 != 11 ? value.one : isInArray([2,3,4], count % 10) && !isInArray([12,13,14], count % 100) ? value.few : count % 10 == 0 || isInArray([5,6,7,8,9], count % 10) || isInArray([11,12,13,14], count % 100) ? value.many : value.other;
|
428
|
+
},
|
429
|
+
"hu": function(value, count) { return value.other; },
|
430
|
+
"id": function(value, count) { return value.other; },
|
431
|
+
"is": I18n.default_pluralization_rule,
|
432
|
+
"it": I18n.default_pluralization_rule,
|
433
|
+
"iw": I18n.default_pluralization_rule,
|
434
|
+
"ja": function(value, count) { return value.other; },
|
435
|
+
"jv": function(value, count) { return value.other; },
|
436
|
+
"ka": function(value, count) { return value.other; },
|
437
|
+
"km": function(value, count) { return value.other; },
|
438
|
+
"kn": function(value, count) { return value.other; },
|
439
|
+
"ko": function(value, count) { return value.other; },
|
440
|
+
"ku": I18n.default_pluralization_rule,
|
441
|
+
"lb": I18n.default_pluralization_rule,
|
442
|
+
"ln": I18n.other_default_pluralization_rule,
|
443
|
+
"lt": function(value, count) {
|
444
|
+
return count % 10 == 1 && ! isInArray([11, 12, 13, 14, 15, 16, 17, 18, 19], count % 100) ? value.one : isInArray([2, 3, 4, 5, 6, 7, 8, 9], count % 10) && ! isInArray([11, 12, 13, 14, 15, 16, 17, 18, 19], count % 100) ? value.few : value.other;
|
445
|
+
},
|
446
|
+
"lv": function(value, count) { return count == 0 ? value.zero : count % 10 == 1 && count % 100 != 11 ? value.one : value.other; },
|
447
|
+
"mg": I18n.default_pluralization_rule,
|
448
|
+
"mk": function(value, count) { return count % 10 == 1 ? value.one : value.other; },
|
449
|
+
"ml": I18n.default_pluralization_rule,
|
450
|
+
"mn": I18n.default_pluralization_rule,
|
451
|
+
"mo": function(value, count) { return count ==1 ? value.one : count == 0 ? value.few : value.other; },
|
452
|
+
"mr": I18n.default_pluralization_rule,
|
453
|
+
"ms": function(value, count) { return value.other; },
|
454
|
+
"mt": function(value, count) {
|
455
|
+
return count == 1 ? value.one : count == 0 || isInArray([2,3,4,5,6,7,8,9,10], count % 100) ? value.few : isInArray([11,12,13,14,15,16,17,18,19], count % 100) ? value.many : value.other;
|
456
|
+
},
|
457
|
+
"my": function(value, count) { return value.other; },
|
458
|
+
"nah": I18n.default_pluralization_rule,
|
459
|
+
"nb": I18n.default_pluralization_rule,
|
460
|
+
"ne": I18n.default_pluralization_rule,
|
461
|
+
"nl": I18n.default_pluralization_rule,
|
462
|
+
"nn": I18n.default_pluralization_rule,
|
463
|
+
"no": I18n.default_pluralization_rule,
|
464
|
+
"nso": I18n.other_default_pluralization_rule,
|
465
|
+
"or": I18n.default_pluralization_rule,
|
466
|
+
"pa": I18n.default_pluralization_rule,
|
467
|
+
"pap": I18n.default_pluralization_rule,
|
468
|
+
"pl": function(value, count) {
|
469
|
+
return count == 1 ? value.one : isInArray([2,3,4], count % 10) && !isInArray([12,13,14], count % 100) ? value.few : value.other;
|
470
|
+
},
|
471
|
+
"ps": I18n.default_pluralization_rule,
|
472
|
+
"pt": I18n.other_default_pluralization_rule,
|
473
|
+
"pt-PT": I18n.default_pluralization_rule,
|
474
|
+
"ro": function(value, count) { return count == 1 ? value.one : count == 0 ? value.few : value.other; },
|
475
|
+
"ru": function(value, count) {
|
476
|
+
return count % 10 == 1 && count % 100 != 11 ? value.one : isInArray([2,3,4], count % 10) && !isInArray([12,13,14], count % 100) ? value.few : count % 10 == 0 || isInArray([5,6,7,8,9], count % 10) || isInArray([11,12,13,14], count % 100) ? value.many : value.other;
|
477
|
+
},
|
478
|
+
"se": function(value, count) { return count == 1 ? value.one : count == 2 ? value.two : value.other; },
|
479
|
+
"sh": function(value, count) {
|
480
|
+
return count % 10 == 1 && count % 100 != 11 ? value.one : isInArray([2,3,4], count % 10) && !isInArray([12,13,14], count % 100) ? value.few : count % 10 == 0 || isInArray([5,6,7,8,9], count % 10) || isInArray([11,12,13,14], count % 100) ? value.many : value.other;
|
481
|
+
},
|
482
|
+
"sk": function(value, count) { return count == 1 ? value.one : isInArray([2,3,4], count) ? valuer.few : value.other; },
|
483
|
+
"sl": function(value, count) { return count % 100 == 1 ? value.one : count % 100 == 2 ? value.two : isInArray([3,4], count % 100) ? value.few : value.other; },
|
484
|
+
"sma": function(value, count) { return count == 1 ? value.one : count == 2 ? value.two : value.other; },
|
485
|
+
"smi": function(value, count) { return count == 1 ? value.one : count == 2 ? value.two : value.other; },
|
486
|
+
"smj": function(value, count) { return count == 1 ? value.one : count == 2 ? value.two : value.other; },
|
487
|
+
"smn": function(value, count) { return count == 1 ? value.one : count == 2 ? value.two : value.other; },
|
488
|
+
"sms": function(value, count) { return count == 1 ? value.one : count == 2 ? value.two : value.other; },
|
489
|
+
"so": I18n.default_pluralization_rule,
|
490
|
+
"sq": I18n.default_pluralization_rule,
|
491
|
+
"sr": function(value, count) {
|
492
|
+
return count % 10 == 1 && count % 100 != 11 ? value.one : isInArray([2,3,4], count % 10) && ! isInArray([12,13,14], count % 100) ? value.few : count % 10 == 0 || isInArray([5,6,7,8,9], count % 10) || isInArray([11,12,13,14], count % 100) ? value.many : value.other;
|
493
|
+
},
|
494
|
+
"sv": I18n.default_pluralization_rule,
|
495
|
+
"sw": I18n.default_pluralization_rule,
|
496
|
+
"ta": I18n.default_pluralization_rule,
|
497
|
+
"te": I18n.default_pluralization_rule,
|
498
|
+
"th": function(value, count) { return value.other; },
|
499
|
+
"ti": I18n.other_default_pluralization_rule,
|
500
|
+
"tk": I18n.default_pluralization_rule,
|
501
|
+
"tl": I18n.other_default_pluralization_rule,
|
502
|
+
"to": function(value, count) { return value.other; },
|
503
|
+
"tr": function(value, count) { return value.other; },
|
504
|
+
"uk": function(value, count) {
|
505
|
+
return count % 10 == 1 && count % 100 != 11 ? value.one : isInArray([2,3,4], count % 10) && !isInArray([12,13,14], count % 100) ? value.few : count % 10 == 0 || isInArray([5,6,7,8,9], count % 10) || isInArray([11,12,13,14], count % 100) ? value.many : value.other;
|
506
|
+
},
|
507
|
+
"ur": I18n.default_pluralization_rule,
|
508
|
+
"vi": function(value, count) { return value.other; },
|
509
|
+
"wa": I18n.other_default_pluralization_rule,
|
510
|
+
"yo": function(value, count) { return value.other; },
|
511
|
+
"zh": function(value, count) { return value.other; },
|
512
|
+
"zu": I18n.default_pluralization_rule
|
513
|
+
}
|
514
|
+
|
357
515
|
// Returns '[missing translation: "en.missing"]' when translation is not found
|
358
516
|
I18n.missingTranslation = function(key) {
|
359
|
-
var message = '[missing translation: "' +
|
517
|
+
var message = '[missing translation: "' + I18n.current_locale();
|
360
518
|
for (var i in key) {
|
361
519
|
message += "." + key[i];
|
362
520
|
}
|
data/config/locales/pl.yml
CHANGED
@@ -164,11 +164,13 @@ describe("Localization of human sizes", function() {
|
|
164
164
|
I18n.locale = "pl"
|
165
165
|
})
|
166
166
|
|
167
|
-
it("localizes numbers in human sizes", function() {
|
167
|
+
it("localizes numbers in human sizes using pluralization rules", function() {
|
168
168
|
kb = 1024
|
169
169
|
|
170
170
|
expect(I18n.toHumanSize(1)).toEqual("1bajt")
|
171
|
-
expect(I18n.toHumanSize(
|
171
|
+
expect(I18n.toHumanSize(5)).toEqual("5bajtów")
|
172
|
+
expect(I18n.toHumanSize(12)).toEqual("12bajtów")
|
173
|
+
expect(I18n.toHumanSize(22)).toEqual("22bajty")
|
172
174
|
|
173
175
|
expect(I18n.toHumanSize(kb)).toEqual("1KB")
|
174
176
|
expect(I18n.toHumanSize(kb * 1.5)).toEqual("1,5KB")
|
@@ -365,8 +367,9 @@ describe("Date parsing", function() {
|
|
365
367
|
expect(I18n.strftime(date, "%I")).toEqual("12")
|
366
368
|
})
|
367
369
|
|
368
|
-
it("parses and formats a Ruby Time.now.to_s string
|
369
|
-
|
370
|
+
it("parses and formats a Ruby Time.now.to_s string", function() {
|
371
|
+
// the `Time.now` string below is devoid of timezone information; this way this test can pass in different timezones
|
372
|
+
expect(I18n.strftime(I18n.parseDate("Wed Sep 14 12:03:11 2011"), "%Y/%m/%d %H:%M")).toEqual("2011/09/14 12:03")
|
370
373
|
})
|
371
374
|
|
372
375
|
it("localizes date strings", function() {
|
@@ -376,9 +379,45 @@ describe("Date parsing", function() {
|
|
376
379
|
})
|
377
380
|
|
378
381
|
it("localizes time strings", function() {
|
379
|
-
expect(I18n.l("time.formats.default", "2009-11-29 15:07:59")).
|
382
|
+
expect(I18n.l("time.formats.default", "2009-11-29 15:07:59")).toMatch("nie, 29 lis 2009 15:07:59")
|
380
383
|
expect(I18n.l("time.formats.short", "2009-01-07 09:12:35")).toEqual("07 sty 09:12")
|
381
384
|
expect(I18n.l("time.formats.long", "2009-11-29 15:07:59")).toEqual("listopad 29, 2009 15:07")
|
382
385
|
})
|
383
386
|
|
384
387
|
})
|
388
|
+
|
389
|
+
describe("Pluralizations", function() {
|
390
|
+
|
391
|
+
it("correctly pluralizes the English phrase", function() {
|
392
|
+
I18n.locale = "en"
|
393
|
+
expect(I18n.t("contact", {count: 1})).toEqual("1 Contact")
|
394
|
+
expect(I18n.t("contact", {count: 2})).toEqual("2 Contacts")
|
395
|
+
expect(I18n.t("contact", {count: 22})).toEqual("22 Contacts")
|
396
|
+
})
|
397
|
+
|
398
|
+
it("correctly pluralizes the French phrase", function() {
|
399
|
+
I18n.locale = "fr"
|
400
|
+
expect(I18n.t("contact", {count: 0})).toEqual("0 contact")
|
401
|
+
expect(I18n.t("contact", {count: 1})).toEqual("1 contact")
|
402
|
+
expect(I18n.t("contact", {count: 2})).toEqual("2 contacts")
|
403
|
+
expect(I18n.t("contact", {count: 5})).toEqual("5 contacts")
|
404
|
+
})
|
405
|
+
|
406
|
+
it("correctly pluralizes the Polish phrase", function() {
|
407
|
+
I18n.locale = "pl"
|
408
|
+
expect(I18n.t("contact", {count: 1})).toEqual("1 Kontakt")
|
409
|
+
expect(I18n.t("contact", {count: 2})).toEqual("2 Kontakty")
|
410
|
+
expect(I18n.t("contact", {count: 5})).toEqual("5 Kontaktów")
|
411
|
+
expect(I18n.t("contact", {count: 12})).toEqual("12 Kontaktów")
|
412
|
+
expect(I18n.t("contact", {count: 22})).toEqual("22 Kontakty")
|
413
|
+
})
|
414
|
+
|
415
|
+
it("correctly pluralizes the Portuguese phrase", function() {
|
416
|
+
I18n.locale = "pt"
|
417
|
+
expect(I18n.t("contact", {count: 0})).toEqual("0 Contato")
|
418
|
+
expect(I18n.t("contact", {count: 1})).toEqual("1 Contato")
|
419
|
+
expect(I18n.t("contact", {count: 2})).toEqual("2 Contatos")
|
420
|
+
expect(I18n.t("contact", {count: 22})).toEqual("22 Contatos")
|
421
|
+
})
|
422
|
+
|
423
|
+
})
|
@@ -7,6 +7,11 @@ I18n.translations = {
|
|
7
7
|
hello: "Hello %{name}!",
|
8
8
|
world: "World",
|
9
9
|
|
10
|
+
contact: {
|
11
|
+
one: "1 Contact",
|
12
|
+
other: "%{count} Contacts"
|
13
|
+
},
|
14
|
+
|
10
15
|
page: {
|
11
16
|
footer: "Footer",
|
12
17
|
title: "Title",
|
@@ -17,6 +22,13 @@ I18n.translations = {
|
|
17
22
|
}
|
18
23
|
},
|
19
24
|
|
25
|
+
fr: {
|
26
|
+
contact: {
|
27
|
+
one: "%{count} contact",
|
28
|
+
other: "%{count} contacts"
|
29
|
+
}
|
30
|
+
},
|
31
|
+
|
20
32
|
pl: {
|
21
33
|
date: {
|
22
34
|
formats: {
|
@@ -81,8 +93,9 @@ I18n.translations = {
|
|
81
93
|
format: "%n %u",
|
82
94
|
units: {
|
83
95
|
byte: {
|
84
|
-
one:
|
85
|
-
|
96
|
+
one: "bajt",
|
97
|
+
few: "bajty",
|
98
|
+
other: "bajtów"
|
86
99
|
},
|
87
100
|
kb: "KB",
|
88
101
|
mb: "MB",
|
@@ -93,6 +106,19 @@ I18n.translations = {
|
|
93
106
|
}
|
94
107
|
},
|
95
108
|
|
96
|
-
world: "Świat"
|
109
|
+
world: "Świat",
|
110
|
+
|
111
|
+
contact: {
|
112
|
+
one: "1 Kontakt",
|
113
|
+
few: "%{count} Kontakty",
|
114
|
+
other: "%{count} Kontaktów"
|
115
|
+
}
|
116
|
+
},
|
117
|
+
|
118
|
+
pt: {
|
119
|
+
contact: {
|
120
|
+
one: "%{count} Contato",
|
121
|
+
other: "%{count} Contatos"
|
122
|
+
}
|
97
123
|
}
|
98
124
|
}
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: exvo_globalize
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 9
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 5
|
9
|
-
-
|
10
|
-
version: 0.5.
|
9
|
+
- 1
|
10
|
+
version: 0.5.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- "Pawe\xC5\x82 Go\xC5\x9Bcicki"
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-09-
|
18
|
+
date: 2011-09-19 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|