diff --git a/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.Approve_Public_Api.DotNet8_0.verified.txt b/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.Approve_Public_Api.DotNet8_0.verified.txt index 52553d968..df13478b9 100644 --- a/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.Approve_Public_Api.DotNet8_0.verified.txt +++ b/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.Approve_Public_Api.DotNet8_0.verified.txt @@ -216,14 +216,16 @@ namespace Humanizer public class DefaultFormatter : Humanizer.IFormatter { public DefaultFormatter(string localeCode) { } + protected System.Globalization.CultureInfo Culture { get; } public virtual string DataUnitHumanize(Humanizer.DataUnit dataUnit, double count, bool toSymbol = true) { } public virtual string DateHumanize(Humanizer.TimeUnit timeUnit, Humanizer.Tense timeUnitTense, int unit) { } public virtual string DateHumanize_Never() { } public virtual string DateHumanize_Now() { } protected virtual string Format(string resourceKey) { } - protected virtual string Format(string resourceKey, int number, bool toWords = false) { } + protected virtual string Format(Humanizer.TimeUnit unit, string resourceKey, int number, bool toWords = false) { } protected virtual string GetResourceKey(string resourceKey) { } protected virtual string GetResourceKey(string resourceKey, int number) { } + protected virtual string NumberToWords(Humanizer.TimeUnit unit, int number, System.Globalization.CultureInfo culture) { } public virtual string TimeSpanHumanize(Humanizer.TimeUnit timeUnit, int unit, bool toWords = false) { } public virtual string TimeSpanHumanize_Age() { } public virtual string TimeSpanHumanize_Zero() { } diff --git a/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.Approve_Public_Api.Net4_8.verified.txt b/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.Approve_Public_Api.Net4_8.verified.txt index 90a3d038d..06213bab0 100644 --- a/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.Approve_Public_Api.Net4_8.verified.txt +++ b/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.Approve_Public_Api.Net4_8.verified.txt @@ -201,14 +201,16 @@ namespace Humanizer public class DefaultFormatter : Humanizer.IFormatter { public DefaultFormatter(string localeCode) { } + protected System.Globalization.CultureInfo Culture { get; } public virtual string DataUnitHumanize(Humanizer.DataUnit dataUnit, double count, bool toSymbol = true) { } public virtual string DateHumanize(Humanizer.TimeUnit timeUnit, Humanizer.Tense timeUnitTense, int unit) { } public virtual string DateHumanize_Never() { } public virtual string DateHumanize_Now() { } protected virtual string Format(string resourceKey) { } - protected virtual string Format(string resourceKey, int number, bool toWords = false) { } + protected virtual string Format(Humanizer.TimeUnit unit, string resourceKey, int number, bool toWords = false) { } protected virtual string GetResourceKey(string resourceKey) { } protected virtual string GetResourceKey(string resourceKey, int number) { } + protected virtual string NumberToWords(Humanizer.TimeUnit unit, int number, System.Globalization.CultureInfo culture) { } public virtual string TimeSpanHumanize(Humanizer.TimeUnit timeUnit, int unit, bool toWords = false) { } public virtual string TimeSpanHumanize_Age() { } public virtual string TimeSpanHumanize_Zero() { } diff --git a/src/Humanizer.Tests/Localisation/ru-RU/TimeSpanHumanizeTests.cs b/src/Humanizer.Tests/Localisation/ru-RU/TimeSpanHumanizeTests.cs index 6e58c8405..9f7ab9860 100644 --- a/src/Humanizer.Tests/Localisation/ru-RU/TimeSpanHumanizeTests.cs +++ b/src/Humanizer.Tests/Localisation/ru-RU/TimeSpanHumanizeTests.cs @@ -76,6 +76,7 @@ public void Hours(int hours, string expected, bool toWords = false) => [InlineData(19, "19 минут")] [InlineData(20, "20 минут")] [InlineData(21, "21 минута")] + [InlineData(21, "двадцать одна минута", true)] [InlineData(22, "22 минуты")] [InlineData(23, "23 минуты")] [InlineData(24, "24 минуты")] @@ -97,6 +98,7 @@ public void Minutes(int minutes, string expected, bool toWords = false) => [InlineData(19, "19 секунд")] [InlineData(20, "20 секунд")] [InlineData(21, "21 секунда")] + [InlineData(21, "двадцать одна секунда", true)] [InlineData(22, "22 секунды")] [InlineData(23, "23 секунды")] [InlineData(24, "24 секунды")] @@ -118,7 +120,9 @@ public void Seconds(int seconds, string expected, bool toWords = false) => [InlineData(19, "19 миллисекунд")] [InlineData(20, "20 миллисекунд")] [InlineData(21, "21 миллисекунда")] + [InlineData(21, "двадцать одна миллисекунда", true)] [InlineData(22, "22 миллисекунды")] + [InlineData(22, "двадцать две миллисекунды", true)] [InlineData(23, "23 миллисекунды")] [InlineData(24, "24 миллисекунды")] [InlineData(25, "25 миллисекунд")] diff --git a/src/Humanizer.Tests/Localisation/uk-UA/TimeSpanHumanizeTests.cs b/src/Humanizer.Tests/Localisation/uk-UA/TimeSpanHumanizeTests.cs index 06f361b82..551a0ff72 100644 --- a/src/Humanizer.Tests/Localisation/uk-UA/TimeSpanHumanizeTests.cs +++ b/src/Humanizer.Tests/Localisation/uk-UA/TimeSpanHumanizeTests.cs @@ -5,44 +5,51 @@ public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] - [InlineData(366, "один рік")] + [InlineData(366, "один рік", true)] + [InlineData(366, "1 рік")] [InlineData(731, "2 роки")] [InlineData(1096, "3 роки")] [InlineData(4018, "11 років")] - public void Years(int days, string expected) => - Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); + public void Years(int days, string expected, bool toWords = false) => + Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year, toWords: toWords)); [Theory] [Trait("Translation", "Google")] - [InlineData(31, "один місяць")] + [InlineData(31, "один місяць", true)] + [InlineData(31, "1 місяць")] [InlineData(61, "2 місяці")] [InlineData(92, "3 місяці")] [InlineData(335, "11 місяців")] - public void Months(int days, string expected) => - Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); + public void Months(int days, string expected, bool toWords = false) => + Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year, toWords: toWords)); [Theory] - [InlineData(7, "один тиждень")] + [InlineData(7, "один тиждень", true)] + [InlineData(7, "1 тиждень")] [InlineData(14, "2 тижні")] [InlineData(21, "3 тижні")] [InlineData(28, "4 тижні")] [InlineData(35, "5 тижнів")] [InlineData(77, "11 тижнів")] - public void Weeks(int days, string expected) => - Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); + [InlineData(147, "двадцять один тиждень", true)] + public void Weeks(int days, string expected, bool toWords = false) => + Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(toWords: toWords)); [Theory] - [InlineData(1, "один день")] + [InlineData(1, "один день", true)] + [InlineData(1, "1 день")] [InlineData(2, "2 дні")] [InlineData(3, "3 дні")] [InlineData(4, "4 дні")] [InlineData(5, "5 днів")] [InlineData(6, "6 днів")] - public void Days(int days, string expected) => - Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); + [InlineData(21, "двадцять один день", true)] + public void Days(int days, string expected, bool toWords = false) => + Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(toWords: toWords, maxUnit: TimeUnit.Day)); [Theory] - [InlineData(1, "одна година")] + [InlineData(1, "одна година", true)] + [InlineData(1, "1 година")] [InlineData(2, "2 години")] [InlineData(3, "3 години")] [InlineData(4, "4 години")] @@ -53,13 +60,15 @@ public void Days(int days, string expected) => [InlineData(19, "19 годин")] [InlineData(20, "20 годин")] [InlineData(21, "21 година")] + [InlineData(21, "двадцять одна година", true)] [InlineData(22, "22 години")] [InlineData(23, "23 години")] - public void Hours(int hours, string expected) => - Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); + public void Hours(int hours, string expected, bool toWords = false) => + Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize(toWords: toWords)); [Theory] - [InlineData(1, "одна хвилина")] + [InlineData(1, "одна хвилина",true)] + [InlineData(1, "1 хвилина")] [InlineData(2, "2 хвилини")] [InlineData(3, "3 хвилини")] [InlineData(4, "4 хвилини")] @@ -70,16 +79,18 @@ public void Hours(int hours, string expected) => [InlineData(19, "19 хвилин")] [InlineData(20, "20 хвилин")] [InlineData(21, "21 хвилина")] + [InlineData(21, "двадцять одна хвилина", true)] [InlineData(22, "22 хвилини")] [InlineData(23, "23 хвилини")] [InlineData(24, "24 хвилини")] [InlineData(25, "25 хвилин")] [InlineData(40, "40 хвилин")] - public void Minutes(int minutes, string expected) => - Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); + public void Minutes(int minutes, string expected, bool toWords = false) => + Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize(toWords: toWords)); [Theory] - [InlineData(1, "одна секунда")] + [InlineData(1, "одна секунда", true)] + [InlineData(1, "1 секунда")] [InlineData(2, "2 секунди")] [InlineData(3, "3 секунди")] [InlineData(4, "4 секунди")] @@ -90,16 +101,18 @@ public void Minutes(int minutes, string expected) => [InlineData(19, "19 секунд")] [InlineData(20, "20 секунд")] [InlineData(21, "21 секунда")] + [InlineData(21, "двадцять одна секунда", true)] [InlineData(22, "22 секунди")] [InlineData(23, "23 секунди")] [InlineData(24, "24 секунди")] [InlineData(25, "25 секунд")] [InlineData(40, "40 секунд")] - public void Seconds(int seconds, string expected) => - Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); + public void Seconds(int seconds, string expected, bool toWords = false) => + Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize(toWords: toWords)); [Theory] - [InlineData(1, "одна мілісекунда")] + [InlineData(1, "одна мілісекунда", true)] + [InlineData(1, "1 мілісекунда")] [InlineData(2, "2 мілісекунди")] [InlineData(3, "3 мілісекунди")] [InlineData(4, "4 мілісекунди")] @@ -110,13 +123,14 @@ public void Seconds(int seconds, string expected) => [InlineData(19, "19 мілісекунд")] [InlineData(20, "20 мілісекунд")] [InlineData(21, "21 мілісекунда")] + [InlineData(21, "двадцять одна мілісекунда", true)] [InlineData(22, "22 мілісекунди")] [InlineData(23, "23 мілісекунди")] [InlineData(24, "24 мілісекунди")] [InlineData(25, "25 мілісекунд")] [InlineData(40, "40 мілісекунд")] - public void Milliseconds(int milliseconds, string expected) => - Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); + public void Milliseconds(int milliseconds, string expected, bool toWords = false) => + Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize(toWords: toWords)); [Fact] public void NoTime() => diff --git a/src/Humanizer.Tests/Localisation/vi/NumberToWordsTests.cs b/src/Humanizer.Tests/Localisation/vi/NumberToWordsTests.cs index 18699a039..bb4d4bef6 100644 --- a/src/Humanizer.Tests/Localisation/vi/NumberToWordsTests.cs +++ b/src/Humanizer.Tests/Localisation/vi/NumberToWordsTests.cs @@ -1,4 +1,4 @@ -namespace Humanizer.Tests.vi; +namespace Humanizer.Tests.Localisation.vi; [UseCulture("vi")] public class NumberToWordsTests diff --git a/src/Humanizer/Localisation/Formatters/DefaultFormatter.cs b/src/Humanizer/Localisation/Formatters/DefaultFormatter.cs index 2c1df2c01..344b3bd53 100644 --- a/src/Humanizer/Localisation/Formatters/DefaultFormatter.cs +++ b/src/Humanizer/Localisation/Formatters/DefaultFormatter.cs @@ -5,11 +5,11 @@ /// public class DefaultFormatter : IFormatter { - readonly CultureInfo _culture; + protected CultureInfo Culture { get; } /// Name of the culture to use. public DefaultFormatter(string localeCode) => - _culture = new(localeCode); + Culture = new(localeCode); public virtual string DateHumanize_Now() => GetResourceForDate(TimeUnit.Millisecond, Tense.Past, 0); @@ -41,41 +41,41 @@ public virtual string TimeSpanHumanize(TimeUnit timeUnit, int unit, bool toWords /// public virtual string TimeSpanHumanize_Age() { - if (Resources.TryGetResource("TimeSpanHumanize_Age", _culture, out var ageFormat)) - return ageFormat; - return "{0}"; - } + if (Resources.TryGetResource("TimeSpanHumanize_Age", Culture, out var ageFormat)) + return ageFormat; + return "{0}"; + } /// public virtual string DataUnitHumanize(DataUnit dataUnit, double count, bool toSymbol = true) { - var resourceKey = toSymbol ? $"DataUnit_{dataUnit}Symbol" : $"DataUnit_{dataUnit}"; - var resourceValue = Format(resourceKey); + var resourceKey = toSymbol ? $"DataUnit_{dataUnit}Symbol" : $"DataUnit_{dataUnit}"; + var resourceValue = Format(resourceKey); - if (!toSymbol && count > 1) - resourceValue += 's'; + if (!toSymbol && count > 1) + resourceValue += 's'; - return resourceValue; - } + return resourceValue; + } /// public virtual string TimeUnitHumanize(TimeUnit timeUnit) { - var resourceKey = ResourceKeys.TimeUnitSymbol.GetResourceKey(timeUnit); - return Format(resourceKey); - } + var resourceKey = ResourceKeys.TimeUnitSymbol.GetResourceKey(timeUnit); + return Format(resourceKey); + } string GetResourceForDate(TimeUnit unit, Tense timeUnitTense, int count) { - var resourceKey = ResourceKeys.DateHumanize.GetResourceKey(unit, timeUnitTense: timeUnitTense, count: count); - return count == 1 ? Format(resourceKey) : Format(resourceKey, count); - } + var resourceKey = ResourceKeys.DateHumanize.GetResourceKey(unit, timeUnitTense: timeUnitTense, count: count); + return count == 1 ? Format(resourceKey) : Format(unit, resourceKey, count); + } string GetResourceForTimeSpan(TimeUnit unit, int count, bool toWords = false) { - var resourceKey = ResourceKeys.TimeSpanHumanize.GetResourceKey(unit, count, toWords); - return count == 1 ? Format(resourceKey + (toWords ? "_Words" : "")) : Format(resourceKey, count, toWords); - } + var resourceKey = ResourceKeys.TimeSpanHumanize.GetResourceKey(unit, count, toWords); + return count == 1 ? Format(resourceKey + (toWords ? "_Words" : "")) : Format(unit, resourceKey, count, toWords); + } /// /// Formats the specified resource key. @@ -84,28 +84,28 @@ string GetResourceForTimeSpan(TimeUnit unit, int count, bool toWords = false) /// If the resource not exists on the specified culture. protected virtual string Format(string resourceKey) { - var resolvedKey = GetResourceKey(resourceKey); - return Resources.GetResource(resolvedKey, _culture); - } + var resolvedKey = GetResourceKey(resourceKey); + return Resources.GetResource(resolvedKey, Culture); + } /// /// Formats the specified resource key. /// + /// /// The resource key. /// The number. + /// /// If the resource not exists on the specified culture. - protected virtual string Format(string resourceKey, int number, bool toWords = false) + protected virtual string Format(TimeUnit unit, string resourceKey, int number, bool toWords = false) { - var resolvedKey = GetResourceKey(resourceKey, number); - var resourceString = Resources.GetResource(resolvedKey, _culture); + var resolvedKey = GetResourceKey(resourceKey, number); + var resourceString = Resources.GetResource(resolvedKey, Culture); - if (toWords) - { - return string.Format(resourceString, number.ToWords(_culture)); - } + return string.Format(resourceString, toWords ? NumberToWords(unit, number, Culture) : number.ToString(Culture)); + } - return string.Format(resourceString, number); - } + protected virtual string NumberToWords(TimeUnit unit, int number, CultureInfo culture) => + number.ToWords(culture); /// /// Override this method if your locale has complex rules around multiple units; e.g. Arabic, Russian diff --git a/src/Humanizer/Localisation/Formatters/IcelandicFormatter.cs b/src/Humanizer/Localisation/Formatters/IcelandicFormatter.cs index d6210f371..e10536554 100644 --- a/src/Humanizer/Localisation/Formatters/IcelandicFormatter.cs +++ b/src/Humanizer/Localisation/Formatters/IcelandicFormatter.cs @@ -1,40 +1,19 @@ namespace Humanizer; class IcelandicFormatter() : - DefaultFormatter(LocaleCode) + DefaultFormatter("is") { - const string LocaleCode = "is"; - readonly CultureInfo localCulture = new(LocaleCode); - public override string DataUnitHumanize(DataUnit dataUnit, double count, bool toSymbol = true) => base.DataUnitHumanize(dataUnit, count, toSymbol).TrimEnd('s'); - protected override string Format(string resourceKey, int number, bool toWords = false) - { - var resourceString = Resources.GetResource(GetResourceKey(resourceKey, number), localCulture); - - if (toWords) - { - var unitGender = GetGrammaticalGender(resourceString); - return string.Format(resourceString, number.ToWords(unitGender, localCulture)); - } - - return string.Format(resourceString, number); - } + protected override string NumberToWords(TimeUnit unit, int number, CultureInfo culture) => + number.ToWords(GetUnitGender(unit), culture); - static GrammaticalGender GetGrammaticalGender(string resource) - { - if (resource.Contains(" mán") || - resource.Contains(" dag")) + static GrammaticalGender GetUnitGender(TimeUnit unit) => + unit switch { - return GrammaticalGender.Masculine; - } - - if (resource.Contains(" ár")) - { - return GrammaticalGender.Neuter; - } - - return GrammaticalGender.Feminine; - } + TimeUnit.Day or TimeUnit.Month => GrammaticalGender.Masculine, + TimeUnit.Year => GrammaticalGender.Neuter, + _ => GrammaticalGender.Feminine + }; } \ No newline at end of file diff --git a/src/Humanizer/Localisation/Formatters/LuxembourgishFormatter.cs b/src/Humanizer/Localisation/Formatters/LuxembourgishFormatter.cs index f234f7a8e..cd1e4682a 100644 --- a/src/Humanizer/Localisation/Formatters/LuxembourgishFormatter.cs +++ b/src/Humanizer/Localisation/Formatters/LuxembourgishFormatter.cs @@ -1,11 +1,10 @@ namespace Humanizer; class LuxembourgishFormatter() : - DefaultFormatter(LocaleCode) + DefaultFormatter("lb") { - const string LocaleCode = "lb"; - readonly CultureInfo localCulture = new(LocaleCode); const string DualPostfix = "_Dual"; + // https://lb.wikipedia.org/wiki/Eifeler_Reegel const char EifelerRuleSuffix = 'n'; const string EifelerRuleCharacters = "unitedzohay"; @@ -25,30 +24,14 @@ public static bool DoesEifelerRuleApply(string nextWord) => !string.IsNullOrWhiteSpace(nextWord) && !EifelerRuleCharacters.Contains(nextWord[0]); - protected override string Format(string resourceKey, int number, bool toWords = false) + protected override string Format(TimeUnit unit, string resourceKey, int number, bool toWords = false) { - var resourceString = Resources.GetResource(GetResourceKey(resourceKey, number), localCulture); - - var unitGender = GetUnitGender(resourceString); - - var numberAsWord = number.ToWords(unitGender, localCulture); - - if (DoesEifelerRuleApply(numberAsWord)) - { - if (toWords) - { - return string.Format(resourceString, numberAsWord, string.Empty); - } - - return string.Format(resourceString, number, string.Empty); - } + var resourceString = Resources.GetResource(GetResourceKey(resourceKey, number), Culture); + var numberAsWord = number.ToWords(GetUnitGender(unit), Culture); - if (toWords) - { - return string.Format(resourceString, numberAsWord, EifelerRuleSuffix); - } - - return string.Format(resourceString, number, EifelerRuleSuffix); + return string.Format(resourceString, + toWords ? numberAsWord : number, + DoesEifelerRuleApply(numberAsWord) ? "" : EifelerRuleSuffix); } protected override string GetResourceKey(string resourceKey, int number) @@ -62,17 +45,10 @@ protected override string GetResourceKey(string resourceKey, int number) return resourceKey; } - static GrammaticalGender GetUnitGender(string resourceString) - { - if (resourceString.EndsWith(" Millisekonnen") || - resourceString.EndsWith(" Sekonnen") || - resourceString.EndsWith(" Minutten") || - resourceString.EndsWith(" Stonnen") || - resourceString.EndsWith(" Wochen")) + static GrammaticalGender GetUnitGender(TimeUnit unit) => + unit switch { - return GrammaticalGender.Feminine; - } - - return GrammaticalGender.Masculine; - } + TimeUnit.Day or TimeUnit.Month or TimeUnit.Year => GrammaticalGender.Masculine, + _ => GrammaticalGender.Feminine + }; } diff --git a/src/Humanizer/Localisation/Formatters/RomanianFormatter.cs b/src/Humanizer/Localisation/Formatters/RomanianFormatter.cs index efa29fe31..774593842 100644 --- a/src/Humanizer/Localisation/Formatters/RomanianFormatter.cs +++ b/src/Humanizer/Localisation/Formatters/RomanianFormatter.cs @@ -1,21 +1,18 @@ namespace Humanizer; class RomanianFormatter() : - DefaultFormatter(RomanianCultureCode) + DefaultFormatter("ro") { const int PrepositionIndicatingDecimals = 2; const int MaxNumeralWithNoPreposition = 19; const int MinNumeralWithNoPreposition = 1; const string UnitPreposition = " de"; - const string RomanianCultureCode = "ro"; static readonly double Divider = Math.Pow(10, PrepositionIndicatingDecimals); - readonly CultureInfo _romanianCulture = new(RomanianCultureCode); - - protected override string Format(string resourceKey, int number, bool toWords = false) + protected override string Format(TimeUnit unit, string resourceKey, int number, bool toWords = false) { - var format = Resources.GetResource(GetResourceKey(resourceKey, number), _romanianCulture); + var format = Resources.GetResource(GetResourceKey(resourceKey, number), Culture); var preposition = ShouldUsePreposition(number) ? UnitPreposition : string.Empty; diff --git a/src/Humanizer/Localisation/Formatters/RussianFormatter.cs b/src/Humanizer/Localisation/Formatters/RussianFormatter.cs index 8e0d75117..5b81b125b 100644 --- a/src/Humanizer/Localisation/Formatters/RussianFormatter.cs +++ b/src/Humanizer/Localisation/Formatters/RussianFormatter.cs @@ -5,23 +5,26 @@ class RussianFormatter() : { protected override string GetResourceKey(string resourceKey, int number) { - var grammaticalNumber = RussianGrammaticalNumberDetector.Detect(number); - var suffix = GetSuffix(grammaticalNumber); - return resourceKey + suffix; - } + var grammaticalNumber = RussianGrammaticalNumberDetector.Detect(number); + var suffix = GetSuffix(grammaticalNumber); + return resourceKey + suffix; + } - static string GetSuffix(RussianGrammaticalNumber grammaticalNumber) - { - if (grammaticalNumber == RussianGrammaticalNumber.Singular) - { - return "_Singular"; - } + protected override string NumberToWords(TimeUnit unit, int number, CultureInfo culture) => + number.ToWords(GetUnitGender(unit), culture); - if (grammaticalNumber == RussianGrammaticalNumber.Paucal) - { - return "_Paucal"; - } + static string GetSuffix(RussianGrammaticalNumber grammaticalNumber) => + grammaticalNumber switch + { + RussianGrammaticalNumber.Singular => "_Singular", + RussianGrammaticalNumber.Paucal => "_Paucal", + _ => "" + }; - return ""; - } + static GrammaticalGender GetUnitGender(TimeUnit unit) => + unit switch + { + TimeUnit.Hour or TimeUnit.Day or TimeUnit.Month or TimeUnit.Year => GrammaticalGender.Masculine, + _ => GrammaticalGender.Feminine + }; } \ No newline at end of file diff --git a/src/Humanizer/Localisation/Formatters/UkrainianFormatter.cs b/src/Humanizer/Localisation/Formatters/UkrainianFormatter.cs index ab7da5176..ad28a1058 100644 --- a/src/Humanizer/Localisation/Formatters/UkrainianFormatter.cs +++ b/src/Humanizer/Localisation/Formatters/UkrainianFormatter.cs @@ -4,23 +4,26 @@ class UkrainianFormatter() : DefaultFormatter("uk") { protected override string GetResourceKey(string resourceKey, int number) { - var grammaticalNumber = RussianGrammaticalNumberDetector.Detect(number); - var suffix = GetSuffix(grammaticalNumber); - return resourceKey + suffix; - } + var grammaticalNumber = RussianGrammaticalNumberDetector.Detect(number); + var suffix = GetSuffix(grammaticalNumber); + return resourceKey + suffix; + } - static string GetSuffix(RussianGrammaticalNumber grammaticalNumber) - { - if (grammaticalNumber == RussianGrammaticalNumber.Singular) - { - return "_Singular"; - } + protected override string NumberToWords(TimeUnit unit, int number, CultureInfo culture) => + number.ToWords(GetUnitGender(unit), culture); - if (grammaticalNumber == RussianGrammaticalNumber.Paucal) - { - return "_Paucal"; - } + static string GetSuffix(RussianGrammaticalNumber grammaticalNumber) => + grammaticalNumber switch + { + RussianGrammaticalNumber.Singular => "_Singular", + RussianGrammaticalNumber.Paucal => "_Paucal", + _ => "" + }; - return ""; - } + static GrammaticalGender GetUnitGender(TimeUnit unit) => + unit switch + { + TimeUnit.Day or TimeUnit.Week or TimeUnit.Month or TimeUnit.Year => GrammaticalGender.Masculine, + _ => GrammaticalGender.Feminine + }; } \ No newline at end of file diff --git a/src/Humanizer/Properties/Resources.uk.resx b/src/Humanizer/Properties/Resources.uk.resx index 1147b8176..b608ae002 100644 --- a/src/Humanizer/Properties/Resources.uk.resx +++ b/src/Humanizer/Properties/Resources.uk.resx @@ -247,22 +247,22 @@ {0} тиждень - один день + 1 день - одна година + 1 година - одна мілісекунда + 1 мілісекунда - одна хвилина + 1 хвилина - одна секунда + 1 секунда - один тиждень + 1 тиждень без часу @@ -358,9 +358,33 @@ {0} рік - один місяць + 1 місяць + 1 рік + + + один день + + + одна година + + + одна мілісекунда + + + одна хвилина + + + один місяць + + + одна секунда + + + один тиждень + + один рік \ No newline at end of file