i18n-js 3.0.0.rc14 → 3.0.0.rc15
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|