diff --git a/.editorconfig b/.editorconfig index f7ec9b06d..7c33c3443 100644 --- a/.editorconfig +++ b/.editorconfig @@ -48,6 +48,7 @@ dotnet_style_coalesce_expression = true:suggestion dotnet_style_null_propagation = true:suggestion dotnet_style_explicit_tuple_names = true:suggestion dotnet_style_require_accessibility_modifiers = always +dotnet_style_prefer_conditional_expression_over_return = false # CSharp code style settings: [*.cs] diff --git a/.vsts-shared.yml b/.vsts-shared.yml index 05b5e9cbc..5f0a8e3ce 100644 --- a/.vsts-shared.yml +++ b/.vsts-shared.yml @@ -10,9 +10,9 @@ steps: displayName: Setup Environment Variables - task: NuGetToolInstaller@0 - displayName: Use NuGet 4.6.2 + displayName: Use NuGet 4.7.0 inputs: - versionSpec: 4.6.2 + versionSpec: 4.7.0 - task: DotNetCoreCLI@2 inputs: @@ -31,9 +31,10 @@ steps: # version nuget install NerdBank.GitVersioning -SolutionDir $(Build.SourcesDirectory) -Verbosity quiet -ExcludeVersion $vers = & $(Build.SourcesDirectory)\packages\nerdbank.gitversioning\tools\Get-Version.ps1 - $nugetVer = $vers.NuGetPackageVersion + $nugetVer = $vers.NuGetPackageVersion + $commitId = $vers.GitCommitId - ls .\NuSpecs\*.nuspec | %{ nuget pack $_.FullName -version "$nugetVer" -BasePath "src" -NoPackageAnalysis -OutputDirectory $(Build.ArtifactStagingDirectory)\Packages } + ls .\NuSpecs\*.nuspec | %{ nuget pack $_.FullName -version "$nugetVer" -BasePath "src" -NoPackageAnalysis -OutputDirectory $(Build.ArtifactStagingDirectory)\Packages -Properties "RepositoryType=git;RepositoryCommit=$commitId;RepositoryUrl=https://github.com/Humanizr/Humanizer"} displayName: Create packages - task: DotNetCoreCLI@2 diff --git a/NuSpecs/Humanizer.Core.af.nuspec b/NuSpecs/Humanizer.Core.af.nuspec index 502f66d53..b2758e8aa 100644 --- a/NuSpecs/Humanizer.Core.af.nuspec +++ b/NuSpecs/Humanizer.Core.af.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (af) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + af @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.ar.nuspec b/NuSpecs/Humanizer.Core.ar.nuspec index 629de39bb..5f964cfba 100644 --- a/NuSpecs/Humanizer.Core.ar.nuspec +++ b/NuSpecs/Humanizer.Core.ar.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (ar) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + ar @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.bg.nuspec b/NuSpecs/Humanizer.Core.bg.nuspec index 08e860741..a3d6218c9 100644 --- a/NuSpecs/Humanizer.Core.bg.nuspec +++ b/NuSpecs/Humanizer.Core.bg.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (bg) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + bg @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.bn-BD.nuspec b/NuSpecs/Humanizer.Core.bn-BD.nuspec index 469b8313f..389598648 100644 --- a/NuSpecs/Humanizer.Core.bn-BD.nuspec +++ b/NuSpecs/Humanizer.Core.bn-BD.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (bn-BD) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + bn-BD @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.cs.nuspec b/NuSpecs/Humanizer.Core.cs.nuspec index 6c710ced1..2ec8e2890 100644 --- a/NuSpecs/Humanizer.Core.cs.nuspec +++ b/NuSpecs/Humanizer.Core.cs.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (cs) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + cs @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.da.nuspec b/NuSpecs/Humanizer.Core.da.nuspec index 138077db7..033c00502 100644 --- a/NuSpecs/Humanizer.Core.da.nuspec +++ b/NuSpecs/Humanizer.Core.da.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (da) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + da @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.de-CH.nuspec b/NuSpecs/Humanizer.Core.de-CH.nuspec new file mode 100644 index 000000000..4f7585d1a --- /dev/null +++ b/NuSpecs/Humanizer.Core.de-CH.nuspec @@ -0,0 +1,25 @@ + + + + Humanizer.Core.de-CH + $version$ + Humanizer Locale (de-CH) + Mehdi Khalili, Oren Novotny + Mehdi Khalili, onovotny + https://github.com/Humanizr/Humanizer + https://raw.github.com/Humanizr/Humanizer/master/logo.png + false + Humanizer Locale (de-CH) + Copyright 2012-2015 Mehdi Khalili + https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + + de-CH + + + + + + + + + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.de-LI.nuspec b/NuSpecs/Humanizer.Core.de-LI.nuspec new file mode 100644 index 000000000..e677d15d0 --- /dev/null +++ b/NuSpecs/Humanizer.Core.de-LI.nuspec @@ -0,0 +1,25 @@ + + + + Humanizer.Core.de-LI + $version$ + Humanizer Locale (de-LI) + Mehdi Khalili, Oren Novotny + Mehdi Khalili, onovotny + https://github.com/Humanizr/Humanizer + https://raw.github.com/Humanizr/Humanizer/master/logo.png + false + Humanizer Locale (de-LI) + Copyright 2012-2015 Mehdi Khalili + https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + + de-LI + + + + + + + + + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.de.nuspec b/NuSpecs/Humanizer.Core.de.nuspec index 3bd1a1b0a..c1e39adb3 100644 --- a/NuSpecs/Humanizer.Core.de.nuspec +++ b/NuSpecs/Humanizer.Core.de.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (de) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + de @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.el.nuspec b/NuSpecs/Humanizer.Core.el.nuspec index fce38cd89..81f3cd8c0 100644 --- a/NuSpecs/Humanizer.Core.el.nuspec +++ b/NuSpecs/Humanizer.Core.el.nuspec @@ -12,12 +12,13 @@ Humanizer Locale (el) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + el - + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.es.nuspec b/NuSpecs/Humanizer.Core.es.nuspec index 725453cbb..1b2111be0 100644 --- a/NuSpecs/Humanizer.Core.es.nuspec +++ b/NuSpecs/Humanizer.Core.es.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (es) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + es @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.fa.nuspec b/NuSpecs/Humanizer.Core.fa.nuspec index a5742c1f2..2865d9a9d 100644 --- a/NuSpecs/Humanizer.Core.fa.nuspec +++ b/NuSpecs/Humanizer.Core.fa.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (fa) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + fa @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.fi-FI.nuspec b/NuSpecs/Humanizer.Core.fi-FI.nuspec index 6d87f321b..382e14f48 100644 --- a/NuSpecs/Humanizer.Core.fi-FI.nuspec +++ b/NuSpecs/Humanizer.Core.fi-FI.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (fi-FI) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + fi-FI @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.fr-BE.nuspec b/NuSpecs/Humanizer.Core.fr-BE.nuspec index 694d0772a..974bd1654 100644 --- a/NuSpecs/Humanizer.Core.fr-BE.nuspec +++ b/NuSpecs/Humanizer.Core.fr-BE.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (fr-BE) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + fr-BE @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.fr.nuspec b/NuSpecs/Humanizer.Core.fr.nuspec index cfa75aa9f..cf642cd49 100644 --- a/NuSpecs/Humanizer.Core.fr.nuspec +++ b/NuSpecs/Humanizer.Core.fr.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (fr) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + fr @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.he.nuspec b/NuSpecs/Humanizer.Core.he.nuspec index 92e99d01d..21ac87ba5 100644 --- a/NuSpecs/Humanizer.Core.he.nuspec +++ b/NuSpecs/Humanizer.Core.he.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (he) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + he @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.hr.nuspec b/NuSpecs/Humanizer.Core.hr.nuspec index c59d0d144..d9b820fe8 100644 --- a/NuSpecs/Humanizer.Core.hr.nuspec +++ b/NuSpecs/Humanizer.Core.hr.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (hr) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + hr @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.hu.nuspec b/NuSpecs/Humanizer.Core.hu.nuspec index a3a6b2eba..e1355a80f 100644 --- a/NuSpecs/Humanizer.Core.hu.nuspec +++ b/NuSpecs/Humanizer.Core.hu.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (hu) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + hu @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.id.nuspec b/NuSpecs/Humanizer.Core.id.nuspec index b79872b41..cf32a5a07 100644 --- a/NuSpecs/Humanizer.Core.id.nuspec +++ b/NuSpecs/Humanizer.Core.id.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (id) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + id @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.it.nuspec b/NuSpecs/Humanizer.Core.it.nuspec index 5e513fdf6..1ec5e0dcf 100644 --- a/NuSpecs/Humanizer.Core.it.nuspec +++ b/NuSpecs/Humanizer.Core.it.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (it) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + it @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.ja.nuspec b/NuSpecs/Humanizer.Core.ja.nuspec index c0244f78d..b6737c765 100644 --- a/NuSpecs/Humanizer.Core.ja.nuspec +++ b/NuSpecs/Humanizer.Core.ja.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (ja) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + ja @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.lv.nuspec b/NuSpecs/Humanizer.Core.lv.nuspec index 8ff5c2842..9761398a4 100644 --- a/NuSpecs/Humanizer.Core.lv.nuspec +++ b/NuSpecs/Humanizer.Core.lv.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (lv) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + lv @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.nb-NO.nuspec b/NuSpecs/Humanizer.Core.nb-NO.nuspec index 8b938716b..8e8f04f5d 100644 --- a/NuSpecs/Humanizer.Core.nb-NO.nuspec +++ b/NuSpecs/Humanizer.Core.nb-NO.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (nb-NO) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + nb-NO @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.nb.nuspec b/NuSpecs/Humanizer.Core.nb.nuspec index 585a81a78..78a26bddb 100644 --- a/NuSpecs/Humanizer.Core.nb.nuspec +++ b/NuSpecs/Humanizer.Core.nb.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (nb) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + nb @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.nl.nuspec b/NuSpecs/Humanizer.Core.nl.nuspec index 8d0c61d9a..c21c010d1 100644 --- a/NuSpecs/Humanizer.Core.nl.nuspec +++ b/NuSpecs/Humanizer.Core.nl.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (nl) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + nl @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.nuspec b/NuSpecs/Humanizer.Core.nuspec index 5056db553..ffa8832f2 100644 --- a/NuSpecs/Humanizer.Core.nuspec +++ b/NuSpecs/Humanizer.Core.nuspec @@ -13,14 +13,16 @@ Copyright 2012-2016 https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE en + - + + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.pl.nuspec b/NuSpecs/Humanizer.Core.pl.nuspec index 5e9d84566..f4d8fb78e 100644 --- a/NuSpecs/Humanizer.Core.pl.nuspec +++ b/NuSpecs/Humanizer.Core.pl.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (pl) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + pl @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.pt.nuspec b/NuSpecs/Humanizer.Core.pt.nuspec index 26728c957..1484bfd5d 100644 --- a/NuSpecs/Humanizer.Core.pt.nuspec +++ b/NuSpecs/Humanizer.Core.pt.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (pt) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + pt @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.ro.nuspec b/NuSpecs/Humanizer.Core.ro.nuspec index 6026c8929..f2de305f1 100644 --- a/NuSpecs/Humanizer.Core.ro.nuspec +++ b/NuSpecs/Humanizer.Core.ro.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (ro) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + ro @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.ru.nuspec b/NuSpecs/Humanizer.Core.ru.nuspec index 336ac8e53..cf2364163 100644 --- a/NuSpecs/Humanizer.Core.ru.nuspec +++ b/NuSpecs/Humanizer.Core.ru.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (ru) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + ru @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.sk.nuspec b/NuSpecs/Humanizer.Core.sk.nuspec index f6f11c01e..3bc21fc95 100644 --- a/NuSpecs/Humanizer.Core.sk.nuspec +++ b/NuSpecs/Humanizer.Core.sk.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (sk) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + sk @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.sl.nuspec b/NuSpecs/Humanizer.Core.sl.nuspec index e56b77e14..94c80f2f6 100644 --- a/NuSpecs/Humanizer.Core.sl.nuspec +++ b/NuSpecs/Humanizer.Core.sl.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (sl) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + sl @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.sr-Latn.nuspec b/NuSpecs/Humanizer.Core.sr-Latn.nuspec index 7e26b6647..b3414ed43 100644 --- a/NuSpecs/Humanizer.Core.sr-Latn.nuspec +++ b/NuSpecs/Humanizer.Core.sr-Latn.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (sr-Latn) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + sr-Latn @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.sr.nuspec b/NuSpecs/Humanizer.Core.sr.nuspec index dd5e36b5a..0ea0d215a 100644 --- a/NuSpecs/Humanizer.Core.sr.nuspec +++ b/NuSpecs/Humanizer.Core.sr.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (sr) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + sr @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.sv.nuspec b/NuSpecs/Humanizer.Core.sv.nuspec index 595cf3555..7c8806d91 100644 --- a/NuSpecs/Humanizer.Core.sv.nuspec +++ b/NuSpecs/Humanizer.Core.sv.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (sv) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + sv @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.tr.nuspec b/NuSpecs/Humanizer.Core.tr.nuspec index 32dc47cdb..1de385ed6 100644 --- a/NuSpecs/Humanizer.Core.tr.nuspec +++ b/NuSpecs/Humanizer.Core.tr.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (tr) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + tr @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.uk.nuspec b/NuSpecs/Humanizer.Core.uk.nuspec index b3e6cdb23..e9a501f54 100644 --- a/NuSpecs/Humanizer.Core.uk.nuspec +++ b/NuSpecs/Humanizer.Core.uk.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (uk) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + uk @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.uz-Cyrl-UZ.nuspec b/NuSpecs/Humanizer.Core.uz-Cyrl-UZ.nuspec index e852d551f..eb18a2fe1 100644 --- a/NuSpecs/Humanizer.Core.uz-Cyrl-UZ.nuspec +++ b/NuSpecs/Humanizer.Core.uz-Cyrl-UZ.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (uz-Cyrl-UZ) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + uz-Cyrl-UZ @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.uz-Latn-UZ.nuspec b/NuSpecs/Humanizer.Core.uz-Latn-UZ.nuspec index 002f1aa59..6d1fb0838 100644 --- a/NuSpecs/Humanizer.Core.uz-Latn-UZ.nuspec +++ b/NuSpecs/Humanizer.Core.uz-Latn-UZ.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (uz-Latn-UZ) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + uz-Latn-UZ @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.vi.nuspec b/NuSpecs/Humanizer.Core.vi.nuspec index 4e3cd4eea..136d80dc6 100644 --- a/NuSpecs/Humanizer.Core.vi.nuspec +++ b/NuSpecs/Humanizer.Core.vi.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (vi) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + vi @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.zh-CN.nuspec b/NuSpecs/Humanizer.Core.zh-CN.nuspec index 7c7ecac3a..acd286f13 100644 --- a/NuSpecs/Humanizer.Core.zh-CN.nuspec +++ b/NuSpecs/Humanizer.Core.zh-CN.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (zh-CN) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + zh-CN @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.zh-Hans.nuspec b/NuSpecs/Humanizer.Core.zh-Hans.nuspec index 382a3af7d..bf6792dca 100644 --- a/NuSpecs/Humanizer.Core.zh-Hans.nuspec +++ b/NuSpecs/Humanizer.Core.zh-Hans.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (zh-Hans) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + zh-Hans @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.Core.zh-Hant.nuspec b/NuSpecs/Humanizer.Core.zh-Hant.nuspec index a0888b5c4..59c2dc97f 100644 --- a/NuSpecs/Humanizer.Core.zh-Hant.nuspec +++ b/NuSpecs/Humanizer.Core.zh-Hant.nuspec @@ -12,6 +12,7 @@ Humanizer Locale (zh-Hant) Copyright 2012-2015 Mehdi Khalili https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + zh-Hant @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/NuSpecs/Humanizer.nuspec b/NuSpecs/Humanizer.nuspec index 04a9be1b1..c6189470f 100644 --- a/NuSpecs/Humanizer.nuspec +++ b/NuSpecs/Humanizer.nuspec @@ -11,7 +11,8 @@ false Humanizer meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities Copyright 2012-2017 Mehdi Khalili - https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE + @@ -20,6 +21,8 @@ + + diff --git a/readme.md b/readme.md index 3f9dd58e8..ce0d8d40a 100644 --- a/readme.md +++ b/readme.md @@ -770,6 +770,7 @@ The possible values are `GrammaticalGender.Masculine`, `GrammaticalGender.Femini 1.ToWords(GrammaticalGender.Masculine) => "واحد" 1.ToWords(GrammaticalGender.Feminine) => "واحدة" 1.ToWords(GrammaticalGender.Neuter) => "واحد" +(-1).ToWords() => "ناقص واحد" ``` Obviously this only applies to some cultures. For others passing gender in doesn't make any difference in the result. diff --git a/scripts/Sign-Package.ps1 b/scripts/Sign-Package.ps1 index daedfbf48..7ac7d7e75 100644 --- a/scripts/Sign-Package.ps1 +++ b/scripts/Sign-Package.ps1 @@ -6,20 +6,18 @@ if([string]::IsNullOrEmpty($env:SignClientSecret)){ return; } -& nuget install SignClient -Version 0.9.1 -SolutionDir "$currentDirectory\..\" -Verbosity quiet -ExcludeVersion +dotnet tool install --tool-path . SignClient # Setup Variables we need to pass into the sign client tool $appSettings = "$currentDirectory\SignClient.json" -$appPath = "$currentDirectory\..\packages\SignClient\tools\netcoreapp2.0\SignClient.dll" - $nupgks = gci $Env:ArtifactDirectory\*.nupkg | Select -ExpandProperty FullName foreach ($nupkg in $nupgks){ Write-Host "Submitting $nupkg for signing" - dotnet $appPath 'sign' -c $appSettings -i $nupkg -r $env:SignClientUser -s $env:SignClientSecret -n 'Humanizer' -d 'Humanizer' -u 'https://github.com/Humanizr/Humanizer' + .\SignClient 'sign' -c $appSettings -i $nupkg -r $env:SignClientUser -s $env:SignClientSecret -n 'Humanizer' -d 'Humanizer' -u 'https://github.com/Humanizr/Humanizer' Write-Host "Finished signing $nupkg" } diff --git a/src/Directory.build.props b/src/Directory.build.props index 44762675b..84d7166db 100644 --- a/src/Directory.build.props +++ b/src/Directory.build.props @@ -1,11 +1,23 @@ latest + true + true + $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb - + - - \ No newline at end of file + + + + + <_Parameter1>CommitHash + <_Parameter2>$(SourceRevisionId) + + + + + \ No newline at end of file diff --git a/src/Humanizer.Tests.Shared/Humanizer.Tests.Shared.projitems b/src/Humanizer.Tests.Shared/Humanizer.Tests.Shared.projitems index dead06d9a..d2be62186 100644 --- a/src/Humanizer.Tests.Shared/Humanizer.Tests.Shared.projitems +++ b/src/Humanizer.Tests.Shared/Humanizer.Tests.Shared.projitems @@ -47,6 +47,8 @@ + + diff --git a/src/Humanizer.Tests.Shared/Localisation/ar/NumberToWordsTests.cs b/src/Humanizer.Tests.Shared/Localisation/ar/NumberToWordsTests.cs index 5379e5d9e..6914a793a 100644 --- a/src/Humanizer.Tests.Shared/Localisation/ar/NumberToWordsTests.cs +++ b/src/Humanizer.Tests.Shared/Localisation/ar/NumberToWordsTests.cs @@ -1,4 +1,5 @@ -using Xunit; +using Humanizer.Localisation.NumberToWords; +using Xunit; namespace Humanizer.Tests.Localisation.ar { @@ -18,6 +19,47 @@ public void ToWordsArabic(string expected, int number) Assert.Equal(expected, number.ToWords()); } + [Theory] + [InlineData("ناقص واحد", -1)] + [InlineData("ناقص اثنان", -2)] + [InlineData("ناقص اثنان و عشرون", -22)] + [InlineData("ناقص أحد عشر", -11)] + [InlineData("ناقص ثلاثة آلاف و خمس مئة و واحد", -3501)] + [InlineData("ناقص مليون و واحد", -1000001)] + public void ToWordsArabicNegative(string expected, int number) + { + Assert.Equal(expected, number.ToWords()); + } + + [Theory] + [InlineData(1L, "واحد")] + [InlineData(11L, "أحد عشر")] + [InlineData(111L, "مئة و أحد عشر")] + [InlineData(1111L, "ألف و مئة و أحد عشر")] + [InlineData(11111L, "أحد عشر ألفاً و مئة و أحد عشر")] + [InlineData(111111L, "مئة و أحد عشر ألفاً و مئة و أحد عشر")] + [InlineData(1111111L, "مليون و مئة و أحد عشر ألفاً و مئة و أحد عشر")] + [InlineData(11111111L, "أحد عشر مليوناً و مئة و أحد عشر ألفاً و مئة و أحد عشر")] + [InlineData(111111111L, "مئة و أحد عشر مليوناً و مئة و أحد عشر ألفاً و مئة و أحد عشر")] + [InlineData(1111111111L, "مليار و مئة و أحد عشر مليوناً و مئة و أحد عشر ألفاً و مئة و أحد عشر")] + [InlineData(11111111111L, "أحد عشر ملياراً و مئة و أحد عشر مليوناً و مئة و أحد عشر ألفاً و مئة و أحد عشر")] + [InlineData(111111111111L, "مئة و أحد عشر ملياراً و مئة و أحد عشر مليوناً و مئة و أحد عشر ألفاً و مئة و أحد عشر")] + [InlineData(1111111111111L, "تريليون و مئة و أحد عشر ملياراً و مئة و أحد عشر مليوناً و مئة و أحد عشر ألفاً و مئة و أحد عشر")] + [InlineData(11111111111111L, "أحد عشر تريليوناً و مئة و أحد عشر ملياراً و مئة و أحد عشر مليوناً و مئة و أحد عشر ألفاً و مئة و أحد عشر")] + [InlineData(111111111111111L, "مئة و أحد عشر تريليوناً و مئة و أحد عشر ملياراً و مئة و أحد عشر مليوناً و مئة و أحد عشر ألفاً و مئة و أحد عشر")] + [InlineData(1111111111111111L, "كوادريليون و مئة و أحد عشر تريليوناً و مئة و أحد عشر ملياراً و مئة و أحد عشر مليوناً و مئة و أحد عشر ألفاً و مئة و أحد عشر")] + [InlineData(11111111111111111L, "أحد عشر كوادريليوناً و مئة و أحد عشر تريليوناً و مئة و أحد عشر ملياراً و مئة و أحد عشر مليوناً و مئة و أحد عشر ألفاً و مئة و أحد عشر")] + [InlineData(111111111111111111L, "مئة و أحد عشر كوادريليوناً و مئة و أحد عشر تريليوناً و مئة و أحد عشر ملياراً و مئة و أحد عشر مليوناً و مئة و أحد عشر ألفاً و مئة و أحد عشر")] + [InlineData(1111111111111111111L, "كوينتليون و مئة و أحد عشر كوادريليوناً و مئة و أحد عشر تريليوناً و مئة و أحد عشر ملياراً و مئة و أحد عشر مليوناً و مئة و أحد عشر ألفاً و مئة و أحد عشر")] + [InlineData(10000000001L, "عشرة مليارات و واحد")] + [InlineData(8750000500001L, "ثمانية تريليونات و سبع مئة و خمسون ملياراً و خمس مئة ألفاً و واحد")] + [InlineData(-10000000001L, "ناقص عشرة مليارات و واحد")] + [InlineData(-8750000500001L, "ناقص ثمانية تريليونات و سبع مئة و خمسون ملياراً و خمس مئة ألفاً و واحد")] + public void ToWordsArabicLong(long number, string expected) + { + Assert.Equal(expected, number.ToWords()); + } + [Theory] [InlineData("صفر", 0)] [InlineData("واحدة", 1)] @@ -26,7 +68,15 @@ public void ToWordsArabic(string expected, int number) [InlineData("إحدى عشرة", 11)] [InlineData("ثلاثة آلاف و خمس مئة و واحدة", 3501)] [InlineData("مليون و واحدة", 1000001)] - public void ToWordsArabicFeminine(string expected, int number) + public void ToWordsArabicFeminine(string expected, long number) + { + Assert.Equal(expected, number.ToWords(GrammaticalGender.Feminine)); + } + + [Theory] + [InlineData("عشرة مليارات و واحدة", 10000000001)] + [InlineData("ثمانية تريليونات و سبع مئة و خمسون ملياراً و خمس مئة ألفاً و واحدة", 8750000500001)] + public void ToWordsArabicLongFeminine(string expected, long number) { Assert.Equal(expected, number.ToWords(GrammaticalGender.Feminine)); } @@ -35,7 +85,7 @@ public void ToWordsArabicFeminine(string expected, int number) [InlineData(122, "مئة و اثنتان و عشرون", GrammaticalGender.Feminine)] [InlineData(3501, "ثلاثة آلاف و خمس مئة و واحدة", GrammaticalGender.Feminine)] [InlineData(3501, "ثلاثة آلاف و خمس مئة و واحد", GrammaticalGender.Neuter)] - public void ToWordsWithGender(int number, string expected, GrammaticalGender gender) + public void ToWordsWithGender(long number, string expected, GrammaticalGender gender) { Assert.Equal(expected, number.ToWords(gender)); } diff --git a/src/Humanizer.Tests.Shared/Localisation/de-CH/NumberToWordsTests.cs b/src/Humanizer.Tests.Shared/Localisation/de-CH/NumberToWordsTests.cs new file mode 100644 index 000000000..f09bd5e9e --- /dev/null +++ b/src/Humanizer.Tests.Shared/Localisation/de-CH/NumberToWordsTests.cs @@ -0,0 +1,163 @@ +using Xunit; + +namespace Humanizer.Tests.Localisation.deCH +{ + [UseCulture("de-CH")] + public class NumberToWordsTests + { + [Theory] + [InlineData(0, "null")] + [InlineData(1, "ein")] + [InlineData(2, "zwei")] + [InlineData(3, "drei")] + [InlineData(4, "vier")] + [InlineData(5, "fünf")] + [InlineData(6, "sechs")] + [InlineData(7, "sieben")] + [InlineData(8, "acht")] + [InlineData(9, "neun")] + [InlineData(10, "zehn")] + [InlineData(20, "zwanzig")] + [InlineData(30, "dreissig")] + [InlineData(40, "vierzig")] + [InlineData(50, "fünfzig")] + [InlineData(60, "sechzig")] + [InlineData(70, "siebzig")] + [InlineData(80, "achtzig")] + [InlineData(90, "neunzig")] + [InlineData(100, "einhundert")] + [InlineData(200, "zweihundert")] + [InlineData(1000, "eintausend")] + [InlineData(10000, "zehntausend")] + [InlineData(100000, "einhunderttausend")] + [InlineData(1000000, "eine Million")] + [InlineData(10000000, "zehn Millionen")] + [InlineData(100000000, "einhundert Millionen")] + [InlineData(1000000000, "eine Milliarde")] + [InlineData(2000000000, "zwei Milliarden")] + [InlineData(122, "einhundertzweiundzwanzig")] + [InlineData(3501, "dreitausendfünfhundertein")] + [InlineData(111, "einhundertelf")] + [InlineData(1112, "eintausendeinhundertzwölf")] + [InlineData(11213, "elftausendzweihundertdreizehn")] + [InlineData(121314, "einhunderteinundzwanzigtausenddreihundertvierzehn")] + [InlineData(2132415, "zwei Millionen einhundertzweiunddreissigtausendvierhundertfünfzehn")] + [InlineData(12345516, "zwölf Millionen dreihundertfünfundvierzigtausendfünfhundertsechzehn")] + [InlineData(751633617, "siebenhunderteinundfünfzig Millionen sechshundertdreiunddreissigtausendsechshundertsiebzehn")] + [InlineData(1111111118, "eine Milliarde einhundertelf Millionen einhundertelftausendeinhundertachtzehn")] + [InlineData(35484694489515, "fünfunddreissig Billionen vierhundertvierundachtzig Milliarden sechshundertvierundneunzig Millionen vierhundertneunundachtzigtausendfünfhundertfünfzehn")] + [InlineData(8183162164626926, "acht Billiarden einhundertdreiundachtzig Billionen einhundertzweiundsechzig Milliarden einhundertvierundsechzig Millionen sechshundertsechsundzwanzigtausendneunhundertsechsundzwanzig")] + [InlineData(4564121926659524672, "vier Trillionen fünfhundertvierundsechzig Billiarden einhunderteinundzwanzig Billionen neunhundertsechsundzwanzig Milliarden sechshundertneunundfünfzig Millionen fünfhundertvierundzwanzigtausendsechshundertzweiundsiebzig")] + [InlineData(-751633619, "minus siebenhunderteinundfünfzig Millionen sechshundertdreiunddreissigtausendsechshundertneunzehn")] + public void ToWords(long number, string expected) + { + Assert.Equal(expected, number.ToWords()); + } + + [Theory] + [InlineData(1, "eine")] + [InlineData(3501, "dreitausendfünfhunderteine")] + public void ToWordsFeminine(long number, string expected) + { + Assert.Equal(expected, number.ToWords(GrammaticalGender.Feminine)); + } + + [Theory] + [InlineData(0, "nullter")] + [InlineData(1, "erster")] + [InlineData(2, "zweiter")] + [InlineData(3, "dritter")] + [InlineData(4, "vierter")] + [InlineData(5, "fünfter")] + [InlineData(6, "sechster")] + [InlineData(7, "siebter")] + [InlineData(8, "achter")] + [InlineData(9, "neunter")] + [InlineData(10, "zehnter")] + [InlineData(20, "zwanzigster")] + [InlineData(30, "dreissigster")] + [InlineData(40, "vierzigster")] + [InlineData(50, "fünfzigster")] + [InlineData(60, "sechzigster")] + [InlineData(70, "siebzigster")] + [InlineData(80, "achtzigster")] + [InlineData(90, "neunzigster")] + [InlineData(100, "einhundertster")] + [InlineData(200, "zweihundertster")] + [InlineData(1000, "eintausendster")] + [InlineData(10000, "zehntausendster")] + [InlineData(100000, "einhunderttausendster")] + [InlineData(1000000, "einmillionster")] + [InlineData(10000000, "zehnmillionster")] + [InlineData(100000000, "einhundertmillionster")] + [InlineData(1000000000, "einmilliardster")] + [InlineData(2000000000, "zweimilliardster")] + [InlineData(122, "einhundertzweiundzwanzigster")] + [InlineData(3501, "dreitausendfünfhunderterster")] + [InlineData(111, "einhundertelfter")] + [InlineData(1112, "eintausendeinhundertzwölfter")] + [InlineData(11213, "elftausendzweihundertdreizehnter")] + [InlineData(121314, "einhunderteinundzwanzigtausenddreihundertvierzehnter")] + [InlineData(2132415, "zweimillioneneinhundertzweiunddreissigtausendvierhundertfünfzehnter")] + [InlineData(12345516, "zwölfmillionendreihundertfünfundvierzigtausendfünfhundertsechzehnter")] + [InlineData(751633617, "siebenhunderteinundfünfzigmillionensechshundertdreiunddreissigtausendsechshundertsiebzehnter")] + [InlineData(1111111118, "einemilliardeeinhundertelfmillioneneinhundertelftausendeinhundertachtzehnter")] + [InlineData(-751633619, "minus siebenhunderteinundfünfzigmillionensechshundertdreiunddreissigtausendsechshundertneunzehnter")] + public void ToOrdinalWords(int number, string expected) + { + Assert.Equal(expected, number.ToOrdinalWords()); + } + + [Theory] + [InlineData(0, "nullte")] + [InlineData(1, "erste")] + [InlineData(2, "zweite")] + [InlineData(3, "dritte")] + [InlineData(4, "vierte")] + [InlineData(5, "fünfte")] + [InlineData(6, "sechste")] + [InlineData(7, "siebte")] + [InlineData(8, "achte")] + [InlineData(9, "neunte")] + [InlineData(10, "zehnte")] + [InlineData(111, "einhundertelfte")] + [InlineData(1112, "eintausendeinhundertzwölfte")] + [InlineData(11213, "elftausendzweihundertdreizehnte")] + [InlineData(121314, "einhunderteinundzwanzigtausenddreihundertvierzehnte")] + [InlineData(2132415, "zweimillioneneinhundertzweiunddreissigtausendvierhundertfünfzehnte")] + [InlineData(12345516, "zwölfmillionendreihundertfünfundvierzigtausendfünfhundertsechzehnte")] + [InlineData(751633617, "siebenhunderteinundfünfzigmillionensechshundertdreiunddreissigtausendsechshundertsiebzehnte")] + [InlineData(1111111118, "einemilliardeeinhundertelfmillioneneinhundertelftausendeinhundertachtzehnte")] + [InlineData(-751633619, "minus siebenhunderteinundfünfzigmillionensechshundertdreiunddreissigtausendsechshundertneunzehnte")] + public void ToOrdinalWordsFeminine(int number, string expected) + { + Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Feminine)); + } + + [Theory] + [InlineData(0, "nulltes")] + [InlineData(1, "erstes")] + [InlineData(2, "zweites")] + [InlineData(3, "drittes")] + [InlineData(4, "viertes")] + [InlineData(5, "fünftes")] + [InlineData(6, "sechstes")] + [InlineData(7, "siebtes")] + [InlineData(8, "achtes")] + [InlineData(9, "neuntes")] + [InlineData(10, "zehntes")] + [InlineData(111, "einhundertelftes")] + [InlineData(1112, "eintausendeinhundertzwölftes")] + [InlineData(11213, "elftausendzweihundertdreizehntes")] + [InlineData(121314, "einhunderteinundzwanzigtausenddreihundertvierzehntes")] + [InlineData(2132415, "zweimillioneneinhundertzweiunddreissigtausendvierhundertfünfzehntes")] + [InlineData(12345516, "zwölfmillionendreihundertfünfundvierzigtausendfünfhundertsechzehntes")] + [InlineData(751633617, "siebenhunderteinundfünfzigmillionensechshundertdreiunddreissigtausendsechshundertsiebzehntes")] + [InlineData(1111111118, "einemilliardeeinhundertelfmillioneneinhundertelftausendeinhundertachtzehntes")] + [InlineData(-751633619, "minus siebenhunderteinundfünfzigmillionensechshundertdreiunddreissigtausendsechshundertneunzehntes")] + public void ToOrdinalWordsNeuter(int number, string expected) + { + Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Neuter)); + } + } +} diff --git a/src/Humanizer.Tests.Shared/Localisation/de-LI/NumberToWordsTests.cs b/src/Humanizer.Tests.Shared/Localisation/de-LI/NumberToWordsTests.cs new file mode 100644 index 000000000..0c5baa803 --- /dev/null +++ b/src/Humanizer.Tests.Shared/Localisation/de-LI/NumberToWordsTests.cs @@ -0,0 +1,163 @@ +using Xunit; + +namespace Humanizer.Tests.Localisation.deLI +{ + [UseCulture("de-LI")] + public class NumberToWordsTests + { + [Theory] + [InlineData(0, "null")] + [InlineData(1, "ein")] + [InlineData(2, "zwei")] + [InlineData(3, "drei")] + [InlineData(4, "vier")] + [InlineData(5, "fünf")] + [InlineData(6, "sechs")] + [InlineData(7, "sieben")] + [InlineData(8, "acht")] + [InlineData(9, "neun")] + [InlineData(10, "zehn")] + [InlineData(20, "zwanzig")] + [InlineData(30, "dreissig")] + [InlineData(40, "vierzig")] + [InlineData(50, "fünfzig")] + [InlineData(60, "sechzig")] + [InlineData(70, "siebzig")] + [InlineData(80, "achtzig")] + [InlineData(90, "neunzig")] + [InlineData(100, "einhundert")] + [InlineData(200, "zweihundert")] + [InlineData(1000, "eintausend")] + [InlineData(10000, "zehntausend")] + [InlineData(100000, "einhunderttausend")] + [InlineData(1000000, "eine Million")] + [InlineData(10000000, "zehn Millionen")] + [InlineData(100000000, "einhundert Millionen")] + [InlineData(1000000000, "eine Milliarde")] + [InlineData(2000000000, "zwei Milliarden")] + [InlineData(122, "einhundertzweiundzwanzig")] + [InlineData(3501, "dreitausendfünfhundertein")] + [InlineData(111, "einhundertelf")] + [InlineData(1112, "eintausendeinhundertzwölf")] + [InlineData(11213, "elftausendzweihundertdreizehn")] + [InlineData(121314, "einhunderteinundzwanzigtausenddreihundertvierzehn")] + [InlineData(2132415, "zwei Millionen einhundertzweiunddreissigtausendvierhundertfünfzehn")] + [InlineData(12345516, "zwölf Millionen dreihundertfünfundvierzigtausendfünfhundertsechzehn")] + [InlineData(751633617, "siebenhunderteinundfünfzig Millionen sechshundertdreiunddreissigtausendsechshundertsiebzehn")] + [InlineData(1111111118, "eine Milliarde einhundertelf Millionen einhundertelftausendeinhundertachtzehn")] + [InlineData(35484694489515, "fünfunddreissig Billionen vierhundertvierundachtzig Milliarden sechshundertvierundneunzig Millionen vierhundertneunundachtzigtausendfünfhundertfünfzehn")] + [InlineData(8183162164626926, "acht Billiarden einhundertdreiundachtzig Billionen einhundertzweiundsechzig Milliarden einhundertvierundsechzig Millionen sechshundertsechsundzwanzigtausendneunhundertsechsundzwanzig")] + [InlineData(4564121926659524672, "vier Trillionen fünfhundertvierundsechzig Billiarden einhunderteinundzwanzig Billionen neunhundertsechsundzwanzig Milliarden sechshundertneunundfünfzig Millionen fünfhundertvierundzwanzigtausendsechshundertzweiundsiebzig")] + [InlineData(-751633619, "minus siebenhunderteinundfünfzig Millionen sechshundertdreiunddreissigtausendsechshundertneunzehn")] + public void ToWords(long number, string expected) + { + Assert.Equal(expected, number.ToWords()); + } + + [Theory] + [InlineData(1, "eine")] + [InlineData(3501, "dreitausendfünfhunderteine")] + public void ToWordsFeminine(long number, string expected) + { + Assert.Equal(expected, number.ToWords(GrammaticalGender.Feminine)); + } + + [Theory] + [InlineData(0, "nullter")] + [InlineData(1, "erster")] + [InlineData(2, "zweiter")] + [InlineData(3, "dritter")] + [InlineData(4, "vierter")] + [InlineData(5, "fünfter")] + [InlineData(6, "sechster")] + [InlineData(7, "siebter")] + [InlineData(8, "achter")] + [InlineData(9, "neunter")] + [InlineData(10, "zehnter")] + [InlineData(20, "zwanzigster")] + [InlineData(30, "dreissigster")] + [InlineData(40, "vierzigster")] + [InlineData(50, "fünfzigster")] + [InlineData(60, "sechzigster")] + [InlineData(70, "siebzigster")] + [InlineData(80, "achtzigster")] + [InlineData(90, "neunzigster")] + [InlineData(100, "einhundertster")] + [InlineData(200, "zweihundertster")] + [InlineData(1000, "eintausendster")] + [InlineData(10000, "zehntausendster")] + [InlineData(100000, "einhunderttausendster")] + [InlineData(1000000, "einmillionster")] + [InlineData(10000000, "zehnmillionster")] + [InlineData(100000000, "einhundertmillionster")] + [InlineData(1000000000, "einmilliardster")] + [InlineData(2000000000, "zweimilliardster")] + [InlineData(122, "einhundertzweiundzwanzigster")] + [InlineData(3501, "dreitausendfünfhunderterster")] + [InlineData(111, "einhundertelfter")] + [InlineData(1112, "eintausendeinhundertzwölfter")] + [InlineData(11213, "elftausendzweihundertdreizehnter")] + [InlineData(121314, "einhunderteinundzwanzigtausenddreihundertvierzehnter")] + [InlineData(2132415, "zweimillioneneinhundertzweiunddreissigtausendvierhundertfünfzehnter")] + [InlineData(12345516, "zwölfmillionendreihundertfünfundvierzigtausendfünfhundertsechzehnter")] + [InlineData(751633617, "siebenhunderteinundfünfzigmillionensechshundertdreiunddreissigtausendsechshundertsiebzehnter")] + [InlineData(1111111118, "einemilliardeeinhundertelfmillioneneinhundertelftausendeinhundertachtzehnter")] + [InlineData(-751633619, "minus siebenhunderteinundfünfzigmillionensechshundertdreiunddreissigtausendsechshundertneunzehnter")] + public void ToOrdinalWords(int number, string expected) + { + Assert.Equal(expected, number.ToOrdinalWords()); + } + + [Theory] + [InlineData(0, "nullte")] + [InlineData(1, "erste")] + [InlineData(2, "zweite")] + [InlineData(3, "dritte")] + [InlineData(4, "vierte")] + [InlineData(5, "fünfte")] + [InlineData(6, "sechste")] + [InlineData(7, "siebte")] + [InlineData(8, "achte")] + [InlineData(9, "neunte")] + [InlineData(10, "zehnte")] + [InlineData(111, "einhundertelfte")] + [InlineData(1112, "eintausendeinhundertzwölfte")] + [InlineData(11213, "elftausendzweihundertdreizehnte")] + [InlineData(121314, "einhunderteinundzwanzigtausenddreihundertvierzehnte")] + [InlineData(2132415, "zweimillioneneinhundertzweiunddreissigtausendvierhundertfünfzehnte")] + [InlineData(12345516, "zwölfmillionendreihundertfünfundvierzigtausendfünfhundertsechzehnte")] + [InlineData(751633617, "siebenhunderteinundfünfzigmillionensechshundertdreiunddreissigtausendsechshundertsiebzehnte")] + [InlineData(1111111118, "einemilliardeeinhundertelfmillioneneinhundertelftausendeinhundertachtzehnte")] + [InlineData(-751633619, "minus siebenhunderteinundfünfzigmillionensechshundertdreiunddreissigtausendsechshundertneunzehnte")] + public void ToOrdinalWordsFeminine(int number, string expected) + { + Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Feminine)); + } + + [Theory] + [InlineData(0, "nulltes")] + [InlineData(1, "erstes")] + [InlineData(2, "zweites")] + [InlineData(3, "drittes")] + [InlineData(4, "viertes")] + [InlineData(5, "fünftes")] + [InlineData(6, "sechstes")] + [InlineData(7, "siebtes")] + [InlineData(8, "achtes")] + [InlineData(9, "neuntes")] + [InlineData(10, "zehntes")] + [InlineData(111, "einhundertelftes")] + [InlineData(1112, "eintausendeinhundertzwölftes")] + [InlineData(11213, "elftausendzweihundertdreizehntes")] + [InlineData(121314, "einhunderteinundzwanzigtausenddreihundertvierzehntes")] + [InlineData(2132415, "zweimillioneneinhundertzweiunddreissigtausendvierhundertfünfzehntes")] + [InlineData(12345516, "zwölfmillionendreihundertfünfundvierzigtausendfünfhundertsechzehntes")] + [InlineData(751633617, "siebenhunderteinundfünfzigmillionensechshundertdreiunddreissigtausendsechshundertsiebzehntes")] + [InlineData(1111111118, "einemilliardeeinhundertelfmillioneneinhundertelftausendeinhundertachtzehntes")] + [InlineData(-751633619, "minus siebenhunderteinundfünfzigmillionensechshundertdreiunddreissigtausendsechshundertneunzehntes")] + public void ToOrdinalWordsNeuter(int number, string expected) + { + Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Neuter)); + } + } +} diff --git a/src/Humanizer.Tests.Shared/Localisation/de/NumberToWordsTests.cs b/src/Humanizer.Tests.Shared/Localisation/de/NumberToWordsTests.cs index 06dcb8f0b..e5e8d890a 100644 --- a/src/Humanizer.Tests.Shared/Localisation/de/NumberToWordsTests.cs +++ b/src/Humanizer.Tests.Shared/Localisation/de/NumberToWordsTests.cs @@ -7,7 +7,7 @@ public class NumberToWordsTests { [Theory] [InlineData(0, "null")] - [InlineData(1, "eins")] + [InlineData(1, "ein")] [InlineData(2, "zwei")] [InlineData(3, "drei")] [InlineData(4, "vier")] @@ -36,7 +36,7 @@ public class NumberToWordsTests [InlineData(1000000000, "eine Milliarde")] [InlineData(2000000000, "zwei Milliarden")] [InlineData(122, "einhundertzweiundzwanzig")] - [InlineData(3501, "dreitausendfünfhunderteins")] + [InlineData(3501, "dreitausendfünfhundertein")] [InlineData(111, "einhundertelf")] [InlineData(1112, "eintausendeinhundertzwölf")] [InlineData(11213, "elftausendzweihundertdreizehn")] @@ -45,12 +45,23 @@ public class NumberToWordsTests [InlineData(12345516, "zwölf Millionen dreihundertfünfundvierzigtausendfünfhundertsechzehn")] [InlineData(751633617, "siebenhunderteinundfünfzig Millionen sechshundertdreiunddreißigtausendsechshundertsiebzehn")] [InlineData(1111111118, "eine Milliarde einhundertelf Millionen einhundertelftausendeinhundertachtzehn")] + [InlineData(35484694489515, "fünfunddreißig Billionen vierhundertvierundachtzig Milliarden sechshundertvierundneunzig Millionen vierhundertneunundachtzigtausendfünfhundertfünfzehn")] + [InlineData(8183162164626926, "acht Billiarden einhundertdreiundachtzig Billionen einhundertzweiundsechzig Milliarden einhundertvierundsechzig Millionen sechshundertsechsundzwanzigtausendneunhundertsechsundzwanzig")] + [InlineData(4564121926659524672, "vier Trillionen fünfhundertvierundsechzig Billiarden einhunderteinundzwanzig Billionen neunhundertsechsundzwanzig Milliarden sechshundertneunundfünfzig Millionen fünfhundertvierundzwanzigtausendsechshundertzweiundsiebzig")] [InlineData(-751633619, "minus siebenhunderteinundfünfzig Millionen sechshundertdreiunddreißigtausendsechshundertneunzehn")] - public void ToWords(int number, string expected) + public void ToWords(long number, string expected) { Assert.Equal(expected, number.ToWords()); } + [Theory] + [InlineData(1, "eine")] + [InlineData(3501, "dreitausendfünfhunderteine")] + public void ToWordsFeminine(long number, string expected) + { + Assert.Equal(expected, number.ToWords(GrammaticalGender.Feminine)); + } + [Theory] [InlineData(0, "nullter")] [InlineData(1, "erster")] diff --git a/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.cs b/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.cs index cd5bf39ca..d970355e9 100644 --- a/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.cs +++ b/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.cs @@ -1,9 +1,9 @@ #if NET46 -using System.IO; -using ApiApprover; +using System; +using System.Linq; using ApprovalTests; using ApprovalTests.Reporters; -using Mono.Cecil; +using PublicApiGenerator; using Xunit; namespace Humanizer.Tests.ApiApprover @@ -17,21 +17,24 @@ public class PublicApiApprovalTest [IgnoreLineEndings(true)] public void approve_public_api() { - var assemblyPath = typeof(StringHumanizeExtensions).Assembly.Location; - var assemblyResolver = new DefaultAssemblyResolver(); - assemblyResolver.AddSearchDirectory(Path.GetDirectoryName(assemblyPath)); - - var readSymbols = File.Exists(Path.ChangeExtension(assemblyPath, ".pdb")); - var asm = AssemblyDefinition.ReadAssembly(assemblyPath, new ReaderParameters(ReadingMode.Deferred) - { - ReadSymbols = readSymbols, - AssemblyResolver = assemblyResolver - }); - - var publicApi = PublicApiGenerator.CreatePublicApiForAssembly(asm); + var publicApi = Filter(ApiGenerator.GeneratePublicApi(typeof(StringHumanizeExtensions).Assembly)); Approvals.Verify(publicApi); } + + private static string Filter(string text) + { + return string.Join(Environment.NewLine, text.Split(new[] + { + Environment.NewLine + }, StringSplitOptions.RemoveEmptyEntries) + .Where(l => !l.StartsWith("[assembly: AssemblyVersion(")) + .Where(l => !l.StartsWith("[assembly: AssemblyFileVersion(")) + .Where(l => !l.StartsWith("[assembly: AssemblyInformationalVersion(")) + .Where(l => !l.StartsWith("[assembly: System.Reflection.AssemblyMetadataAttribute(\"CommitHash\"")) + .Where(l => !string.IsNullOrWhiteSpace(l)) + ); + } } } -#endif \ No newline at end of file +#endif diff --git a/src/Humanizer.Tests/App_Packages/ApiApprover.3.0.1/PublicApiApprover.cs b/src/Humanizer.Tests/App_Packages/ApiApprover.3.0.1/PublicApiApprover.cs deleted file mode 100644 index e6fc8e78f..000000000 --- a/src/Humanizer.Tests/App_Packages/ApiApprover.3.0.1/PublicApiApprover.cs +++ /dev/null @@ -1,45 +0,0 @@ -#if NET46 -using System.IO; -using ApprovalTests; -using ApprovalTests.Namers; -using Mono.Cecil; - -namespace ApiApprover -{ - public static class PublicApiApprover - { - public static void ApprovePublicApi(string assemblyPath) - { - var assemblyResolver = new DefaultAssemblyResolver(); - assemblyResolver.AddSearchDirectory(Path.GetDirectoryName(assemblyPath)); - - var readSymbols = File.Exists(Path.ChangeExtension(assemblyPath, ".pdb")); - var asm = AssemblyDefinition.ReadAssembly(assemblyPath, new ReaderParameters(ReadingMode.Deferred) - { - ReadSymbols = readSymbols, - AssemblyResolver = assemblyResolver, - }); - - var publicApi = PublicApiGenerator.CreatePublicApiForAssembly(asm); - var writer = new ApprovalTextWriter(publicApi, "cs"); - var approvalNamer = new AssemblyPathNamer(assemblyPath); - ApprovalTests.Approvals.Verify(writer, approvalNamer, ApprovalTests.Approvals.GetReporter()); - } - - private class AssemblyPathNamer : UnitTestFrameworkNamer - { - private readonly string name; - - public AssemblyPathNamer(string assemblyPath) - { - name = Path.GetFileNameWithoutExtension(assemblyPath); - } - - public override string Name - { - get { return name; } - } - } - } -} -#endif \ No newline at end of file diff --git a/src/Humanizer.Tests/App_Packages/ApiApprover.3.0.1/PublicApiGenerator.cs b/src/Humanizer.Tests/App_Packages/ApiApprover.3.0.1/PublicApiGenerator.cs deleted file mode 100644 index 06438ec6e..000000000 --- a/src/Humanizer.Tests/App_Packages/ApiApprover.3.0.1/PublicApiGenerator.cs +++ /dev/null @@ -1,795 +0,0 @@ -#if NET46 -using System; -using System.CodeDom; -using System.CodeDom.Compiler; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using Microsoft.CSharp; -using Mono.Cecil; -using Mono.Cecil.Rocks; -using TypeAttributes = System.Reflection.TypeAttributes; - -// ReSharper disable CheckNamespace -// ReSharper disable BitwiseOperatorOnEnumWithoutFlags -namespace ApiApprover -{ - public static class CecilEx - { - public static IEnumerable GetMembers(this TypeDefinition type) - { - return type.Fields.Cast() - .Concat(type.Methods) - .Concat(type.Properties) - .Concat(type.Events); - } - } - - - public static class PublicApiGenerator - { - // TODO: Assembly references? - // TODO: Better handle namespaces - using statements? - requires non-qualified type names - public static string CreatePublicApiForAssembly(AssemblyDefinition assembly) - { - return CreatePublicApiForAssembly(assembly, t => true, true); - } - - public static string CreatePublicApiForAssembly(AssemblyDefinition assembly, Func shouldIncludeType, bool shouldIncludeAssemblyAttributes) - { - var publicApiBuilder = new StringBuilder(); - var cgo = new CodeGeneratorOptions - { - BracingStyle = "C", - BlankLinesBetweenMembers = false, - VerbatimOrder = false - }; - - using (var provider = new CSharpCodeProvider()) - { - var compileUnit = new CodeCompileUnit(); - if (shouldIncludeAssemblyAttributes && assembly.HasCustomAttributes) - { - PopulateCustomAttributes(assembly, compileUnit.AssemblyCustomAttributes); - } - - var publicTypes = assembly.Modules.SelectMany(m => m.GetTypes()) - .Where(t => !t.IsNested && ShouldIncludeType(t) && shouldIncludeType(t)) - .OrderBy(t => t.FullName); - foreach (var publicType in publicTypes) - { - var @namespace = compileUnit.Namespaces.Cast() - .FirstOrDefault(n => n.Name == publicType.Namespace); - if (@namespace == null) - { - @namespace = new CodeNamespace(publicType.Namespace); - compileUnit.Namespaces.Add(@namespace); - } - - var typeDeclaration = CreateTypeDeclaration(publicType); - @namespace.Types.Add(typeDeclaration); - } - - using (var writer = new StringWriter()) - { - provider.GenerateCodeFromCompileUnit(compileUnit, writer, cgo); - var typeDeclarationText = NormaliseGeneratedCode(writer); - publicApiBuilder.AppendLine(typeDeclarationText); - } - } - return NormaliseLineEndings(publicApiBuilder.ToString().Trim()); - } - - private static string NormaliseLineEndings(string value) - { - return Regex.Replace(value, @"\r\n|\n\r|\r|\n", Environment.NewLine); - } - - private static bool IsDelegate(TypeDefinition publicType) - { - return publicType.BaseType != null && publicType.BaseType.FullName == "System.MulticastDelegate"; - } - - private static bool ShouldIncludeType(TypeDefinition t) - { - return (t.IsPublic || t.IsNestedPublic || t.IsNestedFamily) && !IsCompilerGenerated(t); - } - - private static bool ShouldIncludeMember(IMemberDefinition m) - { - return !IsCompilerGenerated(m) && !IsDotNetTypeMember(m) && !(m is FieldDefinition); - } - - private static bool IsCompilerGenerated(IMemberDefinition m) - { - return m.CustomAttributes.Any(a => a.AttributeType.FullName == "System.Runtime.CompilerServices.CompilerGeneratedAttribute"); - } - - private static bool IsDotNetTypeMember(IMemberDefinition m) - { - if (m.DeclaringType == null || m.DeclaringType.FullName == null) - return false; - return m.DeclaringType.FullName.StartsWith("System") || m.DeclaringType.FullName.StartsWith("Microsoft"); - } - - static void AddMemberToTypeDeclaration(CodeTypeDeclaration typeDeclaration, IMemberDefinition memberInfo) - { - if (memberInfo is MethodDefinition methodDefinition) - { - if (methodDefinition.IsConstructor) - AddCtorToTypeDeclaration(typeDeclaration, methodDefinition); - else - AddMethodToTypeDeclaration(typeDeclaration, methodDefinition); - } - else if (memberInfo is PropertyDefinition) - { - AddPropertyToTypeDeclaration(typeDeclaration, (PropertyDefinition)memberInfo); - } - else if (memberInfo is EventDefinition) - { - typeDeclaration.Members.Add(GenerateEvent((EventDefinition)memberInfo)); - } - else if (memberInfo is FieldDefinition) - { - AddFieldToTypeDeclaration(typeDeclaration, (FieldDefinition)memberInfo); - } - } - - static string NormaliseGeneratedCode(StringWriter writer) - { - var gennedClass = writer.ToString(); - const string autoGeneratedHeader = @"^//-+\s*$.*^//-+\s*$"; - const string emptyGetSet = @"\s+{\s+get\s+{\s+}\s+set\s+{\s+}\s+}"; - const string emptyGet = @"\s+{\s+get\s+{\s+}\s+}"; - const string emptySet = @"\s+{\s+set\s+{\s+}\s+}"; - const string getSet = @"\s+{\s+get;\s+set;\s+}"; - const string get = @"\s+{\s+get;\s+}"; - const string set = @"\s+{\s+set;\s+}"; - gennedClass = Regex.Replace(gennedClass, autoGeneratedHeader, string.Empty, - RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline | RegexOptions.Singleline); - gennedClass = Regex.Replace(gennedClass, emptyGetSet, " { get; set; }", RegexOptions.IgnorePatternWhitespace); - gennedClass = Regex.Replace(gennedClass, getSet, " { get; set; }", RegexOptions.IgnorePatternWhitespace); - gennedClass = Regex.Replace(gennedClass, emptyGet, " { get; }", RegexOptions.IgnorePatternWhitespace); - gennedClass = Regex.Replace(gennedClass, emptySet, " { set; }", RegexOptions.IgnorePatternWhitespace); - gennedClass = Regex.Replace(gennedClass, get, " { get; }", RegexOptions.IgnorePatternWhitespace); - gennedClass = Regex.Replace(gennedClass, set, " { set; }", RegexOptions.IgnorePatternWhitespace); - gennedClass = Regex.Replace(gennedClass, @"\s+{\s+}", " { }", RegexOptions.IgnorePatternWhitespace); - gennedClass = Regex.Replace(gennedClass, @"\)\s+;", ");", RegexOptions.IgnorePatternWhitespace); - return gennedClass; - } - - static CodeTypeDeclaration CreateTypeDeclaration(TypeDefinition publicType) - { - if (IsDelegate(publicType)) - return CreateDelegateDeclaration(publicType); - - bool @static = false; - TypeAttributes attributes = 0; - if (publicType.IsPublic || publicType.IsNestedPublic) - attributes |= TypeAttributes.Public; - if (publicType.IsNestedFamily) - attributes |= TypeAttributes.NestedFamily; - if (publicType.IsSealed && !publicType.IsAbstract) - attributes |= TypeAttributes.Sealed; - else if (!publicType.IsSealed && publicType.IsAbstract && !publicType.IsInterface) - attributes |= TypeAttributes.Abstract; - else if (publicType.IsSealed && publicType.IsAbstract) - @static = true; - - // Static support is a hack. CodeDOM does support it, and this isn't - // correct C#, but it's good enough for our API outline - var name = publicType.Name; - - var index = name.IndexOf('`'); - if (index != -1) - name = name.Substring(0, index); - var declaration = new CodeTypeDeclaration(@static ? "static " + name : name) - { - CustomAttributes = CreateCustomAttributes(publicType), - // TypeAttributes must be specified before the IsXXX as they manipulate TypeAttributes! - TypeAttributes = attributes, - IsClass = publicType.IsClass, - IsEnum = publicType.IsEnum, - IsInterface = publicType.IsInterface, - IsStruct = publicType.IsValueType && !publicType.IsPrimitive && !publicType.IsEnum, - }; - - if (declaration.IsInterface && publicType.BaseType != null) - throw new NotImplementedException("Base types for interfaces needs testing"); - - PopulateGenericParameters(publicType, declaration.TypeParameters); - - if (publicType.BaseType != null && ShouldOutputBaseType(publicType)) - { - if (publicType.BaseType.FullName == "System.Enum") - { - var underlyingType = publicType.GetEnumUnderlyingType(); - if (underlyingType.FullName != "System.Int32") - declaration.BaseTypes.Add(CreateCodeTypeReference(underlyingType)); - } - else - declaration.BaseTypes.Add(CreateCodeTypeReference(publicType.BaseType)); - } - foreach (var @interface in publicType.Interfaces.OrderBy(i => i.FullName)) - declaration.BaseTypes.Add(CreateCodeTypeReference(@interface)); - - foreach (var memberInfo in publicType.GetMembers().Where(ShouldIncludeMember).OrderBy(m => m.Name)) - AddMemberToTypeDeclaration(declaration, memberInfo); - - // Fields should be in defined order for an enum - var fields = !publicType.IsEnum - ? publicType.Fields.OrderBy(f => f.Name) - : (IEnumerable)publicType.Fields; - foreach (var field in fields) - AddMemberToTypeDeclaration(declaration, field); - - foreach (var nestedType in publicType.NestedTypes.Where(ShouldIncludeType).OrderBy(t => t.FullName)) - { - var nestedTypeDeclaration = CreateTypeDeclaration(nestedType); - declaration.Members.Add(nestedTypeDeclaration); - } - - return declaration; - } - - private static CodeTypeDeclaration CreateDelegateDeclaration(TypeDefinition publicType) - { - var invokeMethod = publicType.Methods.Single(m => m.Name == "Invoke"); - var name = publicType.Name; - var index = name.IndexOf('`'); - if (index != -1) - name = name.Substring(0, index); - var declaration = new CodeTypeDelegate(name) - { - Attributes = MemberAttributes.Public, - CustomAttributes = CreateCustomAttributes(publicType), - ReturnType = CreateCodeTypeReference(invokeMethod.ReturnType), - }; - - // CodeDOM. No support. Return type attributes. - PopulateCustomAttributes(invokeMethod.MethodReturnType, declaration.CustomAttributes, type => ModifyCodeTypeReference(type, "return:")); - PopulateGenericParameters(publicType, declaration.TypeParameters); - PopulateMethodParameters(invokeMethod, declaration.Parameters); - - // Of course, CodeDOM doesn't support generic type parameters for delegates. Of course. - if (declaration.TypeParameters.Count > 0) - { - var parameterNames = from parameterType in declaration.TypeParameters.Cast() - select parameterType.Name; - declaration.Name = string.Format("{0}<{1}>", declaration.Name, string.Join(", ", parameterNames)); - } - - return declaration; - } - - private static bool ShouldOutputBaseType(TypeDefinition publicType) - { - return publicType.BaseType.FullName != "System.Object" && publicType.BaseType.FullName != "System.ValueType"; - } - - private static void PopulateGenericParameters(IGenericParameterProvider publicType, CodeTypeParameterCollection parameters) - { - foreach (var parameter in publicType.GenericParameters) - { - if (parameter.HasCustomAttributes) - throw new NotImplementedException("Attributes on type parameters is not supported. And weird"); - - // A little hacky. Means we get "in" and "out" prefixed on any constraints, but it's either that - // or add it as a custom attribute, which looks even weirder - var name = parameter.Name; - if (parameter.IsCovariant) - name = "out " + name; - if (parameter.IsContravariant) - name = "in " + name; - - var typeParameter = new CodeTypeParameter(name) - { - HasConstructorConstraint = - parameter.HasDefaultConstructorConstraint && !parameter.HasNotNullableValueTypeConstraint - }; - if (parameter.HasNotNullableValueTypeConstraint) - typeParameter.Constraints.Add(" struct"); // Extra space is a hack! - if (parameter.HasReferenceTypeConstraint) - typeParameter.Constraints.Add(" class"); - foreach (var constraint in parameter.Constraints.Where(t => t.FullName != "System.ValueType")) - { - typeParameter.Constraints.Add(CreateCodeTypeReference(constraint.GetElementType())); - } - parameters.Add(typeParameter); - } - } - - private static CodeAttributeDeclarationCollection CreateCustomAttributes(ICustomAttributeProvider type) - { - var attributes = new CodeAttributeDeclarationCollection(); - PopulateCustomAttributes(type, attributes); - return attributes; - } - - private static void PopulateCustomAttributes(ICustomAttributeProvider type, - CodeAttributeDeclarationCollection attributes) - { - PopulateCustomAttributes(type, attributes, ctr => ctr); - } - - private static void PopulateCustomAttributes(ICustomAttributeProvider type, - CodeAttributeDeclarationCollection attributes, Func codeTypeModifier) - { - foreach (var customAttribute in type.CustomAttributes.Where(ShouldIncludeAttribute).OrderBy(a => a.AttributeType.FullName).ThenBy(a => ConvertAttrbuteToCode(codeTypeModifier, a))) - { - var attribute = GenerateCodeAttributeDeclaration(codeTypeModifier, customAttribute); - attributes.Add(attribute); - } - } - - private static CodeAttributeDeclaration GenerateCodeAttributeDeclaration(Func codeTypeModifier, CustomAttribute customAttribute) - { - var attribute = new CodeAttributeDeclaration(codeTypeModifier(CreateCodeTypeReference(customAttribute.AttributeType))); - foreach (var arg in customAttribute.ConstructorArguments) - { - attribute.Arguments.Add(new CodeAttributeArgument(CreateInitialiserExpression(arg))); - } - foreach (var field in customAttribute.Fields.OrderBy(f => f.Name)) - { - attribute.Arguments.Add(new CodeAttributeArgument(field.Name, CreateInitialiserExpression(field.Argument))); - } - foreach (var property in customAttribute.Properties.OrderBy(p => p.Name)) - { - attribute.Arguments.Add(new CodeAttributeArgument(property.Name, CreateInitialiserExpression(property.Argument))); - } - return attribute; - } - - // Litee: This method is used for additional sorting of custom attributes when multiple values are allowed - private static object ConvertAttrbuteToCode(Func codeTypeModifier, CustomAttribute customAttribute) - { - using (var provider = new CSharpCodeProvider()) - { - var cgo = new CodeGeneratorOptions - { - BracingStyle = "C", - BlankLinesBetweenMembers = false, - VerbatimOrder = false - }; - var attribute = GenerateCodeAttributeDeclaration(codeTypeModifier, customAttribute); - var declaration = new CodeTypeDeclaration("DummyClass") - { - CustomAttributes = new CodeAttributeDeclarationCollection(new[] { attribute }), - }; - using (var writer = new StringWriter()) - { - provider.GenerateCodeFromType(declaration, writer, cgo); - return writer.ToString(); - } - } - } - - private static readonly HashSet SkipAttributeNames = new HashSet - { - "System.CodeDom.Compiler.GeneratedCodeAttribute", - "System.ComponentModel.EditorBrowsableAttribute", - "System.Runtime.CompilerServices.AsyncStateMachineAttribute", - "System.Runtime.CompilerServices.CompilerGeneratedAttribute", - "System.Runtime.CompilerServices.CompilationRelaxationsAttribute", - "System.Runtime.CompilerServices.ExtensionAttribute", - "System.Runtime.CompilerServices.RuntimeCompatibilityAttribute", - "System.Reflection.DefaultMemberAttribute", - "System.Diagnostics.DebuggableAttribute", - "System.Diagnostics.DebuggerNonUserCodeAttribute", - "System.Diagnostics.DebuggerStepThroughAttribute", - "System.Reflection.AssemblyCompanyAttribute", - "System.Reflection.AssemblyConfigurationAttribute", - "System.Reflection.AssemblyCopyrightAttribute", - "System.Reflection.AssemblyDescriptionAttribute", - "System.Reflection.AssemblyFileVersionAttribute", - "System.Reflection.AssemblyInformationalVersionAttribute", - "System.Reflection.AssemblyProductAttribute", - "System.Reflection.AssemblyTitleAttribute", - "System.Reflection.AssemblyTrademarkAttribute" - }; - - private static bool ShouldIncludeAttribute(CustomAttribute attribute) - { - return !SkipAttributeNames.Contains(attribute.AttributeType.FullName); - } - - private static CodeExpression CreateInitialiserExpression(CustomAttributeArgument attributeArgument) - { - if (attributeArgument.Value is CustomAttributeArgument) - { - return CreateInitialiserExpression((CustomAttributeArgument) attributeArgument.Value); - } - - if (attributeArgument.Value is CustomAttributeArgument[]) - { - var initialisers = from argument in (CustomAttributeArgument[]) attributeArgument.Value - select CreateInitialiserExpression(argument); - return new CodeArrayCreateExpression(CreateCodeTypeReference(attributeArgument.Type), initialisers.ToArray()); - } - - var type = attributeArgument.Type.Resolve(); - var value = attributeArgument.Value; - if (type.BaseType != null && type.BaseType.FullName == "System.Enum") - { - var originalValue = Convert.ToInt64(value); - if (type.CustomAttributes.Any(a => a.AttributeType.FullName == "System.FlagsAttribute")) - { - //var allFlags = from f in type.Fields - // where f.Constant != null - // let v = Convert.ToInt64(f.Constant) - // where v == 0 || (originalValue & v) != 0 - // select (CodeExpression)new CodeFieldReferenceExpression(typeExpression, f.Name); - //return allFlags.Aggregate((current, next) => new CodeBinaryOperatorExpression(current, CodeBinaryOperatorType.BitwiseOr, next)); - - // I'd rather use the above, as it's just using the CodeDOM, but it puts - // brackets around each CodeBinaryOperatorExpression - var flags = from f in type.Fields - where f.Constant != null - let v = Convert.ToInt64(f.Constant) - where v == 0 || (originalValue & v) != 0 - select type.FullName + "." + f.Name; - return new CodeSnippetExpression(flags.Aggregate((current, next) => current + " | " + next)); - } - - var allFlags = from f in type.Fields - where f.Constant != null - let v = Convert.ToInt64(f.Constant) - where v == originalValue - select new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(CreateCodeTypeReference(type)), f.Name); - return allFlags.FirstOrDefault(); - } - - if (type.FullName == "System.Type" && value is TypeReference) - { - return new CodeTypeOfExpression(CreateCodeTypeReference((TypeReference)value)); - } - - if (value is string) - { - // CodeDOM outputs a verbatim string. Any string with \n is treated as such, so normalise - // it to make it easier for comparisons - value = Regex.Replace((string)value, @"\n", "\\n"); - value = Regex.Replace((string)value, @"\r\n|\r\\n", "\\r\\n"); - } - - return new CodePrimitiveExpression(value); - } - - private static void AddCtorToTypeDeclaration(CodeTypeDeclaration typeDeclaration, MethodDefinition member) - { - if (member.IsAssembly || member.IsPrivate) - return; - - var method = new CodeConstructor - { - CustomAttributes = CreateCustomAttributes(member), - Name = member.Name, - Attributes = GetMethodAttributes(member) - }; - PopulateMethodParameters(member, method.Parameters); - - typeDeclaration.Members.Add(method); - } - - private static void AddMethodToTypeDeclaration(CodeTypeDeclaration typeDeclaration, MethodDefinition member) - { - if (member.IsAssembly || member.IsPrivate || member.IsSpecialName) - return; - - var returnType = CreateCodeTypeReference(member.ReturnType); - if (IsAsyncMethod(member)) - returnType = MakeAsync(returnType); - - var method = new CodeMemberMethod - { - Name = member.Name, - Attributes = GetMethodAttributes(member), - CustomAttributes = CreateCustomAttributes(member), - ReturnType = returnType, - }; - PopulateCustomAttributes(member.MethodReturnType, method.ReturnTypeCustomAttributes); - PopulateGenericParameters(member, method.TypeParameters); - PopulateMethodParameters(member, method.Parameters, IsExtensionMethod(member)); - - typeDeclaration.Members.Add(method); - } - - private static bool IsAsyncMethod(ICustomAttributeProvider method) - { - return method.CustomAttributes.Any(a => a.AttributeType.FullName == "System.Runtime.CompilerServices.AsyncStateMachineAttribute"); - } - - private static bool IsExtensionMethod(ICustomAttributeProvider method) - { - return method.CustomAttributes.Any(a => a.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute"); - } - - private static void PopulateMethodParameters(IMethodSignature member, - CodeParameterDeclarationExpressionCollection parameters, bool isExtension = false) - { - foreach (var parameter in member.Parameters) - { - FieldDirection direction = 0; - if (parameter.IsOut) - direction |= FieldDirection.Out; - else if (parameter.ParameterType.IsByReference) - direction |= FieldDirection.Ref; - - var parameterType = parameter.ParameterType.IsByReference - ? parameter.ParameterType.GetElementType() - : parameter.ParameterType; - - var type = CreateCodeTypeReference(parameterType); - - if (isExtension) - { - type = ModifyCodeTypeReference(type, "this"); - isExtension = false; - } - - var name = parameter.HasConstant - ? string.Format("{0} = {1}", parameter.Name, FormatParameterConstant(parameter)) - : parameter.Name; - var expression = new CodeParameterDeclarationExpression(type, name) - { - Direction = direction, - CustomAttributes = CreateCustomAttributes(parameter) - }; - parameters.Add(expression); - } - } - - private static object FormatParameterConstant(IConstantProvider parameter) - { - return parameter.Constant is string ? string.Format("\"{0}\"", parameter.Constant) : (parameter.Constant ?? "null"); - } - - static MemberAttributes GetMethodAttributes(MethodDefinition method) - { - MemberAttributes access = 0; - if (method.IsFamily) - access = MemberAttributes.Family; - if (method.IsPublic) - access = MemberAttributes.Public; - if (method.IsAssembly) - access = MemberAttributes.Assembly; - if (method.IsFamilyAndAssembly) - access = MemberAttributes.FamilyAndAssembly; - if (method.IsFamilyOrAssembly) - access = MemberAttributes.FamilyOrAssembly; - - MemberAttributes scope = 0; - if (method.IsStatic) - scope |= MemberAttributes.Static; - if (method.IsFinal || !method.IsVirtual) - scope |= MemberAttributes.Final; - if (method.IsAbstract) - scope |= MemberAttributes.Abstract; - if (method.IsVirtual && !method.IsNewSlot) - scope |= MemberAttributes.Override; - - MemberAttributes vtable = 0; - if (IsHidingMethod(method)) - vtable = MemberAttributes.New; - - return access | scope | vtable; - } - - private static bool IsHidingMethod(MethodDefinition method) - { - var typeDefinition = method.DeclaringType; - - // If we're an interface, just try and find any method with the same signature - // in any of the interfaces that we implement - if (typeDefinition.IsInterface) - { - var interfaceMethods = from @interfaceReference in typeDefinition.Interfaces - let interfaceDefinition = @interfaceReference.Resolve() - where interfaceDefinition != null - select interfaceDefinition.Methods; - - return interfaceMethods.Any(ms => MetadataResolver.GetMethod(ms, method) != null); - } - - // If we're not an interface, find a base method that isn't virtual - return !method.IsVirtual && GetBaseTypes(typeDefinition).Any(d => MetadataResolver.GetMethod(d.Methods, method) != null); - } - - private static IEnumerable GetBaseTypes(TypeDefinition type) - { - var baseType = type.BaseType; - while (baseType != null) - { - var definition = baseType.Resolve(); - if (definition == null) - yield break; - yield return definition; - - baseType = baseType.DeclaringType; - } - } - - private static void AddPropertyToTypeDeclaration(CodeTypeDeclaration typeDeclaration, PropertyDefinition member) - { - var getterAttributes = member.GetMethod != null ? GetMethodAttributes(member.GetMethod) : 0; - var setterAttributes = member.SetMethod != null ? GetMethodAttributes(member.SetMethod) : 0; - - if (!HasVisiblePropertyMethod(getterAttributes) && !HasVisiblePropertyMethod(setterAttributes)) - return; - - var propertyAttributes = GetPropertyAttributes(getterAttributes, setterAttributes); - - var propertyType = member.PropertyType.IsGenericParameter - ? new CodeTypeReference(member.PropertyType.Name) - : CreateCodeTypeReference(member.PropertyType); - - var property = new CodeMemberProperty - { - Name = member.Name, - Type = propertyType, - Attributes = propertyAttributes, - CustomAttributes = CreateCustomAttributes(member), - HasGet = member.GetMethod != null && HasVisiblePropertyMethod(getterAttributes), - HasSet = member.SetMethod != null && HasVisiblePropertyMethod(setterAttributes) - }; - - // Here's a nice hack, because hey, guess what, the CodeDOM doesn't support - // attributes on getters or setters - if (member.GetMethod != null && member.GetMethod.HasCustomAttributes) - { - PopulateCustomAttributes(member.GetMethod, property.CustomAttributes, type => ModifyCodeTypeReference(type, "get:")); - } - if (member.SetMethod != null && member.SetMethod.HasCustomAttributes) - { - PopulateCustomAttributes(member.GetMethod, property.CustomAttributes, type => ModifyCodeTypeReference(type, "set:")); - } - - foreach (var parameter in member.Parameters) - { - property.Parameters.Add( - new CodeParameterDeclarationExpression(CreateCodeTypeReference(parameter.ParameterType), - parameter.Name)); - } - - // TODO: CodeDOM has no support for different access modifiers for getters and setters - // TODO: CodeDOM has no support for attributes on setters or getters - promote to property? - - typeDeclaration.Members.Add(property); - } - - private static MemberAttributes GetPropertyAttributes(MemberAttributes getterAttributes, MemberAttributes setterAttributes) - { - MemberAttributes access = 0; - var getterAccess = getterAttributes & MemberAttributes.AccessMask; - var setterAccess = setterAttributes & MemberAttributes.AccessMask; - if (getterAccess == MemberAttributes.Public || setterAccess == MemberAttributes.Public) - access = MemberAttributes.Public; - else if (getterAccess == MemberAttributes.Family || setterAccess == MemberAttributes.Family) - access = MemberAttributes.Family; - else if (getterAccess == MemberAttributes.FamilyAndAssembly || setterAccess == MemberAttributes.FamilyAndAssembly) - access = MemberAttributes.FamilyAndAssembly; - else if (getterAccess == MemberAttributes.FamilyOrAssembly || setterAccess == MemberAttributes.FamilyOrAssembly) - access = MemberAttributes.FamilyOrAssembly; - else if (getterAccess == MemberAttributes.Assembly || setterAccess == MemberAttributes.Assembly) - access = MemberAttributes.Assembly; - else if (getterAccess == MemberAttributes.Private || setterAccess == MemberAttributes.Private) - access = MemberAttributes.Private; - - // Scope should be the same for getter and setter. If one isn't specified, it'll be 0 - var getterScope = getterAttributes & MemberAttributes.ScopeMask; - var setterScope = setterAttributes & MemberAttributes.ScopeMask; - var scope = (MemberAttributes) Math.Max((int) getterScope, (int) setterScope); - - // Vtable should be the same for getter and setter. If one isn't specified, it'll be 0 - var getterVtable = getterAttributes & MemberAttributes.VTableMask; - var setterVtable = setterAttributes & MemberAttributes.VTableMask; - var vtable = (MemberAttributes) Math.Max((int) getterVtable, (int) setterVtable); - - return access | scope | vtable; - } - - private static bool HasVisiblePropertyMethod(MemberAttributes attributes) - { - var access = attributes & MemberAttributes.AccessMask; - return access == MemberAttributes.Public || access == MemberAttributes.Family || - access == MemberAttributes.FamilyOrAssembly; - } - - static CodeTypeMember GenerateEvent(EventDefinition eventDefinition) - { - var @event = new CodeMemberEvent - { - Name = eventDefinition.Name, - Attributes = MemberAttributes.Public | MemberAttributes.Final, - CustomAttributes = CreateCustomAttributes(eventDefinition), - Type = CreateCodeTypeReference(eventDefinition.EventType) - }; - - return @event; - } - - static void AddFieldToTypeDeclaration(CodeTypeDeclaration typeDeclaration, FieldDefinition memberInfo) - { - if (memberInfo.IsPrivate || memberInfo.IsAssembly || memberInfo.IsSpecialName) - return; - - MemberAttributes attributes = 0; - if (memberInfo.HasConstant) - attributes |= MemberAttributes.Const; - if (memberInfo.IsFamily) - attributes |= MemberAttributes.Family; - if (memberInfo.IsPublic) - attributes |= MemberAttributes.Public; - if (memberInfo.IsStatic && !memberInfo.HasConstant) - attributes |= MemberAttributes.Static; - - // TODO: Values for readonly fields are set in the ctor - var codeTypeReference = CreateCodeTypeReference(memberInfo.FieldType); - if (memberInfo.IsInitOnly) - codeTypeReference = MakeReadonly(codeTypeReference); - var field = new CodeMemberField(codeTypeReference, memberInfo.Name) - { - Attributes = attributes, - CustomAttributes = CreateCustomAttributes(memberInfo) - }; - - if (memberInfo.HasConstant) - field.InitExpression = new CodePrimitiveExpression(memberInfo.Constant); - - typeDeclaration.Members.Add(field); - } - - private static CodeTypeReference MakeReadonly(CodeTypeReference typeReference) - { - return ModifyCodeTypeReference(typeReference, "readonly"); - } - - private static CodeTypeReference MakeAsync(CodeTypeReference typeReference) - { - return ModifyCodeTypeReference(typeReference, "async"); - } - - private static CodeTypeReference ModifyCodeTypeReference(CodeTypeReference typeReference, string modifier) - { - using (var provider = new CSharpCodeProvider()) - return new CodeTypeReference(modifier + " " + provider.GetTypeOutput(typeReference)); - } - - private static CodeTypeReference CreateCodeTypeReference(TypeReference type) - { - var typeName = GetTypeName(type); - return new CodeTypeReference(typeName, CreateGenericArguments(type)); - } - - private static string GetTypeName(TypeReference type) - { - if (type.IsGenericParameter) - return type.Name; - - if (!type.IsNested) - { - return (!string.IsNullOrEmpty(type.Namespace) ? (type.Namespace + ".") : "") + type.Name; - } - - return GetTypeName(type.DeclaringType) + "." + type.Name; - } - - private static CodeTypeReference[] CreateGenericArguments(TypeReference type) - { - var genericInstance = type as IGenericInstance; - if (genericInstance == null) return null; - - var genericArguments = new List(); - foreach (var argument in genericInstance.GenericArguments) - { - genericArguments.Add(CreateCodeTypeReference(argument)); - } - return genericArguments.ToArray(); - } - } -} -// ReSharper restore BitwiseOperatorOnEnumWihtoutFlags -// ReSharper restore CheckNamespace -#endif diff --git a/src/Humanizer.Tests/Humanizer.Tests.csproj b/src/Humanizer.Tests/Humanizer.Tests.csproj index 2bab8a48e..5ac882661 100644 --- a/src/Humanizer.Tests/Humanizer.Tests.csproj +++ b/src/Humanizer.Tests/Humanizer.Tests.csproj @@ -1,22 +1,21 @@  - net46;netcoreapp2.0 + net46;netcoreapp2.1 - + $(DefineConstants);NETFX_CORE - - - - + + + - - + + @@ -24,7 +23,9 @@ - + + PreserveNewest + PreserveNewest diff --git a/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt b/src/Humanizer.Tests/PublicApiApprovalTest.approve_public_api.approved.txt similarity index 99% rename from src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt rename to src/Humanizer.Tests/PublicApiApprovalTest.approve_public_api.approved.txt index c62df0d51..433b7b3c8 100644 --- a/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt +++ b/src/Humanizer.Tests/PublicApiApprovalTest.approve_public_api.approved.txt @@ -1,9 +1,7 @@ [assembly: System.Resources.NeutralResourcesLanguageAttribute("en")] [assembly: System.Runtime.Versioning.TargetFrameworkAttribute(".NETStandard,Version=v1.0", FrameworkDisplayName="")] - namespace Humanizer.Bytes { - public class ByteRate { public ByteRate(Humanizer.Bytes.ByteSize size, System.TimeSpan interval) { } @@ -63,7 +61,6 @@ namespace Humanizer.Bytes } namespace Humanizer { - public class static ByteSizeExtensions { public static Humanizer.Bytes.ByteSize Bits(this byte input) { } @@ -1020,7 +1017,6 @@ namespace Humanizer } namespace Humanizer.Configuration { - public class static Configurator { public static Humanizer.Configuration.LocaliserRegistry CollectionFormatters { get; } @@ -1045,7 +1041,6 @@ namespace Humanizer.Configuration } namespace Humanizer.DateTimeHumanizeStrategy { - public class DefaultDateTimeHumanizeStrategy : Humanizer.DateTimeHumanizeStrategy.IDateTimeHumanizeStrategy { public DefaultDateTimeHumanizeStrategy() { } @@ -1077,7 +1072,6 @@ namespace Humanizer.DateTimeHumanizeStrategy } namespace Humanizer.Inflections { - public class static Vocabularies { public static Humanizer.Inflections.Vocabulary Default { get; } @@ -1094,7 +1088,6 @@ namespace Humanizer.Inflections } namespace Humanizer.Localisation.CollectionFormatters { - public interface ICollectionFormatter { string Humanize(System.Collections.Generic.IEnumerable collection); @@ -1107,7 +1100,6 @@ namespace Humanizer.Localisation.CollectionFormatters } namespace Humanizer.Localisation.DateToOrdinalWords { - public interface IDateToOrdinalWordConverter { string Convert(System.DateTime date); @@ -1116,7 +1108,6 @@ namespace Humanizer.Localisation.DateToOrdinalWords } namespace Humanizer.Localisation.Formatters { - public class DefaultFormatter : Humanizer.Localisation.Formatters.IFormatter { public DefaultFormatter(string localeCode) { } @@ -1141,7 +1132,6 @@ namespace Humanizer.Localisation.Formatters } namespace Humanizer.Localisation.NumberToWords { - public interface INumberToWordsConverter { string Convert(long number); @@ -1152,7 +1142,6 @@ namespace Humanizer.Localisation.NumberToWords } namespace Humanizer.Localisation.Ordinalizers { - public interface IOrdinalizer { string Convert(int number, string numberString); @@ -1161,7 +1150,6 @@ namespace Humanizer.Localisation.Ordinalizers } namespace Humanizer.Localisation { - public class ResourceKeys { public ResourceKeys() { } diff --git a/src/Humanizer.sln b/src/Humanizer.sln index 7a62ee41a..2bfaf0a70 100644 --- a/src/Humanizer.sln +++ b/src/Humanizer.sln @@ -12,7 +12,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ..\.editorconfig = ..\.editorconfig ..\.gitattributes = ..\.gitattributes ..\.gitignore = ..\.gitignore - ..\appveyor.yml = ..\appveyor.yml ..\NuSpecs\Humanizer.Core.nuspec = ..\NuSpecs\Humanizer.Core.nuspec ..\NuSpecs\Humanizer.nuspec = ..\NuSpecs\Humanizer.nuspec ..\LICENSE = ..\LICENSE @@ -23,7 +22,6 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{97AAE24D-0488-42AE-A585-86D882F23D5F}" ProjectSection(SolutionItems) = preProject ..\build.cmd = ..\build.cmd - ..\build.proj = ..\build.proj Humanizer.ruleset = Humanizer.ruleset EndProjectSection EndProject @@ -41,6 +39,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NuSpecs", "NuSpecs", "{AA44 ..\NuSpecs\Humanizer.Core.bn-BD.nuspec = ..\NuSpecs\Humanizer.Core.bn-BD.nuspec ..\NuSpecs\Humanizer.Core.cs.nuspec = ..\NuSpecs\Humanizer.Core.cs.nuspec ..\NuSpecs\Humanizer.Core.da.nuspec = ..\NuSpecs\Humanizer.Core.da.nuspec + ..\NuSpecs\Humanizer.Core.de-CH.nuspec = ..\NuSpecs\Humanizer.Core.de-CH.nuspec + ..\NuSpecs\Humanizer.Core.de-LI.nuspec = ..\NuSpecs\Humanizer.Core.de-LI.nuspec ..\NuSpecs\Humanizer.Core.de.nuspec = ..\NuSpecs\Humanizer.Core.de.nuspec ..\NuSpecs\Humanizer.Core.el.nuspec = ..\NuSpecs\Humanizer.Core.el.nuspec ..\NuSpecs\Humanizer.Core.es.nuspec = ..\NuSpecs\Humanizer.Core.es.nuspec diff --git a/src/Humanizer/Configuration/NumberToWordsConverterRegistry.cs b/src/Humanizer/Configuration/NumberToWordsConverterRegistry.cs index 7e582082f..f5f1d76ad 100644 --- a/src/Humanizer/Configuration/NumberToWordsConverterRegistry.cs +++ b/src/Humanizer/Configuration/NumberToWordsConverterRegistry.cs @@ -24,6 +24,8 @@ public NumberToWordsConverterRegistry() Register("he", (culture) => new HebrewNumberToWordsConverter(culture)); Register("sl", (culture) => new SlovenianNumberToWordsConverter(culture)); Register("de", new GermanNumberToWordsConverter()); + Register("de-CH", new GermanSwissLiechtensteinNumberToWordsConverter()); + Register("de-LI", new GermanSwissLiechtensteinNumberToWordsConverter()); Register("bn-BD", new BanglaNumberToWordsConverter()); Register("tr", new TurkishNumberToWordConverter()); Register("it", new ItalianNumberToWordsConverter()); diff --git a/src/Humanizer/Humanizer.csproj b/src/Humanizer/Humanizer.csproj index a187b776f..2e9a2bfc3 100644 --- a/src/Humanizer/Humanizer.csproj +++ b/src/Humanizer/Humanizer.csproj @@ -1,12 +1,12 @@  - netstandard1.0 + netstandard1.0;netstandard2.0 Mehdi Khalili, Oren Novotny https://raw.githubusercontent.com/Humanizr/Humanizer/master/LICENSE https://github.com/Humanizr/Humanizer 2.12 A micro-framework that turns your normal strings, type names, enum fields, date fields ETC into a human friendly format - Copyright © 2012-2017 Mehdi Khalili + Copyright © 2012-2018 Mehdi Khalili Humanizer ($(TargetFramework)) true true diff --git a/src/Humanizer/Localisation/NumberToWords/ArabicNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/ArabicNumberToWordsConverter.cs index ae6f47276..a3fd652df 100644 --- a/src/Humanizer/Localisation/NumberToWords/ArabicNumberToWordsConverter.cs +++ b/src/Humanizer/Localisation/NumberToWords/ArabicNumberToWordsConverter.cs @@ -17,16 +17,12 @@ internal class ArabicNumberToWordsConverter : GenderedNumberToWordsConverter private static readonly string[] FeminineOnesGroup = { "", "واحدة", "اثنتان", "ثلاث", "أربع", "خمس", "ست", "سبع", "ثمان", "تسع", "عشر", "إحدى عشرة", "اثنتا عشرة", "ثلاث عشرة", "أربع عشرة", "خمس عشرة", "ست عشرة", "سبع عشرة", "ثمان عشرة", "تسع عشرة" }; - public override string Convert(long input, GrammaticalGender gender) + public override string Convert(long number, GrammaticalGender gender) { - if (input > Int32.MaxValue || input < Int32.MinValue) - { - throw new NotImplementedException(); - } - var number = (int)input; - if (number == 0) return "صفر"; + if (number < 0) + return string.Format("ناقص {0}", Convert(-number, gender)); var result = string.Empty; var groupLevel = 0; @@ -225,4 +221,4 @@ private static string ParseNumber(string word, int number, GrammaticalGender gen return word; } } -} \ No newline at end of file +} diff --git a/src/Humanizer/Localisation/NumberToWords/GermanNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/GermanNumberToWordsConverter.cs index 9ca130a4e..7e2f5c29c 100644 --- a/src/Humanizer/Localisation/NumberToWords/GermanNumberToWordsConverter.cs +++ b/src/Humanizer/Localisation/NumberToWords/GermanNumberToWordsConverter.cs @@ -1,166 +1,6 @@ -using System; -using System.Collections.Generic; - -namespace Humanizer.Localisation.NumberToWords +namespace Humanizer.Localisation.NumberToWords { - internal class GermanNumberToWordsConverter : GenderedNumberToWordsConverter + internal class GermanNumberToWordsConverter : GermanNumberToWordsConverterBase { - 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" }; - private static readonly string[] UnitsOrdinal = { string.Empty, "ers", "zwei", "drit", "vier", "fünf", "sechs", "sieb", "ach", "neun", "zehn", "elf", "zwölf", "dreizehn", "vierzehn", "fünfzehn", "sechzehn", "siebzehn", "achtzehn", "neunzehn" }; - private static readonly string[] MillionOrdinalSingular = {"einmillion", "einemillion"}; - private static readonly string[] MillionOrdinalPlural = {"{0}million", "{0}millionen"}; - private static readonly string[] BillionOrdinalSingular = {"einmilliard", "einemilliarde"}; - private static readonly string[] BillionOrdinalPlural = {"{0}milliard", "{0}milliarden"}; - - public override string Convert(long input, GrammaticalGender gender) - { - if (input > Int32.MaxValue || input < Int32.MinValue) - { - throw new NotImplementedException(); - } - var number = (int)input; - - if (number == 0) - return "null"; - - if (number < 0) - return string.Format("minus {0}", Convert(-number)); - - var parts = new List(); - - var billions = number/1000000000; - if (billions > 0) - { - parts.Add(Part("{0} Milliarden", "eine Milliarde", billions)); - number %= 1000000000; - if (number > 0) - parts.Add(" "); - } - - var millions = number/1000000; - if (millions > 0) - { - parts.Add(Part("{0} Millionen", "eine Million", millions)); - number %= 1000000; - if (number > 0) - parts.Add(" "); - } - - var thousands = number/1000; - if (thousands > 0) - { - parts.Add(Part("{0}tausend", "eintausend", thousands)); - number %= 1000; - } - - var hundreds = number/100; - if (hundreds > 0) - { - parts.Add(Part("{0}hundert", "einhundert", hundreds)); - number %= 100; - } - - if (number > 0) - { - if (number < 20) - { - if (number > 1) - parts.Add(UnitsMap[number]); - else - parts.Add("eins"); - } - else - { - var units = number%10; - if (units > 0) - parts.Add(string.Format("{0}und", UnitsMap[units])); - - parts.Add(TensMap[number/10]); - } - } - - return string.Join("", parts); - } - - public override string ConvertToOrdinal(int number, GrammaticalGender gender) - { - if (number == 0) - return "null" + GetEndingForGender(gender); - - var parts = new List(); - if (number < 0) - { - parts.Add("minus "); - number = -number; - } - - var billions = number/1000000000; - if (billions > 0) - { - number %= 1000000000; - var noRest = NoRestIndex(number); - parts.Add(Part(BillionOrdinalPlural[noRest], BillionOrdinalSingular[noRest], billions)); - } - - var millions = number/1000000; - if (millions > 0) - { - number %= 1000000; - var noRest = NoRestIndex(number); - parts.Add(Part(MillionOrdinalPlural[noRest], MillionOrdinalSingular[noRest], millions)); - } - - var thousands = number/1000; - if (thousands > 0) - { - parts.Add(Part("{0}tausend", "eintausend", thousands)); - number %= 1000; - } - - var hundreds = number/100; - if (hundreds > 0) - { - parts.Add(Part("{0}hundert", "einhundert", hundreds)); - number %= 100; - } - - if (number > 0) - parts.Add(number < 20 ? UnitsOrdinal[number] : Convert(number)); - - if (number == 0 || number >= 20) - parts.Add("s"); - - parts.Add(GetEndingForGender(gender)); - - return string.Join("", parts); - } - - private string Part(string pluralFormat, string singular, int number) - { - if (number == 1) - return singular; - return string.Format(pluralFormat, Convert(number)); - } - - private static int NoRestIndex(int number) - { - return number == 0 ? 0 : 1; - } - - private static string GetEndingForGender(GrammaticalGender gender) - { - switch (gender) - { - case GrammaticalGender.Masculine: - return "ter"; - case GrammaticalGender.Feminine: - return "te"; - case GrammaticalGender.Neuter: - return "tes"; - default: - throw new ArgumentOutOfRangeException(nameof(gender)); - } - } } -} \ No newline at end of file +} diff --git a/src/Humanizer/Localisation/NumberToWords/GermanNumberToWordsConverterBase.cs b/src/Humanizer/Localisation/NumberToWords/GermanNumberToWordsConverterBase.cs new file mode 100644 index 000000000..88cb69bd0 --- /dev/null +++ b/src/Humanizer/Localisation/NumberToWords/GermanNumberToWordsConverterBase.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections.Generic; + +namespace Humanizer.Localisation.NumberToWords +{ + abstract class GermanNumberToWordsConverterBase : GenderedNumberToWordsConverter + { + private 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 readonly string[] TensMap = { "null", "zehn", "zwanzig", "dreißig", "vierzig", "fünfzig", "sechzig", "siebzig", "achtzig", "neunzig" }; + private readonly string[] UnitsOrdinal = { string.Empty, "ers", "zwei", "drit", "vier", "fünf", "sechs", "sieb", "ach", "neun", "zehn", "elf", "zwölf", "dreizehn", "vierzehn", "fünfzehn", "sechzehn", "siebzehn", "achtzehn", "neunzehn" }; + private readonly string[] HundredOrdinalSingular = { "einhundert" }; + private readonly string[] HundredOrdinalPlural = { "{0}hundert" }; + private readonly string[] ThousandOrdinalSingular = { "eintausend" }; + private readonly string[] ThousandOrdinalPlural = { "{0}tausend" }; + private readonly string[] MillionOrdinalSingular = { "einmillion", "einemillion" }; + private readonly string[] MillionOrdinalPlural = { "{0}million", "{0}millionen" }; + private readonly string[] BillionOrdinalSingular = { "einmilliard", "einemilliarde" }; + private readonly string[] BillionOrdinalPlural = { "{0}milliard", "{0}milliarden" }; + + public override string Convert(long number, GrammaticalGender gender) + { + if (number == 0) + return UnitsMap[number]; + + var parts = new List(); + if (number < 0) + { + parts.Add("minus "); + number = -number; + } + + CollectParts(parts, ref number, 1000000000000000000, true, "{0} Trillionen", "eine Trillion"); + CollectParts(parts, ref number, 1000000000000000, true, "{0} Billiarden", "eine Billiarde"); + CollectParts(parts, ref number, 1000000000000, true, "{0} Billionen", "eine Billion"); + CollectParts(parts, ref number, 1000000000, true, "{0} Milliarden", "eine Milliarde"); + CollectParts(parts, ref number, 1000000, true, "{0} Millionen", "eine Million"); + CollectParts(parts, ref number, 1000, false, "{0}tausend", "eintausend"); + CollectParts(parts, ref number, 100, false, "{0}hundert", "einhundert"); + + if (number > 0) + { + if (number < 20) + { + if (number == 1 && gender == GrammaticalGender.Feminine) + parts.Add("eine"); + else + parts.Add(UnitsMap[number]); + } + else + { + var units = number % 10; + if (units > 0) + parts.Add(string.Format("{0}und", UnitsMap[units])); + + parts.Add(GetTens(number / 10)); + } + } + + return string.Join("", parts); + } + + public override string ConvertToOrdinal(int number, GrammaticalGender gender) + { + if (number == 0) + return UnitsMap[number] + GetEndingForGender(gender); + + var parts = new List(); + if (number < 0) + { + parts.Add("minus "); + number = -number; + } + + CollectOrdinalParts(parts, ref number, 1000000000, true, BillionOrdinalPlural, BillionOrdinalSingular); + CollectOrdinalParts(parts, ref number, 1000000, true, MillionOrdinalPlural, MillionOrdinalSingular); + CollectOrdinalParts(parts, ref number, 1000, false, ThousandOrdinalPlural, ThousandOrdinalSingular); + CollectOrdinalParts(parts, ref number, 100, false, HundredOrdinalPlural, HundredOrdinalSingular); + + if (number > 0) + parts.Add(number < 20 ? UnitsOrdinal[number] : Convert(number)); + + if (number == 0 || number >= 20) + parts.Add("s"); + + parts.Add(GetEndingForGender(gender)); + + return string.Join("", parts); + } + + private void CollectParts(ICollection parts, ref long number, long divisor, bool addSpaceBeforeNextPart, string pluralFormat, string singular) + { + if (number / divisor > 0) + { + parts.Add(Part(pluralFormat, singular, number / divisor)); + number %= divisor; + if (addSpaceBeforeNextPart && number > 0) + parts.Add(" "); + } + } + + private void CollectOrdinalParts(ICollection parts, ref int number, int divisor, bool evaluateNoRest, string[] pluralFormats, string[] singulars) + { + if (number / divisor > 0) + { + var noRest = evaluateNoRest ? NoRestIndex(number % divisor) : 0; + parts.Add(Part(pluralFormats[noRest], singulars[noRest], number / divisor)); + number %= divisor; + } + } + + private string Part(string pluralFormat, string singular, long number) + { + if (number == 1) + return singular; + return string.Format(pluralFormat, Convert(number)); + } + + private int NoRestIndex(int number) + { + return number == 0 ? 0 : 1; + } + + private string GetEndingForGender(GrammaticalGender gender) + { + switch (gender) + { + case GrammaticalGender.Masculine: + return "ter"; + case GrammaticalGender.Feminine: + return "te"; + case GrammaticalGender.Neuter: + return "tes"; + default: + throw new ArgumentOutOfRangeException(nameof(gender)); + } + } + + protected virtual string GetTens(long tens) + { + return TensMap[tens]; + } + } +} diff --git a/src/Humanizer/Localisation/NumberToWords/GermanSwissLiechtensteinNumberToWordsConverter.cs b/src/Humanizer/Localisation/NumberToWords/GermanSwissLiechtensteinNumberToWordsConverter.cs new file mode 100644 index 000000000..20a649865 --- /dev/null +++ b/src/Humanizer/Localisation/NumberToWords/GermanSwissLiechtensteinNumberToWordsConverter.cs @@ -0,0 +1,13 @@ +namespace Humanizer.Localisation.NumberToWords +{ + internal class GermanSwissLiechtensteinNumberToWordsConverter : GermanNumberToWordsConverterBase + { + protected override string GetTens(long tens) + { + if (tens == 3) + return "dreissig"; + + return base.GetTens(tens); + } + } +} diff --git a/src/Humanizer/Properties/Resources.resx b/src/Humanizer/Properties/Resources.resx index 1fec4c24f..ebde4142a 100644 --- a/src/Humanizer/Properties/Resources.resx +++ b/src/Humanizer/Properties/Resources.resx @@ -576,4 +576,7 @@ one year + + {0} days + \ No newline at end of file diff --git a/src/NuGet.config b/src/NuGet.config index bb337ec79..1ab6bbd3b 100644 --- a/src/NuGet.config +++ b/src/NuGet.config @@ -1,8 +1,6 @@ - - - + \ No newline at end of file diff --git a/version.json b/version.json index 631cd1d41..bca583e1b 100644 --- a/version.json +++ b/version.json @@ -1,9 +1,8 @@ { - "version": "2.2.1-preview.{height}", + "version": "2.3", "publicReleaseRefSpec": [ "^refs/heads/master$", // we release out of master - "^refs/heads/dev$", // we release out of develop - "^refs/tags/v\\d+\\.\\d+" // we also release tags starting with vN.N + "^refs/heads/rel/v\\d+\\.\\d+" // we also release branches starting with rel/vN.N ], "nugetPackageVersion":{ "semVer": 2