i18n-js 3.2.0 → 3.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d31e5a96a37e60b0fddf00af9f9bad30a93b66adde3d85e3ad9b9b2771c31bdc
4
- data.tar.gz: e615279399a220d76c6678d63e797b2abd5b843ae92078fab95b1bfc220b2b16
3
+ metadata.gz: ceb49e2e527b6abd26c72eb57d2489197ed2d3991b24bc79acef35869a171232
4
+ data.tar.gz: 40f6a0b8c6c9d312db6a859123f22f7a8a46e7ef92f495b7ea024d6885e88b85
5
5
  SHA512:
6
- metadata.gz: f43b695fba0788ca02c5a36776b1f197895cc639640f4fc96a1bb5a8cd236229991f69ab83c08e1a2d0163cc77f68832ba45b34c0f61903b28b76305e590ff94
7
- data.tar.gz: 387b2be62ae991d415c9c599cf9b56c4162654bbb2ee5cd5e11b8b264f6d79f2f14b007d16051c4a9d1c5a0b50d15f8f94cbe2b9dea2623a9daf1fe6b92c67bf
6
+ metadata.gz: 030147ab7bb566fcadadb31090480fbcf233850ec9ea0468e8b4d7d984d8a5a77c7e9a7366e8babb40139313c2306774d10e8812869c0a6c083d66b9a4312224
7
+ data.tar.gz: 388552233bb2a66c6c899d28daca4a9ca49aa115b19cc765ba2cbe00308f9c4b3840fb92c0ca4fc71a78e5a2bed5a780e8cc7431348a7d53f5b11dc806d741ed
@@ -8,23 +8,25 @@ cache:
8
8
  directories:
9
9
  - node_modules
10
10
  rvm:
11
- - 2.1
12
- - 2.2
13
11
  - 2.3
14
12
  - 2.4
15
13
  - 2.5
14
+ - 2.6
16
15
  - ruby-head
17
16
  before_install:
18
- # Need to install something extra to test JS
17
+ # Needed to test JS
19
18
  - yarn install
20
- # Bundler 1.16.1 and rubygems 2.7.3 got issue
21
- # https://github.com/travis-ci/travis-ci/issues/8978#issuecomment-354036443
22
- - gem update --system
23
19
  gemfile:
20
+ - gemfiles/i18n_0_6.gemfile
21
+ - gemfiles/i18n_0_7.gemfile
24
22
  - gemfiles/i18n_0_8.gemfile
25
23
  - gemfiles/i18n_0_9.gemfile
26
24
  - gemfiles/i18n_1_0.gemfile
27
25
  - gemfiles/i18n_1_1.gemfile
26
+ - gemfiles/i18n_1_2.gemfile
27
+ - gemfiles/i18n_1_3.gemfile
28
+ - gemfiles/i18n_1_4.gemfile
29
+ - gemfiles/i18n_1_5.gemfile
28
30
  matrix:
29
31
  fast_finish: true
30
32
  allow_failures:
data/Appraisals CHANGED
@@ -14,3 +14,19 @@ end
14
14
  appraise "i18n_1_1" do
15
15
  gem "i18n", "~> 1.1.0"
16
16
  end
