diff --git a/src/Humanizer.Tests/Localisation/ar/NumberToWordsTests.cs b/src/Humanizer.Tests/Localisation/ar/NumberToWordsTests.cs new file mode 100644 index 000000000..33e82ae3e --- /dev/null +++ b/src/Humanizer.Tests/Localisation/ar/NumberToWordsTests.cs @@ -0,0 +1,23 @@ +using Xunit; +using Xunit.Extensions; + +namespace Humanizer.Tests.Localisation.ar +{ + public class NumberToWordsTests : AmbientCulture + { + public NumberToWordsTests() : base("ar") { } + + [Theory] + [InlineData("صفر", 0)] + [InlineData("واحد", 1)] + [InlineData("اثنان", 2)] + [InlineData("اثنان و عشرون", 22)] + [InlineData("أحد عشر", 11)] + [InlineData("ثلاثة آلاف و خمس مئة و واحد", 3501)] + [InlineData("مليون و واحد", 1000001)] + public void ToWordsArabic(string expected, int number) + { + Assert.Equal(expected, number.ToWords()); + } + } +} diff --git a/src/Humanizer/NumberToWordsExtension.cs b/src/Humanizer/NumberToWordsExtension.cs index 6464350e9..62ccf9f5b 100644 --- a/src/Humanizer/NumberToWordsExtension.cs +++ b/src/Humanizer/NumberToWordsExtension.cs @@ -1,17 +1,33 @@ using System; using System.Collections.Generic; +using System.Globalization; namespace Humanizer { + /// + /// Transform a number into words; e.g. 1 => one + /// public static class NumberToWordsExtension { - // http://stackoverflow.com/questions/2729752/converting-numbers-in-to-words-c-sharp /// /// 3501.ToWords() -> "three thousand five hundred and one" /// /// Number to be turned to words /// public static string ToWords(this int number) + { + switch (CultureInfo.CurrentUICulture.TwoLetterISOLanguageName) + { + case "ar": + return ToArabicWords(number); + case "en": + return ToEnglishWords(number); + default: + throw new Exception(); + } + } + + private static string ToEnglishWords(int number) { if (number == 0) return "zero"; @@ -60,5 +76,113 @@ public static string ToWords(this int number) return string.Join(" ", parts.ToArray()); } + + private static string ToArabicWords(int number) + { + string[] arabicGroup = { "مئة", "ألف", "مليون", "مليار", "تريليون", "كوادريليون", "كوينتليون", "سكستيليون" }; + string[] arabicAppendedGroup = { "", "ألفاً", "مليوناً", "ملياراً", "تريليوناً", "كوادريليوناً", "كوينتليوناً", "سكستيليوناً" }; + string[] arabicPluralGroups = { "", "آلاف", "ملايين", "مليارات", "تريليونات", "كوادريليونات", "كوينتليونات", "سكستيليونات" }; + string[] onesGroup = { "", "واحد", "اثنان", "ثلاثة", "أربعة", "خمسة", "ستة", "سبعة", "ثمانية", "تسعة", "عشرة", "أحد عشر", "اثنا عشر", "ثلاثة عشر", "أربعة عشر", "خمسة عشر", "ستة عشر", "سبعة عشر", "ثمانية عشر", "تسعة عشر" }; + string[] tensGroup = { "", "عشرة", "عشرون", "ثلاثون", "أربعون", "خمسون", "ستون", "سبعون", "ثمانون", "تسعون" }; + string[] hundredsGroup = { "", "مئة", "مئتان", "ثلاث مئة", "أربع مئة", "خمس مئة", "ست مئة", "سبع مئة", "ثمان مئة", "تسع مئة" }; + string[] arabicAppendedTwos = { "مئتان", "ألفان", "مليونان", "ملياران", "تريليونان", "كوادريليونان", "كوينتليونان", "سكستيليونلن" }; + string[] arabicTwos = { "مئتان", "ألفان", "مليونان", "ملياران", "تريليونان", "كوادريليونان", "كوينتليونان", "سكستيليونان" }; + + if (number == 0) + return "صفر"; + + string result = String.Empty; + int groupLevel = 0; + + while (number >= 1) + { + int groupNumber = number % 1000; + number /= 1000; + + int tens = groupNumber % 100; + int hundreds = groupNumber / 100; + string process = String.Empty; + + if (hundreds > 0) + { + if (tens == 0 && hundreds == 2) + process = arabicAppendedTwos[0]; + else + process = hundredsGroup[hundreds]; + } + + if (tens > 0) + { + if (tens < 20) + { + if (tens == 2 && hundreds == 0 && groupLevel > 0) + { + if (number == 2000 || number == 2000000 || number == 2000000000) + process = arabicAppendedTwos[groupLevel]; + else + process = arabicTwos[groupLevel]; + } + else + { + if (process != String.Empty) + process += " و "; + + if (tens == 1 && groupLevel > 0 && hundreds == 0) + process += " "; + else + process += onesGroup[tens]; + } + } + else + { + int ones = tens % 10; + tens = (tens / 10); + + if (ones > 0) + { + if (process != String.Empty) + process += " و "; + + process += onesGroup[ones]; + } + + if (process != String.Empty) + process += " و "; + + process += tensGroup[tens]; + } + } + + if (process != String.Empty) + { + if (groupLevel > 0) + { + if (result != String.Empty) + result = String.Format("{0} {1}", "و", result); + + if (groupNumber != 2) + { + if (groupNumber % 100 != 1) + { + if (groupNumber >= 3 && groupNumber <= 10) + result = String.Format("{0} {1}", arabicPluralGroups[groupLevel], result); + else + { + result = String.Format("{0} {1}", result != String.Empty ? arabicAppendedGroup[groupLevel] : arabicGroup[groupLevel], result); + } + } + else + { + result = String.Format("{0} {1}", arabicGroup[groupLevel], result); + } + } + } + result = String.Format("{0} {1}", process, result); + } + groupLevel++; + } + + return result.Trim(); + } } }