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 CHANGED
@@ -1,5 +1,6 @@
1
1
  *.gem
2
2
  .bundle
3
+ .jhw-cache
3
4
  Gemfile.lock
4
5
  pkg/*
5
6
  log/*
data/README.md CHANGED
@@ -1,7 +1,26 @@
1
1
  # Exvo Globalize
2
2
 
3
- This gem lets you make use of the Globalize app (http://globalize.exvo.com/)
4
- to handle the translation of your Rails app into multiple languages.
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
- => "14-09-2011"
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 (http://globalize.exvo.com/) and order some translations (Globalize should automatically detect the gem installation and should let you choose the JSON translations option).
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
- ## Running the tests
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
- Running tests via `Guard` is the recommended way:
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 tests can be run separately as well:
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
- https://github.com/svenfuchs/i18n
218
- https://github.com/svenfuchs/rails-i18n/
219
- https://github.com/toretore/babilu
220
- https://github.com/spider-network/i18n-js
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 interpolate(str, obj) {
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 keyToArray(key) {
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 locale() {
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(locale(), key, opts.defaultValue);
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(locale(), ["number", "format"]);
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(locale(), keyToArray(scope));
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(locale(), ["date"]);
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(locale(), ["time"]);
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(locale(), ["number", "format"]),
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(locale(), ["number", "currency", "format"]),
294
- this.lookup(locale(), ["number", "format"]),
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(locale(), ["number", "percentage", "format"]),
344
- this.lookup(locale(), ["number", "format"]),
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 count == 1 ? value.one : value.other;
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: "' + locale();
517
+ var message = '[missing translation: "' + I18n.current_locale();
360
518
  for (var i in key) {
361
519
  message += "." + key[i];
362
520
  }
@@ -114,7 +114,8 @@ pl:
114
114
  units:
115
115
  byte:
116
116
  one: "bajt"
117
- other: "bajty"
117
+ few: "bajty"
118
+ other: "bajtów"
118
119
  kb: "KB"
119
120
  mb: "MB"
120
121
  gb: "GB"
@@ -1,3 +1,3 @@
1
1
  module ExvoGlobalize
2
- VERSION = "0.5.0"
2
+ VERSION = "0.5.1"
3
3
  end
@@ -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(102)).toEqual("102bajty")
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 ", function() {
369
- expect(I18n.strftime(I18n.parseDate("Wed Sep 14 12:03:11 +0200 2011"), "%Y/%m/%d %H:%M")).toEqual("2011/09/14 12:03")
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")).toEqual("nie, 29 lis 2009 15:07:59 +0100")
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: "bajt",
85
- other: "bajty"
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: 11
4
+ hash: 9
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 5
9
- - 0
10
- version: 0.5.0
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-14 00:00:00 +02:00
18
+ date: 2011-09-19 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency