Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add russian translation for ToWords #147

Closed
wants to merge 13 commits into from
Next Next commit
add russian translation for ToWords
  • Loading branch information
mexx committed Apr 12, 2014
commit 1ef992cb88d68ddb07efa4428699b414382bf90a
1 change: 1 addition & 0 deletions src/Humanizer.Tests/Humanizer.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
<Compile Include="Localisation\pl\DateHumanizeTests.cs" />
<Compile Include="Localisation\pl\NumberToWordsTests.cs" />
<Compile Include="Localisation\pl\TimeSpanHumanizeTests.cs" />
<Compile Include="Localisation\ru-RU\NumberToWordsTests.cs" />
<Compile Include="Localisation\ru-RU\TimeSpanHumanizeTests.cs" />
<Compile Include="Localisation\sk\DateHumanizeTests.cs" />
<Compile Include="Localisation\ar\DateHumanizeTests.cs" />
Expand Down
71 changes: 71 additions & 0 deletions src/Humanizer.Tests/Localisation/ru-RU/NumberToWordsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using Xunit;
using Xunit.Extensions;

namespace Humanizer.Tests.Localisation.ruRU
{
public class NumberToWordsTests : AmbientCulture
{
public NumberToWordsTests() : base("ru-RU") { }

[InlineData(0, "ноль")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Holy crap!! ;)

[InlineData(1, "один")]
[InlineData(10, "десять")]
[InlineData(11, "одиннадцать")]
[InlineData(12, "двенадцать")]
[InlineData(13, "тринадцать")]
[InlineData(14, "четырнадцать")]
[InlineData(15, "пятнадцать")]
[InlineData(16, "шестнадцать")]
[InlineData(17, "семнадцать")]
[InlineData(18, "восемнадцать")]
[InlineData(19, "девятнадцать")]
[InlineData(20, "двадцать")]
[InlineData(30, "тридцать")]
[InlineData(40, "сорок")]
[InlineData(50, "пятьдесят")]
[InlineData(60, "шестьдесят")]
[InlineData(70, "семьдесят")]
[InlineData(80, "восемьдесят")]
[InlineData(90, "девяносто")]
[InlineData(100, "сто")]
[InlineData(200, "двести")]
[InlineData(300, "триста")]
[InlineData(400, "четыреста")]
[InlineData(500, "пятьсот")]
[InlineData(600, "шестьсот")]
[InlineData(700, "семьсот")]
[InlineData(800, "восемьсот")]
[InlineData(900, "девятьсот")]
[InlineData(1000, "одна тысяча")]
[InlineData(2000, "две тысячи")]
[InlineData(3000, "три тысячи")]
[InlineData(4000, "четыре тысячи")]
[InlineData(5000, "пять тысячь")]
[InlineData(10000, "десять тысячь")]
[InlineData(100000, "сто тысячь")]
[InlineData(1000000, "один миллион")]
[InlineData(2000000, "два миллиона")]
[InlineData(10000000, "десять миллионов")]
[InlineData(100000000, "сто миллионов")]
[InlineData(1000000000, "один миллиард")]
[InlineData(2000000000, "два миллиарда")]
//[InlineData(5000000000, "пять миллиардов")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this commented out? We should either make it work or remove it from the test cases.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5*10^9 do not fit in an int 👎
Should we extend the range by providing the Humanize method for long?
But for now I will remove it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That could be a breaking change. So let's leave it out for now.


[InlineData(122, "сто двадцать два")]
[InlineData(3501, "три тысячи пятьсот один")]
[InlineData(111, "сто одиннадцать")]
[InlineData(1112, "одна тысяча сто двенадцать")]
[InlineData(11213, "одиннадцать тысячь двести тринадцать")]
[InlineData(121314, "сто двадцать одна тысяча триста четырнадцать")]
[InlineData(2132415, "два миллиона сто тридцать две тысячи четыреста пятнадцать")]
[InlineData(12345516, "двенадцать миллионов триста сорок пять тысячь пятьсот шестнадцать")]
[InlineData(751633617, "семьсот пятьдесят один миллион шестьсот тридцать три тысячи шестьсот семнадцать")]
[InlineData(1111111118, "один миллиард сто одиннадцать миллионов сто одиннадцать тысячь сто восемнадцать")]
[InlineData(-751633617, "минус семьсот пятьдесят один миллион шестьсот тридцать три тысячи шестьсот семнадцать")]
[Theory]
public void ToWords(int number, string expected)
{
Assert.Equal(expected, number.ToWords());
}
}
}
1 change: 1 addition & 0 deletions src/Humanizer/Humanizer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
<Compile Include="DateTimeHumanizeStrategy\IDateTimeHumanizeStrategy.cs" />
<Compile Include="DateTimeHumanizeStrategy\PrecisionDateTimeHumanizeStrategy.cs" />
<Compile Include="Localisation\NumberToWords\PolishNumberToWordsConverter.cs" />
<Compile Include="Localisation\NumberToWords\RussianNumberToWordsConverter.cs" />
<Compile Include="Localisation\Tense.cs" />
<Compile Include="Localisation\NumberToWords\SpanishNumberToWordsConverter.cs" />
<Compile Include="TimeSpanHumanizeExtensions.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
using System.Collections.Generic;

