From 908fdbced82ee98a0b07913a5cb7b8c74840afae Mon Sep 17 00:00:00 2001 From: Johan van Rhyn Date: Sun, 28 Jun 2015 18:45:45 +0200 Subject: [PATCH] Add Afrikaans localization --- src/Humanizer.Tests/Humanizer.Tests.csproj | 3 + .../Localisation/af/DateHumanizeTests.cs | 117 +++++++++++++++ .../Localisation/af/NumberToWordsTests.cs | 115 +++++++++++++++ .../Localisation/af/TimeSpanHumanizeTests.cs | 94 ++++++++++++ .../NumberToWordsConverterRegistry.cs | 1 + src/Humanizer/Humanizer.csproj | 3 +- .../AfrikaansNumberToWordsConverter.cs | 136 ++++++++++++++++++ src/Humanizer/Properties/Resources.af.resx | 96 +++++++++++-- 8 files changed, 555 insertions(+), 10 deletions(-) create mode 100644 src/Humanizer.Tests/Localisation/af/DateHumanizeTests.cs create mode 100644 src/Humanizer.Tests/Localisation/af/NumberToWordsTests.cs create mode 100644 src/Humanizer.Tests/Localisation/af/TimeSpanHumanizeTests.cs create mode 100644 src/Humanizer/Localisation/NumberToWords/AfrikaansNumberToWordsConverter.cs diff --git a/src/Humanizer.Tests/Humanizer.Tests.csproj b/src/Humanizer.Tests/Humanizer.Tests.csproj index f425164d4..afcad6e05 100644 --- a/src/Humanizer.Tests/Humanizer.Tests.csproj +++ b/src/Humanizer.Tests/Humanizer.Tests.csproj @@ -71,6 +71,9 @@ + + + diff --git a/src/Humanizer.Tests/Localisation/af/DateHumanizeTests.cs b/src/Humanizer.Tests/Localisation/af/DateHumanizeTests.cs new file mode 100644 index 000000000..5bad15fb2 --- /dev/null +++ b/src/Humanizer.Tests/Localisation/af/DateHumanizeTests.cs @@ -0,0 +1,117 @@ +using System; +using Humanizer.Localisation; +using Xunit; +using Xunit.Extensions; + +namespace Humanizer.Tests.Localisation.af +{ + public class DateHumanizeTests : AmbientCulture + { + public DateHumanizeTests() : base("af") { } + + [Theory] + [InlineData(2, "2 dae gelede")] + [InlineData(1, "gister")] + public void DaysAgo(int days, string expected) + { + DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); + } + + [Theory] + [InlineData(2, "2 ure gelede")] + [InlineData(1, "1 uur terug")] + public void HoursAgo(int hours, string expected) + { + DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); + } + + [Theory] + [InlineData(2, "2 minute terug")] + [InlineData(1, "1 minuut terug")] + [InlineData(60, "1 uur terug")] + public void MinutesAgo(int minutes, string expected) + { + DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); + } + + [Theory] + [InlineData(2, "2 maande gelede")] + [InlineData(1, "1 maand gelede")] + public void MonthsAgo(int months, string expected) + { + DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); + } + + [Theory] + [InlineData(2, "2 sekondes terug")] + [InlineData(1, "1 sekonde terug")] + public void SecondsAgo(int seconds, string expected) + { + DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); + } + + [Theory] + [InlineData(2, "2 jaar gelede")] + [InlineData(1, "1 jaar gelede")] + public void YearsAgo(int years, string expected) + { + DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); + } + + [Theory] + [InlineData(2, "oor 2 dae")] + [InlineData(1, "môre")] + public void DaysFromNow(int days, string expected) + { + DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); + } + + [Theory] + [InlineData(2, "oor 2 ure")] + [InlineData(1, "oor 1 uur")] + public void HoursFromNow(int hours, string expected) + { + DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); + } + + [Theory] + [InlineData(2, "oor 2 minute")] + [InlineData(1, "oor 1 minuut")] + [InlineData(60, "oor 1 uur")] + public void MinutesFromNow(int minutes, string expected) + { + DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); + } + + [Theory] + [InlineData(2, "oor 2 maande")] + [InlineData(1, "oor 1 maand")] + public void MonthsFromNow(int months, string expected) + { + DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); + } + + [Theory] + [InlineData(2, "oor 2 sekondes")] + [InlineData(1, "oor 1 sekonde")] + public void SecondsFromNow(int seconds, string expected) + { + DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); + } + + [Theory] + [InlineData(2, "oor 2 jaar")] + [InlineData(1, "oor 1 jaar")] + public void YearsFromNow(int years, string expected) + { + DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); + } + + [Theory] + [InlineData(0, "nou")] + public void RightNow(int seconds, string expected) + { + DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); + } + } +} diff --git a/src/Humanizer.Tests/Localisation/af/NumberToWordsTests.cs b/src/Humanizer.Tests/Localisation/af/NumberToWordsTests.cs new file mode 100644 index 000000000..51e915f17 --- /dev/null +++ b/src/Humanizer.Tests/Localisation/af/NumberToWordsTests.cs @@ -0,0 +1,115 @@ +using System.Globalization; +using Xunit; +using Xunit.Extensions; + +namespace Humanizer.Tests.Localisation.af +{ + public class AfrikaansNumberToWordsTests : AmbientCulture + { + public AfrikaansNumberToWordsTests() + : base("af") + { + } + + [InlineData(1, "een")] + [InlineData(10, "tien")] + [InlineData(11, "elf")] + [InlineData(20, "twintig")] + [InlineData(122, "een honderd twee en twintig")] + [InlineData(3501, "drie duisend vyf honderd en een")] + [InlineData(100, "een honderd")] + [InlineData(1000, "een duisend")] + [InlineData(100000, "een honderd duisend")] + [InlineData(1000000, "een miljoen")] + [InlineData(10000000, "tien miljoen")] + [InlineData(100000000, "een honderd miljoen")] + [InlineData(1000000000, "een miljard")] + [InlineData(111, "een honderd en elf")] + [InlineData(1111, "een duisend een honderd en elf")] + [InlineData(111111, "een honderd en elf duisend een honderd en elf")] + [InlineData(1111111, "een miljoen een honderd en elf duisend een honderd en elf")] + [InlineData(11111111, "elf miljoen een honderd en elf duisend een honderd en elf")] + [InlineData(111111111, "een honderd en elf miljoen een honderd en elf duisend een honderd en elf")] + [InlineData(1111111111, "een miljard een honderd en elf miljoen een honderd en elf duisend een honderd en elf")] + [InlineData(123, "een honderd drie en twintig")] + [InlineData(1234, "een duisend twee honderd vier en dertig")] + [InlineData(12345, "twaalf duisend drie honderd vyf en veertig")] + [InlineData(123456, "een honderd drie en twintig duisend vier honderd ses en vyftig")] + [InlineData(1234567, "een miljoen twee honderd vier en dertig duisend vyf honderd sewe en sestig")] + [InlineData(12345678, "twaalf miljoen drie honderd vyf en veertig duisend ses honderd agt en sewentig")] + [InlineData(123456789, "een honderd drie en twintig miljoen vier honderd ses en vyftig duisend sewe honderd nege en tagtig")] + [InlineData(1234567890, "een miljard twee honderd vier en dertig miljoen vyf honderd sewe en sestig duisend agt honderd en negentig")] + [Theory] + public void ToWords(int number, string expected) + { + Assert.Equal(expected, number.ToWords()); + } + + [Theory] + [InlineData(0, "nulste")] + [InlineData(1, "eerste")] + [InlineData(2, "tweede")] + [InlineData(3, "derde")] + [InlineData(4, "vierde")] + [InlineData(5, "vyfde")] + [InlineData(6, "sesde")] + [InlineData(7, "sewende")] + [InlineData(8, "agste")] + [InlineData(9, "negende")] + [InlineData(10, "tiende")] + [InlineData(11, "elfde")] + [InlineData(12, "twaalfde")] + [InlineData(13, "dertiende")] + [InlineData(14, "veertiende")] + [InlineData(15, "vyftiende")] + [InlineData(16, "sestiende")] + [InlineData(17, "sewentiende")] + [InlineData(18, "agtiende")] + [InlineData(19, "negentiende")] + [InlineData(20, "twintigste")] + [InlineData(21, "een en twintigste")] + [InlineData(22, "twee en twintigste")] + [InlineData(30, "dertigste")] + [InlineData(40, "veertigste")] + [InlineData(50, "vyftigste")] + [InlineData(60, "sestigste")] + [InlineData(70, "sewentigste")] + [InlineData(80, "tagtigste")] + [InlineData(90, "negentigste")] + [InlineData(95, "vyf en negentigste")] + [InlineData(96, "ses en negentigste")] + [InlineData(100, "honderdste")] + [InlineData(112, "honderd en twaalfde")] + [InlineData(120, "honderd en twintigste")] + [InlineData(121, "honderd een en twintigste")] + [InlineData(1000, "duisendste")] + [InlineData(1001, "duisend en eerste")] + [InlineData(1021, "duisend een en twintigste")] + [InlineData(10000, "tien duisendste")] + [InlineData(10121, "tien duisend een honderd een en twintigste")] + [InlineData(100000, "honderd duisendste")] + [InlineData(1000000, "miljoenste")] + public void ToOrdinalWords(int number, string words) + { + Assert.Equal(words, number.ToOrdinalWords()); + } + + [Theory] + [InlineData(11, "en-US", "eleven")] + [InlineData(22, "ar", "اثنان و عشرون")] + [InlineData(40, "ru", "сорок")] + public void ToWords_CanSpecifyCultureExplicitly(int number, string culture, string expected) + { + Assert.Equal(expected, number.ToWords(new CultureInfo(culture))); + } + + [Theory] + [InlineData(1021, "en-US", "thousand and twenty-first")] + [InlineData(21, "ar", "الحادي و العشرون")] + [InlineData(1112, "ru", "одна тысяча сто двенадцатый")] + public void ToOrdinalWords_CanSpecifyCultureExplicitly(int number, string culture, string expected) + { + Assert.Equal(expected, number.ToOrdinalWords(new CultureInfo(culture))); + } + } +} \ No newline at end of file diff --git a/src/Humanizer.Tests/Localisation/af/TimeSpanHumanizeTests.cs b/src/Humanizer.Tests/Localisation/af/TimeSpanHumanizeTests.cs new file mode 100644 index 000000000..5a6f1dca9 --- /dev/null +++ b/src/Humanizer.Tests/Localisation/af/TimeSpanHumanizeTests.cs @@ -0,0 +1,94 @@ +using System; +using Xunit; + +namespace Humanizer.Tests.Localisation.af +{ + public class TimeSpanHumanizeTests : AmbientCulture + { + public TimeSpanHumanizeTests() : base("af") { } + + [Fact] + public void TwoWeeks() + { + Assert.Equal("2 weke", TimeSpan.FromDays(14).Humanize()); + } + + [Fact] + public void OneWeek() + { + Assert.Equal("1 week", TimeSpan.FromDays(7).Humanize()); + } + + [Fact] + public void SixDays() + { + Assert.Equal("6 dae", TimeSpan.FromDays(6).Humanize()); + } + + [Fact] + public void TwoDays() + { + Assert.Equal("2 dae", TimeSpan.FromDays(2).Humanize()); + } + + [Fact] + public void OneDay() + { + Assert.Equal("1 dag", TimeSpan.FromDays(1).Humanize()); + } + + [Fact] + public void TwoHours() + { + Assert.Equal("2 ure", TimeSpan.FromHours(2).Humanize()); + } + + [Fact] + public void OneHour() + { + Assert.Equal("1 uur", TimeSpan.FromHours(1).Humanize()); + } + + [Fact] + public void TwoMinutes() + { + Assert.Equal("2 minute", TimeSpan.FromMinutes(2).Humanize()); + } + + [Fact] + public void OneMinute() + { + Assert.Equal("1 minuut", TimeSpan.FromMinutes(1).Humanize()); + } + + [Fact] + public void TwoSeconds() + { + Assert.Equal("2 sekondes", TimeSpan.FromSeconds(2).Humanize()); + } + + [Fact] + public void OneSecond() + { + Assert.Equal("1 sekond", TimeSpan.FromSeconds(1).Humanize()); + } + + [Fact] + public void TwoMilliseconds() + { + Assert.Equal("2 millisekondes", TimeSpan.FromMilliseconds(2).Humanize()); + } + + [Fact] + public void OneMillisecond() + { + Assert.Equal("1 millisekond", TimeSpan.FromMilliseconds(1).Humanize()); + } + + [Fact] + public void NoTime() + { + Assert.Equal("geen tyd", TimeSpan.Zero.Humanize()); + } + } +} \ No newline at end of file diff --git a/src/Humanizer/Configuration/NumberToWordsConverterRegistry.cs b/src/Humanizer/Configuration/NumberToWordsConverterRegistry.cs index 0245e9b82..cc09a39dc 100644 --- a/src/Humanizer/Configuration/NumberToWordsConverterRegistry.cs +++ b/src/Humanizer/Configuration/NumberToWordsConverterRegistry.cs @@ -7,6 +7,7 @@ internal class NumberToWordsConverterRegistry : LocaliserRegistry new DefaultNumberToWordsConverter(culture)) { + Register("af", new AfrikaansNumberToWordsConverter()); Register("en", new EnglishNumberToWordsConverter()); Register("ar", new ArabicNumberToWordsConverter()); Register("fa", new FarsiNumberToWordsConverter()); diff --git a/src/Humanizer/Humanizer.csproj b/src/Humanizer/Humanizer.csproj index 1d91d3479..69b101dfd 100644 --- a/src/Humanizer/Humanizer.csproj +++ b/src/Humanizer/Humanizer.csproj @@ -75,6 +75,7 @@ + @@ -243,7 +244,7 @@ - + diff --git a/src/Humanizer/Localisation/NumberToWords/AfrikaansNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/AfrikaansNumberToWordsConverter.cs new file mode 100644 index 000000000..af924efca --- /dev/null +++ b/src/Humanizer/Localisation/NumberToWords/AfrikaansNumberToWordsConverter.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; + +namespace Humanizer.Localisation.NumberToWords +{ + internal class AfrikaansNumberToWordsConverter : GenderlessNumberToWordsConverter + { + private static readonly string[] UnitsMap = { "nul", "een", "twee", "drie", "vier", "vyf", "ses", "sewe", "agt", "nege", "tien", "elf", "twaalf", "dertien", "veertien", "vyftien", "sestien", "sewentien", "agtien", "negentien" }; + private static readonly string[] TensMap = { "nul", "tien", "twintig", "dertig", "veertig", "vyftig", "sestig", "sewentig", "tagtig", "negentig" }; + + private static readonly Dictionary OrdinalExceptions = new Dictionary + { + {0, "nulste"}, + {1, "eerste"}, + {3, "derde"}, + {7, "sewende"}, + {8, "agste"}, + {9, "negende"}, + {10, "tiende"}, + {14, "veertiende"}, + {17, "sewentiende"}, + {19, "negentiende"} + }; + + public override string Convert(int number) + { + return Convert(number, false); + } + + public override string ConvertToOrdinal(int number) + { + return Convert(number, true); + } + + private string Convert(int number, bool isOrdinal) + { + if (number == 0) + return GetUnitValue(0, isOrdinal); + + if (number < 0) + return string.Format("minus {0}", Convert(-number)); + + var parts = new List(); + + if ((number / 1000000000) > 0) + { + parts.Add(string.Format("{0} miljard", Convert(number / 1000000000))); + number %= 1000000000; + } + + if ((number / 1000000) > 0) + { + parts.Add(string.Format("{0} miljoen", Convert(number / 1000000))); + number %= 1000000; + } + + if ((number / 1000) > 0) + { + parts.Add(string.Format("{0} duisend", Convert(number / 1000))); + number %= 1000; + } + + if ((number / 100) > 0) + { + parts.Add(string.Format("{0} honderd", Convert(number / 100))); + number %= 100; + } + + if (number > 0) + { + //if (parts.Count != 0) + // parts.Add("en"); + + if (number < 20) + { + if (parts.Count > 0) + parts.Add("en"); + parts.Add(GetUnitValue(number, isOrdinal)); + } + else + { + var lastPartValue = (number/10)*10; + var lastPart = TensMap[number/10]; + if ((number%10) > 0) + lastPart = string.Format("{0} en {1}",GetUnitValue(number % 10, false), isOrdinal ? GetUnitValue(lastPartValue, isOrdinal) : lastPart); + else if ((number%10) == 0) + lastPart = string.Format("{0}{1}{2}", parts.Count > 0 ? "en " : "", lastPart, isOrdinal ? "ste" : ""); + else if (isOrdinal) + lastPart = lastPart.TrimEnd('~') + "ste"; + + parts.Add(lastPart); + } + } + else if (isOrdinal) + parts[parts.Count - 1] += "ste"; + + string toWords = string.Join(" ", parts.ToArray()); + + if (isOrdinal) + toWords = RemoveOnePrefix(toWords); + + return toWords; + } + + private static string GetUnitValue(int number, bool isOrdinal) + { + if (isOrdinal) + { + string exceptionString; + if (ExceptionNumbersToWords(number, out exceptionString)) + return exceptionString; + else if (number > 19) + return TensMap[number/10] + "ste"; + else + return UnitsMap[number] + "de"; + } + else + return UnitsMap[number]; + } + + private static string RemoveOnePrefix(string toWords) + { + // one hundred => hundredth + if (toWords.IndexOf("een", StringComparison.Ordinal) == 0) + if (toWords.IndexOf("een en", StringComparison.Ordinal) != 0) + toWords = toWords.Remove(0, 4); + + return toWords; + } + + private static bool ExceptionNumbersToWords(int number, out string words) + { + return OrdinalExceptions.TryGetValue(number, out words); + } + } +} \ No newline at end of file diff --git a/src/Humanizer/Properties/Resources.af.resx b/src/Humanizer/Properties/Resources.af.resx index 9197486c6..955479a5a 100644 --- a/src/Humanizer/Properties/Resources.af.resx +++ b/src/Humanizer/Properties/Resources.af.resx @@ -118,39 +118,117 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - 'n sekonde gelede + 1 sekonde terug {0} sekondes terug - 'n minuut gelede + 1 minuut terug {0} minute terug - 'n uur gelede + 1 uur terug - {0} ure terug + {0} ure gelede gister - {0} dae terug + {0} dae gelede - 'n maand gelede + 1 maand gelede - {0} maande terug + {0} maande gelede - 'n jaar gelede + 1 jaar gelede - {0} jare terug + {0} jaar gelede + + + {0} dae + + + {0} ure + + + {0} millisekondes + + + {0} minute + + + {0} sekondes + + + {0} weke + + + 1 dag + + + 1 uur + + + 1 millisekond + + + 1 minuut + + + 1 sekond + + + 1 week + + + geen tyd + + + oor {0} dae + + + oor {0} ure + + + oor {0} minute + + + oor {0} maande + + + oor {0} sekondes + + + oor {0} jaar + + + nou + + + môre + + + oor 1 uur + + + oor 1 minuut + + + oor 1 maand + + + oor 1 sekonde + + + oor 1 jaar \ No newline at end of file