Skip to content

Commit ee45900

Browse files
authored
Fix: fix & improve AR (#137)
* Fix: fix & improve AR * more tests * AR improvements * Add 1 test * test params
1 parent ec37966 commit ee45900

File tree

2 files changed

+127
-100
lines changed

2 files changed

+127
-100
lines changed

lib/i18n/ar.js

Lines changed: 59 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export class Arabic extends AbstractLanguage {
2828
'تسعة عشر',
2929
],
3030
feminine: [
31-
'إحدى',
31+
'واحدة',
3232
'اثنتان',
3333
'ثلاث',
3434
'أربع',
@@ -64,10 +64,6 @@ export class Arabic extends AbstractLanguage {
6464

6565
arabicPluralGroups = ['', 'آلاف', 'ملايين', 'مليارات', 'تريليونات', 'كوادريليونات', 'كوينتليونات', 'سكستيليونات'];
6666

67-
// isCurrencyPartNameFeminine = true
68-
69-
// isCurrencyNameFeminine = false
70-
7167
constructor(options) {
7268
options = Object.assign({
7369
negativeWord: 'ناقص',
@@ -82,98 +78,101 @@ export class Arabic extends AbstractLanguage {
8278
}
8379

8480
digitFeminineStatus(digit) {
85-
// if ((groupLevel == -1 && this.isCurrencyPartNameFeminine) || (groupLevel == 0 && this.isCurrencyNameFeminine)) {
86-
// return this.arabicFeminineOnes[digit]
87-
// }
8881
return this.ones[this.feminine ? 'feminine' : 'masculine'][digit - 1];
8982
}
9083

91-
processArabicGroup(groupNumber, groupLevel, remainingNumber) {
84+
/**
85+
* Processes the Arabic group number and returns the corresponding Arabic representation.
86+
* @param {number} groupNumber - The number to process. From 1 to 999.
87+
* @param {number} groupLevel - The level of the group.
88+
* Example: 12345678 is processed in blocks: '678' (group 0), '345' (group 1), '12' (group 2)
89+
* @returns {string} The Arabic representation of the group number.
90+
*/
91+
processArabicGroup(groupNumber, groupLevel) {
9292
let tens = groupNumber % 100;
9393
const hundreds = groupNumber / 100;
9494
let retVal = '';
9595

96-
if (hundreds > 0) {
97-
retVal = (tens == 0 && Math.trunc(hundreds) == 2 ? this.arabicAppendedTwos[0] : this.arabicHundreds[Math.trunc(hundreds)]);
96+
if (Math.trunc(hundreds) > 0) {
97+
if (tens == 0 && Math.trunc(hundreds) == 2) {
98+
retVal = this.arabicTwos[0];
99+
} else {
100+
retVal = this.arabicHundreds[Math.trunc(hundreds)];
101+
if (retVal != '' && tens != 0) {
102+
retVal += ' و';
103+
}
104+
}
98105
}
99106

100-
if (tens > 0) {
101-
if (tens < 20) {
102-
if (tens == 2 && Math.trunc(hundreds) == 0 && groupLevel > 0) {
103-
retVal = ([
104-
2000, 2000000, 2000000000, 2000000000000, 2000000000000000, 2000000000000000000
105-
].indexOf(this.number) != -1) ? this.arabicAppendedTwos[groupLevel] : this.arabicTwos[groupLevel];
106-
} else {
107-
// Add divider
108-
if (retVal != '') {
109-
retVal += ' و ';
110-
}
111-
112-
if (tens == 1 && groupLevel > 0 && hundreds == 0) {
113-
retVal += '';
114-
} else if (
115-
(tens == 1 || tens == 2) &&
116-
(groupLevel == 0 || groupLevel == -1) &&
117-
(hundreds == 0 && remainingNumber == 0)
118-
) {
119-
retVal += '';
107+
if (tens > 0 && tens < 20) { // 1 -> 19
108+
if (tens === 2 && Math.trunc(hundreds) === 0 && groupLevel > 0) {
109+
const pow = Math.trunc(Math.log10(Number(this.number)));
110+
if (pow % 3 === 0 && this.number === 2 * Math.pow(10, pow)) {
111+
if (groupNumber === 2) {
112+
retVal = this.arabicTwos[Math.trunc(groupLevel)];
120113
} else {
121-
retVal += this.digitFeminineStatus(Math.trunc(tens), groupLevel);
114+
retVal = this.arabicAppendedTwos[Math.trunc(groupLevel)];
122115
}
116+
} else {
117+
retVal = this.arabicTwos[Math.trunc(groupLevel)];
123118
}
119+
} else if (tens === 1 && groupLevel > 0) {
120+
retVal += this.arabicGroup[Math.trunc(groupLevel)];
124121
} else {
125-
const ones = tens % 10;
126-
tens = (tens / 10) - 2;
127-
128-
if (ones > 0) {
129-
if (retVal != '' && tens < 4) {
130-
retVal += ' و ';
131-
}
132-
133-
retVal += this.digitFeminineStatus(ones, groupLevel);
134-
}
135-
if (retVal != '' && ones != 0) {
136-
retVal += ' و ';
137-
}
138-
139-
retVal += this.arabicTens[Math.trunc(tens)];
122+
retVal += this.digitFeminineStatus(Math.trunc(tens), groupLevel);
123+
}
124+
} else if (tens >= 20) { // 20 -> 99
125+
const ones = tens % 10;
126+
const tensIndex = (tens / 10) - 2;
127+
if (ones > 0) {
128+
retVal += this.digitFeminineStatus(ones, groupLevel);
140129
}
130+
if (retVal != '' && ones != 0) {
131+
retVal += ' و';
132+
}
133+
retVal += this.arabicTens[Math.trunc(tensIndex)];
141134
}
142135

143136
return retVal;
144137
}
145138

139+
/**
140+
* Converts a number to its cardinal representation in Arabic.
141+
* It process by blocks of 3 digits.
142+
* @param {number} number - The number to convert.
143+
* @returns {string} The cardinal representation of the number in Arabic.
144+
*/
146145
toCardinal(number) {
147146
if (number == 0) {
148147
return this.zero;
149148
}
150149

151150
this.number = number;
152151
let tempNumber = number;
152+
let tempNumberDec;
153153
let group = 0;
154154
let retVal = '';
155155

156156
// Loop until number has been reduced to zero or less
157157
while (tempNumber > 0) {
158+
tempNumberDec = tempNumber;
158159
// Get the remaining value after dividing by 1000
159-
const numberToProcess = Number(tempNumber % 1000n); // Maximum: 999
160-
// Divide number by 1000
161-
tempNumber = tempNumber / 1000n;
160+
const numberToProcess = Number(tempNumberDec % 1000n); // Maximum: 999
161+
tempNumber = tempNumberDec / 1000n;
162162

163163
// Process "group"
164-
const groupDescription = this.processArabicGroup(numberToProcess, group, tempNumber);
164+
const groupDescription = this.processArabicGroup(numberToProcess, group);
165165

166166
// Did the group return anything?
167167
if (groupDescription != '') {
168-
// Is this after the first "group"?
169-
if (group > 0) {
170-
// Is the return value still empty?
168+
// Is this after the first "group" ? Because nothing is appeded after group 0.
169+
if (group > 0) { // hundreds, thousands, etc...
170+
// Is the return value still empty ?
171171
if (retVal != '') {
172-
retVal = ' و ' + retVal;
172+
retVal = ' و' + retVal;
173173
}
174174

175-
// Process every number other than 2
176-
if (numberToProcess != 2) {
175+
if (numberToProcess > 2) {
177176
if (numberToProcess % 100 != 1) {
178177
if (numberToProcess >= 3 && numberToProcess <= 10) {
179178
retVal = this.arabicPluralGroups[group] + ' ' + retVal;
@@ -199,6 +198,9 @@ export class Arabic extends AbstractLanguage {
199198
group++;
200199
}
201200

201+
// Replace multiple spaces with one space
202+
retVal = retVal.replace(/ +/g, ' ');
203+
202204
return retVal.trim();
203205
}
204206
}

test/i18n/ar.js

Lines changed: 68 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,70 +2,95 @@ export default [
22
[0.01, 'صفر فاصلة صفر واحد'],
33
[1.7, 'واحد فاصلة سبعة'],
44
[1.007, 'واحد فاصلة صفر صفر سبعة'],
5-
[17.42, 'سبعة عشر فاصلة اثنان و أربعون'],
6-
[27.312, 'سبعة و عشرون فاصلة ثلاثمائة و اثنا عشر'],
7-
[53.486, 'ثلاثة و خمسون فاصلة أربعمائةستة و ثمانون'], //FIXME
8-
[300.42, 'ثلاثمائة فاصلة اثنان و أربعون'],
9-
[4196.42, 'أربعة آلاف و مائةستة و تسعون فاصلة اثنان و أربعون'], //FIXME
5+
[17.42, 'سبعة عشر فاصلة اثنان وأربعون'],
6+
[27.312, 'سبعة وعشرون فاصلة ثلاثمائة واثنا عشر'],
7+
[53.486, 'ثلاثة وخمسون فاصلة أربعمائة وستة وثمانون'],
8+
[300.42, 'ثلاثمائة فاصلة اثنان وأربعون'],
9+
[4196.42, 'أربعة آلاف ومائة وستة وتسعون فاصلة اثنان وأربعون'],
1010

11-
[-17.42, 'ناقص سبعة عشر فاصلة اثنان و أربعون'],
11+
[-17.42, 'ناقص سبعة عشر فاصلة اثنان وأربعون'],
1212
[-1, 'ناقص واحد'],
1313
[-20, 'ناقص عشرون'],
14+
[-20, 'سالب عشرون', { negativeWord: 'سالب' }],
1415

1516
[0, 'صفر'],
1617
[1, 'واحد'],
18+
[1, 'واحدة', { feminine: true }],
1719
[2, 'اثنان'],
1820
[3, 'ثلاثة'],
21+
[3, 'ثلاث', { feminine: true }],
1922
[11, 'أحد عشر'],
23+
[11, 'إحدى عشرة', { feminine: true }],
2024
[12, 'اثنا عشر'],
2125
[16, 'ستة عشر'],
2226
[19, 'تسعة عشر'],
2327
[20, 'عشرون'],
24-
[21, 'واحد و عشرون'],
25-
[26, 'ستة و عشرون'],
26-
[28, 'ثمانية و عشرون'],
28+
[21, 'واحد وعشرون'],
29+
[26, 'ستة وعشرون'],
30+
[28, 'ثمانية وعشرون'],
2731
[30, 'ثلاثون'],
28-
[31, 'واحد و ثلاثون'],
32+
[31, 'واحد وثلاثون'],
2933
[40, 'أربعون'],
30-
[44, 'أربعة و أربعون'],
34+
[44, 'أربعة وأربعون'],
3135
[50, 'خمسون'],
32-
[55, 'خمسة و خمسون'],
36+
[55, 'خمسة وخمسون'],
3337
[60, 'ستون'],
34-
[67, 'سبعة و ستون'],
38+
[67, 'سبعة وستون'],
3539
[70, 'سبعون'],
36-
[79, 'تسعة و سبعون'],
37-
[89, 'تسعة و ثمانون'],
38-
[95, 'خمسة و تسعون'],
40+
[79, 'تسعة وسبعون'],
41+
[89, 'تسعة وثمانون'],
42+
[95, 'خمسة وتسعون'],
3943
[100, 'مائة'],
40-
[101, 'مائة و واحد'],
41-
[199, 'مائةتسعة و تسعون'],
42-
[203, 'مئتان و ثلاثة'],
43-
[287, 'مئتانسبعة و ثمانون'],
44-
[356, 'ثلاثمائة و ستة و خمسون'],
44+
[101, 'مائة وواحد'],
45+
[110, 'مائة وعشرة'],
46+
[110, 'مائة وعشر', { feminine: true }],
47+
[120, 'مائة وعشرون'],
48+
[130, 'مائة وثلاثون'],
49+
[130, 'مائة وثلاثون', { feminine: true }],
50+
[190, 'مائة وتسعون'],
51+
[198, 'مائة وثمانية وتسعون'],
52+
[199, 'مائة وتسعة وتسعون'],
53+
[200, 'مئتان'],
54+
[203, 'مئتان وثلاثة'],
55+
[287, 'مئتان وسبعة وثمانون'],
56+
[356, 'ثلاثمائة وستة وخمسون'],
4557
[400, 'أربعمائة'],
46-
[434, 'أربعمائة و أربعة و ثلاثون'],
47-
[578, 'خمسمائةثمانية و سبعون'],
48-
[689, 'ستمائةتسعة و ثمانون'],
49-
[729, 'سبعمائة و تسعة و عشرون'],
50-
[894, 'ثمانمائةأربعة و تسعون'],
51-
[999, 'تسعمائةتسعة و تسعون'],
52-
[1000, 'واحد ألف'],
53-
[1001, 'واحد ألف و واحد'],
54-
[1097, 'واحد ألف و سبعة و تسعون'],
55-
[1104, 'واحد ألف و مائة و أربعة'],
56-
[1243, 'واحد ألف و مئتان و ثلاثة و أربعون'],
57-
[2385, 'ألفان و ثلاثمائةخمسة و ثمانون'],
58-
[3766, 'ثلاثة آلاف و سبعمائةستة و ستون'],
59-
[4196, 'أربعة آلاف و مائةستة و تسعون'], //FIXME
60-
[5846, 'خمسة آلاف و ثمانمائة و ستة و أربعون'],
61-
[6459, 'ستة آلاف و أربعمائة و تسعة و خمسون'],
62-
[7232, 'سبعة آلاف و مئتان و اثنان و ثلاثون'],
63-
[8569, 'ثمانية آلاف و خمسمائةتسعة و ستون'],
64-
[9539, 'تسعة آلاف و خمسمائة و تسعة و ثلاثون'],
65-
[1000000, 'واحد مليون'],
66-
[1000001, 'واحد مليون و واحد'],
58+
[434, 'أربعمائة وأربعة وثلاثون'],
59+
[578, 'خمسمائة وثمانية وسبعون'],
60+
[689, 'ستمائة وتسعة وثمانون'],
61+
[729, 'سبعمائة وتسعة وعشرون'],
62+
[810, 'ثمانمائة وعشرة'],
63+
[820, 'ثمانمائة وعشرون'],
64+
[823, 'ثمانمائة وثلاثة وعشرون'],
65+
[833, 'ثمانمائة وثلاثة وثلاثون'],
66+
[863, 'ثمانمائة وثلاثة وستون'],
67+
[883, 'ثمانمائة وثلاثة وثمانون'],
68+
[894, 'ثمانمائة وأربعة وتسعون'],
69+
[999, 'تسعمائة وتسعة وتسعون'],
70+
[1000, 'ألف'],
71+
[2000, 'ألفان'],
72+
[1001, 'ألف وواحد'],
73+
[1097, 'ألف وسبعة وتسعون'],
74+
[1104, 'ألف ومائة وأربعة'],
75+
[1243, 'ألف ومئتان وثلاثة وأربعون'],
76+
[2385, 'ألفان وثلاثمائة وخمسة وثمانون'],
77+
[3766, 'ثلاثة آلاف وسبعمائة وستة وستون'],
78+
[4196, 'أربعة آلاف ومائة وستة وتسعون'],
79+
[5846, 'خمسة آلاف وثمانمائة وستة وأربعون'],
80+
[6459, 'ستة آلاف وأربعمائة وتسعة وخمسون'],
81+
[7232, 'سبعة آلاف ومئتان واثنان وثلاثون'],
82+
[8569, 'ثمانية آلاف وخمسمائة وتسعة وستون'],
83+
[9539, 'تسعة آلاف وخمسمائة وتسعة وثلاثون'],
84+
[200200, 'مئتان ألفاً ومئتان'],
85+
[200000, 'مئتان ألف'],
86+
[300200, 'ثلاثمائة ألفاً ومئتان'],
87+
[1000000, 'مليون'],
88+
[1000001, 'مليون وواحد'],
89+
[2000000, 'مليونان'],
6790
[4000000, 'أربعة ملايين'],
91+
[12345678, 'اثنا عشر مليوناً وثلاثمائة وخمسة وأربعون ألفاً وستمائة وثمانية وسبعون'],
92+
[2000000000, 'ملياران'],
6893
[10000000000000, 'عشرة تريليونات'],
6994
[100000000000000, 'مائة تريليون'],
70-
[1000000000000000000n, 'واحد كوينتليون'],
95+
[1000000000000000000n, 'كوينتليون'],
7196
];

0 commit comments

Comments
 (0)