From ee45900d3b56efa6f9297944c18e992b8a3a8569 Mon Sep 17 00:00:00 2001 From: Wael <8544289+forzagreen@users.noreply.github.com> Date: Sun, 14 Apr 2024 17:42:29 +0200 Subject: [PATCH] Fix: fix & improve AR (#137) * Fix: fix & improve AR * more tests * AR improvements * Add 1 test * test params --- lib/i18n/ar.js | 116 ++++++++++++++++++++++++------------------------ test/i18n/ar.js | 111 +++++++++++++++++++++++++++------------------ 2 files changed, 127 insertions(+), 100 deletions(-) diff --git a/lib/i18n/ar.js b/lib/i18n/ar.js index bb41314..09b3cad 100644 --- a/lib/i18n/ar.js +++ b/lib/i18n/ar.js @@ -28,7 +28,7 @@ export class Arabic extends AbstractLanguage { 'تسعة عشر', ], feminine: [ - 'إحدى', + 'واحدة', 'اثنتان', 'ثلاث', 'أربع', @@ -64,10 +64,6 @@ export class Arabic extends AbstractLanguage { arabicPluralGroups = ['', 'آلاف', 'ملايين', 'مليارات', 'تريليونات', 'كوادريليونات', 'كوينتليونات', 'سكستيليونات']; - // isCurrencyPartNameFeminine = true - - // isCurrencyNameFeminine = false - constructor(options) { options = Object.assign({ negativeWord: 'ناقص', @@ -82,67 +78,70 @@ export class Arabic extends AbstractLanguage { } digitFeminineStatus(digit) { - // if ((groupLevel == -1 && this.isCurrencyPartNameFeminine) || (groupLevel == 0 && this.isCurrencyNameFeminine)) { - // return this.arabicFeminineOnes[digit] - // } return this.ones[this.feminine ? 'feminine' : 'masculine'][digit - 1]; } - processArabicGroup(groupNumber, groupLevel, remainingNumber) { + /** + * Processes the Arabic group number and returns the corresponding Arabic representation. + * @param {number} groupNumber - The number to process. From 1 to 999. + * @param {number} groupLevel - The level of the group. + * Example: 12345678 is processed in blocks: '678' (group 0), '345' (group 1), '12' (group 2) + * @returns {string} The Arabic representation of the group number. + */ + processArabicGroup(groupNumber, groupLevel) { let tens = groupNumber % 100; const hundreds = groupNumber / 100; let retVal = ''; - if (hundreds > 0) { - retVal = (tens == 0 && Math.trunc(hundreds) == 2 ? this.arabicAppendedTwos[0] : this.arabicHundreds[Math.trunc(hundreds)]); + if (Math.trunc(hundreds) > 0) { + if (tens == 0 && Math.trunc(hundreds) == 2) { + retVal = this.arabicTwos[0]; + } else { + retVal = this.arabicHundreds[Math.trunc(hundreds)]; + if (retVal != '' && tens != 0) { + retVal += ' و'; + } + } } - if (tens > 0) { - if (tens < 20) { - if (tens == 2 && Math.trunc(hundreds) == 0 && groupLevel > 0) { - retVal = ([ - 2000, 2000000, 2000000000, 2000000000000, 2000000000000000, 2000000000000000000 - ].indexOf(this.number) != -1) ? this.arabicAppendedTwos[groupLevel] : this.arabicTwos[groupLevel]; - } else { - // Add divider - if (retVal != '') { - retVal += ' و '; - } - - if (tens == 1 && groupLevel > 0 && hundreds == 0) { - retVal += ''; - } else if ( - (tens == 1 || tens == 2) && - (groupLevel == 0 || groupLevel == -1) && - (hundreds == 0 && remainingNumber == 0) - ) { - retVal += ''; + if (tens > 0 && tens < 20) { // 1 -> 19 + if (tens === 2 && Math.trunc(hundreds) === 0 && groupLevel > 0) { + const pow = Math.trunc(Math.log10(Number(this.number))); + if (pow % 3 === 0 && this.number === 2 * Math.pow(10, pow)) { + if (groupNumber === 2) { + retVal = this.arabicTwos[Math.trunc(groupLevel)]; } else { - retVal += this.digitFeminineStatus(Math.trunc(tens), groupLevel); + retVal = this.arabicAppendedTwos[Math.trunc(groupLevel)]; } + } else { + retVal = this.arabicTwos[Math.trunc(groupLevel)]; } + } else if (tens === 1 && groupLevel > 0) { + retVal += this.arabicGroup[Math.trunc(groupLevel)]; } else { - const ones = tens % 10; - tens = (tens / 10) - 2; - - if (ones > 0) { - if (retVal != '' && tens < 4) { - retVal += ' و '; - } - - retVal += this.digitFeminineStatus(ones, groupLevel); - } - if (retVal != '' && ones != 0) { - retVal += ' و '; - } - - retVal += this.arabicTens[Math.trunc(tens)]; + retVal += this.digitFeminineStatus(Math.trunc(tens), groupLevel); + } + } else if (tens >= 20) { // 20 -> 99 + const ones = tens % 10; + const tensIndex = (tens / 10) - 2; + if (ones > 0) { + retVal += this.digitFeminineStatus(ones, groupLevel); } + if (retVal != '' && ones != 0) { + retVal += ' و'; + } + retVal += this.arabicTens[Math.trunc(tensIndex)]; } return retVal; } + /** + * Converts a number to its cardinal representation in Arabic. + * It process by blocks of 3 digits. + * @param {number} number - The number to convert. + * @returns {string} The cardinal representation of the number in Arabic. + */ toCardinal(number) { if (number == 0) { return this.zero; @@ -150,30 +149,30 @@ export class Arabic extends AbstractLanguage { this.number = number; let tempNumber = number; + let tempNumberDec; let group = 0; let retVal = ''; // Loop until number has been reduced to zero or less while (tempNumber > 0) { + tempNumberDec = tempNumber; // Get the remaining value after dividing by 1000 - const numberToProcess = Number(tempNumber % 1000n); // Maximum: 999 - // Divide number by 1000 - tempNumber = tempNumber / 1000n; + const numberToProcess = Number(tempNumberDec % 1000n); // Maximum: 999 + tempNumber = tempNumberDec / 1000n; // Process "group" - const groupDescription = this.processArabicGroup(numberToProcess, group, tempNumber); + const groupDescription = this.processArabicGroup(numberToProcess, group); // Did the group return anything? if (groupDescription != '') { - // Is this after the first "group"? - if (group > 0) { - // Is the return value still empty? + // Is this after the first "group" ? Because nothing is appeded after group 0. + if (group > 0) { // hundreds, thousands, etc... + // Is the return value still empty ? if (retVal != '') { - retVal = ' و ' + retVal; + retVal = ' و' + retVal; } - // Process every number other than 2 - if (numberToProcess != 2) { + if (numberToProcess > 2) { if (numberToProcess % 100 != 1) { if (numberToProcess >= 3 && numberToProcess <= 10) { retVal = this.arabicPluralGroups[group] + ' ' + retVal; @@ -199,6 +198,9 @@ export class Arabic extends AbstractLanguage { group++; } + // Replace multiple spaces with one space + retVal = retVal.replace(/ +/g, ' '); + return retVal.trim(); } } diff --git a/test/i18n/ar.js b/test/i18n/ar.js index b34afc7..7a79905 100644 --- a/test/i18n/ar.js +++ b/test/i18n/ar.js @@ -2,70 +2,95 @@ export default [ [0.01, 'صفر فاصلة صفر واحد'], [1.7, 'واحد فاصلة سبعة'], [1.007, 'واحد فاصلة صفر صفر سبعة'], - [17.42, 'سبعة عشر فاصلة اثنان و أربعون'], - [27.312, 'سبعة و عشرون فاصلة ثلاثمائة و اثنا عشر'], - [53.486, 'ثلاثة و خمسون فاصلة أربعمائةستة و ثمانون'], //FIXME - [300.42, 'ثلاثمائة فاصلة اثنان و أربعون'], - [4196.42, 'أربعة آلاف و مائةستة و تسعون فاصلة اثنان و أربعون'], //FIXME + [17.42, 'سبعة عشر فاصلة اثنان وأربعون'], + [27.312, 'سبعة وعشرون فاصلة ثلاثمائة واثنا عشر'], + [53.486, 'ثلاثة وخمسون فاصلة أربعمائة وستة وثمانون'], + [300.42, 'ثلاثمائة فاصلة اثنان وأربعون'], + [4196.42, 'أربعة آلاف ومائة وستة وتسعون فاصلة اثنان وأربعون'], - [-17.42, 'ناقص سبعة عشر فاصلة اثنان و أربعون'], + [-17.42, 'ناقص سبعة عشر فاصلة اثنان وأربعون'], [-1, 'ناقص واحد'], [-20, 'ناقص عشرون'], + [-20, 'سالب عشرون', { negativeWord: 'سالب' }], [0, 'صفر'], [1, 'واحد'], + [1, 'واحدة', { feminine: true }], [2, 'اثنان'], [3, 'ثلاثة'], + [3, 'ثلاث', { feminine: true }], [11, 'أحد عشر'], + [11, 'إحدى عشرة', { feminine: true }], [12, 'اثنا عشر'], [16, 'ستة عشر'], [19, 'تسعة عشر'], [20, 'عشرون'], - [21, 'واحد و عشرون'], - [26, 'ستة و عشرون'], - [28, 'ثمانية و عشرون'], + [21, 'واحد وعشرون'], + [26, 'ستة وعشرون'], + [28, 'ثمانية وعشرون'], [30, 'ثلاثون'], - [31, 'واحد و ثلاثون'], + [31, 'واحد وثلاثون'], [40, 'أربعون'], - [44, 'أربعة و أربعون'], + [44, 'أربعة وأربعون'], [50, 'خمسون'], - [55, 'خمسة و خمسون'], + [55, 'خمسة وخمسون'], [60, 'ستون'], - [67, 'سبعة و ستون'], + [67, 'سبعة وستون'], [70, 'سبعون'], - [79, 'تسعة و سبعون'], - [89, 'تسعة و ثمانون'], - [95, 'خمسة و تسعون'], + [79, 'تسعة وسبعون'], + [89, 'تسعة وثمانون'], + [95, 'خمسة وتسعون'], [100, 'مائة'], - [101, 'مائة و واحد'], - [199, 'مائةتسعة و تسعون'], - [203, 'مئتان و ثلاثة'], - [287, 'مئتانسبعة و ثمانون'], - [356, 'ثلاثمائة و ستة و خمسون'], + [101, 'مائة وواحد'], + [110, 'مائة وعشرة'], + [110, 'مائة وعشر', { feminine: true }], + [120, 'مائة وعشرون'], + [130, 'مائة وثلاثون'], + [130, 'مائة وثلاثون', { feminine: true }], + [190, 'مائة وتسعون'], + [198, 'مائة وثمانية وتسعون'], + [199, 'مائة وتسعة وتسعون'], + [200, 'مئتان'], + [203, 'مئتان وثلاثة'], + [287, 'مئتان وسبعة وثمانون'], + [356, 'ثلاثمائة وستة وخمسون'], [400, 'أربعمائة'], - [434, 'أربعمائة و أربعة و ثلاثون'], - [578, 'خمسمائةثمانية و سبعون'], - [689, 'ستمائةتسعة و ثمانون'], - [729, 'سبعمائة و تسعة و عشرون'], - [894, 'ثمانمائةأربعة و تسعون'], - [999, 'تسعمائةتسعة و تسعون'], - [1000, 'واحد ألف'], - [1001, 'واحد ألف و واحد'], - [1097, 'واحد ألف و سبعة و تسعون'], - [1104, 'واحد ألف و مائة و أربعة'], - [1243, 'واحد ألف و مئتان و ثلاثة و أربعون'], - [2385, 'ألفان و ثلاثمائةخمسة و ثمانون'], - [3766, 'ثلاثة آلاف و سبعمائةستة و ستون'], - [4196, 'أربعة آلاف و مائةستة و تسعون'], //FIXME - [5846, 'خمسة آلاف و ثمانمائة و ستة و أربعون'], - [6459, 'ستة آلاف و أربعمائة و تسعة و خمسون'], - [7232, 'سبعة آلاف و مئتان و اثنان و ثلاثون'], - [8569, 'ثمانية آلاف و خمسمائةتسعة و ستون'], - [9539, 'تسعة آلاف و خمسمائة و تسعة و ثلاثون'], - [1000000, 'واحد مليون'], - [1000001, 'واحد مليون و واحد'], + [434, 'أربعمائة وأربعة وثلاثون'], + [578, 'خمسمائة وثمانية وسبعون'], + [689, 'ستمائة وتسعة وثمانون'], + [729, 'سبعمائة وتسعة وعشرون'], + [810, 'ثمانمائة وعشرة'], + [820, 'ثمانمائة وعشرون'], + [823, 'ثمانمائة وثلاثة وعشرون'], + [833, 'ثمانمائة وثلاثة وثلاثون'], + [863, 'ثمانمائة وثلاثة وستون'], + [883, 'ثمانمائة وثلاثة وثمانون'], + [894, 'ثمانمائة وأربعة وتسعون'], + [999, 'تسعمائة وتسعة وتسعون'], + [1000, 'ألف'], + [2000, 'ألفان'], + [1001, 'ألف وواحد'], + [1097, 'ألف وسبعة وتسعون'], + [1104, 'ألف ومائة وأربعة'], + [1243, 'ألف ومئتان وثلاثة وأربعون'], + [2385, 'ألفان وثلاثمائة وخمسة وثمانون'], + [3766, 'ثلاثة آلاف وسبعمائة وستة وستون'], + [4196, 'أربعة آلاف ومائة وستة وتسعون'], + [5846, 'خمسة آلاف وثمانمائة وستة وأربعون'], + [6459, 'ستة آلاف وأربعمائة وتسعة وخمسون'], + [7232, 'سبعة آلاف ومئتان واثنان وثلاثون'], + [8569, 'ثمانية آلاف وخمسمائة وتسعة وستون'], + [9539, 'تسعة آلاف وخمسمائة وتسعة وثلاثون'], + [200200, 'مئتان ألفاً ومئتان'], + [200000, 'مئتان ألف'], + [300200, 'ثلاثمائة ألفاً ومئتان'], + [1000000, 'مليون'], + [1000001, 'مليون وواحد'], + [2000000, 'مليونان'], [4000000, 'أربعة ملايين'], + [12345678, 'اثنا عشر مليوناً وثلاثمائة وخمسة وأربعون ألفاً وستمائة وثمانية وسبعون'], + [2000000000, 'ملياران'], [10000000000000, 'عشرة تريليونات'], [100000000000000, 'مائة تريليون'], - [1000000000000000000n, 'واحد كوينتليون'], + [1000000000000000000n, 'كوينتليون'], ];