Skip to content

Commit 4c476cf

Browse files
committed
Added ability to parse complex conditions for plurals.
Removed unnecessary functions and replaced with eval() with checking for accepted syntax.
1 parent 981617e commit 4c476cf

File tree

2 files changed

+50
-68
lines changed

2 files changed

+50
-68
lines changed

l10n.js

Lines changed: 15 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*/
1010

1111
/*global XMLHttpRequest, setTimeout, document, navigator, ActiveXObject*/
12-
/*jslint plusplus: true, continue: true*/
12+
/*jslint plusplus: true, continue: true, evil: true*/
1313
(function () {
1414
"use strict";
1515

@@ -115,56 +115,6 @@
115115
delete load_queues[locale];
116116
},
117117
use_default,
118-
opDetect = /n(==|!=|<|>|<=|>=|%|&&|\|\|)([0-9]+)/i,
119-
opEqual = function (operand1, operand2) {
120-
return operand1 === operand2;
121-
},
122-
opNotEqual = function (operand1, operand2) {
123-
return operand1 !== operand2;
124-
},
125-
opLesser = function (operand1, operand2) {
126-
return operand1 < operand2;
127-
},
128-
opGreater = function (operand1, operand2) {
129-
return operand1 > operand2;
130-
},
131-
opLesserEqual = function (operand1, operand2) {
132-
return operand1 <= operand2;
133-
},
134-
opGreaterEqual = function (operand1, operand2) {
135-
return operand1 >= operand2;
136-
},
137-
opMod = function (operand1, operand2) {
138-
return (operand1 % operand2) === 0;
139-
},
140-
opAnd = function (operand1, operand2) {
141-
return operand1 && operand2;
142-
},
143-
opOr = function (operand1, operand2) {
144-
return operand1 || operand2;
145-
},
146-
operate = function (operand1, operator, operand2) {
147-
switch (operator) {
148-
case '==':
149-
return opEqual(operand1, operand2);
150-
case '!=':
151-
return opNotEqual(operand1, operand2);
152-
case '<':
153-
return opLesser(operand1, operand2);
154-
case '>':
155-
return opGreater(operand1, operand2);
156-
case '<=':
157-
return opLesserEqual(operand1, operand2);
158-
case '>=':
159-
return opGreaterEqual(operand1, operand2);
160-
case '%':
161-
return opMod(operand1, operand2);
162-
case '&&':
163-
return opAnd(operand1, operand2);
164-
case '||':
165-
return opOr(operand1, operand2);
166-
}
167-
},
168118
/**
169119
* Evaluates the plural statements to get the correct index in the array.
170120
* The plurality evaluation statement has to be coordinated with
@@ -173,15 +123,21 @@
173123
* On the other hand, if plural=(n==1), first cell should be "cat"
174124
* and second cell should be "cats".
175125
*/
176-
parsePlural = function (pluralForms, cardinality) {
177-
var re = /^nplurals=[0-9];\s*plural=\(([n!=><%0-9]*)\)/i,
178-
plural,
126+
parsePlural = function (pluralForms, n) {
127+
//n is used in eval()
128+
var re = /^nplurals=[0-9];\s*plural=\(([n!=><(?:\s+\|\|\s+)(?:\s+&&\s+)%0-9]{3,})\)/i,
129+
evalResult,
179130
result = re.exec(pluralForms);
180-
//get the part of the evaluation and determine
181-
//the operation to execute
182-
result = opDetect.exec(result[1]);
183-
plural = operate(cardinality, result[1], parseInt(result[2], 10));
184-
return plural ? 0 : 1;
131+
if (result && result[1]) {
132+
evalResult = eval(result[1]);
133+
if (evalResult === true) {
134+
return 0;
135+
}
136+
if (evalResult === false) {
137+
return 1;
138+
}
139+
}
140+
return 0;
185141
},
186142
getPlural = function (localization, position, this_val) {
187143
if (localization['&plurals']) {
@@ -233,7 +189,6 @@
233189
plural = getPlural(localizations[locale], position, this_val);
234190
return plural.replace('__n__', cardinality);
235191
}
236-
//TODO check for more forms
237192
}
238193
if (localizations[locale][this_val]) {
239194
return localizations[locale][this_val];

tests/plural-operator.html

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
e1quite = 'There are quite a number of bears in the zoo.';
2222

2323
test('Inequality test', function () {
24-
//initiate 1 locale
2524
String.toLocaleString({
2625
'en': {
2726
'&plural-forms': 'nplurals=2; plural=(n!=1)',
@@ -48,7 +47,6 @@
4847
});
4948

5049
test('Equality test - singular form is default', function () {
51-
//initiate 1 locale
5250
String.toLocaleString({
5351
'en': {
5452
'&plural-forms': 'nplurals=2; plural=(n==1)',
@@ -75,7 +73,6 @@
7573
});
7674

7775
test('Lesser than test', function () {
78-
//initiate 1 locale
7976
String.toLocaleString({
8077
'en': {
8178
'&plural-forms': 'nplurals=2; plural=(n<5)',
@@ -108,7 +105,6 @@
108105
});
109106

110107
test('Lesser than, equal to test', function () {
111-
//initiate 1 locale
112108
String.toLocaleString({
113109
'en': {
114110
'&plural-forms': 'nplurals=2; plural=(n<=5)',
@@ -141,7 +137,6 @@
141137
});
142138

143139
test('More than test', function () {
144-
//initiate 1 locale
145140
String.toLocaleString({
146141
'en': {
147142
'&plural-forms': 'nplurals=2; plural=(n>5)',
@@ -174,7 +169,6 @@
174169
});
175170

176171
test('Lesser than, equal to test', function () {
177-
//initiate 1 locale
178172
String.toLocaleString({
179173
'en': {
180174
'&plural-forms': 'nplurals=2; plural=(n>=5)',
@@ -207,10 +201,9 @@
207201
});
208202

209203
test('Mod test', function () {
210-
//initiate 1 locale
211204
String.toLocaleString({
212205
'en': {
213-
'&plural-forms': 'nplurals=2; plural=(n%12)',
206+
'&plural-forms': 'nplurals=2; plural=(n%12==0)',
214207
'&plurals': [
215208
{
216209
'%phrase1': 'There are dozens of bears in the zoo.'
@@ -240,6 +233,40 @@
240233
equal(phrase1.toLocaleString(24), e1dozen,
241234
'24: Translated as "' + e1dozen + '".');
242235
});
236+
237+
test('Mod test with special treatment of 0', function () {
238+
String.toLocaleString({
239+
'en': {
240+
'&plural-forms': 'nplurals=2; plural=(n%12==0 && n!=0)',
241+
'&plurals': [
242+
{
243+
'%phrase1': 'There are dozens of bears in the zoo.'
244+
},
245+
{
246+
'%phrase1': 'There are quite a number of bears in the zoo.'
247+
}
248+
]
249+
}
250+
});
251+
String.defaultLocale = 'en';
252+
253+
equal(phrase1.toLocaleString(), e1dozen,
254+
'NULL: Translated as "' + e1dozen + '" because of default.');
255+
equal(phrase1.toLocaleString(0), e1quite,
256+
'0: Translated as "' + e1quite + '".');
257+
equal(phrase1.toLocaleString(1), e1quite,
258+
'1: Translated as "' + e1quite + '".');
259+
equal(phrase1.toLocaleString(2), e1quite,
260+
'2: Translated as "' + e1quite + '".');
261+
equal(phrase1.toLocaleString(11), e1quite,
262+
'11: Translated as "' + e1quite + '".');
263+
equal(phrase1.toLocaleString(12), e1dozen,
264+
'12: Translated as "' + e1dozen + '".');
265+
equal(phrase1.toLocaleString(13), e1quite,
266+
'13: Translated as "' + e1quite + '".');
267+
equal(phrase1.toLocaleString(24), e1dozen,
268+
'24: Translated as "' + e1dozen + '".');
269+
});
243270
</script>
244271
</html>
245272

0 commit comments

Comments
 (0)