From 7a78924ba3033ac1b20309b32753508d328425aa Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Mon, 18 Aug 2014 13:11:07 +0200 Subject: [PATCH 01/39] Added initial Resource italian translation --- src/Humanizer/Properties/Resources.it.resx | 234 +++++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100644 src/Humanizer/Properties/Resources.it.resx diff --git a/src/Humanizer/Properties/Resources.it.resx b/src/Humanizer/Properties/Resources.it.resx new file mode 100644 index 000000000..c1e4efa0f --- /dev/null +++ b/src/Humanizer/Properties/Resources.it.resx @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + un secondo fa + + + {0} secondi fa + + + un minuto fa + + + {0} minuti fa + + + un'ora fa + + + {0} ore fa + + + ieri + + + {0} giorni fa + + + un mese fa + + + {0} mesi fa + + + un anno fa + + + {0} anni fa + + + {0} giorni + + + {0} ore + + + {0} millisecondi + + + {0} minuti + + + {0} secondi + + + 1 giorno + + + 1 ora + + + 1 millisecondo + + + 1 minuto + + + 1 secondo + + + no time + + + {0} settimane + + + 1 settimana + + + {0} giorni da ora + + + {0} ore da adesso + + + {0} minuti da adesso + + + {0} mesi da ora + + + {0} secondi da adesso + + + {0} anni da ora + + + adesso + + + domani + + + un'ora da adesso + + + un minuto da adesso + + + un mese da ora + + + un secondo da adesso + + + un anno da ora + + \ No newline at end of file From 2b650015a66e39f10b3353a9fa67dbd2c96b093f Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Mon, 18 Aug 2014 13:14:55 +0200 Subject: [PATCH 02/39] Improved 'xxxFromNow' translations --- src/Humanizer/Properties/Resources.it.resx | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Humanizer/Properties/Resources.it.resx b/src/Humanizer/Properties/Resources.it.resx index c1e4efa0f..f246144c8 100644 --- a/src/Humanizer/Properties/Resources.it.resx +++ b/src/Humanizer/Properties/Resources.it.resx @@ -193,22 +193,22 @@ 1 settimana - {0} giorni da ora + entro {0} giorni - {0} ore da adesso + entro {0} ore - {0} minuti da adesso + entro {0} minuti - {0} mesi da ora + entro {0} mesi - {0} secondi da adesso + entro {0} secondi - {0} anni da ora + entro {0} anni adesso @@ -217,18 +217,18 @@ domani - un'ora da adesso + entro un'ora - un minuto da adesso + entro un minuto - un mese da ora + entro un mese - un secondo da adesso + entro un secondo - un anno da ora + entro un anno \ No newline at end of file From 107ba30dc60a430e2bf0d2d2363fe98e587ddd93 Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Mon, 18 Aug 2014 13:22:55 +0200 Subject: [PATCH 03/39] Added Zero Time italian translation --- src/Humanizer/Properties/Resources.it.resx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Humanizer/Properties/Resources.it.resx b/src/Humanizer/Properties/Resources.it.resx index f246144c8..a3b389dd3 100644 --- a/src/Humanizer/Properties/Resources.it.resx +++ b/src/Humanizer/Properties/Resources.it.resx @@ -184,7 +184,7 @@ 1 secondo - no time + 0 secondi {0} settimane From 5a38abf23a7d8a0de240d456a75f9b73dcc0db3b Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Mon, 25 Aug 2014 20:11:47 +0200 Subject: [PATCH 04/39] L10n: added italian collection formatter --- .../Configuration/CollectionFormatterRegistry.cs | 1 + src/Humanizer/Humanizer.csproj | 1 + .../ItalianCollectionFormatter.cs | 14 ++++++++++++++ 3 files changed, 16 insertions(+) create mode 100644 src/Humanizer/Localisation/CollectionFormatters/ItalianCollectionFormatter.cs diff --git a/src/Humanizer/Configuration/CollectionFormatterRegistry.cs b/src/Humanizer/Configuration/CollectionFormatterRegistry.cs index 43b1f317f..21b2ca376 100644 --- a/src/Humanizer/Configuration/CollectionFormatterRegistry.cs +++ b/src/Humanizer/Configuration/CollectionFormatterRegistry.cs @@ -8,6 +8,7 @@ public CollectionFormatterRegistry() : base(new DefaultCollectionFormatter()) { Register("en", new EnglishCollectionFormatter()); + Register("it", new ItalianCollectionFormatter()); } } } diff --git a/src/Humanizer/Humanizer.csproj b/src/Humanizer/Humanizer.csproj index 0af4bf994..d558014c0 100644 --- a/src/Humanizer/Humanizer.csproj +++ b/src/Humanizer/Humanizer.csproj @@ -54,6 +54,7 @@ + diff --git a/src/Humanizer/Localisation/CollectionFormatters/ItalianCollectionFormatter.cs b/src/Humanizer/Localisation/CollectionFormatters/ItalianCollectionFormatter.cs new file mode 100644 index 000000000..0be5f26c6 --- /dev/null +++ b/src/Humanizer/Localisation/CollectionFormatters/ItalianCollectionFormatter.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Humanizer.Localisation.CollectionFormatters +{ + internal class ItalianCollectionFormatter : EnglishCollectionFormatter + { + public ItalianCollectionFormatter() + { + DefaultSeparator = "and"; + } + } +} From b84a80b5d371bbda321aa84c693e90908aa11de9 Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Mon, 25 Aug 2014 20:21:40 +0200 Subject: [PATCH 05/39] L10n: added failing italian DateHumanizeTests --- src/Humanizer.Tests/Humanizer.Tests.csproj | 1 + .../Localisation/it/DateHumanizeTests.cs | 109 ++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 src/Humanizer.Tests/Localisation/it/DateHumanizeTests.cs diff --git a/src/Humanizer.Tests/Humanizer.Tests.csproj b/src/Humanizer.Tests/Humanizer.Tests.csproj index 2d6937c42..c28b97df6 100644 --- a/src/Humanizer.Tests/Humanizer.Tests.csproj +++ b/src/Humanizer.Tests/Humanizer.Tests.csproj @@ -94,6 +94,7 @@ + diff --git a/src/Humanizer.Tests/Localisation/it/DateHumanizeTests.cs b/src/Humanizer.Tests/Localisation/it/DateHumanizeTests.cs new file mode 100644 index 000000000..77e577c80 --- /dev/null +++ b/src/Humanizer.Tests/Localisation/it/DateHumanizeTests.cs @@ -0,0 +1,109 @@ +using System; +using Humanizer.Localisation; +using Xunit; +using Xunit.Extensions; + +namespace Humanizer.Tests.Localisation.it +{ + public class DateHumanizeTests : AmbientCulture + { + public DateHumanizeTests() : base("it") { } + + [Theory] + [InlineData(1, "hace un segundo")] + [InlineData(2, "hace 2 segundos")] + public void SecondsAgo(int seconds, string expected) + { + DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); + } + + [Theory] + [InlineData(1, "en un segundo")] + [InlineData(2, "en 2 segundos")] + public void SecondsFromNow(int seconds, string expected) + { + DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); + } + + [Theory] + [InlineData(1, "hace un minuto")] + [InlineData(2, "hace 2 minutos")] + [InlineData(60, "hace una hora")] + public void MinutesAgo(int minutes, string expected) + { + DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); + } + + [Theory] + [InlineData(1, "en un minuto")] + [InlineData(2, "en 2 minutos")] + public void MinutesFromNow(int minutes, string expected) + { + DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); + } + + [Theory] + [InlineData(1, "hace una hora")] + [InlineData(2, "hace 2 horas")] + public void HoursAgo(int hours, string expected) + { + DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); + } + + [Theory] + [InlineData(1, "en una hora")] + [InlineData(2, "en 2 horas")] + public void HoursFromNow(int hours, string expected) + { + DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); + } + + [Theory] + [InlineData(1, "ayer")] + [InlineData(2, "hace 2 días")] + public void DaysAgo(int days, string expected) + { + DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); + } + + [Theory] + [InlineData(1, "mañana")] + [InlineData(2, "en 2 días")] + public void DaysFromNow(int days, string expected) + { + DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); + } + + [Theory] + [InlineData(1, "hace un mes")] + [InlineData(2, "hace 2 meses")] + public void MonthsAgo(int months, string expected) + { + DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); + } + + [Theory] + [InlineData(1, "en un mes")] + [InlineData(2, "en 2 meses")] + public void MonthsFromNow(int months, string expected) + { + DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); + } + + [Theory] + [InlineData(1, "hace un año")] + [InlineData(2, "hace 2 años")] + public void YearsAgo(int years, string expected) + { + DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); + } + + [Theory] + [InlineData(1, "en un año")] + [InlineData(2, "en 2 años")] + public void YearsFromNow(int years, string expected) + { + DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); + } + } +} From 960e46e4d7cb5541be6b2acf048ec564efb53127 Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Mon, 25 Aug 2014 20:31:57 +0200 Subject: [PATCH 06/39] L10n: Fix: VS project was missing italian resource file --- src/Humanizer/Humanizer.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Humanizer/Humanizer.csproj b/src/Humanizer/Humanizer.csproj index 0af4bf994..d366b0f76 100644 --- a/src/Humanizer/Humanizer.csproj +++ b/src/Humanizer/Humanizer.csproj @@ -206,6 +206,7 @@ + From 7158e06db20c0d21ff1085d3df81694f9f15af4e Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Tue, 26 Aug 2014 01:07:52 +0200 Subject: [PATCH 07/39] L10n: italian DateHumanizeTests now passing --- src/Humanizer.Tests/Humanizer.Tests.csproj | 2 +- .../Localisation/it/DateHumanizeTests.cs | 108 ++++++++++-------- .../Configuration/FormatterRegistry.cs | 1 + src/Humanizer/Properties/Resources.it.resx | 22 ++-- 4 files changed, 72 insertions(+), 61 deletions(-) diff --git a/src/Humanizer.Tests/Humanizer.Tests.csproj b/src/Humanizer.Tests/Humanizer.Tests.csproj index c28b97df6..7fd23305c 100644 --- a/src/Humanizer.Tests/Humanizer.Tests.csproj +++ b/src/Humanizer.Tests/Humanizer.Tests.csproj @@ -94,7 +94,6 @@ - @@ -141,6 +140,7 @@ + diff --git a/src/Humanizer.Tests/Localisation/it/DateHumanizeTests.cs b/src/Humanizer.Tests/Localisation/it/DateHumanizeTests.cs index 77e577c80..1e42766dd 100644 --- a/src/Humanizer.Tests/Localisation/it/DateHumanizeTests.cs +++ b/src/Humanizer.Tests/Localisation/it/DateHumanizeTests.cs @@ -7,101 +7,111 @@ namespace Humanizer.Tests.Localisation.it { public class DateHumanizeTests : AmbientCulture { - public DateHumanizeTests() : base("it") { } + public DateHumanizeTests() + : base("it") + { + } [Theory] - [InlineData(1, "hace un segundo")] - [InlineData(2, "hace 2 segundos")] - public void SecondsAgo(int seconds, string expected) + [InlineData(-2, "2 giorni fa")] + [InlineData(-1, "ieri")] + public void DaysAgo(int days, string expected) { - DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); + DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); } - [Theory] - [InlineData(1, "en un segundo")] - [InlineData(2, "en 2 segundos")] - public void SecondsFromNow(int seconds, string expected) + [Theory] + [InlineData(2, "tra 2 giorni")] + [InlineData(1, "domani")] + public void DaysFromNow(int days, string expected) { - DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); + DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); } [Theory] - [InlineData(1, "hace un minuto")] - [InlineData(2, "hace 2 minutos")] - [InlineData(60, "hace una hora")] - public void MinutesAgo(int minutes, string expected) + [InlineData(-2, "2 ore fa")] + [InlineData(-1, "un'ora fa")] + public void HoursAgo(int hours, string expected) { - DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); + DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); } [Theory] - [InlineData(1, "en un minuto")] - [InlineData(2, "en 2 minutos")] - public void MinutesFromNow(int minutes, string expected) + [InlineData(2, "tra 2 ore")] + [InlineData(1, "tra un'ora")] + public void HoursFromNow(int hours, string expected) { - DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); + DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); } [Theory] - [InlineData(1, "hace una hora")] - [InlineData(2, "hace 2 horas")] - public void HoursAgo(int hours, string expected) + [InlineData(-2, "2 minuti fa")] + [InlineData(-1, "un minuto fa")] + [InlineData(60, "un'ora fa")] + public void MinutesAgo(int minutes, string expected) { - DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); + DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); } [Theory] - [InlineData(1, "en una hora")] - [InlineData(2, "en 2 horas")] - public void HoursFromNow(int hours, string expected) + [InlineData(2, "tra 2 minuti")] + [InlineData(1, "tra un minuto")] + public void MinutesFromNow(int minutes, string expected) { - DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); + DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); } [Theory] - [InlineData(1, "ayer")] - [InlineData(2, "hace 2 días")] - public void DaysAgo(int days, string expected) + [InlineData(-2, "2 mesi fa")] + [InlineData(-1, "un mese fa")] + public void MonthsAgo(int months, string expected) { - DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); + DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); } [Theory] - [InlineData(1, "mañana")] - [InlineData(2, "en 2 días")] - public void DaysFromNow(int days, string expected) + [InlineData(2, "tra 2 mesi")] + [InlineData(1, "tra un mese")] + public void MonthsFromNow(int months, string expected) { - DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); + DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); } [Theory] - [InlineData(1, "hace un mes")] - [InlineData(2, "hace 2 meses")] - public void MonthsAgo(int months, string expected) + [InlineData(-2, "2 secondi fa")] + [InlineData(-1, "un secondo fa")] + public void SecondsAgo(int seconds, string expected) { - DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); + DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); } [Theory] - [InlineData(1, "en un mes")] - [InlineData(2, "en 2 meses")] - public void MonthsFromNow(int months, string expected) + [InlineData(2, "tra 2 secondi")] + [InlineData(1, "tra un secondo")] + public void SecondsFromNow(int seconds, string expected) { - DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); + DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); } [Theory] - [InlineData(1, "hace un año")] - [InlineData(2, "hace 2 años")] - public void YearsAgo(int years, string expected) + [InlineData(-2, "2 anni fa")] + [InlineData(-1, "un anno fa")] + public void YearsAgo(int years, string expected) { DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); } [Theory] - [InlineData(1, "en un año")] - [InlineData(2, "en 2 años")] - public void YearsFromNow(int years, string expected) + [InlineData(2, "tra 2 anni")] + [InlineData(1, "tra un anno")] + public void YearsFromNow(int years, string expected) + { + DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); + } + + [Theory] + [InlineData(0, "adesso")] + public void Now(int years, string expected) { DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); } diff --git a/src/Humanizer/Configuration/FormatterRegistry.cs b/src/Humanizer/Configuration/FormatterRegistry.cs index 6e568d119..2bd4bd8d3 100644 --- a/src/Humanizer/Configuration/FormatterRegistry.cs +++ b/src/Humanizer/Configuration/FormatterRegistry.cs @@ -38,6 +38,7 @@ public FormatterRegistry() : base(new DefaultFormatter("en-US")) RegisterDefaultFormatter("nb-NO"); RegisterDefaultFormatter("nl"); RegisterDefaultFormatter("bn-BD"); + RegisterDefaultFormatter("it"); } private void RegisterDefaultFormatter(string localeCode) diff --git a/src/Humanizer/Properties/Resources.it.resx b/src/Humanizer/Properties/Resources.it.resx index a3b389dd3..2be83b07a 100644 --- a/src/Humanizer/Properties/Resources.it.resx +++ b/src/Humanizer/Properties/Resources.it.resx @@ -193,22 +193,22 @@ 1 settimana - entro {0} giorni + tra {0} giorni - entro {0} ore + tra {0} ore - entro {0} minuti + tra {0} minuti - entro {0} mesi + tra {0} mesi - entro {0} secondi + tra {0} secondi - entro {0} anni + tra {0} anni adesso @@ -217,18 +217,18 @@ domani - entro un'ora + tra un'ora - entro un minuto + tra un minuto - entro un mese + tra un mese - entro un secondo + tra un secondo - entro un anno + tra un anno \ No newline at end of file From 104a1dc909a6d6780ddb704c0f9a3599fe0a00ec Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Tue, 26 Aug 2014 01:41:31 +0200 Subject: [PATCH 08/39] L10n: italian TimeSpanHumanizeTests passing --- src/Humanizer.Tests/Humanizer.Tests.csproj | 1 + .../Localisation/it/TimeSpanHumanizeTests.cs | 66 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 src/Humanizer.Tests/Localisation/it/TimeSpanHumanizeTests.cs diff --git a/src/Humanizer.Tests/Humanizer.Tests.csproj b/src/Humanizer.Tests/Humanizer.Tests.csproj index 7fd23305c..a1b2d526a 100644 --- a/src/Humanizer.Tests/Humanizer.Tests.csproj +++ b/src/Humanizer.Tests/Humanizer.Tests.csproj @@ -141,6 +141,7 @@ + diff --git a/src/Humanizer.Tests/Localisation/it/TimeSpanHumanizeTests.cs b/src/Humanizer.Tests/Localisation/it/TimeSpanHumanizeTests.cs new file mode 100644 index 000000000..f585709a9 --- /dev/null +++ b/src/Humanizer.Tests/Localisation/it/TimeSpanHumanizeTests.cs @@ -0,0 +1,66 @@ +using System; +using Xunit; +using Xunit.Extensions; + +namespace Humanizer.Tests.Localisation.it +{ + public class TimeSpanHumanizeTests : AmbientCulture + { + public TimeSpanHumanizeTests() : base("it") { } + + [Theory] + [InlineData(7, "1 settimana")] + [InlineData(14, "2 settimane")] + public void Weeks(int days, string expected) + { + Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); + } + + [Theory] + [InlineData(1, "1 giorno")] + [InlineData(2, "2 giorni")] + public void Days(int days, string expected) + { + Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); + } + + [Theory] + [InlineData(1, "1 ora")] + [InlineData(2, "2 ore")] + public void Hours(int hours, string expected) + { + Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); + } + + [Theory] + [InlineData(1, "1 minuto")] + [InlineData(2, "2 minuti")] + public void Minutes(int minutes, string expected) + { + Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); + } + + [Theory] + [InlineData(1, "1 secondo")] + [InlineData(2, "2 secondi")] + public void Seconds(int seconds, string expected) + { + Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); + } + + [Theory] + [InlineData(1, "1 millisecondo")] + [InlineData(2, "2 millisecondi")] + public void Milliseconds(int milliseconds, string expected) + { + Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); + } + + [Fact] + public void NoTime() + { + // This does not make much sense in italian, anyway + Assert.Equal("0 secondi", TimeSpan.Zero.Humanize()); + } + } +} \ No newline at end of file From f39506bd507c74ef2be027284543b8a19977095c Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Tue, 26 Aug 2014 02:06:32 +0200 Subject: [PATCH 09/39] L10n: italian CollectionFormatterTests passing --- src/Humanizer.Tests/Humanizer.Tests.csproj | 1 + .../it/CollectionFormatterTests.cs | 36 +++++++++++++++++++ .../ItalianCollectionFormatter.cs | 3 +- 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 src/Humanizer.Tests/Localisation/it/CollectionFormatterTests.cs diff --git a/src/Humanizer.Tests/Humanizer.Tests.csproj b/src/Humanizer.Tests/Humanizer.Tests.csproj index a1b2d526a..f43921d45 100644 --- a/src/Humanizer.Tests/Humanizer.Tests.csproj +++ b/src/Humanizer.Tests/Humanizer.Tests.csproj @@ -142,6 +142,7 @@ + diff --git a/src/Humanizer.Tests/Localisation/it/CollectionFormatterTests.cs b/src/Humanizer.Tests/Localisation/it/CollectionFormatterTests.cs new file mode 100644 index 000000000..63867869d --- /dev/null +++ b/src/Humanizer.Tests/Localisation/it/CollectionFormatterTests.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using Xunit; +using Xunit.Extensions; + +namespace Humanizer.Tests.Localisation.it +{ + public class CollectionFormatterTests : AmbientCulture + { + public CollectionFormatterTests() : base("it") { } + + [Fact] + public void OneItem() + { + var collection = new List(new int[] {1}); + string humanized = "1"; + Assert.Equal(humanized, collection.Humanize()); + } + + [Fact] + public void TwoItems() + { + var collection = new List(new int[] {1, 2}); + string humanized = "1 e 2"; + Assert.Equal(humanized, collection.Humanize()); + } + + [Fact] + public void MoreThanTwoItems() + { + var collection = new List(new int[] {1, 2, 3}); + string humanized = "1, 2, e 3"; + Assert.Equal(humanized, collection.Humanize()); + } + } +} \ No newline at end of file diff --git a/src/Humanizer/Localisation/CollectionFormatters/ItalianCollectionFormatter.cs b/src/Humanizer/Localisation/CollectionFormatters/ItalianCollectionFormatter.cs index 0be5f26c6..388cd9e78 100644 --- a/src/Humanizer/Localisation/CollectionFormatters/ItalianCollectionFormatter.cs +++ b/src/Humanizer/Localisation/CollectionFormatters/ItalianCollectionFormatter.cs @@ -7,8 +7,9 @@ namespace Humanizer.Localisation.CollectionFormatters internal class ItalianCollectionFormatter : EnglishCollectionFormatter { public ItalianCollectionFormatter() + : base() { - DefaultSeparator = "and"; + DefaultSeparator = "e"; } } } From 42a2f7e2902d373935bdc665714e759381667f66 Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Tue, 26 Aug 2014 02:14:08 +0200 Subject: [PATCH 10/39] L10n: in italian collections avoid last comma Comparing to english collection format, avoid last comma before default separator. --- .../it/CollectionFormatterTests.cs | 2 +- .../ItalianCollectionFormatter.cs | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/Humanizer.Tests/Localisation/it/CollectionFormatterTests.cs b/src/Humanizer.Tests/Localisation/it/CollectionFormatterTests.cs index 63867869d..32a9cbe38 100644 --- a/src/Humanizer.Tests/Localisation/it/CollectionFormatterTests.cs +++ b/src/Humanizer.Tests/Localisation/it/CollectionFormatterTests.cs @@ -29,7 +29,7 @@ public void TwoItems() public void MoreThanTwoItems() { var collection = new List(new int[] {1, 2, 3}); - string humanized = "1, 2, e 3"; + string humanized = "1, 2 e 3"; Assert.Equal(humanized, collection.Humanize()); } } diff --git a/src/Humanizer/Localisation/CollectionFormatters/ItalianCollectionFormatter.cs b/src/Humanizer/Localisation/CollectionFormatters/ItalianCollectionFormatter.cs index 388cd9e78..61f4667fa 100644 --- a/src/Humanizer/Localisation/CollectionFormatters/ItalianCollectionFormatter.cs +++ b/src/Humanizer/Localisation/CollectionFormatters/ItalianCollectionFormatter.cs @@ -11,5 +11,26 @@ public ItalianCollectionFormatter() { DefaultSeparator = "e"; } + + public override string Humanize(IEnumerable collection, Func objectFormatter, String separator) + { + if (collection == null) + throw new ArgumentException("collection"); + + var enumerable = collection as T[] ?? collection.ToArray(); + + int count = enumerable.Count(); + + if (count == 0) + return ""; + + if (count == 1) + return objectFormatter(enumerable.First()); + + return String.Format("{0} {1} {2}", + String.Join(", ", enumerable.Take(count - 1).Select(objectFormatter)), + separator, + objectFormatter(enumerable.Skip(count - 1).First())); + } } } From bcbadfec3861b1b9c65f3b2e6effbed79da6818f Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Tue, 26 Aug 2014 02:16:23 +0200 Subject: [PATCH 11/39] L10n: Refactored italian CollectionFormatterTests --- .../CollectionFormatters/ItalianCollectionFormatter.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Humanizer/Localisation/CollectionFormatters/ItalianCollectionFormatter.cs b/src/Humanizer/Localisation/CollectionFormatters/ItalianCollectionFormatter.cs index 61f4667fa..29cc49e21 100644 --- a/src/Humanizer/Localisation/CollectionFormatters/ItalianCollectionFormatter.cs +++ b/src/Humanizer/Localisation/CollectionFormatters/ItalianCollectionFormatter.cs @@ -27,10 +27,13 @@ public override string Humanize(IEnumerable collection, Func ob if (count == 1) return objectFormatter(enumerable.First()); + var frontItems = enumerable.Take(count - 1); + var tailItem = enumerable.Skip(count - 1).First(); + return String.Format("{0} {1} {2}", - String.Join(", ", enumerable.Take(count - 1).Select(objectFormatter)), + String.Join(", ", frontItems.Select(objectFormatter)), separator, - objectFormatter(enumerable.Skip(count - 1).First())); + objectFormatter(tailItem)); } } } From d413baea65d67c5cf9245085311d0b3e2485032a Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Tue, 26 Aug 2014 02:31:45 +0200 Subject: [PATCH 12/39] Readme: fixed ToOrdinalWords in place of Ordinalize --- readme.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/readme.md b/readme.md index ff4bceb5f..a886cd722 100644 --- a/readme.md +++ b/readme.md @@ -467,12 +467,12 @@ The possible values are `GrammaticalGender.Masculine`, `GrammaticalGender.Femini ```C# // for Brazilian Portuguese locale -1.ToOrdinalWords(GrammaticalGender.Masculine) => "1º" -1.ToOrdinalWords(GrammaticalGender.Feminine) => "1ª" -1.ToOrdinalWords(GrammaticalGender.Neuter) => "1º" -"2".ToOrdinalWords(GrammaticalGender.Masculine) => "2º" -"2".ToOrdinalWords(GrammaticalGender.Feminine) => "2ª" -"2".ToOrdinalWords(GrammaticalGender.Neuter) => "2º" +1.Ordinalize(GrammaticalGender.Masculine) => "1º" +1.Ordinalize(GrammaticalGender.Feminine) => "1ª" +1.Ordinalize(GrammaticalGender.Neuter) => "1º" +"2".Ordinalize(GrammaticalGender.Masculine) => "2º" +"2".Ordinalize(GrammaticalGender.Feminine) => "2ª" +"2".Ordinalize(GrammaticalGender.Neuter) => "2º" ``` Obviously this only applies to some cultures. For others passing gender in or not passing at all doesn't make any difference in the result. From eebaabdb2205ef4e87729fa3c88ce46d1f765290 Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Tue, 26 Aug 2014 02:55:37 +0200 Subject: [PATCH 13/39] L10n: added italian OrdinalizerTests --- src/Humanizer.Tests/Humanizer.Tests.csproj | 1 + .../Localisation/it/OrdinalizerTests.cs | 42 +++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 src/Humanizer.Tests/Localisation/it/OrdinalizerTests.cs diff --git a/src/Humanizer.Tests/Humanizer.Tests.csproj b/src/Humanizer.Tests/Humanizer.Tests.csproj index f43921d45..311f58d65 100644 --- a/src/Humanizer.Tests/Humanizer.Tests.csproj +++ b/src/Humanizer.Tests/Humanizer.Tests.csproj @@ -143,6 +143,7 @@ + diff --git a/src/Humanizer.Tests/Localisation/it/OrdinalizerTests.cs b/src/Humanizer.Tests/Localisation/it/OrdinalizerTests.cs new file mode 100644 index 000000000..30abdacb3 --- /dev/null +++ b/src/Humanizer.Tests/Localisation/it/OrdinalizerTests.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using Xunit; +using Xunit.Extensions; + +namespace Humanizer.Tests.Localisation.it +{ + public class OrdinalizerTests : AmbientCulture + { + public OrdinalizerTests() : base("it") { } + + [Theory] + [InlineData(0, "0")] // No ordinal for 0 in italian (neologism apart) + [InlineData(1, "1°")] + [InlineData(11, "11°")] + [InlineData(111, "111°")] + public void Genderless(int number, string expected) + { + Assert.Equal(expected, number.Ordinalize()); + } + + [Theory] + [InlineData(0, "0")] // No ordinal for 0 in italian (neologism apart) + [InlineData(1, "1°")] + [InlineData(11, "11°")] + [InlineData(111, "111°")] + public void Masculine(int number, string expected) + { + Assert.Equal(expected, number.Ordinalize(GrammaticalGender.Masculine)); + } + + [Theory] + [InlineData(0, "0")] // No ordinal for 0 in italian (neologism apart) + [InlineData(1, "1ª")] + [InlineData(11, "11ª")] + [InlineData(111, "111ª")] + public void Feminine(int number, string expected) + { + Assert.Equal(expected, number.Ordinalize(GrammaticalGender.Feminine)); + } + } +} \ No newline at end of file From 3946dee2ce1590f2e16cc800080b55e67d03a807 Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Tue, 26 Aug 2014 02:56:18 +0200 Subject: [PATCH 14/39] L10n: italian OrdinalizerTests passing --- .../Configuration/OrdinalizerRegistry.cs | 5 +++-- src/Humanizer/Humanizer.csproj | 1 + .../Ordinalizers/ItalianOrdinalizer.cs | 22 +++++++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 src/Humanizer/Localisation/Ordinalizers/ItalianOrdinalizer.cs diff --git a/src/Humanizer/Configuration/OrdinalizerRegistry.cs b/src/Humanizer/Configuration/OrdinalizerRegistry.cs index 53634461f..a7fcdc555 100644 --- a/src/Humanizer/Configuration/OrdinalizerRegistry.cs +++ b/src/Humanizer/Configuration/OrdinalizerRegistry.cs @@ -6,11 +6,12 @@ internal class OrdinalizerRegistry : LocaliserRegistry { public OrdinalizerRegistry() : base(new DefaultOrdinalizer()) { + Register("de", new GermanOrdinalizer()); Register("en", new EnglishOrdinalizer()); Register("es", new SpanishOrdinalizer()); - Register("ru", new RussianOrdinalizer()); + Register("it", new ItalianOrdinalizer()); Register("pt-BR", new BrazilianPortugueseOrdinalizer()); - Register("de", new GermanOrdinalizer()); + Register("ru", new RussianOrdinalizer()); Register("tr", new TurkishOrdinalizer()); } } diff --git a/src/Humanizer/Humanizer.csproj b/src/Humanizer/Humanizer.csproj index 63c1c8425..16ea29598 100644 --- a/src/Humanizer/Humanizer.csproj +++ b/src/Humanizer/Humanizer.csproj @@ -101,6 +101,7 @@ + diff --git a/src/Humanizer/Localisation/Ordinalizers/ItalianOrdinalizer.cs b/src/Humanizer/Localisation/Ordinalizers/ItalianOrdinalizer.cs new file mode 100644 index 000000000..3681ff273 --- /dev/null +++ b/src/Humanizer/Localisation/Ordinalizers/ItalianOrdinalizer.cs @@ -0,0 +1,22 @@ +namespace Humanizer.Localisation.Ordinalizers +{ + internal class ItalianOrdinalizer : DefaultOrdinalizer + { + public override string Convert(int number, string numberString) + { + return Convert(number, numberString, GrammaticalGender.Masculine); + } + + public override string Convert(int number, string numberString, GrammaticalGender gender) + { + // No ordinal for 0 in italian (neologism apart) + if (number == 0) + return "0"; + + if (gender == GrammaticalGender.Feminine) + return numberString + "ª"; + + return numberString + "°"; + } + } +} \ No newline at end of file From 55a61f3b87d595ba359ecf8cbb793d8e6184e9d6 Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Tue, 26 Aug 2014 03:04:00 +0200 Subject: [PATCH 15/39] L10: italian OrdinalizerTests passing with text input Also: code formatting on base constructor invocation. --- .../it/CollectionFormatterTests.cs | 5 ++- .../Localisation/it/DateHumanizeTests.cs | 2 +- .../Localisation/it/OrdinalizerTests.cs | 41 +++++++++++++++++-- .../Localisation/it/TimeSpanHumanizeTests.cs | 5 ++- 4 files changed, 46 insertions(+), 7 deletions(-) diff --git a/src/Humanizer.Tests/Localisation/it/CollectionFormatterTests.cs b/src/Humanizer.Tests/Localisation/it/CollectionFormatterTests.cs index 32a9cbe38..a0a279627 100644 --- a/src/Humanizer.Tests/Localisation/it/CollectionFormatterTests.cs +++ b/src/Humanizer.Tests/Localisation/it/CollectionFormatterTests.cs @@ -7,7 +7,10 @@ namespace Humanizer.Tests.Localisation.it { public class CollectionFormatterTests : AmbientCulture { - public CollectionFormatterTests() : base("it") { } + public CollectionFormatterTests() + : base("it") + { + } [Fact] public void OneItem() diff --git a/src/Humanizer.Tests/Localisation/it/DateHumanizeTests.cs b/src/Humanizer.Tests/Localisation/it/DateHumanizeTests.cs index 1e42766dd..4fd1cbda9 100644 --- a/src/Humanizer.Tests/Localisation/it/DateHumanizeTests.cs +++ b/src/Humanizer.Tests/Localisation/it/DateHumanizeTests.cs @@ -8,7 +8,7 @@ namespace Humanizer.Tests.Localisation.it public class DateHumanizeTests : AmbientCulture { public DateHumanizeTests() - : base("it") + : base("it") { } diff --git a/src/Humanizer.Tests/Localisation/it/OrdinalizerTests.cs b/src/Humanizer.Tests/Localisation/it/OrdinalizerTests.cs index 30abdacb3..8a9873b31 100644 --- a/src/Humanizer.Tests/Localisation/it/OrdinalizerTests.cs +++ b/src/Humanizer.Tests/Localisation/it/OrdinalizerTests.cs @@ -7,14 +7,27 @@ namespace Humanizer.Tests.Localisation.it { public class OrdinalizerTests : AmbientCulture { - public OrdinalizerTests() : base("it") { } + public OrdinalizerTests() + : base("it") + { + } [Theory] [InlineData(0, "0")] // No ordinal for 0 in italian (neologism apart) [InlineData(1, "1°")] [InlineData(11, "11°")] [InlineData(111, "111°")] - public void Genderless(int number, string expected) + public void GenderlessNumber(int number, string expected) + { + Assert.Equal(expected, number.Ordinalize()); + } + + [Theory] + [InlineData("0", "0")] // No ordinal for 0 in italian (neologism apart) + [InlineData("1", "1°")] + [InlineData("11", "11°")] + [InlineData("111", "111°")] + public void GenderlessText(string number, string expected) { Assert.Equal(expected, number.Ordinalize()); } @@ -24,7 +37,17 @@ public void Genderless(int number, string expected) [InlineData(1, "1°")] [InlineData(11, "11°")] [InlineData(111, "111°")] - public void Masculine(int number, string expected) + public void MasculineNumber(int number, string expected) + { + Assert.Equal(expected, number.Ordinalize(GrammaticalGender.Masculine)); + } + + [Theory] + [InlineData("0", "0")] // No ordinal for 0 in italian (neologism apart) + [InlineData("1", "1°")] + [InlineData("11", "11°")] + [InlineData("111", "111°")] + public void MasculineText(string number, string expected) { Assert.Equal(expected, number.Ordinalize(GrammaticalGender.Masculine)); } @@ -34,7 +57,17 @@ public void Masculine(int number, string expected) [InlineData(1, "1ª")] [InlineData(11, "11ª")] [InlineData(111, "111ª")] - public void Feminine(int number, string expected) + public void FeminineNumber(int number, string expected) + { + Assert.Equal(expected, number.Ordinalize(GrammaticalGender.Feminine)); + } + + [Theory] + [InlineData("0", "0")] // No ordinal for 0 in italian (neologism apart) + [InlineData("1", "1ª")] + [InlineData("11", "11ª")] + [InlineData("111", "111ª")] + public void FeminineText(string number, string expected) { Assert.Equal(expected, number.Ordinalize(GrammaticalGender.Feminine)); } diff --git a/src/Humanizer.Tests/Localisation/it/TimeSpanHumanizeTests.cs b/src/Humanizer.Tests/Localisation/it/TimeSpanHumanizeTests.cs index f585709a9..b025bb5c3 100644 --- a/src/Humanizer.Tests/Localisation/it/TimeSpanHumanizeTests.cs +++ b/src/Humanizer.Tests/Localisation/it/TimeSpanHumanizeTests.cs @@ -6,7 +6,10 @@ namespace Humanizer.Tests.Localisation.it { public class TimeSpanHumanizeTests : AmbientCulture { - public TimeSpanHumanizeTests() : base("it") { } + public TimeSpanHumanizeTests() + : base("it") + { + } [Theory] [InlineData(7, "1 settimana")] From 793139fc663d0537537390d585b5c85f9df997d1 Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Tue, 26 Aug 2014 06:46:06 +0200 Subject: [PATCH 16/39] L10n: added initial italian NumberToWordsConverter --- src/Humanizer.Tests/Humanizer.Tests.csproj | 1 + .../Localisation/it/NumberToWordsTests.cs | 201 ++++++++++++++++ .../NumberToWordsConverterRegistry.cs | 1 + src/Humanizer/Humanizer.csproj | 1 + .../ItalianNumberToWordsConverter.cs | 219 ++++++++++++++++++ 5 files changed, 423 insertions(+) create mode 100644 src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs create mode 100644 src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs diff --git a/src/Humanizer.Tests/Humanizer.Tests.csproj b/src/Humanizer.Tests/Humanizer.Tests.csproj index 311f58d65..3d57cc267 100644 --- a/src/Humanizer.Tests/Humanizer.Tests.csproj +++ b/src/Humanizer.Tests/Humanizer.Tests.csproj @@ -144,6 +144,7 @@ + diff --git a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs new file mode 100644 index 000000000..fb9e0aabf --- /dev/null +++ b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs @@ -0,0 +1,201 @@ +using Xunit; +using Xunit.Extensions; + +namespace Humanizer.Tests.Localisation.it +{ + public class NumberToWordsTests : AmbientCulture + { + public NumberToWordsTests() + : base("it") + { + } + + [Theory] + [InlineData(0, "zero")] + [InlineData(1, "uno")] + [InlineData(10, "dieci")] + [InlineData(11, "undici")] + [InlineData(21, "ventuno")] + /* + [InlineData(-1, "meno uno")] + [InlineData(122, "centoventidue")] + [InlineData(3501, "tremilacinquecentouno")] + [InlineData(100, "cento")] + [InlineData(1000, "mille")] + [InlineData(100000, "centomila")] + [InlineData(1000000, "un milione")] + [InlineData(10000000, "dieci milioni")] + [InlineData(100000000, "cento milioni")] + [InlineData(1000000000, "un miliardo")] + [InlineData(111, "centoundici")] + [InlineData(1111, "millecentoundici")] + [InlineData(111111, "centoundicimilacentoundici")] + [InlineData(1111101, "un milione centoundicimilacentouno")] + [InlineData(1111111, "un milione centoundicimilacentoundici")] + [InlineData(11111111, "undici milioni centoundicimilacentoundici")] + [InlineData(111111111, "centoundici milioni centoundicimilacentoundici")] + [InlineData(1101111101, "un miliardo centouno milioni centoundicimilacentouno")] + [InlineData(1111111111, "un miliardo centoundici milioni centoundicimilacentoundici")] + [InlineData(123, "centoventitré")] + [InlineData(1234, "milleduecentotrentaquattro")] + [InlineData(8100, "ottomilacento")] + [InlineData(12345, "dodicimilatrecentoquarantacinque")] + [InlineData(123456, "centoventitremilaquattrocentocinquantasei")] + [InlineData(1234567, "un milione duecentotrentaquattromilacinquecentosessantasette")] + [InlineData(12345678, "dodici milioni trecentoquarantacinquemilaseicentosettantotto")] + [InlineData(123456789, "centoventitrè milioni quattrocentocinquantaseimilasettecentoottantanove")] + [InlineData(1234567890, "un miliardo duecentotrentaquattromilioni cinquecentosessantasettemilaottocentonovanta")] + [InlineData(1999, "millenovecentonovantanove")] + [InlineData(2014, "duemilaquattordici")] + [InlineData(2048, "duemilaquarantotto")] + */ + public void ToWords(int number, string expected) + { + Assert.Equal(expected, number.ToWords()); + } + + /* + [Theory] + [InlineData(1, "uma")] + [InlineData(2, "duas")] + [InlineData(3, "três")] + [InlineData(11, "onze")] + [InlineData(21, "vinte e uma")] + [InlineData(122, "cento e vinte e duas")] + [InlineData(232, "duzentas e trinta e duas")] + [InlineData(343, "trezentas e quarenta e três")] + [InlineData(3501, "três mil quinhentas e uma")] + [InlineData(100, "cem")] + [InlineData(1000, "mil")] + [InlineData(111, "cento e onze")] + [InlineData(1111, "mil cento e onze")] + [InlineData(111111, "cento e onze mil cento e onze")] + [InlineData(1111101, "um milhão cento e onze mil cento e uma")] + [InlineData(1111111, "um milhão cento e onze mil cento e onze")] + [InlineData(1101111101, "um bilhão cento e um milhões cento e onze mil cento e uma")] + [InlineData(1234, "mil duzentas e trinta e quatro")] + [InlineData(8100, "oito mil e cem")] + [InlineData(12345, "doze mil trezentas e quarenta e cinco")] + public void ToFeminineWords(int number, string expected) + { + Assert.Equal(expected, number.ToWords(GrammaticalGender.Feminine)); + } + + [Theory] + [InlineData(0, "zero")] + [InlineData(1, "primeiro")] + [InlineData(2, "segundo")] + [InlineData(3, "terceiro")] + [InlineData(4, "quarto")] + [InlineData(5, "quinto")] + [InlineData(6, "sexto")] + [InlineData(7, "sétimo")] + [InlineData(8, "oitavo")] + [InlineData(9, "nono")] + [InlineData(10, "décimo")] + [InlineData(11, "décimo primeiro")] + [InlineData(12, "décimo segundo")] + [InlineData(13, "décimo terceiro")] + [InlineData(14, "décimo quarto")] + [InlineData(15, "décimo quinto")] + [InlineData(16, "décimo sexto")] + [InlineData(17, "décimo sétimo")] + [InlineData(18, "décimo oitavo")] + [InlineData(19, "décimo nono")] + [InlineData(20, "vigésimo")] + [InlineData(21, "vigésimo primeiro")] + [InlineData(22, "vigésimo segundo")] + [InlineData(30, "trigésimo")] + [InlineData(40, "quadragésimo")] + [InlineData(50, "quinquagésimo")] + [InlineData(60, "sexagésimo")] + [InlineData(70, "septuagésimo")] + [InlineData(80, "octogésimo")] + [InlineData(90, "nonagésimo")] + [InlineData(95, "nonagésimo quinto")] + [InlineData(96, "nonagésimo sexto")] + [InlineData(100, "centésimo")] + [InlineData(120, "centésimo vigésimo")] + [InlineData(121, "centésimo vigésimo primeiro")] + [InlineData(200, "ducentésimo")] + [InlineData(300, "trecentésimo")] + [InlineData(400, "quadringentésimo")] + [InlineData(500, "quingentésimo")] + [InlineData(600, "sexcentésimo")] + [InlineData(700, "septingentésimo")] + [InlineData(800, "octingentésimo")] + [InlineData(900, "noningentésimo")] + [InlineData(1000, "milésimo")] + [InlineData(1001, "milésimo primeiro")] + [InlineData(1021, "milésimo vigésimo primeiro")] + [InlineData(2021, "segundo milésimo vigésimo primeiro")] + [InlineData(10000, "décimo milésimo")] + [InlineData(10121, "décimo milésimo centésimo vigésimo primeiro")] + [InlineData(100000, "centésimo milésimo")] + [InlineData(1000000, "milionésimo")] + [InlineData(1000000000, "bilionésimo")] + public void ToOrdinalWords(int number, string words) + { + Assert.Equal(words, number.ToOrdinalWords()); + } + + [Theory] + [InlineData(0, "zero")] + [InlineData(1, "primeira")] + [InlineData(2, "segunda")] + [InlineData(3, "terceira")] + [InlineData(4, "quarta")] + [InlineData(5, "quinta")] + [InlineData(6, "sexta")] + [InlineData(7, "sétima")] + [InlineData(8, "oitava")] + [InlineData(9, "nona")] + [InlineData(10, "décima")] + [InlineData(11, "décima primeira")] + [InlineData(12, "décima segunda")] + [InlineData(13, "décima terceira")] + [InlineData(14, "décima quarta")] + [InlineData(15, "décima quinta")] + [InlineData(16, "décima sexta")] + [InlineData(17, "décima sétima")] + [InlineData(18, "décima oitava")] + [InlineData(19, "décima nona")] + [InlineData(20, "vigésima")] + [InlineData(21, "vigésima primeira")] + [InlineData(22, "vigésima segunda")] + [InlineData(30, "trigésima")] + [InlineData(40, "quadragésima")] + [InlineData(50, "quinquagésima")] + [InlineData(60, "sexagésima")] + [InlineData(70, "septuagésima")] + [InlineData(80, "octogésima")] + [InlineData(90, "nonagésima")] + [InlineData(95, "nonagésima quinta")] + [InlineData(96, "nonagésima sexta")] + [InlineData(100, "centésima")] + [InlineData(120, "centésima vigésima")] + [InlineData(121, "centésima vigésima primeira")] + [InlineData(200, "ducentésima")] + [InlineData(300, "trecentésima")] + [InlineData(400, "quadringentésima")] + [InlineData(500, "quingentésima")] + [InlineData(600, "sexcentésima")] + [InlineData(700, "septingentésima")] + [InlineData(800, "octingentésima")] + [InlineData(900, "noningentésima")] + [InlineData(1000, "milésima")] + [InlineData(1001, "milésima primeira")] + [InlineData(1021, "milésima vigésima primeira")] + [InlineData(2021, "segunda milésima vigésima primeira")] + [InlineData(10000, "décima milésima")] + [InlineData(10121, "décima milésima centésima vigésima primeira")] + [InlineData(100000, "centésima milésima")] + [InlineData(1000000, "milionésima")] + [InlineData(1000000000, "bilionésima")] + public void ToFeminineOrdinalWords(int number, string words) + { + Assert.Equal(words, number.ToOrdinalWords(GrammaticalGender.Feminine)); + } + */ + } +} \ No newline at end of file diff --git a/src/Humanizer/Configuration/NumberToWordsConverterRegistry.cs b/src/Humanizer/Configuration/NumberToWordsConverterRegistry.cs index 07d9c270b..52efb010c 100644 --- a/src/Humanizer/Configuration/NumberToWordsConverterRegistry.cs +++ b/src/Humanizer/Configuration/NumberToWordsConverterRegistry.cs @@ -20,6 +20,7 @@ internal class NumberToWordsConverterRegistry : LocaliserRegistry + diff --git a/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs new file mode 100644 index 000000000..07ef3825b --- /dev/null +++ b/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs @@ -0,0 +1,219 @@ +using System; +using System.Collections.Generic; + +namespace Humanizer.Localisation.NumberToWords +{ + internal class ItalianNumberToWordsConverter : GenderedNumberToWordsConverter + { + public override string Convert(int number, GrammaticalGender gender) + { + if (number == 0) + return "zero"; + + ItalianNumberCruncher cruncher = new ItalianNumberCruncher(number); + + return cruncher.Convert(); + } + + public override string ConvertToOrdinal(int number, GrammaticalGender gender) + { + return String.Empty; + } + + class ItalianNumberCruncher + { + public ItalianNumberCruncher(int number) + { + _number = number; + } + + public string Convert() + { + string word = String.Empty; + + List threeDigitChops = ThreeDigitChop(_number); + + ThreeDigitSequenceConverter sequenceConverter = new ThreeDigitSequenceConverter(); + + foreach(int chop in threeDigitChops) + { + Func chopToString = sequenceConverter.GetNext(); + + word += chopToString(chop); + } + + return word; + } + + protected string ThreeDigitConvert(int threeDigit) + { + return threeDigit.ToString(); + } + + protected readonly int _number; + + protected static List ThreeDigitChop(int number) + { + List chops = new List(); + int rest = number; + + while (rest > 0) + { + int threeDigit = rest % 1000; + + chops.Add(threeDigit); + + rest = (int)(rest / 1000); + } + + chops.Reverse(); + + return chops; + } + + class ThreeDigitSequenceConverter + { + public ThreeDigitSequenceConverter() + { + _nextSet = ThreeDigitSets.Units; + } + + public Func GetNext() + { + Func converter; + + switch (_nextSet) + { + case ThreeDigitSets.Units: + converter = UnitsConverter; + _nextSet = ThreeDigitSets.Thousands; + break; + + case ThreeDigitSets.Thousands: + converter = null; + break; + + case ThreeDigitSets.Millions: + converter = null; + break; + + case ThreeDigitSets.Billions: + converter = null; + break; + + case ThreeDigitSets.More: + converter = null; + break; + + default: + throw new ArgumentOutOfRangeException("Unknow ThreeDigitSet: " + _nextSet); + } + + return converter; + } + + protected string UnitsConverter(int number) + { + int tensAndUnits = number % 100; + int hundreds = (int)(number / 100); + + int units = tensAndUnits % 10; + int tens = (int)(tensAndUnits / 10); + + string words = String.Empty; + + words += _numberToHundred[hundreds]; + + words += _numberToTen[tens]; + + if (tensAndUnits <= 9) + { + words += _numberToUnit[tensAndUnits]; + } + else if (tensAndUnits <= 19) + { + words += _numberToTeens[tensAndUnits - 10]; + } + else + { + if (units == 1 || units == 8) + { + words = words.Remove(words.Length - 1); + } + + words += _numberToUnit[units]; + } + + return words; + } + + protected ThreeDigitSets _nextSet; + + protected static string[] _numberToUnit = new string[] + { + String.Empty, + "uno", + "due", + "tre", + "quattro", + "cinque", + "sei", + "sette", + "otto", + "nove" + }; + + protected static string[] _numberToTen = new string[] + { + String.Empty, + String.Empty, + "venti", + "trenta", + "quaranta", + "cinquanta", + "sessanta", + "settanta", + "ottanta", + "novanta" + }; + + protected static string[] _numberToTeens = new string[] + { + "dieci", + "undici", + "dodici", + "tredici", + "quattordici", + "quindici", + "sedici", + "diciassette", + "diciotto", + "diciannove" + }; + + protected static string[] _numberToHundred = new string[] + { + String.Empty, + "cento", + "duecento", + "trecento", + "quattrocento", + "cinquecento", + "seicento", + "settecento", + "ottocento", + "novecento" + }; + + protected enum ThreeDigitSets + { + Units, + Thousands, + Millions, + Billions, + More + } + } + } + } +} \ No newline at end of file From 103f6d22f51e4dac07d3fbd36c23f8377d4142a9 Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Tue, 26 Aug 2014 15:33:32 +0200 Subject: [PATCH 17/39] L10n: italian NumberToWordsTests passing for thousand and negative --- .../Localisation/it/NumberToWordsTests.cs | 5 ++-- .../ItalianNumberToWordsConverter.cs | 28 ++++++++++--------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs index fb9e0aabf..8232cf951 100644 --- a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs +++ b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs @@ -13,13 +13,14 @@ public NumberToWordsTests() [Theory] [InlineData(0, "zero")] [InlineData(1, "uno")] + [InlineData(-1, "meno uno")] [InlineData(10, "dieci")] [InlineData(11, "undici")] [InlineData(21, "ventuno")] - /* - [InlineData(-1, "meno uno")] + [InlineData(38, "trentotto")] [InlineData(122, "centoventidue")] [InlineData(3501, "tremilacinquecentouno")] + /* [InlineData(100, "cento")] [InlineData(1000, "mille")] [InlineData(100000, "centomila")] diff --git a/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs index 07ef3825b..837c977f2 100644 --- a/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs +++ b/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs @@ -8,7 +8,10 @@ internal class ItalianNumberToWordsConverter : GenderedNumberToWordsConverter public override string Convert(int number, GrammaticalGender gender) { if (number == 0) - return "zero"; + return "zero"; + + if (number < 0) + return "meno " + Convert(Math.Abs(number), gender); ItalianNumberCruncher cruncher = new ItalianNumberCruncher(number); @@ -31,7 +34,7 @@ public string Convert() { string word = String.Empty; - List threeDigitChops = ThreeDigitChop(_number); + List threeDigitChops = ChopEveryThreeDigits(_number); ThreeDigitSequenceConverter sequenceConverter = new ThreeDigitSequenceConverter(); @@ -39,20 +42,15 @@ public string Convert() { Func chopToString = sequenceConverter.GetNext(); - word += chopToString(chop); + word = chopToString(chop) + word; } return word; } - protected string ThreeDigitConvert(int threeDigit) - { - return threeDigit.ToString(); - } - protected readonly int _number; - protected static List ThreeDigitChop(int number) + protected static List ChopEveryThreeDigits(int number) { List chops = new List(); int rest = number; @@ -66,8 +64,6 @@ protected static List ThreeDigitChop(int number) rest = (int)(rest / 1000); } - chops.Reverse(); - return chops; } @@ -90,7 +86,8 @@ public Func GetNext() break; case ThreeDigitSets.Thousands: - converter = null; + converter = ThousandsConverter; + _nextSet = ThreeDigitSets.Millions; break; case ThreeDigitSets.Millions: @@ -112,7 +109,7 @@ public Func GetNext() return converter; } - protected string UnitsConverter(int number) + protected static string UnitsConverter(int number) { int tensAndUnits = number % 100; int hundreds = (int)(number / 100); @@ -147,6 +144,11 @@ protected string UnitsConverter(int number) return words; } + protected static string ThousandsConverter(int number) + { + return UnitsConverter(number) + "mila"; + } + protected ThreeDigitSets _nextSet; protected static string[] _numberToUnit = new string[] From d113e6b0f42cc03933df4a847e76651e821ccfbc Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Tue, 26 Aug 2014 15:39:42 +0200 Subject: [PATCH 18/39] L10n: Refactor: removed inner class in ItalianNumberToWordsConverter --- .../ItalianNumberToWordsConverter.cs | 271 +++++++++--------- 1 file changed, 131 insertions(+), 140 deletions(-) diff --git a/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs index 837c977f2..47f2f3f94 100644 --- a/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs +++ b/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs @@ -28,19 +28,17 @@ class ItalianNumberCruncher public ItalianNumberCruncher(int number) { _number = number; + _threeDigitChops = ChopEveryThreeDigits(_number); + _nextSet = ThreeDigitSets.Units; } public string Convert() { string word = String.Empty; - List threeDigitChops = ChopEveryThreeDigits(_number); - - ThreeDigitSequenceConverter sequenceConverter = new ThreeDigitSequenceConverter(); - - foreach(int chop in threeDigitChops) + foreach(int chop in _threeDigitChops) { - Func chopToString = sequenceConverter.GetNext(); + Func chopToString = GetNextChopConverter(); word = chopToString(chop) + word; } @@ -49,6 +47,9 @@ public string Convert() } protected readonly int _number; + protected readonly List _threeDigitChops; + + protected ThreeDigitSets _nextSet; protected static List ChopEveryThreeDigits(int number) { @@ -67,154 +68,144 @@ protected static List ChopEveryThreeDigits(int number) return chops; } - class ThreeDigitSequenceConverter + public Func GetNextChopConverter() { - public ThreeDigitSequenceConverter() - { - _nextSet = ThreeDigitSets.Units; - } + Func converter; - public Func GetNext() + switch (_nextSet) { - Func converter; - - switch (_nextSet) - { - case ThreeDigitSets.Units: - converter = UnitsConverter; - _nextSet = ThreeDigitSets.Thousands; - break; - - case ThreeDigitSets.Thousands: - converter = ThousandsConverter; - _nextSet = ThreeDigitSets.Millions; - break; - - case ThreeDigitSets.Millions: - converter = null; - break; - - case ThreeDigitSets.Billions: - converter = null; - break; - - case ThreeDigitSets.More: - converter = null; - break; - - default: - throw new ArgumentOutOfRangeException("Unknow ThreeDigitSet: " + _nextSet); - } - - return converter; - } - - protected static string UnitsConverter(int number) - { - int tensAndUnits = number % 100; - int hundreds = (int)(number / 100); - - int units = tensAndUnits % 10; - int tens = (int)(tensAndUnits / 10); - - string words = String.Empty; - - words += _numberToHundred[hundreds]; - - words += _numberToTen[tens]; - - if (tensAndUnits <= 9) - { - words += _numberToUnit[tensAndUnits]; - } - else if (tensAndUnits <= 19) - { - words += _numberToTeens[tensAndUnits - 10]; - } - else - { - if (units == 1 || units == 8) - { - words = words.Remove(words.Length - 1); - } + case ThreeDigitSets.Units: + converter = UnitsConverter; + _nextSet = ThreeDigitSets.Thousands; + break; - words += _numberToUnit[units]; - } - - return words; + case ThreeDigitSets.Thousands: + converter = ThousandsConverter; + _nextSet = ThreeDigitSets.Millions; + break; + + case ThreeDigitSets.Millions: + converter = null; + break; + + case ThreeDigitSets.Billions: + converter = null; + break; + + case ThreeDigitSets.More: + converter = null; + break; + + default: + throw new ArgumentOutOfRangeException("Unknow ThreeDigitSet: " + _nextSet); } - protected static string ThousandsConverter(int number) - { - return UnitsConverter(number) + "mila"; - } + return converter; + } + + protected static string UnitsConverter(int number) + { + int tensAndUnits = number % 100; + int hundreds = (int)(number / 100); - protected ThreeDigitSets _nextSet; + int units = tensAndUnits % 10; + int tens = (int)(tensAndUnits / 10); - protected static string[] _numberToUnit = new string[] - { - String.Empty, - "uno", - "due", - "tre", - "quattro", - "cinque", - "sei", - "sette", - "otto", - "nove" - }; + string words = String.Empty; - protected static string[] _numberToTen = new string[] - { - String.Empty, - String.Empty, - "venti", - "trenta", - "quaranta", - "cinquanta", - "sessanta", - "settanta", - "ottanta", - "novanta" - }; + words += _numberToHundred[hundreds]; - protected static string[] _numberToTeens = new string[] - { - "dieci", - "undici", - "dodici", - "tredici", - "quattordici", - "quindici", - "sedici", - "diciassette", - "diciotto", - "diciannove" - }; + words += _numberToTen[tens]; - protected static string[] _numberToHundred = new string[] + if (tensAndUnits <= 9) { - String.Empty, - "cento", - "duecento", - "trecento", - "quattrocento", - "cinquecento", - "seicento", - "settecento", - "ottocento", - "novecento" - }; - - protected enum ThreeDigitSets + words += _numberToUnit[tensAndUnits]; + } + else if (tensAndUnits <= 19) { - Units, - Thousands, - Millions, - Billions, - More + words += _numberToTeens[tensAndUnits - 10]; } + else + { + if (units == 1 || units == 8) + { + words = words.Remove(words.Length - 1); + } + + words += _numberToUnit[units]; + } + + return words; + } + + protected static string ThousandsConverter(int number) + { + return UnitsConverter(number) + "mila"; + } + + protected static string[] _numberToUnit = new string[] + { + String.Empty, + "uno", + "due", + "tre", + "quattro", + "cinque", + "sei", + "sette", + "otto", + "nove" + }; + + protected static string[] _numberToTen = new string[] + { + String.Empty, + String.Empty, + "venti", + "trenta", + "quaranta", + "cinquanta", + "sessanta", + "settanta", + "ottanta", + "novanta" + }; + + protected static string[] _numberToTeens = new string[] + { + "dieci", + "undici", + "dodici", + "tredici", + "quattordici", + "quindici", + "sedici", + "diciassette", + "diciotto", + "diciannove" + }; + + protected static string[] _numberToHundred = new string[] + { + String.Empty, + "cento", + "duecento", + "trecento", + "quattrocento", + "cinquecento", + "seicento", + "settecento", + "ottocento", + "novecento" + }; + + protected enum ThreeDigitSets + { + Units, + Thousands, + Millions, + Billions, + More } } } From 19742d10a2b72aebc31e7ebac95e8fd6864f1b0d Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Tue, 26 Aug 2014 16:06:14 +0200 Subject: [PATCH 19/39] L10n: Refactor: added header comments and renamed identifiers. --- .../ItalianNumberToWordsConverter.cs | 91 +++++++++++++++---- 1 file changed, 73 insertions(+), 18 deletions(-) diff --git a/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs index 47f2f3f94..91edd1dbd 100644 --- a/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs +++ b/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs @@ -28,7 +28,7 @@ class ItalianNumberCruncher public ItalianNumberCruncher(int number) { _number = number; - _threeDigitChops = ChopEveryThreeDigits(_number); + _threeDigitParts = SplitEveryThreeDigits(_number); _nextSet = ThreeDigitSets.Units; } @@ -36,38 +36,49 @@ public string Convert() { string word = String.Empty; - foreach(int chop in _threeDigitChops) + foreach(int part in _threeDigitParts) { - Func chopToString = GetNextChopConverter(); + Func partToString = GetNextChopConverter(); - word = chopToString(chop) + word; + word = partToString(part) + word; } return word; } protected readonly int _number; - protected readonly List _threeDigitChops; + protected readonly List _threeDigitParts; protected ThreeDigitSets _nextSet; - protected static List ChopEveryThreeDigits(int number) + /// + /// Splits a number into a sequence of three-digits numbers, starting + /// from units, then thousands, millions, and so on. + /// + /// The number to split. + /// The sequence of three-digit numbers. + protected static List SplitEveryThreeDigits(int number) { - List chops = new List(); + List parts = new List(); int rest = number; while (rest > 0) { int threeDigit = rest % 1000; - chops.Add(threeDigit); + parts.Add(threeDigit); rest = (int)(rest / 1000); } - return chops; + return parts; } + /// + /// During number conversion to text, finds out the converter to use + /// for the next three-digit pack. + /// + /// The next conversion function to use. public Func GetNextChopConverter() { Func converter; @@ -103,6 +114,11 @@ public Func GetNextChopConverter() return converter; } + /// + /// Converts a three-digit number to text. + /// + /// The three-digit number to convert. + /// The same three-digit number expressed as text. protected static string UnitsConverter(int number) { int tensAndUnits = number % 100; @@ -113,17 +129,17 @@ protected static string UnitsConverter(int number) string words = String.Empty; - words += _numberToHundred[hundreds]; + words += _hundredNumberToText[hundreds]; - words += _numberToTen[tens]; + words += _tensNumberToText[tens]; if (tensAndUnits <= 9) { - words += _numberToUnit[tensAndUnits]; + words += _unitsNumberToText[tensAndUnits]; } else if (tensAndUnits <= 19) { - words += _numberToTeens[tensAndUnits - 10]; + words += _teensNumberToText[tensAndUnits - 10]; } else { @@ -132,18 +148,26 @@ protected static string UnitsConverter(int number) words = words.Remove(words.Length - 1); } - words += _numberToUnit[units]; + words += _unitsNumberToText[units]; } return words; } + /// + /// Converts a thousands three-digit number to text. + /// + /// The three-digit number, as thousands, to convert. + /// The same three-digit number of thousands expressed as text. protected static string ThousandsConverter(int number) { return UnitsConverter(number) + "mila"; } - protected static string[] _numberToUnit = new string[] + /// + /// Lookup table converting units number to text. Index 1 for 1, index 2 for 2, up to index 9. + /// + protected static string[] _unitsNumberToText = new string[] { String.Empty, "uno", @@ -157,7 +181,10 @@ protected static string ThousandsConverter(int number) "nove" }; - protected static string[] _numberToTen = new string[] + /// + /// Lookup table converting tens number to text. Index 2 for 20, index 3 for 30, up to index 9 for 90. + /// + protected static string[] _tensNumberToText = new string[] { String.Empty, String.Empty, @@ -171,7 +198,10 @@ protected static string ThousandsConverter(int number) "novanta" }; - protected static string[] _numberToTeens = new string[] + /// + /// Lookup table converting teens number to text. Index 0 for 10, index 1 for 11, up to index 9 for 19. + /// + protected static string[] _teensNumberToText = new string[] { "dieci", "undici", @@ -185,7 +215,10 @@ protected static string ThousandsConverter(int number) "diciannove" }; - protected static string[] _numberToHundred = new string[] + /// + /// Lookup table converting hundreds number to text. Index 0 for no hundreds, index 1 for 100, up to index 9. + /// + protected static string[] _hundredNumberToText = new string[] { String.Empty, "cento", @@ -199,12 +232,34 @@ protected static string ThousandsConverter(int number) "novecento" }; + /// + /// Enumerates sets of three-digits having distinct conversion to text. + /// protected enum ThreeDigitSets { + /// + /// Lowest three-digits set, from 1 to 999. + /// Units, + + /// + /// Three-digits set counting the thousands, from 1'000 to 999'000. + /// Thousands, + + /// + /// Three-digits set counting millions, from 1'000'000 to 999'000'000. + /// Millions, + + /// + /// Three-digits set counting billions, from 1'000'000'000 to 999'000'000'000. + /// Billions, + + /// + /// Three-digits set beyond 999 billions, from 1'000'000'000'000 onward. + /// More } } From 43cae6fd224a3fbcf03d3bafd5029d93c4ad67fc Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Tue, 26 Aug 2014 16:16:55 +0200 Subject: [PATCH 20/39] L10n: italian NumberToWordsTests passing for simple million numbers --- .../Localisation/it/NumberToWordsTests.cs | 5 +++- .../ItalianNumberToWordsConverter.cs | 24 +++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs index 8232cf951..1539b33f3 100644 --- a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs +++ b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs @@ -20,13 +20,16 @@ public NumberToWordsTests() [InlineData(38, "trentotto")] [InlineData(122, "centoventidue")] [InlineData(3501, "tremilacinquecentouno")] - /* [InlineData(100, "cento")] [InlineData(1000, "mille")] + [InlineData(2000, "duemila")] + [InlineData(10000, "diecimila")] [InlineData(100000, "centomila")] [InlineData(1000000, "un milione")] + [InlineData(5000000, "cinque milioni")] [InlineData(10000000, "dieci milioni")] [InlineData(100000000, "cento milioni")] + /* [InlineData(1000000000, "un miliardo")] [InlineData(111, "centoundici")] [InlineData(1111, "millecentoundici")] diff --git a/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs index 91edd1dbd..ebd32c1fd 100644 --- a/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs +++ b/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs @@ -43,7 +43,7 @@ public string Convert() word = partToString(part) + word; } - return word; + return word.Trim(); } protected readonly int _number; @@ -96,7 +96,8 @@ public Func GetNextChopConverter() break; case ThreeDigitSets.Millions: - converter = null; + converter = MillionsConverter; + _nextSet = ThreeDigitSets.Billions; break; case ThreeDigitSets.Billions: @@ -161,9 +162,28 @@ protected static string UnitsConverter(int number) /// The same three-digit number of thousands expressed as text. protected static string ThousandsConverter(int number) { + if (number == 0) + return String.Empty; + + if (number == 1) + return "mille"; + return UnitsConverter(number) + "mila"; } + /// + /// Converts a millions three-digit number to text. + /// + /// The three-digit number, as millions, to convert. + /// The same three-digit number of millions expressed as text. + protected static string MillionsConverter(int number) + { + if (number == 1) + return "un milione "; + + return UnitsConverter(number) + " milioni "; + } + /// /// Lookup table converting units number to text. Index 1 for 1, index 2 for 2, up to index 9. /// From 1ae2ff0fe01a4343793d6edcb5f549fccbe72213 Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Tue, 26 Aug 2014 16:36:56 +0200 Subject: [PATCH 21/39] L10n: italian NumberToWordsTests passing for simple billions numbers. --- .../Localisation/it/NumberToWordsTests.cs | 6 ++- .../ItalianNumberToWordsConverter.cs | 43 ++++++++++++++++--- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs index 1539b33f3..e0ac9b32f 100644 --- a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs +++ b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs @@ -20,6 +20,7 @@ public NumberToWordsTests() [InlineData(38, "trentotto")] [InlineData(122, "centoventidue")] [InlineData(3501, "tremilacinquecentouno")] + [InlineData(-3501, "meno tremilacinquecentouno")] [InlineData(100, "cento")] [InlineData(1000, "mille")] [InlineData(2000, "duemila")] @@ -29,8 +30,11 @@ public NumberToWordsTests() [InlineData(5000000, "cinque milioni")] [InlineData(10000000, "dieci milioni")] [InlineData(100000000, "cento milioni")] - /* [InlineData(1000000000, "un miliardo")] + //[InlineData(9000000000, "nove miliardi")] // int = System.Int32, fixed in API, is not big enough + //[InlineData(10000000000, "dieci miliardi")] // int = System.Int32, fixed in API, is not big enough + //[InlineData(100000000000, "cento miliardi")] // int = System.Int32, fixed in API, is not big enough + /* [InlineData(111, "centoundici")] [InlineData(1111, "millecentoundici")] [InlineData(111111, "centoundicimilacentoundici")] diff --git a/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs index ebd32c1fd..b952befd4 100644 --- a/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs +++ b/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs @@ -43,7 +43,8 @@ public string Convert() word = partToString(part) + word; } - return word.Trim(); + // remove trailing spaces if there are only thousands, or millions, etc. + return word.TrimEnd(); } protected readonly int _number; @@ -101,7 +102,8 @@ public Func GetNextChopConverter() break; case ThreeDigitSets.Billions: - converter = null; + converter = BillionsConverter; + _nextSet = ThreeDigitSets.More; break; case ThreeDigitSets.More: @@ -122,28 +124,41 @@ public Func GetNextChopConverter() /// The same three-digit number expressed as text. protected static string UnitsConverter(int number) { + if (number == 0) + return String.Empty; + + // grab lowest two digits int tensAndUnits = number % 100; + // grab third digit int hundreds = (int)(number / 100); + // grab also first and second digits separately int units = tensAndUnits % 10; int tens = (int)(tensAndUnits / 10); string words = String.Empty; + // append text for hundreds words += _hundredNumberToText[hundreds]; - words += _tensNumberToText[tens]; + // append text for tens, only those from twenty upward + words += _tensOver20NumberToText[tens]; if (tensAndUnits <= 9) { + // simple case for units, under 10 words += _unitsNumberToText[tensAndUnits]; } else if (tensAndUnits <= 19) { - words += _teensNumberToText[tensAndUnits - 10]; + // special case for 'teens', from 10 to 19 + words += _teensUnder20NumberToText[tensAndUnits - 10]; } else { + // just append units text, truncating tens last vowel before + // 'uno' (1) and 'otto' (8) + if (units == 1 || units == 8) { words = words.Remove(words.Length - 1); @@ -178,12 +193,28 @@ protected static string ThousandsConverter(int number) /// The same three-digit number of millions expressed as text. protected static string MillionsConverter(int number) { + if (number == 0) + return String.Empty; + if (number == 1) return "un milione "; return UnitsConverter(number) + " milioni "; } + /// + /// Converts a billions three-digit number to text. + /// + /// The three-digit number, as billions, to convert. + /// The same three-digit number of billions expressed as text. + protected static string BillionsConverter(int number) + { + if (number == 1) + return "un miliardo "; + + return UnitsConverter(number) + " miliardi "; + } + /// /// Lookup table converting units number to text. Index 1 for 1, index 2 for 2, up to index 9. /// @@ -204,7 +235,7 @@ protected static string MillionsConverter(int number) /// /// Lookup table converting tens number to text. Index 2 for 20, index 3 for 30, up to index 9 for 90. /// - protected static string[] _tensNumberToText = new string[] + protected static string[] _tensOver20NumberToText = new string[] { String.Empty, String.Empty, @@ -221,7 +252,7 @@ protected static string MillionsConverter(int number) /// /// Lookup table converting teens number to text. Index 0 for 10, index 1 for 11, up to index 9 for 19. /// - protected static string[] _teensNumberToText = new string[] + protected static string[] _teensUnder20NumberToText = new string[] { "dieci", "undici", From 7409b5c963186af097f4d31bde8ed5ea7b5a12da Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Tue, 26 Aug 2014 17:01:53 +0200 Subject: [PATCH 22/39] =?UTF-8?q?L10n:=20italian=20NumberToWords=20convert?= =?UTF-8?q?er=20supports=20ventitr=C3=A8,=20trentatr=C3=A8,=20etc.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Localisation/it/NumberToWordsTests.cs | 5 ++- .../ItalianNumberToWordsConverter.cs | 32 +++++++++++++------ 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs index e0ac9b32f..453fb2ac2 100644 --- a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs +++ b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs @@ -31,10 +31,11 @@ public NumberToWordsTests() [InlineData(10000000, "dieci milioni")] [InlineData(100000000, "cento milioni")] [InlineData(1000000000, "un miliardo")] + [InlineData(2000000000, "due miliardi")] + [InlineData(2147483647, "due miliardi centoquarantasette milioni quattrocentoottantatremilaseicentoquarantasette")] // int.MaxValue //[InlineData(9000000000, "nove miliardi")] // int = System.Int32, fixed in API, is not big enough //[InlineData(10000000000, "dieci miliardi")] // int = System.Int32, fixed in API, is not big enough //[InlineData(100000000000, "cento miliardi")] // int = System.Int32, fixed in API, is not big enough - /* [InlineData(111, "centoundici")] [InlineData(1111, "millecentoundici")] [InlineData(111111, "centoundicimilacentoundici")] @@ -44,7 +45,9 @@ public NumberToWordsTests() [InlineData(111111111, "centoundici milioni centoundicimilacentoundici")] [InlineData(1101111101, "un miliardo centouno milioni centoundicimilacentouno")] [InlineData(1111111111, "un miliardo centoundici milioni centoundicimilacentoundici")] + [InlineData(43, "quarantatré")] [InlineData(123, "centoventitré")] + /* [InlineData(1234, "milleduecentotrentaquattro")] [InlineData(8100, "ottomilacento")] [InlineData(12345, "dodicimilatrecentoquarantacinque")] diff --git a/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs index b952befd4..f373ccec8 100644 --- a/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs +++ b/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs @@ -118,11 +118,12 @@ public Func GetNextChopConverter() } /// - /// Converts a three-digit number to text. + /// Converts a three-digit set to text. /// - /// The three-digit number to convert. - /// The same three-digit number expressed as text. - protected static string UnitsConverter(int number) + /// The three-digit set to convert. + /// True if the current three-digit set is the last in the word. + /// The same three-digit set expressed as text. + protected static string ThreeDigitSetConverter(int number, bool thisIsLastSet = false) { if (number == 0) return String.Empty; @@ -156,20 +157,33 @@ protected static string UnitsConverter(int number) } else { - // just append units text, truncating tens last vowel before - // 'uno' (1) and 'otto' (8) + // just append units text, with some corner cases + // truncate tens last vowel before 'uno' (1) and 'otto' (8) if (units == 1 || units == 8) { words = words.Remove(words.Length - 1); } - words += _unitsNumberToText[units]; + // if this is the last set, an accent could be due + string unitsText = (thisIsLastSet && units == 3 ? "tré" : _unitsNumberToText[units]); + + words += unitsText; } return words; } + /// + /// Converts a three-digit number, as units, to text. + /// + /// The three-digit number, as units, to convert. + /// The same three-digit number, as units, expressed as text. + protected static string UnitsConverter(int number) + { + return ThreeDigitSetConverter(number, true); + } + /// /// Converts a thousands three-digit number to text. /// @@ -183,7 +197,7 @@ protected static string ThousandsConverter(int number) if (number == 1) return "mille"; - return UnitsConverter(number) + "mila"; + return ThreeDigitSetConverter(number) + "mila"; } /// @@ -199,7 +213,7 @@ protected static string MillionsConverter(int number) if (number == 1) return "un milione "; - return UnitsConverter(number) + " milioni "; + return ThreeDigitSetConverter(number) + " milioni "; } /// From 92c5ca3e0d18909081cd0310f802e5637d0472dd Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Tue, 26 Aug 2014 17:08:30 +0200 Subject: [PATCH 23/39] L10n: italian NumberToWords passing all ToWords tests --- src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs | 8 +++----- .../NumberToWords/ItalianNumberToWordsConverter.cs | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs index 453fb2ac2..75782470e 100644 --- a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs +++ b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs @@ -45,21 +45,19 @@ public NumberToWordsTests() [InlineData(111111111, "centoundici milioni centoundicimilacentoundici")] [InlineData(1101111101, "un miliardo centouno milioni centoundicimilacentouno")] [InlineData(1111111111, "un miliardo centoundici milioni centoundicimilacentoundici")] + [InlineData(8100, "ottomilacento")] [InlineData(43, "quarantatré")] [InlineData(123, "centoventitré")] - /* [InlineData(1234, "milleduecentotrentaquattro")] - [InlineData(8100, "ottomilacento")] [InlineData(12345, "dodicimilatrecentoquarantacinque")] [InlineData(123456, "centoventitremilaquattrocentocinquantasei")] [InlineData(1234567, "un milione duecentotrentaquattromilacinquecentosessantasette")] [InlineData(12345678, "dodici milioni trecentoquarantacinquemilaseicentosettantotto")] - [InlineData(123456789, "centoventitrè milioni quattrocentocinquantaseimilasettecentoottantanove")] - [InlineData(1234567890, "un miliardo duecentotrentaquattromilioni cinquecentosessantasettemilaottocentonovanta")] + [InlineData(123456789, "centoventitré milioni quattrocentocinquantaseimilasettecentoottantanove")] + [InlineData(1234567890, "un miliardo duecentotrentaquattro milioni cinquecentosessantasettemilaottocentonovanta")] [InlineData(1999, "millenovecentonovantanove")] [InlineData(2014, "duemilaquattordici")] [InlineData(2048, "duemilaquarantotto")] - */ public void ToWords(int number, string expected) { Assert.Equal(expected, number.ToWords()); diff --git a/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs index f373ccec8..3d4c0c965 100644 --- a/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs +++ b/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs @@ -213,7 +213,7 @@ protected static string MillionsConverter(int number) if (number == 1) return "un milione "; - return ThreeDigitSetConverter(number) + " milioni "; + return ThreeDigitSetConverter(number, true) + " milioni "; } /// From 88f5baee408261da75837e537396a774f7025cb3 Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Tue, 26 Aug 2014 17:36:53 +0200 Subject: [PATCH 24/39] L10n: italian NumberToWordsTests passing for feminine gender --- .../Localisation/it/NumberToWordsTests.cs | 39 +++++++++++++- .../ItalianNumberToWordsConverter.cs | 51 +++++++++++-------- 2 files changed, 68 insertions(+), 22 deletions(-) diff --git a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs index 75782470e..6772ee864 100644 --- a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs +++ b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs @@ -14,6 +14,7 @@ public NumberToWordsTests() [InlineData(0, "zero")] [InlineData(1, "uno")] [InlineData(-1, "meno uno")] + [InlineData(3, "tre")] [InlineData(10, "dieci")] [InlineData(11, "undici")] [InlineData(21, "ventuno")] @@ -36,6 +37,14 @@ public NumberToWordsTests() //[InlineData(9000000000, "nove miliardi")] // int = System.Int32, fixed in API, is not big enough //[InlineData(10000000000, "dieci miliardi")] // int = System.Int32, fixed in API, is not big enough //[InlineData(100000000000, "cento miliardi")] // int = System.Int32, fixed in API, is not big enough + [InlineData(101, "centouno")] + [InlineData(1001, "milleuno")] + [InlineData(10001, "diecimilauno")] + [InlineData(100001, "centomilauno")] + [InlineData(1000001, "un milione uno")] + [InlineData(10000001, "dieci milioni uno")] + [InlineData(100000001, "cento milioni uno")] + [InlineData(1000000001, "un miliardo uno")] [InlineData(111, "centoundici")] [InlineData(1111, "millecentoundici")] [InlineData(111111, "centoundicimilacentoundici")] @@ -46,7 +55,7 @@ public NumberToWordsTests() [InlineData(1101111101, "un miliardo centouno milioni centoundicimilacentouno")] [InlineData(1111111111, "un miliardo centoundici milioni centoundicimilacentoundici")] [InlineData(8100, "ottomilacento")] - [InlineData(43, "quarantatré")] + [InlineData(43, "quarantatré")] // Ref. http://dizionari.corriere.it/dizionario-si-dice/V/ventitre.shtml [InlineData(123, "centoventitré")] [InlineData(1234, "milleduecentotrentaquattro")] [InlineData(12345, "dodicimilatrecentoquarantacinque")] @@ -63,8 +72,17 @@ public void ToWords(int number, string expected) Assert.Equal(expected, number.ToWords()); } - /* [Theory] + [InlineData(0, "zero")] + [InlineData(1, "una")] + [InlineData(-1, "meno una")] + [InlineData(3, "tre")] + [InlineData(21, "ventuno")] + [InlineData(101, "centouno")] + [InlineData(1001, "milleuno")] + [InlineData(10001, "diecimilauno")] + [InlineData(100001, "centomilauno")] + /* [InlineData(1, "uma")] [InlineData(2, "duas")] [InlineData(3, "três")] @@ -85,11 +103,28 @@ public void ToWords(int number, string expected) [InlineData(1234, "mil duzentas e trinta e quatro")] [InlineData(8100, "oito mil e cem")] [InlineData(12345, "doze mil trezentas e quarenta e cinco")] + */ public void ToFeminineWords(int number, string expected) { Assert.Equal(expected, number.ToWords(GrammaticalGender.Feminine)); } + [Theory] + [InlineData(0, "zero")] + [InlineData(1, "uno")] + [InlineData(-1, "meno uno")] + [InlineData(3, "tre")] + [InlineData(21, "ventuno")] + [InlineData(101, "centouno")] + [InlineData(1001, "milleuno")] + [InlineData(10001, "diecimilauno")] + [InlineData(100001, "centomilauno")] + public void ToMasculineWords(int number, string expected) + { + Assert.Equal(expected, number.ToWords(GrammaticalGender.Masculine)); + } + + /* [Theory] [InlineData(0, "zero")] [InlineData(1, "primeiro")] diff --git a/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs index 3d4c0c965..af532a12c 100644 --- a/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs +++ b/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs @@ -13,7 +13,7 @@ public override string Convert(int number, GrammaticalGender gender) if (number < 0) return "meno " + Convert(Math.Abs(number), gender); - ItalianNumberCruncher cruncher = new ItalianNumberCruncher(number); + ItalianNumberCruncher cruncher = new ItalianNumberCruncher(number, gender); return cruncher.Convert(); } @@ -25,30 +25,32 @@ public override string ConvertToOrdinal(int number, GrammaticalGender gender) class ItalianNumberCruncher { - public ItalianNumberCruncher(int number) + public ItalianNumberCruncher(int number, GrammaticalGender gender) { - _number = number; - _threeDigitParts = SplitEveryThreeDigits(_number); + _fullNumber = number; + _threeDigitParts = SplitEveryThreeDigits(number); + _gender = gender; _nextSet = ThreeDigitSets.Units; } public string Convert() { string word = String.Empty; - + foreach(int part in _threeDigitParts) { - Func partToString = GetNextChopConverter(); + Func partToString = GetNextChopConverter(); - word = partToString(part) + word; + word = partToString(part, _gender) + word; } - // remove trailing spaces if there are only thousands, or millions, etc. + // remove trailing spaces if there are only millions or billions return word.TrimEnd(); } - protected readonly int _number; + protected readonly int _fullNumber; protected readonly List _threeDigitParts; + protected readonly GrammaticalGender _gender; protected ThreeDigitSets _nextSet; @@ -80,9 +82,9 @@ protected static List SplitEveryThreeDigits(int number) /// for the next three-digit pack. /// /// The next conversion function to use. - public Func GetNextChopConverter() + public Func GetNextChopConverter() { - Func converter; + Func converter; switch (_nextSet) { @@ -121,9 +123,10 @@ public Func GetNextChopConverter() /// Converts a three-digit set to text. /// /// The three-digit set to convert. + /// Gender of noun following number /// True if the current three-digit set is the last in the word. /// The same three-digit set expressed as text. - protected static string ThreeDigitSetConverter(int number, bool thisIsLastSet = false) + protected static string ThreeDigitSetConverter(int number, GrammaticalGender gender, bool thisIsLastSet = false) { if (number == 0) return String.Empty; @@ -178,18 +181,24 @@ protected static string ThreeDigitSetConverter(int number, bool thisIsLastSet = /// Converts a three-digit number, as units, to text. /// /// The three-digit number, as units, to convert. + /// Gender of noun following number /// The same three-digit number, as units, expressed as text. - protected static string UnitsConverter(int number) + protected string UnitsConverter(int number, GrammaticalGender gender) { - return ThreeDigitSetConverter(number, true); + // being a unique case, it's easier to treat unity feminine gender as a completely distinct case + if (_gender == GrammaticalGender.Feminine && _fullNumber == 1) + return "una"; + + return ThreeDigitSetConverter(number, gender, true); } /// /// Converts a thousands three-digit number to text. /// /// The three-digit number, as thousands, to convert. + /// Gender of noun following number /// The same three-digit number of thousands expressed as text. - protected static string ThousandsConverter(int number) + protected static string ThousandsConverter(int number, GrammaticalGender gender) { if (number == 0) return String.Empty; @@ -197,15 +206,16 @@ protected static string ThousandsConverter(int number) if (number == 1) return "mille"; - return ThreeDigitSetConverter(number) + "mila"; + return ThreeDigitSetConverter(number, gender) + "mila"; } /// /// Converts a millions three-digit number to text. /// /// The three-digit number, as millions, to convert. + /// Gender of noun following number /// The same three-digit number of millions expressed as text. - protected static string MillionsConverter(int number) + protected static string MillionsConverter(int number, GrammaticalGender gender) { if (number == 0) return String.Empty; @@ -213,20 +223,21 @@ protected static string MillionsConverter(int number) if (number == 1) return "un milione "; - return ThreeDigitSetConverter(number, true) + " milioni "; + return ThreeDigitSetConverter(number, gender, true) + " milioni "; } /// /// Converts a billions three-digit number to text. /// /// The three-digit number, as billions, to convert. + /// Gender of noun following number /// The same three-digit number of billions expressed as text. - protected static string BillionsConverter(int number) + protected static string BillionsConverter(int number, GrammaticalGender gender) { if (number == 1) return "un miliardo "; - return UnitsConverter(number) + " miliardi "; + return ThreeDigitSetConverter(number, gender) + " miliardi "; } /// From f4cca21df5bf9e58be646a7344c3a9188b26afcd Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Tue, 26 Aug 2014 17:52:38 +0200 Subject: [PATCH 25/39] L10n: Refactor: italian cardinal number to words logic moved to separate file --- .../Localisation/it/NumberToWordsTests.cs | 34 +- src/Humanizer/Humanizer.csproj | 1 + .../Italian/ItalianCardinalNumberCruncher.cs | 323 +++++++++++++++++ .../ItalianNumberToWordsConverter.cs | 324 +----------------- 4 files changed, 336 insertions(+), 346 deletions(-) create mode 100644 src/Humanizer/Localisation/NumberToWords/Italian/ItalianCardinalNumberCruncher.cs diff --git a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs index 6772ee864..cdf2c4165 100644 --- a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs +++ b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs @@ -82,28 +82,6 @@ public void ToWords(int number, string expected) [InlineData(1001, "milleuno")] [InlineData(10001, "diecimilauno")] [InlineData(100001, "centomilauno")] - /* - [InlineData(1, "uma")] - [InlineData(2, "duas")] - [InlineData(3, "três")] - [InlineData(11, "onze")] - [InlineData(21, "vinte e uma")] - [InlineData(122, "cento e vinte e duas")] - [InlineData(232, "duzentas e trinta e duas")] - [InlineData(343, "trezentas e quarenta e três")] - [InlineData(3501, "três mil quinhentas e uma")] - [InlineData(100, "cem")] - [InlineData(1000, "mil")] - [InlineData(111, "cento e onze")] - [InlineData(1111, "mil cento e onze")] - [InlineData(111111, "cento e onze mil cento e onze")] - [InlineData(1111101, "um milhão cento e onze mil cento e uma")] - [InlineData(1111111, "um milhão cento e onze mil cento e onze")] - [InlineData(1101111101, "um bilhão cento e um milhões cento e onze mil cento e uma")] - [InlineData(1234, "mil duzentas e trinta e quatro")] - [InlineData(8100, "oito mil e cem")] - [InlineData(12345, "doze mil trezentas e quarenta e cinco")] - */ public void ToFeminineWords(int number, string expected) { Assert.Equal(expected, number.ToWords(GrammaticalGender.Feminine)); @@ -124,10 +102,10 @@ public void ToMasculineWords(int number, string expected) Assert.Equal(expected, number.ToWords(GrammaticalGender.Masculine)); } - /* [Theory] [InlineData(0, "zero")] - [InlineData(1, "primeiro")] + /* + [InlineData(1, "primo")] [InlineData(2, "segundo")] [InlineData(3, "terceiro")] [InlineData(4, "quarto")] @@ -178,11 +156,13 @@ public void ToMasculineWords(int number, string expected) [InlineData(100000, "centésimo milésimo")] [InlineData(1000000, "milionésimo")] [InlineData(1000000000, "bilionésimo")] - public void ToOrdinalWords(int number, string words) + */ + public void ToOrdinalWords(int number, string expected) { - Assert.Equal(words, number.ToOrdinalWords()); + Assert.Equal(expected, number.ToOrdinalWords()); } - + + /* [Theory] [InlineData(0, "zero")] [InlineData(1, "primeira")] diff --git a/src/Humanizer/Humanizer.csproj b/src/Humanizer/Humanizer.csproj index 1733d31bc..20e4d766d 100644 --- a/src/Humanizer/Humanizer.csproj +++ b/src/Humanizer/Humanizer.csproj @@ -77,6 +77,7 @@ + diff --git a/src/Humanizer/Localisation/NumberToWords/Italian/ItalianCardinalNumberCruncher.cs b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianCardinalNumberCruncher.cs new file mode 100644 index 000000000..4e4a8aca2 --- /dev/null +++ b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianCardinalNumberCruncher.cs @@ -0,0 +1,323 @@ +using System; +using System.Collections.Generic; + +namespace Humanizer.Localisation.NumberToWords.Italian +{ + class ItalianCardinalNumberCruncher + { + public ItalianCardinalNumberCruncher(int number, GrammaticalGender gender) + { + _fullNumber = number; + _threeDigitParts = SplitEveryThreeDigits(number); + _gender = gender; + _nextSet = ThreeDigitSets.Units; + } + + public string Convert() + { + string word = String.Empty; + + foreach(int part in _threeDigitParts) + { + Func partToString = GetNextChopConverter(); + + word = partToString(part, _gender) + word; + } + + // remove trailing spaces if there are only millions or billions + return word.TrimEnd(); + } + + protected readonly int _fullNumber; + protected readonly List _threeDigitParts; + protected readonly GrammaticalGender _gender; + + protected ThreeDigitSets _nextSet; + + /// + /// Splits a number into a sequence of three-digits numbers, starting + /// from units, then thousands, millions, and so on. + /// + /// The number to split. + /// The sequence of three-digit numbers. + protected static List SplitEveryThreeDigits(int number) + { + List parts = new List(); + int rest = number; + + while (rest > 0) + { + int threeDigit = rest % 1000; + + parts.Add(threeDigit); + + rest = (int)(rest / 1000); + } + + return parts; + } + + /// + /// During number conversion to text, finds out the converter to use + /// for the next three-digit pack. + /// + /// The next conversion function to use. + public Func GetNextChopConverter() + { + Func converter; + + switch (_nextSet) + { + case ThreeDigitSets.Units: + converter = UnitsConverter; + _nextSet = ThreeDigitSets.Thousands; + break; + + case ThreeDigitSets.Thousands: + converter = ThousandsConverter; + _nextSet = ThreeDigitSets.Millions; + break; + + case ThreeDigitSets.Millions: + converter = MillionsConverter; + _nextSet = ThreeDigitSets.Billions; + break; + + case ThreeDigitSets.Billions: + converter = BillionsConverter; + _nextSet = ThreeDigitSets.More; + break; + + case ThreeDigitSets.More: + converter = null; + break; + + default: + throw new ArgumentOutOfRangeException("Unknow ThreeDigitSet: " + _nextSet); + } + + return converter; + } + + /// + /// Converts a three-digit set to text. + /// + /// The three-digit set to convert. + /// Gender of noun following number + /// True if the current three-digit set is the last in the word. + /// The same three-digit set expressed as text. + protected static string ThreeDigitSetConverter(int number, GrammaticalGender gender, bool thisIsLastSet = false) + { + if (number == 0) + return String.Empty; + + // grab lowest two digits + int tensAndUnits = number % 100; + // grab third digit + int hundreds = (int)(number / 100); + + // grab also first and second digits separately + int units = tensAndUnits % 10; + int tens = (int)(tensAndUnits / 10); + + string words = String.Empty; + + // append text for hundreds + words += _hundredNumberToText[hundreds]; + + // append text for tens, only those from twenty upward + words += _tensOver20NumberToText[tens]; + + if (tensAndUnits <= 9) + { + // simple case for units, under 10 + words += _unitsNumberToText[tensAndUnits]; + } + else if (tensAndUnits <= 19) + { + // special case for 'teens', from 10 to 19 + words += _teensUnder20NumberToText[tensAndUnits - 10]; + } + else + { + // just append units text, with some corner cases + + // truncate tens last vowel before 'uno' (1) and 'otto' (8) + if (units == 1 || units == 8) + { + words = words.Remove(words.Length - 1); + } + + // if this is the last set, an accent could be due + string unitsText = (thisIsLastSet && units == 3 ? "tré" : _unitsNumberToText[units]); + + words += unitsText; + } + + return words; + } + + /// + /// Converts a three-digit number, as units, to text. + /// + /// The three-digit number, as units, to convert. + /// Gender of noun following number + /// The same three-digit number, as units, expressed as text. + protected string UnitsConverter(int number, GrammaticalGender gender) + { + // being a unique case, it's easier to treat unity feminine gender as a completely distinct case + if (_gender == GrammaticalGender.Feminine && _fullNumber == 1) + return "una"; + + return ThreeDigitSetConverter(number, gender, true); + } + + /// + /// Converts a thousands three-digit number to text. + /// + /// The three-digit number, as thousands, to convert. + /// Gender of noun following number + /// The same three-digit number of thousands expressed as text. + protected static string ThousandsConverter(int number, GrammaticalGender gender) + { + if (number == 0) + return String.Empty; + + if (number == 1) + return "mille"; + + return ThreeDigitSetConverter(number, gender) + "mila"; + } + + /// + /// Converts a millions three-digit number to text. + /// + /// The three-digit number, as millions, to convert. + /// Gender of noun following number + /// The same three-digit number of millions expressed as text. + protected static string MillionsConverter(int number, GrammaticalGender gender) + { + if (number == 0) + return String.Empty; + + if (number == 1) + return "un milione "; + + return ThreeDigitSetConverter(number, gender, true) + " milioni "; + } + + /// + /// Converts a billions three-digit number to text. + /// + /// The three-digit number, as billions, to convert. + /// Gender of noun following number + /// The same three-digit number of billions expressed as text. + protected static string BillionsConverter(int number, GrammaticalGender gender) + { + if (number == 1) + return "un miliardo "; + + return ThreeDigitSetConverter(number, gender) + " miliardi "; + } + + /// + /// Lookup table converting units number to text. Index 1 for 1, index 2 for 2, up to index 9. + /// + protected static string[] _unitsNumberToText = new string[] + { + String.Empty, + "uno", + "due", + "tre", + "quattro", + "cinque", + "sei", + "sette", + "otto", + "nove" + }; + + /// + /// Lookup table converting tens number to text. Index 2 for 20, index 3 for 30, up to index 9 for 90. + /// + protected static string[] _tensOver20NumberToText = new string[] + { + String.Empty, + String.Empty, + "venti", + "trenta", + "quaranta", + "cinquanta", + "sessanta", + "settanta", + "ottanta", + "novanta" + }; + + /// + /// Lookup table converting teens number to text. Index 0 for 10, index 1 for 11, up to index 9 for 19. + /// + protected static string[] _teensUnder20NumberToText = new string[] + { + "dieci", + "undici", + "dodici", + "tredici", + "quattordici", + "quindici", + "sedici", + "diciassette", + "diciotto", + "diciannove" + }; + + /// + /// Lookup table converting hundreds number to text. Index 0 for no hundreds, index 1 for 100, up to index 9. + /// + protected static string[] _hundredNumberToText = new string[] + { + String.Empty, + "cento", + "duecento", + "trecento", + "quattrocento", + "cinquecento", + "seicento", + "settecento", + "ottocento", + "novecento" + }; + + /// + /// Enumerates sets of three-digits having distinct conversion to text. + /// + protected enum ThreeDigitSets + { + /// + /// Lowest three-digits set, from 1 to 999. + /// + Units, + + /// + /// Three-digits set counting the thousands, from 1'000 to 999'000. + /// + Thousands, + + /// + /// Three-digits set counting millions, from 1'000'000 to 999'000'000. + /// + Millions, + + /// + /// Three-digits set counting billions, from 1'000'000'000 to 999'000'000'000. + /// + Billions, + + /// + /// Three-digits set beyond 999 billions, from 1'000'000'000'000 onward. + /// + More + } + } +} + diff --git a/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs index af532a12c..2e70dbf56 100644 --- a/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs +++ b/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs @@ -1,5 +1,5 @@ using System; -using System.Collections.Generic; +using Humanizer.Localisation.NumberToWords.Italian; namespace Humanizer.Localisation.NumberToWords { @@ -13,331 +13,17 @@ public override string Convert(int number, GrammaticalGender gender) if (number < 0) return "meno " + Convert(Math.Abs(number), gender); - ItalianNumberCruncher cruncher = new ItalianNumberCruncher(number, gender); + ItalianCardinalNumberCruncher cruncher = new ItalianCardinalNumberCruncher(number, gender); return cruncher.Convert(); } public override string ConvertToOrdinal(int number, GrammaticalGender gender) { - return String.Empty; - } + if (number == 0) + return "zero"; - class ItalianNumberCruncher - { - public ItalianNumberCruncher(int number, GrammaticalGender gender) - { - _fullNumber = number; - _threeDigitParts = SplitEveryThreeDigits(number); - _gender = gender; - _nextSet = ThreeDigitSets.Units; - } - - public string Convert() - { - string word = String.Empty; - - foreach(int part in _threeDigitParts) - { - Func partToString = GetNextChopConverter(); - - word = partToString(part, _gender) + word; - } - - // remove trailing spaces if there are only millions or billions - return word.TrimEnd(); - } - - protected readonly int _fullNumber; - protected readonly List _threeDigitParts; - protected readonly GrammaticalGender _gender; - - protected ThreeDigitSets _nextSet; - - /// - /// Splits a number into a sequence of three-digits numbers, starting - /// from units, then thousands, millions, and so on. - /// - /// The number to split. - /// The sequence of three-digit numbers. - protected static List SplitEveryThreeDigits(int number) - { - List parts = new List(); - int rest = number; - - while (rest > 0) - { - int threeDigit = rest % 1000; - - parts.Add(threeDigit); - - rest = (int)(rest / 1000); - } - - return parts; - } - - /// - /// During number conversion to text, finds out the converter to use - /// for the next three-digit pack. - /// - /// The next conversion function to use. - public Func GetNextChopConverter() - { - Func converter; - - switch (_nextSet) - { - case ThreeDigitSets.Units: - converter = UnitsConverter; - _nextSet = ThreeDigitSets.Thousands; - break; - - case ThreeDigitSets.Thousands: - converter = ThousandsConverter; - _nextSet = ThreeDigitSets.Millions; - break; - - case ThreeDigitSets.Millions: - converter = MillionsConverter; - _nextSet = ThreeDigitSets.Billions; - break; - - case ThreeDigitSets.Billions: - converter = BillionsConverter; - _nextSet = ThreeDigitSets.More; - break; - - case ThreeDigitSets.More: - converter = null; - break; - - default: - throw new ArgumentOutOfRangeException("Unknow ThreeDigitSet: " + _nextSet); - } - - return converter; - } - - /// - /// Converts a three-digit set to text. - /// - /// The three-digit set to convert. - /// Gender of noun following number - /// True if the current three-digit set is the last in the word. - /// The same three-digit set expressed as text. - protected static string ThreeDigitSetConverter(int number, GrammaticalGender gender, bool thisIsLastSet = false) - { - if (number == 0) - return String.Empty; - - // grab lowest two digits - int tensAndUnits = number % 100; - // grab third digit - int hundreds = (int)(number / 100); - - // grab also first and second digits separately - int units = tensAndUnits % 10; - int tens = (int)(tensAndUnits / 10); - - string words = String.Empty; - - // append text for hundreds - words += _hundredNumberToText[hundreds]; - - // append text for tens, only those from twenty upward - words += _tensOver20NumberToText[tens]; - - if (tensAndUnits <= 9) - { - // simple case for units, under 10 - words += _unitsNumberToText[tensAndUnits]; - } - else if (tensAndUnits <= 19) - { - // special case for 'teens', from 10 to 19 - words += _teensUnder20NumberToText[tensAndUnits - 10]; - } - else - { - // just append units text, with some corner cases - - // truncate tens last vowel before 'uno' (1) and 'otto' (8) - if (units == 1 || units == 8) - { - words = words.Remove(words.Length - 1); - } - - // if this is the last set, an accent could be due - string unitsText = (thisIsLastSet && units == 3 ? "tré" : _unitsNumberToText[units]); - - words += unitsText; - } - - return words; - } - - /// - /// Converts a three-digit number, as units, to text. - /// - /// The three-digit number, as units, to convert. - /// Gender of noun following number - /// The same three-digit number, as units, expressed as text. - protected string UnitsConverter(int number, GrammaticalGender gender) - { - // being a unique case, it's easier to treat unity feminine gender as a completely distinct case - if (_gender == GrammaticalGender.Feminine && _fullNumber == 1) - return "una"; - - return ThreeDigitSetConverter(number, gender, true); - } - - /// - /// Converts a thousands three-digit number to text. - /// - /// The three-digit number, as thousands, to convert. - /// Gender of noun following number - /// The same three-digit number of thousands expressed as text. - protected static string ThousandsConverter(int number, GrammaticalGender gender) - { - if (number == 0) - return String.Empty; - - if (number == 1) - return "mille"; - - return ThreeDigitSetConverter(number, gender) + "mila"; - } - - /// - /// Converts a millions three-digit number to text. - /// - /// The three-digit number, as millions, to convert. - /// Gender of noun following number - /// The same three-digit number of millions expressed as text. - protected static string MillionsConverter(int number, GrammaticalGender gender) - { - if (number == 0) - return String.Empty; - - if (number == 1) - return "un milione "; - - return ThreeDigitSetConverter(number, gender, true) + " milioni "; - } - - /// - /// Converts a billions three-digit number to text. - /// - /// The three-digit number, as billions, to convert. - /// Gender of noun following number - /// The same three-digit number of billions expressed as text. - protected static string BillionsConverter(int number, GrammaticalGender gender) - { - if (number == 1) - return "un miliardo "; - - return ThreeDigitSetConverter(number, gender) + " miliardi "; - } - - /// - /// Lookup table converting units number to text. Index 1 for 1, index 2 for 2, up to index 9. - /// - protected static string[] _unitsNumberToText = new string[] - { - String.Empty, - "uno", - "due", - "tre", - "quattro", - "cinque", - "sei", - "sette", - "otto", - "nove" - }; - - /// - /// Lookup table converting tens number to text. Index 2 for 20, index 3 for 30, up to index 9 for 90. - /// - protected static string[] _tensOver20NumberToText = new string[] - { - String.Empty, - String.Empty, - "venti", - "trenta", - "quaranta", - "cinquanta", - "sessanta", - "settanta", - "ottanta", - "novanta" - }; - - /// - /// Lookup table converting teens number to text. Index 0 for 10, index 1 for 11, up to index 9 for 19. - /// - protected static string[] _teensUnder20NumberToText = new string[] - { - "dieci", - "undici", - "dodici", - "tredici", - "quattordici", - "quindici", - "sedici", - "diciassette", - "diciotto", - "diciannove" - }; - - /// - /// Lookup table converting hundreds number to text. Index 0 for no hundreds, index 1 for 100, up to index 9. - /// - protected static string[] _hundredNumberToText = new string[] - { - String.Empty, - "cento", - "duecento", - "trecento", - "quattrocento", - "cinquecento", - "seicento", - "settecento", - "ottocento", - "novecento" - }; - - /// - /// Enumerates sets of three-digits having distinct conversion to text. - /// - protected enum ThreeDigitSets - { - /// - /// Lowest three-digits set, from 1 to 999. - /// - Units, - - /// - /// Three-digits set counting the thousands, from 1'000 to 999'000. - /// - Thousands, - - /// - /// Three-digits set counting millions, from 1'000'000 to 999'000'000. - /// - Millions, - - /// - /// Three-digits set counting billions, from 1'000'000'000 to 999'000'000'000. - /// - Billions, - - /// - /// Three-digits set beyond 999 billions, from 1'000'000'000'000 onward. - /// - More - } + return String.Empty; } } } \ No newline at end of file From 4a7533ff757773ebd0c540097da41e3d5624a076 Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Tue, 26 Aug 2014 18:12:20 +0200 Subject: [PATCH 26/39] L10n: added initial italian ordinal NumberToWordsConverter Also: rename identifiers in ItaliaCardinaNumberCruncher --- src/Humanizer/Humanizer.csproj | 1 + .../Italian/ItalianCardinalNumberCruncher.cs | 37 ++--- .../Italian/ItalianOrdinalNumberCruncher.cs | 150 ++++++++++++++++++ .../ItalianNumberToWordsConverter.cs | 4 +- 4 files changed, 170 insertions(+), 22 deletions(-) create mode 100644 src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs diff --git a/src/Humanizer/Humanizer.csproj b/src/Humanizer/Humanizer.csproj index 20e4d766d..b5a755cc6 100644 --- a/src/Humanizer/Humanizer.csproj +++ b/src/Humanizer/Humanizer.csproj @@ -78,6 +78,7 @@ + diff --git a/src/Humanizer/Localisation/NumberToWords/Italian/ItalianCardinalNumberCruncher.cs b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianCardinalNumberCruncher.cs index 4e4a8aca2..382afbc4c 100644 --- a/src/Humanizer/Localisation/NumberToWords/Italian/ItalianCardinalNumberCruncher.cs +++ b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianCardinalNumberCruncher.cs @@ -15,17 +15,17 @@ public ItalianCardinalNumberCruncher(int number, GrammaticalGender gender) public string Convert() { - string word = String.Empty; + string words = String.Empty; foreach(int part in _threeDigitParts) { - Func partToString = GetNextChopConverter(); + Func partToString = GetNextPartConverter(); - word = partToString(part, _gender) + word; + words = partToString(part) + words; } // remove trailing spaces if there are only millions or billions - return word.TrimEnd(); + return words.TrimEnd(); } protected readonly int _fullNumber; @@ -59,12 +59,12 @@ protected static List SplitEveryThreeDigits(int number) /// /// During number conversion to text, finds out the converter to use - /// for the next three-digit pack. + /// for the next three-digit set. /// /// The next conversion function to use. - public Func GetNextChopConverter() + public Func GetNextPartConverter() { - Func converter; + Func converter; switch (_nextSet) { @@ -103,10 +103,9 @@ public Func GetNextChopConverter() /// Converts a three-digit set to text. /// /// The three-digit set to convert. - /// Gender of noun following number /// True if the current three-digit set is the last in the word. /// The same three-digit set expressed as text. - protected static string ThreeDigitSetConverter(int number, GrammaticalGender gender, bool thisIsLastSet = false) + protected static string ThreeDigitSetConverter(int number, bool thisIsLastSet = false) { if (number == 0) return String.Empty; @@ -161,24 +160,22 @@ protected static string ThreeDigitSetConverter(int number, GrammaticalGender gen /// Converts a three-digit number, as units, to text. /// /// The three-digit number, as units, to convert. - /// Gender of noun following number /// The same three-digit number, as units, expressed as text. - protected string UnitsConverter(int number, GrammaticalGender gender) + protected string UnitsConverter(int number) { // being a unique case, it's easier to treat unity feminine gender as a completely distinct case if (_gender == GrammaticalGender.Feminine && _fullNumber == 1) return "una"; - return ThreeDigitSetConverter(number, gender, true); + return ThreeDigitSetConverter(number, true); } /// /// Converts a thousands three-digit number to text. /// /// The three-digit number, as thousands, to convert. - /// Gender of noun following number /// The same three-digit number of thousands expressed as text. - protected static string ThousandsConverter(int number, GrammaticalGender gender) + protected static string ThousandsConverter(int number) { if (number == 0) return String.Empty; @@ -186,16 +183,15 @@ protected static string ThousandsConverter(int number, GrammaticalGender gender) if (number == 1) return "mille"; - return ThreeDigitSetConverter(number, gender) + "mila"; + return ThreeDigitSetConverter(number) + "mila"; } /// /// Converts a millions three-digit number to text. /// /// The three-digit number, as millions, to convert. - /// Gender of noun following number /// The same three-digit number of millions expressed as text. - protected static string MillionsConverter(int number, GrammaticalGender gender) + protected static string MillionsConverter(int number) { if (number == 0) return String.Empty; @@ -203,21 +199,20 @@ protected static string MillionsConverter(int number, GrammaticalGender gender) if (number == 1) return "un milione "; - return ThreeDigitSetConverter(number, gender, true) + " milioni "; + return ThreeDigitSetConverter(number, true) + " milioni "; } /// /// Converts a billions three-digit number to text. /// /// The three-digit number, as billions, to convert. - /// Gender of noun following number /// The same three-digit number of billions expressed as text. - protected static string BillionsConverter(int number, GrammaticalGender gender) + protected static string BillionsConverter(int number) { if (number == 1) return "un miliardo "; - return ThreeDigitSetConverter(number, gender) + " miliardi "; + return ThreeDigitSetConverter(number) + " miliardi "; } /// diff --git a/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs new file mode 100644 index 000000000..abf079af9 --- /dev/null +++ b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections.Generic; + +namespace Humanizer.Localisation.NumberToWords.Italian +{ + class ItalianOrdinalNumberCruncher + { + public ItalianOrdinalNumberCruncher(int number, GrammaticalGender gender) + { + _fullNumber = number; + _gender = gender; + } + + public string Convert() + { + string words = String.Empty; + + if (_fullNumber < 1000) + { + words = UnitsConverter(_fullNumber); + } + + return words; + } + + protected string UnitsConverter(int number) + { + return ThreeDigitSetConverter(number); + } + + protected static string ThreeDigitSetConverter(int number) + { + if (number == 0) + return String.Empty; + + // grab lowest two digits + int tensAndUnits = number % 100; + // grab third digit + int hundreds = (int)(number / 100); + + // grab also first and second digits separately + int units = tensAndUnits % 10; + int tens = (int)(tensAndUnits / 10); + + string words = String.Empty; + + // append text for hundreds + words += _hundredNumberToText[hundreds]; + + // append text for tens, only those from twenty upward + words += _tensOver20NumberToText[tens]; + + if (tensAndUnits <= 9) + { + // simple case for units, under 10 + words += _unitsNumberToText[tensAndUnits]; + } + else if (tensAndUnits <= 19) + { + // special case for 'teens', from 10 to 19 + words += _teensUnder20NumberToText[tensAndUnits - 10]; + } + else + { + // just append units text, with some corner cases + + // truncate tens last vowel before 'uno' (1) and 'otto' (8) + if (units == 1 || units == 8) + { + words = words.Remove(words.Length - 1); + } + + words += _unitsNumberToText[units]; + } + + return words; + } + + protected readonly int _fullNumber; + protected readonly GrammaticalGender _gender; + + /// + /// Lookup table converting units number to text. Index 1 for 1, index 2 for 2, up to index 9. + /// + protected static string[] _unitsNumberToText = new string[] + { + String.Empty, + "primo", + "secondo", + "terzo", + "quarto", + "quinto", + "sesto", + "settimo", + "ottavo", + "nono" + }; + + /// + /// Lookup table converting tens number to text. Index 2 for 20, index 3 for 30, up to index 9 for 90. + /// + protected static string[] _tensOver20NumberToText = new string[] + { + String.Empty, + String.Empty, + "venti", + "trenta", + "quaranta", + "cinquanta", + "sessanta", + "settanta", + "ottanta", + "novanta" + }; + + /// + /// Lookup table converting teens number to text. Index 0 for 10, index 1 for 11, up to index 9 for 19. + /// + protected static string[] _teensUnder20NumberToText = new string[] + { + "decimo", + "undicesimo", + "dodicesimo", + "tredicesimo", + "quattordicesimo", + "quindicesimo", + "sedicesimo", + "diciassettesimo", + "diciottesimo", + "diciannovesimo" + }; + + /// + /// Lookup table converting hundreds number to text. Index 0 for no hundreds, index 1 for 100, up to index 9. + /// + protected static string[] _hundredNumberToText = new string[] + { + String.Empty, + "cento", + "duecento", + "trecento", + "quattrocento", + "cinquecento", + "seicento", + "settecento", + "ottocento", + "novecento" + }; + } +} \ No newline at end of file diff --git a/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs index 2e70dbf56..808d5abd0 100644 --- a/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs +++ b/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs @@ -23,7 +23,9 @@ public override string ConvertToOrdinal(int number, GrammaticalGender gender) if (number == 0) return "zero"; - return String.Empty; + ItalianOrdinalNumberCruncher cruncher = new ItalianOrdinalNumberCruncher(number, gender); + + return cruncher.Convert(); } } } \ No newline at end of file From 17e2e12ca5d8f0db0ec08a61dfb556663c81f88e Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Tue, 26 Aug 2014 18:26:11 +0200 Subject: [PATCH 27/39] L10n: italian NumberToWordsTests passing for ordinals up to 30. --- .../Localisation/it/NumberToWordsTests.cs | 33 +++++++------------ .../Italian/ItalianOrdinalNumberCruncher.cs | 33 ++++++++++++++++--- 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs index cdf2c4165..baf0aa080 100644 --- a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs +++ b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs @@ -104,30 +104,19 @@ public void ToMasculineWords(int number, string expected) [Theory] [InlineData(0, "zero")] - /* [InlineData(1, "primo")] - [InlineData(2, "segundo")] - [InlineData(3, "terceiro")] - [InlineData(4, "quarto")] - [InlineData(5, "quinto")] - [InlineData(6, "sexto")] - [InlineData(7, "sétimo")] - [InlineData(8, "oitavo")] + [InlineData(2, "secondo")] [InlineData(9, "nono")] - [InlineData(10, "décimo")] - [InlineData(11, "décimo primeiro")] - [InlineData(12, "décimo segundo")] - [InlineData(13, "décimo terceiro")] - [InlineData(14, "décimo quarto")] - [InlineData(15, "décimo quinto")] - [InlineData(16, "décimo sexto")] - [InlineData(17, "décimo sétimo")] - [InlineData(18, "décimo oitavo")] - [InlineData(19, "décimo nono")] - [InlineData(20, "vigésimo")] - [InlineData(21, "vigésimo primeiro")] - [InlineData(22, "vigésimo segundo")] - [InlineData(30, "trigésimo")] + [InlineData(10, "decimo")] + [InlineData(11, "undicesimo")] + [InlineData(15, "quindicesimo")] + [InlineData(18, "diciottesimo")] + [InlineData(20, "ventesimo")] + [InlineData(21, "ventunesimo")] + [InlineData(22, "ventiduesimo")] + [InlineData(28, "ventottesimo")] + [InlineData(30, "trentesimo")] + /* [InlineData(40, "quadragésimo")] [InlineData(50, "quinquagésimo")] [InlineData(60, "sexagésimo")] diff --git a/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs index abf079af9..7eb00f436 100644 --- a/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs +++ b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs @@ -53,14 +53,22 @@ protected static string ThreeDigitSetConverter(int number) if (tensAndUnits <= 9) { // simple case for units, under 10 - words += _unitsNumberToText[tensAndUnits]; + words += _unitsUnder10NumberToText[tensAndUnits]; } else if (tensAndUnits <= 19) { // special case for 'teens', from 10 to 19 words += _teensUnder20NumberToText[tensAndUnits - 10]; } - else + else if (units == 0) + { + // truncate tens/hundreds last vowel + words = words.Remove(words.Length - 1); + + // append suffix '-esimo' + words += "esimo"; + } + else { // just append units text, with some corner cases @@ -70,7 +78,7 @@ protected static string ThreeDigitSetConverter(int number) words = words.Remove(words.Length - 1); } - words += _unitsNumberToText[units]; + words += _unitsOver10NumberToText[units]; } return words; @@ -82,7 +90,7 @@ protected static string ThreeDigitSetConverter(int number) /// /// Lookup table converting units number to text. Index 1 for 1, index 2 for 2, up to index 9. /// - protected static string[] _unitsNumberToText = new string[] + protected static string[] _unitsUnder10NumberToText = new string[] { String.Empty, "primo", @@ -96,6 +104,23 @@ protected static string ThreeDigitSetConverter(int number) "nono" }; + /// + /// Lookup table converting units number to text. Index 1 for 1, index 2 for 2, up to index 9. + /// + protected static string[] _unitsOver10NumberToText = new string[] + { + String.Empty, + "unesimo", + "duesimo", + "treesimo", + "quattresimo", + "cinquesimo", + "seiesimo", + "settesimo", + "ottesimo", + "novesimo" + }; + /// /// Lookup table converting tens number to text. Index 2 for 20, index 3 for 30, up to index 9 for 90. /// From adf31539fccc92aac0c76335f7d18fb03f0d8467 Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Tue, 26 Aug 2014 19:34:41 +0200 Subject: [PATCH 28/39] L10n: italian NumberToWordsTests passing for ordinals up to 99. --- .../Localisation/it/NumberToWordsTests.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs index baf0aa080..ec1cb82ea 100644 --- a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs +++ b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs @@ -116,12 +116,15 @@ public void ToMasculineWords(int number, string expected) [InlineData(22, "ventiduesimo")] [InlineData(28, "ventottesimo")] [InlineData(30, "trentesimo")] + [InlineData(44, "quarantaquattresimo")] + [InlineData(55, "cinquantacinquesimo")] + [InlineData(60, "sessantesimo")] + [InlineData(63, "sessantatreesimo")] + [InlineData(66, "sessantaseiesimo")] + [InlineData(77, "settantasettesimo")] + [InlineData(88, "ottantottesimo")] + [InlineData(99, "novantanovesimo")] /* - [InlineData(40, "quadragésimo")] - [InlineData(50, "quinquagésimo")] - [InlineData(60, "sexagésimo")] - [InlineData(70, "septuagésimo")] - [InlineData(80, "octogésimo")] [InlineData(90, "nonagésimo")] [InlineData(95, "nonagésimo quinto")] [InlineData(96, "nonagésimo sexto")] From 2d28a62ba71c68382673ab5c475189cd398b3709 Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Tue, 26 Aug 2014 23:16:29 +0200 Subject: [PATCH 29/39] L10n: italian NumberToWordsTests passing for ordinals up to 201 --- .../Localisation/it/NumberToWordsTests.cs | 17 ++++---- .../Italian/ItalianOrdinalNumberCruncher.cs | 40 ++++++++++++------- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs index ec1cb82ea..99b3ef58c 100644 --- a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs +++ b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs @@ -124,14 +124,17 @@ public void ToMasculineWords(int number, string expected) [InlineData(77, "settantasettesimo")] [InlineData(88, "ottantottesimo")] [InlineData(99, "novantanovesimo")] + [InlineData(100, "centesimo")] + [InlineData(101, "centounesimo")] + [InlineData(102, "centoduesimo")] + [InlineData(105, "centocinquesimo")] + [InlineData(109, "centonovesimo")] + [InlineData(110, "centodecimo")] + [InlineData(120, "centoventesimo")] + [InlineData(121, "centoventunesimo")] + [InlineData(200, "duecentesimo")] + [InlineData(201, "duecentounesimo")] /* - [InlineData(90, "nonagésimo")] - [InlineData(95, "nonagésimo quinto")] - [InlineData(96, "nonagésimo sexto")] - [InlineData(100, "centésimo")] - [InlineData(120, "centésimo vigésimo")] - [InlineData(121, "centésimo vigésimo primeiro")] - [InlineData(200, "ducentésimo")] [InlineData(300, "trecentésimo")] [InlineData(400, "quadringentésimo")] [InlineData(500, "quingentésimo")] diff --git a/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs index 7eb00f436..e86b3747b 100644 --- a/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs +++ b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs @@ -41,43 +41,53 @@ protected static string ThreeDigitSetConverter(int number) // grab also first and second digits separately int units = tensAndUnits % 10; int tens = (int)(tensAndUnits / 10); - + + if (number <= 9) + { + // it's easier to treat units, from 1 to 9, as a distinct case + return _unitsUnder10NumberToText[tensAndUnits]; + } + string words = String.Empty; - + // append text for hundreds words += _hundredNumberToText[hundreds]; - + // append text for tens, only those from twenty upward words += _tensOver20NumberToText[tens]; - - if (tensAndUnits <= 9) + + if (tensAndUnits == 0) { - // simple case for units, under 10 - words += _unitsUnder10NumberToText[tensAndUnits]; + // truncate hundreds last vowel + words = words.Remove(words.Length - 1); + + // append suffix '-esimo' + words += "esimo"; } - else if (tensAndUnits <= 19) + else if (10 <= tensAndUnits && tensAndUnits <= 19) { // special case for 'teens', from 10 to 19 words += _teensUnder20NumberToText[tensAndUnits - 10]; } else if (units == 0) { - // truncate tens/hundreds last vowel + // truncate tens last vowel words = words.Remove(words.Length - 1); - + // append suffix '-esimo' words += "esimo"; } - else + else { // just append units text, with some corner cases - - // truncate tens last vowel before 'uno' (1) and 'otto' (8) - if (units == 1 || units == 8) + + // truncate tens last vowel before 'uno' (1) and 'otto' (8) + // (only tens, not hundreds) + if (tens != 0 && (units == 1 || units == 8)) { words = words.Remove(words.Length - 1); } - + words += _unitsOver10NumberToText[units]; } From 28d72e0a9db0087167f135b5d51c4fc1129bcbdd Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Wed, 27 Aug 2014 00:17:29 +0200 Subject: [PATCH 30/39] L10n: Refactor: move zero logic to NumberCruncher in italian NumberToWordsConverter --- .../Italian/ItalianCardinalNumberCruncher.cs | 8 ++++++-- .../NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs | 4 ++++ .../NumberToWords/ItalianNumberToWordsConverter.cs | 6 ------ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Humanizer/Localisation/NumberToWords/Italian/ItalianCardinalNumberCruncher.cs b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianCardinalNumberCruncher.cs index 382afbc4c..f8cdac9e3 100644 --- a/src/Humanizer/Localisation/NumberToWords/Italian/ItalianCardinalNumberCruncher.cs +++ b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianCardinalNumberCruncher.cs @@ -16,8 +16,12 @@ public ItalianCardinalNumberCruncher(int number, GrammaticalGender gender) public string Convert() { string words = String.Empty; - - foreach(int part in _threeDigitParts) + + // it's easier to treat zero as a completely distinct case + if (_fullNumber == 0) + return "zero"; + + foreach (int part in _threeDigitParts) { Func partToString = GetNextPartConverter(); diff --git a/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs index e86b3747b..8c36313e5 100644 --- a/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs +++ b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs @@ -14,6 +14,10 @@ public ItalianOrdinalNumberCruncher(int number, GrammaticalGender gender) public string Convert() { string words = String.Empty; + + // it's easier to treat zero as a completely distinct case + if (_fullNumber == 0) + return "zero"; if (_fullNumber < 1000) { diff --git a/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs index 808d5abd0..60a8314d4 100644 --- a/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs +++ b/src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs @@ -7,9 +7,6 @@ internal class ItalianNumberToWordsConverter : GenderedNumberToWordsConverter { public override string Convert(int number, GrammaticalGender gender) { - if (number == 0) - return "zero"; - if (number < 0) return "meno " + Convert(Math.Abs(number), gender); @@ -20,9 +17,6 @@ public override string Convert(int number, GrammaticalGender gender) public override string ConvertToOrdinal(int number, GrammaticalGender gender) { - if (number == 0) - return "zero"; - ItalianOrdinalNumberCruncher cruncher = new ItalianOrdinalNumberCruncher(number, gender); return cruncher.Convert(); From 2462be23960ec29b602ebaaddaeeb4917e60cc0f Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Wed, 27 Aug 2014 00:17:53 +0200 Subject: [PATCH 31/39] L10n: italian NumberToWordsTests passing for ordinals up to 900 --- .../Localisation/it/NumberToWordsTests.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs index 99b3ef58c..24b24ce59 100644 --- a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs +++ b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs @@ -130,17 +130,15 @@ public void ToMasculineWords(int number, string expected) [InlineData(105, "centocinquesimo")] [InlineData(109, "centonovesimo")] [InlineData(110, "centodecimo")] + [InlineData(119, "centodiciannovesimo")] [InlineData(120, "centoventesimo")] [InlineData(121, "centoventunesimo")] [InlineData(200, "duecentesimo")] [InlineData(201, "duecentounesimo")] + [InlineData(240, "duecentoquarantesimo")] + [InlineData(300, "trecentesimo")] + [InlineData(900, "novecentesimo")] /* - [InlineData(300, "trecentésimo")] - [InlineData(400, "quadringentésimo")] - [InlineData(500, "quingentésimo")] - [InlineData(600, "sexcentésimo")] - [InlineData(700, "septingentésimo")] - [InlineData(800, "octingentésimo")] [InlineData(900, "noningentésimo")] [InlineData(1000, "milésimo")] [InlineData(1001, "milésimo primeiro")] From 200273d95825a0f243511dbba2c3ec742dc90f58 Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Wed, 27 Aug 2014 00:51:04 +0200 Subject: [PATCH 32/39] L10n: Refactor: italian ordinal NumberToWords reuses cardinal logic --- .../Italian/ItalianCardinalNumberCruncher.cs | 4 +- .../Italian/ItalianOrdinalNumberCruncher.cs | 159 +++--------------- 2 files changed, 27 insertions(+), 136 deletions(-) diff --git a/src/Humanizer/Localisation/NumberToWords/Italian/ItalianCardinalNumberCruncher.cs b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianCardinalNumberCruncher.cs index f8cdac9e3..00b8912cf 100644 --- a/src/Humanizer/Localisation/NumberToWords/Italian/ItalianCardinalNumberCruncher.cs +++ b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianCardinalNumberCruncher.cs @@ -15,12 +15,12 @@ public ItalianCardinalNumberCruncher(int number, GrammaticalGender gender) public string Convert() { - string words = String.Empty; - // it's easier to treat zero as a completely distinct case if (_fullNumber == 0) return "zero"; + string words = String.Empty; + foreach (int part in _threeDigitParts) { Func partToString = GetNextPartConverter(); diff --git a/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs index 8c36313e5..cebdb6270 100644 --- a/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs +++ b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs @@ -13,94 +13,50 @@ public ItalianOrdinalNumberCruncher(int number, GrammaticalGender gender) public string Convert() { - string words = String.Empty; - // it's easier to treat zero as a completely distinct case if (_fullNumber == 0) return "zero"; - - if (_fullNumber < 1000) - { - words = UnitsConverter(_fullNumber); - } - - return words; - } - - protected string UnitsConverter(int number) - { - return ThreeDigitSetConverter(number); - } - - protected static string ThreeDigitSetConverter(int number) - { - if (number == 0) - return String.Empty; - - // grab lowest two digits - int tensAndUnits = number % 100; - // grab third digit - int hundreds = (int)(number / 100); - - // grab also first and second digits separately - int units = tensAndUnits % 10; - int tens = (int)(tensAndUnits / 10); - if (number <= 9) + if (_fullNumber <= 9) { - // it's easier to treat units, from 1 to 9, as a distinct case - return _unitsUnder10NumberToText[tensAndUnits]; + // units ordinals, 1 to 9, are totally different than the rest: treat them as a distinct case + return _unitsUnder10NumberToText[_fullNumber]; } - string words = String.Empty; + ItalianCardinalNumberCruncher cardinalCruncher = new ItalianCardinalNumberCruncher(_fullNumber, _gender); - // append text for hundreds - words += _hundredNumberToText[hundreds]; + string words = cardinalCruncher.Convert(); - // append text for tens, only those from twenty upward - words += _tensOver20NumberToText[tens]; + int tensAndUnits = _fullNumber % 100; - if (tensAndUnits == 0) + if (tensAndUnits == 10) { - // truncate hundreds last vowel - words = words.Remove(words.Length - 1); - - // append suffix '-esimo' - words += "esimo"; + // for numbers ending in 10, cardinal and ordinal endings are different, suffix doesn't work + words = words.Remove(words.Length - _lengthOf10AsCardinal) + "decimo"; } - else if (10 <= tensAndUnits && tensAndUnits <= 19) - { - // special case for 'teens', from 10 to 19 - words += _teensUnder20NumberToText[tensAndUnits - 10]; - } - else if (units == 0) + else { - // truncate tens last vowel + // truncate last vowel words = words.Remove(words.Length - 1); - // append suffix '-esimo' - words += "esimo"; - } - else - { - // just append units text, with some corner cases + int units = _fullNumber % 10; - // truncate tens last vowel before 'uno' (1) and 'otto' (8) - // (only tens, not hundreds) - if (tens != 0 && (units == 1 || units == 8)) - { - words = words.Remove(words.Length - 1); - } + // reintroduce *unaccented* last vowel in some corner cases + if (units == 3) + words += 'e'; + else if (units == 6) + words += 'i'; - words += _unitsOver10NumberToText[units]; + // append common ordinal suffix + words += "esimo"; } - + return words; } - + protected readonly int _fullNumber; protected readonly GrammaticalGender _gender; - + /// /// Lookup table converting units number to text. Index 1 for 1, index 2 for 2, up to index 9. /// @@ -117,73 +73,8 @@ protected static string ThreeDigitSetConverter(int number) "ottavo", "nono" }; - - /// - /// Lookup table converting units number to text. Index 1 for 1, index 2 for 2, up to index 9. - /// - protected static string[] _unitsOver10NumberToText = new string[] - { - String.Empty, - "unesimo", - "duesimo", - "treesimo", - "quattresimo", - "cinquesimo", - "seiesimo", - "settesimo", - "ottesimo", - "novesimo" - }; - - /// - /// Lookup table converting tens number to text. Index 2 for 20, index 3 for 30, up to index 9 for 90. - /// - protected static string[] _tensOver20NumberToText = new string[] - { - String.Empty, - String.Empty, - "venti", - "trenta", - "quaranta", - "cinquanta", - "sessanta", - "settanta", - "ottanta", - "novanta" - }; - - /// - /// Lookup table converting teens number to text. Index 0 for 10, index 1 for 11, up to index 9 for 19. - /// - protected static string[] _teensUnder20NumberToText = new string[] - { - "decimo", - "undicesimo", - "dodicesimo", - "tredicesimo", - "quattordicesimo", - "quindicesimo", - "sedicesimo", - "diciassettesimo", - "diciottesimo", - "diciannovesimo" - }; - - /// - /// Lookup table converting hundreds number to text. Index 0 for no hundreds, index 1 for 100, up to index 9. - /// - protected static string[] _hundredNumberToText = new string[] - { - String.Empty, - "cento", - "duecento", - "trecento", - "quattrocento", - "cinquecento", - "seicento", - "settecento", - "ottocento", - "novecento" - }; + + protected static int _lengthOf10AsCardinal = "dieci".Length; + } } \ No newline at end of file From 2901c67a50295e024feb11923acc7eec9438023f Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Wed, 27 Aug 2014 01:03:49 +0200 Subject: [PATCH 33/39] L10n: italian NumberToWordsTests passing for ordinals up to 10121 --- .../Localisation/it/NumberToWordsTests.cs | 19 +++++++++++++------ .../Italian/ItalianOrdinalNumberCruncher.cs | 5 +++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs index 24b24ce59..0e352772d 100644 --- a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs +++ b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs @@ -138,13 +138,20 @@ public void ToMasculineWords(int number, string expected) [InlineData(240, "duecentoquarantesimo")] [InlineData(300, "trecentesimo")] [InlineData(900, "novecentesimo")] + [InlineData(1000, "millesimo")] + [InlineData(1001, "milleunesimo")] + [InlineData(1002, "milleduesimo")] + [InlineData(1003, "milletreesimo")] + [InlineData(1009, "millenovesimo")] + [InlineData(1010, "milledecimo")] + [InlineData(1021, "milleventunesimo")] + [InlineData(2000, "duemillesimo")] + [InlineData(2001, "duemilaunesimo")] + [InlineData(3000, "tremillesimo")] + [InlineData(10000, "diecimillesimo")] + [InlineData(10001, "diecimilaunesimo")] + [InlineData(10121, "diecimilacentoventunesimo")] /* - [InlineData(900, "noningentésimo")] - [InlineData(1000, "milésimo")] - [InlineData(1001, "milésimo primeiro")] - [InlineData(1021, "milésimo vigésimo primeiro")] - [InlineData(2021, "segundo milésimo vigésimo primeiro")] - [InlineData(10000, "décimo milésimo")] [InlineData(10121, "décimo milésimo centésimo vigésimo primeiro")] [InlineData(100000, "centésimo milésimo")] [InlineData(1000000, "milionésimo")] diff --git a/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs index cebdb6270..bd500c440 100644 --- a/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs +++ b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs @@ -40,6 +40,7 @@ public string Convert() words = words.Remove(words.Length - 1); int units = _fullNumber % 10; + int lowestThreeDigits = _fullNumber % 1000; // reintroduce *unaccented* last vowel in some corner cases if (units == 3) @@ -47,6 +48,10 @@ public string Convert() else if (units == 6) words += 'i'; + // double the final 'l' if exact thousands, apart 1000 already having that + if (lowestThreeDigits == 0 && _fullNumber > 1000) + words += 'l'; + // append common ordinal suffix words += "esimo"; } From 06d7d14df4de906e0769c3cfe3aebe38b69cada2 Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Wed, 27 Aug 2014 01:20:47 +0200 Subject: [PATCH 34/39] L10n: italian NumberToWordsTests passing for ordinals up to 100000000 --- .../Localisation/it/NumberToWordsTests.cs | 16 +++++++++++----- .../Italian/ItalianOrdinalNumberCruncher.cs | 18 ++++++++++++++++-- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs index 0e352772d..4c438434e 100644 --- a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs +++ b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs @@ -151,12 +151,18 @@ public void ToMasculineWords(int number, string expected) [InlineData(10000, "diecimillesimo")] [InlineData(10001, "diecimilaunesimo")] [InlineData(10121, "diecimilacentoventunesimo")] + [InlineData(100000, "centomillesimo")] + [InlineData(100001, "centomilaunesimo")] + [InlineData(1000000, "milionesimo")] + [InlineData(1000001, "un milione unesimo")] + [InlineData(1000002, "un milione duesimo")] + [InlineData(2000000, "duemilionesimo")] + [InlineData(10000000, "diecimilionesimo")] + [InlineData(100000000, "centomilionesimo")] /* - [InlineData(10121, "décimo milésimo centésimo vigésimo primeiro")] - [InlineData(100000, "centésimo milésimo")] - [InlineData(1000000, "milionésimo")] - [InlineData(1000000000, "bilionésimo")] - */ + [InlineData(1000000000, "miliardesimo")] + [InlineData(2000000000, "duemiliardesimo")] + * */ public void ToOrdinalWords(int number, string expected) { Assert.Equal(expected, number.ToOrdinalWords()); diff --git a/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs index bd500c440..2be64365c 100644 --- a/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs +++ b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs @@ -41,6 +41,7 @@ public string Convert() int units = _fullNumber % 10; int lowestThreeDigits = _fullNumber % 1000; + int lowestSixDigits = _fullNumber % 1000000; // reintroduce *unaccented* last vowel in some corner cases if (units == 3) @@ -48,9 +49,22 @@ public string Convert() else if (units == 6) words += 'i'; - // double the final 'l' if exact thousands, apart 1000 already having that - if (lowestThreeDigits == 0 && _fullNumber > 1000) + if (lowestSixDigits == 0) + { + // if exact millions, cardinal number words are joined + words = words.Replace(" milion", "milion"); + + // if 1 million, numeral prefix is removed completely + if (_fullNumber == 1000000) + { + words = words.Replace("un", String.Empty); + } + } + else if (lowestThreeDigits == 0 && _fullNumber > 1000) + { + // if exact thousands, double the final 'l', apart from 1000 already having that words += 'l'; + } // append common ordinal suffix words += "esimo"; From c9cad01000d3dc1c33070a80d9801b3ac7beb3c4 Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Wed, 27 Aug 2014 01:30:28 +0200 Subject: [PATCH 35/39] L10n: italian NumberToWordsTests passing for ordinals up to 2 billions --- .../Localisation/it/NumberToWordsTests.cs | 2 -- .../Italian/ItalianOrdinalNumberCruncher.cs | 14 +++++++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs index 4c438434e..30fc46f77 100644 --- a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs +++ b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs @@ -159,10 +159,8 @@ public void ToMasculineWords(int number, string expected) [InlineData(2000000, "duemilionesimo")] [InlineData(10000000, "diecimilionesimo")] [InlineData(100000000, "centomilionesimo")] - /* [InlineData(1000000000, "miliardesimo")] [InlineData(2000000000, "duemiliardesimo")] - * */ public void ToOrdinalWords(int number, string expected) { Assert.Equal(expected, number.ToOrdinalWords()); diff --git a/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs index 2be64365c..ef656bbc2 100644 --- a/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs +++ b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs @@ -42,6 +42,7 @@ public string Convert() int units = _fullNumber % 10; int lowestThreeDigits = _fullNumber % 1000; int lowestSixDigits = _fullNumber % 1000000; + int lowestNineDigits = _fullNumber % 1000000000; // reintroduce *unaccented* last vowel in some corner cases if (units == 3) @@ -49,7 +50,18 @@ public string Convert() else if (units == 6) words += 'i'; - if (lowestSixDigits == 0) + if (lowestNineDigits == 0) + { + // if exact billions, cardinal number words are joined + words = words.Replace(" miliard", "miliard"); + + // if 1 billion, numeral prefix is removed completely + if (_fullNumber == 1000000000) + { + words = words.Replace("un", String.Empty); + } + } + else if (lowestSixDigits == 0) { // if exact millions, cardinal number words are joined words = words.Replace(" milion", "milion"); From 164f12c04449f010b16e994979a9f29845ed2622 Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Wed, 27 Aug 2014 03:37:38 +0200 Subject: [PATCH 36/39] L10n: italian NumberToWordsTests passing for feminine ordinal --- .../Localisation/it/NumberToWordsTests.cs | 68 ++++--------------- .../Italian/ItalianOrdinalNumberCruncher.cs | 27 ++++---- 2 files changed, 29 insertions(+), 66 deletions(-) diff --git a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs index 30fc46f77..418f82244 100644 --- a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs +++ b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs @@ -166,64 +166,26 @@ public void ToOrdinalWords(int number, string expected) Assert.Equal(expected, number.ToOrdinalWords()); } - /* [Theory] [InlineData(0, "zero")] - [InlineData(1, "primeira")] - [InlineData(2, "segunda")] - [InlineData(3, "terceira")] - [InlineData(4, "quarta")] + [InlineData(1, "prima")] + [InlineData(2, "seconda")] [InlineData(5, "quinta")] - [InlineData(6, "sexta")] - [InlineData(7, "sétima")] - [InlineData(8, "oitava")] [InlineData(9, "nona")] - [InlineData(10, "décima")] - [InlineData(11, "décima primeira")] - [InlineData(12, "décima segunda")] - [InlineData(13, "décima terceira")] - [InlineData(14, "décima quarta")] - [InlineData(15, "décima quinta")] - [InlineData(16, "décima sexta")] - [InlineData(17, "décima sétima")] - [InlineData(18, "décima oitava")] - [InlineData(19, "décima nona")] - [InlineData(20, "vigésima")] - [InlineData(21, "vigésima primeira")] - [InlineData(22, "vigésima segunda")] - [InlineData(30, "trigésima")] - [InlineData(40, "quadragésima")] - [InlineData(50, "quinquagésima")] - [InlineData(60, "sexagésima")] - [InlineData(70, "septuagésima")] - [InlineData(80, "octogésima")] - [InlineData(90, "nonagésima")] - [InlineData(95, "nonagésima quinta")] - [InlineData(96, "nonagésima sexta")] - [InlineData(100, "centésima")] - [InlineData(120, "centésima vigésima")] - [InlineData(121, "centésima vigésima primeira")] - [InlineData(200, "ducentésima")] - [InlineData(300, "trecentésima")] - [InlineData(400, "quadringentésima")] - [InlineData(500, "quingentésima")] - [InlineData(600, "sexcentésima")] - [InlineData(700, "septingentésima")] - [InlineData(800, "octingentésima")] - [InlineData(900, "noningentésima")] - [InlineData(1000, "milésima")] - [InlineData(1001, "milésima primeira")] - [InlineData(1021, "milésima vigésima primeira")] - [InlineData(2021, "segunda milésima vigésima primeira")] - [InlineData(10000, "décima milésima")] - [InlineData(10121, "décima milésima centésima vigésima primeira")] - [InlineData(100000, "centésima milésima")] - [InlineData(1000000, "milionésima")] - [InlineData(1000000000, "bilionésima")] - public void ToFeminineOrdinalWords(int number, string words) + [InlineData(10, "decima")] + [InlineData(11, "undicesima")] + [InlineData(18, "diciottesima")] + [InlineData(20, "ventesima")] + [InlineData(21, "ventunesima")] + [InlineData(100, "centesima")] + [InlineData(101, "centounesima")] + [InlineData(200, "duecentesima")] + [InlineData(1000, "millesima")] + [InlineData(1001, "milleunesima")] + [InlineData(10000, "diecimillesima")] + public void ToFeminineOrdinalWords(int number, string expected) { - Assert.Equal(words, number.ToOrdinalWords(GrammaticalGender.Feminine)); + Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Feminine)); } - */ } } \ No newline at end of file diff --git a/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs index ef656bbc2..da5774dce 100644 --- a/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs +++ b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs @@ -9,6 +9,7 @@ public ItalianOrdinalNumberCruncher(int number, GrammaticalGender gender) { _fullNumber = number; _gender = gender; + _genderSuffix = (gender == GrammaticalGender.Feminine ? "a" : "o"); } public string Convert() @@ -20,7 +21,7 @@ public string Convert() if (_fullNumber <= 9) { // units ordinals, 1 to 9, are totally different than the rest: treat them as a distinct case - return _unitsUnder10NumberToText[_fullNumber]; + return _unitsUnder10NumberToText[_fullNumber] + _genderSuffix; } ItalianCardinalNumberCruncher cardinalCruncher = new ItalianCardinalNumberCruncher(_fullNumber, _gender); @@ -32,7 +33,7 @@ public string Convert() if (tensAndUnits == 10) { // for numbers ending in 10, cardinal and ordinal endings are different, suffix doesn't work - words = words.Remove(words.Length - _lengthOf10AsCardinal) + "decimo"; + words = words.Remove(words.Length - _lengthOf10AsCardinal) + "decim" + _genderSuffix; } else { @@ -79,7 +80,7 @@ public string Convert() } // append common ordinal suffix - words += "esimo"; + words += "esim" + _genderSuffix; } return words; @@ -87,6 +88,7 @@ public string Convert() protected readonly int _fullNumber; protected readonly GrammaticalGender _gender; + private readonly string _genderSuffix; /// /// Lookup table converting units number to text. Index 1 for 1, index 2 for 2, up to index 9. @@ -94,18 +96,17 @@ public string Convert() protected static string[] _unitsUnder10NumberToText = new string[] { String.Empty, - "primo", - "secondo", - "terzo", - "quarto", - "quinto", - "sesto", - "settimo", - "ottavo", - "nono" + "prim", + "second", + "terz", + "quart", + "quint", + "sest", + "settim", + "ottav", + "non" }; protected static int _lengthOf10AsCardinal = "dieci".Length; - } } \ No newline at end of file From af961ff4a69b91afcf8272785dbbd253e7cbc612 Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Thu, 28 Aug 2014 21:03:28 +0200 Subject: [PATCH 37/39] L10n: italian NumberToWordsTests passing for masculine ordinal --- .../Localisation/it/NumberToWordsTests.cs | 22 +++++++++++++++++++ .../Italian/ItalianOrdinalNumberCruncher.cs | 7 +++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs index 418f82244..f1e36fa05 100644 --- a/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs +++ b/src/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs @@ -187,5 +187,27 @@ public void ToFeminineOrdinalWords(int number, string expected) { Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Feminine)); } + + [Theory] + [InlineData(0, "zero")] + [InlineData(1, "primo")] + [InlineData(2, "secondo")] + [InlineData(5, "quinto")] + [InlineData(9, "nono")] + [InlineData(10, "decimo")] + [InlineData(11, "undicesimo")] + [InlineData(18, "diciottesimo")] + [InlineData(20, "ventesimo")] + [InlineData(21, "ventunesimo")] + [InlineData(100, "centesimo")] + [InlineData(101, "centounesimo")] + [InlineData(200, "duecentesimo")] + [InlineData(1000, "millesimo")] + [InlineData(1001, "milleunesimo")] + [InlineData(10000, "diecimillesimo")] + public void ToMasculineOrdinalWords(int number, string expected) + { + Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Masculine)); + } } } \ No newline at end of file diff --git a/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs index da5774dce..b511ace80 100644 --- a/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs +++ b/src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs @@ -41,9 +41,6 @@ public string Convert() words = words.Remove(words.Length - 1); int units = _fullNumber % 10; - int lowestThreeDigits = _fullNumber % 1000; - int lowestSixDigits = _fullNumber % 1000000; - int lowestNineDigits = _fullNumber % 1000000000; // reintroduce *unaccented* last vowel in some corner cases if (units == 3) @@ -51,6 +48,10 @@ public string Convert() else if (units == 6) words += 'i'; + int lowestThreeDigits = _fullNumber % 1000; + int lowestSixDigits = _fullNumber % 1000000; + int lowestNineDigits = _fullNumber % 1000000000; + if (lowestNineDigits == 0) { // if exact billions, cardinal number words are joined From ceba64c8608f3c47dbf1536829aa00f6888e3213 Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Thu, 28 Aug 2014 21:21:03 +0200 Subject: [PATCH 38/39] Added PR entry in release notes --- release_notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/release_notes.md b/release_notes.md index e9d0f5ae4..91170d3e6 100644 --- a/release_notes.md +++ b/release_notes.md @@ -2,6 +2,7 @@ - [#320](https://github.com/MehdiK/Humanizer/pull/320): Fixed Dehumanize actually humanizing an already dehumanized string - [#322](https://github.com/MehdiK/Humanizer/pull/322): DefaultFormatter.TimeSpanHumanize throws a more meaningful exception when called with TimeUnits larger than TimeUnit.Week - [#314](https://github.com/MehdiK/Humanizer/pull/314): Added ByteRate class and supporting members to facilitate calculation of byte transfer rates + - [#332](https://github.com/MehdiK/Humanizer/pull/332): Added Italian localisation and tests: date and time Resources, CollectionFormatter, NumberToWordsConverter (cardinal and ordinal), Ordinalizer [Commits](https://github.com/MehdiK/Humanizer/compare/v1.28.0...master) From 8c2f27576755799737f17132737788ab567d8c17 Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Mon, 1 Sep 2014 11:24:41 +0200 Subject: [PATCH 39/39] Refactor: ItalianCollectionFormatter starts with an array, not enumerable --- .../ItalianCollectionFormatter.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Humanizer/Localisation/CollectionFormatters/ItalianCollectionFormatter.cs b/src/Humanizer/Localisation/CollectionFormatters/ItalianCollectionFormatter.cs index 29cc49e21..bed8328aa 100644 --- a/src/Humanizer/Localisation/CollectionFormatters/ItalianCollectionFormatter.cs +++ b/src/Humanizer/Localisation/CollectionFormatters/ItalianCollectionFormatter.cs @@ -17,23 +17,23 @@ public override string Humanize(IEnumerable collection, Func ob if (collection == null) throw new ArgumentException("collection"); - var enumerable = collection as T[] ?? collection.ToArray(); + T[] itemsArray = collection as T[] ?? collection.ToArray(); - int count = enumerable.Count(); + int count = itemsArray.Length; if (count == 0) return ""; if (count == 1) - return objectFormatter(enumerable.First()); + return objectFormatter(itemsArray[0]); - var frontItems = enumerable.Take(count - 1); - var tailItem = enumerable.Skip(count - 1).First(); + IEnumerable itemsBeforeLast = itemsArray.Take(count - 1); + T lastItem = itemsArray.Skip(count - 1).First(); return String.Format("{0} {1} {2}", - String.Join(", ", frontItems.Select(objectFormatter)), + String.Join(", ", itemsBeforeLast.Select(objectFormatter)), separator, - objectFormatter(tailItem)); + objectFormatter(lastItem)); } } }