i18n-js 2.1.2 → 3.0.11

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.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +24 -0
  3. data/.gitignore +5 -4
  4. data/.npmignore +27 -0
  5. data/.travis.yml +37 -0
  6. data/Appraisals +20 -0
  7. data/CHANGELOG.md +354 -0
  8. data/Gemfile +1 -1
  9. data/README.md +872 -0
  10. data/Rakefile +19 -7
  11. data/app/assets/javascripts/i18n/filtered.js.erb +23 -0
  12. data/app/assets/javascripts/i18n/shims.js +208 -0
  13. data/app/assets/javascripts/i18n/translations.js +3 -0
  14. data/app/assets/javascripts/i18n.js +1077 -0
  15. data/gemfiles/i18n_0_6.gemfile +7 -0
  16. data/gemfiles/i18n_0_7.gemfile +7 -0
  17. data/gemfiles/i18n_0_8.gemfile +7 -0
  18. data/gemfiles/i18n_0_9.gemfile +7 -0
  19. data/gemfiles/i18n_1_0.gemfile +7 -0
  20. data/i18n-js.gemspec +11 -9
  21. data/lib/i18n/js/dependencies.rb +59 -0
  22. data/lib/i18n/js/engine.rb +87 -0
  23. data/lib/i18n/js/fallback_locales.rb +70 -0
  24. data/lib/{i18n-js → i18n/js}/middleware.rb +32 -9
  25. data/lib/i18n/js/private/hash_with_symbol_keys.rb +36 -0
  26. data/lib/i18n/js/segment.rb +88 -0
  27. data/lib/i18n/js/utils.rb +52 -0
  28. data/lib/i18n/js/version.rb +7 -0
  29. data/lib/i18n/js.rb +242 -0
  30. data/lib/i18n-js.rb +1 -177
  31. data/lib/rails/generators/i18n/js/config/config_generator.rb +19 -0
  32. data/{config → lib/rails/generators/i18n/js/config/templates}/i18n-js.yml +11 -6
  33. data/lib/tasks/export.rake +8 -0
  34. data/package.json +25 -0
  35. data/spec/fixtures/custom_path.yml +5 -0
  36. data/spec/fixtures/default.yml +5 -0
  37. data/spec/fixtures/erb.yml +5 -0
  38. data/spec/fixtures/except_condition.yml +7 -0
  39. data/spec/fixtures/js_export_dir_custom.yml +7 -0
  40. data/spec/fixtures/js_export_dir_none.yml +6 -0
  41. data/spec/fixtures/js_extend_parent.yml +6 -0
  42. data/spec/fixtures/js_extend_segment.yml +6 -0
  43. data/spec/fixtures/js_file_per_locale.yml +7 -0
  44. data/spec/fixtures/js_file_per_locale_with_fallbacks_as_default_locale_symbol.yml +4 -0
  45. data/spec/fixtures/js_file_per_locale_with_fallbacks_as_hash.yml +6 -0
  46. data/spec/fixtures/js_file_per_locale_with_fallbacks_as_locale.yml +4 -0
  47. data/spec/fixtures/js_file_per_locale_with_fallbacks_as_locale_without_fallback_translations.yml +4 -0
  48. data/spec/fixtures/js_file_per_locale_with_fallbacks_enabled.yml +4 -0
  49. data/spec/fixtures/js_file_per_locale_without_fallbacks.yml +4 -0
  50. data/spec/fixtures/js_file_with_namespace_and_pretty_print.yml +7 -0
  51. data/spec/fixtures/js_sort_translation_keys_false.yml +6 -0
  52. data/spec/fixtures/js_sort_translation_keys_true.yml +6 -0
  53. data/spec/{resources → fixtures}/locales.yml +13 -1
  54. data/spec/fixtures/multiple_conditions.yml +7 -0
  55. data/spec/fixtures/multiple_conditions_per_locale.yml +7 -0
  56. data/spec/fixtures/multiple_files.yml +7 -0
  57. data/spec/{resources → fixtures}/no_config.yml +0 -0
  58. data/spec/fixtures/no_scope.yml +4 -0
  59. data/spec/fixtures/simple_scope.yml +5 -0
  60. data/spec/js/currency.spec.js +62 -0
  61. data/spec/js/current_locale.spec.js +19 -0
  62. data/spec/js/dates.spec.js +265 -0
  63. data/spec/js/defaults.spec.js +31 -0
  64. data/spec/js/extend.spec.js +110 -0
  65. data/spec/js/interpolation.spec.js +124 -0
  66. data/spec/js/jasmine/MIT.LICENSE +20 -0
  67. data/spec/js/jasmine/jasmine-html.js +190 -0
  68. data/spec/js/jasmine/jasmine.css +166 -0
  69. data/spec/js/jasmine/jasmine.js +2476 -0
  70. data/spec/js/jasmine/jasmine_favicon.png +0 -0
  71. data/spec/js/locales.spec.js +31 -0
  72. data/spec/js/localization.spec.js +48 -0
  73. data/spec/js/numbers.spec.js +170 -0
  74. data/spec/js/placeholder.spec.js +24 -0
  75. data/spec/js/pluralization.spec.js +211 -0
  76. data/spec/js/prepare_options.spec.js +41 -0
  77. data/spec/js/require.js +2083 -0
  78. data/spec/js/specs.html +49 -0
  79. data/spec/js/specs_requirejs.html +72 -0
  80. data/spec/js/translate.spec.js +277 -0
  81. data/spec/js/translations.js +164 -0
  82. data/spec/js/utility_functions.spec.js +20 -0
  83. data/spec/ruby/i18n/js/fallback_locales_spec.rb +84 -0
  84. data/spec/ruby/i18n/js/segment_spec.rb +157 -0
  85. data/spec/ruby/i18n/js/utils_spec.rb +106 -0
  86. data/spec/ruby/i18n/js_spec.rb +627 -0
  87. data/spec/spec_helper.rb +55 -14
  88. data/yarn.lock +131 -0
  89. metadata +188 -96
  90. data/.rspec +0 -1
  91. data/Gemfile.lock +0 -51
  92. data/README.rdoc +0 -305
  93. data/lib/i18n-js/engine.rb +0 -62
  94. data/lib/i18n-js/railtie.rb +0 -13
  95. data/lib/i18n-js/rake.rb +0 -16
  96. data/lib/i18n-js/version.rb +0 -10
  97. data/spec/i18n_spec.js +0 -768
  98. data/spec/i18n_spec.rb +0 -205
  99. data/spec/resources/custom_path.yml +0 -4
  100. data/spec/resources/default.yml +0 -4
  101. data/spec/resources/js_file_per_locale.yml +0 -3
  102. data/spec/resources/multiple_conditions.yml +0 -6
  103. data/spec/resources/multiple_files.yml +0 -6
  104. data/spec/resources/no_scope.yml +0 -3
  105. data/spec/resources/simple_scope.yml +0 -4
  106. data/vendor/assets/javascripts/i18n/translations.js.erb +0 -7
  107. data/vendor/assets/javascripts/i18n.js +0 -450
