From 1fad7646262361e09285cd575ee5a542b7b93bb3 Mon Sep 17 00:00:00 2001 From: aloisdg Date: Mon, 27 Jun 2016 13:09:45 +0200 Subject: [PATCH] Add Esperanto support to NumberToWords. Fixes #558 --- .../Humanizer.Tests.Shared.projitems | 1 + .../Localisation/eo/NumberToWordTests.cs | 100 ++++++++++++++++++ .../NumberToWordsConverterRegistry.cs | 3 +- src/Humanizer/Humanizer.csproj | 1 + .../EsperantoNumberToWordsConverter.cs | 85 +++++++++++++++ 5 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 src/Humanizer.Tests.Shared/Localisation/eo/NumberToWordTests.cs create mode 100644 src/Humanizer/Localisation/NumberToWords/EsperantoNumberToWordsConverter.cs diff --git a/src/Humanizer.Tests.Shared/Humanizer.Tests.Shared.projitems b/src/Humanizer.Tests.Shared/Humanizer.Tests.Shared.projitems index e317f1043..48b40e429 100644 --- a/src/Humanizer.Tests.Shared/Humanizer.Tests.Shared.projitems +++ b/src/Humanizer.Tests.Shared/Humanizer.Tests.Shared.projitems @@ -53,6 +53,7 @@ + diff --git a/src/Humanizer.Tests.Shared/Localisation/eo/NumberToWordTests.cs b/src/Humanizer.Tests.Shared/Localisation/eo/NumberToWordTests.cs new file mode 100644 index 000000000..81b8abb33 --- /dev/null +++ b/src/Humanizer.Tests.Shared/Localisation/eo/NumberToWordTests.cs @@ -0,0 +1,100 @@ +using System.Globalization; +using Xunit; + +namespace Humanizer.Tests.Localisation.eo +{ + [UseCulture ("eo-Eo")] + public class NumberToWordsTests + { + [Theory] + [InlineData (-42, "minus kvardek du")] + [InlineData (-1, "minus unu")] + [InlineData (0, "nul")] + [InlineData (1, "unu")] + [InlineData (2, "du")] + [InlineData (3, "tri")] + [InlineData (4, "kvar")] + [InlineData (5, "kvin")] + [InlineData (6, "ses")] + [InlineData (7, "sep")] + [InlineData (8, "ok")] + [InlineData (9, "naŭ")] + [InlineData (10, "dek")] + [InlineData (11, "dek unu")] + [InlineData (15, "dek kvin")] + [InlineData (17, "dek sep")] + [InlineData (20, "dudek")] + [InlineData (25, "dudek kvin")] + [InlineData (31, "tridek unu")] + [InlineData (71, "sepdek unu")] + [InlineData (122, "cent dudek du")] + [InlineData (256, "ducent kvindek ses")] + [InlineData (3501, "trimil kvincent unu")] + [InlineData (100, "cent")] + [InlineData (1000, "mil")] + [InlineData (10000, "dek mil")] + [InlineData (100000, "cent mil")] + [InlineData (1000000, "miliono")] + [InlineData (10000000, "dek miliono")] + [InlineData (100000000, "cent miliono")] + [InlineData (1000000000, "miliardo")] + [InlineData (110, "cent dek")] + [InlineData (1100, "mil cent")] + [InlineData (11000, "dek unu mil")] + [InlineData (111, "cent dek unu")] + [InlineData (1111, "mil cent dek unu")] + [InlineData (111111, "cent dek unu mil cent dek unu")] + [InlineData (1111111, "miliono cent dek unu mil cent dek unu")] + [InlineData (11111111, "dek unu miliono cent dek unu mil cent dek unu")] + [InlineData (111111111, "cent dek unu miliono cent dek unu mil cent dek unu")] + [InlineData (1111111111, "miliardo cent dek unu miliono cent dek unu mil cent dek unu")] + [InlineData (123, "cent dudek tri")] + [InlineData (1234, "mil ducent tridek kvar")] + [InlineData (12345, "dek dumil tricent kvardek kvin")] + [InlineData (123456, "cent dudek trimil kvarcent kvindek ses")] + [InlineData (1234567, "miliono ducent tridek kvarmil kvincent sesdek sep")] + [InlineData (12345678, "dek du miliono tricent kvardek kvinmil sescent sepdek ok")] + [InlineData (123456789, "cent dudek tri miliono kvarcent kvindek sesmil sepcent okdek naŭ")] + [InlineData (1234567890, "miliardo ducent tridek kvar miliono kvincent sesdek sepmil okcent naŭdek")] + [InlineData (1234567899, "miliardo ducent tridek kvar miliono kvincent sesdek sepmil okcent naŭdek naŭ")] + [InlineData (223, "ducent dudek tri")] + [InlineData (1999, "mil naŭcent naŭdek naŭ")] + [InlineData (2014, "dumil dek kvar")] + [InlineData (2048, "dumil kvardek ok")] + [InlineData (31786, "tridek unu mil sepcent okdek ses")] + [InlineData (30786, "tridek mil sepcent okdek ses")] + public void ToWords(int number, string words) + { + Assert.Equal (words, number.ToWords(new CultureInfo("eo"))); + } + + [Theory] + [InlineData (0, "nula")] + [InlineData (1, "unua")] + [InlineData (2, "dua")] + [InlineData (3, "tria")] + [InlineData (4, "kvara")] + [InlineData (5, "kvina")] + [InlineData (6, "sesa")] + [InlineData (7, "sepa")] + [InlineData (8, "oka")] + [InlineData (9, "naŭa")] + [InlineData (10, "deka")] + [InlineData (100, "centa")] + [InlineData (120, "cent dudeka")] + [InlineData (121, "cent dudek unua")] + [InlineData (1000, "mila")] + [InlineData (1001, "mil unua")] + [InlineData (1021, "mil dudek unua")] + [InlineData (3000, "trimila")] + [InlineData (10000, "dek mila")] + [InlineData (10121, "dek mil cent dudek unua")] + [InlineData (100000, "cent mila")] + [InlineData (1000000, "milionoa")] + [InlineData (1000000000, "miliardoa")] + public void ToOrdinalWords(int number, string words) + { + Assert.Equal (words, number.ToOrdinalWords()); + } + } +} \ No newline at end of file diff --git a/src/Humanizer/Configuration/NumberToWordsConverterRegistry.cs b/src/Humanizer/Configuration/NumberToWordsConverterRegistry.cs index cd8aa262e..989467991 100644 --- a/src/Humanizer/Configuration/NumberToWordsConverterRegistry.cs +++ b/src/Humanizer/Configuration/NumberToWordsConverterRegistry.cs @@ -11,7 +11,8 @@ public NumberToWordsConverterRegistry() Register("en", new EnglishNumberToWordsConverter()); Register("ar", new ArabicNumberToWordsConverter()); Register("fa", new FarsiNumberToWordsConverter()); - Register("es", new SpanishNumberToWordsConverter()); + Register("eo", new EsperantoNumberToWordsConverter()); + Register("es", new SpanishNumberToWordsConverter ()); Register("pl", (culture) => new PolishNumberToWordsConverter(culture)); Register("pt-BR", new BrazilianPortugueseNumberToWordsConverter()); Register("ro", new RomanianNumberToWordsConverter()); diff --git a/src/Humanizer/Humanizer.csproj b/src/Humanizer/Humanizer.csproj index 0e260c3b4..e4bbb5511 100644 --- a/src/Humanizer/Humanizer.csproj +++ b/src/Humanizer/Humanizer.csproj @@ -80,6 +80,7 @@ + diff --git a/src/Humanizer/Localisation/NumberToWords/EsperantoNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/EsperantoNumberToWordsConverter.cs new file mode 100644 index 000000000..3cd75ad47 --- /dev/null +++ b/src/Humanizer/Localisation/NumberToWords/EsperantoNumberToWordsConverter.cs @@ -0,0 +1,85 @@ +// Wrote by Alois de Gouvello https://github.com/aloisdg + +// The MIT License (MIT) + +// Copyright (c) 2015 Alois de Gouvello + +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Humanizer.Localisation.NumberToWords +{ + internal class EsperantoNumberToWordsConverter : GenderlessNumberToWordsConverter + { + private static readonly string[] UnitsMap = + { + "nul", "unu", "du", "tri", "kvar", "kvin", "ses", "sep", "ok", "naŭ" + }; + + private static readonly Dictionary TensMap = new Dictionary + { + { 1000000000, " miliardo" }, { 1000000 , " miliono" }, { 1000, " mil" }, { 100, "cent" }, { 10, "dek" }, { 1, null } + }; + + private const string Minus = "minus"; + + public override string ConvertToOrdinal(int number) + { + return Convert(number) + "a"; + } + + public override string Convert(int number) + { + var words = number < 0 ? Minus + " " : string.Empty; + number = Math.Abs (number); + words += number <= 1 ? UnitsMap[number] : ConvertInside(number); + return words; + } + + private static string ConvertInside(int number) + { + if (number == 1) + return string.Empty; + + var parts = new List (); + foreach (var item in TensMap.Where(x => number / x.Key > 0)) + { + parts.Add(!string.IsNullOrEmpty(item.Value) + ? $"{ConvertInside (number / item.Key)}{TrimMil (item, number)}" + : UnitsMap[number]); + number %= item.Key; + } + + var toWords = string.Join(" ", parts.ToArray ()).TrimStart(' '); + return toWords; + } + + private static string TrimMil(KeyValuePair item, int number) + { + if (item.Key != 1000) + return item.Value; + var quotient = number / item.Key % 10; + return quotient < 2 || quotient > 9 + ? item.Value + : item.Value.TrimStart(' '); + } + } +}