diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index d6fa05aa2..f1b611dc0 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -42,7 +42,7 @@ Currently Humanizer supports quite a few localisations for `DateTime.Humanize`,
Humanizer could definitely do with more translations.
To add a translation for `DateTime.Humanize` and `TimeSpan.Humanize`,
fork the repository if you haven't done yet, duplicate the [resources.resx](https://github.com/Humanizr/Humanizer/blob/master/src/Humanizer/Properties/Resources.resx) file, add your target [locale code](http://msdn.microsoft.com/en-us/library/hh441729.aspx)
-to the end (e.g. resources.ru.resx for Russian), translate the values to your language, write unit tests for the translation, commit, and send a pull request for it. Thanks.
+to the end (e.g. resources.ru.resx for Russian), translate the values to your language, register your formatter in [FormatterRegistry.cs](https://github.com/Humanizr/Humanizer/blob/master/src/Humanizer/Configuration/FormatterRegistry.cs), write unit tests for the translation, commit, and send a pull request for it. Thanks.
Some languages have complex rules when it comes to dealing with numbers; for example, in Romanian "5 days" is "5 zile", while "24 days" is "24 de zile" and in Arabic "2 days" is "يومان" not "2 يوم".
Obviously a normal resource file doesn't cut it in these cases as a more complex mapping is required.
diff --git a/NuSpecs/Humanizer.Core.mt.nuspec b/NuSpecs/Humanizer.Core.mt.nuspec
new file mode 100644
index 000000000..3a5749838
--- /dev/null
+++ b/NuSpecs/Humanizer.Core.mt.nuspec
@@ -0,0 +1,24 @@
+
+
+
+ Humanizer.Core.mt
+ $version$
+ Humanizer Locale (mt)
+ Mehdi Khalili, Oren Novotny
+ https://github.com/Humanizr/Humanizer
+ https://raw.github.com/Humanizr/Humanizer/master/logo.png
+ false
+ Humanizer Locale (mt)
+ Copyright (c) .NET Foundation and Contributors
+ https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE
+
+ mt
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Humanizer.Tests.Shared/Humanizer.Tests.Shared.projitems b/src/Humanizer.Tests.Shared/Humanizer.Tests.Shared.projitems
index 315e288d1..29ca4b6fb 100644
--- a/src/Humanizer.Tests.Shared/Humanizer.Tests.Shared.projitems
+++ b/src/Humanizer.Tests.Shared/Humanizer.Tests.Shared.projitems
@@ -96,6 +96,9 @@
+
+
+
diff --git a/src/Humanizer.Tests.Shared/Localisation/mt/DateHumanizeTests.cs b/src/Humanizer.Tests.Shared/Localisation/mt/DateHumanizeTests.cs
new file mode 100644
index 000000000..9511dab70
--- /dev/null
+++ b/src/Humanizer.Tests.Shared/Localisation/mt/DateHumanizeTests.cs
@@ -0,0 +1,124 @@
+using Humanizer.Localisation;
+using Xunit;
+
+namespace Humanizer.Tests.Localisation.mt
+{
+
+ [UseCulture("mt")]
+ public class DateHumanizeTests
+ {
+
+ [Theory]
+ [InlineData(-3, "3 jiem ilu")]
+ [InlineData(-2, "jumejn ilu")]
+ [InlineData(-1, "il-bieraħ")]
+ public void DaysAgo(int days, string expected)
+ {
+ DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past);
+ }
+
+ [Theory]
+ [InlineData(3, "3 jiem oħra")]
+ [InlineData(2, "pitgħada")]
+ [InlineData(1, "għada")]
+ public void DaysFromNow(int days, string expected)
+ {
+ DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future);
+ }
+
+ [Theory]
+ [InlineData(-3, "3 siegħat ilu")]
+ [InlineData(-2, "sagħtejn ilu")]
+ [InlineData(-1, "siegħa ilu")]
+ public void HoursAgo(int hours, string expected)
+ {
+ DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past);
+ }
+
+ [Theory]
+ [InlineData(3, "3 siegħat oħra")]
+ [InlineData(2, "sagħtejn oħra")]
+ [InlineData(1, "siegħa oħra")]
+ public void HoursFromNow(int hours, string expected)
+ {
+ DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future);
+ }
+
+ [Theory]
+ [InlineData(-3, "3 minuti ilu")]
+ [InlineData(-2, "2 minuti ilu")]
+ [InlineData(-1, "minuta ilu")]
+ [InlineData(60, "siegħa ilu")]
+ public void MinutesAgo(int minutes, string expected)
+ {
+ DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past);
+ }
+
+ [Theory]
+ [InlineData(2, "2 minuti oħra")]
+ [InlineData(1, "minuta oħra")]
+ public void MinutesFromNow(int minutes, string expected)
+ {
+ DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future);
+ }
+
+ [Theory]
+ [InlineData(-3, "3 xhur ilu")]
+ [InlineData(-2, "xahrejn ilu")]
+ [InlineData(-1, "xahar ilu")]
+ public void MonthsAgo(int months, string expected)
+ {
+ DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past);
+ }
+
+ [Theory]
+ [InlineData(3, "3 xhur oħra")]
+ [InlineData(2, "xahrejn oħra")]
+ [InlineData(1, "xahar ieħor")]
+ public void MonthsFromNow(int months, string expected)
+ {
+ DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future);
+ }
+
+ [Theory]
+ [InlineData(-2, "2 sekondi ilu")]
+ [InlineData(-1, "sekonda ilu")]
+ public void SecondsAgo(int seconds, string expected)
+ {
+ DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past);
+ }
+
+ [Theory]
+ [InlineData(2, "2 sekondi oħra")]
+ [InlineData(1, "sekonda oħra")]
+ public void SecondsFromNow(int seconds, string expected)
+ {
+ DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future);
+ }
+
+ [Theory]
+ [InlineData(-3, "3 snin ilu")]
+ [InlineData(-2, "sentejn ilu")]
+ [InlineData(-1, "sena ilu")]
+ public void YearsAgo(int years, string expected)
+ {
+ DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past);
+ }
+
+ [Theory]
+ [InlineData(3, "3 snin oħra")]
+ [InlineData(2, "sentejn oħra")]
+ [InlineData(1, "sena oħra")]
+ public void YearsFromNow(int years, string expected)
+ {
+ DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future);
+ }
+
+ [Theory]
+ [InlineData(0, "issa")]
+ public void Now(int years, string expected)
+ {
+ DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future);
+ }
+ }
+}
diff --git a/src/Humanizer.Tests.Shared/Localisation/mt/NumberToWordsTests.cs b/src/Humanizer.Tests.Shared/Localisation/mt/NumberToWordsTests.cs
new file mode 100644
index 000000000..3038a0b82
--- /dev/null
+++ b/src/Humanizer.Tests.Shared/Localisation/mt/NumberToWordsTests.cs
@@ -0,0 +1,284 @@
+using Xunit;
+namespace Humanizer.Tests.Localisation.mt
+{
+ [UseCulture("mt")]
+ public class NumberToWordsTests
+ {
+
+ [Theory]
+ [InlineData(0, "żero")]
+ [InlineData(1, "wieħed")]
+ [InlineData(3, "tlieta")]
+ [InlineData(10, "għaxra")]
+ [InlineData(11, "ħdax")]
+ [InlineData(20, "għoxrin")]
+ [InlineData(21, "wieħed u għoxrin")]
+ [InlineData(38, "tmienja u tletin")]
+ [InlineData(43, "tlieta u erbgħin")]
+ [InlineData(78, "tmienja u sebgħin")]
+ [InlineData(99, "disgħa u disgħin")]
+ [InlineData(100, "mija")]
+ [InlineData(101, "mija u wieħed")]
+ [InlineData(103, "mija u tlieta")]
+ [InlineData(110, "mija u għaxra")]
+ [InlineData(111, "mija u ħdax")]
+ [InlineData(121, "mija u wieħed u għoxrin")]
+ [InlineData(122, "mija u tnejn u għoxrin")]
+ [InlineData(123, "mija u tlieta u għoxrin")]
+ [InlineData(138, "mija u tmienja u tletin")]
+ [InlineData(143, "mija u tlieta u erbgħin")]
+ [InlineData(178, "mija u tmienja u sebgħin")]
+ [InlineData(199, "mija u disgħa u disgħin")]
+ [InlineData(200, "mitejn")]
+ [InlineData(201, "mitejn u wieħed")]
+ [InlineData(203, "mitejn u tlieta")]
+ [InlineData(210, "mitejn u għaxra")]
+ [InlineData(211, "mitejn u ħdax")]
+ [InlineData(221, "mitejn u wieħed u għoxrin")]
+ [InlineData(222, "mitejn u tnejn u għoxrin")]
+ [InlineData(223, "mitejn u tlieta u għoxrin")]
+ [InlineData(238, "mitejn u tmienja u tletin")]
+ [InlineData(243, "mitejn u tlieta u erbgħin")]
+ [InlineData(278, "mitejn u tmienja u sebgħin")]
+ [InlineData(299, "mitejn u disgħa u disgħin")]
+ [InlineData(300, "tlett mija")]
+ [InlineData(401, "erbgħa mija u wieħed")]
+ [InlineData(503, "ħames mija u tlieta")]
+ [InlineData(610, "sitt mija u għaxra")]
+ [InlineData(711, "sebgħa mija u ħdax")]
+ [InlineData(821, "tminn mija u wieħed u għoxrin")]
+ [InlineData(922, "disgħa mija u tnejn u għoxrin")]
+ [InlineData(323, "tlett mija u tlieta u għoxrin")]
+ [InlineData(438, "erbgħa mija u tmienja u tletin")]
+ [InlineData(543, "ħames mija u tlieta u erbgħin")]
+ [InlineData(678, "sitt mija u tmienja u sebgħin")]
+ [InlineData(799, "sebgħa mija u disgħa u disgħin")]
+ [InlineData(1000, "elf")]
+ [InlineData(1001, "elf u wieħed")]
+ [InlineData(1111, "elf u mija u ħdax")]
+ [InlineData(1234, "elf u mitejn u erbgħa u tletin")]
+ [InlineData(1999, "elf u disgħa mija u disgħa u disgħin")]
+ [InlineData(2000, "elfejn")]
+ [InlineData(2014, "elfejn u erbatax")]
+ [InlineData(2048, "elfejn u tmienja u erbgħin")]
+ [InlineData(3000, "tlett elef")]
+ [InlineData(3501, "tlett elef u ħames mija u wieħed")]
+ [InlineData(8100, "tmint elef u mija")]
+ [InlineData(10000, "għaxart elef")]
+ [InlineData(10001, "għaxart elef u wieħed")]
+ [InlineData(12345, "tnax il-elf u tlett mija u ħamsa u erbgħin")]
+ [InlineData(18000, "tmintax il-elf")]
+ [InlineData(100000, "mitt elf")]
+ [InlineData(100001, "mitt elf u wieħed")]
+ [InlineData(111111, "mija u ħdax il-elf u mija u ħdax")]
+ [InlineData(123456, "mija u tlieta u għoxrin elf u erbgħa mija u sitta u ħamsin")]
+ [InlineData(1000000, "miljun")]
+ [InlineData(1000001, "miljun u wieħed")]
+ [InlineData(1111101, "miljun u mija u ħdax il-elf u mija u wieħed")]
+ [InlineData(1111111, "miljun u mija u ħdax il-elf u mija u ħdax")]
+ [InlineData(1234567, "miljun u mitejn u erbgħa u tletin elf u ħames mija u sebgħa u sittin")]
+ [InlineData(5000000, "ħames miljuni")]
+ [InlineData(10000000, "għaxar miljuni")]
+ [InlineData(10000001, "għaxar miljuni u wieħed")]
+ [InlineData(11111111, "ħdax il-miljun u mija u ħdax il-elf u mija u ħdax")]
+ [InlineData(12345678, "tnax il-miljun u tlett mija u ħamsa u erbgħin elf u sitt mija u tmienja u sebgħin")]
+ [InlineData(100000000, "mitt miljun")]
+ [InlineData(100000001, "mitt miljun u wieħed")]
+ [InlineData(111111111, "mija u ħdax il-miljun u mija u ħdax il-elf u mija u ħdax")]
+ [InlineData(123456789, "mija u tlieta u għoxrin miljun u erbgħa mija u sitta u ħamsin elf u sebgħa mija u disgħa u tmenin")]
+ [InlineData(1000000000, "biljun")]
+ [InlineData(1000000001, "biljun u wieħed")]
+ [InlineData(1101111101, "biljun u mija u miljun u mija u ħdax il-elf u mija u wieħed")]
+ [InlineData(2000000000, "żewġ biljuni")]
+ [InlineData(2147483647, "żewġ biljuni u mija u sebgħa u erbgħin miljun u erbgħa mija u tlieta u tmenin elf u sitt mija u sebgħa u erbgħin")]
+ public void ToWords(int number, string expected)
+ {
+ Assert.Equal(expected, number.ToWords());
+ }
+
+ [Theory]
+ [InlineData(1, "waħda")]
+ [InlineData(1001, "elf u waħda")]
+ [InlineData(100001, "mitt elf u waħda")]
+ [InlineData(1000000001, "biljun u waħda")]
+ public void ToFeminineWords(int number, string expected)
+ {
+ Assert.Equal(expected, number.ToWords(GrammaticalGender.Feminine));
+ }
+
+ [Theory]
+ [InlineData(0, "żero")]
+ [InlineData(1, "wieħed")]
+ [InlineData(3, "tlieta")]
+ [InlineData(10, "għaxra")]
+ [InlineData(11, "ħdax")]
+ [InlineData(20, "għoxrin")]
+ [InlineData(21, "wieħed u għoxrin")]
+ [InlineData(38, "tmienja u tletin")]
+ [InlineData(43, "tlieta u erbgħin")]
+ [InlineData(78, "tmienja u sebgħin")]
+ [InlineData(99, "disgħa u disgħin")]
+ [InlineData(100, "mija")]
+ [InlineData(101, "mija u wieħed")]
+ [InlineData(103, "mija u tlieta")]
+ [InlineData(110, "mija u għaxra")]
+ [InlineData(111, "mija u ħdax")]
+ [InlineData(121, "mija u wieħed u għoxrin")]
+ [InlineData(122, "mija u tnejn u għoxrin")]
+ [InlineData(123, "mija u tlieta u għoxrin")]
+ [InlineData(138, "mija u tmienja u tletin")]
+ [InlineData(143, "mija u tlieta u erbgħin")]
+ [InlineData(178, "mija u tmienja u sebgħin")]
+ [InlineData(199, "mija u disgħa u disgħin")]
+ [InlineData(200, "mitejn")]
+ [InlineData(201, "mitejn u wieħed")]
+ [InlineData(203, "mitejn u tlieta")]
+ [InlineData(210, "mitejn u għaxra")]
+ [InlineData(211, "mitejn u ħdax")]
+ [InlineData(221, "mitejn u wieħed u għoxrin")]
+ [InlineData(222, "mitejn u tnejn u għoxrin")]
+ [InlineData(223, "mitejn u tlieta u għoxrin")]
+ [InlineData(238, "mitejn u tmienja u tletin")]
+ [InlineData(243, "mitejn u tlieta u erbgħin")]
+ [InlineData(278, "mitejn u tmienja u sebgħin")]
+ [InlineData(299, "mitejn u disgħa u disgħin")]
+ [InlineData(300, "tlett mija")]
+ [InlineData(401, "erbgħa mija u wieħed")]
+ [InlineData(503, "ħames mija u tlieta")]
+ [InlineData(610, "sitt mija u għaxra")]
+ [InlineData(711, "sebgħa mija u ħdax")]
+ [InlineData(821, "tminn mija u wieħed u għoxrin")]
+ [InlineData(922, "disgħa mija u tnejn u għoxrin")]
+ [InlineData(323, "tlett mija u tlieta u għoxrin")]
+ [InlineData(438, "erbgħa mija u tmienja u tletin")]
+ [InlineData(543, "ħames mija u tlieta u erbgħin")]
+ [InlineData(678, "sitt mija u tmienja u sebgħin")]
+ [InlineData(799, "sebgħa mija u disgħa u disgħin")]
+ [InlineData(1000, "elf")]
+ [InlineData(1001, "elf u wieħed")]
+ [InlineData(1111, "elf u mija u ħdax")]
+ [InlineData(1234, "elf u mitejn u erbgħa u tletin")]
+ [InlineData(1999, "elf u disgħa mija u disgħa u disgħin")]
+ [InlineData(2000, "elfejn")]
+ [InlineData(2014, "elfejn u erbatax")]
+ [InlineData(2048, "elfejn u tmienja u erbgħin")]
+ [InlineData(3000, "tlett elef")]
+ [InlineData(3501, "tlett elef u ħames mija u wieħed")]
+ [InlineData(8100, "tmint elef u mija")]
+ [InlineData(10000, "għaxart elef")]
+ [InlineData(10001, "għaxart elef u wieħed")]
+ [InlineData(12345, "tnax il-elf u tlett mija u ħamsa u erbgħin")]
+ [InlineData(18000, "tmintax il-elf")]
+ [InlineData(100000, "mitt elf")]
+ [InlineData(100001, "mitt elf u wieħed")]
+ [InlineData(111111, "mija u ħdax il-elf u mija u ħdax")]
+ [InlineData(123456, "mija u tlieta u għoxrin elf u erbgħa mija u sitta u ħamsin")]
+ [InlineData(1000000, "miljun")]
+ [InlineData(1000001, "miljun u wieħed")]
+ [InlineData(1111101, "miljun u mija u ħdax il-elf u mija u wieħed")]
+ [InlineData(1111111, "miljun u mija u ħdax il-elf u mija u ħdax")]
+ [InlineData(1234567, "miljun u mitejn u erbgħa u tletin elf u ħames mija u sebgħa u sittin")]
+ [InlineData(5000000, "ħames miljuni")]
+ [InlineData(10000000, "għaxar miljuni")]
+ [InlineData(10000001, "għaxar miljuni u wieħed")]
+ [InlineData(11111111, "ħdax il-miljun u mija u ħdax il-elf u mija u ħdax")]
+ [InlineData(12345678, "tnax il-miljun u tlett mija u ħamsa u erbgħin elf u sitt mija u tmienja u sebgħin")]
+ [InlineData(100000000, "mitt miljun")]
+ [InlineData(100000001, "mitt miljun u wieħed")]
+ [InlineData(111111111, "mija u ħdax il-miljun u mija u ħdax il-elf u mija u ħdax")]
+ [InlineData(123456789, "mija u tlieta u għoxrin miljun u erbgħa mija u sitta u ħamsin elf u sebgħa mija u disgħa u tmenin")]
+ [InlineData(1000000000, "biljun")]
+ [InlineData(1000000001, "biljun u wieħed")]
+ [InlineData(1101111101, "biljun u mija u miljun u mija u ħdax il-elf u mija u wieħed")]
+ [InlineData(2000000000, "żewġ biljuni")]
+ [InlineData(2147483647, "żewġ biljuni u mija u sebgħa u erbgħin miljun u erbgħa mija u tlieta u tmenin elf u sitt mija u sebgħa u erbgħin")]
+ public void ToMasculineWords(int number, string expected)
+ {
+ Assert.Equal(expected, number.ToWords(GrammaticalGender.Masculine));
+ }
+
+ [Theory]
+ [InlineData(0, "0")]
+ [InlineData(1, "l-ewwel")]
+ [InlineData(2, "it-tieni")]
+ [InlineData(9, "id-disa'")]
+ [InlineData(10, "l-għaxar")]
+ [InlineData(11, "il-ħdax")]
+ [InlineData(15, "il-ħmistax")]
+ [InlineData(18, "it-tmintax")]
+ [InlineData(20, "l-għoxrin")]
+ [InlineData(21, "il-wieħed u għoxrin")]
+ [InlineData(22, "it-tnejn u għoxrin")]
+ [InlineData(28, "it-tmienja u għoxrin")]
+ [InlineData(44, "l-erbgħa u erbgħin")]
+ [InlineData(55, "il-ħamsa u ħamsin")]
+ [InlineData(60, "is-sittin")]
+ [InlineData(99, "id-disgħa u disgħin")]
+ [InlineData(100, "il-mija")]
+ [InlineData(101, "il-mija u wieħed")]
+ [InlineData(1000, "l-elf")]
+ [InlineData(1001, "l-elf u wieħed")]
+ [InlineData(2000, "l-elfejn")]
+ [InlineData(3000, "it-tlett elef")]
+ public void ToOrdinalWords(int number, string expected)
+ {
+ Assert.Equal(expected, number.ToOrdinalWords());
+ }
+
+ [Theory]
+ [InlineData(0, "0")]
+ [InlineData(1, "l-ewwel")]
+ [InlineData(2, "it-tieni")]
+ [InlineData(9, "id-disa'")]
+ [InlineData(10, "l-għaxar")]
+ [InlineData(11, "il-ħdax")]
+ [InlineData(15, "il-ħmistax")]
+ [InlineData(18, "it-tmintax")]
+ [InlineData(20, "l-għoxrin")]
+ [InlineData(21, "il-wieħed u għoxrin")]
+ [InlineData(22, "it-tnejn u għoxrin")]
+ [InlineData(28, "it-tmienja u għoxrin")]
+ [InlineData(44, "l-erbgħa u erbgħin")]
+ [InlineData(55, "il-ħamsa u ħamsin")]
+ [InlineData(60, "is-sittin")]
+ [InlineData(99, "id-disgħa u disgħin")]
+ [InlineData(100, "il-mija")]
+ [InlineData(101, "il-mija u waħda")]
+ [InlineData(1000, "l-elf")]
+ [InlineData(1001, "l-elf u waħda")]
+ [InlineData(2000, "l-elfejn")]
+ [InlineData(3000, "it-tlett elef")]
+ public void ToFeminineOrdinalWords(int number, string expected)
+ {
+ Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Feminine));
+ }
+
+ [Theory]
+ [InlineData(0, "0")]
+ [InlineData(1, "l-ewwel")]
+ [InlineData(2, "it-tieni")]
+ [InlineData(9, "id-disa'")]
+ [InlineData(10, "l-għaxar")]
+ [InlineData(11, "il-ħdax")]
+ [InlineData(15, "il-ħmistax")]
+ [InlineData(18, "it-tmintax")]
+ [InlineData(20, "l-għoxrin")]
+ [InlineData(21, "il-wieħed u għoxrin")]
+ [InlineData(22, "it-tnejn u għoxrin")]
+ [InlineData(28, "it-tmienja u għoxrin")]
+ [InlineData(44, "l-erbgħa u erbgħin")]
+ [InlineData(55, "il-ħamsa u ħamsin")]
+ [InlineData(60, "is-sittin")]
+ [InlineData(99, "id-disgħa u disgħin")]
+ [InlineData(100, "il-mija")]
+ [InlineData(101, "il-mija u wieħed")]
+ [InlineData(1000, "l-elf")]
+ [InlineData(1001, "l-elf u wieħed")]
+ [InlineData(2000, "l-elfejn")]
+ [InlineData(3000, "it-tlett elef")]
+ public void ToMasculineOrdinalWords(int number, string expected)
+ {
+ Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Masculine));
+ }
+ }
+}
diff --git a/src/Humanizer.Tests.Shared/Localisation/mt/TimeSpanHumanizeTests.cs b/src/Humanizer.Tests.Shared/Localisation/mt/TimeSpanHumanizeTests.cs
new file mode 100644
index 000000000..e83400f00
--- /dev/null
+++ b/src/Humanizer.Tests.Shared/Localisation/mt/TimeSpanHumanizeTests.cs
@@ -0,0 +1,100 @@
+using System;
+using Xunit;
+
+namespace Humanizer.Tests.Localisation.mt
+{
+
+ [UseCulture("mt")]
+ public class TimeSpanHumanizeTests
+ {
+
+ [Theory]
+ [Trait("Translation", "Google")]
+ [InlineData(366, "sena")]
+ [InlineData(731, "sentejn")]
+ [InlineData(1096, "3 snin")]
+ [InlineData(4018, "11 snin")]
+ public void Years(int days, string expected)
+ {
+ Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: Humanizer.Localisation.TimeUnit.Year));
+ }
+
+
+ [Theory]
+ [Trait("Translation", "Google")]
+ [InlineData(31, "xahar")]
+ [InlineData(61, "xahrejn")]
+ [InlineData(92, "3 xhur")]
+ [InlineData(335, "11 xhur")]
+ public void Months(int days, string expected)
+ {
+ Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: Humanizer.Localisation.TimeUnit.Year));
+ }
+
+ [Theory]
+ [InlineData(7, "ġimgħa")]
+ [InlineData(14, "ġimgħatejn")]
+ [InlineData(21, "3 ġimgħat")]
+ public void Weeks(int days, string expected)
+ {
+ Assert.Equal(expected, TimeSpan.FromDays(days).Humanize());
+ }
+
+ [Theory]
+ [InlineData(1, "ġurnata")]
+ [InlineData(2, "jumejn")]
+ [InlineData(3, "3 jiem")]
+ public void Days(int days, string expected)
+ {
+ Assert.Equal(expected, TimeSpan.FromDays(days).Humanize());
+ }
+
+ [Theory]
+ [InlineData(1, "siegħa")]
+ [InlineData(2, "sagħtejn")]
+ [InlineData(3, "3 siegħat")]
+ public void Hours(int hours, string expected)
+ {
+ Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize());
+ }
+
+ [Theory]
+ [InlineData(1, "minuta")]
+ [InlineData(2, "2 minuti")]
+ [InlineData(3, "3 minuti")]
+ public void Minutes(int minutes, string expected)
+ {
+ Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize());
+ }
+
+ [Theory]
+ [InlineData(1, "sekonda")]
+ [InlineData(2, "2 sekondi")]
+ [InlineData(3, "3 sekondi")]
+ public void Seconds(int seconds, string expected)
+ {
+ Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize());
+ }
+
+ [Theory]
+ [InlineData(1, "millisekonda")]
+ [InlineData(2, "2 millisekondi")]
+ [InlineData(3, "3 millisekondi")]
+ public void Milliseconds(int milliseconds, string expected)
+ {
+ Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize());
+ }
+
+ [Fact]
+ public void NoTime()
+ {
+ Assert.Equal("0 millisekondi", TimeSpan.Zero.Humanize());
+ }
+
+ [Fact]
+ public void NoTimeToWords()
+ {
+ Assert.Equal("xejn", TimeSpan.Zero.Humanize(toWords: true));
+ }
+ }
+}
diff --git a/src/Humanizer/Configuration/FormatterRegistry.cs b/src/Humanizer/Configuration/FormatterRegistry.cs
index 52fd88c99..719b82758 100644
--- a/src/Humanizer/Configuration/FormatterRegistry.cs
+++ b/src/Humanizer/Configuration/FormatterRegistry.cs
@@ -36,6 +36,7 @@ public FormatterRegistry() : base(new DefaultFormatter("en-US"))
RegisterDefaultFormatter("hu");
RegisterDefaultFormatter("id");
RegisterDefaultFormatter("ja");
+ Register("mt", new MalteseFormatter("mt"));
RegisterDefaultFormatter("nb");
RegisterDefaultFormatter("nb-NO");
RegisterDefaultFormatter("nl");
diff --git a/src/Humanizer/Configuration/NumberToWordsConverterRegistry.cs b/src/Humanizer/Configuration/NumberToWordsConverterRegistry.cs
index f5f1d76ad..f0af8bd3f 100644
--- a/src/Humanizer/Configuration/NumberToWordsConverterRegistry.cs
+++ b/src/Humanizer/Configuration/NumberToWordsConverterRegistry.cs
@@ -29,6 +29,7 @@ public NumberToWordsConverterRegistry()
Register("bn-BD", new BanglaNumberToWordsConverter());
Register("tr", new TurkishNumberToWordConverter());
Register("it", new ItalianNumberToWordsConverter());
+ Register("mt", new MalteseNumberToWordsConvertor());
Register("uk", new UkrainianNumberToWordsConverter());
Register("uz-Latn-UZ", new UzbekLatnNumberToWordConverter());
Register("uz-Cyrl-UZ", new UzbekCyrlNumberToWordConverter());
diff --git a/src/Humanizer/Localisation/Formatters/MalteseFormatter.cs b/src/Humanizer/Localisation/Formatters/MalteseFormatter.cs
new file mode 100644
index 000000000..331b08177
--- /dev/null
+++ b/src/Humanizer/Localisation/Formatters/MalteseFormatter.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Humanizer.Localisation.Formatters
+{
+ internal class MalteseFormatter : DefaultFormatter
+ {
+ private const string DualPostfix = "_Dual";
+
+ private static readonly string[] DualResourceKeys = new[]
+ {
+ "DateHumanize_MultipleDaysAgo", "DateHumanize_MultipleDaysFromNow", "DateHumanize_MultipleHoursAgo", "DateHumanize_MultipleHoursFromNow" ,
+ "DateHumanize_MultipleMonthsAgo", "DateHumanize_MultipleMonthsFromNow", "DateHumanize_MultipleYearsAgo", "DateHumanize_MultipleYearsFromNow",
+ "TimeSpanHumanize_MultipleDays", "TimeSpanHumanize_MultipleYears", "TimeSpanHumanize_MultipleMonths", "TimeSpanHumanize_MultipleHours",
+ "TimeSpanHumanize_MultipleWeeks"
+ };
+
+ public MalteseFormatter(string localeCode)
+ : base(localeCode)
+ {
+ }
+
+ protected override string GetResourceKey(string resourceKey, int number)
+ {
+ if (number == 2 && DualResourceKeys.Contains(resourceKey))
+ {
+ return resourceKey + DualPostfix;
+ }
+
+ return resourceKey;
+ }
+ }
+}
diff --git a/src/Humanizer/Localisation/NumberToWords/MalteseNumberToWordsConvertor.cs b/src/Humanizer/Localisation/NumberToWords/MalteseNumberToWordsConvertor.cs
new file mode 100644
index 000000000..d5ea09f69
--- /dev/null
+++ b/src/Humanizer/Localisation/NumberToWords/MalteseNumberToWordsConvertor.cs
@@ -0,0 +1,238 @@
+using System;
+using System.Collections.Generic;
+
+namespace Humanizer.Localisation.NumberToWords
+{
+ internal class MalteseNumberToWordsConvertor : GenderedNumberToWordsConverter
+ {
+ private static readonly string[] OrdinalOverrideMap =
+ {
+ "0", "l-ewwel", "it-tieni", "it-tielet", "ir-raba'", "il-ħames", "is-sitt", "is-seba'", "it-tmien", "id-disa'",
+ "l-għaxar", "il-ħdax", "it-tnax", "it-tlettax", "l-erbatax", "il-ħmistax", "is-sittax", "is-sbatax",
+ "it-tmintax", "id-dsatax", "l-għoxrin"
+ };
+
+ private static readonly string[] UnitsMap =
+ {
+ "żero", "wieħed", "tnejn", "tlieta", "erbgħa", "ħamsa", "sitta", "sebgħa", "tmienja", "disgħa", "għaxra",
+ "ħdax", "tnax", "tlettax", "erbatax", "ħmistax", "sittax", "sbatax", "tmintax", "dsatax"
+ };
+
+ private static readonly string[] TensMap =
+ {"zero", "għaxra", "għoxrin", "tletin", "erbgħin", "ħamsin", "sittin", "sebgħin", "tmenin", "disgħin"};
+
+ private static readonly string[] HundredsMap =
+ {
+ string.Empty, string.Empty, string.Empty, "tlett", "erbgħa", "ħames", "sitt", "sebgħa", "tminn", "disgħa",
+ "għaxar"
+ };
+
+ private static readonly string[] PrefixMap =
+ {
+ string.Empty, string.Empty, string.Empty, "tlett", "erbat", "ħamest", "sitt", "sebat", "tmint", "disat",
+ "għaxart", "ħdax il-", "tnax il-", "tletax il-", "erbatax il-", "ħmistax il-", "sittax il-", "sbatax il-",
+ "tmintax il-", "dsatax il-"
+ };
+
+ public override string Convert(long input, GrammaticalGender gender)
+ {
+ if (input < 1000000000)
+ {
+ return GetMillions(input, gender);
+ }
+
+ var billions = input / 1000000000;
+ var tensInBillions = billions % 100;
+ var millions = input % 1000000000;
+
+ var billionsText = GetPrefixText(billions, tensInBillions, "biljun", "żewġ biljuni", "biljuni", false, gender);
+ var millionsText = GetMillions(millions, gender);
+
+ if (millions == 0)
+ {
+ return billionsText;
+ }
+
+ return $"{billionsText} u {millionsText}";
+ }
+
+ public override string ConvertToOrdinal(int number, GrammaticalGender gender)
+ {
+ if (number <= 20)
+ {
+ return OrdinalOverrideMap[number];
+ }
+
+ var ordinal = Convert(number, gender);
+
+ if (ordinal.StartsWith("d"))
+ {
+ return $"id-{Convert(number, gender)}";
+ }
+ if (ordinal.StartsWith("s"))
+ {
+ return $"is-{Convert(number, gender)}";
+ }
+ if (ordinal.StartsWith("t"))
+ {
+ return $"it-{Convert(number, gender)}";
+ }
+ if (ordinal.StartsWith("e"))
+ {
+ return $"l-{Convert(number, gender)}";
+ }
+ return $"il-{Convert(number, gender)}";
+ }
+
+ private static string GetTens(long value, bool usePrefixMap, bool usePrefixMapForLowerDigits, GrammaticalGender gender)
+ {
+ if (value == 1 && gender == GrammaticalGender.Feminine)
+ {
+ return "waħda";
+ }
+
+ if (value < 11 && usePrefixMap && usePrefixMapForLowerDigits)
+ {
+ return PrefixMap[value];
+ }
+
+ if (value < 11 && usePrefixMap && !usePrefixMapForLowerDigits)
+ {
+ return HundredsMap[value];
+ }
+
+ if (value > 10 && value < 20 && usePrefixMap)
+ {
+ return PrefixMap[value];
+ }
+
+ if (value < 20)
+ {
+ return UnitsMap[value];
+ }
+
+ var single = value % 10;
+ var numberOfTens = value / 10;
+ if (single == 0)
+ {
+
+ return TensMap[numberOfTens];
+ }
+
+ return $"{UnitsMap[single]} u {TensMap[numberOfTens]}";
+ }
+
+ private static string GetHundreds(long value, bool usePrefixMap, bool usePrefixMapForLowerValueDigits, GrammaticalGender gender)
+ {
+ if (value < 100)
+ {
+ return GetTens(value, usePrefixMap, usePrefixMapForLowerValueDigits, gender);
+ }
+
+ var tens = value % 100;
+ var numberOfHundreds = value / 100;
+
+ var hundredsText = string.Empty;
+ if (numberOfHundreds == 1)
+ {
+ hundredsText = "mija";
+ }
+ else if (numberOfHundreds == 2)
+ {
+ hundredsText = "mitejn";
+ }
+ else
+ {
+ hundredsText = HundredsMap[numberOfHundreds] + " mija";
+ }
+
+ if (tens == 0)
+ {
+ return hundredsText;
+ }
+
+ return $"{hundredsText} u {GetTens(tens, usePrefixMap, usePrefixMapForLowerValueDigits, gender)}";
+ }
+
+ private static string GetThousands(long value, GrammaticalGender gender)
+ {
+ if (value < 1000)
+ {
+ return GetHundreds(value, false, false, gender);
+ }
+
+ var thousands = value / 1000;
+ var tensInThousands = thousands % 100;
+ var hundreds = value % 1000;
+
+ var thousandsInText = GetPrefixText(thousands, tensInThousands, "elf", "elfejn", "elef", true, gender);
+
+ var hundredsInText = GetHundreds(hundreds, false, false, gender);
+
+ if (hundreds == 0)
+ {
+ return thousandsInText;
+ }
+
+ return $"{thousandsInText} u {hundredsInText}";
+ }
+
+ private static string GetMillions(long value, GrammaticalGender gender)
+ {
+ if (value < 1000000)
+ {
+ return GetThousands(value, gender);
+ }
+
+ var millions = value / 1000000;
+ var tensInMillions = millions % 100;
+ var thousands = value % 1000000;
+
+ var millionsText = GetPrefixText(millions, tensInMillions, "miljun", "żewġ miljuni", "miljuni", false, gender);
+ var thousandsText = GetThousands(thousands, gender);
+
+ if (thousands == 0)
+ {
+ return millionsText;
+ }
+
+ return $"{millionsText} u {thousandsText}";
+ }
+
+ private static string GetPrefixText(long thousands, long tensInThousands, string singular, string dual, string plural, bool usePrefixMapForLowerValueDigits, GrammaticalGender gender)
+ {
+ if (thousands == 1)
+ {
+ return singular;
+ }
+
+ if (thousands == 2)
+ {
+ return dual;
+ }
+
+ if (tensInThousands > 10 && tensInThousands < 20)
+ {
+ return $"{GetHundreds(thousands, true, usePrefixMapForLowerValueDigits, gender)}{singular}";
+ }
+
+ if (tensInThousands > 20)
+ {
+ return $"{GetHundreds(thousands, true, usePrefixMapForLowerValueDigits, gender)} {singular}";
+ }
+
+ if (thousands == 100)
+ {
+ return $"mitt {singular}";
+ }
+
+ if (thousands == 101)
+ {
+ return $"mija u {singular}";
+ }
+
+ return $"{GetHundreds(thousands, true, usePrefixMapForLowerValueDigits, gender)} {plural}";
+
+ }
+ }
+}
diff --git a/src/Humanizer/Properties/AssemblyInfo.cs b/src/Humanizer/Properties/AssemblyInfo.cs
index 149d621c4..27bfb7922 100644
--- a/src/Humanizer/Properties/AssemblyInfo.cs
+++ b/src/Humanizer/Properties/AssemblyInfo.cs
@@ -1,3 +1,3 @@
using System.Resources;
-[assembly: NeutralResourcesLanguage("en")]
\ No newline at end of file
+[assembly: NeutralResourcesLanguage("en")]
diff --git a/src/Humanizer/Properties/Resources.mt.resx b/src/Humanizer/Properties/Resources.mt.resx
new file mode 100644
index 000000000..a71b83597
--- /dev/null
+++ b/src/Humanizer/Properties/Resources.mt.resx
@@ -0,0 +1,678 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ sekonda ilu
+
+
+ {0} sekondi ilu
+
+
+ minuta ilu
+
+
+ {0} minuti ilu
+
+
+ siegħa ilu
+
+
+ {0} siegħat ilu
+
+
+ il-bieraħ
+
+
+ {0} jiem ilu
+
+
+ xahar ilu
+
+
+ {0} xhur ilu
+
+
+ sena ilu
+
+
+ {0} snin ilu
+
+
+ {0} jiem
+
+
+ {0} siegħat
+
+
+ {0} millisekondi
+
+
+ {0} minuti
+
+
+ {0} sekondi
+
+
+ ġurnata
+
+
+ siegħa
+
+
+ millisekonda
+
+
+ minuta
+
+
+ sekonda
+
+
+ xejn
+
+
+ {0} ġimgħat
+
+
+ ġimgħa
+
+
+ {0} jiem oħra
+
+
+ {0} siegħat oħra
+
+
+ {0} minuti oħra
+
+
+ {0} xhur oħra
+
+
+ {0} sekondi oħra
+
+
+ {0} snin oħra
+
+
+ issa
+
+
+ għada
+
+
+ siegħa oħra
+
+
+ minuta oħra
+
+
+ xahar ieħor
+
+
+ sekonda oħra
+
+
+ sena oħra
+
+
+ sagħtejn oħra
+
+
+ {0} minuti oħra
+
+
+ {0} sekondi ilu
+
+
+ {0} sekondi oħra
+
+
+ sentejn oħra
+
+
+ jumejn
+
+
+ {0} jiem
+
+
+ {0} siegħat
+
+
+ {0} millisekondi
+
+
+ {0} minuti
+
+
+ {0} minuti
+
+
+ {0} sekondi
+
+
+ {0} millisekondi
+
+
+ {0} jiem ilu
+
+
+ jumejn ilu
+
+
+ {0} jiem ilu
+
+
+ il-bieraħ
+
+
+ {0} jiem ilu
+
+
+ pitgħada
+
+
+ {0} jiem oħra
+
+
+ għada
+
+
+ {0} jiem oħra
+
+
+ {0} siegħat ilu
+
+
+ sagħtejn ilu
+
+
+ {0} siegħat ilu
+
+
+ siegħa ilu
+
+
+ {0} siegħat ilu
+
+
+ {0} siegħat oħra
+
+
+ siegħa oħra
+
+
+ {0} siegħat oħra
+
+
+ {0} minuti ilu
+
+
+ {0} minuti ilu
+
+
+ {0} minuti ilu
+
+
+ minuta ilu
+
+
+ {0} minuti ilu
+
+
+ {0} minuti oħra
+
+
+ minuta oħra
+
+
+ {0} minuti oħra
+
+
+ xahrejn ilu
+
+
+ {0} xhur ilu
+
+
+ xahar ilu
+
+
+ {0} xhur ilu
+
+
+ xahrejn oħra
+
+
+ {0} xhur oħra
+
+
+ xahar ieħor
+
+
+ {0} xhur oħra
+
+
+ {0} sekondi ilu
+
+
+ {0} sekondi ilu
+
+
+ sekonda ilu
+
+
+ {0} sekondi ilu
+
+
+ {0} sekondi oħra
+
+
+ sekonda oħra
+
+
+ {0} sekondi oħra
+
+
+ {0} snin ilu
+
+
+ sentejn ilu
+
+
+ {0} snin ilu
+
+
+ sena ilu
+
+
+ {0} snin ilu
+
+
+ {0} snin oħra
+
+
+ sena oħra
+
+
+ {0} snin oħra
+
+
+ jum
+
+
+ {0} jiem
+
+
+ sagħtejn
+
+
+ siegħa
+
+
+ {0} siegħat
+
+
+ millisekonda
+
+
+ {0} millisekondi
+
+
+ {0} minuta
+
+
+ {0} minuti
+
+
+ {0} sekondi
+
+
+ sekonda
+
+
+ {0} sekondi
+
+
+ ġimgħatejn
+
+
+ {0} ġimgħat
+
+
+ ġimgħa
+
+
+ {0} ġimgħat
+
+
+ {0} xhur
+
+
+ {0} snin
+
+
+ xahar
+
+
+ sena
+
+
+ {0} siegħat ilu
+
+
+ {0} siegħat oħra
+
+
+ {0} minuti ilu
+
+
+ {0} minuti oħra
+
+
+ {0} xhur ilu
+
+
+ {0} xhur oħra
+
+
+ {0} sekondi ilu
+
+
+ {0} sekondi oħra
+
+
+ {0} snin ilu
+
+
+ {0} snin oħra
+
+
+ {0} siegħat
+
+
+ {0} millisekondi
+
+
+ {0} minuti
+
+
+ {0} sekondi
+
+
+ {0} ġimgħat
+
+
+ qatt
+
+
+ xahrejn
+
+
+ {0} xhur
+
+
+ {0} xhur
+
+
+ xahar
+
+
+ {0} xhur
+
+
+ sentejn
+
+
+ {0} snin
+
+
+ {0} snin
+
+
+ {0} snin
+
+
+ {0} snin
+
+
+ ġurnata
+
+
+ siegħa
+
+
+ millisekonda
+
+
+ minuta
+
+
+ xahar
+
+
+ sekonda
+
+
+ ġimgħa
+
+
+ sena
+
+
+ {0} jiem
+
+
+ XL
+
+
+ grieg it-tramuntana
+
+
+ grigal
+
+
+ grieg il-lvant
+
+
+ lvant
+
+
+ east-southeast
+
+
+ xlokk
+
+
+ nofsinhar ix-xlokk
+
+
+ nofsinhar
+
+
+ nofsinhar il-lbiċ
+
+
+ lbiċ
+
+
+ punent il-lbiċ
+
+
+ punent
+
+
+ punent majjistru
+
+
+ majjistral
+
+
+ majjistral it-tramuntana
+
+
+ T
+
+
+ GT
+
+
+ G
+
+
+ GL
+
+
+ L
+
+
+ xlokk il-lvant
+
+
+ X
+
+
+ NX
+
+
+ N
+
+
+ NL
+
+
+ L
+
+
+ PL
+
+
+ P
+
+
+ PM
+
+
+ M
+
+
+ MT
+
+
\ No newline at end of file