diff --git a/readme.md b/readme.md
index d3846b2b7..fe15f78f5 100644
--- a/readme.md
+++ b/readme.md
@@ -560,6 +560,13 @@ The possible values are `GrammaticalGender.Masculine`, `GrammaticalGender.Femini
Obviously this only applies to some cultures. For others passing gender in doesn't make any difference in the result.
+Also, culture to use can be specified explicitly. If it is not, current thread's current UI culture is used. Here's an example:
+
+```C#
+11.ToWords(new CultureInfo("en")) => "eleven"
+1.ToWords(GrammaticalGender.Masculine, new CultureInfo("ru")) => "один"
+```
+
###Number to ordinal words
This is kind of mixing `ToWords` with `Ordinalize`. You can call `ToOrdinalWords` on a number to get an ordinal representation of the number in words! For example:
@@ -592,6 +599,13 @@ The possible values are `GrammaticalGender.Masculine`, `GrammaticalGender.Femini
Obviously this only applies to some cultures. For others passing gender in doesn't make any difference in the result.
+Also, culture to use can be specified explicitly. If it is not, current thread's current UI culture is used. Here's an example:
+
+```C#
+10.ToOrdinalWords(new CultureInfo("en-US")) => "tenth"
+1.ToOrdinalWords(GrammaticalGender.Masculine, new CulureInfo("pt-BR")) => "primeiro"
+```
+
###Roman numerals
Humanizer can change numbers to Roman numerals using the `ToRoman` extension. The numbers 1 to 10 can be expressed in Roman numerals as follows:
diff --git a/release_notes.md b/release_notes.md
index 9a7730feb..711190fb8 100644
--- a/release_notes.md
+++ b/release_notes.md
@@ -5,6 +5,7 @@
- [#278](https://github.com/MehdiK/Humanizer/pull/278): Changed DefaultDateTimeHumanizeStrategy to turn 60 min to one hour not 45
- [#283](https://github.com/MehdiK/Humanizer/pull/283): Added Neutral nb support for DateTime and TimeSpan Humanize
- [#286](https://github.com/MehdiK/Humanizer/pull/286): Added optional Culture parameter to DateTime.Humanize & TimeSpan.Humanize
+ - [#295](https://github.com/MehdiK/Humanizer/pull/295): Added optional Culture parameter to NumberToWords
[Commits](https://github.com/MehdiK/Humanizer/compare/v1.26.1...master)
diff --git a/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt b/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt
index 3a2bd3dd3..eba13a1c6 100644
--- a/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt
+++ b/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt
@@ -84,7 +84,9 @@ public class Configurator
public class LocaliserRegistry`1
{
public LocaliserRegistry`1(TLocaliser defaultLocaliser) { }
+ public LocaliserRegistry`1(System.Func<, > defaultLocaliser) { }
public void Register(string localeCode, TLocaliser localiser) { }
+ public void Register(string localeCode, System.Func<, > localiser) { }
public TLocaliser ResolveForCulture(System.Globalization.CultureInfo culture) { }
public TLocaliser ResolveForUiCulture() { }
}
@@ -291,10 +293,10 @@ public class NumberToTimeSpanExtensions
public class NumberToWordsExtension
{
- public string ToOrdinalWords(int number) { }
- public string ToOrdinalWords(int number, Humanizer.GrammaticalGender gender) { }
- public string ToWords(int number) { }
- public string ToWords(int number, Humanizer.GrammaticalGender gender) { }
+ public string ToOrdinalWords(int number, System.Globalization.CultureInfo culture) { }
+ public string ToOrdinalWords(int number, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo culture) { }
+ public string ToWords(int number, System.Globalization.CultureInfo culture) { }
+ public string ToWords(int number, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo culture) { }
}
public class On
diff --git a/src/Humanizer.Tests/NumberToWordsTests.cs b/src/Humanizer.Tests/NumberToWordsTests.cs
index d77dddf3c..fc8787c87 100644
--- a/src/Humanizer.Tests/NumberToWordsTests.cs
+++ b/src/Humanizer.Tests/NumberToWordsTests.cs
@@ -1,4 +1,5 @@
-using Xunit;
+using System.Globalization;
+using Xunit;
using Xunit.Extensions;
namespace Humanizer.Tests
@@ -92,5 +93,23 @@ 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/Configuration/Configurator.cs b/src/Humanizer/Configuration/Configurator.cs
index afadff4f5..c3605537b 100644
--- a/src/Humanizer/Configuration/Configurator.cs
+++ b/src/Humanizer/Configuration/Configurator.cs
@@ -72,12 +72,10 @@ internal static IFormatter GetFormatter(CultureInfo culture)
///
/// The converter to be used
///
- internal static INumberToWordsConverter NumberToWordsConverter
+ /// The culture to retrieve number to words converter for. Null means that current thread's UI culture should be used.
+ internal static INumberToWordsConverter GetNumberToWordsConverter(CultureInfo culture)
{
- get
- {
- return NumberToWordsConverters.ResolveForUiCulture();
- }
+ return NumberToWordsConverters.ResolveForCulture(culture);
}
///
diff --git a/src/Humanizer/Configuration/LocaliserRegistry.cs b/src/Humanizer/Configuration/LocaliserRegistry.cs
index 4492dbfa4..a7e4880f3 100644
--- a/src/Humanizer/Configuration/LocaliserRegistry.cs
+++ b/src/Humanizer/Configuration/LocaliserRegistry.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Globalization;
namespace Humanizer.Configuration
@@ -7,16 +8,26 @@ namespace Humanizer.Configuration
/// A registry of localised system components with their associated locales
///
///
- public class LocaliserRegistry
+ public class LocaliserRegistry
+ where TLocaliser : class
{
- private readonly IDictionary _localisers = new Dictionary();
- private readonly TLocaliser _defaultLocaliser;
+ private readonly IDictionary> _localisers = new Dictionary>();
+ private readonly Func _defaultLocaliser;
///
/// Creates a localiser registry with the default localiser set to the provided value
///
///
public LocaliserRegistry(TLocaliser defaultLocaliser)
+ {
+ _defaultLocaliser = (culture) => defaultLocaliser;
+ }
+
+ ///
+ /// Creates a localiser registry with the default localiser factory set to the provided value
+ ///
+ ///
+ public LocaliserRegistry(Func defaultLocaliser)
{
_defaultLocaliser = defaultLocaliser;
}
@@ -35,9 +46,28 @@ public TLocaliser ResolveForUiCulture()
/// The culture to retrieve localiser for. If not specified, current thread's UI culture is used.
public TLocaliser ResolveForCulture(CultureInfo culture)
{
- culture = culture ?? CultureInfo.CurrentUICulture;
+ return FindLocaliser(culture ?? CultureInfo.CurrentUICulture)(culture);
+ }
- TLocaliser localiser;
+ ///
+ /// Registers the localiser for the culture provided
+ ///
+ public void Register(string localeCode, TLocaliser localiser)
+ {
+ _localisers[localeCode] = (culture) => localiser;
+ }
+
+ ///
+ /// Registers the localiser factory for the culture provided
+ ///
+ public void Register(string localeCode, Func localiser)
+ {
+ _localisers[localeCode] = localiser;
+ }
+
+ private Func FindLocaliser(CultureInfo culture)
+ {
+ Func localiser;
if (_localisers.TryGetValue(culture.Name, out localiser))
return localiser;
@@ -47,13 +77,5 @@ public TLocaliser ResolveForCulture(CultureInfo culture)
return _defaultLocaliser;
}
-
- ///
- /// Registers the localiser for the culture provided
- ///
- public void Register(string localeCode, TLocaliser localiser)
- {
- _localisers[localeCode] = localiser;
- }
}
}
diff --git a/src/Humanizer/Configuration/NumberToWordsConverterRegistry.cs b/src/Humanizer/Configuration/NumberToWordsConverterRegistry.cs
index 45c829a14..b22be4615 100644
--- a/src/Humanizer/Configuration/NumberToWordsConverterRegistry.cs
+++ b/src/Humanizer/Configuration/NumberToWordsConverterRegistry.cs
@@ -4,19 +4,19 @@ namespace Humanizer.Configuration
{
internal class NumberToWordsConverterRegistry : LocaliserRegistry
{
- public NumberToWordsConverterRegistry() : base(new DefaultNumberToWordsConverter())
+ public NumberToWordsConverterRegistry() : base((culture) => new DefaultNumberToWordsConverter(culture))
{
Register("en", new EnglishNumberToWordsConverter());
Register("ar", new ArabicNumberToWordsConverter());
Register("fa", new FarsiNumberToWordsConverter());
Register("es", new SpanishNumberToWordsConverter());
- Register("pl", new PolishNumberToWordsConverter());
+ Register("pl", (culture) => new PolishNumberToWordsConverter(culture));
Register("pt-BR", new BrazilianPortugueseNumberToWordsConverter());
Register("ru", new RussianNumberToWordsConverter());
Register("fr", new FrenchNumberToWordsConverter());
Register("nl", new DutchNumberToWordsConverter());
- Register("he", new HebrewNumberToWordsConverter());
- Register("sl", new SlovenianNumberToWordsConverter());
+ Register("he", (culture) => new HebrewNumberToWordsConverter(culture));
+ Register("sl", (culture) => new SlovenianNumberToWordsConverter(culture));
Register("de", new GermanNumberToWordsConverter());
}
}
diff --git a/src/Humanizer/Humanizer.csproj b/src/Humanizer/Humanizer.csproj
index de6eaa08e..f23d6d0d5 100644
--- a/src/Humanizer/Humanizer.csproj
+++ b/src/Humanizer/Humanizer.csproj
@@ -65,6 +65,8 @@
+
+
diff --git a/src/Humanizer/Localisation/NumberToWords/ArabicNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/ArabicNumberToWordsConverter.cs
index e47f7c199..6cb2cd9c4 100644
--- a/src/Humanizer/Localisation/NumberToWords/ArabicNumberToWordsConverter.cs
+++ b/src/Humanizer/Localisation/NumberToWords/ArabicNumberToWordsConverter.cs
@@ -4,7 +4,7 @@
namespace Humanizer.Localisation.NumberToWords
{
- internal class ArabicNumberToWordsConverter : DefaultNumberToWordsConverter
+ internal class ArabicNumberToWordsConverter : GenderlessNumberToWordsConverter
{
private static readonly string[] Groups = { "مئة", "ألف", "مليون", "مليار", "تريليون", "كوادريليون", "كوينتليون", "سكستيليون" };
private static readonly string[] AppendedGroups = { "", "ألفاً", "مليوناً", "ملياراً", "تريليوناً", "كوادريليوناً", "كوينتليوناً", "سكستيليوناً" };
diff --git a/src/Humanizer/Localisation/NumberToWords/BrazilianPortugueseNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/BrazilianPortugueseNumberToWordsConverter.cs
index 00efdf2e1..8b646a44d 100644
--- a/src/Humanizer/Localisation/NumberToWords/BrazilianPortugueseNumberToWordsConverter.cs
+++ b/src/Humanizer/Localisation/NumberToWords/BrazilianPortugueseNumberToWordsConverter.cs
@@ -3,7 +3,7 @@
namespace Humanizer.Localisation.NumberToWords
{
- internal class BrazilianPortugueseNumberToWordsConverter : DefaultNumberToWordsConverter
+ internal class BrazilianPortugueseNumberToWordsConverter : GenderedNumberToWordsConverter
{
private static readonly string[] PortugueseUnitsMap = { "zero", "um", "dois", "três", "quatro", "cinco", "seis", "sete", "oito", "nove", "dez", "onze", "doze", "treze", "quatorze", "quinze", "dezesseis", "dezessete", "dezoito", "dezenove" };
private static readonly string[] PortugueseTensMap = { "zero", "dez", "vinte", "trinta", "quarenta", "cinquenta", "sessenta", "setenta", "oitenta", "noventa" };
@@ -81,11 +81,6 @@ public override string Convert(int number, GrammaticalGender gender)
return string.Join(" ", parts.ToArray());
}
- public override string Convert(int number)
- {
- return Convert(number, GrammaticalGender.Masculine);
- }
-
public override string ConvertToOrdinal(int number, GrammaticalGender gender)
{
// N/A in Portuguese ordinal
@@ -139,12 +134,7 @@ public override string ConvertToOrdinal(int number, GrammaticalGender gender)
return string.Join(" ", parts.ToArray());
}
- public override string ConvertToOrdinal(int number)
- {
- return ConvertToOrdinal(number, GrammaticalGender.Masculine);
- }
-
- private string ApplyGender(string toWords, GrammaticalGender gender)
+ private static string ApplyGender(string toWords, GrammaticalGender gender)
{
if (gender != GrammaticalGender.Feminine)
return toWords;
@@ -161,11 +151,11 @@ private string ApplyGender(string toWords, GrammaticalGender gender)
return toWords;
}
- private string ApplyOrdinalGender(string toWords, GrammaticalGender gender)
+ private static string ApplyOrdinalGender(string toWords, GrammaticalGender gender)
{
if (gender == GrammaticalGender.Feminine)
return toWords.TrimEnd('o') + 'a';
-
+
return toWords;
}
}
diff --git a/src/Humanizer/Localisation/NumberToWords/DefaultNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/DefaultNumberToWordsConverter.cs
index 35c34adaf..ece6e9b0c 100644
--- a/src/Humanizer/Localisation/NumberToWords/DefaultNumberToWordsConverter.cs
+++ b/src/Humanizer/Localisation/NumberToWords/DefaultNumberToWordsConverter.cs
@@ -1,41 +1,28 @@
-namespace Humanizer.Localisation.NumberToWords
+using System.Globalization;
+
+namespace Humanizer.Localisation.NumberToWords
{
- internal class DefaultNumberToWordsConverter : INumberToWordsConverter
+ internal class DefaultNumberToWordsConverter : GenderlessNumberToWordsConverter
{
- ///
- /// for Russian locale
- /// 1.ToWords(GrammaticalGender.Masculine) -> "один"
- /// 1.ToWords(GrammaticalGender.Feminine) -> "одна"
- ///
- /// Number to be turned to words
- /// The grammatical gender to use for output words
- ///
- public virtual string Convert(int number, GrammaticalGender gender)
- {
- return Convert(number);
- }
+ private readonly CultureInfo _culture;
///
- /// 3501.ToWords() -> "three thousand five hundred and one"
+ /// Constructor.
///
- /// Number to be turned to words
- ///
- public virtual string Convert(int number)
+ /// Culture to use.
+ public DefaultNumberToWordsConverter(CultureInfo culture)
{
- return number.ToString();
+ _culture = culture;
}
///
- /// for Brazilian Portuguese
- /// 1.ToOrdinalWords(GrammaticalGender.Masculine) -> "primeiro"
- /// 1.ToOrdinalWords(GrammaticalGender.Feminine) -> "primeira"
+ /// 3501.ToWords() -> "three thousand five hundred and one"
///
/// Number to be turned to words
- /// The grammatical gender to use for output words
///
- public virtual string ConvertToOrdinal(int number, GrammaticalGender gender)
+ public override string Convert(int number)
{
- return ConvertToOrdinal(number);
+ return number.ToString(_culture);
}
///
@@ -43,9 +30,9 @@ public virtual string ConvertToOrdinal(int number, GrammaticalGender gender)
///
/// Number to be turned to ordinal words
///
- public virtual string ConvertToOrdinal(int number)
+ public override string ConvertToOrdinal(int number)
{
- return number.ToString();
+ return number.ToString(_culture);
}
}
}
\ No newline at end of file
diff --git a/src/Humanizer/Localisation/NumberToWords/DutchNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/DutchNumberToWordsConverter.cs
index a370f17c0..f071b1b05 100644
--- a/src/Humanizer/Localisation/NumberToWords/DutchNumberToWordsConverter.cs
+++ b/src/Humanizer/Localisation/NumberToWords/DutchNumberToWordsConverter.cs
@@ -9,7 +9,7 @@ namespace Humanizer.Localisation.NumberToWords
/// Used the rules as stated here.
/// http://www.beterspellen.nl/website/?pag=110
///
- internal class DutchNumberToWordsConverter : DefaultNumberToWordsConverter
+ internal class DutchNumberToWordsConverter : GenderlessNumberToWordsConverter
{
private static readonly string[] UnitsMap = { "nul", "een", "twee", "drie", "vier", "vijf", "zes", "zeven", "acht", "negen", "tien", "elf", "twaalf", "dertien", "veertien", "vijftien", "zestien", "zeventien", "achttien", "negentien" };
private static readonly string[] TensMap = { "nul", "tien", "twintig", "dertig", "veertig", "vijftig", "zestig", "zeventig", "tachtig", "negentig" };
@@ -24,12 +24,12 @@ class Fact
}
private static readonly Fact[] Hunderds =
- {
- new Fact {Value = 1000000000, Name = "miljard", Prefix = " ", Postfix = " ", DisplayOneUnit = true},
- new Fact {Value = 1000000, Name = "miljoen", Prefix = " ", Postfix = " ", DisplayOneUnit = true},
- new Fact {Value = 1000, Name = "duizend", Prefix = "", Postfix = " ", DisplayOneUnit = false},
- new Fact {Value = 100, Name = "honderd", Prefix = "", Postfix = "", DisplayOneUnit = false}
- };
+ {
+ new Fact {Value = 1000000000, Name = "miljard", Prefix = " ", Postfix = " ", DisplayOneUnit = true},
+ new Fact {Value = 1000000, Name = "miljoen", Prefix = " ", Postfix = " ", DisplayOneUnit = true},
+ new Fact {Value = 1000, Name = "duizend", Prefix = "", Postfix = " ", DisplayOneUnit = false},
+ new Fact {Value = 100, Name = "honderd", Prefix = "", Postfix = "", DisplayOneUnit = false}
+ };
public override string Convert(int number)
{
@@ -88,7 +88,7 @@ public override string Convert(int number)
};
private static readonly char[] EndingCharForSte = {'t', 'g', 'd'};
-
+
public override string ConvertToOrdinal(int number)
{
var word = Convert(number);
diff --git a/src/Humanizer/Localisation/NumberToWords/EnglishNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/EnglishNumberToWordsConverter.cs
index 1887f2cf4..d123caa91 100644
--- a/src/Humanizer/Localisation/NumberToWords/EnglishNumberToWordsConverter.cs
+++ b/src/Humanizer/Localisation/NumberToWords/EnglishNumberToWordsConverter.cs
@@ -3,7 +3,7 @@
namespace Humanizer.Localisation.NumberToWords
{
- internal class EnglishNumberToWordsConverter : DefaultNumberToWordsConverter
+ internal class EnglishNumberToWordsConverter : GenderlessNumberToWordsConverter
{
private static readonly string[] UnitsMap = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" };
private static readonly string[] TensMap = { "zero", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" };
diff --git a/src/Humanizer/Localisation/NumberToWords/FarsiNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/FarsiNumberToWordsConverter.cs
index 9602fde39..66d6b3f70 100644
--- a/src/Humanizer/Localisation/NumberToWords/FarsiNumberToWordsConverter.cs
+++ b/src/Humanizer/Localisation/NumberToWords/FarsiNumberToWordsConverter.cs
@@ -3,7 +3,7 @@
namespace Humanizer.Localisation.NumberToWords
{
- internal class FarsiNumberToWordsConverter : DefaultNumberToWordsConverter
+ internal class FarsiNumberToWordsConverter : GenderlessNumberToWordsConverter
{
private static readonly string[] FarsiHundredsMap = { "صفر", "صد", "دویست", "سیصد", "چهارصد", "پانصد", "ششصد", "هفتصد", "هشتصد", "نهصد" };
private static readonly string[] FarsiTensMap = { "صفر", "ده", "بیست", "سی", "چهل", "پنجاه", "شصت", "هفتاد", "هشتاد", "نود" };
@@ -61,10 +61,5 @@ public override string ConvertToOrdinal(int number)
var word = Convert(number);
return string.Format("{0}{1}", word, word.EndsWith("ی") ? " ام" : "م");
}
-
- public override string ConvertToOrdinal(int number, GrammaticalGender gender)
- {
- return ConvertToOrdinal(number);
- }
}
}
diff --git a/src/Humanizer/Localisation/NumberToWords/FrenchNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/FrenchNumberToWordsConverter.cs
index b022a5241..a8eee698c 100644
--- a/src/Humanizer/Localisation/NumberToWords/FrenchNumberToWordsConverter.cs
+++ b/src/Humanizer/Localisation/NumberToWords/FrenchNumberToWordsConverter.cs
@@ -3,7 +3,7 @@
namespace Humanizer.Localisation.NumberToWords
{
- internal class FrenchNumberToWordsConverter : DefaultNumberToWordsConverter
+ internal class FrenchNumberToWordsConverter : GenderedNumberToWordsConverter
{
private static readonly string[] UnitsMap = { "zéro", "un", "deux", "trois", "quatre", "cinq", "six", "sept", "huit", "neuf", "dix", "onze", "douze", "treize", "quatorze", "quinze", "seize", "dix-sept", "dix-huit", "dix-neuf" };
private static readonly string[] TensMap = { "zéro", "dix", "vingt", "trente", "quarante", "cinquante", "soixante", "soixante-dix", "quatre-vingt", "quatre-vingt-dix"};
@@ -15,7 +15,7 @@ internal class FrenchNumberToWordsConverter : DefaultNumberToWordsConverter
{91, "quatre-vingt-onze"}
};
- public override string Convert(int number)
+ public override string Convert(int number, GrammaticalGender gender)
{
if (number == 0)
return UnitsMap[0];
@@ -91,17 +91,9 @@ public override string Convert(int number)
}
public override string ConvertToOrdinal(int number, GrammaticalGender gender)
- {
- if (number == 1 && gender == GrammaticalGender.Feminine)
- return "première";
-
- return base.ConvertToOrdinal(number, gender);
- }
-
- public override string ConvertToOrdinal(int number)
{
if (number == 1)
- return "premier";
+ return gender == GrammaticalGender.Feminine ? "première" : "premier";
var convertedNumber = Convert(number);
diff --git a/src/Humanizer/Localisation/NumberToWords/GenderedNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/GenderedNumberToWordsConverter.cs
new file mode 100644
index 000000000..4af91b4f3
--- /dev/null
+++ b/src/Humanizer/Localisation/NumberToWords/GenderedNumberToWordsConverter.cs
@@ -0,0 +1,48 @@
+namespace Humanizer.Localisation.NumberToWords
+{
+ abstract class GenderedNumberToWordsConverter : INumberToWordsConverter
+ {
+ private readonly GrammaticalGender _defaultGender;
+
+ protected GenderedNumberToWordsConverter(GrammaticalGender defaultGender = GrammaticalGender.Masculine)
+ {
+ _defaultGender = defaultGender;
+ }
+
+ ///
+ /// Converts the number to string using the locale's default grammatical gender
+ ///
+ ///
+ ///
+ public string Convert(int number)
+ {
+ return Convert(number, _defaultGender);
+ }
+
+ ///
+ /// Converts the number to string using the provided grammatical gender
+ ///
+ ///
+ ///
+ ///
+ public abstract string Convert(int number, GrammaticalGender gender);
+
+ ///
+ /// Converts the number to ordinal string using the locale's default grammatical gender
+ ///
+ ///
+ ///
+ public string ConvertToOrdinal(int number)
+ {
+ return ConvertToOrdinal(number, _defaultGender);
+ }
+
+ ///
+ /// Converts the number to ordinal string using the provided grammatical gender
+ ///
+ ///
+ ///
+ ///
+ public abstract string ConvertToOrdinal(int number, GrammaticalGender gender);
+ }
+}
diff --git a/src/Humanizer/Localisation/NumberToWords/GenderlessNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/GenderlessNumberToWordsConverter.cs
new file mode 100644
index 000000000..fa89f250d
--- /dev/null
+++ b/src/Humanizer/Localisation/NumberToWords/GenderlessNumberToWordsConverter.cs
@@ -0,0 +1,41 @@
+namespace Humanizer.Localisation.NumberToWords
+{
+ abstract class GenderlessNumberToWordsConverter : INumberToWordsConverter
+ {
+ ///
+ /// Converts the number to string
+ ///
+ ///
+ ///
+ public abstract string Convert(int number);
+
+ ///
+ /// Converts the number to string ignoring the provided grammatical gender
+ ///
+ ///
+ ///
+ ///
+ public string Convert(int number, GrammaticalGender gender)
+ {
+ return Convert(number);
+ }
+
+ ///
+ /// Converts the number to ordinal string
+ ///
+ ///
+ ///
+ public abstract string ConvertToOrdinal(int number);
+
+ ///
+ /// Converts the number to ordinal string ignoring the provided grammatical gender
+ ///
+ ///
+ ///
+ ///
+ public string ConvertToOrdinal(int number, GrammaticalGender gender)
+ {
+ return ConvertToOrdinal(number);
+ }
+ }
+}
diff --git a/src/Humanizer/Localisation/NumberToWords/GermanNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/GermanNumberToWordsConverter.cs
index 99f0bb877..547534a09 100644
--- a/src/Humanizer/Localisation/NumberToWords/GermanNumberToWordsConverter.cs
+++ b/src/Humanizer/Localisation/NumberToWords/GermanNumberToWordsConverter.cs
@@ -3,7 +3,7 @@
namespace Humanizer.Localisation.NumberToWords
{
- internal class GermanNumberToWordsConverter : DefaultNumberToWordsConverter
+ internal class GermanNumberToWordsConverter : GenderedNumberToWordsConverter
{
private static readonly string[] UnitsMap = { "null", "ein", "zwei", "drei", "vier", "fünf", "sechs", "sieben", "acht", "neun", "zehn", "elf", "zwölf", "dreizehn", "vierzehn", "fünfzehn", "sechzehn", "siebzehn", "achtzehn", "neunzehn" };
private static readonly string[] TensMap = { "null", "zehn", "zwanzig", "dreißig", "vierzig", "fünfzig", "sechzig", "siebzig", "achtzig", "neunzig" };
@@ -13,7 +13,7 @@ internal class GermanNumberToWordsConverter : DefaultNumberToWordsConverter
private static readonly string[] BillionOrdinalSingular = {"einmilliard", "einemilliarde"};
private static readonly string[] BillionOrdinalPlural = {"{0}milliard", "{0}milliarden"};
- public override string Convert(int number)
+ public override string Convert(int number, GrammaticalGender gender)
{
if (number == 0)
return "null";
@@ -77,11 +77,6 @@ public override string Convert(int number)
return string.Join("", parts);
}
- public override string ConvertToOrdinal(int number)
- {
- return ConvertToOrdinal(number, GrammaticalGender.Masculine);
- }
-
public override string ConvertToOrdinal(int number, GrammaticalGender gender)
{
if (number == 0)
diff --git a/src/Humanizer/Localisation/NumberToWords/HebrewNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/HebrewNumberToWordsConverter.cs
index 759b158de..411dc0b53 100644
--- a/src/Humanizer/Localisation/NumberToWords/HebrewNumberToWordsConverter.cs
+++ b/src/Humanizer/Localisation/NumberToWords/HebrewNumberToWordsConverter.cs
@@ -1,14 +1,17 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
namespace Humanizer.Localisation.NumberToWords
{
- internal class HebrewNumberToWordsConverter : DefaultNumberToWordsConverter
+ internal class HebrewNumberToWordsConverter : GenderedNumberToWordsConverter
{
private static readonly string[] UnitsFeminine = { "אפס", "אחת", "שתיים", "שלוש", "ארבע", "חמש", "שש", "שבע", "שמונה", "תשע", "עשר" };
private static readonly string[] UnitsMasculine = { "אפס", "אחד", "שניים", "שלושה", "ארבעה", "חמישה", "שישה", "שבעה", "שמונה", "תשעה", "עשרה" };
private static readonly string[] TensUnit = { "עשר", "עשרים", "שלושים", "ארבעים", "חמישים", "שישים", "שבעים", "שמונים", "תשעים" };
+ private readonly CultureInfo _culture;
+
private class DescriptionAttribute : Attribute
{
public string Description { get; set; }
@@ -29,10 +32,10 @@ private enum Group
Billions = 1000000000
}
- public override string Convert(int number)
+ public HebrewNumberToWordsConverter(CultureInfo culture)
+ : base(GrammaticalGender.Feminine)
{
- // in Hebrew, the default number gender form is feminine.
- return Convert(number, GrammaticalGender.Feminine);
+ _culture = culture;
}
public override string Convert(int number, GrammaticalGender gender)
@@ -104,6 +107,11 @@ public override string Convert(int number, GrammaticalGender gender)
return string.Join(" ", parts);
}
+ public override string ConvertToOrdinal(int number, GrammaticalGender gender)
+ {
+ return number.ToString(_culture);
+ }
+
private void ToBigNumber(int number, Group group, List parts)
{
// Big numbers (million and above) always use the masculine form
@@ -131,7 +139,7 @@ private void ToThousands(int number, List parts)
parts.Add(Convert(thousands) + " אלף");
}
- private void ToHundreds(int number, List parts)
+ private static void ToHundreds(int number, List parts)
{
// For hundreds, Hebrew is using the feminine form
// See https://www.safa-ivrit.org/dikduk/numbers.php
diff --git a/src/Humanizer/Localisation/NumberToWords/PolishNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/PolishNumberToWordsConverter.cs
index 38386c368..894a90852 100644
--- a/src/Humanizer/Localisation/NumberToWords/PolishNumberToWordsConverter.cs
+++ b/src/Humanizer/Localisation/NumberToWords/PolishNumberToWordsConverter.cs
@@ -1,13 +1,21 @@
using System.Collections.Generic;
+using System.Globalization;
namespace Humanizer.Localisation.NumberToWords
{
- internal class PolishNumberToWordsConverter : DefaultNumberToWordsConverter
+ internal class PolishNumberToWordsConverter : GenderlessNumberToWordsConverter
{
private static readonly string[] HundredsMap = { "zero", "sto", "dwieście", "trzysta", "czterysta", "pięćset", "sześćset", "siedemset", "osiemset", "dziewięćset" };
private static readonly string[] TensMap = { "zero", "dziesięć", "dwadzieścia", "trzydzieści", "czterdzieści", "pięćdziesiąt", "sześćdziesiąt", "siedemdziesiąt", "osiemdziesiąt", "dziewięćdziesiąt" };
private static readonly string[] UnitsMap = { "zero", "jeden", "dwa", "trzy", "cztery", "pięć", "sześć", "siedem", "osiem", "dziewięć", "dziesięć", "jedenaście", "dwanaście", "trzynaście", "czternaście", "piętnaście", "szesnaście", "siedemnaście", "osiemnaście", "dziewiętnaście" };
+ private readonly CultureInfo _culture;
+
+ public PolishNumberToWordsConverter(CultureInfo culture)
+ {
+ _culture = culture;
+ }
+
private static void CollectPartsUnderThousand(ICollection parts, int number)
{
var hundreds = number/100;
@@ -99,5 +107,10 @@ public override string Convert(int number)
return string.Join(" ", parts);
}
+
+ public override string ConvertToOrdinal(int number)
+ {
+ return number.ToString(_culture);
+ }
}
}
diff --git a/src/Humanizer/Localisation/NumberToWords/RussianNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/RussianNumberToWordsConverter.cs
index 90bcd2aa7..e53092aad 100644
--- a/src/Humanizer/Localisation/NumberToWords/RussianNumberToWordsConverter.cs
+++ b/src/Humanizer/Localisation/NumberToWords/RussianNumberToWordsConverter.cs
@@ -4,7 +4,7 @@
namespace Humanizer.Localisation.NumberToWords
{
- internal class RussianNumberToWordsConverter : DefaultNumberToWordsConverter
+ internal class RussianNumberToWordsConverter : GenderedNumberToWordsConverter
{
private static readonly string[] HundredsMap = { "ноль", "сто", "двести", "триста", "четыреста", "пятьсот", "шестьсот", "семьсот", "восемьсот", "девятьсот" };
private static readonly string[] TensMap = { "ноль", "десять", "двадцать", "тридцать", "сорок", "пятьдесят", "шестьдесят", "семьдесят", "восемьдесят", "девяносто" };
@@ -14,11 +14,6 @@ internal class RussianNumberToWordsConverter : DefaultNumberToWordsConverter
private static readonly string[] TensOrdinal = { string.Empty, "десят", "двадцат", "тридцат", "сороков", "пятидесят", "шестидесят", "семидесят", "восьмидесят", "девяност" };
private static readonly string[] UnitsOrdinal = { string.Empty, "перв", "втор", "трет", "четверт", "пят", "шест", "седьм", "восьм", "девят", "десят", "одиннадцат", "двенадцат", "тринадцат", "четырнадцат", "пятнадцат", "шестнадцат", "семнадцат", "восемнадцат", "девятнадцат" };
- public override string Convert(int number)
- {
- return Convert(number, GrammaticalGender.Masculine);
- }
-
public override string Convert(int number, GrammaticalGender gender)
{
if (number == 0)
@@ -42,11 +37,6 @@ public override string Convert(int number, GrammaticalGender gender)
return string.Join(" ", parts);
}
- public override string ConvertToOrdinal(int number)
- {
- return ConvertToOrdinal(number, GrammaticalGender.Masculine);
- }
-
public override string ConvertToOrdinal(int number, GrammaticalGender gender)
{
if (number == 0)
diff --git a/src/Humanizer/Localisation/NumberToWords/SlovenianNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/SlovenianNumberToWordsConverter.cs
index 743adf90f..eaa48ca2c 100644
--- a/src/Humanizer/Localisation/NumberToWords/SlovenianNumberToWordsConverter.cs
+++ b/src/Humanizer/Localisation/NumberToWords/SlovenianNumberToWordsConverter.cs
@@ -1,13 +1,21 @@
using System.Collections.Generic;
+using System.Globalization;
namespace Humanizer.Localisation.NumberToWords
{
- internal class SlovenianNumberToWordsConverter : DefaultNumberToWordsConverter
- {
- private static readonly string[] UnitsMap = {"nič", "ena", "dva", "tri", "štiri", "pet", "šest", "sedem", "osem", "devet", "deset", "enajst", "dvanajst", "trinajst", "štirinajst", "petnajst", "šestnajst", "sedemnajst", "osemnajst", "devetnajst"};
- private static readonly string[] TensMap = {"nič", "deset", "dvajset", "trideset", "štirideset", "petdeset", "šestdeset", "sedemdeset", "osemdeset", "devetdeset"};
+ internal class SlovenianNumberToWordsConverter : GenderlessNumberToWordsConverter
+ {
+ private static readonly string[] UnitsMap = {"nič", "ena", "dva", "tri", "štiri", "pet", "šest", "sedem", "osem", "devet", "deset", "enajst", "dvanajst", "trinajst", "štirinajst", "petnajst", "šestnajst", "sedemnajst", "osemnajst", "devetnajst"};
+ private static readonly string[] TensMap = {"nič", "deset", "dvajset", "trideset", "štirideset", "petdeset", "šestdeset", "sedemdeset", "osemdeset", "devetdeset"};
- public override string Convert(int number)
+ private readonly CultureInfo _culture;
+
+ public SlovenianNumberToWordsConverter(CultureInfo culture)
+ {
+ _culture = culture;
+ }
+
+ public override string Convert(int number)
{
if (number == 0)
return "nič";
@@ -75,7 +83,12 @@ public override string Convert(int number)
return string.Join("", parts);
}
- private string Part(string singular, string dual, string trialQuadral, string plural, int number)
+ public override string ConvertToOrdinal(int number)
+ {
+ return number.ToString(_culture);
+ }
+
+ private string Part(string singular, string dual, string trialQuadral, string plural, int number)
{
if (number == 1)
return singular;
@@ -88,5 +101,5 @@ private string Part(string singular, string dual, string trialQuadral, string pl
return string.Format(plural, Convert(number));
}
- }
+ }
}
\ No newline at end of file
diff --git a/src/Humanizer/Localisation/NumberToWords/SpanishNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/SpanishNumberToWordsConverter.cs
index a3afe02ab..d8ef2d238 100644
--- a/src/Humanizer/Localisation/NumberToWords/SpanishNumberToWordsConverter.cs
+++ b/src/Humanizer/Localisation/NumberToWords/SpanishNumberToWordsConverter.cs
@@ -3,7 +3,7 @@
namespace Humanizer.Localisation.NumberToWords
{
- internal class SpanishNumberToWordsConverter : DefaultNumberToWordsConverter
+ internal class SpanishNumberToWordsConverter : GenderedNumberToWordsConverter
{
private static readonly string[] UnitsMap = { "cero", "uno", "dos", "tres", "cuatro", "cinco", "seis", "siete", "ocho", "nueve", "diez", "once", "doce",
"trece", "catorce", "quince", "dieciséis", "diecisiete", "dieciocho", "diecinueve", "veinte", "veintiuno",
@@ -25,7 +25,7 @@ internal class SpanishNumberToWordsConverter : DefaultNumberToWordsConverter
{10, "décimo"}
};
- public override string Convert(int number)
+ public override string Convert(int number, GrammaticalGender gender)
{
if (number == 0)
return "cero";
@@ -92,7 +92,7 @@ public override string Convert(int number)
return string.Join(" ", parts.ToArray());
}
- public override string ConvertToOrdinal(int number, GrammaticalGender gender = GrammaticalGender.Masculine)
+ public override string ConvertToOrdinal(int number, GrammaticalGender gender)
{
string towords;
if (!Ordinals.TryGetValue(number, out towords))
diff --git a/src/Humanizer/NumberToWordsExtension.cs b/src/Humanizer/NumberToWordsExtension.cs
index ca9f211ec..afab61866 100644
--- a/src/Humanizer/NumberToWordsExtension.cs
+++ b/src/Humanizer/NumberToWordsExtension.cs
@@ -1,3 +1,4 @@
+using System.Globalization;
using Humanizer.Configuration;
namespace Humanizer
@@ -11,10 +12,11 @@ public static class NumberToWordsExtension
/// 3501.ToWords() -> "three thousand five hundred and one"
///
/// Number to be turned to words
+ /// Culture to use. If null, current thread's UI culture is used.
///
- public static string ToWords(this int number)
+ public static string ToWords(this int number, CultureInfo culture = null)
{
- return Configurator.NumberToWordsConverter.Convert(number);
+ return Configurator.GetNumberToWordsConverter(culture).Convert(number);
}
///
@@ -35,20 +37,22 @@ public static string ToWords(this int number)
///
/// Number to be turned to words
/// The grammatical gender to use for output words
+ /// Culture to use. If null, current thread's UI culture is used.
///
- public static string ToWords(this int number, GrammaticalGender gender)
+ public static string ToWords(this int number, GrammaticalGender gender, CultureInfo culture = null)
{
- return Configurator.NumberToWordsConverter.Convert(number, gender);
+ return Configurator.GetNumberToWordsConverter(culture).Convert(number, gender);
}
///
/// 1.ToOrdinalWords() -> "first"
///
/// Number to be turned to ordinal words
+ /// Culture to use. If null, current thread's UI culture is used.
///
- public static string ToOrdinalWords(this int number)
+ public static string ToOrdinalWords(this int number, CultureInfo culture = null)
{
- return Configurator.NumberToWordsConverter.ConvertToOrdinal(number);
+ return Configurator.GetNumberToWordsConverter(culture).ConvertToOrdinal(number);
}
///
@@ -58,10 +62,11 @@ public static string ToOrdinalWords(this int number)
///
/// Number to be turned to words
/// The grammatical gender to use for output words
+ /// Culture to use. If null, current thread's UI culture is used.
///
- public static string ToOrdinalWords(this int number, GrammaticalGender gender)
+ public static string ToOrdinalWords(this int number, GrammaticalGender gender, CultureInfo culture = null)
{
- return Configurator.NumberToWordsConverter.ConvertToOrdinal(number, gender);
+ return Configurator.GetNumberToWordsConverter(culture).ConvertToOrdinal(number, gender);
}
}
}