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