UNPKG

9.67 kBJavaScriptView Raw
1'use strict';
2
3
4var Assert = require('assert');
5var BabelFish = require('../lib/babelfish');
6
7
8function hasFunction(func) {
9 return function (i18n) {
10 Assert.isFunction(i18n[func], 'has ' + func + ' function');
11 };
12}
13
14
15function hasAlias(alias, original) {
16 return function (i18n) {
17 Assert.ok(i18n[original] === i18n[alias],
18 alias + ' is alias of ' + original);
19 };
20}
21
22
23function hasProperty(prop) {
24 return function (i18n) {
25 Assert.include(i18n, prop, 'has ' + prop + ' property');
26 Assert.isFalse('function' === typeof i18n[prop],
27 prop + ' is a scalar or getter');
28 };
29}
30
31
32require('vows').describe('BabelFish').addBatch({
33 // API consistence tests
34 'Exported module': {
35 'is a constructor': function () {
36 Assert.isFunction(BabelFish);
37 Assert.instanceOf(new BabelFish(), BabelFish);
38 },
39
40 'has `create` (constructor proxy)': function () {
41 Assert.isFunction(BabelFish.create);
42 Assert.equal(BabelFish.create.length, BabelFish.length);
43 Assert.instanceOf(BabelFish.create(), BabelFish);
44 }
45 },
46
47 'Instance': {
48 topic: new BabelFish(),
49 'has `addPhrase()` method' : hasFunction('addPhrase'),
50 'has `getCompiledData()` method' : hasFunction('getCompiledData'),
51 'has `setFallback()` method' : hasFunction('setFallback'),
52 'has `translate()` method' : hasFunction('translate'),
53 'has `t()` aliase' : hasAlias('t', 'translate'),
54 'has `defaultLocale` property' : hasProperty('defaultLocale'),
55
56 '`defaultLocale` property is read-only': function (i18n) {
57 Assert.throws(function () { i18n.defaultLocale = 'ru'; }, TypeError);
58 Assert.throws(function () { delete i18n.defaultLocale; }, TypeError);
59 }
60 },
61
62 'New instance with defaults': {
63 topic: function () { return BabelFish.create(); },
64 'has defaultLocale = `en`': function (i18n) {
65 Assert.equal(i18n.defaultLocale, 'en', 'defaultLocale is en');
66 }
67 },
68
69 'New instance with defaultLocale given': {
70 topic: function () { return BabelFish.create('ru'); },
71 'has defaultLocale equal to the specified one': function (i18n) {
72 Assert.equal(i18n.defaultLocale, 'ru', 'defaultLocale is ru');
73 }
74 }
75}).addBatch({
76 // Behavior and unit tests come here
77 'When fallback is given': {
78 topic: function () {
79 var i18n = BabelFish.create('en');
80
81 i18n.setFallback('es', ['es-ES', 'es-MX']);
82 i18n.setFallback('es-ES', ['es', 'es-US']);
83
84 i18n.addPhrase('en', 'aaa', 'aaa (en)');
85 i18n.addPhrase('en', 'bbb', 'bbb (en)');
86 i18n.addPhrase('en', 'ccc', 'ccc (en)');
87 i18n.addPhrase('en', 'ddd', 'ddd (en)');
88 i18n.addPhrase('es', 'aaa', 'aaa (es)');
89 i18n.addPhrase('es-ES', 'bbb', 'bbb (es-ES)');
90 i18n.addPhrase('es-MX', 'ccc', 'ccc (es-MX)');
91 i18n.addPhrase('es-US', 'ddd', 'ddd (es-US)');
92
93 i18n.setFallback('es-US', ['es']);
94
95 return i18n;
96 },
97
98 'use defaultLocale in worst case': function (i18n) {
99 Assert.equal(i18n.t('es', 'ddd'), 'ddd (en)');
100 Assert.equal(i18n.t('ru', 'ddd'), 'ddd (en)');
101 },
102
103 'allows specify more than one fallback locale': function (i18n) {
104 Assert.equal(i18n.t('es', 'aaa'), 'aaa (es)');
105 Assert.equal(i18n.t('es', 'bbb'), 'bbb (es-ES)');
106 Assert.equal(i18n.t('es', 'ccc'), 'ccc (es-MX)');
107 Assert.equal(i18n.t('es', 'ddd'), 'ddd (en)');
108 },
109
110 'do not recursively resolve locale fallbacks': function (i18n) {
111 Assert.equal(i18n.t('es-ES', 'aaa'), 'aaa (es)');
112 Assert.equal(i18n.t('es-ES', 'bbb'), 'bbb (es-ES)');
113 Assert.equal(i18n.t('es-ES', 'ccc'), 'ccc (en)');
114 Assert.equal(i18n.t('es-ES', 'ddd'), 'ddd (es-US)');
115 },
116
117 'allow specify fallbacks after phrases were added': function (i18n) {
118 Assert.equal(i18n.t('es-US', 'aaa'), 'aaa (es)');
119 Assert.equal(i18n.t('es-US', 'bbb'), 'bbb (en)');
120 Assert.equal(i18n.t('es-US', 'ccc'), 'ccc (en)');
121 Assert.equal(i18n.t('es-US', 'ddd'), 'ddd (es-US)');
122 },
123
124 'allows re-assign fallbacks': function (i18n) {
125 i18n.setFallback('es-US', ['es-ES', 'es-MX']);
126
127 Assert.equal(i18n.t('es', 'aaa'), 'aaa (es)');
128 Assert.equal(i18n.t('es', 'bbb'), 'bbb (es-ES)');
129 Assert.equal(i18n.t('es', 'ccc'), 'ccc (es-MX)');
130 Assert.equal(i18n.t('es', 'ddd'), 'ddd (en)');
131 }
132 },
133
134 'Setting fallback for defaultLocale': {
135 topic: function () {
136 return BabelFish.create('en');
137 },
138 'cause exception': function (i18n) {
139 Assert.throws(function () { i18n.setFallback('en', ['en-GB']); }, Error);
140 }
141 },
142
143 'Adding phrases': {
144 topic: function () {
145 var i18n = BabelFish.create('en');
146
147 i18n.addPhrase('en', 'phrase1', 'foobar');
148 i18n.addPhrase('en', 'scope.phrase2', 'foobar');
149 i18n.addPhrase('en', 'scope', {phrase3: 'foobar'});
150
151 return i18n;
152 },
153
154 'allows specify phrase within `global` scope': function (i18n) {
155 Assert.equal(i18n.t('en', 'phrase1'), 'foobar');
156 },
157
158 'allows specify phrase prefixed with scope': function (i18n) {
159 Assert.equal(i18n.t('en', 'scope.phrase2'), 'foobar');
160 },
161
162 'allows specify translations as inner scope': function (i18n) {
163 Assert.equal(i18n.t('en', 'scope.phrase3'), 'foobar');
164 }
165 },
166
167 'Getting compiled data': {
168 topic: function () {
169 var i18n = BabelFish.create('en');
170
171 i18n.addPhrase('en', 'test.simple_string', 'test');
172 i18n.addPhrase('en', 'test.complex.variable', '-#{count}-');
173 i18n.addPhrase('en', 'test.complex.plurals', '-((foo|bar)):count-');
174 i18n.addPhrase('ru', 'test.complex.plurals', '-((ruu|bar)):count-');
175
176 return i18n;
177 },
178
179 'data is a String when scope has no macros or variables': function (i18n) {
180 var translation = i18n.getCompiledData('en', 'test.simple_string');
181
182 Assert.equal(translation.type, 'string');
183 Assert.equal(translation.translation, 'test');
184 },
185
186 // locale is needed on stage of locale recompiling (to override fallback
187 // translations if needed)
188 'data has field with actual locale of translation': function (i18n) {
189 Assert.equal(i18n.getCompiledData('ru', 'test.simple_string').locale, 'en');
190 Assert.equal(i18n.getCompiledData('ru', 'test.complex.variable').locale, 'en');
191 Assert.equal(i18n.getCompiledData('ru', 'test.complex.plurals').locale, 'ru');
192 },
193
194 'data is a Function when scope has macros or variable': function (i18n) {
195 ['test.complex.plurals', 'test.complex.variable'].forEach(function (scope) {
196 var data = i18n.getCompiledData('en', scope);
197 Assert.equal(data.type, 'function', 'type of ' + scope + ' data is function');
198 Assert.instanceOf(data.translation, Function, 'value of ' + scope + ' data is Function');
199 });
200 },
201
202 'returns inner scope Object when locale only requested': function (i18n) {
203 var data = i18n.getCompiledData('ru');
204
205 Assert.typeOf(data, 'object');
206
207 Assert.include(data, 'test.simple_string');
208 Assert.include(data, 'test.complex.variable');
209
210 Assert.equal(data['test.simple_string'].type, 'string');
211 Assert.equal(data['test.complex.variable'].type, 'function');
212 }
213 },
214
215 'Translating a phrase': {
216 topic: function () {
217 var i18n = BabelFish.create('en');
218
219 i18n.addPhrase('en', 'a', 'a (en)');
220 i18n.addPhrase('en', 'b', 'b (en)');
221 i18n.addPhrase('en', 'c', 'c (en) ((one|other)):count');
222 i18n.addPhrase('fr', 'd', 'd (fr) ((une|autre)):count');
223 i18n.addPhrase('ru', 'b', 'b (ru) #{foo}');
224 i18n.addPhrase('es', 'b', 'b (es) #{f.o}');
225
226 return i18n;
227 },
228
229 'always returns a string': function (i18n) {
230 Assert.equal(i18n.t('en', 'a'), 'a (en)');
231 Assert.equal(i18n.t('en', 'b'), 'b (en)');
232 Assert.equal(i18n.t('ru', 'b', {foo: 'bar'}), 'b (ru) bar');
233 },
234
235 'ignores provided params when they are not needed': function (i18n) {
236 Assert.equal(i18n.t('en', 'b', {foo: 'bar', bar: 'baz'}), 'b (en)');
237 },
238
239 'replaces missing params with [missed variable: <name>]': function (i18n) {
240 Assert.equal(i18n.t('ru', 'b'), 'b (ru) [missed variable: foo]');
241 Assert.equal(i18n.t('es', 'b'), 'b (es) [missed variable: f.o]');
242 },
243
244 'honors objects in params': function (i18n) {
245 Assert.equal(i18n.t('es', 'b', {f: {o: 'bar'}}), 'b (es) bar');
246 },
247
248 'reports missing translation': function (i18n) {
249 Assert.equal(i18n.t('en', 'd', {count: 0}), 'en: No translation for [d]');
250 },
251
252 'honors pluralization': function (i18n) {
253 Assert.equal(i18n.t('en', 'c', {count: 0}), 'c (en) other');
254 Assert.equal(i18n.t('en', 'c', {count: 1}), 'c (en) one');
255 Assert.equal(i18n.t('en', 'c', {count: 2}), 'c (en) other');
256 Assert.equal(i18n.t('fr', 'c', {count: 0}), 'c (en) other');
257
258 // check that we use correct pluralizer
259 Assert.equal(i18n.t('en', 'c', {count: 1}), 'c (en) one');
260 Assert.equal(i18n.t('en', 'c', {count: 1.5}), 'c (en) other');
261 Assert.equal(i18n.t('fr', 'd', {count: 0}), 'd (fr) une');
262 Assert.equal(i18n.t('fr', 'd', {count: 1.5}), 'd (fr) une');
263 },
264
265 'replaces invalid plurals amount with [invalid plurals amount: <name>(<value>)]': function (i18n) {
266 Assert.equal(i18n.t('en', 'c'), 'c (en) [invalid plurals amount: count(undefined)]');
267 Assert.equal(i18n.t('en', 'c', {count: null}), 'c (en) [invalid plurals amount: count(null)]');
268 Assert.equal(i18n.t('en', 'c', {count: "foo"}), 'c (en) [invalid plurals amount: count(foo)]');
269 }
270 }
271}).export(module);