From bbba4673e0bc5c7d407ee0bc4467f54e932170ef Mon Sep 17 00:00:00 2001 From: Ali Hmer Date: Fri, 18 Apr 2014 19:02:27 -0600 Subject: [PATCH 1/4] Adding code & tests to handle Arabic numbers to ordinal words --- .../Localisation/ar/NumberToWordsTests.cs | 54 ++++++++++++ .../ArabicNumberToWordsConverter.cs | 87 +++++++++++++++++++ 2 files changed, 141 insertions(+) diff --git a/src/Humanizer.Tests/Localisation/ar/NumberToWordsTests.cs b/src/Humanizer.Tests/Localisation/ar/NumberToWordsTests.cs index 33e82ae3e..d318ecf2b 100644 --- a/src/Humanizer.Tests/Localisation/ar/NumberToWordsTests.cs +++ b/src/Humanizer.Tests/Localisation/ar/NumberToWordsTests.cs @@ -19,5 +19,59 @@ public void ToWordsArabic(string expected, int number) { Assert.Equal(expected, number.ToWords()); } + + [Theory] + [InlineData(0, "الصفر")] + [InlineData(1, "الأول")] + [InlineData(2, "الثاني")] + [InlineData(3, "الثالث")] + [InlineData(4, "الرابع")] + [InlineData(5, "الخامس")] + [InlineData(6, "السادس")] + [InlineData(7, "السابع")] + [InlineData(8, "الثامن")] + [InlineData(9, "التاسع")] + [InlineData(10, "العاشر")] + [InlineData(11, "الحادي عشر")] + [InlineData(12, "الثاني عشر")] + [InlineData(13, "الثالث عشر")] + [InlineData(14, "الرابع عشر")] + [InlineData(15, "الخامس عشر")] + [InlineData(16, "السادس عشر")] + [InlineData(17, "السابع عشر")] + [InlineData(18, "الثامن عشر")] + [InlineData(19, "التاسع عشر")] + [InlineData(20, "العشرون")] + [InlineData(21, "الحادي و العشرون")] + [InlineData(22, "الثاني و العشرون")] + [InlineData(30, "الثلاثون")] + [InlineData(40, "الأربعون")] + [InlineData(50, "الخمسون")] + [InlineData(60, "الستون")] + [InlineData(70, "السبعون")] + [InlineData(80, "الثمانون")] + [InlineData(90, "التسعون")] + [InlineData(95, "الخامس و التسعون")] + [InlineData(96, "السادس و التسعون")] + [InlineData(100, "المئة")] + [InlineData(120, "العشرون بعد المئة")] + [InlineData(121, "الحادي و العشرون بعد المئة")] + [InlineData(200, "المئتان")] + [InlineData(221, "الحادي و العشرون بعد المئتان")] + [InlineData(300, "الثلاث مئة")] + [InlineData(321, "الحادي و العشرون بعد الثلاث مئة")] + [InlineData(327, "السابع و العشرون بعد الثلاث مئة")] + [InlineData(1000, "الألف")] + [InlineData(1001, "الأول بعد الألف")] + [InlineData(1021, "الحادي و العشرون بعد الألف")] + [InlineData(10000, "العشرة آلاف")] + [InlineData(10121, "الحادي و العشرون بعد العشرة آلاف و مئة")] + [InlineData(100000, "المئة ألف")] + [InlineData(1000000, "المليون")] + [InlineData(1020135, "الخامس و الثلاثون بعد المليون و عشرون ألفاً و مئة")] + public void ToOrdinalWords(int number, string words) + { + Assert.Equal(words, number.ToOrdinalWords()); + } } } diff --git a/src/Humanizer/Localisation/NumberToWords/ArabicNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/ArabicNumberToWordsConverter.cs index a4104c69b..7a717e4bc 100644 --- a/src/Humanizer/Localisation/NumberToWords/ArabicNumberToWordsConverter.cs +++ b/src/Humanizer/Localisation/NumberToWords/ArabicNumberToWordsConverter.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; namespace Humanizer.Localisation.NumberToWords { @@ -111,5 +113,90 @@ public override string Convert(int number) return result.Trim(); } + + private static readonly Dictionary OrdinalExceptions = new Dictionary + { + {"واحد", "الحادي"}, + {"أحد", "الحادي"}, + {"اثنان", "الثاني"}, + {"اثنا", "الثاني"}, + {"ثلاثة", "الثالث"}, + {"أربعة", "الرابع"}, + {"خمسة", "الخامس"}, + {"ستة", "السادس"}, + {"سبعة", "السابع"}, + {"ثمانية", "الثامن"}, + {"تسعة", "التاسع"}, + {"عشرة", "العاشر"}, + }; + + public override string ConvertToOrdinal(int number) + { + if (number == 0) return "الصفر"; + var beforeOneHundredNumber = number%100; + var overTensPart = number/100*100; + var beforeOneHundredWord = string.Empty; + var overTensWord = string.Empty; + + if (beforeOneHundredNumber > 0) + { + beforeOneHundredWord = Convert(beforeOneHundredNumber); + beforeOneHundredWord = ParseNumber(beforeOneHundredWord, beforeOneHundredNumber); + } + + if (overTensPart > 0) + { + overTensWord = Convert(overTensPart); + overTensWord = ParseNumber(overTensWord, overTensPart); + } + + var word = + beforeOneHundredWord + (overTensPart > 0 + ? (string.IsNullOrWhiteSpace(beforeOneHundredWord) ? string.Empty : " بعد ") + overTensWord + : string.Empty + ); + return word.Trim(); + } + + private static string ParseNumber(string word, int number) + { + if (number == 1) return "الأول"; + + if (number <= 10) + { + foreach (var kv in OrdinalExceptions.Where(kv => word.EndsWith(kv.Key))) + { + // replace word with exception + return word.Substring(0, word.Length - kv.Key.Length) + kv.Value; + } + } + else if (number > 10 && number < 100) + { + var parts = word.Split(' '); + var newParts = new string[parts.Length]; + int count = 0; + foreach (var part in parts) + { + var newPart = part; + var oldPart = part; + foreach (var kv in OrdinalExceptions.Where(kv => oldPart.EndsWith(kv.Key))) + { + // replace word with exception + newPart = oldPart.Substring(0, oldPart.Length - kv.Key.Length) + kv.Value; + } + if (number > 19 && newPart == oldPart && oldPart.Length > 1) + newPart = "ال" + oldPart; + newParts[count++] = newPart; + } + word = newParts.Aggregate(string.Empty, (current, newPart) => current + (newPart + " ")); + word = word.Trim(); + } + else + { + word = "ال"+word; + } + + return word; + } } } \ No newline at end of file From 79d0710b0feb453b5b52d3b1edaa3f407b7b1d8f Mon Sep 17 00:00:00 2001 From: Ali Hmer Date: Fri, 18 Apr 2014 19:11:28 -0600 Subject: [PATCH 2/4] Update release_notes.md --- release_notes.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/release_notes.md b/release_notes.md index 44f8f340c..6bdf0cd55 100644 --- a/release_notes.md +++ b/release_notes.md @@ -4,6 +4,8 @@ - [#221](https://github.com/Mehdik/Humanizer/pull/221): Added Russian ordinalizer - [#228](https://github.com/Mehdik/Humanizer/pull/228): Fixed the "twenties" in SpanishNumberToWordsConverter - [#231](https://github.com/Mehdik/Humanizer/pull/231): Added more settings for FromNow, Dual and Plural (Arabic) + - [#232](https://github.com/Mehdik/Humanizer/pull/232): Adding code & tests to handle Arabic numbers to ordinal + [Commits](https://github.com/MehdiK/Humanizer/compare/v1.22.1...master) From f27e1b60894a1eca7532ea7c5db913fe2230b9c7 Mon Sep 17 00:00:00 2001 From: Ali Hmer Date: Fri, 18 Apr 2014 20:05:37 -0600 Subject: [PATCH 3/4] Adding missing setting for DateHumanize_Now (Arabic) --- src/Humanizer.Tests/Localisation/ar/DateHumanizeTests.cs | 1 + src/Humanizer/Properties/Resources.ar.resx | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Humanizer.Tests/Localisation/ar/DateHumanizeTests.cs b/src/Humanizer.Tests/Localisation/ar/DateHumanizeTests.cs index dcacec886..51ba125be 100644 --- a/src/Humanizer.Tests/Localisation/ar/DateHumanizeTests.cs +++ b/src/Humanizer.Tests/Localisation/ar/DateHumanizeTests.cs @@ -98,6 +98,7 @@ public void SecondsAgo(int seconds, string expected) } [Theory] + [InlineData(0, "الآن")] [InlineData(1, "في غضون ثانية واحدة من الآن")] [InlineData(2, "في غضون ثانيتين من الآن")] [InlineData(10, "في غضون 10 ثوان من الآن")] diff --git a/src/Humanizer/Properties/Resources.ar.resx b/src/Humanizer/Properties/Resources.ar.resx index b20210703..f70c4b314 100644 --- a/src/Humanizer/Properties/Resources.ar.resx +++ b/src/Humanizer/Properties/Resources.ar.resx @@ -397,4 +397,8 @@ في غضون سنة واحدة من الآن - + + الآن + now + + \ No newline at end of file From 1b49f7bdafd0937a318d4a62099737b82d7de2ac Mon Sep 17 00:00:00 2001 From: Ali Hmer Date: Sat, 19 Apr 2014 06:42:39 -0600 Subject: [PATCH 4/4] Changing Aggregate code to String.Join --- .../Localisation/NumberToWords/ArabicNumberToWordsConverter.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Humanizer/Localisation/NumberToWords/ArabicNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/ArabicNumberToWordsConverter.cs index 7a717e4bc..651e25a7b 100644 --- a/src/Humanizer/Localisation/NumberToWords/ArabicNumberToWordsConverter.cs +++ b/src/Humanizer/Localisation/NumberToWords/ArabicNumberToWordsConverter.cs @@ -188,8 +188,7 @@ private static string ParseNumber(string word, int number) newPart = "ال" + oldPart; newParts[count++] = newPart; } - word = newParts.Aggregate(string.Empty, (current, newPart) => current + (newPart + " ")); - word = word.Trim(); + word = string.Join(" ", newParts); } else {