namespace Humanizer.Localisation.NumberToWords
{
internal class RussianNumberToWordsConverter : DefaultNumberToWordsConverter
{
private enum GrammaticalGender
{
Masculine,
Feminine,
Neuter
}

private enum GrammaticalNumber
{
Singular,
Paucal,
Plural
}

private static GrammaticalNumber ToRussianGrammaticalNumber(int number)
{
var mod100 = number % 100;
if (mod100 / 10 != 1)
{
var mod10 = number % 10;

if (mod10 == 1) // 1, 21, 31, 41 ... 91, 101, 121 ..
return GrammaticalNumber.Singular;

if (mod10 > 1 && mod10 < 5) // 2, 3, 4, 22, 23, 24 ...
return GrammaticalNumber.Paucal;
}

return GrammaticalNumber.Plural;
}

private static string ToWordsUnderThousand(int number, GrammaticalGender gender)
{
var parts = new List<string>();

var hunderdsMap = new[] { "ноль", "сто", "двести", "триста", "четыреста", "пятьсот", "шестьсот", "семьсот", "восемьсот", "девятьсот" };
var hunderds = number / 100;
if (hunderds > 0)
{
parts.Add(hunderdsMap[hunderds]);
number %= 100;
}

var tens = number / 10;
if (tens > 1)
{
var tensMap = new[] { "ноль", "десять", "двадцать", "тридцать", "сорок", "пятьдесят", "шестьдесят", "семьдесят", "восемьдесят", "девяносто" };
parts.Add(tensMap[tens]);
number %= 10;
}

if (number > 0)
{
if (number == 1 && gender == GrammaticalGender.Feminine)
parts.Add("одна");
else if (number == 1 && gender == GrammaticalGender.Neuter)
parts.Add("одно");
else if (number == 2 && gender == GrammaticalGender.Feminine)
parts.Add("две");
else
{
var unitsMap = new[] { "ноль", "один", "два", "три", "четыре", "пять", "шесть", "семь", "восемь", "девять", "десять", "одиннадцать", "двенадцать", "тринадцать", "четырнадцать", "пятнадцать", "шестнадцать", "семнадцать", "восемнадцать", "девятнадцать" };
if (number < 20)
parts.Add(unitsMap[number]);
}
}

return string.Join(" ", parts.ToArray());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not need .ToArray() call

}

public override string Convert(int number)
{
if (number == 0)
return "ноль";

if (number < 0)
return string.Format("минус {0}", Convert(-number));

var parts = new List<string>();

var milliards = number / 1000000000;
if (milliards > 0)
{
var map = new[] { "миллиард", "миллиарда", "миллиардов" };
var grammaticalNumber = ToRussianGrammaticalNumber(milliards);
parts.Add(string.Format("{0} {1}", ToWordsUnderThousand(milliards, GrammaticalGender.Masculine), map[(int)grammaticalNumber]));
number %= 1000000000;
}

var millions = number / 1000000;
if (millions > 0)
{
var map = new[] { "миллион", "миллиона", "миллионов" };
var grammaticalNumber = ToRussianGrammaticalNumber(millions);
parts.Add(string.Format("{0} {1}", ToWordsUnderThousand(millions, GrammaticalGender.Masculine), map[(int)grammaticalNumber]));
number %= 1000000;
}

var thousands = number / 1000;
if (thousands > 0)
{
var map = new[] { "тысяча", "тысячи", "тысячь" };
var grammaticalNumber = ToRussianGrammaticalNumber(thousands);
parts.Add(string.Format("{0} {1}", ToWordsUnderThousand(thousands, GrammaticalGender.Feminine), map[(int)grammaticalNumber]));
number %= 1000;
}

if (number > 0)
{
parts.Add(ToWordsUnderThousand(number, GrammaticalGender.Masculine));
}

return string.Join(" ", parts.ToArray());
}
}
}
3 changes: 2 additions & 1 deletion src/Humanizer/NumberToWordsExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ public static class NumberToWordsExtension {
{ "ar", () => new ArabicNumberToWordsConverter() },
{ "fa", () => new FarsiNumberToWordsConverter() },
{ "es", () => new SpanishNumberToWordsConverter() },
{ "pl", () => new PolishNumberToWordsConverter() }
{ "pl", () => new PolishNumberToWordsConverter() },
{ "ru", () => new RussianNumberToWordsConverter() }
};

/// <summary>
Expand Down