i18n-js 3.5.1 → 3.8.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/.github/FUNDING.yml +3 -0
- data/.github/workflows/tests.yaml +100 -0
- data/Appraisals +4 -0
- data/CHANGELOG.md +46 -1
- data/README.md +457 -340
- data/app/assets/javascripts/i18n.js +24 -21
- data/gemfiles/i18n_1_8.gemfile +7 -0
- data/i18n-js.gemspec +1 -1
- data/i18njs.png +0 -0
- data/lib/i18n/js.rb +13 -8
- data/lib/i18n/js/formatters/base.rb +2 -1
- data/lib/i18n/js/formatters/js.rb +1 -1
- data/lib/i18n/js/private/config_store.rb +31 -0
- 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/localization.spec.js +14 -0
- data/spec/js/numbers.spec.js +4 -0
- data/spec/js/translate.spec.js +13 -3
- data/spec/js/translations.js +27 -2
- data/spec/ruby/i18n/js_spec.rb +2 -1
- data/spec/spec_helper.rb +1 -0
- data/yarn.lock +2 -2
- metadata +13 -9
- data/.travis.yml +0 -37
@@ -402,7 +402,7 @@
|
|
402
402
|
|
403
403
|
while (locales.length) {
|
404
404
|
locale = locales.shift();
|
405
|
-
scopes = fullScope.split(this.defaultSeparator);
|
405
|
+
scopes = fullScope.split(options.separator || this.defaultSeparator);
|
406
406
|
translations = this.translations[locale];
|
407
407
|
|
408
408
|
if (!translations) {
|
@@ -459,7 +459,7 @@
|
|
459
459
|
|
460
460
|
while (locales.length) {
|
461
461
|
locale = locales.shift();
|
462
|
-
scopes = scope.split(this.defaultSeparator);
|
462
|
+
scopes = scope.split(options.separator || this.defaultSeparator);
|
463
463
|
translations = this.translations[locale];
|
464
464
|
|
465
465
|
if (!translations) {
|
@@ -679,13 +679,13 @@
|
|
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
|
|
686
686
|
var localeForTranslation = (options != null && options.locale != null) ? options.locale : this.currentLocale();
|
687
687
|
var fullScope = this.getFullScope(scope, options);
|
688
|
-
var fullScopeWithLocale = [localeForTranslation, fullScope].join(this.defaultSeparator);
|
688
|
+
var fullScopeWithLocale = [localeForTranslation, fullScope].join(options.separator || this.defaultSeparator);
|
689
689
|
|
690
690
|
return '[missing "' + fullScopeWithLocale + '" translation]';
|
691
691
|
};
|
@@ -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
|
}
|
@@ -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
|
|
@@ -984,9 +984,9 @@
|
|
984
984
|
};
|
985
985
|
|
986
986
|
// Convert the given dateString into a formatted date.
|
987
|
-
I18n.toTime = function(scope, dateString) {
|
987
|
+
I18n.toTime = function(scope, dateString, options) {
|
988
988
|
var date = this.parseDate(dateString)
|
989
|
-
, format = this.lookup(scope)
|
989
|
+
, format = this.lookup(scope, options)
|
990
990
|
;
|
991
991
|
|
992
992
|
// A date input of `null` or `undefined` will be returned as-is
|
@@ -1003,15 +1003,15 @@
|
|
1003
1003
|
return date_string;
|
1004
1004
|
}
|
1005
1005
|
|
1006
|
-
return this.strftime(date, format);
|
1006
|
+
return this.strftime(date, format, options);
|
1007
1007
|
};
|
1008
1008
|
|
1009
1009
|
// Convert a number into a formatted percentage value.
|
1010
1010
|
I18n.toPercentage = function(number, options) {
|
1011
1011
|
options = this.prepareOptions(
|
1012
1012
|
options
|
1013
|
-
, this.lookup("number.percentage.format")
|
1014
|
-
, this.lookup("number.format")
|
1013
|
+
, this.lookup("number.percentage.format", options)
|
1014
|
+
, this.lookup("number.format", options)
|
1015
1015
|
, PERCENTAGE_FORMAT
|
1016
1016
|
);
|
1017
1017
|
|
@@ -1025,6 +1025,7 @@
|
|
1025
1025
|
, iterations = 0
|
1026
1026
|
, unit
|
1027
1027
|
, precision
|
1028
|
+
, fullScope
|
1028
1029
|
;
|
1029
1030
|
|
1030
1031
|
while (size >= kb && iterations < 4) {
|
@@ -1033,10 +1034,12 @@
|
|
1033
1034
|
}
|
1034
1035
|
|
1035
1036
|
if (iterations === 0) {
|
1036
|
-
|
1037
|
+
fullScope = this.getFullScope("number.human.storage_units.units.byte", options);
|
1038
|
+
unit = this.t(fullScope, {count: size});
|
1037
1039
|
precision = 0;
|
1038
1040
|
} else {
|
1039
|
-
|
1041
|
+
fullScope = this.getFullScope("number.human.storage_units.units." + SIZE_UNITS[iterations], options);
|
1042
|
+
unit = this.t(fullScope);
|
1040
1043
|
precision = (size - Math.floor(size) === 0) ? 0 : 1;
|
1041
1044
|
}
|
1042
1045
|
|
@@ -1053,7 +1056,7 @@
|
|
1053
1056
|
|
1054
1057
|
// Deal with the scope as an array.
|
1055
1058
|
if (isArray(scope)) {
|
1056
|
-
scope = scope.join(this.defaultSeparator);
|
1059
|
+
scope = scope.join(options.separator || this.defaultSeparator);
|
1057
1060
|
}
|
1058
1061
|
|
1059
1062
|
// Deal with the scope option provided through the second argument.
|
@@ -1061,7 +1064,7 @@
|
|
1061
1064
|
// I18n.t('hello', {scope: 'greetings'});
|
1062
1065
|
//
|
1063
1066
|
if (options.scope) {
|
1064
|
-
scope = [options.scope, scope].join(this.defaultSeparator);
|
1067
|
+
scope = [options.scope, scope].join(options.separator || this.defaultSeparator);
|
1065
1068
|
}
|
1066
1069
|
|
1067
1070
|
return scope;
|
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"
|
data/i18njs.png
ADDED
Binary file
|
data/lib/i18n/js.rb
CHANGED
@@ -4,6 +4,7 @@ require "i18n"
|
|
4
4
|
|
5
5
|
require "i18n/js/utils"
|
6
6
|
require "i18n/js/private/hash_with_symbol_keys"
|
7
|
+
require "i18n/js/private/config_store"
|
7
8
|
|
8
9
|
module I18n
|
9
10
|
module JS
|
@@ -26,6 +27,8 @@ module I18n
|
|
26
27
|
|
27
28
|
def self.config_file_path=(new_path)
|
28
29
|
@config_file_path = new_path
|
30
|
+
# new config file path = need to re-read config from new file
|
31
|
+
Private::ConfigStore.instance.flush_cache
|
29
32
|
end
|
30
33
|
|
31
34
|
# Allow using a different backend than the one globally configured
|
@@ -108,14 +111,16 @@ module I18n
|
|
108
111
|
# Load configuration file for partial exporting and
|
109
112
|
# custom output directory
|
110
113
|
def self.config
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
114
|
+
Private::ConfigStore.instance.fetch do
|
115
|
+
if config_file_exists?
|
116
|
+
erb_result_from_yaml_file = ERB.new(File.read(config_file_path)).result
|
117
|
+
Private::HashWithSymbolKeys.new(
|
118
|
+
(::YAML.load(erb_result_from_yaml_file) || {})
|
119
|
+
)
|
120
|
+
else
|
121
|
+
Private::HashWithSymbolKeys.new({})
|
122
|
+
end.freeze
|
123
|
+
end
|
119
124
|
end
|
120
125
|
|
121
126
|
# @api private
|
@@ -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
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "singleton"
|
4
|
+
|
5
|
+
module I18n
|
6
|
+
module JS
|
7
|
+
# @api private
|
8
|
+
module Private
|
9
|
+
# Caching implementation for I18n::JS.config
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
class ConfigStore
|
13
|
+
include Singleton
|
14
|
+
|
15
|
+
def fetch
|
16
|
+
return @config if @config
|
17
|
+
|
18
|
+
yield.tap do |obj|
|
19
|
+
raise AugumentError, "unexpected falsy object from block" unless obj
|
20
|
+
|
21
|
+
@config = obj
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def flush_cache
|
26
|
+
@config = nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
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
@@ -36,6 +36,20 @@ describe("Localization", function(){
|
|
36
36
|
expect(I18n.localize("date.formats.long", "2009-01-07")).toEqual("07 de Janeiro de 2009");
|
37
37
|
});
|
38
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%");
|
51
|
+
});
|
52
|
+
|
39
53
|
it("localizes time strings", function(){
|
40
54
|
I18n.locale = "pt-BR";
|
41
55
|
|
data/spec/js/numbers.spec.js
CHANGED
@@ -150,6 +150,10 @@ describe("Numbers", function(){
|
|
150
150
|
expect(I18n.toHumanSize(1024 * 1.6, {precision: 0})).toEqual("2KB");
|
151
151
|
});
|
152
152
|
|
153
|
+
it("returns number as human size using custom scope", function(){
|
154
|
+
expect(I18n.toHumanSize(1024 * 1024, {scope: "extended"})).toEqual("1Megabyte");
|
155
|
+
});
|
156
|
+
|
153
157
|
it("formats numbers with strip insignificant zero", function() {
|
154
158
|
options = {separator: ".", delimiter: ",", strip_insignificant_zeros: true};
|
155
159
|
|
data/spec/js/translate.spec.js
CHANGED
@@ -48,9 +48,14 @@ describe("Translate", function(){
|
|
48
48
|
|
49
49
|
it("returns guessed translation if missingBehaviour is set to guess", function(){
|
50
50
|
I18n.missingBehaviour = 'guess'
|
51
|
-
|
52
|
-
|
53
|
-
|
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);
|
54
59
|
});
|
55
60
|
|
56
61
|
it("returns guessed translation with prefix if missingBehaviour is set to guess and prefix is also provided", function(){
|
@@ -291,4 +296,9 @@ describe("Translate", function(){
|
|
291
296
|
{foo: "bar"}
|
292
297
|
]);
|
293
298
|
});
|
299
|
+
|
300
|
+
|
301
|
+
it("returns value with key containing dot but different separator specified", function() {
|
302
|
+
expect(I18n.t(["A implies B means something."], {scope: "sentences_with_dots", separator: "|"})).toEqual("A implies B means that when A is true, B must be true.");
|
303
|
+
});
|
294
304
|
});
|
data/spec/js/translations.js
CHANGED
@@ -58,6 +58,18 @@
|
|
58
58
|
}
|
59
59
|
}
|
60
60
|
|
61
|
+
, extended: {
|
62
|
+
number: {
|
63
|
+
human: {
|
64
|
+
storage_units: {
|
65
|
+
units: {
|
66
|
+
"mb": "Megabyte"
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
61
73
|
, arrayWithParams: [
|
62
74
|
null,
|
63
75
|
"An item with a param of {{value}}",
|
@@ -67,7 +79,11 @@
|
|
67
79
|
{foo: "bar"}
|
68
80
|
]
|
69
81
|
|
70
|
-
, null_key: null
|
82
|
+
, null_key: null,
|
83
|
+
|
84
|
+
sentences_with_dots: {
|
85
|
+
"A implies B means something.": "A implies B means that when A is true, B must be true."
|
86
|
+
}
|
71
87
|
};
|
72
88
|
|
73
89
|
Translations["en-US"] = {
|
@@ -90,7 +106,16 @@
|
|
90
106
|
hello: "Olá Mundo!"
|
91
107
|
|
92
108
|
, number: {
|
93
|
-
|
109
|
+
currency: {
|
110
|
+
format: {
|
111
|
+
delimiter: ".",
|
112
|
+
format: "%u %n",
|
113
|
+
precision: 2,
|
114
|
+
separator: ",",
|
115
|
+
unit: "R$"
|
116
|
+
}
|
117
|
+
}
|
118
|
+
, percentage: {
|
94
119
|
format: {
|
95
120
|
delimiter: ""
|
96
121
|
, 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
|