i18n-js 3.0.0.rc14 → 3.0.0.rc15

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 10a07ab318e610dfc7102d3d88015d8a55c42a76
4
- data.tar.gz: 21fa8daa428b711f6d592c3b14bad7183e5af2f8
3
+ metadata.gz: 3cb04a52e869d4da0331db74c65512cae5c19abc
4
+ data.tar.gz: 6522e5f84e73ca868c2054a2d67946c3d798a672
5
5
  SHA512:
6
- metadata.gz: cef3f6f68e7ca327e96902093069c47df6897074d35db121700076e3e7137d1ae68a9222e76ded1bea5e8d3145597cc0f37c9651d12a3b62ccbf766ce8374186
7
- data.tar.gz: 6940d5acc297f6482cb74caa56f64c85b2be20065a069fd26267956ee157ce139b2f92b425c9e2e55ce983c285bd66dcdae861454bc4371aa4e478687613da4d
6
+ metadata.gz: a500c069fd37898516080b518c313f8cb3cc7e0d3acc8cf9cd0a0f0b82f6f2c5f751ea777868d6de14f88fda66797f60e37246aedfbfc73942558ca648149dad
7
+ data.tar.gz: ce0941d24100dd6c414f4699de4db0fac4725c2f995129cc19cec35847e7693503570e5ca8262aa7cda7da93e8ac5712bdd94c82db58271fcbc5687c3d89128a
data/CHANGELOG.md CHANGED
@@ -2,6 +2,7 @@
2
2
  All notable changes to this project will be documented in this file.
