Skip to content

Commit

Permalink
Add support for large numbers in French up to 10^18 level
Browse files Browse the repository at this point in the history
Note that French uses the "long scale" rather than the "short scale" for large numbers.
  • Loading branch information
louis-z committed May 1, 2021
1 parent 1285835 commit 490fbcc
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 25 deletions.
29 changes: 27 additions & 2 deletions src/Humanizer.Tests.Shared/Localisation/fr/NumberToWordsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public class NumberToWordsTests
[InlineData(80080080, "quatre-vingts millions quatre-vingt mille quatre-vingts")]
[InlineData(200200200, "deux cents millions deux cent mille deux cents")]
[InlineData(200200202, "deux cents millions deux cent mille deux cent deux")]
public void ToWords(int number, string expected)
public void ToWordsInt(int number, string expected)
{
Assert.Equal(expected, number.ToWords());
}
Expand Down Expand Up @@ -98,11 +98,36 @@ public void ToWords(int number, string expected)
[InlineData(10121, "dix mille cent vingt et un", GrammaticalGender.Masculine)]
[InlineData(81000, "quatre-vingt-un mille", GrammaticalGender.Feminine)]
[InlineData(81000, "quatre-vingt-un mille", GrammaticalGender.Masculine)]
public void ToWordsWithGender(int number, string expected, GrammaticalGender gender)
public void ToWordsIntWithGender(int number, string expected, GrammaticalGender gender)
{
Assert.Equal(expected, number.ToWords(gender));
}

[Theory]
[InlineData(1L, "un")]
[InlineData(11L, "onze")]
[InlineData(111L, "cent onze")]
[InlineData(1111L, "mille cent onze")]
[InlineData(11111L, "onze mille cent onze")]
[InlineData(111111L, "cent onze mille cent onze")]
[InlineData(1111111L, "un million cent onze mille cent onze")]
[InlineData(11111111L, "onze millions cent onze mille cent onze")]
[InlineData(111111111L, "cent onze millions cent onze mille cent onze")]
[InlineData(1111111111L, "un milliard cent onze millions cent onze mille cent onze")]
[InlineData(11111111111L, "onze milliards cent onze millions cent onze mille cent onze")]
[InlineData(111111111111L, "cent onze milliards cent onze millions cent onze mille cent onze")]
[InlineData(1111111111111L, "un billion cent onze milliards cent onze millions cent onze mille cent onze")]
[InlineData(11111111111111L, "onze billions cent onze milliards cent onze millions cent onze mille cent onze")]
[InlineData(111111111111111L, "cent onze billions cent onze milliards cent onze millions cent onze mille cent onze")]
[InlineData(1111111111111111L, "un billiard cent onze billions cent onze milliards cent onze millions cent onze mille cent onze")]
[InlineData(11111111111111111L, "onze billiards cent onze billions cent onze milliards cent onze millions cent onze mille cent onze")]
[InlineData(111111111111111111L, "cent onze billiards cent onze billions cent onze milliards cent onze millions cent onze mille cent onze")]
[InlineData(1111111111111111111L, "un trillion cent onze billiards cent onze billions cent onze milliards cent onze millions cent onze mille cent onze")]
public void ToWordsLong(long number, string expected)
{
Assert.Equal(expected, number.ToWords());
}

[Theory]
[InlineData(0, "zérotième")]
[InlineData(1, "premier")]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using Humanizer.Localisation;

using Xunit;