17
+
18
+ appraise "i18n_1_2" do
19
+ gem "i18n", "~> 1.2.0"
20
+ end
21
+
22
+ appraise "i18n_1_3" do
23
+ gem "i18n", "~> 1.3.0"
24
+ end
25
+
26
+ appraise "i18n_1_4" do
27
+ gem "i18n", "~> 1.4.0"
28
+ end
29
+
30
+ appraise "i18n_1_5" do
31
+ gem "i18n", "~> 1.5.1"
32
+ end
@@ -18,6 +18,24 @@ This project adheres to [Semantic Versioning](http://semver.org/).
18
18
  - Nothing
19
19
 
20
20
 
21
+ ## [3.2.1] - 2019-01-22
22
+
23
+ ### Changed
24
+
25
+ - [Ruby] `json_only` option should allow multiple locales.
26
+ (PR: https://github.com/fnando/i18n-js/pull/531)
27
+ - [Ruby] Simplified and cleaned code related to JS/JSON formatting.
28
+ (PR: https://github.com/fnando/i18n-js/pull/531)
29
+ - [JS] Use strict value comparison
30
+
31
+ ### Fixed
32
+
33
+ - [Ruby] Relax `i18n` version requirement back to `>= 0.6.6`
34
+ (PR: https://github.com/fnando/i18n-js/pull/530)
35
+ - [Ruby] Fix merging of plural keys across locales.
36
+ (PR: https://github.com/fnando/i18n-js/pull/472)
37
+
38
+
21
39
  ## [3.2.0] - 2018-11-16
22
40
 
23
41
  ### Added
@@ -359,7 +377,8 @@ And today is not April Fools' Day
359
377
 
360
378
 
361
379
 
362
- [Unreleased]: https://github.com/fnando/i18n-js/compare/v3.2.0...HEAD
380
+ [Unreleased]: https://github.com/fnando/i18n-js/compare/v3.2.1...HEAD
381
+ [3.2.1]: https://github.com/fnando/i18n-js/compare/v3.2.0...v3.2.1
363
382
  [3.2.0]: https://github.com/fnando/i18n-js/compare/v3.1.0...v3.2.0
364
383
  [3.1.0]: https://github.com/fnando/i18n-js/compare/v3.0.11...v3.1.0
365
384
  [3.0.11]: https://github.com/fnando/i18n-js/compare/v3.0.10...v3.0.11
@@ -107,7 +107,7 @@
107
107
  // Shift back
108
108
  value = value.toString().split('e');
109
109
  return +(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp));
110
- }
110
+ };
111
111
 
112
112
  var lazyEvaluate = function(message, scope) {
113
113
  if (isFunction(message)) {
@@ -115,7 +115,7 @@
115
115
  } else {
116
116
  return message;
117
117
  }
118
- }
118
+ };
119
119
 
120
120
  var merge = function (dest, obj) {
121
121
  var key, value;
@@ -389,7 +389,7 @@
389
389
  // This is used internally by some functions and should not be used as an
390
390
  // public API.
391
391
  I18n.lookup = function(scope, options) {
392
- options = options || {}
392
+ options = options || {};
393
393
 
394
394
  var locales = this.locales.get(options.locale).slice()
395
395
  , locale
@@ -448,7 +448,7 @@
448
448
 
449
449
  // Lookup dedicated to pluralization
450
450
  I18n.pluralizationLookup = function(count, scope, options) {
451
- options = options || {}
451
+ options = options || {};
452
452
  var locales = this.locales.get(options.locale).slice()
453
453
  , locale
454
454
  , scopes
@@ -471,16 +471,16 @@
471
471
  if (!isObject(translations)) {
472
472
  break;
473
473
  }
474
- if (scopes.length == 0) {
474
+ if (scopes.length === 0) {
475
475
  message = this.pluralizationLookupWithoutFallback(count, locale, translations);
476
476
  }
477
477
  }
478
- if (message != null && message != undefined) {
478
+ if (typeof message !== "undefined" && message !== null) {
479
479
  break;
480
480
  }
481
481
  }
482
482
 
483
- if (message == null || message == undefined) {
483
+ if (typeof message === "undefined" || message === null) {
484
484
  if (isSet(options.defaultValue)) {
485
485
  if (isObject(options.defaultValue)) {
486
486
  message = this.pluralizationLookupWithoutFallback(count, options.locale, options.defaultValue);
@@ -570,7 +570,7 @@
570
570
 
571
571
  // Translate the given scope with the provided options.
572
572
  I18n.translate = function(scope, options) {
573
- options = options || {}
573
+ options = options || {};
574
574
 
575
575
  var translationOptions = this.createTranslationOptions(scope, options);
576
576
 
@@ -619,7 +619,7 @@
619
619
  return message;
620
620
  }
621
621
 
622
- options = options || {}
622
+ options = options || {};
623
623
  var matches = message.match(this.placeholder)
624
624
  , placeholder
625
625
  , value
@@ -631,8 +631,6 @@
631
631
  return message;
632
632
  }
633
633
 
634
- var value;
635
-
636
634
  while (matches.length) {
637
635
  placeholder = matches.shift();
638
636
  name = placeholder.replace(this.placeholder, "$1");
@@ -645,7 +643,7 @@
645
643
  value = this.missingPlaceholder(placeholder, message, options);
646
644
  }
647
645
 
648
- regex = new RegExp(placeholder.replace(/\{/gm, "\\{").replace(/\}/gm, "\\}"));
646
+ regex = new RegExp(placeholder.replace(/{/gm, "\\{").replace(/}/gm, "\\}"));
649
647
  message = message.replace(regex, value);
650
648
  }
651
649
 
@@ -657,14 +655,14 @@
657
655
  // which will be retrieved from `options`.
658
656
  I18n.pluralize = function(count, scope, options) {
659
657
  options = this.prepareOptions({count: String(count)}, options)
660
- var pluralizer, message, result;
658
+ var pluralizer, result;
661
659
 
662
660
  result = this.pluralizationLookup(count, scope, options);
663
- if (result.translations == undefined || result.translations == null) {
661
+ if (typeof result.translations === "undefined" || result.translations == null) {
664
662
  return this.missingTranslation(scope, options);
665
663
  }
666
664
 
667
- if (result.message != undefined && result.message != null) {
665
+ if (typeof result.message !== "undefined" && result.message != null) {
668
666
  return this.interpolate(result.message, options);
669
667
  }
670
668
  else {
@@ -676,7 +674,7 @@
676
674
  // Return a missing translation message for the given parameters.
677
675
  I18n.missingTranslation = function(scope, options) {
678
676
  //guess intended string
679
- if(this.missingBehaviour == 'guess'){
677
+ if(this.missingBehaviour === 'guess'){
680
678
  //get only the last portion of the scope
681
679
  var s = scope.split('.').slice(-1)[0];
682
680
  //replace underscore with space && camelcase with space and lowercase letter
@@ -838,7 +836,7 @@
838
836
  // we have a date, so just return it.
839
837
  if (typeof(date) == "object") {
840
838
  return date;
841
- };
839
+ }
842
840
 
843
841
  matches = date.toString().match(/(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2}):(\d{2})([\.,]\d{1,3})?)?(Z|\+00:?00)?/);
844
842
 
@@ -1036,7 +1034,7 @@
1036
1034
  };
1037
1035
 
1038
1036
  I18n.getFullScope = function(scope, options) {
1039
- options = options || {}
1037
+ options = options || {};
1040
1038
 
1041
1039
  // Deal with the scope as an array.
1042
1040
  if (isArray(scope)) {
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "i18n", "~> 0.6.0"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "i18n", "~> 0.7.0"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "i18n", "~> 1.2.0"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "i18n", "~> 1.3.0"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "i18n", "~> 1.4.0"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "i18n", "~> 1.5.1"
6
+
7
+ gemspec path: "../"
@@ -18,9 +18,7 @@ Gem::Specification.new do |s|
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
19
  s.require_paths = ["lib"]
20
20
 
21
- # CVE-2014-10077 which is fixed for >= 0.8.0
22
- # https://nvd.nist.gov/vuln/detail/CVE-2014-10077
23
- s.add_dependency "i18n", ">= 0.8.0", "< 2"
21
+ s.add_dependency "i18n", ">= 0.6.6"
24
22
 
25
23
  s.add_development_dependency "appraisal", "~> 2.0"
26
24
  s.add_development_dependency "rspec", "~> 3.0"
@@ -0,0 +1,23 @@
1
+ module I18n
2
+ module JS
3
+ module Formatters
4
+ class Base
5
+ def initialize(js_extend: false, namespace: nil, pretty_print: false)
6
+ @js_extend = js_extend
7
+ @namespace = namespace
8
+ @pretty_print = pretty_print
9
+ end
10
+
11
+ protected
12
+
13
+ def format_json(translations)
14
+ if @pretty_print
15
+ ::JSON.pretty_generate(translations)
16
+ else
17
+ translations.to_json
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,31 @@
1
+ require "i18n/js/formatters/base"
2
+
3
+ module I18n
4
+ module JS
5
+ module Formatters
6
+ class JS < Base
7
+ def format(translations)
8
+ contents = header
9
+ translations.each do |locale, translations_for_locale|
10
+ contents << line(locale, format_json(translations_for_locale))
11
+ end
12
+ contents
13
+ end
14
+
15
+ protected
16
+
17
+ def header
18
+ %(#{@namespace}.translations || (#{@namespace}.translations = {});\n)
19
+ end
20
+
21
+ def line(locale, translations)
22
+ if @js_extend
23
+ %(#{@namespace}.translations["#{locale}"] = I18n.extend((#{@namespace}.translations["#{locale}"] || {}), #{translations});\n)
24
+ else
25
+ %(#{@namespace}.translations["#{locale}"] = #{translations};\n)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,13 @@
1
+ require "i18n/js/formatters/base"
2
+
3
+ module I18n
4
+ module JS
5
+ module Formatters
6
+ class JSON < Base
7
+ def format(translations)
8
+ format_json(translations)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,5 +1,6 @@
1
1
  require "i18n/js/private/hash_with_symbol_keys"
2
- require "i18n/js/errors"
2
+ require "i18n/js/formatters/js"
3
+ require "i18n/js/formatters/json"
3
4
 
4
5
  module I18n
5
6
  module JS
@@ -34,21 +35,20 @@ module I18n
34
35
  write_file(file_for_locale(locale), @translations.slice(locale))
35
36
  end
36
37
  else
37
- if @json_only
38
- raise I18n::JS::JsonOnlyLocaleRequiredError
39
- end
40
38
  write_file
41
39
  end
42
40
  end
43
41
 
44
42
  protected
45
43
 
44
+ def file_for_locale(locale)
45
+ @file.gsub(LOCALE_INTERPOLATOR, locale.to_s)
46
+ end
47
+
46
48
  def write_file(_file = @file, _translations = @translations)
47
49
  FileUtils.mkdir_p File.dirname(_file)
48
- contents = js_header
49
- _translations.each do |locale, translations_for_locale|
50
- contents << js_translations(locale, translations_for_locale)
51
- end
50
+ _translations = Utils.deep_key_sort(_translations) if @sort_translation_keys
51
+ contents = formatter.format(_translations)
52
52
 
53
53
  return if File.exist?(_file) && File.read(_file) == contents
54
54
 
@@ -57,42 +57,18 @@ module I18n
57
57
  end
58
58
  end
59
59
 
60
- def js_header
60
+ def formatter
61
61
  if @json_only
62
- ''
62
+ Formatters::JSON.new(**formatter_options)
63
63
  else
64
- %(#{@namespace}.translations || (#{@namespace}.translations = {});\n)
64
+ Formatters::JS.new(**formatter_options)
65
65
  end
66
66
  end
67
67
 
68
- def js_translations(locale, translations)
69
- translations = Utils.deep_key_sort(translations) if @sort_translation_keys
70
- translations = print_json(translations)
71
- js_translations_line(locale, translations)
72
- end
73
-
74
- def js_translations_line(locale, translations)
75
- if @json_only
76
- %({"#{locale}":#{translations}})
77
- elsif @js_extend
78
- %(#{@namespace}.translations["#{locale}"] = I18n.extend((#{@namespace}.translations["#{locale}"] || {}), #{translations});\n)
79
- else
80
- %(#{@namespace}.translations["#{locale}"] = #{translations};\n)
81
- end
82
- end
83
-
84
- # Outputs pretty or ugly JSON depending on :pretty_print option
85
- def print_json(translations)
86
- if @pretty_print
87
- JSON.pretty_generate(translations)
88
- else
89
- translations.to_json
90
- end
91
- end
92
-
93
- # interpolates filename
94
- def file_for_locale(locale)
95
- @file.gsub(LOCALE_INTERPOLATOR, locale.to_s)
68
+ def formatter_options
69
+ { js_extend: @js_extend,
70
+ namespace: @namespace,
71
+ pretty_print: @pretty_print }
96
72
  end
97
73
  end
98
74
  end
@@ -1,10 +1,23 @@
1
1
  module I18n
2
2
  module JS
3
3
  module Utils
4
- # deep_merge by Stefan Rusterholz, see <http://www.ruby-forum.com/topic/142809>.
5
- # The last result is modified to treat `nil` as missing key
4
+ PLURAL_KEYS = %i[zero one two few many other].freeze
5
+
6
+ # Based on deep_merge by Stefan Rusterholz, see <http://www.ruby-forum.com/topic/142809>.
7
+ # This method is used to handle I18n fallbacks. Given two equivalent path nodes in two locale trees:
8
+ # 1. If the node in the current locale appears to be an I18n pluralization (:one, :other, etc.),
9
+ # use the node as-is without merging. This prevents mixing locales with different pluralization schemes.
10
+ # 2. Else if both nodes are Hashes, combine (merge) the key-value pairs of the two nodes into one,
11
+ # prioritizing the current locale.
12
+ # 3. Else if either node is nil, use the other node.
6
13
  MERGER = proc do |_key, v1, v2|
7
- Hash === v1 && Hash === v2 ? v1.merge(v2, &MERGER) : (v2.nil? ? v1 : v2)
14
+ if Hash === v2 && (v2.keys - PLURAL_KEYS).empty?
15
+ v2
16
+ elsif Hash === v1 && Hash === v2
17
+ v1.merge(v2, &MERGER)
18
+ else
19
+ v2.nil? ? v1 : v2
20
+ end
8
21
  end
9
22
 
10
23
  HASH_NIL_VALUE_CLEANER_PROC = proc do |k, v|
@@ -2,6 +2,6 @@
2
2
 
3
3
  module I18n
4
4
  module JS
5
- VERSION = "3.2.0"
5
+ VERSION = "3.2.1"
6
6
  end
7
7
  end
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "i18n-js",
3
- "version": "3.1.0",
3
+ "version": "3.2.1",
4
4
  "description": "A javascript library similar to Ruby on Rails i18n gem",
5
5
  "author": "Nando Vieira",
6
6
  "license": "MIT",
@@ -6,3 +6,13 @@ translations:
6
6
  only:
7
7
  - "*.date.formats.*"
8
8
  - "*.number.currency.*"
9
+
10
+ - file: "tmp/i18n-js/json_only_multi.js"
11
+ only:
12
+ - "*.date.formats.*"
13
+ - "*.number.currency.*"
14
+
15
+ - file: "tmp/i18n-js/json_only_multi_pretty.js"
16
+ only:
17
+ - "*.date.formats.*"
18
+ - "*.number.currency.*"
@@ -37,6 +37,9 @@ en:
37
37
  foo: "Foo"
38
38
  fallback_test: "Success"
39
39
  null_test: "fallback for null"
40
+ merge_plurals:
41
+ one: Apple
42
+ other: Apples
40
43
 
41
44
  de:
42
45
  fallback_test: "Erfolg"
@@ -81,6 +84,10 @@ fr:
81
84
  note: "plus de détails"
82
85
  edit:
83
86
  title: "Editer"
87
+ merge_plurals:
88
+ zero: Pomme
89
+ one: Pomme
90
+ other: Pommes
84
91
 
85
92
  ja:
86
93
  admin:
@@ -0,0 +1,6 @@
1
+ fallbacks: false
2
+
3
+ translations:
4
+ - file: "tmp/i18n-js/merge_plurals.js"
5
+ only:
6
+ - "*.merge_plurals"
@@ -1,4 +1,3 @@
1
- var DEBUG = false;
2
1
 
3
2
  ;(function(){
4
3
  var generator = function() {
@@ -19,22 +19,22 @@ describe I18n::JS::Segment do
19
19
  describe ".new" do
20
20
 
21
21
  it "should persist the file path variable" do
22
- subject.file.should eql("tmp/i18n-js/segment.js")
22
+ expect(subject.file).to eql("tmp/i18n-js/segment.js")
23
23
  end
24
24
 
25
25
  it "should persist the translations variable" do
26
- subject.translations.should eql(translations)
26
+ expect(subject.translations).to eql(translations)
27
27
  end
28
28
 
29
29
  it "should persist the namespace variable" do
30
- subject.namespace.should eql("MyNamespace")
30
+ expect(subject.namespace).to eql("MyNamespace")
31
31
  end
32
32
 
33
33
  context "when namespace is nil" do
34
34
  let(:namespace){ nil }
35
35
 
36
36
  it "should default namespace to `I18n`" do
37
- subject.namespace.should eql("I18n")
37
+ expect(subject.namespace).to eql("I18n")
38
38
  end
39
39
  end
40
40
 
@@ -42,13 +42,13 @@ describe I18n::JS::Segment do
42
42
  subject { I18n::JS::Segment.new(file, translations) }
43
43
 
44
44
  it "should default namespace to `I18n`" do
45
- subject.namespace.should eql("I18n")
45
+ expect(subject.namespace).to eql("I18n")
46
46
  end
47
47
  end
48
48
 
49
49
  context "when pretty_print is nil" do
50
50
  it "should set pretty_print to false" do
51
- subject.pretty_print.should be false
51
+ expect(subject.pretty_print).to be false
52
52
  end
53
53
  end
54
54
 
@@ -56,7 +56,7 @@ describe I18n::JS::Segment do
56
56
  let(:pretty_print){ 1 }
57
57
 
58
58
  it "should set pretty_print to true" do
59
- subject.pretty_print.should be true
59
+ expect(subject.pretty_print).to be true
60
60
  end
61
61
  end
62
62
  end
@@ -64,19 +64,20 @@ describe I18n::JS::Segment do
64
64
  describe "#saving!" do
65
65
  before { allow(I18n::JS).to receive(:export_i18n_js_dir_path).and_return(temp_path) }
66
66
 
67
- context "when json_only is true" do
67
+ context "when json_only is true with locale" do
68
68
  let(:file){ "tmp/i18n-js/%{locale}.js" }
69
69
  let(:json_only){ true }
70
- it 'should output the keys as sorted' do
70
+
71
+ it 'should output JSON files per locale' do
71
72
  subject.save!
72
73
  file_should_exist "en.js"
73
74
  file_should_exist "fr.js"
74
75
 
75
- File.open(File.join(temp_path, "en.js")){|f| f.read}.should eql(
76
+ expect(File.read(File.join(temp_path, "en.js"))).to eql(
76
77
  %Q({"en":{"test":"Test"}})
77
78
  )
78
79
 
79
- File.open(File.join(temp_path, "fr.js")){|f| f.read}.should eql(
80
+ expect(File.read(File.join(temp_path, "fr.js"))).to eql(
80
81
  %Q({"fr":{"test":"Test2"}})
81
82
  )
82
83
  end
@@ -85,8 +86,37 @@ describe I18n::JS::Segment do
85
86
  context "when json_only is true without locale" do
86
87
  let(:file){ "tmp/i18n-js/segment.js" }
87
88
  let(:json_only){ true }
88
- it 'should output the keys as sorted' do
89
- expect { subject.save! }.to raise_error(I18n::JS::JsonOnlyLocaleRequiredError)
89
+
90
+ it 'should output one JSON file for all locales' do
91
+ subject.save!
92
+ file_should_exist "segment.js"
93
+
94
+ expect(File.read(File.join(temp_path, "segment.js"))).to eql(
95
+ %Q({"en":{"test":"Test"},"fr":{"test":"Test2"}})
96
+ )
97
+ end
98
+ end
99
+
100
+ context "when json_only and pretty print are true" do
101
+ let(:file){ "tmp/i18n-js/segment.js" }
102
+ let(:json_only){ true }
103
+ let(:pretty_print){ true }
104
+
105
+ it 'should output one JSON file for all locales' do
106
+ subject.save!
107
+ file_should_exist "segment.js"
108
+
109
+ expect(File.read(File.join(temp_path, "segment.js"))).to eql <<-EOS
110
+ {
111
+ "en": {
112
+ "test": "Test"
113
+ },
114
+ "fr": {
115
+ "test": "Test2"
116
+ }
117
+ }
118
+ EOS
119
+ .chomp
90
120
  end
91
121
  end
92
122
  end
@@ -99,7 +129,7 @@ describe I18n::JS::Segment do
99
129
  it "should write the file" do
100
130
  file_should_exist "segment.js"
101
131
 
102
- File.open(File.join(temp_path, "segment.js")){|f| f.read}.should eql <<-EOF
132
+ expect(File.open(File.join(temp_path, "segment.js")){|f| f.read}).to eql <<-EOF
103
133
  MyNamespace.translations || (MyNamespace.translations = {});
104
134
  MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), {"test":"Test"});
105
135
  MyNamespace.translations["fr"] = I18n.extend((MyNamespace.translations["fr"] || {}), {"test":"Test2"});
@@ -114,12 +144,12 @@ MyNamespace.translations["fr"] = I18n.extend((MyNamespace.translations["fr"] ||
114
144
  file_should_exist "en.js"
115
145
  file_should_exist "fr.js"
116
146
 
117
- File.open(File.join(temp_path, "en.js")){|f| f.read}.should eql <<-EOF
147
+ expect(File.open(File.join(temp_path, "en.js")){|f| f.read}).to eql <<-EOF
118
148
  MyNamespace.translations || (MyNamespace.translations = {});
119
149
  MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), {"test":"Test"});
120
150
  EOF
121
151
 
122
- File.open(File.join(temp_path, "fr.js")){|f| f.read}.should eql <<-EOF
152
+ expect(File.open(File.join(temp_path, "fr.js")){|f| f.read}).to eql <<-EOF
123
153
  MyNamespace.translations || (MyNamespace.translations = {});
124
154
  MyNamespace.translations["fr"] = I18n.extend((MyNamespace.translations["fr"] || {}), {"test":"Test2"});
125
155
  EOF
@@ -134,7 +164,7 @@ MyNamespace.translations["fr"] = I18n.extend((MyNamespace.translations["fr"] ||
134
164
  it 'should output the keys as sorted' do
135
165
  file_should_exist "segment.js"
136
166
 
137
- File.open(File.join(temp_path, "segment.js")){|f| f.read}.should eql <<-EOF
167
+ expect(File.open(File.join(temp_path, "segment.js")){|f| f.read}).to eql <<-EOF
138
168
  MyNamespace.translations || (MyNamespace.translations = {});
139
169
  MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), {"a":"Test","b":"Test"});
140
170
  EOF
@@ -149,7 +179,7 @@ MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] ||
149
179
  it 'should output the keys as sorted' do
150
180
  file_should_exist "segment.js"
151
181
 
152
- File.open(File.join(temp_path, "segment.js")){|f| f.read}.should eql <<-EOF
182
+ expect(File.open(File.join(temp_path, "segment.js")){|f| f.read}).to eql <<-EOF
153
183
  MyNamespace.translations || (MyNamespace.translations = {});
154
184
  MyNamespace.translations["en"] = {"a":"Test","b":"Test"};
155
185
  EOF
@@ -164,7 +194,7 @@ MyNamespace.translations["en"] = {"a":"Test","b":"Test"};
164
194
  it 'should output the keys as sorted' do
165
195
  file_should_exist "segment.js"
166
196
 
167
- File.open(File.join(temp_path, "segment.js")){|f| f.read}.should eql <<-EOF
197
+ expect(File.open(File.join(temp_path, "segment.js")){|f| f.read}).to eql <<-EOF
168
198
  MyNamespace.translations || (MyNamespace.translations = {});
169
199
  MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), {"a":"Test","b":"Test"});
170
200
  EOF
@@ -179,7 +209,7 @@ MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] ||
179
209
  it 'should output the keys as sorted' do
180
210
  file_should_exist "segment.js"
181
211
 
182
- File.open(File.join(temp_path, "segment.js")){|f| f.read}.should eql <<-EOF
212
+ expect(File.open(File.join(temp_path, "segment.js")){|f| f.read}).to eql <<-EOF
183
213
  MyNamespace.translations || (MyNamespace.translations = {});
184
214
  MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), {"b":"Test","a":"Test"});
185
215
  EOF
@@ -28,14 +28,14 @@ describe I18n::JS::Utils do
28
28
  target = {:a => {:b => 1}}
29
29
  result = described_class.deep_merge(target, {:a => {:c => 2}})
30
30
 
31
- result[:a].should eql({:b => 1, :c => 2})
31
+ expect(result[:a]).to eql({:b => 1, :c => 2})
32
32
  end
33
33
 
34
34
  it "performs a banged deep merge" do
35
35
  target = {:a => {:b => 1}}
36
36
  described_class.deep_merge!(target, {:a => {:c => 2}})
37
37
 
38
- target[:a].should eql({:b => 1, :c => 2})
38
+ expect(target[:a]).to eql({:b => 1, :c => 2})
39
39
  end
40
40
  end
41
41
 
@@ -45,7 +45,7 @@ describe I18n::JS::Utils do
45
45
 
46
46
  result = described_class.deep_reject(hash) { |k, v| k == :b }
47
47
 
48
- result.should eql({:a => {}})
48
+ expect(result).to eql({:a => {}})
49
49
  end
50
50
 
51
51
  it "performs a deep keys rejection prunning the whole tree if necessary" do
@@ -53,7 +53,7 @@ describe I18n::JS::Utils do
53
53
 
54
54
  result = described_class.deep_reject(hash) { |k, v| k == :b }
55
55
 
56
- result.should eql({:a => {}})
56
+ expect(result).to eql({:a => {}})
57
57
  end
58
58
 
59
59
 
@@ -62,8 +62,8 @@ describe I18n::JS::Utils do
62
62
 
63
63
  result = described_class.deep_reject(hash) { |k, v| k == :b }
64
64
 
65
- result.should eql({:a => {:c => 2}})
66
- hash.should eql({:a => {:b => 1, :c => 2}})
65
+ expect(result).to eql({:a => {:c => 2}})
66
+ expect(hash).to eql({:a => {:b => 1, :c => 2}})
67
67
  end
68
68
  end
69
69
 
@@ -73,7 +73,7 @@ describe I18n::JS::Utils do
73
73
 
74
74
  it "performs a deep keys sort without changing the original hash" do
75
75
  should eql({:y => 3, :z => {:a => 2, :b => 1}})
76
- unsorted_hash.should eql({:z => {:b => 1, :a => 2}, :y => 3})
76
+ expect(unsorted_hash).to eql({:z => {:b => 1, :a => 2}, :y => 3})
77
77
  end
78
78
 
79
79
  # Idea from gem `rails_admin`
@@ -91,16 +91,16 @@ describe I18n::JS::Utils do
91
91
 
92
92
  describe ".scopes_match?" do
93
93
  it "performs a comparison of literal scopes" do
94
- described_class.scopes_match?([:a, :b], [:a, :b, :c]).should_not eql true
95
- described_class.scopes_match?([:a, :b, :c], [:a, :b, :c]).should eql true
96
- described_class.scopes_match?([:a, :b, :c], [:a, :b, :d]).should_not eql true
94
+ expect(described_class.scopes_match?([:a, :b], [:a, :b, :c])).to_not eql true
95
+ expect(described_class.scopes_match?([:a, :b, :c], [:a, :b, :c])).to eql true
96
+ expect(described_class.scopes_match?([:a, :b, :c], [:a, :b, :d])).to_not eql true
97
97
  end
98
98
 
99
99
  it "performs a comparison of wildcard scopes" do
100
- described_class.scopes_match?([:a, '*'], [:a, :b, :c]).should_not eql true
101
- described_class.scopes_match?([:a, '*', :c], [:a, :b, :c]).should eql true
102
- described_class.scopes_match?([:a, :b, :c], [:a, '*', :c]).should eql true
103
- described_class.scopes_match?([:a, :b, :c], [:a, '*', '*']).should eql true
100
+ expect(described_class.scopes_match?([:a, '*'], [:a, :b, :c])).to_not eql true
101
+ expect(described_class.scopes_match?([:a, '*', :c], [:a, :b, :c])).to eql true
102
+ expect(described_class.scopes_match?([:a, :b, :c], [:a, '*', :c])).to eql true
103
+ expect(described_class.scopes_match?([:a, :b, :c], [:a, '*', '*'])).to eql true
104
104
  end
105
105
  end
106
106
  end
@@ -30,15 +30,15 @@ describe I18n::JS do
30
30
 
31
31
  it "exports messages using custom output path" do
32
32
  set_config "custom_path.yml"
33
- I18n::JS::Segment.should_receive(:new).with("tmp/i18n-js/all.js", translations, {js_extend: true, sort_translation_keys: true, json_only: false}).and_call_original
34
- I18n::JS::Segment.any_instance.should_receive(:save!).with(no_args)
33
+ allow(I18n::JS::Segment).to receive(:new).with("tmp/i18n-js/all.js", translations, {js_extend: true, sort_translation_keys: true, json_only: false}).and_call_original
34
+ allow_any_instance_of(I18n::JS::Segment).to receive(:save!).with(no_args)
35
35
  I18n::JS.export
36
36
  end
37
37
 
38
38
  it "sets default scope to * when not specified" do
39
39
  set_config "no_scope.yml"
40
- I18n::JS::Segment.should_receive(:new).with("tmp/i18n-js/no_scope.js", translations, {js_extend: true, sort_translation_keys: true, json_only: false}).and_call_original
41
- I18n::JS::Segment.any_instance.should_receive(:save!).with(no_args)
40
+ allow(I18n::JS::Segment).to receive(:new).with("tmp/i18n-js/no_scope.js", translations, {js_extend: true, sort_translation_keys: true, json_only: false}).and_call_original
41
+ allow_any_instance_of(I18n::JS::Segment).to receive(:save!).with(no_args)
42
42
  I18n::JS.export
43
43
  end
44
44
 
@@ -91,7 +91,7 @@ EOS
91
91
  set_config "multiple_conditions_per_locale.yml"
92
92
 
93
93
  result = I18n::JS.translation_segments
94
- result.map(&:file).should eql(["tmp/i18n-js/bits.%{locale}.js"])
94
+ expect(result.map(&:file)).to eql(["tmp/i18n-js/bits.%{locale}.js"])
95
95
 
96
96
  result.map(&:save!)
97
97
 
@@ -142,40 +142,40 @@ EOS
142
142
  context "filters" do
143
143
  it "filters translations using scope *.date.formats" do
144
144
  result = I18n::JS.filter(translations, "*.date.formats")
145
- result[:en][:date].keys.should eql([:formats])
146
- result[:fr][:date].keys.should eql([:formats])
145
+ expect(result[:en][:date].keys).to eql([:formats])
146
+ expect(result[:fr][:date].keys).to eql([:formats])
147
147
  end
148
148
 
149
149
  it "filters translations using scope [*.date.formats, *.number.currency.format]" do
150
150
  result = I18n::JS.scoped_translations(["*.date.formats", "*.number.currency.format"])
151
- result[:en].keys.collect(&:to_s).sort.should eql(%w[ date number ])
152
- result[:fr].keys.collect(&:to_s).sort.should eql(%w[ date number ])
151
+ expect(result[:en].keys.collect(&:to_s).sort).to eql(%w[ date number ])
152
+ expect(result[:fr].keys.collect(&:to_s).sort).to eql(%w[ date number ])
153
153
  end
154
154
 
155
155
  it "filters translations using multi-star scope" do
156
156
  result = I18n::JS.scoped_translations("*.*.formats")
157
157
 
158
- result[:en].keys.collect(&:to_s).sort.should eql(%w[ date time ])
159
- result[:fr].keys.collect(&:to_s).sort.should eql(%w[ date time ])
158
+ expect(result[:en].keys.collect(&:to_s).sort).to eql(%w[ date time ])
159
+ expect(result[:fr].keys.collect(&:to_s).sort).to eql(%w[ date time ])
160
160
 
161
- result[:en][:date].keys.should eql([:formats])
162
- result[:en][:time].keys.should eql([:formats])
161
+ expect(result[:en][:date].keys).to eql([:formats])
162
+ expect(result[:en][:time].keys).to eql([:formats])
163
163
 
164
- result[:fr][:date].keys.should eql([:formats])
165
- result[:fr][:time].keys.should eql([:formats])
164
+ expect(result[:fr][:date].keys).to eql([:formats])
165
+ expect(result[:fr][:time].keys).to eql([:formats])
166
166
  end
167
167
 
168
168
  it "filters translations using alternated stars" do
169
169
  result = I18n::JS.scoped_translations("*.admin.*.title")
170
170
 
171
- result[:en][:admin].keys.collect(&:to_s).sort.should eql(%w[ edit show ])
172
- result[:fr][:admin].keys.collect(&:to_s).sort.should eql(%w[ edit show ])
171
+ expect(result[:en][:admin].keys.collect(&:to_s).sort).to eql(%w[ edit show ])
172
+ expect(result[:fr][:admin].keys.collect(&:to_s).sort).to eql(%w[ edit show ])
173
173
 
174
- result[:en][:admin][:show][:title].should eql("Show")
175
- result[:fr][:admin][:show][:title].should eql("Visualiser")
174
+ expect(result[:en][:admin][:show][:title]).to eql("Show")
175
+ expect(result[:fr][:admin][:show][:title]).to eql("Visualiser")
176
176
 
177
- result[:en][:admin][:edit][:title].should eql("Edit")
178
- result[:fr][:admin][:edit][:title].should eql("Editer")
177
+ expect(result[:en][:admin][:edit][:title]).to eql("Edit")
178
+ expect(result[:fr][:admin][:edit][:title]).to eql("Editer")
179
179
  end
180
180
 
181
181
  describe ".filtered_translations" do
@@ -227,50 +227,50 @@ EOS
227
227
  it "does not include scopes listed in the exceptions list" do
228
228
  result = I18n::JS.scoped_translations("*", ['de.*', '*.admin', '*.*.currency'])
229
229
 
230
- result[:de].should be_empty
230
+ expect(result[:de]).to be_empty
231
231
 
232
- result[:en][:admin].should be_nil
233
- result[:fr][:admin].should be_nil
234
- result[:ja][:admin].should be_nil
232
+ expect(result[:en][:admin]).to be_nil
233
+ expect(result[:fr][:admin]).to be_nil
234
+ expect(result[:ja][:admin]).to be_nil
235
235
 
236
- result[:en][:number][:currency].should be_nil
237
- result[:fr][:number][:currency].should be_nil
236
+ expect(result[:en][:number][:currency]).to be_nil
237
+ expect(result[:fr][:number][:currency]).to be_nil
238
238
  end
239
239
 
240
240
  it "does not include scopes listed in the exceptions list and respects the 'only' option" do
241
241
  result = I18n::JS.scoped_translations("fr.*", ['*.admin', '*.*.currency'])
242
242
 
243
- result[:en].should be_nil
244
- result[:de].should be_nil
245
- result[:ja].should be_nil
243
+ expect(result[:en]).to be_nil
244
+ expect(result[:de]).to be_nil
245
+ expect(result[:ja]).to be_nil
246
246
 
247
- result[:fr][:admin].should be_nil
248
- result[:fr][:number][:currency].should be_nil
247
+ expect(result[:fr][:admin]).to be_nil
248
+ expect(result[:fr][:number][:currency]).to be_nil
249
249
 
250
- result[:fr][:time][:am].should be_a(String)
250
+ expect(result[:fr][:time][:am]).to be_a(String)
251
251
  end
252
252
 
253
253
  it "does exclude absolute scopes listed in the exceptions list" do
254
254
  result = I18n::JS.scoped_translations("*", ['de', 'en.admin', 'fr.number.currency'])
255
255
 
256
- result[:de].should be_nil
256
+ expect(result[:de]).to be_nil
257
257
 
258
- result[:en].should be_a(Hash)
259
- result[:en][:admin].should be_nil
258
+ expect(result[:en]).to be_a(Hash)
259
+ expect(result[:en][:admin]).to be_nil
260
260
 
261
- result[:fr][:number].should be_a(Hash)
262
- result[:fr][:number][:currency].should be_nil
261
+ expect(result[:fr][:number]).to be_a(Hash)
262
+ expect(result[:fr][:number][:currency]).to be_nil
263
263
  end
264
264
 
265
265
  it "does not exclude non-absolute scopes listed in the exceptions list" do
266
266
  result = I18n::JS.scoped_translations("*", ['admin', 'currency'])
267
267
 
268
- result[:en][:admin].should be_a(Hash)
269
- result[:fr][:admin].should be_a(Hash)
270
- result[:ja][:admin].should be_a(Hash)
268
+ expect(result[:en][:admin]).to be_a(Hash)
269
+ expect(result[:fr][:admin]).to be_a(Hash)
270
+ expect(result[:ja][:admin]).to be_a(Hash)
271
271
 
272
- result[:en][:number][:currency].should be_a(Hash)
273
- result[:fr][:number][:currency].should be_a(Hash)
272
+ expect(result[:en][:number][:currency]).to be_a(Hash)
273
+ expect(result[:fr][:number][:currency]).to be_a(Hash)
274
274
  end
275
275
  end
276
276
 
@@ -281,30 +281,30 @@ EOS
281
281
 
282
282
  it "exports without fallback when disabled" do
283
283
  set_config "js_file_per_locale_without_fallbacks.yml"
284
- subject[:fr][:fallback_test].should eql(nil)
285
- subject[:fr][:null_test].should eql(nil)
286
- subject[:de][:null_test].should eql(nil)
284
+ expect(subject[:fr][:fallback_test]).to eql(nil)
285
+ expect(subject[:fr][:null_test]).to eql(nil)
286
+ expect(subject[:de][:null_test]).to eql(nil)
287
287
  end
288
288
 
289
289
  it "exports with default_locale as fallback when enabled" do
290
290
  set_config "js_file_per_locale_with_fallbacks_enabled.yml"
291
- subject[:fr][:fallback_test].should eql("Success")
292
- subject[:fr][:null_test].should eql("fallback for null")
293
- subject[:de][:null_test].should eql("fallback for null")
291
+ expect(subject[:fr][:fallback_test]).to eql("Success")
292
+ expect(subject[:fr][:null_test]).to eql("fallback for null")
293
+ expect(subject[:de][:null_test]).to eql("fallback for null")
294
294
  end
295
295
 
296
296
  it "exports with default_locale as fallback when enabled with :default_locale" do
297
297
  set_config "js_file_per_locale_with_fallbacks_as_default_locale_symbol.yml"
298
- subject[:fr][:fallback_test].should eql("Success")
299
- subject[:fr][:null_test].should eql("fallback for null")
300
- subject[:de][:null_test].should eql("fallback for null")
298
+ expect(subject[:fr][:fallback_test]).to eql("Success")
299
+ expect(subject[:fr][:null_test]).to eql("fallback for null")
300
+ expect(subject[:de][:null_test]).to eql("fallback for null")
301
301
  end
302
302
 
303
303
  it "exports with given locale as fallback" do
304
304
  set_config "js_file_per_locale_with_fallbacks_as_locale.yml"
305
- subject[:fr][:fallback_test].should eql("Erfolg")
306
- subject[:fr][:null_test].should eql(nil)
307
- subject[:de][:null_test].should eql(nil)
305
+ expect(subject[:fr][:fallback_test]).to eql("Erfolg")
306
+ expect(subject[:fr][:null_test]).to eql(nil)
307
+ expect(subject[:de][:null_test]).to eql(nil)
308
308
  end
309
309
 
310
310
  context "when given locale is in `I18n.available_locales` but its translation is missing" do
@@ -336,17 +336,17 @@ EOS
336
336
 
337
337
  it "exports with defined locale as fallback when enabled" do
338
338
  set_config "js_file_per_locale_with_fallbacks_enabled.yml"
339
- subject[:fr][:fallback_test].should eql("Erfolg")
339
+ expect(subject[:fr][:fallback_test]).to eql("Erfolg")
340
340
  end
341
341
 
342
342
  it "exports with defined locale as fallback when enabled with :default_locale" do
343
343
  set_config "js_file_per_locale_with_fallbacks_as_default_locale_symbol.yml"
344
- subject[:fr][:fallback_test].should eql("Success")
344
+ expect(subject[:fr][:fallback_test]).to eql("Success")
345
345
  end
346
346
 
347
347
  it "exports with Fallbacks as Hash" do
348
348
  set_config "js_file_per_locale_with_fallbacks_as_hash.yml"
349
- subject[:fr][:fallback_test].should eql("Erfolg")
349
+ expect(subject[:fr][:fallback_test]).to eql("Erfolg")
350
350
  end
351
351
  end
352
352
  end
@@ -389,9 +389,9 @@ EOS
389
389
  it "should allow all locales" do
390
390
  result = I18n::JS.scoped_translations("*.admin.*.title")
391
391
 
392
- result[:en][:admin][:show][:title].should eql("Show")
393
- result[:fr][:admin][:show][:title].should eql("Visualiser")
394
- result[:ja][:admin][:show][:title].should eql("Ignore me")
392
+ expect(result[:en][:admin][:show][:title]).to eql("Show")
393
+ expect(result[:fr][:admin][:show][:title]).to eql("Visualiser")
394
+ expect(result[:ja][:admin][:show][:title]).to eql("Ignore me")
395
395
  end
396
396
  end
397
397
 
@@ -401,28 +401,28 @@ EOS
401
401
  it "should ignore non-valid locales" do
402
402
  result = I18n::JS.scoped_translations("*.admin.*.title")
403
403
 
404
- result[:en][:admin][:show][:title].should eql("Show")
405
- result[:fr][:admin][:show][:title].should eql("Visualiser")
406
- result.keys.include?(:ja).should eql(false)
404
+ expect(result[:en][:admin][:show][:title]).to eql("Show")
405
+ expect(result[:fr][:admin][:show][:title]).to eql("Visualiser")
406
+ expect(result.keys.include?(:ja)).to eql(false)
407
407
  end
408
408
  end
409
409
  end
410
410
 
411
411
  context "general" do
412
412
  it "sets export directory" do
413
- I18n::JS::DEFAULT_EXPORT_DIR_PATH.should eql("public/javascripts")
413
+ expect(I18n::JS::DEFAULT_EXPORT_DIR_PATH).to eql("public/javascripts")
414
414
  end
415
415
 
416
416
  it "sets empty hash as configuration when no file is found" do
417
- I18n::JS.config_file_exists?.should eql(false)
418
- I18n::JS.config.should eql({})
417
+ expect(I18n::JS.config_file_exists?).to eql(false)
418
+ expect(I18n::JS.config).to eql({})
419
419
  end
420
420
 
421
421
  it "executes erb in config file" do
422
422
  set_config "erb.yml"
423
423
 
424
424
  config_entry = I18n::JS.config[:translations].first
425
- config_entry["only"].should eq("*.date.formats")
425
+ expect(config_entry["only"]).to eq("*.date.formats")
426
426
  end
427
427
  end
428
428
 
@@ -434,7 +434,7 @@ EOS
434
434
  allow(FileUtils).to receive(:mkdir_p).and_call_original
435
435
  allow(FileUtils).to receive(:cp).and_call_original
436
436
 
437
- described_class.stub(:export_i18n_js_dir_path).and_return(export_i18n_js_dir_path)
437
+ allow(described_class).to receive(:export_i18n_js_dir_path).and_return(export_i18n_js_dir_path)
438
438
  I18n::JS.export_i18n_js
439
439
  end
440
440
 
@@ -448,7 +448,7 @@ EOS
448
448
  expect(FileUtils).to have_received(:cp).once
449
449
  end
450
450
  it "exports the file" do
451
- File.should be_file(File.join(I18n::JS.export_i18n_js_dir_path, "i18n.js"))
451
+ expect(File).to be_file(File.join(I18n::JS.export_i18n_js_dir_path, "i18n.js"))
452
452
  end
453
453
  end
454
454
 
@@ -484,7 +484,7 @@ EOS
484
484
  expect(FileUtils).to have_received(:cp).once
485
485
  end
486
486
  it "exports the file" do
487
- File.should be_file(File.join(config_export_path, "i18n.js"))
487
+ expect(File).to be_file(File.join(config_export_path, "i18n.js"))
488
488
  end
489
489
  end
490
490
 
@@ -595,11 +595,10 @@ EOS
595
595
  end
596
596
 
597
597
  it "exports with the keys sorted" do
598
- expect(subject).to eq(<<EOS
598
+ expect(subject).to eq <<EOS
599
599
  I18n.translations || (I18n.translations = {});
600
- I18n.translations["en"] = I18n.extend((I18n.translations["en"] || {}), {"admin":{"edit":{"title":"Edit"},"show":{"note":"more details","title":"Show"}},"date":{"abbr_day_names":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"abbr_month_names":[null,"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],"day_names":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"formats":{"default":"%Y-%m-%d","long":"%B %d, %Y","short":"%b %d"},"month_names":[null,"January","February","March","April","May","June","July","August","September","October","November","December"]},"fallback_test":"Success","foo":"Foo","null_test":"fallback for null","number":{"currency":{"format":{"delimiter":",","format":"%u%n","precision":2,"separator":".","unit":"$"}},"format":{"delimiter":",","precision":3,"separator":"."}},"time":{"am":"am","formats":{"default":"%a, %d %b %Y %H:%M:%S %z","long":"%B %d, %Y %H:%M","short":"%d %b %H:%M"},"pm":"pm"}});
600
+ I18n.translations["en"] = I18n.extend((I18n.translations["en"] || {}), {"admin":{"edit":{"title":"Edit"},"show":{"note":"more details","title":"Show"}},"date":{"abbr_day_names":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"abbr_month_names":[null,"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],"day_names":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"formats":{"default":"%Y-%m-%d","long":"%B %d, %Y","short":"%b %d"},"month_names":[null,"January","February","March","April","May","June","July","August","September","October","November","December"]},"fallback_test":"Success","foo":"Foo","merge_plurals":{"one":"Apple","other":"Apples"},"null_test":"fallback for null","number":{"currency":{"format":{"delimiter":",","format":"%u%n","precision":2,"separator":".","unit":"$"}},"format":{"delimiter":",","precision":3,"separator":"."}},"time":{"am":"am","formats":{"default":"%a, %d %b %Y %H:%M:%S %z","long":"%B %d, %Y %H:%M","short":"%d %b %H:%M"},"pm":"pm"}});
601
601
  EOS
602
- )
603
602
  end
604
603
  end
605
604
  end
@@ -640,4 +639,25 @@ EOS
640
639
  )
641
640
  end
642
641
  end
642
+
643
+ describe "merging plural keys" do
644
+ before do
645
+ stub_const('I18n::JS::DEFAULT_EXPORT_DIR_PATH', temp_path)
646
+ end
647
+
648
+ subject do
649
+ File.read(File.join(I18n::JS.export_i18n_js_dir_path, "merge_plurals.js"))
650
+ end
651
+
652
+ it "should correctly merge the plural keys" do
653
+ set_config "merge_plurals.yml"
654
+ I18n::JS.export
655
+ file_should_exist "merge_plurals.js"
656
+
657
+ expect(subject).to eq <<EOS
658
+ I18n.translations || (I18n.translations = {});
659
+ I18n.translations[\"en\"] = I18n.extend((I18n.translations[\"en\"] || {}), {\"merge_plurals\":{\"one\":\"Apple\",\"other\":\"Apples\"}});\nI18n.translations[\"fr\"] = I18n.extend((I18n.translations[\"fr\"] || {}), {\"merge_plurals\":{\"one\":\"Pomme\",\"other\":\"Pommes\",\"zero\":\"Pomme\"}});
660
+ EOS
661
+ end
662
+ end
643
663
  end
@@ -70,10 +70,10 @@ RSpec.configure do |config|
70
70
 
71
71
  # Remove deprecation warnings
72
72
  config.expect_with :rspec do |c|
73
- c.syntax = [:should, :expect]
73
+ c.syntax = [:expect]
74
74
  end
75
75
  config.mock_with :rspec do |c|
76
- c.syntax = [:should, :expect]
76
+ c.syntax = [:expect]
77
77
  end
78
78
  end
79
79
 
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.2.0
4
+ version: 3.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nando Vieira
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-11-16 00:00:00.000000000 Z
11
+ date: 2019-01-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: i18n
@@ -16,20 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.8.0
20
- - - "<"
21
- - !ruby/object:Gem::Version
22
- version: '2'
19
+ version: 0.6.6
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
26
23
  requirements:
27
24
  - - ">="
28
25
  - !ruby/object:Gem::Version
29
- version: 0.8.0
30
- - - "<"
31
- - !ruby/object:Gem::Version
32
- version: '2'
26
+ version: 0.6.6
33
27
  - !ruby/object:Gem::Dependency
34
28
  name: appraisal
35
29
  requirement: !ruby/object:Gem::Requirement
@@ -120,17 +114,25 @@ files:
120
114
  - app/assets/javascripts/i18n/filtered.js.erb
121
115
  - app/assets/javascripts/i18n/shims.js
122
116
  - app/assets/javascripts/i18n/translations.js
117
+ - gemfiles/i18n_0_6.gemfile
118
+ - gemfiles/i18n_0_7.gemfile
123
119
  - gemfiles/i18n_0_8.gemfile
124
120
  - gemfiles/i18n_0_9.gemfile
125
121
  - gemfiles/i18n_1_0.gemfile
126
122
  - gemfiles/i18n_1_1.gemfile
123
+ - gemfiles/i18n_1_2.gemfile
124
+ - gemfiles/i18n_1_3.gemfile
125
+ - gemfiles/i18n_1_4.gemfile
126
+ - gemfiles/i18n_1_5.gemfile
127
127
  - i18n-js.gemspec
128
128
  - lib/i18n-js.rb
129
129
  - lib/i18n/js.rb
130
130
  - lib/i18n/js/dependencies.rb
131
131
  - lib/i18n/js/engine.rb
132
- - lib/i18n/js/errors.rb
133
132
  - lib/i18n/js/fallback_locales.rb
133
+ - lib/i18n/js/formatters/base.rb
134
+ - lib/i18n/js/formatters/js.rb
135
+ - lib/i18n/js/formatters/json.rb
134
136
  - lib/i18n/js/middleware.rb
135
137
  - lib/i18n/js/private/hash_with_symbol_keys.rb
136
138
  - lib/i18n/js/segment.rb
@@ -160,6 +162,7 @@ files:
160
162
  - spec/fixtures/js_sort_translation_keys_true.yml
161
163
  - spec/fixtures/json_only.yml
162
164
  - spec/fixtures/locales.yml
165
+ - spec/fixtures/merge_plurals.yml
163
166
  - spec/fixtures/multiple_conditions.yml
164
167
  - spec/fixtures/multiple_conditions_per_locale.yml
165
168
  - spec/fixtures/multiple_files.yml
@@ -214,8 +217,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
214
217
  - !ruby/object:Gem::Version
215
218
  version: '0'
216
219
  requirements: []
217
- rubyforge_project:
218
- rubygems_version: 2.7.8
220
+ rubygems_version: 3.0.2
219
221
  signing_key:
220
222
  specification_version: 4
221
223
  summary: It's a small library to provide the Rails I18n translations on the Javascript.
@@ -240,6 +242,7 @@ test_files:
240
242
  - spec/fixtures/js_sort_translation_keys_true.yml
241
243
  - spec/fixtures/json_only.yml
242
244
  - spec/fixtures/locales.yml
245
+ - spec/fixtures/merge_plurals.yml
243
246
  - spec/fixtures/multiple_conditions.yml
244
247
  - spec/fixtures/multiple_conditions_per_locale.yml
245
248
  - spec/fixtures/multiple_files.yml
@@ -1,9 +0,0 @@
1
- module I18n
2
- module JS
3
- class JsonOnlyLocaleRequiredError < StandardError
4
- def message
5
- 'The json_only option requires %{locale} in the file name.'
6
- end
7
- end
8
- end
9
- end