i18n-js 3.2.0 → 3.2.1

Sign up to get free protection for your applications and to get access to all the features.
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