i18n-js 3.4.2 → 3.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +2 -0
- data/Appraisals +4 -0
- data/CHANGELOG.md +47 -2
- data/README.md +8 -3
- data/app/assets/javascripts/i18n.js +19 -18
- data/app/assets/javascripts/i18n/shims.js +32 -0
- data/gemfiles/i18n_1_8.gemfile +7 -0
- data/i18n-js.gemspec +1 -1
- data/lib/i18n/js/formatters/base.rb +2 -1
- data/lib/i18n/js/formatters/js.rb +1 -1
- data/lib/i18n/js/segment.rb +5 -2
- data/lib/i18n/js/version.rb +1 -1
- data/package.json +1 -1
- data/spec/fixtures/js_file_with_namespace_prefix_and_pretty_print.yml +1 -0
- data/spec/js/dates.spec.js +1 -0
- data/spec/js/localization.spec.js +38 -14
- data/spec/js/pluralization.spec.js +10 -2
- data/spec/js/translate.spec.js +63 -48
- data/spec/js/translations.js +10 -1
- data/spec/ruby/i18n/js_spec.rb +2 -1
- metadata +9 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e8b0336b575e1fcbf19bc557cb7fd709db85f8831a842970c03f34517baa90c2
|
4
|
+
data.tar.gz: 4f86f0c6d7e05b0aeb4b8f7898d5947b6a06dd402593d34c068f98da28ed09ff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 20f3d107d1e745c7948ff2fa10173712e84bf58894cab7f1d21f58b5c647bf17fb0a664cc2bb4363d3def74898c0a85dda1a8de6c64161400bd1044663a61cc0
|
7
|
+
data.tar.gz: bc0fa3a90ff5ef2a23c4f084845238564b6c66d9deb96abb79478f719e37e065744cd775b3d8de33765f1d72a266325672b8bcfe95fc1dbd9c0aceb507538d5c
|
data/.travis.yml
CHANGED
@@ -12,6 +12,7 @@ rvm:
|
|
12
12
|
- 2.4
|
13
13
|
- 2.5
|
14
14
|
- 2.6
|
15
|
+
- 2.7
|
15
16
|
- ruby-head
|
16
17
|
before_install:
|
17
18
|
# Needed to test JS
|
@@ -29,6 +30,7 @@ gemfile:
|
|
29
30
|
- gemfiles/i18n_1_5.gemfile
|
30
31
|
- gemfiles/i18n_1_6.gemfile
|
31
32
|
- gemfiles/i18n_1_7.gemfile
|
33
|
+
- gemfiles/i18n_1_8.gemfile
|
32
34
|
matrix:
|
33
35
|
fast_finish: true
|
34
36
|
allow_failures:
|
data/Appraisals
CHANGED
data/CHANGELOG.md
CHANGED
@@ -18,6 +18,46 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
18
18
|
- Nothing
|
19
19
|
|
20
20
|
|
21
|
+
## [3.7.1] - 2020-06-30
|
22
|
+
|
23
|
+
### Fixed
|
24
|
+
|
25
|
+
- [JS] For translation missing behaviour `guess`, replace all underscores to spaces properly
|
26
|
+
(PR: https://github.com/fnando/i18n-js/pull/574)
|
27
|
+
|
28
|
+
|
29
|
+
## [3.7.0] - 2020-05-29
|
30
|
+
|
31
|
+
### Added
|
32
|
+
|
33
|
+
- [JS] Allow options to be passed in when calling `I18n.localize`/`I18n.l`
|
34
|
+
(PR: https://github.com/fnando/i18n-js/pull/570)
|
35
|
+
|
36
|
+
|
37
|
+
## [3.6.0] - 2020-02-14
|
38
|
+
|
39
|
+
### Added
|
40
|
+
|
41
|
+
- [Ruby] Allow `suffix` to be added to generated translations files
|
42
|
+
(PR: https://github.com/fnando/i18n-js/pull/561)
|
43
|
+
|
44
|
+
|
45
|
+
## [3.5.1] - 2019-12-21
|
46
|
+
|
47
|
+
### Changed
|
48
|
+
|
49
|
+
- [JS] Bound shortcut functions
|
50
|
+
(PR: https://github.com/fnando/i18n-js/pull/560)
|
51
|
+
|
52
|
+
|
53
|
+
## [3.5.0] - 2019-11-12
|
54
|
+
|
55
|
+
### Added
|
56
|
+
|
57
|
+
- [JS] Support for `%k` strftime format to match Ruby strftime
|
58
|
+
(PR: https://github.com/fnando/i18n-js/pull/554)
|
59
|
+
|
60
|
+
|
21
61
|
## [3.4.2] - 2019-11-11
|
22
62
|
|
23
63
|
### Fixed
|
@@ -425,8 +465,13 @@ And today is not April Fools' Day
|
|
425
465
|
|
426
466
|
|
427
467
|
|
428
|
-
[Unreleased]: https://github.com/fnando/i18n-js/compare/v3.
|
429
|
-
[3.
|
468
|
+
[Unreleased]: https://github.com/fnando/i18n-js/compare/v3.7.1...HEAD
|
469
|
+
[3.7.1]: https://github.com/fnando/i18n-js/compare/v3.7.0...v3.7.1
|
470
|
+
[3.7.0]: https://github.com/fnando/i18n-js/compare/v3.6.0...v3.7.0
|
471
|
+
[3.6.0]: https://github.com/fnando/i18n-js/compare/v3.5.1...v3.6.0
|
472
|
+
[3.5.1]: https://github.com/fnando/i18n-js/compare/v3.5.0...v3.5.1
|
473
|
+
[3.5.0]: https://github.com/fnando/i18n-js/compare/v3.4.2...v3.5.0
|
474
|
+
[3.4.2]: https://github.com/fnando/i18n-js/compare/v3.4.1...v3.4.2
|
430
475
|
[3.4.1]: https://github.com/fnando/i18n-js/compare/v3.4.0...v3.4.1
|
431
476
|
[3.4.0]: https://github.com/fnando/i18n-js/compare/v3.3.0...v3.4.0
|
432
477
|
[3.3.0]: https://github.com/fnando/i18n-js/compare/v3.2.3...v3.3.0
|
data/README.md
CHANGED
@@ -248,9 +248,9 @@ MyNamespace.translations["en"] = { ... }
|
|
248
248
|
```
|
249
249
|
|
250
250
|
|
251
|
-
### Adding
|
251
|
+
### Adding prefix & suffix to the translations file(s)
|
252
252
|
|
253
|
-
Setting the `prefix: "import I18n from 'i18n-js';\n"` option will add the line at the
|
253
|
+
Setting the `prefix: "import I18n from 'i18n-js';\n"` option will add the line at the beginning of the resultant translation file.
|
254
254
|
This can be useful to use this gem with the [i18n-js](https://www.npmjs.com/package/i18n-js) npm package, which is quite useful to use it with webpack.
|
255
255
|
The user should provide the semi-colon and the newline character if needed.
|
256
256
|
|
@@ -267,6 +267,11 @@ will create:
|
|
267
267
|
```
|
268
268
|
import I18n from 'i18n-js';
|
269
269
|
I18n.translations || (I18n.translations = {});
|
270
|
+
```
|
271
|
+
|
272
|
+
|
273
|
+
`suffix` option is added in https://github.com/fnando/i18n-js/pull/561.
|
274
|
+
It's similar to `prefix` so won't explain it in details.
|
270
275
|
|
271
276
|
|
272
277
|
#### Pretty Print
|
@@ -623,7 +628,7 @@ The accepted formats for `I18n.strftime` are:
|
|
623
628
|
%d - Day of the month (01..31)
|
624
629
|
%-d - Day of the month (1..31)
|
625
630
|
%H - Hour of the day, 24-hour clock (00..23)
|
626
|
-
%-H
|
631
|
+
%-H/%k - Hour of the day, 24-hour clock (0..23)
|
627
632
|
%I - Hour of the day, 12-hour clock (01..12)
|
628
633
|
%-I/%l - Hour of the day, 12-hour clock (1..12)
|
629
634
|
%m - Month of the year (01..12)
|
@@ -679,7 +679,7 @@
|
|
679
679
|
var s = scope.split('.').slice(-1)[0];
|
680
680
|
//replace underscore with space && camelcase with space and lowercase letter
|
681
681
|
return (this.missingTranslationPrefix.length > 0 ? this.missingTranslationPrefix : '') +
|
682
|
-
s.replace(
|
682
|
+
s.replace(/_/g,' ').replace(/([a-z])([A-Z])/g,
|
683
683
|
function(match, p1, p2) {return p1 + ' ' + p2.toLowerCase()} );
|
684
684
|
}
|
685
685
|
|
@@ -779,8 +779,8 @@
|
|
779
779
|
I18n.toCurrency = function(number, options) {
|
780
780
|
options = this.prepareOptions(
|
781
781
|
options
|
782
|
-
, this.lookup("number.currency.format")
|
783
|
-
, this.lookup("number.format")
|
782
|
+
, this.lookup("number.currency.format", options)
|
783
|
+
, this.lookup("number.format", options)
|
784
784
|
, CURRENCY_FORMAT
|
785
785
|
);
|
786
786
|
|
@@ -799,17 +799,17 @@
|
|
799
799
|
|
800
800
|
switch (scope) {
|
801
801
|
case "currency":
|
802
|
-
return this.toCurrency(value);
|
802
|
+
return this.toCurrency(value, options);
|
803
803
|
case "number":
|
804
|
-
scope = this.lookup("number.format");
|
804
|
+
scope = this.lookup("number.format", options);
|
805
805
|
return this.toNumber(value, scope);
|
806
806
|
case "percentage":
|
807
|
-
return this.toPercentage(value);
|
807
|
+
return this.toPercentage(value, options);
|
808
808
|
default:
|
809
809
|
var localizedValue;
|
810
810
|
|
811
811
|
if (scope.match(/^(date|time)/)) {
|
812
|
-
localizedValue = this.toTime(scope, value);
|
812
|
+
localizedValue = this.toTime(scope, value, options);
|
813
813
|
} else {
|
814
814
|
localizedValue = value.toString();
|
815
815
|
}
|
@@ -897,7 +897,7 @@
|
|
897
897
|
// %d - Day of the month (01..31)
|
898
898
|
// %-d - Day of the month (1..31)
|
899
899
|
// %H - Hour of the day, 24-hour clock (00..23)
|
900
|
-
// %-H
|
900
|
+
// %-H/%k - Hour of the day, 24-hour clock (0..23)
|
901
901
|
// %I - Hour of the day, 12-hour clock (01..12)
|
902
902
|
// %-I/%l - Hour of the day, 12-hour clock (1..12)
|
903
903
|
// %m - Month of the year (01..12)
|
@@ -914,8 +914,8 @@
|
|
914
914
|
// %Y - Year with century
|
915
915
|
// %z/%Z - Timezone offset (+0545)
|
916
916
|
//
|
917
|
-
I18n.strftime = function(date, format) {
|
918
|
-
var options = this.lookup("date")
|
917
|
+
I18n.strftime = function(date, format, options) {
|
918
|
+
var options = this.lookup("date", options)
|
919
919
|
, meridianOptions = I18n.meridian()
|
920
920
|
;
|
921
921
|
|
@@ -961,6 +961,7 @@
|
|
961
961
|
format = format.replace("%-d", day);
|
962
962
|
format = format.replace("%H", padding(hour));
|
963
963
|
format = format.replace("%-H", hour);
|
964
|
+
format = format.replace("%k", hour);
|
964
965
|
format = format.replace("%I", padding(hour12));
|
965
966
|
format = format.replace("%-I", hour12);
|
966
967
|
format = format.replace("%l", hour12);
|
@@ -983,9 +984,9 @@
|
|
983
984
|
};
|
984
985
|
|
985
986
|
// Convert the given dateString into a formatted date.
|
986
|
-
I18n.toTime = function(scope, dateString) {
|
987
|
+
I18n.toTime = function(scope, dateString, options) {
|
987
988
|
var date = this.parseDate(dateString)
|
988
|
-
, format = this.lookup(scope)
|
989
|
+
, format = this.lookup(scope, options)
|
989
990
|
;
|
990
991
|
|
991
992
|
// A date input of `null` or `undefined` will be returned as-is
|
@@ -1002,15 +1003,15 @@
|
|
1002
1003
|
return date_string;
|
1003
1004
|
}
|
1004
1005
|
|
1005
|
-
return this.strftime(date, format);
|
1006
|
+
return this.strftime(date, format, options);
|
1006
1007
|
};
|
1007
1008
|
|
1008
1009
|
// Convert a number into a formatted percentage value.
|
1009
1010
|
I18n.toPercentage = function(number, options) {
|
1010
1011
|
options = this.prepareOptions(
|
1011
1012
|
options
|
1012
|
-
, this.lookup("number.percentage.format")
|
1013
|
-
, this.lookup("number.format")
|
1013
|
+
, this.lookup("number.percentage.format", options)
|
1014
|
+
, this.lookup("number.format", options)
|
1014
1015
|
, PERCENTAGE_FORMAT
|
1015
1016
|
);
|
1016
1017
|
|
@@ -1083,9 +1084,9 @@
|
|
1083
1084
|
};
|
1084
1085
|
|
1085
1086
|
// Set aliases, so we can save some typing.
|
1086
|
-
I18n.t = I18n.translate;
|
1087
|
-
I18n.l = I18n.localize;
|
1088
|
-
I18n.p = I18n.pluralize;
|
1087
|
+
I18n.t = I18n.translate.bind(I18n);
|
1088
|
+
I18n.l = I18n.localize.bind(I18n);
|
1089
|
+
I18n.p = I18n.pluralize.bind(I18n);
|
1089
1090
|
|
1090
1091
|
return I18n;
|
1091
1092
|
}));
|
@@ -206,3 +206,35 @@ if (!Array.prototype.map) {
|
|
206
206
|
return A;
|
207
207
|
};
|
208
208
|
}
|
209
|
+
|
210
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind
|
211
|
+
if (!Function.prototype.bind) (function(){
|
212
|
+
var ArrayPrototypeSlice = Array.prototype.slice;
|
213
|
+
Function.prototype.bind = function(otherThis) {
|
214
|
+
if (typeof this !== 'function') {
|
215
|
+
// closest thing possible to the ECMAScript 5
|
216
|
+
// internal IsCallable function
|
217
|
+
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
|
218
|
+
}
|
219
|
+
|
220
|
+
var baseArgs= ArrayPrototypeSlice .call(arguments, 1),
|
221
|
+
baseArgsLength = baseArgs.length,
|
222
|
+
fToBind = this,
|
223
|
+
fNOP = function() {},
|
224
|
+
fBound = function() {
|
225
|
+
baseArgs.length = baseArgsLength; // reset to default base arguments
|
226
|
+
baseArgs.push.apply(baseArgs, arguments);
|
227
|
+
return fToBind.apply(
|
228
|
+
fNOP.prototype.isPrototypeOf(this) ? this : otherThis, baseArgs
|
229
|
+
);
|
230
|
+
};
|
231
|
+
|
232
|
+
if (this.prototype) {
|
233
|
+
// Function.prototype doesn't have a prototype property
|
234
|
+
fNOP.prototype = this.prototype;
|
235
|
+
}
|
236
|
+
fBound.prototype = new fNOP();
|
237
|
+
|
238
|
+
return fBound;
|
239
|
+
};
|
240
|
+
})();
|
data/i18n-js.gemspec
CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
|
|
20
20
|
|
21
21
|
s.add_dependency "i18n", ">= 0.6.6"
|
22
22
|
|
23
|
-
s.add_development_dependency "appraisal", "~> 2.
|
23
|
+
s.add_development_dependency "appraisal", "~> 2.3"
|
24
24
|
s.add_development_dependency "rspec", "~> 3.0"
|
25
25
|
s.add_development_dependency "rake", "~> 12.0"
|
26
26
|
s.add_development_dependency "gem-release", ">= 0.7"
|
@@ -2,11 +2,12 @@ module I18n
|
|
2
2
|
module JS
|
3
3
|
module Formatters
|
4
4
|
class Base
|
5
|
-
def initialize(js_extend: false, namespace: nil, pretty_print: false, prefix: nil)
|
5
|
+
def initialize(js_extend: false, namespace: nil, pretty_print: false, prefix: nil, suffix: nil)
|
6
6
|
@js_extend = js_extend
|
7
7
|
@namespace = namespace
|
8
8
|
@pretty_print = pretty_print
|
9
9
|
@prefix = prefix
|
10
|
+
@suffix = suffix
|
10
11
|
end
|
11
12
|
|
12
13
|
protected
|
data/lib/i18n/js/segment.rb
CHANGED
@@ -7,7 +7,7 @@ module I18n
|
|
7
7
|
|
8
8
|
# Class which enscapulates a translations hash and outputs a single JSON translation file
|
9
9
|
class Segment
|
10
|
-
OPTIONS = [:namespace, :pretty_print, :js_extend, :prefix, :sort_translation_keys, :json_only].freeze
|
10
|
+
OPTIONS = [:namespace, :pretty_print, :js_extend, :prefix, :suffix, :sort_translation_keys, :json_only].freeze
|
11
11
|
LOCALE_INTERPOLATOR = /%\{locale\}/
|
12
12
|
|
13
13
|
attr_reader *([:file, :translations] | OPTIONS)
|
@@ -25,6 +25,7 @@ module I18n
|
|
25
25
|
@pretty_print = !!options[:pretty_print]
|
26
26
|
@js_extend = options.key?(:js_extend) ? !!options[:js_extend] : true
|
27
27
|
@prefix = options.key?(:prefix) ? options[:prefix] : nil
|
28
|
+
@suffix = options.key?(:suffix) ? options[:suffix] : nil
|
28
29
|
@sort_translation_keys = options.key?(:sort_translation_keys) ? !!options[:sort_translation_keys] : true
|
29
30
|
@json_only = options.key?(:json_only) ? !!options[:json_only] : false
|
30
31
|
end
|
@@ -70,7 +71,9 @@ module I18n
|
|
70
71
|
{ js_extend: @js_extend,
|
71
72
|
namespace: @namespace,
|
72
73
|
pretty_print: @pretty_print,
|
73
|
-
prefix: @prefix
|
74
|
+
prefix: @prefix,
|
75
|
+
suffix: @suffix
|
76
|
+
}
|
74
77
|
end
|
75
78
|
end
|
76
79
|
end
|
data/lib/i18n/js/version.rb
CHANGED
data/package.json
CHANGED
data/spec/js/dates.spec.js
CHANGED
@@ -132,6 +132,7 @@ describe("Dates", function(){
|
|
132
132
|
|
133
133
|
// 24-hour without padding
|
134
134
|
expect(I18n.strftime(date, "%-H")).toEqual("7");
|
135
|
+
expect(I18n.strftime(date, "%k")).toEqual("7");
|
135
136
|
|
136
137
|
// 12-hour without padding
|
137
138
|
expect(I18n.strftime(date, "%-I")).toEqual("7");
|
@@ -10,45 +10,69 @@ describe("Localization", function(){
|
|
10
10
|
I18n.translations = Translations();
|
11
11
|
});
|
12
12
|
|
13
|
+
it("sets bound alias", function() {
|
14
|
+
expect(I18n.l).toEqual(jasmine.any(Function));
|
15
|
+
expect(I18n.l).not.toBe(I18n.localize);
|
16
|
+
});
|
17
|
+
|
13
18
|
it("localizes number", function(){
|
14
|
-
expect(I18n.
|
19
|
+
expect(I18n.localize("number", 1234567)).toEqual("1,234,567.000");
|
20
|
+
});
|
21
|
+
|
22
|
+
it("localizes number with 'l' shortcut", function(){
|
23
|
+
var l = I18n.l;
|
24
|
+
expect(l("number", 1234567)).toEqual("1,234,567.000");
|
15
25
|
});
|
16
26
|
|
17
27
|
it("localizes currency", function(){
|
18
|
-
expect(I18n.
|
28
|
+
expect(I18n.localize("currency", 1234567)).toEqual("$1,234,567.00");
|
19
29
|
});
|
20
30
|
|
21
31
|
it("localizes date strings", function(){
|
22
32
|
I18n.locale = "pt-BR";
|
23
33
|
|
24
|
-
expect(I18n.
|
25
|
-
expect(I18n.
|
26
|
-
expect(I18n.
|
34
|
+
expect(I18n.localize("date.formats.default", "2009-11-29")).toEqual("29/11/2009");
|
35
|
+
expect(I18n.localize("date.formats.short", "2009-01-07")).toEqual("07 de Janeiro");
|
36
|
+
expect(I18n.localize("date.formats.long", "2009-01-07")).toEqual("07 de Janeiro de 2009");
|
37
|
+
});
|
38
|
+
|
39
|
+
it("localizes strings with locale from options", function(){
|
40
|
+
I18n.locale = "en";
|
41
|
+
|
42
|
+
expect(I18n.localize("date.formats.default", "2009-11-29", { locale: "pt-BR" })).toEqual("29/11/2009");
|
43
|
+
expect(I18n.localize("date.formats.short", "2009-01-07", { locale: "pt-BR" })).toEqual("07 de Janeiro");
|
44
|
+
expect(I18n.localize("date.formats.long", "2009-01-07", { locale: "pt-BR" })).toEqual("07 de Janeiro de 2009");
|
45
|
+
expect(I18n.localize("time.formats.default", "2009-11-29 15:07:59", { locale: "pt-BR" })).toEqual("Domingo, 29 de Novembro de 2009, 15:07 h");
|
46
|
+
expect(I18n.localize("time.formats.short", "2009-01-07 09:12:35", { locale: "pt-BR" })).toEqual("07/01, 09:12 h");
|
47
|
+
expect(I18n.localize("time.formats.long", "2009-11-29 15:07:59", { locale: "pt-BR" })).toEqual("Domingo, 29 de Novembro de 2009, 15:07 h");
|
48
|
+
expect(I18n.localize("number", 1234567, { locale: "pt-BR" })).toEqual("1,234,567.000");
|
49
|
+
expect(I18n.localize("currency", 1234567, { locale: "pt-BR" })).toEqual("R$ 1.234.567,00");
|
50
|
+
expect(I18n.localize("percentage", 123.45, { locale: "pt-BR" })).toEqual("123,45%");
|
27
51
|
});
|
28
52
|
|
29
53
|
it("localizes time strings", function(){
|
30
54
|
I18n.locale = "pt-BR";
|
31
55
|
|
32
|
-
expect(I18n.
|
33
|
-
expect(I18n.
|
34
|
-
expect(I18n.
|
56
|
+
expect(I18n.localize("time.formats.default", "2009-11-29 15:07:59")).toEqual("Domingo, 29 de Novembro de 2009, 15:07 h");
|
57
|
+
expect(I18n.localize("time.formats.short", "2009-01-07 09:12:35")).toEqual("07/01, 09:12 h");
|
58
|
+
expect(I18n.localize("time.formats.long", "2009-11-29 15:07:59")).toEqual("Domingo, 29 de Novembro de 2009, 15:07 h");
|
35
59
|
});
|
36
60
|
|
37
61
|
it("return 'Invalid Date' or original value for invalid input", function(){
|
38
|
-
expect(I18n.
|
39
|
-
expect(I18n.
|
40
|
-
expect(I18n.
|
62
|
+
expect(I18n.localize("time.formats.default", "")).toEqual("Invalid Date");
|
63
|
+
expect(I18n.localize("time.formats.default", null)).toEqual(null);
|
64
|
+
expect(I18n.localize("time.formats.default", undefined)).toEqual(undefined);
|
41
65
|
});
|
42
66
|
|
43
67
|
it("localizes date/time strings with placeholders", function(){
|
44
68
|
I18n.locale = "pt-BR";
|
45
69
|
|
46
|
-
expect(I18n.
|
47
|
-
expect(I18n.
|
70
|
+
expect(I18n.localize("date.formats.short_with_placeholders", "2009-01-07", { p1: "!", p2: "?" })).toEqual("07 de Janeiro ! ?");
|
71
|
+
expect(I18n.localize("time.formats.short_with_placeholders", "2009-01-07 09:12:35", { p1: "!" })).toEqual("07/01, 09:12 h !");
|
48
72
|
});
|
49
73
|
|
50
74
|
it("localizes percentage", function(){
|
51
75
|
I18n.locale = "pt-BR";
|
52
|
-
expect(I18n.
|
76
|
+
expect(I18n.localize("percentage", 123.45)).toEqual("123,45%");
|
53
77
|
});
|
54
78
|
});
|
@@ -10,8 +10,9 @@ describe("Pluralization", function(){
|
|
10
10
|
I18n.translations = Translations();
|
11
11
|
});
|
12
12
|
|
13
|
-
it("sets alias", function() {
|
14
|
-
expect(I18n.p).toEqual(
|
13
|
+
it("sets bound alias", function() {
|
14
|
+
expect(I18n.p).toEqual(jasmine.any(Function));
|
15
|
+
expect(I18n.p).not.toBe(I18n.pluralize);
|
15
16
|
});
|
16
17
|
|
17
18
|
it("pluralizes scope", function(){
|
@@ -20,6 +21,13 @@ describe("Pluralization", function(){
|
|
20
21
|
expect(I18n.p(5, "inbox")).toEqual("You have 5 messages");
|
21
22
|
});
|
22
23
|
|
24
|
+
it("pluralizes scope with 'p' shortcut", function(){
|
25
|
+
var p = I18n.p;
|
26
|
+
expect(p(0, "inbox")).toEqual("You have no messages");
|
27
|
+
expect(p(1, "inbox")).toEqual("You have 1 message");
|
28
|
+
expect(p(5, "inbox")).toEqual("You have 5 messages");
|
29
|
+
});
|
30
|
+
|
23
31
|
it("pluralizes using the 'other' scope", function(){
|
24
32
|
I18n.translations["en"]["inbox"]["zero"] = null;
|
25
33
|
expect(I18n.p(0, "inbox")).toEqual("You have 0 messages");
|
data/spec/js/translate.spec.js
CHANGED
@@ -10,83 +10,98 @@ describe("Translate", function(){
|
|
10
10
|
I18n.translations = Translations();
|
11
11
|
});
|
12
12
|
|
13
|
+
it("sets bound alias", function() {
|
14
|
+
expect(I18n.t).toEqual(jasmine.any(Function));
|
15
|
+
expect(I18n.t).not.toBe(I18n.translate);
|
16
|
+
});
|
17
|
+
|
13
18
|
it("returns translation for single scope", function(){
|
14
|
-
expect(I18n.
|
19
|
+
expect(I18n.translate("hello")).toEqual("Hello World!");
|
20
|
+
});
|
21
|
+
|
22
|
+
it("returns translation with 't' shortcut", function(){
|
23
|
+
var t = I18n.t;
|
24
|
+
expect(t("hello")).toEqual("Hello World!");
|
15
25
|
});
|
16
26
|
|
17
27
|
it("returns translation as object", function(){
|
18
|
-
expect(I18n.
|
28
|
+
expect(I18n.translate("greetings")).toEqual(I18n.translations.en.greetings);
|
19
29
|
});
|
20
30
|
|
21
31
|
it("returns missing message translation for valid scope with null", function(){
|
22
|
-
actual = I18n.
|
32
|
+
actual = I18n.translate("null_key");
|
23
33
|
expected = '[missing "en.null_key" translation]';
|
24
34
|
expect(actual).toEqual(expected);
|
25
35
|
});
|
26
36
|
|
27
37
|
it("returns missing message translation for invalid scope", function(){
|
28
|
-
actual = I18n.
|
38
|
+
actual = I18n.translate("invalid.scope");
|
29
39
|
expected = '[missing "en.invalid.scope" translation]';
|
30
40
|
expect(actual).toEqual(expected);
|
31
41
|
});
|
32
42
|
|
33
43
|
it("returns missing message translation with provided locale for invalid scope", function(){
|
34
|
-
actual = I18n.
|
44
|
+
actual = I18n.translate("invalid.scope", { locale: "ja" });
|
35
45
|
expected = '[missing "ja.invalid.scope" translation]';
|
36
46
|
expect(actual).toEqual(expected);
|
37
47
|
});
|
38
48
|
|
39
49
|
it("returns guessed translation if missingBehaviour is set to guess", function(){
|
40
50
|
I18n.missingBehaviour = 'guess'
|
41
|
-
|
42
|
-
|
43
|
-
|
51
|
+
|
52
|
+
var actual_1 = I18n.translate("invalid.thisIsAutomaticallyGeneratedTranslation");
|
53
|
+
var expected_1 = 'this is automatically generated translation';
|
54
|
+
expect(actual_1).toEqual(expected_1);
|
55
|
+
|
56
|
+
var actual_2 = I18n.translate("invalid.this_is_automatically_generated_translation");
|
57
|
+
var expected_2 = 'this is automatically generated translation';
|
58
|
+
expect(actual_2).toEqual(expected_2);
|
44
59
|
});
|
45
60
|
|
46
61
|
it("returns guessed translation with prefix if missingBehaviour is set to guess and prefix is also provided", function(){
|
47
62
|
I18n.missingBehaviour = 'guess'
|
48
63
|
I18n.missingTranslationPrefix = 'EE: '
|
49
|
-
actual = I18n.
|
64
|
+
actual = I18n.translate("invalid.thisIsAutomaticallyGeneratedTranslation");
|
50
65
|
expected = 'EE: this is automatically generated translation';
|
51
66
|
expect(actual).toEqual(expected);
|
52
67
|
});
|
53
68
|
|
54
69
|
it("returns missing message translation for valid scope with scope", function(){
|
55
|
-
actual = I18n.
|
70
|
+
actual = I18n.translate("monster", {scope: "greetings"});
|
56
71
|
expected = '[missing "en.greetings.monster" translation]';
|
57
72
|
expect(actual).toEqual(expected);
|
58
73
|
});
|
59
74
|
|
60
75
|
it("returns translation for single scope on a custom locale", function(){
|
61
76
|
I18n.locale = "pt-BR";
|
62
|
-
expect(I18n.
|
77
|
+
expect(I18n.translate("hello")).toEqual("Olá Mundo!");
|
63
78
|
});
|
64
79
|
|
65
80
|
it("returns translation for multiple scopes", function(){
|
66
|
-
expect(I18n.
|
81
|
+
expect(I18n.translate("greetings.stranger")).toEqual("Hello stranger!");
|
67
82
|
});
|
68
83
|
|
69
84
|
it("returns translation with default locale option", function(){
|
70
|
-
expect(I18n.
|
71
|
-
expect(I18n.
|
85
|
+
expect(I18n.translate("hello", {locale: "en"})).toEqual("Hello World!");
|
86
|
+
expect(I18n.translate("hello", {locale: "pt-BR"})).toEqual("Olá Mundo!");
|
72
87
|
});
|
73
88
|
|
74
89
|
it("fallbacks to the default locale when I18n.fallbacks is enabled", function(){
|
75
90
|
I18n.locale = "pt-BR";
|
76
91
|
I18n.fallbacks = true;
|
77
|
-
expect(I18n.
|
92
|
+
expect(I18n.translate("greetings.stranger")).toEqual("Hello stranger!");
|
78
93
|
});
|
79
94
|
|
80
95
|
it("fallbacks to default locale when providing an unknown locale", function(){
|
81
96
|
I18n.locale = "fr";
|
82
97
|
I18n.fallbacks = true;
|
83
|
-
expect(I18n.
|
98
|
+
expect(I18n.translate("greetings.stranger")).toEqual("Hello stranger!");
|
84
99
|
});
|
85
100
|
|
86
101
|
it("fallbacks to less specific locale", function(){
|
87
102
|
I18n.locale = "de-DE";
|
88
103
|
I18n.fallbacks = true;
|
89
|
-
expect(I18n.
|
104
|
+
expect(I18n.translate("hello")).toEqual("Hallo Welt!");
|
90
105
|
});
|
91
106
|
|
92
107
|
describe("when a 3-part locale is used", function(){
|
@@ -96,15 +111,15 @@ describe("Translate", function(){
|
|
96
111
|
});
|
97
112
|
|
98
113
|
it("fallbacks to 2-part locale when absent", function(){
|
99
|
-
expect(I18n.
|
114
|
+
expect(I18n.translate("cat")).toEqual("貓");
|
100
115
|
});
|
101
116
|
|
102
117
|
it("fallbacks to 1-part locale when 2-part missing requested translation", function(){
|
103
|
-
expect(I18n.
|
118
|
+
expect(I18n.translate("dog")).toEqual("狗");
|
104
119
|
});
|
105
120
|
|
106
121
|
it("fallbacks to 2-part for the first time", function(){
|
107
|
-
expect(I18n.
|
122
|
+
expect(I18n.translate("dragon")).toEqual("龍");
|
108
123
|
});
|
109
124
|
});
|
110
125
|
|
@@ -115,7 +130,7 @@ describe("Translate", function(){
|
|
115
130
|
return ["nb"];
|
116
131
|
};
|
117
132
|
|
118
|
-
expect(I18n.
|
133
|
+
expect(I18n.translate("hello")).toEqual("Hei Verden!");
|
119
134
|
});
|
120
135
|
|
121
136
|
it("fallbacks using custom rules (array)", function() {
|
@@ -123,7 +138,7 @@ describe("Translate", function(){
|
|
123
138
|
I18n.fallbacks = true;
|
124
139
|
I18n.locales["no"] = ["no", "nb"];
|
125
140
|
|
126
|
-
expect(I18n.
|
141
|
+
expect(I18n.translate("hello")).toEqual("Hei Verden!");
|
127
142
|
});
|
128
143
|
|
129
144
|
it("fallbacks using custom rules (string)", function() {
|
@@ -131,25 +146,25 @@ describe("Translate", function(){
|
|
131
146
|
I18n.fallbacks = true;
|
132
147
|
I18n.locales["no"] = "nb";
|
133
148
|
|
134
|
-
expect(I18n.
|
149
|
+
expect(I18n.translate("hello")).toEqual("Hei Verden!");
|
135
150
|
});
|
136
151
|
|
137
152
|
describe("when provided default values", function() {
|
138
153
|
it("uses scope provided in defaults if scope doesn't exist", function() {
|
139
|
-
actual = I18n.
|
154
|
+
actual = I18n.translate("Hello!", {defaults: [{scope: "greetings.stranger"}]});
|
140
155
|
expect(actual).toEqual("Hello stranger!");
|
141
156
|
});
|
142
157
|
|
143
158
|
it("continues to fallback until a scope is found", function() {
|
144
159
|
var defaults = [{scope: "foo"}, {scope: "hello"}];
|
145
160
|
|
146
|
-
actual = I18n.
|
161
|
+
actual = I18n.translate("foo", {defaults: defaults});
|
147
162
|
expect(actual).toEqual("Hello World!");
|
148
163
|
});
|
149
164
|
|
150
165
|
it("uses message if specified as a default", function() {
|
151
166
|
var defaults = [{message: "Hello all!"}];
|
152
|
-
actual = I18n.
|
167
|
+
actual = I18n.translate("foo", {defaults: defaults});
|
153
168
|
expect(actual).toEqual("Hello all!");
|
154
169
|
});
|
155
170
|
|
@@ -158,7 +173,7 @@ describe("Translate", function(){
|
|
158
173
|
{scope: "bar"}
|
159
174
|
, {message: "Hello all!"}
|
160
175
|
, {scope: "hello"}];
|
161
|
-
actual = I18n.
|
176
|
+
actual = I18n.translate("foo", {defaults: defaults});
|
162
177
|
expect(actual).toEqual("Hello all!");
|
163
178
|
});
|
164
179
|
|
@@ -167,7 +182,7 @@ describe("Translate", function(){
|
|
167
182
|
defaults: [{scope: "bar"}]
|
168
183
|
, defaultValue: "Hello all!"
|
169
184
|
};
|
170
|
-
actual = I18n.
|
185
|
+
actual = I18n.translate("foo", options);
|
171
186
|
expect(actual).toEqual("Hello all!");
|
172
187
|
});
|
173
188
|
|
@@ -176,7 +191,7 @@ describe("Translate", function(){
|
|
176
191
|
defaults: [{scope: "hello"}]
|
177
192
|
, defaultValue: "Hello all!"
|
178
193
|
};
|
179
|
-
actual = I18n.
|
194
|
+
actual = I18n.translate("foo", options);
|
180
195
|
expect(actual).toEqual("Hello World!");
|
181
196
|
})
|
182
197
|
|
@@ -187,36 +202,36 @@ describe("Translate", function(){
|
|
187
202
|
return scope.toUpperCase();
|
188
203
|
}
|
189
204
|
};
|
190
|
-
actual = I18n.
|
205
|
+
actual = I18n.translate("foo", options);
|
191
206
|
expect(actual).toEqual("FOO");
|
192
207
|
})
|
193
208
|
|
194
209
|
it("pluralizes using the correct scope if translation is found within default scope", function() {
|
195
210
|
expect(I18n.translations["en"]["mailbox"]).toEqual(undefined);
|
196
|
-
actual = I18n.
|
197
|
-
expected = I18n.
|
211
|
+
actual = I18n.translate("mailbox.inbox", {count: 1, defaults: [{scope: "inbox"}]});
|
212
|
+
expected = I18n.translate("inbox", {count: 1})
|
198
213
|
expect(actual).toEqual(expected)
|
199
214
|
})
|
200
215
|
});
|
201
216
|
|
202
217
|
it("uses default value for simple translation", function(){
|
203
|
-
actual = I18n.
|
218
|
+
actual = I18n.translate("warning", {defaultValue: "Warning!"});
|
204
219
|
expect(actual).toEqual("Warning!");
|
205
220
|
});
|
206
221
|
|
207
222
|
it("uses default value for plural translation", function(){
|
208
|
-
actual = I18n.
|
223
|
+
actual = I18n.translate("message", {defaultValue: { one: '%{count} message', other: '%{count} messages'}, count: 1});
|
209
224
|
expect(actual).toEqual("1 message");
|
210
225
|
});
|
211
226
|
|
212
227
|
it("uses default value for unknown locale", function(){
|
213
228
|
I18n.locale = "fr";
|
214
|
-
actual = I18n.
|
229
|
+
actual = I18n.translate("warning", {defaultValue: "Warning!"});
|
215
230
|
expect(actual).toEqual("Warning!");
|
216
231
|
});
|
217
232
|
|
218
233
|
it("uses default value with interpolation", function(){
|
219
|
-
actual = I18n.
|
234
|
+
actual = I18n.translate(
|
220
235
|
"alert",
|
221
236
|
{defaultValue: "Attention! {{message}}", message: "You're out of quota!"}
|
222
237
|
);
|
@@ -225,33 +240,33 @@ describe("Translate", function(){
|
|
225
240
|
});
|
226
241
|
|
227
242
|
it("ignores default value when scope exists", function(){
|
228
|
-
actual = I18n.
|
243
|
+
actual = I18n.translate("hello", {defaultValue: "What's up?"});
|
229
244
|
expect(actual).toEqual("Hello World!");
|
230
245
|
});
|
231
246
|
|
232
247
|
it("returns translation for custom scope separator", function(){
|
233
248
|
I18n.defaultSeparator = "•";
|
234
|
-
actual = I18n.
|
249
|
+
actual = I18n.translate("greetings•stranger");
|
235
250
|
expect(actual).toEqual("Hello stranger!");
|
236
251
|
});
|
237
252
|
|
238
253
|
it("returns boolean values", function() {
|
239
|
-
expect(I18n.
|
240
|
-
expect(I18n.
|
254
|
+
expect(I18n.translate("booleans.yes")).toEqual(true);
|
255
|
+
expect(I18n.translate("booleans.no")).toEqual(false);
|
241
256
|
});
|
242
257
|
|
243
258
|
it("escapes $ when doing substitution (IE)", function(){
|
244
259
|
I18n.locale = "en";
|
245
260
|
|
246
|
-
expect(I18n.
|
247
|
-
expect(I18n.
|
248
|
-
expect(I18n.
|
261
|
+
expect(I18n.translate("paid", {price: "$0"})).toEqual("You were paid $0");
|
262
|
+
expect(I18n.translate("paid", {price: "$0.12"})).toEqual("You were paid $0.12");
|
263
|
+
expect(I18n.translate("paid", {price: "$1.35"})).toEqual("You were paid $1.35");
|
249
264
|
});
|
250
265
|
|
251
266
|
it("replaces all occurrences of escaped $", function(){
|
252
267
|
I18n.locale = "en";
|
253
268
|
|
254
|
-
expect(I18n.
|
269
|
+
expect(I18n.translate("paid_with_vat", {
|
255
270
|
price: "$0.12",
|
256
271
|
vat: "$0.02"}
|
257
272
|
)).toEqual("You were paid $0.12 (incl. VAT $0.02)");
|
@@ -259,20 +274,20 @@ describe("Translate", function(){
|
|
259
274
|
|
260
275
|
it("sets default scope", function(){
|
261
276
|
var options = {scope: "greetings"};
|
262
|
-
expect(I18n.
|
277
|
+
expect(I18n.translate("stranger", options)).toEqual("Hello stranger!");
|
263
278
|
});
|
264
279
|
|
265
280
|
it("accepts the scope as an array", function(){
|
266
|
-
expect(I18n.
|
281
|
+
expect(I18n.translate(["greetings", "stranger"])).toEqual("Hello stranger!");
|
267
282
|
});
|
268
283
|
|
269
284
|
it("accepts the scope as an array using a base scope", function(){
|
270
|
-
expect(I18n.
|
285
|
+
expect(I18n.translate(["stranger"], {scope: "greetings"})).toEqual("Hello stranger!");
|
271
286
|
});
|
272
287
|
|
273
288
|
it("returns an array with values interpolated", function(){
|
274
289
|
var options = {value: 314};
|
275
|
-
expect(I18n.
|
290
|
+
expect(I18n.translate("arrayWithParams", options)).toEqual([
|
276
291
|
null,
|
277
292
|
"An item with a param of " + options.value,
|
278
293
|
"Another item with a param of " + options.value,
|
data/spec/js/translations.js
CHANGED
@@ -90,7 +90,16 @@
|
|
90
90
|
hello: "Olá Mundo!"
|
91
91
|
|
92
92
|
, number: {
|
93
|
-
|
93
|
+
currency: {
|
94
|
+
format: {
|
95
|
+
delimiter: ".",
|
96
|
+
format: "%u %n",
|
97
|
+
precision: 2,
|
98
|
+
separator: ",",
|
99
|
+
unit: "R$"
|
100
|
+
}
|
101
|
+
}
|
102
|
+
, percentage: {
|
94
103
|
format: {
|
95
104
|
delimiter: ""
|
96
105
|
, separator: ","
|
data/spec/ruby/i18n/js_spec.rb
CHANGED
@@ -351,7 +351,7 @@ EOS
|
|
351
351
|
end
|
352
352
|
end
|
353
353
|
|
354
|
-
context "namespace, prefix and pretty_print options" do
|
354
|
+
context "namespace, prefix, suffix, and pretty_print options" do
|
355
355
|
|
356
356
|
before do
|
357
357
|
stub_const('I18n::JS::DEFAULT_EXPORT_DIR_PATH', temp_path)
|
@@ -379,6 +379,7 @@ EOS
|
|
379
379
|
"foo": "Foo",
|
380
380
|
"fallback_test": "Success"
|
381
381
|
};
|
382
|
+
//test
|
382
383
|
EOS
|
383
384
|
}$/)
|
384
385
|
end
|
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.
|
4
|
+
version: 3.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nando Vieira
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-06-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: i18n
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '2.
|
33
|
+
version: '2.3'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '2.
|
40
|
+
version: '2.3'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -126,6 +126,7 @@ files:
|
|
126
126
|
- gemfiles/i18n_1_5.gemfile
|
127
127
|
- gemfiles/i18n_1_6.gemfile
|
128
128
|
- gemfiles/i18n_1_7.gemfile
|
129
|
+
- gemfiles/i18n_1_8.gemfile
|
129
130
|
- i18n-js.gemspec
|
130
131
|
- lib/i18n-js.rb
|
131
132
|
- lib/i18n/js.rb
|
@@ -207,7 +208,7 @@ homepage: http://rubygems.org/gems/i18n-js
|
|
207
208
|
licenses:
|
208
209
|
- MIT
|
209
210
|
metadata: {}
|
210
|
-
post_install_message:
|
211
|
+
post_install_message:
|
211
212
|
rdoc_options: []
|
212
213
|
require_paths:
|
213
214
|
- lib
|
@@ -222,8 +223,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
222
223
|
- !ruby/object:Gem::Version
|
223
224
|
version: '0'
|
224
225
|
requirements: []
|
225
|
-
rubygems_version: 3.
|
226
|
-
signing_key:
|
226
|
+
rubygems_version: 3.1.4
|
227
|
+
signing_key:
|
227
228
|
specification_version: 4
|
228
229
|
summary: It's a small library to provide the Rails I18n translations on the Javascript.
|
229
230
|
test_files:
|