3
3
  This project adheres to [Semantic Versioning](http://semver.org/).
4
4
 
5
+
5
6
  ## [Unreleased]
6
7
 
7
8
  ### Added
@@ -17,6 +18,34 @@ This project adheres to [Semantic Versioning](http://semver.org/).
17
18
  - Nothing
18
19
 
19
20
 
21
+ ## [3.0.0.rc15] - 2016-12-07
22
+
23
+ ### Added
24
+
25
+ - Nothing
26
+
27
+ ### Changed
28
+
29
+ - [JS] Allow `defaultValue` to work in pluralization
30
+ (PR: https://github.com/fnando/i18n-js/pull/433)
31
+ - [Ruby] Stop validating the fallback locales against `I18n.available_locales`
32
+ This allows some locales to be used as fallback locales, but not to be generated in JS.
33
+ (PR: https://github.com/fnando/i18n-js/pull/425)
34
+ - [Ruby] Remove dependency on gem `activesupport`
35
+
36
+ ### Fixed
37
+
38
+ - [JS] Stop converting numeric & boolean values into objects
39
+ when merging objects with `I18n.extend`
40
+ (PR: https://github.com/fnando/i18n-js/pull/420)
41
+ - [JS] Fix I18n pluralization fallback when tree is empty
42
+ (PR: https://github.com/fnando/i18n-js/pull/435)
43
+ - [Ruby] Use old syntax to define lambda for compatibility with older Rubies
44
+ (Issue: https://github.com/fnando/i18n-js/issues/419)
45
+ - [Ruby] Fix error raised in middleware cache cleaning in parallel test
46
+ (Issue: https://github.com/fnando/i18n-js/issues/436)
47
+
48
+
20
49
  ## [3.0.0.rc14] - 2016-08-29
21
50
 
22
51
  ### Changed
@@ -188,7 +217,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
188
217
 
189
218
 
190
219
 
191
- [Unreleased]: https://github.com/fnando/i18n-js/compare/v3.0.0.rc14...HEAD
220
+ [Unreleased]: https://github.com/fnando/i18n-js/compare/v3.0.0.rc15...HEAD
221
+ [3.0.0.rc15]: https://github.com/fnando/i18n-js/compare/v3.0.0.rc14...v3.0.0.rc15
192
222
  [3.0.0.rc14]: https://github.com/fnando/i18n-js/compare/v3.0.0.rc13...v3.0.0.rc14
193
223
  [3.0.0.rc13]: https://github.com/fnando/i18n-js/compare/v3.0.0.rc12...v3.0.0.rc13
194
224
  [3.0.0.rc12]: https://github.com/fnando/i18n-js/compare/v3.0.0.rc11...v3.0.0.rc12
data/README.md CHANGED
@@ -742,6 +742,7 @@ I18n.translations["pt-BR"] = {
742
742
  }
743
743
  ```
744
744
 
745
+
745
746
  ## Known Issues
746
747
 
747
748
  ### Missing translations in precompiled file(s) after adding any new locale file
@@ -774,6 +775,16 @@ This means that new locale files will not be detected, and so they will not trig
774
775
 
775
776
  **Note:** See issue [#213](https://github.com/fnando/i18n-js/issues/213) for more details and discussion of this issue.
776
777
 
778
+ ### Translations in JS are not updated when Sprockets not loaded before this gem
779
+
780
+ The "rails engine" declaration will try to detect existence of "sprockets" before adding the initailizer
781
+ If sprockets is loaded after this gem, the preprocessor for
782
+ making JS translations file cache to depend on content of locale files will not be hooked.
783
+ So ensure sprockets is loaded before this gem like moving entry of sprockets in Gemfile or adding "require" statements for sprockets somewhere.
784
+
785
+ **Note:** See issue [#404](https://github.com/fnando/i18n-js/issues/404) for more details and discussion of this issue.
786
+
787
+
777
788
  ## Maintainer
778
789
 
779
790
  - Nando Vieira - <http://nandovieira.com.br>
@@ -53,11 +53,23 @@
53
53
 
54
54
  // Is a given value an array?
55
55
  // Borrowed from Underscore.js
56
- var isArray = function(obj) {
56
+ var isArray = function(val) {
57
57
  if (Array.isArray) {
58
- return Array.isArray(obj);
58
+ return Array.isArray(val);
59
59
  };
60
- return Object.prototype.toString.call(obj) === '[object Array]';
60
+ return Object.prototype.toString.call(val) === '[object Array]';
61
+ };
62
+
63
+ var isString = function(val) {
64
+ return typeof value == 'string' || Object.prototype.toString.call(val) === '[object String]';
65
+ };
66
+
67
+ var isNumber = function(val) {
68
+ return typeof val == 'number' || Object.prototype.toString.call(val) === '[object Number]';
69
+ };
70
+
71
+ var isBoolean = function(val) {
72
+ return val === true || val === false;
61
73
  };
62
74
 
63
75
  var decimalAdjust = function(type, value, exp) {
@@ -83,7 +95,7 @@
83
95
  var key, value;
84
96
  for (key in obj) if (obj.hasOwnProperty(key)) {
85
97
  value = obj[key];
86
- if (Object.prototype.toString.call(value) === '[object String]') {
98
+ if (isString(value) || isNumber(value) || isBoolean(value)) {
87
99
  dest[key] = value;
88
100
  } else {
89
101
  if (dest[key] == null) dest[key] = {};
@@ -347,7 +359,6 @@
347
359
  if (!translations) {
348
360
  continue;
349
361
  }
350
-
351
362
  while (scopes.length) {
352
363
  translations = translations[scopes.shift()];
353
364
 
@@ -366,6 +377,75 @@
366
377
  }
367
378
  };
368
379
 
380
+ // lookup pluralization rule key into translations
381
+ I18n.pluralizationLookupWithoutFallback = function(count, locale, translations) {
382
+ var pluralizer = this.pluralization.get(locale)
383
+ , pluralizerKeys = pluralizer(count)
384
+ , pluralizerKey
385
+ , message;
386
+
387
+ if (isObject(translations)) {
388
+ while (pluralizerKeys.length) {
389
+ pluralizerKey = pluralizerKeys.shift();
390
+ if (this.isSet(translations[pluralizerKey])) {
391
+ message = translations[pluralizerKey];
392
+ break;
393
+ }
394
+ }
395
+ }
396
+
397
+ return message;
398
+ };
399
+
400
+ // Lookup dedicated to pluralization
401
+ I18n.pluralizationLookup = function(count, scope, options) {
402
+ options = this.prepareOptions(options);
403
+ var locales = this.locales.get(options.locale).slice()
404
+ , requestedLocale = locales[0]
405
+ , locale
406
+ , scopes
407
+ , translations
408
+ , message
409
+ ;
410
+ scope = this.getFullScope(scope, options);
411
+
412
+ while (locales.length) {
413
+ locale = locales.shift();
414
+ scopes = scope.split(this.defaultSeparator);
415
+ translations = this.translations[locale];
416
+
417
+ if (!translations) {
418
+ continue;
419
+ }
420
+
421
+ while (scopes.length) {
422
+ translations = translations[scopes.shift()];
423
+ if (!isObject(translations)) {
424
+ break;
425
+ }
426
+ if (scopes.length == 0) {
427
+ message = this.pluralizationLookupWithoutFallback(count, locale, translations);
428
+ }
429
+ }
430
+ if (message != null && message != undefined) {
431
+ break;
432
+ }
433
+ }
434
+
435
+ if (message == null || message == undefined) {
436
+ if (this.isSet(options.defaultValue)) {
437
+ if (isObject(options.defaultValue)) {
438
+ message = this.pluralizationLookupWithoutFallback(count, options.locale, options.defaultValue);
439
+ } else {
440
+ message = options.defaultValue;
441
+ }
442
+ translations = options.defaultValue;
443
+ }
444
+ }
445
+
446
+ return { message: message, translations: translations };
447
+ };
448
+
369
449
  // Rails changed the way the meridian is stored.
370
450
  // It started with `date.meridian` returning an array,
371
451
  // then it switched to `time.am` and `time.pm`.
@@ -470,7 +550,7 @@
470
550
  if (typeof(translation) === "string") {
471
551
  translation = this.interpolate(translation, options);
472
552
  } else if (isObject(translation) && this.isSet(options.count)) {
473
- translation = this.pluralize(options.count, translation, options);
553
+ translation = this.pluralize(options.count, scope, options);
474
554
  }
475
555
 
476
556
  return translation;
@@ -516,32 +596,22 @@
516
596
  // which will be retrieved from `options`.
517
597
  I18n.pluralize = function(count, scope, options) {
518
598
  options = this.prepareOptions(options);
519
- var translations, pluralizer, keys, key, message;
599
+ var pluralizer, message, result;
520
600
 
521
- if (isObject(scope)) {
522
- translations = scope;
523
- } else {
524
- translations = this.lookup(scope, options);
525
- }
526
-
527
- if (!translations) {
601
+ result = this.pluralizationLookup(count, scope, options);
602
+ if (result.translations == undefined || result.translations == null) {
528
603
  return this.missingTranslation(scope, options);
529
604
  }
530
605
 
531
- pluralizer = this.pluralization.get(options.locale);
532
- keys = pluralizer(count);
533
-
534
- while (keys.length) {
535
- key = keys.shift();
606
+ options.count = String(count);
536
607
 
537
- if (this.isSet(translations[key])) {
538
- message = translations[key];
539
- break;
540
- }
608
+ if (result.message != undefined && result.message != null) {
609
+ return this.interpolate(result.message, options);
610
+ }
611
+ else {
612
+ pluralizer = this.pluralization.get(options.locale);
613
+ return this.missingTranslation(scope + '.' + pluralizer(count)[0], options);
541
614
  }
542
-
543
- options.count = String(count);
544
- return this.interpolate(message, options);
545
615
  };
546
616
 
547
617
  // Return a missing translation message for the given parameters.
data/i18n-js.gemspec CHANGED
@@ -20,7 +20,6 @@ Gem::Specification.new do |s|
20
20
 
21
21
  s.add_dependency "i18n", "~> 0.6", ">= 0.6.6"
22
22
  s.add_development_dependency "appraisal", "~> 2.0"
23
- s.add_development_dependency "activesupport", ">= 3.2.22"
24
23
  s.add_development_dependency "rspec", "~> 3.0"
25
24
  s.add_development_dependency "rake", "~> 10.0"
26
25
  s.add_development_dependency "gem-release", ">= 0.7"
data/lib/i18n/js.rb CHANGED
@@ -1,7 +1,9 @@
1
1
  require "yaml"
2
- require "i18n"
3
2
  require "fileutils"
3
+ require "i18n"
4
+
4
5
  require "i18n/js/utils"
6
+ require "i18n/js/private/hash_with_symbol_keys"
5
7
 
6
8
  module I18n
7
9
  module JS
@@ -43,16 +45,23 @@ module I18n
43
45
  end
44
46
 
45
47
  def self.configured_segments
46
- config[:translations].inject([]) do |segments, options|
47
- file = options[:file]
48
- only = options[:only] || '*'
49
- exceptions = [options[:except] || []].flatten
48
+ config[:translations].inject([]) do |segments, options_hash|
49
+ options_hash_with_symbol_keys = Private::HashWithSymbolKeys.new(options_hash)
50
+ file = options_hash_with_symbol_keys[:file]
51
+ only = options_hash_with_symbol_keys[:only] || '*'
52
+ exceptions = [options_hash_with_symbol_keys[:except] || []].flatten
50
53
 
51
54
  result = segment_for_scope(only, exceptions)
52
55
 
53
56
  merge_with_fallbacks!(result) if fallbacks
54
57
 
55
- segments << Segment.new(file, result, extract_segment_options(options)) unless result.empty?
58
+ unless result.empty?
59
+ segments << Segment.new(
60
+ file,
61
+ result,
62
+ extract_segment_options(options_hash_with_symbol_keys),
63
+ )
64
+ end
56
65
 
57
66
  segments
58
67
  end
@@ -91,11 +100,13 @@ module I18n
91
100
  # custom output directory
92
101
  def self.config
93
102
  if config?
94
- erb = ERB.new(File.read(config_file_path)).result
95
- (YAML.load(erb) || {}).with_indifferent_access
103
+ erb_result_from_yaml_file = ERB.new(File.read(config_file_path)).result
104
+ Private::HashWithSymbolKeys.new(
105
+ (::YAML.load(erb_result_from_yaml_file) || {})
106
+ )
96
107
  else
97
- {}
98
- end
108
+ Private::HashWithSymbolKeys.new({})
109
+ end.freeze
99
110
  end
100
111
 
101
112
  # Check if configuration file exist
@@ -151,7 +162,14 @@ module I18n
151
162
  def self.translations
152
163
  ::I18n.backend.instance_eval do
153
164
  init_translations unless initialized?
154
- translations.slice(*::I18n.available_locales)
165
+ # When activesupport is absent,
166
+ # the core extension (`#slice`) from `i18n` gem will be used instead
167
+ # And it's causing errors (at least in test)
168
+ #
169
+ # So the input is wrapped by our class for better `#slice`
170
+ Private::HashWithSymbolKeys.new(translations).
171
+ slice(*::I18n.available_locales).
172
+ to_h
155
173
  end
156
174
  end
157
175
 
@@ -184,7 +202,10 @@ module I18n
184
202
  end
185
203
 
186
204
  def self.extract_segment_options(options)
187
- segment_options = {js_extend: js_extend, sort_translation_keys: sort_translation_keys?}.with_indifferent_access
205
+ segment_options = Private::HashWithSymbolKeys.new({
206
+ js_extend: js_extend,
207
+ sort_translation_keys: sort_translation_keys?,
208
+ }).freeze
188
209
  segment_options.merge(options.slice(*Segment::OPTIONS))
189
210
  end
190
211
 
@@ -32,8 +32,11 @@ module I18n
32
32
  #
33
33
  # For detail see Pull Request:
34
34
  # https://github.com/fnando/i18n-js/pull/371
35
+ #
36
+ # Not using -> for JRuby compatibility
37
+ # See https://github.com/fnando/i18n-js/issues/419
35
38
  initializer_args = case sprockets_version
36
- when -> (v) { v2_only.match?("", v) || v3_plus.match?("", v) }
39
+ when lambda {|v| v2_only.match?("", v) || v3_plus.match?("", v) }
37
40
  { after: :engines_blank_point, before: :finisher_hook }
38
41
  else
39
42
  raise StandardError, "Sprockets version #{sprockets_version} is not supported"
@@ -32,7 +32,6 @@ module I18n
32
32
  end
33
33
 
34
34
  locales.map! { |locale| locale.to_sym }
35
- ensure_valid_locales!(locales)
36
35
  locales
37
36
  end
38
37
 
@@ -66,16 +65,6 @@ module I18n
66
65
 
67
66
  fail ArgumentError, "If fallbacks is passed as Array, it must ony include Strings or Symbols. Given: #{fallbacks}"
68
67
  end
69
-
70
- # Ensures that only valid locales are returned.
71
- #
72
- # @note
73
- # This ignores option `I18n.enforce_available_locales`
74
- def ensure_valid_locales!(locales)
75
- if locales.any? { |locale| !::I18n.available_locales.include?(locale) }
76
- fail ArgumentError, "Valid locales: #{::I18n.available_locales.join(", ")} - Given Locales: #{locales.join(", ")}"
77
- end
78
- end
79
68
  end
80
69
  end
81
70
  end
@@ -1,3 +1,5 @@
1
+ require "fileutils"
2
+
1
3
  module I18n
2
4
  module JS
3
5
  class Middleware
@@ -32,7 +34,13 @@ module I18n
32
34
  end
33
35
 
34
36
  def clear_cache
35
- File.delete(cache_path) if File.exist?(cache_path)
37
+ # `File.delete` will raise error when "multiple worker"
38
+ # Are running at the same time, like in a parallel test
39
+ #
40
+ # `FileUtils.rm_f` is tested manually
41
+ #
42
+ # See https://github.com/fnando/i18n-js/issues/436
43
+ FileUtils.rm_f(cache_path) if File.exist?(cache_path)
36
44
  end
37
45
 
38
46
  def save_cache(new_cache)
@@ -0,0 +1,36 @@
1
+ module I18n
2
+ module JS
3
+ # @api private
4
+ module Private
5
+ # Hash with string keys converted to symbol keys
6
+ # Used for handling values read on YAML
7
+ #
8
+ # @api private
9
+ class HashWithSymbolKeys < ::Hash
10
+ # An instance can only be created by passing in another hash
11
+ def initialize(hash)
12
+ raise TypeError unless hash.is_a?(::Hash)
13
+
14
+ hash.each_key do |key|
15
+ # Objects like `Integer` does not have `to_sym`
16
+ new_key = key.respond_to?(:to_sym) ? key.to_sym : key
17
+ self[new_key] = hash[key]
18
+ end
19
+
20
+ self.default = hash.default if hash.default
21
+ self.default_proc = hash.default_proc if hash.default_proc
22
+
23
+ freeze
24
+ end
25
+
26
+ # From AS Core extension
27
+ def slice(*keys)
28
+ hash = keys.each_with_object(Hash.new) do |k, hash|
29
+ hash[k] = self[k] if has_key?(k)
30
+ end
31
+ self.class.new(hash)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -1,3 +1,5 @@
1
+ require "i18n/js/private/hash_with_symbol_keys"
2
+
1
3
  module I18n
2
4
  module JS
3
5
 
@@ -10,7 +12,13 @@ module I18n
10
12
 
11
13
  def initialize(file, translations, options = {})
12
14
  @file = file
13
- @translations = translations
15
+ # `#slice` will be used
16
+ # But when activesupport is absent,
17
+ # the core extension from `i18n` gem will be used instead
18
+ # And it's causing errors (at least in test)
19
+ #
20
+ # So the input is wrapped by our class for better `#slice`
21
+ @translations = Private::HashWithSymbolKeys.new(translations)
14
22
  @namespace = options[:namespace] || 'I18n'
15
23
  @pretty_print = !!options[:pretty_print]
16
24
  @js_extend = options.key?(:js_extend) ? !!options[:js_extend] : true
@@ -4,7 +4,7 @@ module I18n
4
4
  MAJOR = 3
5
5
  MINOR = 0
6
6
  PATCH = 0
7
- STRING = "#{MAJOR}.#{MINOR}.#{PATCH}.rc14"
7
+ STRING = "#{MAJOR}.#{MINOR}.#{PATCH}.rc15"
8
8
  end
9
9
  end
10
10
  end
@@ -58,5 +58,28 @@ describe("Extend", function () {
58
58
  }
59
59
 
60
60
  expect(I18n.extend(obj1, obj2)).toEqual(expected);
61
- })
61
+ });
62
+
63
+ it("should correctly merge string, numberic and boolean values", function() {
64
+ var obj1 = {
65
+ test1: {
66
+ test2: false
67
+ }
68
+ }
69
+ , obj2 = {
70
+ test1: {
71
+ test3: 23,
72
+ test4: 'abc'
73
+ }
74
+ }
75
+ , expected = {
76
+ test1: {
77
+ test2: false
78
+ , test3: 23
79
+ , test4: 'abc'
80
+ }
81
+ }
82
+
83
+ expect(I18n.extend(obj1, obj2)).toEqual(expected);
84
+ });
62
85
  });
@@ -46,6 +46,17 @@ describe("Interpolation", function(){
46
46
  expect(I18n.t(translation_key, {count: 5})).toEqual("Hello World!");
47
47
  });
48
48
  });
49
+ describe("and translation key does contain pluralization with null content", function() {
50
+ beforeEach(function() {
51
+ translation_key = "sent";
52
+ });
53
+
54
+ it("return empty string", function() {
55
+ expect(I18n.t(translation_key, {count: 0})).toEqual('[missing "en.sent.zero" translation]');
56
+ expect(I18n.t(translation_key, {count: 1})).toEqual('[missing "en.sent.one" translation]');
57
+ expect(I18n.t(translation_key, {count: 5})).toEqual('[missing "en.sent.other" translation]');
58
+ });
59
+ });
49
60
  });