@@ -0,0 +1,49 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Jasmine Spec Runner</title>
6
+ <link rel="stylesheet" href="jasmine/jasmine.css" type="text/css">
7
+ </head>
8
+
9
+ <body>
10
+ <!-- load jasmine -->
11
+ <script type="text/javascript" src="jasmine/jasmine.js"></script>
12
+ <script type="text/javascript" src="jasmine/jasmine-html.js"></script>
13
+
14
+ <!-- load your javascript files -->
15
+ <script type="text/javascript" src="../../app/assets/javascripts/i18n.js"></script>
16
+ <script type="text/javascript">
17
+ function require(path) {
18
+ if (path.match(/i18n/)) {
19
+ return I18n;
20
+ } else {
21
+ return Translations;
22
+ }
23
+ }
24
+ </script>
25
+
26
+ <!-- load your spec files -->
27
+ <script type="text/javascript" src="translations.js"></script>
28
+ <script type="text/javascript" src="currency.spec.js"></script>
29
+ <script type="text/javascript" src="current_locale.spec.js"></script>
30
+ <script type="text/javascript" src="dates.spec.js"></script>
31
+ <script type="text/javascript" src="defaults.spec.js"></script>
32
+ <script type="text/javascript" src="interpolation.spec.js"></script>
33
+ <script type="text/javascript" src="localization.spec.js"></script>
34
+ <script type="text/javascript" src="locales.spec.js"></script>
35
+ <script type="text/javascript" src="numbers.spec.js"></script>
36
+ <script type="text/javascript" src="placeholder.spec.js"></script>
37
+ <script type="text/javascript" src="pluralization.spec.js"></script>
38
+ <script type="text/javascript" src="prepare_options.spec.js"></script>
39
+ <script type="text/javascript" src="translate.spec.js"></script>
40
+ <script type="text/javascript" src="utility_functions.spec.js"></script>
41
+ <script type="text/javascript" src="extend.spec.js"></script>
42
+
43
+ <!-- run specs -->
44
+ <script type="text/javascript">
45
+ jasmine.getEnv().addReporter(new jasmine.TrivialReporter());
46
+ jasmine.getEnv().execute();
47
+ </script>
48
+ </body>
49
+ </html>
@@ -0,0 +1,72 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Jasmine Spec Runner</title>
6
+ <link rel="stylesheet" href="jasmine/jasmine.css" type="text/css">
7
+ </head>
8
+
9
+ <body>
10
+ <!-- load jasmine -->
11
+ <script type="text/javascript" src="jasmine/jasmine.js"></script>
12
+ <script type="text/javascript" src="jasmine/jasmine-html.js"></script>
13
+
14
+ <!-- load your javascript files -->
15
+ <script type="text/javascript" src="require.js"></script>
16
+
17
+ <script type="text/javascript">
18
+ // Prepare requirejs shims to wrap each test so that it will work with the
19
+ // require syntax loading
20
+ var testScripts = [
21
+ "./translate.spec.js",
22
+ "./currency.spec.js",
23
+ "./current_locale.spec.js",
24
+ "./dates.spec.js",
25
+ "./defaults.spec.js",
26
+ "./interpolation.spec.js",
27
+ "./localization.spec.js",
28
+ "./numbers.spec.js",
29
+ "./placeholder.spec.js",
30
+ "./pluralization.spec.js",
31
+ "./prepare_options.spec.js",
32
+ "./translate.spec.js",
33
+ "./utility_functions.spec.js",
34
+ "./extend.spec.js"
35
+ ];
36
+ var shims = {};
37
+ for(var i = 0; i < testScripts.length; i++) {
38
+ shims[ testScripts[i] ] = {
39
+ "deps": ["i18n"]
40
+ };
41
+ }
42
+ require.config(
43
+ {
44
+ "baseUrl" : "./",
45
+ "paths": {
46
+ "i18n": "../../app/assets/javascripts/i18n"
47
+ },
48
+ /* Since the i18n.js file explicitly names its module 'i18n', but each
49
+ spec uses the full path in the require statement, it appears that
50
+ loading fails. This map will map the full path to the short form.
51
+ */
52
+ "map": {
53
+ "*": {
54
+ "../../app/assets/javascripts/i18n": "i18n"
55
+ }
56
+ },
57
+ "shim": shims
58
+ });
59
+ require((["i18n", './translations']).concat(testScripts),
60
+ function(I18n, translationFactory) {
61
+ // Example for using the translation factory
62
+ I18n.translations = translationFactory();
63
+ console.log(I18n.t('hello'));
64
+
65
+ // Execute the specs
66
+ jasmine.getEnv().addReporter(new jasmine.TrivialReporter());
67
+ jasmine.getEnv().execute();
68
+ });
69
+ </script>
70
+
71
+ </body>
72
+ </html>
@@ -0,0 +1,277 @@
1
+ var I18n = require("../../app/assets/javascripts/i18n")
2
+ , Translations = require("./translations")
3
+ ;
4
+
5
+ describe("Translate", function(){
6
+ var actual, expected;
7
+
8
+ beforeEach(function(){
9
+ I18n.reset();
10
+ I18n.translations = Translations();
11
+ });
12
+
13
+ it("returns translation for single scope", function(){
14
+ expect(I18n.t("hello")).toEqual("Hello World!");
15
+ });
16
+
17
+ it("returns translation as object", function(){
18
+ expect(I18n.t("greetings")).toEqual(I18n.translations.en.greetings);
19
+ });
20
+
21
+ it("returns missing message translation for valid scope with null", function(){
22
+ actual = I18n.t("null_key");
23
+ expected = '[missing "en.null_key" translation]';
24
+ expect(actual).toEqual(expected);
25
+ });
26
+
27
+ it("returns missing message translation for invalid scope", function(){
28
+ actual = I18n.t("invalid.scope");
29
+ expected = '[missing "en.invalid.scope" translation]';
30
+ expect(actual).toEqual(expected);
31
+ });
32
+
33
+ it("returns missing message translation with provided locale for invalid scope", function(){
34
+ actual = I18n.t("invalid.scope", { locale: "ja" });
35
+ expected = '[missing "ja.invalid.scope" translation]';
36
+ expect(actual).toEqual(expected);
37
+ });
38
+
39
+ it("returns guessed translation if missingBehaviour is set to guess", function(){
40
+ I18n.missingBehaviour = 'guess'
41
+ actual = I18n.t("invalid.thisIsAutomaticallyGeneratedTranslation");
42
+ expected = 'this is automatically generated translation';
43
+ expect(actual).toEqual(expected);
44
+ });
45
+
46
+ it("returns guessed translation with prefix if missingBehaviour is set to guess and prefix is also provided", function(){
47
+ I18n.missingBehaviour = 'guess'
48
+ I18n.missingTranslationPrefix = 'EE: '
49
+ actual = I18n.t("invalid.thisIsAutomaticallyGeneratedTranslation");
50
+ expected = 'EE: this is automatically generated translation';
51
+ expect(actual).toEqual(expected);
52
+ });
53
+
54
+ it("returns missing message translation for valid scope with scope", function(){
55
+ actual = I18n.t("monster", {scope: "greetings"});
56
+ expected = '[missing "en.greetings.monster" translation]';
57
+ expect(actual).toEqual(expected);
58
+ });
59
+
60
+ it("returns translation for single scope on a custom locale", function(){
61
+ I18n.locale = "pt-BR";
62
+ expect(I18n.t("hello")).toEqual("Olá Mundo!");
63
+ });
64
+
65
+ it("returns translation for multiple scopes", function(){
66
+ expect(I18n.t("greetings.stranger")).toEqual("Hello stranger!");
67
+ });
68
+
69
+ it("returns translation with default locale option", function(){
70
+ expect(I18n.t("hello", {locale: "en"})).toEqual("Hello World!");
71
+ expect(I18n.t("hello", {locale: "pt-BR"})).toEqual("Olá Mundo!");
72
+ });
73
+
74
+ it("fallbacks to the default locale when I18n.fallbacks is enabled", function(){
75
+ I18n.locale = "pt-BR";
76
+ I18n.fallbacks = true;
77
+ expect(I18n.t("greetings.stranger")).toEqual("Hello stranger!");
78
+ });
79
+
80
+ it("fallbacks to default locale when providing an unknown locale", function(){
81
+ I18n.locale = "fr";
82
+ I18n.fallbacks = true;
83
+ expect(I18n.t("greetings.stranger")).toEqual("Hello stranger!");
84
+ });
85
+
86
+ it("fallbacks to less specific locale", function(){
87
+ I18n.locale = "de-DE";
88
+ I18n.fallbacks = true;
89
+ expect(I18n.t("hello")).toEqual("Hallo Welt!");
90
+ });
91
+
92
+ describe("when a 3-part locale is used", function(){
93
+ beforeEach(function(){
94
+ I18n.locale = "zh-Hant-TW";
95
+ I18n.fallbacks = true;
96
+ });
97
+
98
+ it("fallbacks to 2-part locale when absent", function(){
99
+ expect(I18n.t("cat")).toEqual("貓");
100
+ });
101
+
102
+ it("fallbacks to 1-part locale when 2-part missing requested translation", function(){
103
+ expect(I18n.t("dog")).toEqual("狗");
104
+ });
105
+
106
+ it("fallbacks to 2-part for the first time", function(){
107
+ expect(I18n.t("dragon")).toEqual("龍");
108
+ });
109
+ });
110
+
111
+ it("fallbacks using custom rules (function)", function(){
112
+ I18n.locale = "no";
113
+ I18n.fallbacks = true;
114
+ I18n.locales["no"] = function() {
115
+ return ["nb"];
116
+ };
117
+
118
+ expect(I18n.t("hello")).toEqual("Hei Verden!");
119
+ });
120
+
121
+ it("fallbacks using custom rules (array)", function() {
122
+ I18n.locale = "no";
123
+ I18n.fallbacks = true;
124
+ I18n.locales["no"] = ["no", "nb"];
125
+
126
+ expect(I18n.t("hello")).toEqual("Hei Verden!");
127
+ });
128
+
129
+ it("fallbacks using custom rules (string)", function() {
130
+ I18n.locale = "no";
131
+ I18n.fallbacks = true;
132
+ I18n.locales["no"] = "nb";
133
+
134
+ expect(I18n.t("hello")).toEqual("Hei Verden!");
135
+ });
136
+
137
+ describe("when provided default values", function() {
138
+ it("uses scope provided in defaults if scope doesn't exist", function() {
139
+ actual = I18n.t("Hello!", {defaults: [{scope: "greetings.stranger"}]});
140
+ expect(actual).toEqual("Hello stranger!");
141
+ });
142
+
143
+ it("continues to fallback until a scope is found", function() {
144
+ var defaults = [{scope: "foo"}, {scope: "hello"}];
145
+
146
+ actual = I18n.t("foo", {defaults: defaults});
147
+ expect(actual).toEqual("Hello World!");
148
+ });
149
+
150
+ it("uses message if specified as a default", function() {
151
+ var defaults = [{message: "Hello all!"}];
152
+ actual = I18n.t("foo", {defaults: defaults});
153
+ expect(actual).toEqual("Hello all!");
154
+ });
155
+
156
+ it("uses the first message if no scopes are found", function() {
157
+ var defaults = [
158
+ {scope: "bar"}
159
+ , {message: "Hello all!"}
160
+ , {scope: "hello"}];
161
+ actual = I18n.t("foo", {defaults: defaults});
162
+ expect(actual).toEqual("Hello all!");
163
+ });
164
+
165
+ it("uses default value if no scope is found", function() {
166
+ var options = {
167
+ defaults: [{scope: "bar"}]
168
+ , defaultValue: "Hello all!"
169
+ };
170
+ actual = I18n.t("foo", options);
171
+ expect(actual).toEqual("Hello all!");
172
+ });
173
+
174
+ it("uses default scope over default value if default scope is found", function() {
175
+ var options = {
176
+ defaults: [{scope: "hello"}]
177
+ , defaultValue: "Hello all!"
178
+ };
179
+ actual = I18n.t("foo", options);
180
+ expect(actual).toEqual("Hello World!");
181
+ })
182
+
183
+ it("uses default value with lazy evaluation", function () {
184
+ var options = {
185
+ defaults: [{scope: "bar"}]
186
+ , defaultValue: function(scope) {
187
+ return scope.toUpperCase();
188
+ }
189
+ };
190
+ actual = I18n.t("foo", options);
191
+ expect(actual).toEqual("FOO");
192
+ })
193
+ });
194
+
195
+ it("uses default value for simple translation", function(){
196
+ actual = I18n.t("warning", {defaultValue: "Warning!"});
197
+ expect(actual).toEqual("Warning!");
198
+ });
199
+
200
+ it("uses default value for plural translation", function(){
201
+ actual = I18n.t("message", {defaultValue: { one: '%{count} message', other: '%{count} messages'}, count: 1});
202
+ expect(actual).toEqual("1 message");
203
+ });
204
+
205
+ it("uses default value for unknown locale", function(){
206
+ I18n.locale = "fr";
207
+ actual = I18n.t("warning", {defaultValue: "Warning!"});
208
+ expect(actual).toEqual("Warning!");
209
+ });
210
+
211
+ it("uses default value with interpolation", function(){
212
+ actual = I18n.t(
213
+ "alert",
214
+ {defaultValue: "Attention! {{message}}", message: "You're out of quota!"}
215
+ );
216
+
217
+ expect(actual).toEqual("Attention! You're out of quota!");
218
+ });
219
+
220
+ it("ignores default value when scope exists", function(){
221
+ actual = I18n.t("hello", {defaultValue: "What's up?"});
222
+ expect(actual).toEqual("Hello World!");
223
+ });
224
+
225
+ it("returns translation for custom scope separator", function(){
226
+ I18n.defaultSeparator = "•";
227
+ actual = I18n.t("greetings•stranger");
228
+ expect(actual).toEqual("Hello stranger!");
229
+ });
230
+
231
+ it("returns boolean values", function() {
232
+ expect(I18n.t("booleans.yes")).toEqual(true);
233
+ expect(I18n.t("booleans.no")).toEqual(false);
234
+ });
235
+
236
+ it("escapes $ when doing substitution (IE)", function(){
237
+ I18n.locale = "en";
238
+
239
+ expect(I18n.t("paid", {price: "$0"})).toEqual("You were paid $0");
240
+ expect(I18n.t("paid", {price: "$0.12"})).toEqual("You were paid $0.12");
241
+ expect(I18n.t("paid", {price: "$1.35"})).toEqual("You were paid $1.35");
242
+ });
243
+
244
+ it("replaces all occurrences of escaped $", function(){
245
+ I18n.locale = "en";
246
+
247
+ expect(I18n.t("paid_with_vat", {
248
+ price: "$0.12",
249
+ vat: "$0.02"}
250
+ )).toEqual("You were paid $0.12 (incl. VAT $0.02)");
251
+ });
252
+
253
+ it("sets default scope", function(){
254
+ var options = {scope: "greetings"};
255
+ expect(I18n.t("stranger", options)).toEqual("Hello stranger!");
256
+ });
257
+
258
+ it("accepts the scope as an array", function(){
259
+ expect(I18n.t(["greetings", "stranger"])).toEqual("Hello stranger!");
260
+ });
261
+
262
+ it("accepts the scope as an array using a base scope", function(){
263
+ expect(I18n.t(["stranger"], {scope: "greetings"})).toEqual("Hello stranger!");
264
+ });
265
+
266
+ it("returns an array with values interpolated", function(){
267
+ var options = {value: 314};
268
+ expect(I18n.t("arrayWithParams", options)).toEqual([
269
+ null,
270
+ "An item with a param of " + options.value,
271
+ "Another item with a param of " + options.value,
272
+ "A last item with a param of " + options.value,
273
+ ["An", "array", "of", "strings"],
274
+ {foo: "bar"}
275
+ ]);
276
+ });
277
+ });
@@ -0,0 +1,164 @@
1
+ var DEBUG = false;
2
+
3
+ ;(function(){
4
+ var generator = function() {
5
+ var Translations = {};
6
+
7
+ Translations.en = {
8
+ hello: "Hello World!"
9
+ , paid: "You were paid %{price}"
10
+
11
+ , paid_with_vat: "You were paid %{price} (incl. VAT %{vat})"
12
+
13
+ , booleans: {
14
+ yes: true,
15
+ no: false
16
+ }
17
+
18
+ , greetings: {
19
+ stranger: "Hello stranger!"
20
+ , name: "Hello {{name}}!"
21
+ }
22
+
23
+ , profile: {
24
+ details: "{{name}} is {{age}}-years old"
25
+ }
26
+
27
+ , inbox: {
28
+ one: "You have {{count}} message"
29
+ , other: "You have {{count}} messages"
30
+ , zero: "You have no messages"
31
+ }
32
+
33
+ , sent: {
34
+ one: null
35
+ , other: null
36
+ , zero: null
37
+ }
38
+
39
+ , unread: {
40
+ one: "You have 1 new message ({{unread}} unread)"
41
+ , other: "You have {{count}} new messages ({{unread}} unread)"
42
+ , zero: "You have no new messages ({{unread}} unread)"
43
+ }
44
+
45
+ , number: {
46
+ human: {
47
+ storage_units: {
48
+ units: {
49
+ "byte": {
50
+ one: "Byte"
51
+ , other: "Bytes"
52
+ }
53
+ , "kb": "KB"
54
+ , "mb": "MB"
55
+ , "gb": "GB"
56
+ , "tb": "TB"
57
+ }
58
+ }
59
+ }
60
+ }
61
+
62
+ , arrayWithParams: [
63
+ null,
64
+ "An item with a param of {{value}}",
65
+ "Another item with a param of {{value}}",
66
+ "A last item with a param of {{value}}",
67
+ ["An", "array", "of", "strings"],
68
+ {foo: "bar"}
69
+ ]
70
+
71
+ , null_key: null
72
+ };
73
+
74
+ Translations["en-US"] = {
75
+ date: {
76
+ formats: {
77
+ "default": "%d/%m/%Y"
78
+ , "short": "%d de %B"
79
+ , "long": "%d de %B de %Y"
80
+ }
81
+
82
+ , day_names: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
83
+ , abbr_day_names: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
84
+ , month_names: [null, "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
85
+ , abbr_month_names: [null, "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"]
86
+ , meridian: ["am", "pm"]
87
+ }
88
+ };
89
+
90
+ Translations["pt-BR"] = {
91
+ hello: "Olá Mundo!"
92
+
93
+ , number: {
94
+ percentage: {
95
+ format: {
96
+ delimiter: ""
97
+ , separator: ","
98
+ , precision: 2
99
+ }
100
+ }
101
+ }
102
+
103
+ , date: {
104
+ formats: {
105
+ "default": "%d/%m/%Y"
106
+ , "short": "%d de %B"
107
+ , "long": "%d de %B de %Y"
108
+ , "short_with_placeholders": "%d de %B {{p1}} {{p2}}"
109
+ }
110
+ , day_names: ["Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado"]
111
+ , abbr_day_names: ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb"]
112
+ , month_names: [null, "Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"]
113
+ , abbr_month_names: [null, "Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"]
114
+ }
115
+
116
+ , time: {
117
+ formats: {
118
+ "default": "%A, %d de %B de %Y, %H:%M h"
119
+ , "short": "%d/%m, %H:%M h"
120
+ , "long": "%A, %d de %B de %Y, %H:%M h"
121
+ , "short_with_placeholders": "%d/%m, %H:%M h {{p1}}"
122
+ }
123
+ , am: "AM"
124
+ , pm: "PM"
125
+ }
126
+ };
127
+
128
+ Translations["de"] = {
129
+ hello: "Hallo Welt!"
130
+ , date: {
131
+ day_names: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"]
132
+ }
133
+
134
+ , time: {
135
+ am: "de:AM"
136
+ , pm: "de:PM"
137
+ }
138
+ };
139
+
140
+ Translations["nb"] = {
141
+ hello: "Hei Verden!"
142
+ };
143
+
144
+ Translations["zh-Hant"] = {
145
+ cat: "貓"
146
+ , dragon: "龍"
147
+ };
148
+
149
+ Translations["zh"] = {
150
+ dog: "狗"
151
+ , dragon: "龙"
152
+ };
153
+
154
+ return Translations;
155
+ };
156
+
157
+ if (typeof define === 'function' && define.amd) {
158
+ define(function() { return generator; });
159
+ } else if (typeof(exports) === "undefined") {
160
+ window.Translations = generator;
161
+ } else {
162
+ module.exports = generator;
163
+ }
164
+ })();
@@ -0,0 +1,20 @@
1
+ var I18n = require("../../app/assets/javascripts/i18n");
2
+
3
+ describe("Utility Functions", function(){
4
+ beforeEach(function(){
5
+ I18n.reset();
6
+ });
7
+
8
+ describe("I18n.lookup", function() {
9
+ it("does not change locale on failed lookup", function(){
10
+ var fallback_locales = ['fallback1', 'fallback2'];
11
+
12
+ I18n.locales['lang'] = fallback_locales.slice();
13
+ expect(I18n.locales.lang).toEqual(fallback_locales);
14
+
15
+ I18n.lookup('anything', {locale: 'lang'})
16
+ expect(I18n.locales.lang).toEqual(fallback_locales);
17
+ });
18
+
19
+ })
20
+ });
@@ -0,0 +1,84 @@
1
+ require "spec_helper"
2
+
3
+ describe I18n::JS::FallbackLocales do
4
+ let(:locale) { :fr }
5
+ let(:default_locale) { :en }
6
+
7
+ describe "#locales" do
8
+ let(:fallbacks_locales) { described_class.new(fallbacks, locale) }
9
+ subject { fallbacks_locales.locales }
10
+
11
+ let(:fetching_locales) { proc do fallbacks_locales.locales end }
12
+
13
+ context "when given true as fallbacks" do
14
+ let(:fallbacks) { true }
15
+ it { should eq([default_locale]) }
16
+ end
17
+
18
+ context "when given false as fallbacks" do
19
+ let(:fallbacks) { false }
20
+ it { expect(fetching_locales).to raise_error(ArgumentError) }
21
+ end
22
+
23
+ context "when given a valid locale as fallbacks" do
24
+ let(:fallbacks) { :de }
25
+ it { should eq([:de]) }
26
+ end
27
+
28
+ context "when given a valid Array as fallbacks" do
29
+ let(:fallbacks) { [:de, :en] }
30
+ it { should eq([:de, :en]) }
31
+ end
32
+
33
+ context "when given a valid Hash with current locale as key as fallbacks" do
34
+ let(:fallbacks) do { :fr => [:de, :en] } end
35
+ it { should eq([:de, :en]) }
36
+ end
37
+
38
+ context "when given a valid Hash without current locale as key as fallbacks" do
39
+ let(:fallbacks) do { :de => [:fr, :en] } end
40
+ it { should eq([default_locale]) }
41
+ end
42
+
43
+ context "when given a invalid locale as fallbacks" do
44
+ let(:fallbacks) { :invalid_locale }
45
+ it { should eq([:invalid_locale]) }
46
+ end
47
+
48
+ context "when given a invalid type as fallbacks" do
49
+ let(:fallbacks) { 42 }
50
+ it { expect(fetching_locales).to raise_error(ArgumentError) }
51
+ end
52
+
53
+ # I18n::Backend::Fallbacks
54
+ context "when I18n::Backend::Fallbacks is used" do
55
+ let(:backend_with_fallbacks) { backend_class_with_fallbacks.new }
56
+
57
+ before do
58
+ I18n.backend = backend_with_fallbacks
59
+ I18n.fallbacks[:fr] = [:de, :en]
60
+ end
61
+ after { I18n.backend = I18n::Backend::Simple.new }
62
+
63
+ context "given true as fallbacks" do
64
+ let(:fallbacks) { true }
65
+ it { should eq([:de, :en]) }
66
+ end
67
+
68
+ context "given :default_locale as fallbacks" do
69
+ let(:fallbacks) { :default_locale }
70
+ it { should eq([:en]) }
71
+ end
72
+
73
+ context "given a Hash with current locale as fallbacks" do
74
+ let(:fallbacks) do { :fr => [:en] } end
75
+ it { should eq([:en]) }
76
+ end
77
+
78
+ context "given a Hash without current locale as fallbacks" do
79
+ let(:fallbacks) do { :de => [:en] } end
80
+ it { should eq([:de, :en]) }
81
+ end
82
+ end
83
+ end
84
+ end