From 10f44c977fd1df465a4c13e18f00dada980b4d16 Mon Sep 17 00:00:00 2001 From: Daniel Serrano Date: Fri, 31 Dec 2021 16:28:30 +0100 Subject: [PATCH 01/33] Add custom date converters for spanish --- .../es/DateToOrdinalWordsTests.cs | 30 +++++++++++++++++++ ...DateOnlyToOrdinalWordsConverterRegistry.cs | 1 + .../DateToOrdinalWordsConverterRegistry.cs | 1 + .../EsDateOnlyToOrdinalWordsConverter.cs | 16 ++++++++++ .../EsDateToOrdinalWordsConverter.cs | 12 ++++++++ 5 files changed, 60 insertions(+) create mode 100644 src/Humanizer.Tests/Localisation/es/DateToOrdinalWordsTests.cs create mode 100644 src/Humanizer/Localisation/DateToOrdinalWords/EsDateOnlyToOrdinalWordsConverter.cs create mode 100644 src/Humanizer/Localisation/DateToOrdinalWords/EsDateToOrdinalWordsConverter.cs diff --git a/src/Humanizer.Tests/Localisation/es/DateToOrdinalWordsTests.cs b/src/Humanizer.Tests/Localisation/es/DateToOrdinalWordsTests.cs new file mode 100644 index 000000000..41c5c6e10 --- /dev/null +++ b/src/Humanizer.Tests/Localisation/es/DateToOrdinalWordsTests.cs @@ -0,0 +1,30 @@ +using System; + +using Xunit; + +namespace Humanizer.Tests.Localisation.es +{ + [UseCulture("es-ES")] + public class DateToOrdinalWordsTests + { + [Fact] + public void OrdinalizeString() + { + Assert.Equal("25 de enero de 2022", new DateTime(2022, 1, 25).ToOrdinalWords()); + Assert.Equal("29 de febrero de 2020", new DateTime(2020, 2, 29).ToOrdinalWords()); + Assert.Equal("4 de septiembre de 2015", new DateTime(2015, 9, 4).ToOrdinalWords()); + Assert.Equal("7 de noviembre de 1979", new DateTime(1979, 11, 7).ToOrdinalWords()); + } + +#if NET6_0_OR_GREATER + [Fact] + public void OrdinalizeDateOnlyString() + { + Assert.Equal("25 de enero de 2022", new DateOnly(2022, 1, 25).ToOrdinalWords()); + Assert.Equal("29 de febrero de 2020", new DateOnly(2020, 2, 29).ToOrdinalWords()); + Assert.Equal("4 de septiembre de 2015", new DateOnly(2015, 9, 4).ToOrdinalWords()); + Assert.Equal("7 de noviembre de 1979", new DateOnly(1979, 11, 7).ToOrdinalWords()); + } +#endif + } +} diff --git a/src/Humanizer/Configuration/DateOnlyToOrdinalWordsConverterRegistry.cs b/src/Humanizer/Configuration/DateOnlyToOrdinalWordsConverterRegistry.cs index 73c7c8238..b59e7cc0f 100644 --- a/src/Humanizer/Configuration/DateOnlyToOrdinalWordsConverterRegistry.cs +++ b/src/Humanizer/Configuration/DateOnlyToOrdinalWordsConverterRegistry.cs @@ -9,6 +9,7 @@ public DateOnlyToOrdinalWordsConverterRegistry() : base(new DefaultDateOnlyToOrd { Register("en-US", new UsDateOnlyToOrdinalWordsConverter()); Register("fr", new FrDateOnlyToOrdinalWordsConverter()); + Register("es", new EsDateOnlyToOrdinalWordsConverter()); } } } diff --git a/src/Humanizer/Configuration/DateToOrdinalWordsConverterRegistry.cs b/src/Humanizer/Configuration/DateToOrdinalWordsConverterRegistry.cs index 2908c06c4..083dd9a3a 100644 --- a/src/Humanizer/Configuration/DateToOrdinalWordsConverterRegistry.cs +++ b/src/Humanizer/Configuration/DateToOrdinalWordsConverterRegistry.cs @@ -8,6 +8,7 @@ public DateToOrdinalWordsConverterRegistry() : base(new DefaultDateToOrdinalWord { Register("en-US", new UsDateToOrdinalWordsConverter()); Register("fr", new FrDateToOrdinalWordsConverter()); + Register("es", new EsDateToOrdinalWordsConverter()); } } } diff --git a/src/Humanizer/Localisation/DateToOrdinalWords/EsDateOnlyToOrdinalWordsConverter.cs b/src/Humanizer/Localisation/DateToOrdinalWords/EsDateOnlyToOrdinalWordsConverter.cs new file mode 100644 index 000000000..af1169ba5 --- /dev/null +++ b/src/Humanizer/Localisation/DateToOrdinalWords/EsDateOnlyToOrdinalWordsConverter.cs @@ -0,0 +1,16 @@ +#if NET6_0_OR_GREATER + +using System; + +namespace Humanizer.Localisation.DateToOrdinalWords +{ + internal class EsDateOnlyToOrdinalWordsConverter : DefaultDateOnlyToOrdinalWordConverter + { + public override string Convert(DateOnly date) + { + return date.ToString("d 'de' MMMM 'de' yyyy"); + } + } +} + +#endif diff --git a/src/Humanizer/Localisation/DateToOrdinalWords/EsDateToOrdinalWordsConverter.cs b/src/Humanizer/Localisation/DateToOrdinalWords/EsDateToOrdinalWordsConverter.cs new file mode 100644 index 000000000..2c86a6010 --- /dev/null +++ b/src/Humanizer/Localisation/DateToOrdinalWords/EsDateToOrdinalWordsConverter.cs @@ -0,0 +1,12 @@ +using System; + +namespace Humanizer.Localisation.DateToOrdinalWords +{ + internal class EsDateToOrdinalWordsConverter : DefaultDateToOrdinalWordConverter + { + public override string Convert(DateTime date) + { + return date.ToString("d 'de' MMMM 'de' yyyy"); + } + } +} From 865fb2d5e6b5b6ee6ce1ef0ab2a8a1e5e87ec6d0 Mon Sep 17 00:00:00 2001 From: Daniel Serrano Date: Sat, 1 Jan 2022 17:43:34 +0100 Subject: [PATCH 02/33] Add TimeToClockNotation in Spanish --- .../es/TimeToClockNotationTests.cs | 72 ++++++++++++++++++ ...meOnlyToClockNotationConvertersRegistry.cs | 1 + .../EsTimeOnlyToClockNotationConverter.cs | 73 +++++++++++++++++++ 3 files changed, 146 insertions(+) create mode 100644 src/Humanizer.Tests/Localisation/es/TimeToClockNotationTests.cs create mode 100644 src/Humanizer/Localisation/TimeToClockNotation/EsTimeOnlyToClockNotationConverter.cs diff --git a/src/Humanizer.Tests/Localisation/es/TimeToClockNotationTests.cs b/src/Humanizer.Tests/Localisation/es/TimeToClockNotationTests.cs new file mode 100644 index 000000000..80f3ea847 --- /dev/null +++ b/src/Humanizer.Tests/Localisation/es/TimeToClockNotationTests.cs @@ -0,0 +1,72 @@ +#if NET6_0_OR_GREATER + +using System; + +using Xunit; + +namespace Humanizer.Tests.Localisation.es +{ + [UseCulture("es-ES")] + public class TimeToClockNotationTests + { + [Theory] + [InlineData(0, 0, "medianoche")] + [InlineData(0, 7, "las doce y siete de la madrugada")] + [InlineData(1, 11, "la una y once de la madrugada")] + [InlineData(4, 0, "las cuatro de la madrugada")] + [InlineData(5, 1, "las cinco y uno de la madrugada")] + [InlineData(6, 0, "las seis de la mañana")] + [InlineData(6, 5, "las seis y cinco de la mañana")] + [InlineData(7, 10, "las siete y diez de la mañana")] + [InlineData(8, 15, "las ocho y cuarto de la mañana")] + [InlineData(9, 20, "las nueve y veinte de la mañana")] + [InlineData(10, 25, "las diez y veinticinco de la mañana")] + [InlineData(11, 30, "las once y media de la mañana")] + [InlineData(12, 00, "mediodía")] + [InlineData(12, 38, "las doce y treinta y ocho de la tarde")] + [InlineData(12, 35, "la una menos veinticinco de la tarde")] + [InlineData(15, 40, "las cuatro menos veinte de la tarde")] + [InlineData(17, 45, "las seis menos cuarto de la tarde")] + [InlineData(19, 50, "las ocho menos diez de la tarde")] + [InlineData(21, 0, "las nueve de la noche")] + [InlineData(21, 55, "las diez menos cinco de la noche")] + [InlineData(22, 59, "las diez y cincuenta y nueve de la noche")] + [InlineData(23, 43, "las once y cuarenta y tres de la noche")] + public void ConvertToClockNotationTimeOnlyString(int hours, int minutes, string expectedResult) + { + var actualResult = new TimeOnly(hours, minutes).ToClockNotation(); + Assert.Equal(expectedResult, actualResult); + } + + [Theory] + [InlineData(0, 0, "medianoche")] + [InlineData(0, 7, "las doce y cinco de la madrugada")] + [InlineData(1, 11, "la una y diez de la madrugada")] + [InlineData(4, 0, "las cuatro de la madrugada")] + [InlineData(5, 1, "las cinco de la madrugada")] + [InlineData(6, 0, "las seis de la mañana")] + [InlineData(6, 5, "las seis y cinco de la mañana")] + [InlineData(7, 10, "las siete y diez de la mañana")] + [InlineData(8, 15, "las ocho y cuarto de la mañana")] + [InlineData(9, 20, "las nueve y veinte de la mañana")] + [InlineData(10, 25, "las diez y veinticinco de la mañana")] + [InlineData(11, 30, "las once y media de la mañana")] + [InlineData(12, 00, "mediodía")] + [InlineData(12, 38, "la una menos veinte de la tarde")] + [InlineData(12, 35, "la una menos veinticinco de la tarde")] + [InlineData(15, 40, "las cuatro menos veinte de la tarde")] + [InlineData(17, 45, "las seis menos cuarto de la tarde")] + [InlineData(19, 50, "las ocho menos diez de la tarde")] + [InlineData(21, 0, "las nueve de la noche")] + [InlineData(21, 55, "las diez menos cinco de la noche")] + [InlineData(22, 59, "las once de la noche")] + [InlineData(23, 43, "las doce menos cuarto de la noche")] + public void ConvertToRoundedClockNotationTimeOnlyString(int hours, int minutes, string expectedResult) + { + var actualResult = new TimeOnly(hours, minutes).ToClockNotation(ClockNotationRounding.NearestFiveMinutes); + Assert.Equal(expectedResult, actualResult); + } + } +} + +#endif diff --git a/src/Humanizer/Configuration/TimeOnlyToClockNotationConvertersRegistry.cs b/src/Humanizer/Configuration/TimeOnlyToClockNotationConvertersRegistry.cs index 2f16ad933..91fb9ff2e 100644 --- a/src/Humanizer/Configuration/TimeOnlyToClockNotationConvertersRegistry.cs +++ b/src/Humanizer/Configuration/TimeOnlyToClockNotationConvertersRegistry.cs @@ -10,6 +10,7 @@ public TimeOnlyToClockNotationConvertersRegistry() : base(new DefaultTimeOnlyToC { Register("pt-BR", new BrazilianPortugueseTimeOnlyToClockNotationConverter()); Register("fr", new FrTimeOnlyToClockNotationConverter()); + Register("es", new EsTimeOnlyToClockNotationConverter()); } } } diff --git a/src/Humanizer/Localisation/TimeToClockNotation/EsTimeOnlyToClockNotationConverter.cs b/src/Humanizer/Localisation/TimeToClockNotation/EsTimeOnlyToClockNotationConverter.cs new file mode 100644 index 000000000..5db4e1980 --- /dev/null +++ b/src/Humanizer/Localisation/TimeToClockNotation/EsTimeOnlyToClockNotationConverter.cs @@ -0,0 +1,73 @@ +#if NET6_0_OR_GREATER + +using System; + +namespace Humanizer.Localisation.TimeToClockNotation +{ + internal class EsTimeOnlyToClockNotationConverter : ITimeOnlyToClockNotationConverter + { + public string Convert(TimeOnly time, ClockNotationRounding roundToNearestFive) + { + switch (time) + { + case { Hour: 0, Minute: 0 }: + return "medianoche"; + case { Hour: 12, Minute: 0 }: + return "mediodía"; + } + + var article = GetArticle(time); + var articleNextHour = GetArticle(time.AddHours(1)); + var hour = NormalizeHour(time).ToWords(GrammaticalGender.Feminine); + var nextHour = NormalizeHour(time.AddHours(1)).ToWords(GrammaticalGender.Feminine); + var dayPeriod = GetDayPeriod(time); + var dayPeriodNextHour = GetDayPeriod(time.AddHours(1)); + + var normalizedMinutes = (int)(roundToNearestFive == ClockNotationRounding.NearestFiveMinutes + ? 5 * Math.Round(time.Minute / 5.0) + : time.Minute); + + return normalizedMinutes switch + { + 00 => $"{article} {hour} {dayPeriod}", + 15 => $"{article} {hour} y cuarto {dayPeriod}", + 30 => $"{article} {hour} y media {dayPeriod}", + 35 => $"{articleNextHour} {nextHour} menos veinticinco {dayPeriodNextHour}", + 40 => $"{articleNextHour} {nextHour} menos veinte {dayPeriodNextHour}", + 45 => $"{articleNextHour} {nextHour} menos cuarto {dayPeriodNextHour}", + 50 => $"{articleNextHour} {nextHour} menos diez {dayPeriodNextHour}", + 55 => $"{articleNextHour} {nextHour} menos cinco {dayPeriodNextHour}", + 60 => $"{articleNextHour} {nextHour} {dayPeriodNextHour}", + _ => $"{article} {hour} y {normalizedMinutes.ToWords()} {dayPeriod}" + }; + } + + private static int NormalizeHour(TimeOnly time) + { + return time.Hour % 12 != 0 ? (time.Hour % 12) : 12; + } + + private static string GetArticle(TimeOnly time) + { + return (time.Hour == 1 || time.Hour == 13) ? "la" : "las"; + } + + private static string GetDayPeriod(TimeOnly time) + { + const int MORNING = 6; + const int NOON = 12; + const int AFTERNOON = 20; + + return time.Hour switch + { + int h when h is >= 0 and < MORNING => "de la madrugada", + int h when h is >= MORNING and < NOON => "de la mañana", + int h when h is >= NOON and < AFTERNOON => "de la tarde", + int h when h is >= AFTERNOON and < 24 => "de la noche", + _ => "" + }; + } + } +} + +#endif From 58bbfcad718ecd18e3a442f4f707f8864bfa6ced Mon Sep 17 00:00:00 2001 From: Daniel Serrano Date: Tue, 4 Jan 2022 11:00:26 +0100 Subject: [PATCH 03/33] Fix errors. Add support for long numbers --- .../Localisation/es/NumberToWordsTests.cs | 56 ++++-- .../SpanishNumberToWordsConverter.cs | 173 ++++++++++++++---- 2 files changed, 177 insertions(+), 52 deletions(-) diff --git a/src/Humanizer.Tests.Shared/Localisation/es/NumberToWordsTests.cs b/src/Humanizer.Tests.Shared/Localisation/es/NumberToWordsTests.cs index 0d3c81543..cfba298b7 100644 --- a/src/Humanizer.Tests.Shared/Localisation/es/NumberToWordsTests.cs +++ b/src/Humanizer.Tests.Shared/Localisation/es/NumberToWordsTests.cs @@ -5,14 +5,32 @@ namespace Humanizer.Tests.Localisation.es [UseCulture("es-ES")] public class NumberToWordsTests { - [Theory] [InlineData(0, "cero")] [InlineData(1, "uno")] + [InlineData(1, "un", GrammaticalGender.Neuter)] + [InlineData(1, "una", GrammaticalGender.Feminine)] [InlineData(10, "diez")] [InlineData(11, "once")] + [InlineData(15, "quince")] + [InlineData(16, "dieciséis")] + [InlineData(20, "veinte")] + [InlineData(21, "veintiuno")] + [InlineData(21, "veintiuna", GrammaticalGender.Feminine)] + [InlineData(22, "veintidós")] + [InlineData(25, "veinticinco")] + [InlineData(35, "treinta y cinco")] [InlineData(122, "ciento veintidós")] + [InlineData(1999, "mil novecientos noventa y nueve")] + [InlineData(2014, "dos mil catorce")] + [InlineData(2048, "dos mil cuarenta y ocho")] [InlineData(3501, "tres mil quinientos uno")] + [InlineData(21501, "veintiún mil quinientos uno")] + [InlineData(21501, "veintiuna mil quinientas una", GrammaticalGender.Feminine)] + [InlineData(31501, "treinta y un mil quinientos uno")] + [InlineData(31501, "treinta y una mil quinientas una", GrammaticalGender.Feminine)] + [InlineData(101501, "ciento un mil quinientos uno")] + [InlineData(101501, "ciento una mil quinientas una", GrammaticalGender.Feminine)] [InlineData(100, "cien")] [InlineData(1000, "mil")] [InlineData(100000, "cien mil")] @@ -20,14 +38,27 @@ public class NumberToWordsTests [InlineData(10000000, "diez millones")] [InlineData(100000000, "cien millones")] [InlineData(1000000000, "mil millones")] + [InlineData(1000000000000, "un billón")] + [InlineData(1_000_000_000_000_000_000, "un trillón")] [InlineData(111, "ciento once")] [InlineData(1111, "mil ciento once")] [InlineData(111111, "ciento once mil ciento once")] [InlineData(1111111, "un millón ciento once mil ciento once")] [InlineData(11111111, "once millones ciento once mil ciento once")] [InlineData(111111111, "ciento once millones ciento once mil ciento once")] - [InlineData(1001111111, "mil millones un millón ciento once mil ciento once")] - [InlineData(1111111111, "mil millones ciento once millones ciento once mil ciento once")] + [InlineData(1111111111, "mil ciento once millones ciento once mil ciento once")] + [InlineData(1111111111111, "un billón ciento once mil ciento once millones ciento once mil ciento once")] + [InlineData(1111111111111111, "mil ciento once billones ciento once mil ciento once millones ciento once mil ciento once")] + [InlineData(1111111111111111111, "un trillón ciento once mil ciento once billones ciento once mil ciento once millones ciento once mil ciento once")] + [InlineData(9223372036854775807, "nueve trillones doscientos veintitrés mil trescientos setenta y dos billones treinta y seis mil ochocientos cincuenta y cuatro millones setecientos setenta y cinco mil ochocientos siete")] + [InlineData(1001111111, "mil un millones ciento once mil ciento once")] + [InlineData(1001000001, "mil un millones uno")] + [InlineData(1002000001, "mil dos millones uno")] + [InlineData(2001000001, "dos mil un millones uno")] + [InlineData(1001000000001, "un billón mil millones uno")] + [InlineData(1001000000000001, "mil un billones uno")] + [InlineData(1002000000000001, "mil dos billones uno")] + [InlineData(2002000000000001, "dos mil dos billones uno")] [InlineData(123, "ciento veintitrés")] [InlineData(1234, "mil doscientos treinta y cuatro")] [InlineData(12345, "doce mil trescientos cuarenta y cinco")] @@ -35,19 +66,14 @@ public class NumberToWordsTests [InlineData(1234567, "un millón doscientos treinta y cuatro mil quinientos sesenta y siete")] [InlineData(12345678, "doce millones trescientos cuarenta y cinco mil seiscientos setenta y ocho")] [InlineData(123456789, "ciento veintitrés millones cuatrocientos cincuenta y seis mil setecientos ochenta y nueve")] - [InlineData(1234567890, "mil millones doscientos treinta y cuatro millones quinientos sesenta y siete mil ochocientos noventa")] - [InlineData(15, "quince")] - [InlineData(16, "dieciséis")] - [InlineData(20, "veinte")] - [InlineData(22, "veintidós")] - [InlineData(25, "veinticinco")] - [InlineData(35, "treinta y cinco")] - [InlineData(1999, "mil novecientos noventa y nueve")] - [InlineData(2014, "dos mil catorce")] - [InlineData(2048, "dos mil cuarenta y ocho")] - public void ToWords(int number, string expected) + [InlineData(1234567890, "mil doscientos treinta y cuatro millones quinientos sesenta y siete mil ochocientos noventa")] + [InlineData(-15, "menos quince")] + [InlineData(-123, "menos ciento veintitrés")] + [InlineData(-1234567890, "menos mil doscientos treinta y cuatro millones quinientos sesenta y siete mil ochocientos noventa")] + [InlineData(-9223372036854775808, "menos nueve trillones doscientos veintitrés mil trescientos setenta y dos billones treinta y seis mil ochocientos cincuenta y cuatro millones setecientos setenta y cinco mil ochocientos ocho")] + public void ToWords(long number, string expected, GrammaticalGender gender = GrammaticalGender.Masculine) { - Assert.Equal(expected, number.ToWords()); + Assert.Equal(expected, number.ToWords(gender)); } // TODO: This data is suspect since null cannot go into GramaticalGender diff --git a/src/Humanizer/Localisation/NumberToWords/SpanishNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/SpanishNumberToWordsConverter.cs index f89f25959..3d487bb4b 100644 --- a/src/Humanizer/Localisation/NumberToWords/SpanishNumberToWordsConverter.cs +++ b/src/Humanizer/Localisation/NumberToWords/SpanishNumberToWordsConverter.cs @@ -10,6 +10,7 @@ internal class SpanishNumberToWordsConverter : GenderedNumberToWordsConverter "veintidós", "veintitrés", "veinticuatro", "veinticinco", "veintiséis", "veintisiete", "veintiocho", "veintinueve"}; private const string Feminine1 = "una"; private const string Feminine21 = "veintiuna"; + private const string LongMinValue = "menos nueve trillones doscientos veintitrés mil trescientos setenta y dos billones treinta y seis mil ochocientos cincuenta y cuatro millones setecientos setenta y cinco mil ochocientos ocho"; private static readonly string[] TensMap = { "cero", "diez", "veinte", "treinta", "cuarenta", "cincuenta", "sesenta", "setenta", "ochenta", "noventa" }; private static readonly string[] HundredsMap = { "cero", "ciento", "doscientos", "trescientos", "cuatrocientos", "quinientos", "seiscientos", "setecientos", "ochocientos", "novecientos" }; private static readonly string[] FeminineHundredsMap = { "cero", "ciento", "doscientas", "trescientas", "cuatrocientas", "quinientas", "seiscientas", "setecientas", "ochocientas", "novecientas" }; @@ -31,84 +32,182 @@ internal class SpanishNumberToWordsConverter : GenderedNumberToWordsConverter public override string Convert(long input, GrammaticalGender gender, bool addAnd = true) { - if (input > Int32.MaxValue || input < Int32.MinValue) + if (input == 0) { - throw new NotImplementedException(); + return "cero"; } - var number = (int)input; - if (number == 0) + + if (input == long.MinValue) { - return "cero"; + return LongMinValue; } - if (number < 0) + if (input < 0) { - return string.Format("menos {0}", Convert(Math.Abs(number))); + return $"menos {Convert(-input)}"; } + const long ONE_TRILLION = 1_000_000_000_000_000_000; + const long ONE_BILLION = 1_000_000_000_000; + const long ONE_MILLION = 1_000_000; + var parts = new List(); - if ((number / 1000000000) > 0) + if ((input / ONE_TRILLION) > 0) { - parts.Add(number / 1000000000 == 1 - ? "mil millones" - : string.Format("{0} mil millones", Convert(number / 1000000000))); + if (input / ONE_TRILLION == 1) + { + parts.Add("un trillón"); + } + else + { + if ((input / ONE_TRILLION) % 10 == 1) + { + parts.Add($"{Convert(input / ONE_TRILLION, GrammaticalGender.Neuter)} trillones"); + } + else + { + parts.Add($"{Convert(input / ONE_TRILLION)} trillones"); + } + } - number %= 1000000000; + input %= ONE_TRILLION; } - if ((number / 1000000) > 0) + if ((input / ONE_BILLION) > 0) { - parts.Add(number / 1000000 == 1 - ? "un millón" - : string.Format("{0} millones", Convert(number / 1000000))); + if (input / ONE_BILLION == 1) + { + parts.Add("un billón"); + } + else + { + if ((input / ONE_BILLION) % 10 == 1) + { + parts.Add($"{Convert(input / ONE_BILLION, GrammaticalGender.Neuter)} billones"); + } + else + { + parts.Add($"{Convert(input / ONE_BILLION)} billones"); + } + } - number %= 1000000; + input %= ONE_BILLION; } - if ((number / 1000) > 0) + if ((input / ONE_MILLION) > 0) { - parts.Add(number / 1000 == 1 - ? "mil" - : string.Format("{0} mil", Convert(number / 1000, gender))); + if (input / ONE_MILLION == 1) + { + parts.Add("un millón"); + } + else + { + if ((input / ONE_MILLION) % 10 == 1) + { + parts.Add($"{Convert(input / ONE_MILLION, GrammaticalGender.Neuter)} millones"); + } + else + { + parts.Add($"{Convert(input / ONE_MILLION)} millones"); + } + } - number %= 1000; + input %= ONE_MILLION; } - if ((number / 100) > 0) + if ((input / 1000) > 0) { - parts.Add(number == 100 + if (input / 1000 == 1) + { + parts.Add("mil"); + } + else + { + if ((input % 10 == 1) && (gender == GrammaticalGender.Feminine)) + { + parts.Add($"{Convert(input / 1000, GrammaticalGender.Feminine)} mil"); + } + else + { + parts.Add(string.Format($"{Convert(input / 1000, GrammaticalGender.Neuter)} mil")); + } + } + + input %= 1000; + } + + if ((input / 100) > 0) + { + parts.Add((string)(input == 100 ? "cien" : gender == GrammaticalGender.Feminine - ? FeminineHundredsMap[(number / 100)] - : HundredsMap[(number / 100)]); - number %= 100; + ? FeminineHundredsMap[input / 100] + : HundredsMap[input / 100])); + input %= 100; } - if (number > 0) + if (input > 0) { - if (number < 30) + if (input < 30) { - if (gender == GrammaticalGender.Feminine && (number == 1 || number == 21)) + if (input == 1) + { + if (gender == GrammaticalGender.Feminine) + { + parts.Add(Feminine1); + } + else if (gender == GrammaticalGender.Neuter) + { + parts.Add("un"); + } + else + { + parts.Add(UnitsMap[input]); + } + } + else if (input == 21) { - parts.Add(number == 1 ? Feminine1 : Feminine21); + if (gender == GrammaticalGender.Feminine) + { + parts.Add(Feminine21); + } + else if (gender == GrammaticalGender.Neuter) + { + parts.Add("veintiún"); + } + else + { + parts.Add(UnitsMap[input]); + } } else { - parts.Add(UnitsMap[number]); + parts.Add(UnitsMap[input]); } } else { - var lastPart = TensMap[number / 10]; - var units = number % 10; - if (units == 1 && gender == GrammaticalGender.Feminine) + var lastPart = TensMap[input / 10]; + var units = input % 10; + if (units == 1) { - lastPart += " y una"; + if (gender == GrammaticalGender.Feminine) + { + lastPart += " y una"; + } + else if (gender == GrammaticalGender.Neuter) + { + lastPart += " y un"; + } + else + { + lastPart += " y uno"; + } } else if (units > 0) { - lastPart += string.Format(" y {0}", UnitsMap[number % 10]); + lastPart += string.Format(" y {0}", UnitsMap[input % 10]); } parts.Add(lastPart); From 0c0028a154f38c89744cbd02e5df74563a0e4cf5 Mon Sep 17 00:00:00 2001 From: Daniel Serrano Date: Tue, 4 Jan 2022 14:55:23 +0100 Subject: [PATCH 04/33] Add Spanish translations to resource file --- src/Humanizer/Properties/Resources.es.resx | 494 ++++++++++++++++++++- 1 file changed, 493 insertions(+), 1 deletion(-) diff --git a/src/Humanizer/Properties/Resources.es.resx b/src/Humanizer/Properties/Resources.es.resx index d92340cd5..5626af23f 100644 --- a/src/Humanizer/Properties/Resources.es.resx +++ b/src/Humanizer/Properties/Resources.es.resx @@ -1,4 +1,4 @@ - +