50
61
 
51
62
  describe("when count is NOT passed in", function() {
@@ -57,6 +57,16 @@ describe("Pluralization", function(){
57
57
  expect(I18n.p(0, "inbox")).toEqual("");
58
58
  });
59
59
 
60
+ it("returns missing message on null values", function(){
61
+ I18n.translations["en"]["sent"]["zero"] = null;
62
+ I18n.translations["en"]["sent"]["one"] = null;
63
+ I18n.translations["en"]["sent"]["other"] = null;
64
+
65
+ expect(I18n.p(0, "sent")).toEqual('[missing "en.sent.zero" translation]');
66
+ expect(I18n.p(1, "sent")).toEqual('[missing "en.sent.one" translation]');
67
+ expect(I18n.p(5, "sent")).toEqual('[missing "en.sent.other" translation]');
68
+ });
69
+
60
70
  it("pluralizes using custom rules", function() {
61
71
  I18n.locale = "custom";
62
72
 
@@ -103,4 +113,99 @@ describe("Pluralization", function(){
103
113
  expect(I18n.p(1, "inbox", options)).toEqual("You have 1 message");
104
114
  expect(I18n.p(5, "inbox", options)).toEqual("You have 5 messages");
105
115
  });
116
+
117
+ it("fallback to default locale when I18n.fallbacks is enabled", function() {
118
+ I18n.locale = "pt-BR";
119
+ I18n.fallbacks = true;
120
+ I18n.translations["pt-BR"].inbox= {
121
+ one: null
122
+ , other: null
123
+ , zero: null
124
+ };
125
+ expect(I18n.p(0, "inbox", { count: 0 })).toEqual("You have no messages");
126
+ expect(I18n.p(1, "inbox", { count: 1 })).toEqual("You have 1 message");
127
+ expect(I18n.p(5, "inbox", { count: 5 })).toEqual("You have 5 messages");
128
+ });
129
+
130
+ it("fallback to default locale when I18n.fallbacks is enabled", function() {
131
+ I18n.locale = "pt-BR";
132
+ I18n.fallbacks = true;
133
+ I18n.translations["pt-BR"].inbox= {
134
+ one: "Você tem uma mensagem"
135
+ , other: null
136
+ , zero: "Você não tem nenhuma mensagem"
137
+ };
138
+ expect(I18n.p(0, "inbox", { count: 0 })).toEqual("Você não tem nenhuma mensagem");
139
+ expect(I18n.p(1, "inbox", { count: 1 })).toEqual("Você tem uma mensagem");
140
+ expect(I18n.p(5, "inbox", { count: 5 })).toEqual('You have 5 messages');
141
+ });
142
+
143
+ it("fallback to 'other' scope", function() {
144
+ I18n.locale = "pt-BR";
145
+ I18n.fallbacks = true;
146
+ I18n.translations["pt-BR"].inbox= {
147
+ one: "Você tem uma mensagem"
148
+ , other: "Você tem {{count}} mensagens"
149
+ , zero: null
150
+ }
151
+ expect(I18n.p(0, "inbox", { count: 0 })).toEqual("Você tem 0 mensagens");
152
+ expect(I18n.p(1, "inbox", { count: 1 })).toEqual("Você tem uma mensagem");
153
+ expect(I18n.p(5, "inbox", { count: 5 })).toEqual("Você tem 5 mensagens");
154
+ });
155
+
156
+ it("fallback to defaulValue when defaultValue is string", function() {
157
+ I18n.locale = "pt-BR";
158
+ I18n.fallbacks = true;
159
+ I18n.translations["en"]["inbox"]["zero"] = null;
160
+ I18n.translations["en"]["inbox"]["one"] = null;
161
+ I18n.translations["en"]["inbox"]["other"] = null;
162
+ I18n.translations["pt-BR"].inbox= {
163
+ one: "Você tem uma mensagem"
164
+ , other: null
165
+ , zero: null
166
+ }
167
+ options = {
168
+ defaultValue: "default message"
169
+ };
170
+ expect(I18n.p(0, "inbox", options)).toEqual("default message");
171
+ expect(I18n.p(1, "inbox", options)).toEqual("Você tem uma mensagem");
172
+ expect(I18n.p(5, "inbox", options)).toEqual("default message");
173
+ });
174
+
175
+ it("fallback to defaulValue when defaultValue is an object", function() {
176
+ I18n.locale = "pt-BR";
177
+ I18n.fallbacks = true;
178
+ I18n.translations["en"]["inbox"]["zero"] = null;
179
+ I18n.translations["en"]["inbox"]["one"] = null;
180
+ I18n.translations["en"]["inbox"]["other"] = null;
181
+ I18n.translations["pt-BR"].inbox= {
182
+ one: "Você tem uma mensagem"
183
+ , other: null
184
+ , zero: null
185
+ }
186
+ options = {
187
+ defaultValue: {
188
+ zero: "default message for no message"
189
+ , one: "default message for 1 message"
190
+ , other: "default message for {{count}} messages"
191
+ }
192
+ };
193
+ expect(I18n.p(0, "inbox", options)).toEqual("default message for no message");
194
+ expect(I18n.p(1, "inbox", options)).toEqual("Você tem uma mensagem");
195
+ expect(I18n.p(5, "inbox", options)).toEqual("default message for 5 messages");
196
+ });
197
+
198
+ it("fallback to default locale when I18n.fallbacks is enabled and no translations in sub scope", function() {
199
+ I18n.locale = "pt-BR";
200
+ I18n.fallbacks = true;
201
+ I18n.translations["en"]["mailbox"] = {
202
+ inbox: I18n.translations["en"].inbox
203
+ }
204
+
205
+ expect(I18n.translations["pt-BR"]["mailbox"]).toEqual(undefined);
206
+ expect(I18n.p(0, "mailbox.inbox", { count: 0 })).toEqual("You have no messages");
207
+ expect(I18n.p(1, "mailbox.inbox", { count: 1 })).toEqual("You have 1 message");
208
+ expect(I18n.p(5, "mailbox.inbox", { count: 5 })).toEqual("You have 5 messages");
209
+ });
210
+
106
211
  });
@@ -30,6 +30,12 @@ var DEBUG = false;
30
30
  , zero: "You have no messages"
31
31
  }
32
32
 
33
+ , sent: {
34
+ one: null
35
+ , other: null
36
+ , zero: null
37
+ }
38
+
33
39
  , unread: {
34
40
  one: "You have 1 new message ({{unread}} unread)"
35
41
  , other: "You have {{count}} new messages ({{unread}} unread)"
@@ -42,7 +42,7 @@ describe I18n::JS::FallbackLocales do
42
42
 
43
43
  context "when given a invalid locale as fallbacks" do
44
44
  let(:fallbacks) { :invalid_locale }
45
- it { expect(fetching_locales).to raise_error(ArgumentError) }
45
+ it { should eq([:invalid_locale]) }
46
46
  end
47
47
 
48
48
  context "when given a invalid type as fallbacks" do
@@ -50,16 +50,6 @@ describe I18n::JS::FallbackLocales do
50
50
  it { expect(fetching_locales).to raise_error(ArgumentError) }
51
51
  end
52
52
 
53
- context "when given an invalid Array as fallbacks" do
54
- let(:fallbacks) { [:de, :en, :invalid_locale] }
55
- it { expect(fetching_locales).to raise_error(ArgumentError) }
56
- end
57
-
58
- context "when given a invalid Hash as fallbacks" do
59
- let(:fallbacks) do { :fr => [:de, :en, :invalid_locale] } end
60
- it { expect(fetching_locales).to raise_error(ArgumentError) }
61
- end
62
-
63
53
  # I18n::Backend::Fallbacks
64
54
  context "when I18n::Backend::Fallbacks is used" do
65
55
  let(:backend_with_fallbacks) { backend_class_with_fallbacks.new }
@@ -405,7 +405,7 @@ EOS
405
405
  it "executes erb in config file" do
406
406
  set_config "erb.yml"
407
407
 
408
- config_entry = I18n::JS.config["translations"].first
408
+ config_entry = I18n::JS.config[:translations].first
409
409
  config_entry["only"].should eq("*.date.formats")
410
410
  end
411
411
  end
data/spec/spec_helper.rb CHANGED
@@ -1,14 +1,16 @@
1
1
  require "i18n"
2
2
  require "json"
3
3
 
4
- require "active_support/all"
5
4
  require "i18n/js"
6
5
 
7
6
  module Helpers
8
7
  # Set the configuration as the current one
9
8
  def set_config(path)
10
9
  config_file_path = File.dirname(__FILE__) + "/fixtures/#{path}"
11
- I18n::JS.stub(:config? => true, :config_file_path => config_file_path)
10
+ allow(I18n::JS).to receive_messages(
11
+ :config? => true,
12
+ :config_file_path => config_file_path,
13
+ )
12
14
  end
13
15
 
14
16
  # Shortcut to I18n::JS.translations
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: i18n-js
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0.rc14
4
+ version: 3.0.0.rc15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nando Vieira
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-29 00:00:00.000000000 Z
11
+ date: 2016-12-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: i18n
@@ -44,20 +44,6 @@ dependencies:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
46
  version: '2.0'
47
- - !ruby/object:Gem::Dependency
48
- name: activesupport
49
- requirement: !ruby/object:Gem::Requirement
50
- requirements:
51
- - - ">="
52
- - !ruby/object:Gem::Version
53
- version: 3.2.22
54
- type: :development
55
- prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- requirements:
58
- - - ">="
59
- - !ruby/object:Gem::Version
60
- version: 3.2.22
61
47
  - !ruby/object:Gem::Dependency
62
48
  name: rspec
63
49
  requirement: !ruby/object:Gem::Requirement
@@ -127,6 +113,7 @@ files:
127
113
  - lib/i18n/js/engine.rb
128
114
  - lib/i18n/js/fallback_locales.rb
129
115
  - lib/i18n/js/middleware.rb
116
+ - lib/i18n/js/private/hash_with_symbol_keys.rb
130
117
  - lib/i18n/js/segment.rb
131
118
  - lib/i18n/js/utils.rb
132
119
  - lib/i18n/js/version.rb
@@ -208,7 +195,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
208
195
  version: 1.3.1
209
196
  requirements: []
210
197
  rubyforge_project:
211
- rubygems_version: 2.6.6
198
+ rubygems_version: 2.6.7
212
199
  signing_key:
213
200
  specification_version: 4
214
201
  summary: It's a small library to provide the Rails I18n translations on the Javascript.