diff --git a/.gitignore b/.gitignore
index 6d38a7388..f734e51d8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,7 @@ obj/
src/packages/*
PackageBuild/*
Build/*
+Release/*
src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.received.txt
*.tss
src/TestResults/*
diff --git a/build.cmd b/build.cmd
new file mode 100644
index 000000000..e5f3378f8
--- /dev/null
+++ b/build.cmd
@@ -0,0 +1 @@
+@%WINDIR%\Microsoft.Net\Framework\v4.0.30319\msbuild build.proj /m /clp:Verbosity=minimal
diff --git a/build.config b/build.config
new file mode 100644
index 000000000..680228da3
--- /dev/null
+++ b/build.config
@@ -0,0 +1,23 @@
+
+
+
+ tools\xunit
+
+
+ Release
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build.proj b/build.proj
new file mode 100644
index 000000000..50d2dfde8
--- /dev/null
+++ b/build.proj
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/logo.png b/logo.png
new file mode 100644
index 000000000..9fdf08096
Binary files /dev/null and b/logo.png differ
diff --git a/readme.md b/readme.md
index 658655fe9..ee97d1abd 100644
--- a/readme.md
+++ b/readme.md
@@ -1,3 +1,5 @@
+
+
Humanizer meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities.
###Table of contents
@@ -32,6 +34,7 @@ Humanizer meets all your .NET needs for manipulating and displaying strings, enu
- [Author](#author)
- [Main contributors](#main-contributors)
- [License](#license)
+ - [Icon](#icon)
##Install
You can install Humanizer as [a nuget package](https://nuget.org/packages/Humanizer): `Install-Package Humanizer`
@@ -784,7 +787,7 @@ I have also flagged some of the easier issues as 'jump in' so you can start with
###Contribution guideline
I use [GitHub flow](http://scottchacon.com/2011/08/31/github-flow.html) for pull requests.
-So if you want to contribute, fork the repo, preferrably create a local branch to avoid conflicts with other activities, fix an issue and send a PR.
+So if you want to contribute, fork the repo, preferrably create a local branch to avoid conflicts with other activities, fix an issue, run build.cmd from the root of the project, and send a PR if all is green.
Pull requests are code reviewed. Here is a checklist you should tick through before submitting a pull request:
@@ -844,3 +847,5 @@ Alexander I. Zaytsev ([@hazzik](https://github.com/hazzik))
##License
Humanizer is released under the MIT License. See the [bundled LICENSE](https://github.com/MehdiK/Humanizer/blob/master/LICENSE) file for details.
+##Icon
+Icon created by [Tyrone Rieschiek](https://twitter.com/Inkventive)
\ No newline at end of file
diff --git a/release_notes.md b/release_notes.md
index ae0ddac56..068079dd8 100644
--- a/release_notes.md
+++ b/release_notes.md
@@ -1,8 +1,25 @@
###In Development
- - [#217](https://github.com/Mehdik/Humanizer/pull/217): Changed OrdinalizeExtensions to better accommodate localisations. Added pt-BR and Spanish Ordinalize localisation.
+
+[Commits](https://github.com/MehdiK/Humanizer/compare/v1.24.1...master)
+
+###v1.24.1 - 2014-04-21
+ - [#232](https://github.com/Mehdik/Humanizer/pull/232): Adding code & tests to handle Arabic numbers to ordinal
+ - [#235](https://github.com/Mehdik/Humanizer/pull/235): Fixed the conversion for "1 millon" in SpanishNumberToWordsConverter
+ - [#233](https://github.com/Mehdik/Humanizer/pull/233): Added build.cmd and Verify build configuration for strict project build and analysis
+
+[Commits](https://github.com/MehdiK/Humanizer/compare/v1.23.1...v1.24.1)
+
+###v1.23.1 - 2014-04-19
+ - [#217](https://github.com/Mehdik/Humanizer/pull/217): Added pt-BR and Spanish Ordinalize localisation.
+ - [#220](https://github.com/Mehdik/Humanizer/pull/220): Added string formatting options to ToQuantity
+ - [#219](https://github.com/Mehdik/Humanizer/pull/219): Added Japanese translation for date and timespan
- [#221](https://github.com/Mehdik/Humanizer/pull/221): Added Russian ordinalizer
+ - [#228](https://github.com/Mehdik/Humanizer/pull/228): Fixed the "twenties" in SpanishNumberToWordsConverter
+ - [#231](https://github.com/Mehdik/Humanizer/pull/231): Added more settings for FromNow, Dual and Plural (Arabic)
+ - [#222](https://github.com/Mehdik/Humanizer/pull/222): Updated Ordinalize and ToOrdinalWords to account for special exceptions with 1 and 3.
+
-[Commits](https://github.com/MehdiK/Humanizer/compare/v1.22.1...master)
+[Commits](https://github.com/MehdiK/Humanizer/compare/v1.22.1...v1.23.1)
###v1.22.1 - 2014-04-14
- [#188](https://github.com/Mehdik/Humanizer/pull/188): Added Spanish ToOrdinalWords translations
diff --git a/src/Humanizer.Tests/AmbientCulture.cs b/src/Humanizer.Tests/AmbientCulture.cs
index d8515f329..bbd7e0584 100644
--- a/src/Humanizer.Tests/AmbientCulture.cs
+++ b/src/Humanizer.Tests/AmbientCulture.cs
@@ -4,6 +4,8 @@
namespace Humanizer.Tests
{
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly",
+ Justification = "This is a test only class, and doesn't need a 'proper' IDisposable implementation.")]
public class AmbientCulture : IDisposable
{
private readonly CultureInfo _culture;
@@ -20,6 +22,8 @@ public AmbientCulture(string cultureName)
{
}
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly",
+ Justification="This is a test only class, and doesn't need a 'proper' IDisposable implementation.")]
public void Dispose()
{
Thread.CurrentThread.CurrentUICulture = _culture;
diff --git a/src/Humanizer.Tests/Humanizer.Tests.csproj b/src/Humanizer.Tests/Humanizer.Tests.csproj
index 211b172f1..b7a0d5106 100644
--- a/src/Humanizer.Tests/Humanizer.Tests.csproj
+++ b/src/Humanizer.Tests/Humanizer.Tests.csproj
@@ -49,6 +49,16 @@
true
false
+
+ bin\Verify\
+ ..\Humanizer.ruleset
+ true
+ 1591
+ bin\Verify\Humanizer.Tests.XML
+ pdbonly
+ true
+ true
+
..\packages\ApprovalTests.3.0.5\lib\net40\ApprovalTests.dll
@@ -98,6 +108,8 @@
+
+
@@ -125,6 +137,10 @@
+
+
+
+
diff --git a/src/Humanizer.Tests/Localisation/ar/DateHumanizeTests.cs b/src/Humanizer.Tests/Localisation/ar/DateHumanizeTests.cs
index 00151b5cb..51ba125be 100644
--- a/src/Humanizer.Tests/Localisation/ar/DateHumanizeTests.cs
+++ b/src/Humanizer.Tests/Localisation/ar/DateHumanizeTests.cs
@@ -1,4 +1,4 @@
-using Humanizer.Localisation;
+using Humanizer.Localisation;
using Xunit.Extensions;
namespace Humanizer.Tests.Localisation.ar
@@ -18,6 +18,16 @@ public void DaysAgo(int days, string expected)
DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past);
}
+ [Theory]
+ [InlineData(1, "في غضون يوم واحد من الآن")]
+ [InlineData(2, "في غضون يومين من الآن")]
+ [InlineData(10, "في غضون 10 أيام من الآن")]
+ [InlineData(17, "في غضون 17 يوم من الآن")]
+ public void DaysFromNow(int days, string expected)
+ {
+ DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future);
+ }
+
[Theory]
[InlineData(-2, "منذ ساعتين")]
[InlineData(-1, "منذ ساعة واحدة")]
@@ -28,6 +38,16 @@ public void HoursAgo(int hours, string expected)
DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past);
}
+ [Theory]
+ [InlineData(1, "في غضون ساعة واحدة من الآن")]
+ [InlineData(2, "في غضون ساعتين من الآن")]
+ [InlineData(10, "في غضون 10 ساعات من الآن")]
+ [InlineData(23, "في غضون 23 ساعة من الآن")]
+ public void HoursFromNow(int hours, string expected)
+ {
+ DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future);
+ }
+
[Theory]
[InlineData(-2, "منذ دقيقتين")]
[InlineData(-1, "منذ دقيقة واحدة")]
@@ -38,6 +58,16 @@ public void MinutesAgo(int minutes, string expected)
DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past);
}
+ [Theory]
+ [InlineData(1, "في غضون دقيقة واحدة من الآن")]
+ [InlineData(2, "في غضون دقيقتين من الآن")]
+ [InlineData(10, "في غضون 10 دقائق من الآن")]
+ [InlineData(23, "في غضون 23 دقيقة من الآن")]
+ public void MinutesFromNow(int minutes, string expected)
+ {
+ DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future);
+ }
+
[Theory]
[InlineData(-2, "منذ شهرين")]
[InlineData(-1, "منذ شهر واحد")]
@@ -48,6 +78,15 @@ public void MonthsAgo(int months, string expected)
DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past);
}
+ [Theory]
+ [InlineData(1, "في غضون شهر واحد من الآن")]
+ [InlineData(2, "في غضون شهرين من الآن")]
+ [InlineData(10, "في غضون 10 أشهر من الآن")]
+ public void MonthsFromNow(int months, string expected)
+ {
+ DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future);
+ }
+
[Theory]
[InlineData(-2, "منذ ثانيتين")]
[InlineData(-1, "منذ ثانية واحدة")]
@@ -58,6 +97,17 @@ public void SecondsAgo(int seconds, string expected)
DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past);
}
+ [Theory]
+ [InlineData(0, "الآن")]
+ [InlineData(1, "في غضون ثانية واحدة من الآن")]
+ [InlineData(2, "في غضون ثانيتين من الآن")]
+ [InlineData(10, "في غضون 10 ثوان من الآن")]
+ [InlineData(24, "في غضون 24 ثانية من الآن")]
+ public void SecondsFromNow(int seconds, string expected)
+ {
+ DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future);
+ }
+
[Theory]
[InlineData(-2, "منذ عامين")]
[InlineData(-1, "العام السابق")]
@@ -67,5 +117,15 @@ public void YearsAgo(int years, string expected)
{
DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past);
}
+
+ [Theory]
+ [InlineData(1, "في غضون سنة واحدة من الآن")]
+ [InlineData(2, "في غضون سنتين من الآن")]
+ [InlineData(7, "في غضون 7 سنوات من الآن")]
+ [InlineData(55, "في غضون 55 سنة من الآن")]
+ public void YearsFromNow(int years, string expected)
+ {
+ DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future);
+ }
}
}
diff --git a/src/Humanizer.Tests/Localisation/ar/NumberToWordsTests.cs b/src/Humanizer.Tests/Localisation/ar/NumberToWordsTests.cs
index 33e82ae3e..d318ecf2b 100644
--- a/src/Humanizer.Tests/Localisation/ar/NumberToWordsTests.cs
+++ b/src/Humanizer.Tests/Localisation/ar/NumberToWordsTests.cs
@@ -19,5 +19,59 @@ public void ToWordsArabic(string expected, int number)
{
Assert.Equal(expected, number.ToWords());
}
+
+ [Theory]
+ [InlineData(0, "الصفر")]
+ [InlineData(1, "الأول")]
+ [InlineData(2, "الثاني")]
+ [InlineData(3, "الثالث")]
+ [InlineData(4, "الرابع")]
+ [InlineData(5, "الخامس")]
+ [InlineData(6, "السادس")]
+ [InlineData(7, "السابع")]
+ [InlineData(8, "الثامن")]
+ [InlineData(9, "التاسع")]
+ [InlineData(10, "العاشر")]
+ [InlineData(11, "الحادي عشر")]
+ [InlineData(12, "الثاني عشر")]
+ [InlineData(13, "الثالث عشر")]
+ [InlineData(14, "الرابع عشر")]
+ [InlineData(15, "الخامس عشر")]
+ [InlineData(16, "السادس عشر")]
+ [InlineData(17, "السابع عشر")]
+ [InlineData(18, "الثامن عشر")]
+ [InlineData(19, "التاسع عشر")]
+ [InlineData(20, "العشرون")]
+ [InlineData(21, "الحادي و العشرون")]
+ [InlineData(22, "الثاني و العشرون")]
+ [InlineData(30, "الثلاثون")]
+ [InlineData(40, "الأربعون")]
+ [InlineData(50, "الخمسون")]
+ [InlineData(60, "الستون")]
+ [InlineData(70, "السبعون")]
+ [InlineData(80, "الثمانون")]
+ [InlineData(90, "التسعون")]
+ [InlineData(95, "الخامس و التسعون")]
+ [InlineData(96, "السادس و التسعون")]
+ [InlineData(100, "المئة")]
+ [InlineData(120, "العشرون بعد المئة")]
+ [InlineData(121, "الحادي و العشرون بعد المئة")]
+ [InlineData(200, "المئتان")]
+ [InlineData(221, "الحادي و العشرون بعد المئتان")]
+ [InlineData(300, "الثلاث مئة")]
+ [InlineData(321, "الحادي و العشرون بعد الثلاث مئة")]
+ [InlineData(327, "السابع و العشرون بعد الثلاث مئة")]
+ [InlineData(1000, "الألف")]
+ [InlineData(1001, "الأول بعد الألف")]
+ [InlineData(1021, "الحادي و العشرون بعد الألف")]
+ [InlineData(10000, "العشرة آلاف")]
+ [InlineData(10121, "الحادي و العشرون بعد العشرة آلاف و مئة")]
+ [InlineData(100000, "المئة ألف")]
+ [InlineData(1000000, "المليون")]
+ [InlineData(1020135, "الخامس و الثلاثون بعد المليون و عشرون ألفاً و مئة")]
+ public void ToOrdinalWords(int number, string words)
+ {
+ Assert.Equal(words, number.ToOrdinalWords());
+ }
}
}
diff --git a/src/Humanizer.Tests/Localisation/es/NumberToWordsTests.cs b/src/Humanizer.Tests/Localisation/es/NumberToWordsTests.cs
index d8c96abab..5dcaf3a7d 100644
--- a/src/Humanizer.Tests/Localisation/es/NumberToWordsTests.cs
+++ b/src/Humanizer.Tests/Localisation/es/NumberToWordsTests.cs
@@ -12,33 +12,36 @@ public NumberToWordsTests() : base("es-ES") { }
[InlineData(1, "uno")]
[InlineData(10, "diez")]
[InlineData(11, "once")]
- [InlineData(122, "ciento veinte dos")]
+ [InlineData(122, "ciento veintidós")]
[InlineData(3501, "tres mil quinientos uno")]
[InlineData(100, "cien")]
[InlineData(1000, "mil")]
[InlineData(100000, "cien mil")]
- [InlineData(1000000, "millón")]
+ [InlineData(1000000, "un millón")]
[InlineData(10000000, "diez millones")]
[InlineData(100000000, "cien millones")]
[InlineData(1000000000, "mil millones")]
[InlineData(111, "ciento once")]
[InlineData(1111, "mil ciento once")]
[InlineData(111111, "ciento once mil ciento once")]
- [InlineData(1111111, "millón ciento once mil ciento once")]
+ [InlineData(1111111, "un millón ciento once mil ciento once")]
[InlineData(11111111, "once millones ciento once mil ciento once")]
[InlineData(111111111, "ciento once millones ciento once mil ciento once")]
+ [InlineData(1001111111, "mil millones un millón ciento once mil ciento once")]
[InlineData(1111111111, "mil millones ciento once millones ciento once mil ciento once")]
- [InlineData(123, "ciento veinte tres")]
+ [InlineData(123, "ciento veintitrés")]
[InlineData(1234, "mil doscientos treinta y cuatro")]
[InlineData(12345, "doce mil trescientos cuarenta y cinco")]
- [InlineData(123456, "ciento veinte tres mil cuatrocientos cincuenta y seis")]
- [InlineData(1234567, "millón doscientos treinta y cuatro mil quinientos sesenta y siete")]
+ [InlineData(123456, "ciento veintitrés mil cuatrocientos cincuenta y seis")]
+ [InlineData(1234567, "un millón doscientos treinta y cuatro mil quinientos sesenta y siete")]
[InlineData(12345678, "doce millones trescientos cuarenta y cinco mil seiscientos setenta y ocho")]
- [InlineData(123456789, "ciento veinte tres millones cuatrocientos cincuenta y seis mil setecientos ochenta y nueve")]
+ [InlineData(123456789, "ciento veintitrés millones cuatrocientos cincuenta y seis mil setecientos ochenta y nueve")]
[InlineData(1234567890, "mil millones doscientos treinta y cuatro millones quinientos sesenta y siete mil ochocientos noventa")]
[InlineData(15, "quince")]
[InlineData(16, "dieciséis")]
- [InlineData(25, "veinte cinco")]
+ [InlineData(20, "veinte")]
+ [InlineData(22, "veintidós")]
+ [InlineData(25, "veinticinco")]
[InlineData(35, "treinta y cinco")]
[InlineData(1999, "mil novecientos noventa y nueve")]
[InlineData(2014, "dos mil catorce")]
@@ -49,10 +52,15 @@ public void ToWords(int number, string expected)
}
[Theory]
- [InlineData(1, "primero", null)]
+ [InlineData(1, "primer", null)]
+ [InlineData(1, "primer", GrammaticalGender.Masculine)]
+ [InlineData(1, "primera", GrammaticalGender.Feminine)]
[InlineData(2, "segundo", GrammaticalGender.Masculine)]
[InlineData(2, "segunda", GrammaticalGender.Feminine)]
[InlineData(2, "segundo", GrammaticalGender.Neuter)]
+ [InlineData(3, "tercer", null)]
+ [InlineData(3, "tercer", GrammaticalGender.Masculine)]
+ [InlineData(3, "tercera", GrammaticalGender.Feminine)]
[InlineData(11, "once", null)]
public void ToOrdinalWords(int number, string words, GrammaticalGender gender)
{
diff --git a/src/Humanizer.Tests/Localisation/es/OrdinalizeTests.cs b/src/Humanizer.Tests/Localisation/es/OrdinalizeTests.cs
index c2c6f56bc..cf0e9a64d 100644
--- a/src/Humanizer.Tests/Localisation/es/OrdinalizeTests.cs
+++ b/src/Humanizer.Tests/Localisation/es/OrdinalizeTests.cs
@@ -12,18 +12,18 @@ public OrdinalizeTests()
[Theory]
[InlineData("0", "0")]
- [InlineData("1", "1º")]
- [InlineData("2", "2º")]
- [InlineData("3", "3º")]
- [InlineData("4", "4º")]
- [InlineData("5", "5º")]
- [InlineData("6", "6º")]
- [InlineData("23", "23º")]
- [InlineData("100", "100º")]
- [InlineData("101", "101º")]
- [InlineData("102", "102º")]
- [InlineData("103", "103º")]
- [InlineData("1001", "1001º")]
+ [InlineData("1", "1.º")]
+ [InlineData("2", "2.º")]
+ [InlineData("3", "3.º")]
+ [InlineData("4", "4.º")]
+ [InlineData("5", "5.º")]
+ [InlineData("6", "6.º")]
+ [InlineData("23", "23.º")]
+ [InlineData("100", "100.º")]
+ [InlineData("101", "101.º")]
+ [InlineData("102", "102.º")]
+ [InlineData("103", "103.º")]
+ [InlineData("1001", "1001.º")]
public void OrdinalizeString(string number, string ordinalized)
{
Assert.Equal(number.Ordinalize(GrammaticalGender.Masculine), ordinalized);
@@ -31,18 +31,18 @@ public void OrdinalizeString(string number, string ordinalized)
[Theory]
[InlineData("0", "0")]
- [InlineData("1", "1ª")]
- [InlineData("2", "2ª")]
- [InlineData("3", "3ª")]
- [InlineData("4", "4ª")]
- [InlineData("5", "5ª")]
- [InlineData("6", "6ª")]
- [InlineData("23", "23ª")]
- [InlineData("100", "100ª")]
- [InlineData("101", "101ª")]
- [InlineData("102", "102ª")]
- [InlineData("103", "103ª")]
- [InlineData("1001", "1001ª")]
+ [InlineData("1", "1.ª")]
+ [InlineData("2", "2.ª")]
+ [InlineData("3", "3.ª")]
+ [InlineData("4", "4.ª")]
+ [InlineData("5", "5.ª")]
+ [InlineData("6", "6.ª")]
+ [InlineData("23", "23.ª")]
+ [InlineData("100", "100.ª")]
+ [InlineData("101", "101.ª")]
+ [InlineData("102", "102.ª")]
+ [InlineData("103", "103.ª")]
+ [InlineData("1001", "1001.ª")]
public void OrdinalizeStringFeminine(string number, string ordinalized)
{
Assert.Equal(number.Ordinalize(GrammaticalGender.Feminine), ordinalized);
@@ -50,19 +50,19 @@ public void OrdinalizeStringFeminine(string number, string ordinalized)
[Theory]
[InlineData(0, "0")]
- [InlineData(1, "1º")]
- [InlineData(2, "2º")]
- [InlineData(3, "3º")]
- [InlineData(4, "4º")]
- [InlineData(5, "5º")]
- [InlineData(6, "6º")]
- [InlineData(10, "10º")]
- [InlineData(23, "23º")]
- [InlineData(100, "100º")]
- [InlineData(101, "101º")]
- [InlineData(102, "102º")]
- [InlineData(103, "103º")]
- [InlineData(1001, "1001º")]
+ [InlineData(1, "1.º")]
+ [InlineData(2, "2.º")]
+ [InlineData(3, "3.º")]
+ [InlineData(4, "4.º")]
+ [InlineData(5, "5.º")]
+ [InlineData(6, "6.º")]
+ [InlineData(10, "10.º")]
+ [InlineData(23, "23.º")]
+ [InlineData(100, "100.º")]
+ [InlineData(101, "101.º")]
+ [InlineData(102, "102.º")]
+ [InlineData(103, "103.º")]
+ [InlineData(1001, "1001.º")]
public void OrdinalizeNumber(int number, string ordinalized)
{
Assert.Equal(number.Ordinalize(GrammaticalGender.Masculine), ordinalized);
@@ -70,19 +70,19 @@ public void OrdinalizeNumber(int number, string ordinalized)
[Theory]
[InlineData(0, "0")]
- [InlineData(1, "1ª")]
- [InlineData(2, "2ª")]
- [InlineData(3, "3ª")]
- [InlineData(4, "4ª")]
- [InlineData(5, "5ª")]
- [InlineData(6, "6ª")]
- [InlineData(10, "10ª")]
- [InlineData(23, "23ª")]
- [InlineData(100, "100ª")]
- [InlineData(101, "101ª")]
- [InlineData(102, "102ª")]
- [InlineData(103, "103ª")]
- [InlineData(1001, "1001ª")]
+ [InlineData(1, "1.ª")]
+ [InlineData(2, "2.ª")]
+ [InlineData(3, "3.ª")]
+ [InlineData(4, "4.ª")]
+ [InlineData(5, "5.ª")]
+ [InlineData(6, "6.ª")]
+ [InlineData(10, "10.ª")]
+ [InlineData(23, "23.ª")]
+ [InlineData(100, "100.ª")]
+ [InlineData(101, "101.ª")]
+ [InlineData(102, "102.ª")]
+ [InlineData(103, "103.ª")]
+ [InlineData(1001, "1001.ª")]
public void OrdinalizeNumberFeminine(int number, string ordinalized)
{
Assert.Equal(number.Ordinalize(GrammaticalGender.Feminine), ordinalized);
diff --git a/src/Humanizer.Tests/Localisation/ja/DateHumanizeTests.cs b/src/Humanizer.Tests/Localisation/ja/DateHumanizeTests.cs
new file mode 100644
index 000000000..a36d73c17
--- /dev/null
+++ b/src/Humanizer.Tests/Localisation/ja/DateHumanizeTests.cs
@@ -0,0 +1,113 @@
+using Humanizer.Localisation;
+using Xunit;
+using Xunit.Extensions;
+
+namespace Humanizer.Tests.Localisation.ja
+{
+ public class DateHumanizeTests : AmbientCulture
+ {
+ public DateHumanizeTests() : base("ja") { }
+
+ [Theory]
+ [InlineData(1, "1 秒前")]
+ [InlineData(2, "2 秒前")]
+ public void SecondsAgo(int seconds, string expected)
+ {
+ DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past);
+ }
+
+ [Theory]
+ [InlineData(1, "1 秒後")]
+ [InlineData(2, "2 秒後")]
+ public void SecondsFromNow(int seconds, string expected)
+ {
+ DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future);
+ }
+
+ [Theory]
+ [InlineData(1, "1 分前")]
+ [InlineData(2, "2 分前")]
+ public void MinutesAgo(int minutes, string expected)
+ {
+ DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past);
+ }
+
+ [Theory]
+ [InlineData(1, "1 分後")]
+ [InlineData(2, "2 分後")]
+ public void MinutesFromNow(int minutes, string expected)
+ {
+ DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future);
+ }
+
+ [Theory]
+ [InlineData(1, "1 時間前")]
+ [InlineData(2, "2 時間前")]
+ public void HoursAgo(int hours, string expected)
+ {
+ DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past);
+ }
+
+ [Theory]
+ [InlineData(1, "1 時間後")]
+ [InlineData(2, "2 時間後")]
+ public void HoursFromNow(int hours, string expected)
+ {
+ DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future);
+ }
+
+ [Theory]
+ [InlineData(1, "昨日")]
+ [InlineData(2, "2 日前")]
+ public void DaysAgo(int days, string expected)
+ {
+ DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past);
+ }
+
+ [Theory]
+ [InlineData(1, "明日")]
+ [InlineData(2, "2 日後")]
+ public void DaysFromNow(int days, string expected)
+ {
+ DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future);
+ }
+
+ [Theory]
+ [InlineData(1, "先月")]
+ [InlineData(2, "2 か月前")]
+ public void MonthsAgo(int months, string expected)
+ {
+ DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past);
+ }
+
+ [Theory]
+ [InlineData(1, "来月")]
+ [InlineData(2, "2 か月後")]
+ public void MonthsFromNow(int months, string expected)
+ {
+ DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future);
+ }
+
+ [Theory]
+ [InlineData(1, "去年")]
+ [InlineData(2, "2 年前")]
+ public void YearsAgo(int years, string expected)
+ {
+ DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past);
+ }
+
+ [Theory]
+ [InlineData(1, "来年")]
+ [InlineData(2, "2 年後")]
+ public void YearsFromNow(int years, string expected)
+ {
+ DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future);
+ }
+
+ [Fact]
+ public void Now()
+ {
+ DateHumanize.Verify("今", 0, TimeUnit.Day, Tense.Past);
+ }
+ }
+}
diff --git a/src/Humanizer.Tests/Localisation/ja/TimeSpanHumanizeTests.cs b/src/Humanizer.Tests/Localisation/ja/TimeSpanHumanizeTests.cs
new file mode 100644
index 000000000..136318e5f
--- /dev/null
+++ b/src/Humanizer.Tests/Localisation/ja/TimeSpanHumanizeTests.cs
@@ -0,0 +1,65 @@
+using System;
+using Xunit;
+using Xunit.Extensions;
+
+namespace Humanizer.Tests.Localisation.ja
+{
+ public class TimeSpanHumanizeTests : AmbientCulture
+ {
+ public TimeSpanHumanizeTests() : base("ja") { }
+
+ [Theory]
+ [InlineData(7, "1 週間")]
+ [InlineData(14, "2 週間")]
+ public void Weeks(int days, string expected)
+ {
+ Assert.Equal(expected, TimeSpan.FromDays(days).Humanize());
+ }
+
+ [Theory]
+ [InlineData(1, "1 日")]
+ [InlineData(2, "2 日")]
+ public void Days(int days, string expected)
+ {
+ Assert.Equal(expected, TimeSpan.FromDays(days).Humanize());
+ }
+
+ [Theory]
+ [InlineData(1, "1 時間")]
+ [InlineData(2, "2 時間")]
+ public void Hours(int hours, string expected)
+ {
+ Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize());
+ }
+
+ [Theory]
+ [InlineData(1, "1 分")]
+ [InlineData(2, "2 分")]
+ public void Minutes(int minutes, string expected)
+ {
+ Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize());
+ }
+
+ [Theory]
+ [InlineData(1, "1 秒")]
+ [InlineData(2, "2 秒")]
+ public void Seconds(int seconds, string expected)
+ {
+ Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize());
+ }
+
+ [Theory]
+ [InlineData(1, "1 ミリ秒")]
+ [InlineData(2, "2 ミリ秒")]
+ public void Milliseconds(int milliseconds, string expected)
+ {
+ Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize());
+ }
+
+ [Fact]
+ public void NoTime()
+ {
+ Assert.Equal("0 秒", TimeSpan.Zero.Humanize());
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Humanizer.Tests/Localisation/ru-RU/NumberToWordsTests.cs b/src/Humanizer.Tests/Localisation/ru-RU/NumberToWordsTests.cs
index d5bf08d36..c0e6b16d5 100644
--- a/src/Humanizer.Tests/Localisation/ru-RU/NumberToWordsTests.cs
+++ b/src/Humanizer.Tests/Localisation/ru-RU/NumberToWordsTests.cs
@@ -99,6 +99,8 @@ public void ToWordsWithGender(int number, string expected, GrammaticalGender gen
[InlineData(80, "восьмидесятый")]
[InlineData(90, "девяностый")]
[InlineData(100, "сотый")]
+ [InlineData(101, "сто первый")]
+ [InlineData(140, "сто сороковой")]
[InlineData(200, "двухсотый")]
[InlineData(300, "трёхсотый")]
[InlineData(400, "четырёхсотый")]
@@ -108,16 +110,22 @@ public void ToWordsWithGender(int number, string expected, GrammaticalGender gen
[InlineData(800, "восьмисотый")]
[InlineData(900, "девятисотый")]
[InlineData(1000, "тысячный")]
+ [InlineData(1001, "одна тысяча первый")]
+ [InlineData(1040, "одна тысяча сороковой")]
[InlineData(2000, "двухтысячный")]
[InlineData(3000, "трёхтысячный")]
[InlineData(4000, "четырёхтысячный")]
[InlineData(5000, "пятитысячный")]
[InlineData(10000, "десятитысячный")]
+ [InlineData(21000, "двадцатиоднатысячный")]
[InlineData(100000, "стотысячный")]
+ [InlineData(200000, "двухсоттысячный")]
[InlineData(1000000, "миллионный")]
[InlineData(2000000, "двухмиллионный")]
[InlineData(10000000, "десятимиллионный")]
+ [InlineData(21000000, "двадцатиодномиллионный")]
[InlineData(100000000, "стомиллионный")]
+ [InlineData(230000000, "двухсоттридцатимиллионный")]
[InlineData(1000000000, "миллиардный")]
[InlineData(2000000000, "двухмиллиардный")]
[InlineData(122, "сто двадцать второй")]
@@ -125,11 +133,15 @@ public void ToWordsWithGender(int number, string expected, GrammaticalGender gen
[InlineData(111, "сто одиннадцатый")]
[InlineData(1112, "одна тысяча сто двенадцатый")]
[InlineData(11213, "одиннадцать тысячь двести тринадцатый")]
+ [InlineData(101000, "стооднатысячный")]
[InlineData(121314, "сто двадцать одна тысяча триста четырнадцатый")]
[InlineData(2132415, "два миллиона сто тридцать две тысячи четыреста пятнадцатый")]
[InlineData(12345516, "двенадцать миллионов триста сорок пять тысячь пятьсот шестнадцатый")]
[InlineData(751633617, "семьсот пятьдесят один миллион шестьсот тридцать три тысячи шестьсот семнадцатый")]
[InlineData(1111111118, "один миллиард сто одиннадцать миллионов сто одиннадцать тысячь сто восемнадцатый")]
+ [InlineData(1111111000, "один миллиард сто одиннадцать миллионов стоодиннадцатитысячный")]
+ [InlineData(1234567000, "один миллиард двести тридцать четыре миллиона пятисотшестидесятисемитысячный")]
+ [InlineData(2000000000, "двухмиллиардный")]
[InlineData(-751633617, "минус семьсот пятьдесят один миллион шестьсот тридцать три тысячи шестьсот семнадцатый")]
public void ToOrdinalWords(int number, string expected)
{
diff --git a/src/Humanizer.Tests/Localisation/sr-Latn/DateHumanizeTests.cs b/src/Humanizer.Tests/Localisation/sr-Latn/DateHumanizeTests.cs
new file mode 100644
index 000000000..85c5dced5
--- /dev/null
+++ b/src/Humanizer.Tests/Localisation/sr-Latn/DateHumanizeTests.cs
@@ -0,0 +1,140 @@
+using Humanizer.Localisation;
+using Xunit;
+using Xunit.Extensions;
+
+namespace Humanizer.Tests.Localisation.srLatn
+{
+ public class DateHumanizeDefaultStrategyTests : AmbientCulture
+ {
+ public DateHumanizeDefaultStrategyTests()
+ : base("sr-Latn")
+ {
+ }
+
+ [Theory]
+ [InlineData(1, "pre sekund")]
+ [InlineData(10, "pre 10 sekundi")]
+ [InlineData(59, "pre 59 sekundi")]
+ [InlineData(60, "pre minut")]
+ public void SecondsAgo(int seconds, string expected)
+ {
+ DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past);
+ }
+
+ [Theory]
+ [InlineData(1, "za sekund")]
+ [InlineData(10, "za 10 sekundi")]
+ [InlineData(59, "za 59 sekundi")]
+ [InlineData(60, "za minut")]
+ public void SecondsFromNow(int seconds, string expected)
+ {
+ DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future);
+ }
+
+ [Theory]
+ [InlineData(1, "pre minut")]
+ [InlineData(10, "pre 10 minuta")]
+ [InlineData(44, "pre 44 minuta")]
+ [InlineData(45, "pre sat vremena")]
+ [InlineData(119, "pre sat vremena")]
+ [InlineData(120, "pre 2 sata")]
+ public void MinutesAgo(int minutes, string expected)
+ {
+ DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past);
+ }
+
+ [Theory]
+ [InlineData(1, "za minut")]
+ [InlineData(10, "za 10 minuta")]
+ [InlineData(44, "za 44 minuta")]
+ [InlineData(45, "za sat vremena")]
+ [InlineData(119, "za sat vremena")]
+ [InlineData(120, "za 2 sata")]
+ public void MinutesFromNow(int minutes, string expected)
+ {
+ DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future);
+ }
+
+ [Theory]
+ [InlineData(1, "pre sat vremena")]
+ [InlineData(10, "pre 10 sati")]
+ [InlineData(23, "pre 23 sata")]
+ [InlineData(24, "juče")]
+ public void HoursAgo(int hours, string expected)
+ {
+ DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past);
+ }
+
+ [Theory]
+ [InlineData(1, "za sat vremena")]
+ [InlineData(10, "za 10 sati")]
+ [InlineData(23, "za 23 sata")]
+ [InlineData(24, "sutra")]
+ public void HoursFromNow(int hours, string expected)
+ {
+ DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future);
+ }
+
+ [Theory]
+ [InlineData(1, "juče")]
+ [InlineData(10, "pre 10 dana")]
+ [InlineData(28, "pre 28 dana")]
+ [InlineData(32, "pre mesec dana")]
+ public void DaysAgo(int days, string expected)
+ {
+ DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past);
+ }
+
+ [Theory]
+ [InlineData(1, "sutra")]
+ [InlineData(10, "za 10 dana")]
+ [InlineData(28, "za 28 dana")]
+ [InlineData(32, "za mesec dana")]
+ public void DaysFromNow(int days, string expected)
+ {
+ DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future);
+ }
+
+ [Theory]
+ [InlineData(1, "pre mesec dana")]
+ [InlineData(10, "pre 10 meseci")]
+ [InlineData(11, "pre 11 meseci")]
+ [InlineData(12, "pre godinu dana")]
+ public void MonthsAgo(int months, string expected)
+ {
+ DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past);
+ }
+
+ [Theory]
+ [InlineData(1, "za mesec dana")]
+ [InlineData(10, "za 10 meseci")]
+ [InlineData(11, "za 11 meseci")]
+ [InlineData(12, "za godinu dana")]
+ public void MonthsFromNow(int months, string expected)
+ {
+ DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future);
+ }
+
+ [Theory]
+ [InlineData(1, "pre godinu dana")]
+ [InlineData(2, "pre 2 godine")]
+ public void YearsAgo(int years, string expected)
+ {
+ DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past);
+ }
+
+ [Theory]
+ [InlineData(1, "za godinu dana")]
+ [InlineData(2, "za 2 godine")]
+ public void YearsFromNow(int years, string expected)
+ {
+ DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future);
+ }
+
+ [Fact]
+ public void Now()
+ {
+ DateHumanize.Verify("sada", 0, TimeUnit.Year, Tense.Future);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Humanizer.Tests/Localisation/sr-Latn/TimeSpanHumanizeTests.cs b/src/Humanizer.Tests/Localisation/sr-Latn/TimeSpanHumanizeTests.cs
new file mode 100644
index 000000000..b60181297
--- /dev/null
+++ b/src/Humanizer.Tests/Localisation/sr-Latn/TimeSpanHumanizeTests.cs
@@ -0,0 +1,118 @@
+using System;
+using Xunit;
+using Xunit.Extensions;
+
+namespace Humanizer.Tests.Localisation.srLatn
+{
+ public class TimeSpanHumanizeTests : AmbientCulture
+ {
+ public TimeSpanHumanizeTests() : base("sr-Latn") { }
+
+ [Theory]
+ [InlineData(35, "5 nedelja")]
+ [InlineData(14, "2 nedelje")]
+ [InlineData(7, "1 nedelja")]
+ public void Weeks(int days, string expected)
+ {
+ var actual = TimeSpan.FromDays(days).Humanize();
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory]
+ [InlineData(6, "6 dana")]
+ [InlineData(2, "2 dana")]
+ [InlineData(1, "1 dan")]
+ public void Days(int days, string expected)
+ {
+ var actual = TimeSpan.FromDays(days).Humanize();
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory]
+ [InlineData(5, "5 sati")]
+ [InlineData(2, "2 sata")]
+ [InlineData(1, "1 sat")]
+ public void Hours(int hours, string expected)
+ {
+ var actual = TimeSpan.FromHours(hours).Humanize();
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory]
+ [InlineData(2, "2 minuta")]
+ [InlineData(1, "1 minut")]
+ public void Minutes(int minutes, string expected)
+ {
+ var actual = TimeSpan.FromMinutes(minutes).Humanize();
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory]
+ [InlineData(135, "2 minuta")]
+ [InlineData(60, "1 minut")]
+ [InlineData(5, "5 sekundi")]
+ [InlineData(3, "3 sekunde")]
+ [InlineData(2, "2 sekunde")]
+ [InlineData(1, "1 sekunda")]
+ public void Seconds(int seconds, string expected)
+ {
+ var actual = TimeSpan.FromSeconds(seconds).Humanize();
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory]
+ [InlineData(2500, "2 sekunde")]
+ [InlineData(1400, "1 sekunda")]
+ [InlineData(2, "2 milisekunde")]
+ [InlineData(1, "1 milisekunda")]
+ public void Milliseconds(int ms, string expected)
+ {
+ var actual = TimeSpan.FromMilliseconds(ms).Humanize();
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory]
+ [InlineData(0, 3, "bez proteklog vremena")]
+ [InlineData(0, 2, "bez proteklog vremena")]
+ [InlineData(10, 2, "10 milisekundi")]
+ [InlineData(1400, 2, "1 sekunda, 400 milisekundi")]
+ [InlineData(2500, 2, "2 sekunde, 500 milisekundi")]
+ [InlineData(120000, 2, "2 minuta")]
+ [InlineData(62000, 2, "1 minut, 2 sekunde")]
+ [InlineData(62020, 2, "1 minut, 2 sekunde")]
+ [InlineData(62020, 3, "1 minut, 2 sekunde, 20 milisekundi")]
+ [InlineData(3600020, 4, "1 sat, 20 milisekundi")]
+ [InlineData(3600020, 3, "1 sat, 20 milisekundi")]
+ [InlineData(3600020, 2, "1 sat, 20 milisekundi")]
+ [InlineData(3600020, 1, "1 sat")]
+ [InlineData(3603001, 2, "1 sat, 3 sekunde")]
+ [InlineData(3603001, 3, "1 sat, 3 sekunde, 1 milisekunda")]
+ [InlineData(86400000, 3, "1 dan")]
+ [InlineData(86400000, 2, "1 dan")]
+ [InlineData(86400000, 1, "1 dan")]
+ [InlineData(86401000, 1, "1 dan")]
+ [InlineData(86401000, 2, "1 dan, 1 sekunda")]
+ [InlineData(86401200, 2, "1 dan, 1 sekunda")]
+ [InlineData(86401200, 3, "1 dan, 1 sekunda, 200 milisekundi")]
+ [InlineData(1296000000, 1, "2 nedelje")]
+ [InlineData(1296000000, 2, "2 nedelje, 1 dan")]
+ [InlineData(1299600000, 2, "2 nedelje, 1 dan")]
+ [InlineData(1299600000, 3, "2 nedelje, 1 dan, 1 sat")]
+ [InlineData(1299630020, 3, "2 nedelje, 1 dan, 1 sat")]
+ [InlineData(1299630020, 4, "2 nedelje, 1 dan, 1 sat, 30 sekundi")]
+ [InlineData(1299630020, 5, "2 nedelje, 1 dan, 1 sat, 30 sekundi, 20 milisekundi")]
+ public void TimeSpanWithPrecesion(int milliseconds, int precesion, string expected)
+ {
+ var actual = TimeSpan.FromMilliseconds(milliseconds).Humanize(precesion);
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact]
+ public void NoTime()
+ {
+ var noTime = TimeSpan.Zero;
+ var actual = noTime.Humanize();
+ Assert.Equal("bez proteklog vremena", actual);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Humanizer.Tests/Localisation/sr/DateHumanizeTests.cs b/src/Humanizer.Tests/Localisation/sr/DateHumanizeTests.cs
new file mode 100644
index 000000000..69c95c1d1
--- /dev/null
+++ b/src/Humanizer.Tests/Localisation/sr/DateHumanizeTests.cs
@@ -0,0 +1,140 @@
+using Humanizer.Localisation;
+using Xunit;
+using Xunit.Extensions;
+
+namespace Humanizer.Tests.Localisation.sr
+{
+ public class DateHumanizeDefaultStrategyTests : AmbientCulture
+ {
+ public DateHumanizeDefaultStrategyTests()
+ : base("sr")
+ {
+ }
+
+ [Theory]
+ [InlineData(1, "пре секунд")]
+ [InlineData(10, "пре 10 секунди")]
+ [InlineData(59, "пре 59 секунди")]
+ [InlineData(60, "пре минут")]
+ public void SecondsAgo(int seconds, string expected)
+ {
+ DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past);
+ }
+
+ [Theory]
+ [InlineData(1, "за секунд")]
+ [InlineData(10, "за 10 секунди")]
+ [InlineData(59, "за 59 секунди")]
+ [InlineData(60, "за минут")]
+ public void SecondsFromNow(int seconds, string expected)
+ {
+ DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future);
+ }
+
+ [Theory]
+ [InlineData(1, "пре минут")]
+ [InlineData(10, "пре 10 минута")]
+ [InlineData(44, "пре 44 минута")]
+ [InlineData(45, "пре сат времена")]
+ [InlineData(119, "пре сат времена")]
+ [InlineData(120, "пре 2 сата")]
+ public void MinutesAgo(int minutes, string expected)
+ {
+ DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past);
+ }
+
+ [Theory]
+ [InlineData(1, "за минут")]
+ [InlineData(10, "за 10 минута")]
+ [InlineData(44, "за 44 минута")]
+ [InlineData(45, "за сат времена")]
+ [InlineData(119, "за сат времена")]
+ [InlineData(120, "за 2 сата")]
+ public void MinutesFromNow(int minutes, string expected)
+ {
+ DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future);
+ }
+
+ [Theory]
+ [InlineData(1, "пре сат времена")]
+ [InlineData(10, "пре 10 сати")]
+ [InlineData(23, "пре 23 сата")]
+ [InlineData(24, "јуче")]
+ public void HoursAgo(int hours, string expected)
+ {
+ DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past);
+ }
+
+ [Theory]
+ [InlineData(1, "за сат времена")]
+ [InlineData(10, "за 10 сати")]
+ [InlineData(23, "за 23 сата")]
+ [InlineData(24, "сутра")]
+ public void HoursFromNow(int hours, string expected)
+ {
+ DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future);
+ }
+
+ [Theory]
+ [InlineData(1, "јуче")]
+ [InlineData(10, "пре 10 дана")]
+ [InlineData(28, "пре 28 дана")]
+ [InlineData(32, "пре месец дана")]
+ public void DaysAgo(int days, string expected)
+ {
+ DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past);
+ }
+
+ [Theory]
+ [InlineData(1, "сутра")]
+ [InlineData(10, "за 10 дана")]
+ [InlineData(28, "за 28 дана")]
+ [InlineData(32, "за месец дана")]
+ public void DaysFromNow(int days, string expected)
+ {
+ DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future);
+ }
+
+ [Theory]
+ [InlineData(1, "пре месец дана")]
+ [InlineData(10, "пре 10 месеци")]
+ [InlineData(11, "пре 11 месеци")]
+ [InlineData(12, "пре годину дана")]
+ public void MonthsAgo(int months, string expected)
+ {
+ DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past);
+ }
+
+ [Theory]
+ [InlineData(1, "за месец дана")]
+ [InlineData(10, "за 10 месеци")]
+ [InlineData(11, "за 11 месеци")]
+ [InlineData(12, "за годину дана")]
+ public void MonthsFromNow(int months, string expected)
+ {
+ DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future);
+ }
+
+ [Theory]
+ [InlineData(1, "пре годину дана")]
+ [InlineData(2, "пре 2 године")]
+ public void YearsAgo(int years, string expected)
+ {
+ DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past);
+ }
+
+ [Theory]
+ [InlineData(1, "за годину дана")]
+ [InlineData(2, "за 2 године")]
+ public void YearsFromNow(int years, string expected)
+ {
+ DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future);
+ }
+
+ [Fact]
+ public void Now()
+ {
+ DateHumanize.Verify("сада", 0, TimeUnit.Year, Tense.Future);
+ }
+ }
+}
diff --git a/src/Humanizer.Tests/Localisation/sr/TimeSpanHumanizeTests.cs b/src/Humanizer.Tests/Localisation/sr/TimeSpanHumanizeTests.cs
new file mode 100644
index 000000000..cd8b5fc73
--- /dev/null
+++ b/src/Humanizer.Tests/Localisation/sr/TimeSpanHumanizeTests.cs
@@ -0,0 +1,118 @@
+using System;
+using Xunit;
+using Xunit.Extensions;
+
+namespace Humanizer.Tests.Localisation.srCyrl
+{
+ public class TimeSpanHumanizeTests : AmbientCulture
+ {
+ public TimeSpanHumanizeTests() : base("sr") { }
+
+ [Theory]
+ [InlineData(35, "5 недеља")]
+ [InlineData(14, "2 недеље")]
+ [InlineData(7, "1 недеља")]
+ public void Weeks(int days, string expected)
+ {
+ var actual = TimeSpan.FromDays(days).Humanize();
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory]
+ [InlineData(6, "6 дана")]
+ [InlineData(2, "2 дана")]
+ [InlineData(1, "1 дан")]
+ public void Days(int days, string expected)
+ {
+ var actual = TimeSpan.FromDays(days).Humanize();
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory]
+ [InlineData(5, "5 сати")]
+ [InlineData(2, "2 сата")]
+ [InlineData(1, "1 сат")]
+ public void Hours(int hours, string expected)
+ {
+ var actual = TimeSpan.FromHours(hours).Humanize();
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory]
+ [InlineData(2, "2 минута")]
+ [InlineData(1, "1 минут")]
+ public void Minutes(int minutes, string expected)
+ {
+ var actual = TimeSpan.FromMinutes(minutes).Humanize();
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory]
+ [InlineData(135, "2 минута")]
+ [InlineData(60, "1 минут")]
+ [InlineData(5, "5 секунди")]
+ [InlineData(3, "3 секунде")]
+ [InlineData(2, "2 секунде")]
+ [InlineData(1, "1 секунда")]
+ public void Seconds(int seconds, string expected)
+ {
+ var actual = TimeSpan.FromSeconds(seconds).Humanize();
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory]
+ [InlineData(2500, "2 секунде")]
+ [InlineData(1400, "1 секунда")]
+ [InlineData(2, "2 милисекунде")]
+ [InlineData(1, "1 милисекунда")]
+ public void Milliseconds(int ms, string expected)
+ {
+ var actual = TimeSpan.FromMilliseconds(ms).Humanize();
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory]
+ [InlineData(0, 3, "без протеклог времена")]
+ [InlineData(0, 2, "без протеклог времена")]
+ [InlineData(10, 2, "10 милисекунди")]
+ [InlineData(1400, 2, "1 секунда, 400 милисекунди")]
+ [InlineData(2500, 2, "2 секунде, 500 милисекунди")]
+ [InlineData(120000, 2, "2 минута")]
+ [InlineData(62000, 2, "1 минут, 2 секунде")]
+ [InlineData(62020, 2, "1 минут, 2 секунде")]
+ [InlineData(62020, 3, "1 минут, 2 секунде, 20 милисекунди")]
+ [InlineData(3600020, 4, "1 сат, 20 милисекунди")]
+ [InlineData(3600020, 3, "1 сат, 20 милисекунди")]
+ [InlineData(3600020, 2, "1 сат, 20 милисекунди")]
+ [InlineData(3600020, 1, "1 сат")]
+ [InlineData(3603001, 2, "1 сат, 3 секунде")]
+ [InlineData(3603001, 3, "1 сат, 3 секунде, 1 милисекунда")]
+ [InlineData(86400000, 3, "1 дан")]
+ [InlineData(86400000, 2, "1 дан")]
+ [InlineData(86400000, 1, "1 дан")]
+ [InlineData(86401000, 1, "1 дан")]
+ [InlineData(86401000, 2, "1 дан, 1 секунда")]
+ [InlineData(86401200, 2, "1 дан, 1 секунда")]
+ [InlineData(86401200, 3, "1 дан, 1 секунда, 200 милисекунди")]
+ [InlineData(1296000000, 1, "2 недеље")]
+ [InlineData(1296000000, 2, "2 недеље, 1 дан")]
+ [InlineData(1299600000, 2, "2 недеље, 1 дан")]
+ [InlineData(1299600000, 3, "2 недеље, 1 дан, 1 сат")]
+ [InlineData(1299630020, 3, "2 недеље, 1 дан, 1 сат")]
+ [InlineData(1299630020, 4, "2 недеље, 1 дан, 1 сат, 30 секунди")]
+ [InlineData(1299630020, 5, "2 недеље, 1 дан, 1 сат, 30 секунди, 20 милисекунди")]
+ public void TimeSpanWithPrecesion(int milliseconds, int precesion, string expected)
+ {
+ var actual = TimeSpan.FromMilliseconds(milliseconds).Humanize(precesion);
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact]
+ public void NoTime()
+ {
+ var noTime = TimeSpan.Zero;
+ var actual = noTime.Humanize();
+ Assert.Equal("без протеклог времена", actual);
+ }
+ }
+}
diff --git a/src/Humanizer.nuspec b/src/Humanizer.nuspec
index a4eaf0fd7..2bd8f217a 100644
--- a/src/Humanizer.nuspec
+++ b/src/Humanizer.nuspec
@@ -7,6 +7,7 @@
Mehdi Khalili
Mehdi Khalili
https://github.com/MehdiK/Humanizer
+ https://raw.github.com/MehdiK/Humanizer/master/logo.png
false
Humanizer meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities
Copyright 2012-2014 Mehdi Khalili
diff --git a/src/Humanizer.ruleset b/src/Humanizer.ruleset
new file mode 100644
index 000000000..3af068ece
--- /dev/null
+++ b/src/Humanizer.ruleset
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Humanizer.sln b/src/Humanizer.sln
index 3428859ae..e5d98557f 100644
--- a/src/Humanizer.sln
+++ b/src/Humanizer.sln
@@ -16,22 +16,37 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
..\release_notes.md = ..\release_notes.md
EndProjectSection
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{97AAE24D-0488-42AE-A585-86D882F23D5F}"
+ ProjectSection(SolutionItems) = preProject
+ ..\build.cmd = ..\build.cmd
+ ..\build.config = ..\build.config
+ ..\build.proj = ..\build.proj
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
+ Verify|Any CPU = Verify|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F886A8DA-3EFC-4A89-91DD-06FAF13DA172}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F886A8DA-3EFC-4A89-91DD-06FAF13DA172}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F886A8DA-3EFC-4A89-91DD-06FAF13DA172}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F886A8DA-3EFC-4A89-91DD-06FAF13DA172}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F886A8DA-3EFC-4A89-91DD-06FAF13DA172}.Verify|Any CPU.ActiveCfg = Verify|Any CPU
+ {F886A8DA-3EFC-4A89-91DD-06FAF13DA172}.Verify|Any CPU.Build.0 = Verify|Any CPU
{511A7984-F455-4A6E-ADB9-9CAAC47EA079}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{511A7984-F455-4A6E-ADB9-9CAAC47EA079}.Debug|Any CPU.Build.0 = Debug|Any CPU
{511A7984-F455-4A6E-ADB9-9CAAC47EA079}.Release|Any CPU.ActiveCfg = Release|Any CPU
{511A7984-F455-4A6E-ADB9-9CAAC47EA079}.Release|Any CPU.Build.0 = Release|Any CPU
+ {511A7984-F455-4A6E-ADB9-9CAAC47EA079}.Verify|Any CPU.ActiveCfg = Verify|Any CPU
+ {511A7984-F455-4A6E-ADB9-9CAAC47EA079}.Verify|Any CPU.Build.0 = Verify|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {97AAE24D-0488-42AE-A585-86D882F23D5F} = {4779A7C9-9ED8-4146-A158-FBE0B1BE09D9}
+ EndGlobalSection
EndGlobal
diff --git a/src/Humanizer/Bytes/ByteSize.cs b/src/Humanizer/Bytes/ByteSize.cs
index 934149054..253f749d5 100644
--- a/src/Humanizer/Bytes/ByteSize.cs
+++ b/src/Humanizer/Bytes/ByteSize.cs
@@ -22,12 +22,12 @@
using System;
-// ReSharper disable CSharpWarnings::CS1591
namespace Humanizer.Bytes
{
///
/// Represents a byte size value.
///
+#pragma warning disable 1591
public struct ByteSize : IComparable, IEquatable
{
public static readonly ByteSize MinValue = FromBits(long.MinValue);
@@ -385,4 +385,4 @@ public static ByteSize Parse(string s)
}
}
}
-// ReSharper restore CSharpWarnings::CS1591
+#pragma warning restore 1591
diff --git a/src/Humanizer/Configuration/Configurator.cs b/src/Humanizer/Configuration/Configurator.cs
index 4d7bfc00e..b30cd8378 100644
--- a/src/Humanizer/Configuration/Configurator.cs
+++ b/src/Humanizer/Configuration/Configurator.cs
@@ -20,7 +20,8 @@ public static class Configurator
{ "he", () => new HebrewFormatter() },
{ "sk", () => new CzechSlovakPolishFormatter() },
{ "cs", () => new CzechSlovakPolishFormatter() },
- { "pl", () => new CzechSlovakPolishFormatter() }
+ { "pl", () => new CzechSlovakPolishFormatter() },
+ { "sr", () => new SerbianFormatter() }
};
private static IDateTimeHumanizeStrategy _dateTimeHumanizeStrategy = new DefaultDateTimeHumanizeStrategy();
@@ -40,6 +41,9 @@ public static IFormatter Formatter
}
}
+ ///
+ /// The strategy to be used for DateTime.Humanize
+ ///
public static IDateTimeHumanizeStrategy DateTimeHumanizeStrategy
{
get { return _dateTimeHumanizeStrategy; }
diff --git a/src/Humanizer/DateTimeHumanizeStrategy/DefaultDateTimeHumanizeStrategy.cs b/src/Humanizer/DateTimeHumanizeStrategy/DefaultDateTimeHumanizeStrategy.cs
index 751a4492d..3198cf9c1 100644
--- a/src/Humanizer/DateTimeHumanizeStrategy/DefaultDateTimeHumanizeStrategy.cs
+++ b/src/Humanizer/DateTimeHumanizeStrategy/DefaultDateTimeHumanizeStrategy.cs
@@ -5,7 +5,7 @@
namespace Humanizer.DateTimeHumanizeStrategy
{
///
- /// The default distance of time in works calculator
+ /// The default 'distance of time' -> words calculator.
///
public class DefaultDateTimeHumanizeStrategy : IDateTimeHumanizeStrategy
{
diff --git a/src/Humanizer/DateTimeHumanizeStrategy/IDateTimeHumanizeStrategy.cs b/src/Humanizer/DateTimeHumanizeStrategy/IDateTimeHumanizeStrategy.cs
index 9bff4fe4a..5aedd233b 100644
--- a/src/Humanizer/DateTimeHumanizeStrategy/IDateTimeHumanizeStrategy.cs
+++ b/src/Humanizer/DateTimeHumanizeStrategy/IDateTimeHumanizeStrategy.cs
@@ -2,8 +2,14 @@
namespace Humanizer.DateTimeHumanizeStrategy
{
+ ///
+ /// Implement this interface to create a new strategy for DateTime.Humanize and hook it in the Configurator.DateTimeHumanizeStrategy
+ ///
public interface IDateTimeHumanizeStrategy
{
+ ///
+ /// Calculates the distance of time in words between two provided dates used for DateTime.Humanize
+ ///
string Humanize(DateTime input, DateTime comparisonBase);
}
}
\ No newline at end of file
diff --git a/src/Humanizer/EnumDehumanizeExtensions.cs b/src/Humanizer/EnumDehumanizeExtensions.cs
index 264e5da5b..c6f1a86b2 100644
--- a/src/Humanizer/EnumDehumanizeExtensions.cs
+++ b/src/Humanizer/EnumDehumanizeExtensions.cs
@@ -3,6 +3,9 @@
namespace Humanizer
{
+ ///
+ /// Contains extension methods for dehumanizing Enum string values.
+ ///
public static class EnumDehumanizeExtensions
{
///
diff --git a/src/Humanizer/EnumHumanizeExtensions.cs b/src/Humanizer/EnumHumanizeExtensions.cs
index 4fd2327ce..b4891c463 100644
--- a/src/Humanizer/EnumHumanizeExtensions.cs
+++ b/src/Humanizer/EnumHumanizeExtensions.cs
@@ -4,6 +4,9 @@
namespace Humanizer
{
+ ///
+ /// Contains extension methods for humanizing Enums
+ ///
public static class EnumHumanizeExtensions
{
private static readonly Func DescriptionProperty = p => p.Name == "Description" && p.PropertyType == typeof (string);
diff --git a/src/Humanizer/Humanizer.csproj b/src/Humanizer/Humanizer.csproj
index 48a21ac9b..278bb1252 100644
--- a/src/Humanizer/Humanizer.csproj
+++ b/src/Humanizer/Humanizer.csproj
@@ -27,6 +27,7 @@
prompt
4
bin\Debug\Humanizer.xml
+ false
1591
@@ -37,25 +38,7 @@
prompt
4
bin\Release\Humanizer.xml
- 1591
-
-
- bin\Release\
- TRACE
- true
- pdbonly
- AnyCPU
- bin\Release\Humanizer.dll.CodeAnalysisLog.xml
- true
- GlobalSuppressions.cs
- prompt
- MinimumRecommendedRules.ruleset
- ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets
- true
- ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules
- true
- 1591
- bin\Release\Humanizer.XML
+ true
true
@@ -63,7 +46,20 @@
Humanizer.snk
+
+ bin\Verify\
+ false
+ bin\Verify\Humanizer.XML
+ true
+ ..\Humanizer.ruleset
+ true
+
+
+ pdbonly
+ true
+
+
@@ -167,6 +163,7 @@
+
@@ -190,6 +187,8 @@
+
+
diff --git a/src/Humanizer/Localisation/Formatters/DefaultFormatter.cs b/src/Humanizer/Localisation/Formatters/DefaultFormatter.cs
index 727c157d4..37eca6839 100644
--- a/src/Humanizer/Localisation/Formatters/DefaultFormatter.cs
+++ b/src/Humanizer/Localisation/Formatters/DefaultFormatter.cs
@@ -6,28 +6,41 @@
public class DefaultFormatter : IFormatter
{
///
- /// Now!
+ /// Now
///
- /// Time expressed in words
+ /// Returns Now
public virtual string DateHumanize_Now()
{
return GetResourceForDate(TimeUnit.Millisecond, Tense.Past, 0);
}
+ ///
+ /// Returns the string representation of the provided DateTime
+ ///
+ ///
+ ///
+ ///
+ ///
public virtual string DateHumanize(TimeUnit timeUnit, Tense timeUnitTense, int unit)
{
return GetResourceForDate(timeUnit, timeUnitTense, unit);
}
///
- /// In NO time!
+ /// 0 seconds
///
- /// Time expressed in words
+ /// Returns 0 seconds as the string representation of Zero TimeSpan
public virtual string TimeSpanHumanize_Zero()
{
return GetResourceForTimeSpan(TimeUnit.Millisecond, 0);
}
+ ///
+ /// Returns the string representation of the provided TimeSpan
+ ///
+ ///
+ ///
+ ///
public virtual string TimeSpanHumanize(TimeUnit timeUnit, int unit)
{
return GetResourceForTimeSpan(timeUnit, unit);
@@ -45,21 +58,43 @@ private string GetResourceForTimeSpan(TimeUnit unit, int count)
return count == 1 ? Format(resourceKey) : Format(resourceKey, count);
}
+ ///
+ ///
+ ///
+ ///
+ ///
protected virtual string Format(string resourceKey)
{
return Resources.GetResource(GetResourceKey(resourceKey));
}
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
protected virtual string Format(string resourceKey, int number)
{
return Resources.GetResource(GetResourceKey(resourceKey, number)).FormatWith(number);
}
+ ///
+ /// Override this method if your locale has complex rules around multiple units; e.g. Arabic, Russian
+ ///
+ /// The resource key that's being in formatting
+ /// The number of the units being used in formatting
+ ///
protected virtual string GetResourceKey(string resourceKey, int number)
{
return resourceKey;
}
+ ///
+ ///
+ ///
+ ///
+ ///
protected virtual string GetResourceKey(string resourceKey)
{
return resourceKey;
diff --git a/src/Humanizer/Localisation/Formatters/IFormatter.cs b/src/Humanizer/Localisation/Formatters/IFormatter.cs
index b591d6cfa..887209658 100644
--- a/src/Humanizer/Localisation/Formatters/IFormatter.cs
+++ b/src/Humanizer/Localisation/Formatters/IFormatter.cs
@@ -7,10 +7,33 @@
///
public interface IFormatter
{
+ ///
+ /// Now
+ ///
+ /// Returns Now
string DateHumanize_Now();
+
+ ///
+ /// Returns the string representation of the provided DateTime
+ ///
+ ///
+ ///
+ ///
+ ///
string DateHumanize(TimeUnit timeUnit, Tense timeUnitTense, int unit);
-
+
+ ///
+ /// 0 seconds
+ ///
+ /// Returns 0 seconds as the string representation of Zero TimeSpan
string TimeSpanHumanize_Zero();
+
+ ///
+ /// Returns the string representation of the provided TimeSpan
+ ///
+ ///
+ ///
+ ///
string TimeSpanHumanize(TimeUnit timeUnit, int unit);
}
}
diff --git a/src/Humanizer/Localisation/Formatters/SerbianFormatter.cs b/src/Humanizer/Localisation/Formatters/SerbianFormatter.cs
new file mode 100644
index 000000000..8f8ea913e
--- /dev/null
+++ b/src/Humanizer/Localisation/Formatters/SerbianFormatter.cs
@@ -0,0 +1,17 @@
+namespace Humanizer.Localisation.Formatters
+{
+ internal class SerbianFormatter : DefaultFormatter
+ {
+ private const string PaucalPostfix = "_Paucal";
+
+ protected override string GetResourceKey(string resourceKey, int number)
+ {
+ int mod10 = number % 10;
+
+ if (mod10 > 1 && mod10 < 5)
+ return resourceKey + PaucalPostfix;
+
+ return resourceKey;
+ }
+ }
+}
diff --git a/src/Humanizer/Localisation/NumberToWords/ArabicNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/ArabicNumberToWordsConverter.cs
index a4104c69b..e47f7c199 100644
--- a/src/Humanizer/Localisation/NumberToWords/ArabicNumberToWordsConverter.cs
+++ b/src/Humanizer/Localisation/NumberToWords/ArabicNumberToWordsConverter.cs
@@ -1,4 +1,6 @@
using System;
+using System.Collections.Generic;
+using System.Linq;
namespace Humanizer.Localisation.NumberToWords
{
@@ -94,22 +96,107 @@ public override string Convert(int number)
if (groupNumber >= 3 && groupNumber <= 10)
result = String.Format("{0} {1}", PluralGroups[groupLevel], result);
else
- {
result = String.Format("{0} {1}", result != String.Empty ? AppendedGroups[groupLevel] : Groups[groupLevel], result);
- }
}
else
- {
result = String.Format("{0} {1}", Groups[groupLevel], result);
- }
}
}
+
result = String.Format("{0} {1}", process, result);
}
+
groupLevel++;
}
return result.Trim();
}
+
+ private static readonly Dictionary OrdinalExceptions = new Dictionary
+ {
+ {"واحد", "الحادي"},
+ {"أحد", "الحادي"},
+ {"اثنان", "الثاني"},
+ {"اثنا", "الثاني"},
+ {"ثلاثة", "الثالث"},
+ {"أربعة", "الرابع"},
+ {"خمسة", "الخامس"},
+ {"ستة", "السادس"},
+ {"سبعة", "السابع"},
+ {"ثمانية", "الثامن"},
+ {"تسعة", "التاسع"},
+ {"عشرة", "العاشر"},
+ };
+
+ public override string ConvertToOrdinal(int number)
+ {
+ if (number == 0) return "الصفر";
+ var beforeOneHundredNumber = number%100;
+ var overTensPart = number/100*100;
+ var beforeOneHundredWord = string.Empty;
+ var overTensWord = string.Empty;
+
+ if (beforeOneHundredNumber > 0)
+ {
+ beforeOneHundredWord = Convert(beforeOneHundredNumber);
+ beforeOneHundredWord = ParseNumber(beforeOneHundredWord, beforeOneHundredNumber);
+ }
+
+ if (overTensPart > 0)
+ {
+ overTensWord = Convert(overTensPart);
+ overTensWord = ParseNumber(overTensWord, overTensPart);
+ }
+
+ var word = beforeOneHundredWord +
+ (overTensPart > 0
+ ? (string.IsNullOrWhiteSpace(beforeOneHundredWord) ? string.Empty : " بعد ") + overTensWord
+ : string.Empty);
+ return word.Trim();
+ }
+
+ private static string ParseNumber(string word, int number)
+ {
+ if (number == 1)
+ return "الأول";
+
+ if (number <= 10)
+ {
+ foreach (var kv in OrdinalExceptions.Where(kv => word.EndsWith(kv.Key)))
+ {
+ // replace word with exception
+ return word.Substring(0, word.Length - kv.Key.Length) + kv.Value;
+ }
+ }
+ else if (number > 10 && number < 100)
+ {
+ var parts = word.Split(' ');
+ var newParts = new string[parts.Length];
+ int count = 0;
+
+ foreach (var part in parts)
+ {
+ var newPart = part;
+ var oldPart = part;
+
+ foreach (var kv in OrdinalExceptions.Where(kv => oldPart.EndsWith(kv.Key)))
+ {
+ // replace word with exception
+ newPart = oldPart.Substring(0, oldPart.Length - kv.Key.Length) + kv.Value;
+ }
+
+ if (number > 19 && newPart == oldPart && oldPart.Length > 1)
+ newPart = "ال" + oldPart;
+
+ newParts[count++] = newPart;
+ }
+
+ word = string.Join(" ", newParts);
+ }
+ else
+ word = "ال"+word;
+
+ return word;
+ }
}
}
\ No newline at end of file
diff --git a/src/Humanizer/Localisation/NumberToWords/RussianNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/RussianNumberToWordsConverter.cs
index 0139061e5..f5bbef698 100644
--- a/src/Humanizer/Localisation/NumberToWords/RussianNumberToWordsConverter.cs
+++ b/src/Humanizer/Localisation/NumberToWords/RussianNumberToWordsConverter.cs
@@ -66,21 +66,22 @@ public override string ConvertToOrdinal(int number, GrammaticalGender gender)
if (number >= 100)
{
- var i = number;
+ var ending = GetEndingForGender(gender, number);
var hundreds = number/100;
number %= 100;
if (number == 0)
- parts.Add(GetPrefix(hundreds) + "сот" + GetEndingForGender(gender, i));
+ parts.Add(UnitsOrdinalPrefixes[hundreds] + "сот" + ending);
else
parts.Add(HundredsMap[hundreds]);
}
+
if (number >= 20)
{
- var i = number;
- var tens = i/10;
+ var ending = GetEndingForGender(gender, number);
+ var tens = number/10;
number %= 10;
if (number == 0)
- parts.Add(TensOrdinal[tens] + GetEndingForGender(gender, i));
+ parts.Add(TensOrdinal[tens] + ending);
else
parts.Add(TensMap[tens]);
}
@@ -95,14 +96,14 @@ private static void CollectPartsUnderOneThousand(ICollection parts, int
{
if (number >= 100)
{
- var hundreds = number / 100;
+ var hundreds = number/100;
number %= 100;
parts.Add(HundredsMap[hundreds]);
}
if (number >= 20)
{
- int tens = number/10;
+ var tens = number/10;
parts.Add(TensMap[tens]);
number %= 10;
}
@@ -120,24 +121,35 @@ private static void CollectPartsUnderOneThousand(ICollection parts, int
}
}
- private static string GetPrefix(int number)
+ private static string GetPrefix(int number, GrammaticalGender gender)
{
var parts = new List();
+
if (number >= 100)
{
var hundreds = number/100;
number %= 100;
- parts.Add(HundredsMap[hundreds]);
+ if (hundreds != 1)
+ parts.Add(UnitsOrdinalPrefixes[hundreds] + "сот");
+ else
+ parts.Add("сто");
}
+
if (number >= 20)
{
var tens = number/10;
number %= 10;
parts.Add(TensOrdinalPrefixes[tens]);
}
+
if (number > 0)
- parts.Add(UnitsOrdinalPrefixes[number]);
-
+ {
+ if (number == 1)
+ parts.Add(gender == GrammaticalGender.Feminine ? "одна" : "одно");
+ else
+ parts.Add(UnitsOrdinalPrefixes[number]);
+ }
+
return string.Join("", parts);
}
@@ -157,7 +169,12 @@ private static void CollectOrdinalParts(ICollection parts, ref int numbe
var result = number/divisor;
number %= divisor;
if (number == 0)
- parts.Add(GetPrefix(result) + prefixedForm);
+ {
+ if (result == 1)
+ parts.Add(prefixedForm);
+ else
+ parts.Add(GetPrefix(result, gender) + prefixedForm);
+ }
else
{
CollectPartsUnderOneThousand(parts, result, gender);
diff --git a/src/Humanizer/Localisation/NumberToWords/SpanishNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/SpanishNumberToWordsConverter.cs
index b3880e6bb..a3afe02ab 100644
--- a/src/Humanizer/Localisation/NumberToWords/SpanishNumberToWordsConverter.cs
+++ b/src/Humanizer/Localisation/NumberToWords/SpanishNumberToWordsConverter.cs
@@ -5,9 +5,11 @@ namespace Humanizer.Localisation.NumberToWords
{
internal class SpanishNumberToWordsConverter : DefaultNumberToWordsConverter
{
- private static readonly string[] HundredsMap = { "cero", "ciento", "doscientos", "trescientos", "cuatrocientos", "quinientos", "seiscientos", "setecientos", "ochocientos", "novecientos" };
- 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" };
+ 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",
+ "veintidós", "veintitrés", "veinticuatro", "veinticinco", "veintiséis", "veintisiete", "veintiocho", "veintinueve"};
private static readonly string[] TensMap = { "cero", "diez", "veinte", "treinta", "cuarenta", "cincuenta", "sesenta", "setenta", "ochenta", "noventa" };
+ private static readonly string[] HundredsMap = { "cero", "ciento", "doscientos", "trescientos", "cuatrocientos", "quinientos", "seiscientos", "setecientos", "ochocientos", "novecientos" };
private static readonly Dictionary Ordinals = new Dictionary
{
@@ -45,7 +47,7 @@ public override string Convert(int number)
if ((number / 1000000) > 0)
{
parts.Add(number / 1000000 == 1
- ? string.Format("millón")
+ ? string.Format("un millón")
: string.Format("{0} millones", Convert(number / 1000000)));
number %= 1000000;
@@ -68,7 +70,7 @@ public override string Convert(int number)
if (number > 0)
{
- if (number < 20)
+ if (number < 30)
parts.Add(UnitsMap[number]);
else if (number > 20 && number < 30) {
var lastPart = TensMap[number / 10];
@@ -95,10 +97,13 @@ public override string ConvertToOrdinal(int number, GrammaticalGender gender = G
string towords;
if (!Ordinals.TryGetValue(number, out towords))
towords = Convert(number);
+
if (gender == GrammaticalGender.Feminine)
towords = towords.TrimEnd('o') + "a";
+ else if(number % 10 == 1 || number % 10 == 3)
+ towords = towords.TrimEnd('o');
return towords;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Humanizer/Localisation/Ordinalizers/SpanishOrdinalizer.cs b/src/Humanizer/Localisation/Ordinalizers/SpanishOrdinalizer.cs
index 6735a126e..d34a8fbe7 100644
--- a/src/Humanizer/Localisation/Ordinalizers/SpanishOrdinalizer.cs
+++ b/src/Humanizer/Localisation/Ordinalizers/SpanishOrdinalizer.cs
@@ -14,9 +14,9 @@ public override string Convert(int number, string numberString, GrammaticalGende
return "0";
if (gender == GrammaticalGender.Feminine)
- return numberString + "ª";
-
- return numberString + "º";
+ return numberString + ".ª";
+ else
+ return numberString + ".º";
}
}
}
\ No newline at end of file
diff --git a/src/Humanizer/Localisation/ResourceKeys.Common.cs b/src/Humanizer/Localisation/ResourceKeys.Common.cs
index 1774b1052..5f995cb6d 100644
--- a/src/Humanizer/Localisation/ResourceKeys.Common.cs
+++ b/src/Humanizer/Localisation/ResourceKeys.Common.cs
@@ -2,6 +2,9 @@
namespace Humanizer.Localisation
{
+ ///
+ ///
+ ///
public partial class ResourceKeys
{
private const string Single = "Single";
diff --git a/src/Humanizer/Localisation/ResourceKeys.DateHumanize.cs b/src/Humanizer/Localisation/ResourceKeys.DateHumanize.cs
index 3c49856fd..ee91374f9 100644
--- a/src/Humanizer/Localisation/ResourceKeys.DateHumanize.cs
+++ b/src/Humanizer/Localisation/ResourceKeys.DateHumanize.cs
@@ -2,6 +2,9 @@
{
public partial class ResourceKeys
{
+ ///
+ /// Encapsulates the logic required to get the resource keys for DateTime.Humanize
+ ///
public static class DateHumanize
{
///
diff --git a/src/Humanizer/Localisation/ResourceKeys.TimeSpanHumanize.cs b/src/Humanizer/Localisation/ResourceKeys.TimeSpanHumanize.cs
index 85ef1d74a..321e961a3 100644
--- a/src/Humanizer/Localisation/ResourceKeys.TimeSpanHumanize.cs
+++ b/src/Humanizer/Localisation/ResourceKeys.TimeSpanHumanize.cs
@@ -2,6 +2,9 @@
{
public partial class ResourceKeys
{
+ ///
+ /// Encapsulates the logic required to get the resource keys for TimeSpan.Humanize
+ ///
public static class TimeSpanHumanize
{
///
diff --git a/src/Humanizer/Localisation/TimeUnit.cs b/src/Humanizer/Localisation/TimeUnit.cs
index 86c4a56b4..e8941b3c1 100644
--- a/src/Humanizer/Localisation/TimeUnit.cs
+++ b/src/Humanizer/Localisation/TimeUnit.cs
@@ -3,6 +3,7 @@
///
/// Units of time.
///
+#pragma warning disable 1591
public enum TimeUnit
{
Millisecond,
@@ -14,4 +15,5 @@ public enum TimeUnit
Month,
Year
}
+#pragma warning restore 1591
}
\ No newline at end of file
diff --git a/src/Humanizer/NoMatchFoundException.cs b/src/Humanizer/NoMatchFoundException.cs
index 19dafef78..30614308a 100644
--- a/src/Humanizer/NoMatchFoundException.cs
+++ b/src/Humanizer/NoMatchFoundException.cs
@@ -5,6 +5,7 @@ namespace Humanizer
///
/// This is thrown on String.DehumanizeTo enum when the provided string cannot be mapped to the target enum
///
+#pragma warning disable 1591
public class NoMatchFoundException : Exception
{
public NoMatchFoundException()
@@ -21,4 +22,5 @@ public NoMatchFoundException(string message, Exception inner)
{
}
}
+#pragma warning restore 1591
}
\ No newline at end of file
diff --git a/src/Humanizer/Properties/Resources.ar.resx b/src/Humanizer/Properties/Resources.ar.resx
index d70d8b41c..f70c4b314 100644
--- a/src/Humanizer/Properties/Resources.ar.resx
+++ b/src/Humanizer/Properties/Resources.ar.resx
@@ -1,4 +1,4 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ 1 秒前
+
+
+ {0} 秒前
+
+
+ 1 分前
+
+
+ {0} 分前
+
+
+ 1 時間前
+
+
+ {0} 時間前
+
+
+ 昨日
+
+
+ {0} 日前
+
+
+ 先月
+
+
+ {0} か月前
+
+
+ 去年
+
+
+ {0} 年前
+
+
+ {0} 日
+
+
+ {0} 時間
+
+
+ {0} ミリ秒
+
+
+ {0} 分
+
+
+ {0} 秒
+
+
+ 1 日
+
+
+ 1 時間
+
+
+ 1 ミリ秒
+
+
+ 1 分
+
+
+ 1 秒
+
+
+ 0 秒
+
+
+ {0} 週間
+
+
+ 1 週間
+
+
+ {0} 日後
+
+
+ {0} 時間後
+
+
+ {0} 分後
+
+
+ {0} か月後
+
+
+ {0} 秒後
+
+
+ {0} 年後
+
+
+ 今
+
+
+ 明日
+
+
+ 1 時間後
+
+
+ 1 分後
+
+
+ 来月
+
+
+ 1 秒後
+
+
+ 来年
+
+
\ No newline at end of file
diff --git a/src/Humanizer/Properties/Resources.sr-Latn.resx b/src/Humanizer/Properties/Resources.sr-Latn.resx
new file mode 100644
index 000000000..44974d84e
--- /dev/null
+++ b/src/Humanizer/Properties/Resources.sr-Latn.resx
@@ -0,0 +1,288 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+pre sekund
+
+
+pre {0} sekundi
+
+
+pre minut
+
+
+pre {0} minuta
+
+
+pre sat vremena
+
+
+pre {0} sati
+
+
+juče
+
+
+pre {0} dana
+
+
+pre mesec dana
+
+
+pre {0} meseci
+
+
+pre godinu dana
+
+
+pre {0} godina
+
+
+{0} dana
+
+
+{0} sati
+
+
+{0} milisekundi
+
+
+{0} minuta
+
+
+{0} sekundi
+
+
+1 dan
+
+
+1 sat
+
+
+1 milisekunda
+
+
+1 minut
+
+
+1 sekunda
+
+
+bez proteklog vremena
+
+
+{0} nedelja
+
+
+1 nedelja
+
+
+za {0} dana
+
+
+za {0} sati
+
+
+za {0} minuta
+
+
+za {0} meseci
+
+
+za {0} sekundi
+
+
+za {0} godina
+
+
+sada
+
+
+sutra
+
+
+za sat vremena
+
+
+za minut
+
+
+za mesec dana
+
+
+za sekund
+
+
+za godinu dana
+
+
+pre {0} dana
+
+
+za {0} dana
+
+
+pre {0} sata
+
+
+za {0} sata
+
+
+pre {0} minuta
+
+
+za {0} minuta
+
+
+pre {0} meseca
+
+
+za {0} meseca
+
+
+pre {0} sekunde
+
+
+za {0} sekunde
+
+
+pre {0} godine
+
+
+za {0} godine
+
+
+{0} dana
+
+
+{0} sata
+
+
+{0} milisekunde
+
+
+{0} minuta
+
+
+{0} sekunde
+
+
+{0} nedelje
+
+
\ No newline at end of file
diff --git a/src/Humanizer/Properties/Resources.sr.resx b/src/Humanizer/Properties/Resources.sr.resx
new file mode 100644
index 000000000..bd9d54e72
--- /dev/null
+++ b/src/Humanizer/Properties/Resources.sr.resx
@@ -0,0 +1,288 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ пре секунд
+
+
+ пре {0} секунди
+
+
+ пре минут
+
+
+ пре {0} минута
+
+
+ пре сат времена
+
+
+ пре {0} сати
+
+
+ јуче
+
+
+ пре {0} дана
+
+
+ пре месец дана
+
+
+ пре {0} месеци
+
+
+ пре годину дана
+
+
+ пре {0} година
+
+
+ {0} дана
+
+
+ {0} сати
+
+
+ {0} милисекунди
+
+
+ {0} минута
+
+
+ {0} секунди
+
+
+ 1 дан
+
+
+ 1 сат
+
+
+ 1 милисекунда
+
+
+ 1 минут
+
+
+ 1 секунда
+
+
+ без протеклог времена
+
+
+ {0} недеља
+
+
+ 1 недеља
+
+
+ за {0} дана
+
+
+ за {0} сати
+
+
+ за {0} минута
+
+
+ за {0} месеци
+
+
+ за {0} секунди
+
+
+ за {0} година
+
+
+ сада
+
+
+ сутра
+
+
+ за сат времена
+
+
+ за минут
+
+
+ за месец дана
+
+
+ за секунд
+
+
+ за годину дана
+
+
+ пре {0} дана
+
+
+ за {0} дана
+
+
+ пре {0} сата
+
+
+ за {0} сата
+
+
+ пре {0} минута
+
+
+ за {0} минута
+
+
+ пре {0} месеца
+
+
+ за {0} месеца
+
+
+ пре {0} секунде
+
+
+ за {0} секунде
+
+
+ пре {0} године
+
+
+ за {0} године
+
+
+ {0} дана
+
+
+ {0} сата
+
+
+ {0} милисекунде
+
+
+ {0} минута
+
+
+ {0} секунде
+
+
+ {0} недеље
+
+
\ No newline at end of file
diff --git a/src/Humanizer/RomanNumeralExtensions.cs b/src/Humanizer/RomanNumeralExtensions.cs
index a37c85a45..d6e72b772 100644
--- a/src/Humanizer/RomanNumeralExtensions.cs
+++ b/src/Humanizer/RomanNumeralExtensions.cs
@@ -6,6 +6,9 @@
namespace Humanizer
{
+ ///
+ /// Contains extension methods for changing a number to Roman representation (ToRoman) and from Roman representation back to the number (FromRoman)
+ ///
public static class RomanNumeralExtensions
{
private const int NumberOfRomanNumeralMaps = 13;
diff --git a/src/Humanizer/StringDehumanizeExtensions.cs b/src/Humanizer/StringDehumanizeExtensions.cs
index 79b7b177f..64c485d6d 100644
--- a/src/Humanizer/StringDehumanizeExtensions.cs
+++ b/src/Humanizer/StringDehumanizeExtensions.cs
@@ -2,6 +2,9 @@
namespace Humanizer
{
+ ///
+ /// Contains extension methods for dehumanizing strings.
+ ///
public static class StringDehumanizeExtensions
{
///
diff --git a/src/Humanizer/StringHumanizeExtensions.cs b/src/Humanizer/StringHumanizeExtensions.cs
index 17acd4d60..ed597604c 100644
--- a/src/Humanizer/StringHumanizeExtensions.cs
+++ b/src/Humanizer/StringHumanizeExtensions.cs
@@ -4,6 +4,9 @@
namespace Humanizer
{
+ ///
+ /// Contains extension methods for humanizing string values.
+ ///
public static class StringHumanizeExtensions
{
static string FromUnderscoreDashSeparatedWords (string input)
diff --git a/src/Humanizer/Transformer/To.cs b/src/Humanizer/Transformer/To.cs
index fb0cef5cd..ad24f88f6 100644
--- a/src/Humanizer/Transformer/To.cs
+++ b/src/Humanizer/Transformer/To.cs
@@ -18,6 +18,12 @@ public static string Transform(this string input, params IStringTransformer[] tr
return transformers.Aggregate(input, (current, stringTransformer) => stringTransformer.Transform(current));
}
+ ///
+ /// Changes string to title case
+ ///
+ ///
+ /// "INvalid caSEs arE corrected" -> "Invalid Cases Are Corrected"
+ ///
public static IStringTransformer TitleCase
{
get
@@ -26,6 +32,12 @@ public static IStringTransformer TitleCase
}
}
+ ///
+ /// Changes the string to lower case
+ ///
+ ///
+ /// "Sentence casing" -> "sentence casing"
+ ///
public static IStringTransformer LowerCase
{
get
@@ -34,6 +46,12 @@ public static IStringTransformer LowerCase
}
}
+ ///
+ /// Changes the string to upper case
+ ///
+ ///
+ /// "lower case statement" -> "LOWER CASE STATEMENT"
+ ///
public static IStringTransformer UpperCase
{
get
@@ -42,6 +60,12 @@ public static IStringTransformer UpperCase
}
}
+ ///
+ /// Changes the string to sentence case
+ ///
+ ///
+ /// "lower case statement" -> "Lower case statement"
+ ///
public static IStringTransformer SentenceCase
{
get