namespace Humanizer.Tests.Localisation.fr
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace Humanizer.Localisation.NumberToWords
{
internal class FrenchBelgianNumberToWordsConverter : FrenchNumberToWordsConverterBase
{
protected override void CollectPartsUnderAHundred(ICollection<string> parts, ref int number, GrammaticalGender gender, bool pluralize)
protected override void CollectPartsUnderAHundred(ICollection<string> parts, ref long number, GrammaticalGender gender, bool pluralize)
{
if (number == 80)
{
Expand All @@ -20,7 +20,7 @@ protected override void CollectPartsUnderAHundred(ICollection<string> parts, ref
}
}

protected override string GetTens(int tens)
protected override string GetTens(long tens)
{
if (tens == 8)
{
Expand All @@ -30,4 +30,4 @@ protected override string GetTens(int tens)
return base.GetTens(tens);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace Humanizer.Localisation.NumberToWords
{
internal class FrenchNumberToWordsConverter : FrenchNumberToWordsConverterBase
{
protected override void CollectPartsUnderAHundred(ICollection<string> parts, ref int number, GrammaticalGender gender, bool pluralize)
protected override void CollectPartsUnderAHundred(ICollection<string> parts, ref long number, GrammaticalGender gender, bool pluralize)
{
if (number == 71)
{
Expand All @@ -27,7 +27,7 @@ protected override void CollectPartsUnderAHundred(ICollection<string> parts, ref
}
}

protected override string GetTens(int tens)
protected override string GetTens(long tens)
{
if (tens == 8)
{
Expand All @@ -37,4 +37,4 @@ protected override string GetTens(int tens)
return base.GetTens(tens);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;

namespace Humanizer.Localisation.NumberToWords
{
Expand All @@ -8,14 +7,8 @@ internal abstract class FrenchNumberToWordsConverterBase : GenderedNumberToWords
private static readonly string[] UnitsMap = { "zéro", "un", "deux", "trois", "quatre", "cinq", "six", "sept", "huit", "neuf", "dix", "onze", "douze", "treize", "quatorze", "quinze", "seize", "dix-sept", "dix-huit", "dix-neuf" };
private static readonly string[] TensMap = { "zéro", "dix", "vingt", "trente", "quarante", "cinquante", "soixante", "septante", "octante", "nonante" };

public override string Convert(long input, GrammaticalGender gender, bool addAnd = true)
public override string Convert(long number, GrammaticalGender gender, bool addAnd = true)
{
if (input > Int32.MaxValue || input < Int32.MinValue)
{
throw new NotImplementedException();
}
var number = (int)input;

if (number == 0)
{
return UnitsMap[0];
Expand All @@ -29,6 +22,9 @@ public override string Convert(long input, GrammaticalGender gender, bool addAnd
number = -number;
}

CollectParts(parts, ref number, 1000000000000000000, "trillion");
CollectParts(parts, ref number, 1000000000000000, "billiard");
CollectParts(parts, ref number, 1000000000000, "billion");
CollectParts(parts, ref number, 1000000000, "milliard");
CollectParts(parts, ref number, 1000000, "million");
CollectThousands(parts, ref number, 1000, "mille");
Expand Down Expand Up @@ -75,7 +71,7 @@ public override string ConvertToOrdinal(int number, GrammaticalGender gender)
return convertedNumber;
}

protected static string GetUnits(int number, GrammaticalGender gender)
protected static string GetUnits(long number, GrammaticalGender gender)
{
if (number == 1 && gender == GrammaticalGender.Feminine)
{
Expand All @@ -85,7 +81,7 @@ protected static string GetUnits(int number, GrammaticalGender gender)
return UnitsMap[number];
}

private static void CollectHundreds(ICollection<string> parts, ref int number, int d, string form, bool pluralize)
private static void CollectHundreds(ICollection<string> parts, ref long number, long d, string form, bool pluralize)
{
if (number < d)
{
Expand Down Expand Up @@ -113,7 +109,7 @@ private static void CollectHundreds(ICollection<string> parts, ref int number, i
number %= d;
}

private void CollectParts(ICollection<string> parts, ref int number, int d, string form)
private void CollectParts(ICollection<string> parts, ref long number, long d, string form)
{
if (number < d)
{
Expand All @@ -136,7 +132,7 @@ private void CollectParts(ICollection<string> parts, ref int number, int d, stri
number %= d;
}

private void CollectPartsUnderAThousand(ICollection<string> parts, int number, GrammaticalGender gender, bool pluralize)
private void CollectPartsUnderAThousand(ICollection<string> parts, long number, GrammaticalGender gender, bool pluralize)
{
CollectHundreds(parts, ref number, 100, "cent", pluralize);

Expand All @@ -146,7 +142,7 @@ private void CollectPartsUnderAThousand(ICollection<string> parts, int number, G
}
}

private void CollectThousands(ICollection<string> parts, ref int number, int d, string form)
private void CollectThousands(ICollection<string> parts, ref long number, int d, string form)
{
if (number < d)
{
Expand All @@ -164,7 +160,7 @@ private void CollectThousands(ICollection<string> parts, ref int number, int d,
number %= d;
}

protected virtual void CollectPartsUnderAHundred(ICollection<string> parts, ref int number, GrammaticalGender gender, bool pluralize)
protected virtual void CollectPartsUnderAHundred(ICollection<string> parts, ref long number, GrammaticalGender gender, bool pluralize)
{
if (number < 20)
{
Expand All @@ -191,7 +187,7 @@ protected virtual void CollectPartsUnderAHundred(ICollection<string> parts, ref
}
}

protected virtual string GetTens(int tens)
protected virtual string GetTens(long tens)
{
return TensMap[tens];
}
Expand Down

0 comments on commit 490fbcc

Please sign in to comment.