Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding code & tests to handle Arabic numbers to ordinal words #232

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
1 change: 1 addition & 0 deletions src/Humanizer.Tests/Localisation/ar/DateHumanizeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ public void SecondsAgo(int seconds, string expected)
}

[Theory]
[InlineData(0, "الآن")]
[InlineData(1, "في غضون ثانية واحدة من الآن")]
[InlineData(2, "في غضون ثانيتين من الآن")]
[InlineData(10, "في غضون 10 ثوان من الآن")]
Expand Down
54 changes: 54 additions & 0 deletions src/Humanizer.Tests/Localisation/ar/NumberToWordsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;

namespace Humanizer.Localisation.NumberToWords
{
Expand Down Expand Up @@ -111,5 +113,90 @@ public override string Convert(int number)

return result.Trim();
}

private static readonly Dictionary<string, string> OrdinalExceptions = new Dictionary<string, string>
{
{"واحد", "الحادي"},
{"أحد", "الحادي"},
{"اثنان", "الثاني"},
{"اثنا", "الثاني"},
{"ثلاثة", "الثالث"},
{"أربعة", "الرابع"},
{"خمسة", "الخامس"},
{"ستة", "السادس"},
{"سبعة", "السابع"},
{"ثمانية", "الثامن"},
{"تسعة", "التاسع"},
{"عشرة", "العاشر"},
};

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 + " "));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please change it to string.Join?

word = word.Trim();
}
else
{
word = "ال"+word;
}

return word;
}
}
}
6 changes: 5 additions & 1 deletion src/Humanizer/Properties/Resources.ar.resx
Original file line number Diff line number Diff line change
Expand Up @@ -397,4 +397,8 @@
<data name="DateHumanize_SingleYearFromNow" xml:space="preserve">
<value>في غضون سنة واحدة من الآن</value>
</data>
</root>
<data name="DateHumanize_Now" xml:space="preserve">
<value>الآن</value>
<comment>now</comment>
</data>
</root>