Repository: Humanizr/Humanizer Branch: main Commit: 6b047ad02cd2 Files: 716 Total size: 3.3 MB Directory structure: gitextract_ui5lhkfj/ ├── .editorconfig ├── .gitattributes ├── .github/ │ ├── CODE_OF_CONDUCT.md │ ├── CONTRIBUTING.md │ ├── PULL_REQUEST_TEMPLATE.md │ ├── codeql/ │ │ └── codeql-config.yml │ ├── copilot-instructions.md │ ├── dependabot.yml │ └── workflows/ │ ├── .devskim │ ├── benchmarks-baseline-vs-current.yml │ ├── codeql.yml │ ├── copilot-setup-steps.yml │ ├── devskim.yml │ └── jekyll-gh-pages.yml ├── .gitignore ├── AGENTS.md ├── Directory.Build.props ├── Directory.Build.targets ├── Directory.Packages.props ├── Directory.Solution.targets ├── Humanizer.slnx ├── Humanizer.snk ├── NuSpecs/ │ ├── Humanizer.Core.af.nuspec │ ├── Humanizer.Core.ar.nuspec │ ├── Humanizer.Core.az.nuspec │ ├── Humanizer.Core.bg.nuspec │ ├── Humanizer.Core.bn.nuspec │ ├── Humanizer.Core.ca.nuspec │ ├── Humanizer.Core.cs.nuspec │ ├── Humanizer.Core.da.nuspec │ ├── Humanizer.Core.de.nuspec │ ├── Humanizer.Core.el.nuspec │ ├── Humanizer.Core.es.nuspec │ ├── Humanizer.Core.fa.nuspec │ ├── Humanizer.Core.fi.nuspec │ ├── Humanizer.Core.fil.nuspec │ ├── Humanizer.Core.fr.nuspec │ ├── Humanizer.Core.he.nuspec │ ├── Humanizer.Core.hr.nuspec │ ├── Humanizer.Core.hu.nuspec │ ├── Humanizer.Core.hy.nuspec │ ├── Humanizer.Core.id.nuspec │ ├── Humanizer.Core.is.nuspec │ ├── Humanizer.Core.it.nuspec │ ├── Humanizer.Core.ja.nuspec │ ├── Humanizer.Core.ko.nuspec │ ├── Humanizer.Core.ku.nuspec │ ├── Humanizer.Core.lb.nuspec │ ├── Humanizer.Core.lt.nuspec │ ├── Humanizer.Core.lv.nuspec │ ├── Humanizer.Core.ms.nuspec │ ├── Humanizer.Core.mt.nuspec │ ├── Humanizer.Core.nb.nuspec │ ├── Humanizer.Core.nl.nuspec │ ├── Humanizer.Core.nuspec │ ├── Humanizer.Core.pl.nuspec │ ├── Humanizer.Core.pt-BR.nuspec │ ├── Humanizer.Core.pt.nuspec │ ├── Humanizer.Core.ro.nuspec │ ├── Humanizer.Core.ru.nuspec │ ├── Humanizer.Core.sk.nuspec │ ├── Humanizer.Core.sl.nuspec │ ├── Humanizer.Core.sr-Latn.nuspec │ ├── Humanizer.Core.sr.nuspec │ ├── Humanizer.Core.sv.nuspec │ ├── Humanizer.Core.ta.nuspec.unused │ ├── Humanizer.Core.th.nuspec │ ├── Humanizer.Core.tr.nuspec │ ├── Humanizer.Core.uk.nuspec │ ├── Humanizer.Core.uz-Cyrl-UZ.nuspec │ ├── Humanizer.Core.uz-Latn-UZ.nuspec │ ├── Humanizer.Core.vi.nuspec │ ├── Humanizer.Core.zh-CN.nuspec │ ├── Humanizer.Core.zh-Hans.nuspec │ ├── Humanizer.Core.zh-Hant.nuspec │ └── Humanizer.nuspec ├── ResXManager.config.xml ├── azure-pipelines.yml ├── docs/ │ ├── _config.yml │ ├── _layouts/ │ │ └── default.html │ ├── assets/ │ │ └── css/ │ │ └── style.css │ ├── extensibility.md │ ├── index.md │ ├── installation.md │ ├── localization.md │ ├── migration-v3.md │ ├── quick-start.md │ ├── string-dehumanization.md │ ├── string-humanization.md │ ├── string-truncation.md │ └── v3-namespace-migration.md ├── global.json ├── license.txt ├── nuget.config ├── readme.md ├── release_notes.md ├── src/ │ ├── Benchmarks/ │ │ ├── .editorconfig │ │ ├── Benchmarks.csproj │ │ ├── EnglishArticleBenchmarks.cs │ │ ├── EnglishToWordsBenchmark.cs │ │ ├── EnumBenchmarks.cs │ │ ├── GlobalUsings.cs │ │ ├── InflectorBenchmarks.cs │ │ ├── ItalianNumberBenchmarks.cs │ │ ├── MetricNumeralBenchmarks.cs │ │ ├── NumberToWordsBenchmarks.cs │ │ ├── OrdinalBenchmarks.cs │ │ ├── Program.cs │ │ ├── README.md │ │ ├── RomanNumeralBenchmarks.cs │ │ ├── StringHumanizeBenchmarks.cs │ │ ├── TimeOnlyToClockNotationConverterBenchmarks.cs │ │ ├── ToQuantityBenchmarks.cs │ │ ├── TransformersBenchmarks.cs │ │ ├── VocabularyBenchmarks.cs │ │ └── WordsToNumberBenchmarks.cs │ ├── Humanizer/ │ │ ├── ArticlePrefixSort.cs │ │ ├── Bytes/ │ │ │ ├── ByteRate.cs │ │ │ ├── ByteSize.cs │ │ │ ├── ByteSizeExtensions.cs │ │ │ └── LICENSE │ │ ├── CasingExtensions.cs │ │ ├── ClockNotationRounding.cs │ │ ├── CollectionHumanizeExtensions.cs │ │ ├── Configuration/ │ │ │ ├── CollectionFormatterRegistry.cs │ │ │ ├── Configurator.cs │ │ │ ├── DateOnlyToOrdinalWordsConverterRegistry.cs │ │ │ ├── DateToOrdinalWordsConverterRegistry.cs │ │ │ ├── FormatterRegistry.cs │ │ │ ├── LocaliserRegistry.cs │ │ │ ├── NumberToWordsConverterRegistry.cs │ │ │ ├── OrdinalizerRegistry.cs │ │ │ ├── TimeOnlyToClockNotationConvertersRegistry.cs │ │ │ └── WordsToNumberConverterRegistry.cs │ │ ├── DateHumanizeExtensions.cs │ │ ├── DateTimeHumanizeStrategy/ │ │ │ ├── DateTimeHumanizeAlgorithms.cs │ │ │ ├── DefaultDateOnlyHumanizeStrategy.cs │ │ │ ├── DefaultDateTimeHumanizeStrategy.cs │ │ │ ├── DefaultDateTimeOffsetHumanizeStrategy.cs │ │ │ ├── DefaultTimeOnlyHumanizeStrategy.cs │ │ │ ├── IDateOnlyHumanizeStrategy.cs │ │ │ ├── IDateTimeHumanizeStrategy.cs │ │ │ ├── IDateTimeOffsetHumanizeStrategy.cs │ │ │ ├── ITimeOnlyHumanizeStrategy.cs │ │ │ ├── PrecisionDateOnlyHumanizeStrategy.cs │ │ │ ├── PrecisionDateTimeHumanizeStrategy.cs │ │ │ ├── PrecisionDateTimeOffsetHumanizeStrategy.cs │ │ │ └── PrecisionTimeOnlyHumanizeStrategy.cs │ │ ├── DateToOrdinalWordsExtensions.cs │ │ ├── EnumCache.cs │ │ ├── EnumDehumanizeExtensions.cs │ │ ├── EnumHumanizeExtensions.cs │ │ ├── FluentDate/ │ │ │ ├── In.Months.cs │ │ │ ├── In.Months.tt │ │ │ ├── In.SomeTimeFrom.cs │ │ │ ├── In.SomeTimeFrom.tt │ │ │ ├── In.cs │ │ │ ├── InDate.Months.cs │ │ │ ├── InDate.Months.tt │ │ │ ├── InDate.SomeTimeFrom.cs │ │ │ ├── InDate.SomeTimeFrom.tt │ │ │ ├── InDate.cs │ │ │ ├── On.Days.cs │ │ │ ├── On.Days.tt │ │ │ ├── OnDate.Days.cs │ │ │ ├── OnDate.Days.tt │ │ │ └── PrepositionsExtensions.cs │ │ ├── GlobalUsings.cs │ │ ├── GrammaticalCase.cs │ │ ├── GrammaticalGender.cs │ │ ├── HeadingExtensions.cs │ │ ├── Humanizer.csproj │ │ ├── Inflections/ │ │ │ ├── LICENSE │ │ │ ├── Vocabularies.cs │ │ │ └── Vocabulary.cs │ │ ├── InflectorExtensions.cs │ │ ├── LetterCasing.cs │ │ ├── Localisation/ │ │ │ ├── CollectionFormatters/ │ │ │ │ ├── DefaultCollectionFormatter.cs │ │ │ │ ├── ICollectionFormatter.cs │ │ │ │ └── OxfordStyleCollectionFormatter.cs │ │ │ ├── DataUnit.cs │ │ │ ├── DateToOrdinalWords/ │ │ │ │ ├── CaDateOnlyToOrdinalWordsConverter.cs │ │ │ │ ├── CaDateToOrdinalWordsConverter.cs │ │ │ │ ├── DefaultDateOnlyToOrdinalWordConverter.cs │ │ │ │ ├── DefaultDateToOrdinalWordConverter.cs │ │ │ │ ├── EsDateOnlyToOrdinalWordsConverter.cs │ │ │ │ ├── EsDateToOrdinalWordsConverter.cs │ │ │ │ ├── FrDateOnlyToOrdinalWordsConverter.cs │ │ │ │ ├── FrDateToOrdinalWordsConverter.cs │ │ │ │ ├── IDateOnlyToOrdinalWordConverter.cs │ │ │ │ ├── IDateToOrdinalWordConverter.cs │ │ │ │ ├── LtDateOnlyToOrdinalWordsConverter.cs │ │ │ │ ├── LtDateToOrdinalWordsConverter.cs │ │ │ │ ├── UsDateOnlyToOrdinalWordsConverter.cs │ │ │ │ └── UsDateToOrdinalWordsConverter.cs │ │ │ ├── Formatters/ │ │ │ │ ├── ArabicFormatter.cs │ │ │ │ ├── BulgarianFormatter.cs │ │ │ │ ├── CatalanFormatter.cs │ │ │ │ ├── CroatianFormatter.cs │ │ │ │ ├── CzechSlovakPolishFormatter.cs │ │ │ │ ├── DefaultFormatter.cs │ │ │ │ ├── FrenchFormatter.cs │ │ │ │ ├── GermanFormatter.cs │ │ │ │ ├── HebrewFormatter.cs │ │ │ │ ├── IFormatter.cs │ │ │ │ ├── IcelandicFormatter.cs │ │ │ │ ├── LithuanianFormatter.cs │ │ │ │ ├── LuxembourgishFormatter.cs │ │ │ │ ├── MalteseFormatter.cs │ │ │ │ ├── RomanianFormatter.cs │ │ │ │ ├── RussianFormatter.cs │ │ │ │ ├── SerbianFormatter.cs │ │ │ │ ├── SlovenianFormatter.cs │ │ │ │ └── UkrainianFormatter.cs │ │ │ ├── GrammaticalNumber/ │ │ │ │ ├── LithuanianNumberForm.cs │ │ │ │ ├── LithuanianNumberFormDetector.cs │ │ │ │ ├── RussianGrammaticalNumber.cs │ │ │ │ └── RussianGrammaticalNumberDetector.cs │ │ │ ├── NumberToWords/ │ │ │ │ ├── AfrikaansNumberToWordsConverter.cs │ │ │ │ ├── ArabicNumberToWordsConverter.cs │ │ │ │ ├── ArmenianNumberToWordsConverter.cs │ │ │ │ ├── AzerbaijaniNumberToWordsConverter.cs │ │ │ │ ├── BanglaNumberToWordsConverter.cs │ │ │ │ ├── BrazilianPortugueseNumberToWordsConverter.cs │ │ │ │ ├── BulgarianNumberToWordsConverter.cs │ │ │ │ ├── CatalanNumberToWordsConverter.cs │ │ │ │ ├── CentralKurdishNumberToWordsConverter.cs │ │ │ │ ├── ChineseNumberToWordsConverter.cs │ │ │ │ ├── CroatianNumberToWordsConverter.cs │ │ │ │ ├── CzechNumberToWordsConverter.cs │ │ │ │ ├── DefaultNumberToWordsConverter.cs │ │ │ │ ├── DutchNumberToWordsConverter.cs │ │ │ │ ├── EnglishNumberToWordsConverter.cs │ │ │ │ ├── FarsiNumberToWordsConverter.cs │ │ │ │ ├── FinnishNumberToWordsConverter.cs │ │ │ │ ├── FrenchBelgianNumberToWordsConverter.cs │ │ │ │ ├── FrenchNumberToWordsConverter.cs │ │ │ │ ├── FrenchNumberToWordsConverterBase.cs │ │ │ │ ├── FrenchSwissNumberToWordsConverter.cs │ │ │ │ ├── GenderedNumberToWordsConverter.cs │ │ │ │ ├── GenderlessNumberToWordsConverter.cs │ │ │ │ ├── GermanNumberToWordsConverter.cs │ │ │ │ ├── GermanNumberToWordsConverterBase.cs │ │ │ │ ├── GermanSwissLiechtensteinNumberToWordsConverter.cs │ │ │ │ ├── GreekNumberToWordsConverter.cs │ │ │ │ ├── HebrewNumberToWordsConverter.cs │ │ │ │ ├── HungarianNumberToWordsConverter.cs │ │ │ │ ├── INumberToWordsConverter.cs │ │ │ │ ├── IcelandicNumberToWordsConverter.cs │ │ │ │ ├── IndianNumberToWordsConverter.cs │ │ │ │ ├── Italian/ │ │ │ │ │ ├── ItalianCardinalNumberCruncher.cs │ │ │ │ │ └── ItalianOrdinalNumberCruncher.cs │ │ │ │ ├── ItalianNumberToWordsConverter.cs │ │ │ │ ├── JapaneseNumberToWordsConverter.cs │ │ │ │ ├── KoreanNumberToWordsConverter.cs │ │ │ │ ├── LatvianNumberToWordsConverter.cs │ │ │ │ ├── LithuanianNumberToWordsConverter.cs │ │ │ │ ├── LuxembourgishNumberToWordsConverter.cs │ │ │ │ ├── MalteseNumberToWordsConvertor.cs │ │ │ │ ├── NorwegianBokmalNumberToWordsConverter.cs │ │ │ │ ├── PolishNumberToWordsConverter.cs │ │ │ │ ├── PortugueseNumberToWordsConverter.cs │ │ │ │ ├── Romanian/ │ │ │ │ │ ├── RomanianCardinalNumberConverter.cs │ │ │ │ │ └── RomanianOrdinalNumberConverter.cs │ │ │ │ ├── RomanianNumberToWordsConverter.cs │ │ │ │ ├── RussianNumberToWordsConverter.cs │ │ │ │ ├── SerbianCyrlNumberToWordsConverter.cs │ │ │ │ ├── SerbianNumberToWordsConverter.cs │ │ │ │ ├── SlovenianNumberToWordsConverter.cs │ │ │ │ ├── SpanishNumberToWordsConverter.cs │ │ │ │ ├── SwedishNumberToWordsConverter.cs │ │ │ │ ├── TamilNumberToWordsConverter.cs │ │ │ │ ├── ThaiNumberToWordsConverter.cs │ │ │ │ ├── TurkishNumberToWordConverter.cs │ │ │ │ ├── UkrainianNumberToWordsConverter.cs │ │ │ │ ├── UzbekCyrlNumberToWordConverter.cs │ │ │ │ ├── UzbekLatnNumberToWordConverter.cs │ │ │ │ └── VietnameseNumberToWordsConverter.cs │ │ │ ├── Ordinalizers/ │ │ │ │ ├── ArmenianOrdinalizer.cs │ │ │ │ ├── AzerbaijaniOrdinalizer.cs │ │ │ │ ├── CatalanOrdinalizer.cs │ │ │ │ ├── DefaultOrdinalizer.cs │ │ │ │ ├── DutchOrdinalizer.cs │ │ │ │ ├── EnglishOrdinalizer.cs │ │ │ │ ├── FrenchOrdinalizer.cs │ │ │ │ ├── GermanOrdinalizer.cs │ │ │ │ ├── HungarianOrdinalizer.cs │ │ │ │ ├── IOrdinalizer.cs │ │ │ │ ├── IcelandicOrdinalizer.cs │ │ │ │ ├── ItalianOrdinalizer.cs │ │ │ │ ├── LuxembourgishOrdinalizer.cs │ │ │ │ ├── PortugueseOrdinalizer.cs │ │ │ │ ├── RomanianOrdinalizer.cs │ │ │ │ ├── RussianOrdinalizer.cs │ │ │ │ ├── SpanishOrdinalizer.cs │ │ │ │ ├── TurkishOrdinalizer.cs │ │ │ │ └── UkrainianOrdinalizer.cs │ │ │ ├── ResourceKeys.Common.cs │ │ │ ├── ResourceKeys.DateHumanize.cs │ │ │ ├── ResourceKeys.TimeSpanHumanize.cs │ │ │ ├── ResourceKeys.TimeUnitSymbol.cs │ │ │ ├── Resources.cs │ │ │ ├── Tense.cs │ │ │ ├── TimeToClockNotation/ │ │ │ │ ├── BrazilianPortugueseTimeOnlyToClockNotationConverter.cs │ │ │ │ ├── CaTimeOnlyToClockNotationConverter.cs │ │ │ │ ├── DefaultTimeOnlyToClockNotationConverter.cs │ │ │ │ ├── EsTimeOnlyToClockNotationConverter.cs │ │ │ │ ├── FrTimeOnlyToClockNotationConverter.cs │ │ │ │ ├── GermanTimeOnlyToClockNotationConverter.cs │ │ │ │ ├── ITimeOnlyToClockNotationConverter.cs │ │ │ │ ├── LbTimeOnlyToClockNotationConverter.cs │ │ │ │ └── PortugueseTimeOnlyToClockNotationConverter.cs │ │ │ ├── TimeUnit.cs │ │ │ └── WordsToNumber/ │ │ │ ├── DefaultWordsToNumberConverter.cs │ │ │ ├── EnglishWordsToNumberConverter.cs │ │ │ ├── GenderlessWordsToNumberConverter.cs │ │ │ └── IWordsToNumberConverter.cs │ │ ├── MetricNumeralExtensions.cs │ │ ├── MetricNumeralFormats.cs │ │ ├── NoMatchFoundException.cs │ │ ├── NumberToNumberExtensions.cs │ │ ├── NumberToTimeSpanExtensions.cs │ │ ├── NumberToWordsExtension.cs │ │ ├── OnNoMatch.cs │ │ ├── OrdinalizeExtensions.cs │ │ ├── Plurality.cs │ │ ├── PolyfillShims.cs │ │ ├── PolyfillShims2.cs │ │ ├── Properties/ │ │ │ ├── AssemblyInfo.cs │ │ │ ├── Resources.af.resx │ │ │ ├── Resources.ar.resx │ │ │ ├── Resources.az.resx │ │ │ ├── Resources.bg.resx │ │ │ ├── Resources.bn.resx │ │ │ ├── Resources.ca.resx │ │ │ ├── Resources.cs.resx │ │ │ ├── Resources.da.resx │ │ │ ├── Resources.de.resx │ │ │ ├── Resources.el.resx │ │ │ ├── Resources.es.resx │ │ │ ├── Resources.fa.resx │ │ │ ├── Resources.fi.resx │ │ │ ├── Resources.fil.resx │ │ │ ├── Resources.fr.resx │ │ │ ├── Resources.he.resx │ │ │ ├── Resources.hr.resx │ │ │ ├── Resources.hu.resx │ │ │ ├── Resources.hy.resx │ │ │ ├── Resources.id.resx │ │ │ ├── Resources.is.resx │ │ │ ├── Resources.it.resx │ │ │ ├── Resources.ja.resx │ │ │ ├── Resources.ko.resx │ │ │ ├── Resources.ku.resx │ │ │ ├── Resources.lb.resx │ │ │ ├── Resources.lt.resx │ │ │ ├── Resources.lv.resx │ │ │ ├── Resources.ms.resx │ │ │ ├── Resources.mt.resx │ │ │ ├── Resources.nb.resx │ │ │ ├── Resources.nl.resx │ │ │ ├── Resources.pl.resx │ │ │ ├── Resources.pt-BR.resx │ │ │ ├── Resources.pt.resx │ │ │ ├── Resources.resx │ │ │ ├── Resources.ro.resx │ │ │ ├── Resources.ru.resx │ │ │ ├── Resources.sk.resx │ │ │ ├── Resources.sl.resx │ │ │ ├── Resources.sr-Latn.resx │ │ │ ├── Resources.sr.resx │ │ │ ├── Resources.sv.resx │ │ │ ├── Resources.th.resx │ │ │ ├── Resources.tr.resx │ │ │ ├── Resources.uk.resx │ │ │ ├── Resources.uz-Cyrl-UZ.resx │ │ │ ├── Resources.uz-Latn-UZ.resx │ │ │ ├── Resources.vi.resx │ │ │ ├── Resources.zh-CN.resx │ │ │ ├── Resources.zh-Hans.resx │ │ │ └── Resources.zh-Hant.resx │ │ ├── RomanNumeralExtensions.cs │ │ ├── StringDehumanizeExtensions.cs │ │ ├── StringHumanizeExtensions.cs │ │ ├── TimeOnlyToClockNotationExtensions.cs │ │ ├── TimeSpanHumanizeExtensions.cs │ │ ├── TimeUnitToSymbolExtensions.cs │ │ ├── ToQuantityExtensions.cs │ │ ├── Transformer/ │ │ │ ├── ICulturedStringTransformer.cs │ │ │ ├── IStringTransformer.cs │ │ │ ├── To.cs │ │ │ ├── ToLowerCase.cs │ │ │ ├── ToSentenceCase.cs │ │ │ ├── ToTitleCase.cs │ │ │ └── ToUpperCase.cs │ │ ├── TruncateExtensions.cs │ │ ├── TruncateFrom.cs │ │ ├── Truncation/ │ │ │ ├── DynamicLengthAndPreserveWordsTruncator.cs │ │ │ ├── DynamicNumberOfCharactersAndPreserveWordTruncator.cs │ │ │ ├── FixedLengthTruncator.cs │ │ │ ├── FixedNumberOfCharactersTruncator.cs │ │ │ ├── FixedNumberOfWordsTruncator.cs │ │ │ ├── ITruncator.cs │ │ │ └── Truncator.cs │ │ ├── TupleizeExtensions.cs │ │ ├── WordForm.cs │ │ └── WordsToNumberExtension.cs │ ├── Humanizer.Analyzers/ │ │ ├── AnalyzerReleases.Shipped.md │ │ ├── AnalyzerReleases.Unshipped.md │ │ ├── Humanizer.Analyzers.csproj │ │ ├── NamespaceMigrationAnalyzer.cs │ │ ├── NamespaceMigrationCodeFixProvider.cs │ │ ├── README.md │ │ └── build/ │ │ └── Humanizer.Core.targets │ └── scripts/ │ └── split-benchmark-results.ps1 ├── tests/ │ ├── Humanizer.Analyzers.Tests/ │ │ ├── AnalyzerAssemblyCompatibilityTests.cs │ │ ├── Humanizer.Analyzers.Tests.csproj │ │ ├── NamespaceMigrationAnalyzerTests.cs │ │ ├── NamespaceMigrationCodeFixTests.cs │ │ └── Verifiers.cs │ ├── Humanizer.Tests/ │ │ ├── .editorconfig │ │ ├── ApiApprover/ │ │ │ ├── PublicApiApprovalTest.Approve_Public_Api.DotNet10_0.verified.txt │ │ │ ├── PublicApiApprovalTest.Approve_Public_Api.DotNet8_0.verified.txt │ │ │ ├── PublicApiApprovalTest.Approve_Public_Api.Net4_8.verified.txt │ │ │ └── PublicApiApprovalTest.cs │ │ ├── ArticlePrefixSortTests.cs │ │ ├── BitFieldEnumHumanizeTests.cs │ │ ├── BitFieldEnumUnderTest.cs │ │ ├── Bytes/ │ │ │ ├── ArithmeticTests.cs │ │ │ ├── ByteRateTests.cs │ │ │ ├── ByteSizeExtensionsTests.cs │ │ │ ├── ComparingTests.cs │ │ │ ├── CreatingTests.cs │ │ │ ├── ParsingTests.cs │ │ │ ├── ToFullWordsTests.cs │ │ │ └── ToStringTests.cs │ │ ├── CasingTests.cs │ │ ├── CollectionHumanizeTests.cs │ │ ├── DateHumanize.cs │ │ ├── DateHumanizeDefaultStrategyTests.cs │ │ ├── DateOnlyHumanizeTests.cs │ │ ├── DateTimeHumanizePrecisionStrategyTests.cs │ │ ├── DateTimeOffsetHumanizeTests.cs │ │ ├── EnumHumanizeTests.cs │ │ ├── EnumUnderTest.cs │ │ ├── FluentDate/ │ │ │ ├── InDateTests.cs │ │ │ ├── InTests.cs │ │ │ ├── OnDateTests.cs │ │ │ ├── OnTests.cs │ │ │ └── PrepositionTests.cs │ │ ├── GlobalUsings.cs │ │ ├── HeadingTests.cs │ │ ├── Humanizer.Tests.csproj │ │ ├── InflectorTests.cs │ │ ├── Localisation/ │ │ │ ├── DefaultFormatterTests.cs │ │ │ ├── ResourcesTests.cs │ │ │ ├── af/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── ar/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── az/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── bg/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── bn-BD/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── ca/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── DateToOrdinalWordsTests.cs │ │ │ │ ├── NumberToWordsFeminineTest.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ ├── OrdinalizeTests.cs │ │ │ │ ├── TimeSpanHumanizeTests.cs │ │ │ │ └── TimeToClockNotationTests.cs │ │ │ ├── cs/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── da/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── de/ │ │ │ │ ├── Bytes/ │ │ │ │ │ ├── ByteRateTests.cs │ │ │ │ │ ├── ByteSizeExtensionsTests.cs │ │ │ │ │ ├── ToFullWordsTests.cs │ │ │ │ │ └── ToStringTests.cs │ │ │ │ ├── CollectionFormatterTests.cs │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── DateToOrdinalWordsTests.cs │ │ │ │ ├── HeadingTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ ├── OrdinalizeTests.cs │ │ │ │ ├── TimeSpanHumanizeTests.cs │ │ │ │ ├── TimeToClockNotationTests.cs │ │ │ │ └── TimeUnitToSymbolTests.cs │ │ │ ├── de-CH/ │ │ │ │ └── NumberToWordsTests.cs │ │ │ ├── de-LI/ │ │ │ │ └── NumberToWordsTests.cs │ │ │ ├── el/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToOrdinalWordsTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── en/ │ │ │ │ ├── DateToOrdinalWordsTests.cs │ │ │ │ └── TimeToClockNotationTests.cs │ │ │ ├── en-IN/ │ │ │ │ └── NumberToWordsTests.cs │ │ │ ├── es/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── DateToOrdinalWordsTests.cs │ │ │ │ ├── NumberToWordsFeminineTest.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ ├── OrdinalizeTests.cs │ │ │ │ ├── TimeSpanHumanizeTests.cs │ │ │ │ └── TimeToClockNotationTests.cs │ │ │ ├── fa/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── fi-FI/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ └── NumberToWordsTests.cs │ │ │ ├── fil-PH/ │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── fr/ │ │ │ │ ├── Bytes/ │ │ │ │ │ ├── ByteSizeExtensionsTests.cs │ │ │ │ │ ├── ToFullWordsTests.cs │ │ │ │ │ └── ToStringTests.cs │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── DateToOrdinalWordsTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ ├── OrdinalizeTests.cs │ │ │ │ ├── TimeOnlyHumanizeTests.cs │ │ │ │ ├── TimeSpanHumanizeTests.cs │ │ │ │ ├── TimeToClockNotationTests.cs │ │ │ │ └── TimeUnitToSymbolTests.cs │ │ │ ├── fr-BE/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── fr-CH/ │ │ │ │ └── NumberToWordsTests.cs │ │ │ ├── he/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── hr/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── hu/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── hy/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ ├── OrdinalizeTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── id/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── invariant/ │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ └── ToQuantityTests.cs │ │ │ ├── is/ │ │ │ │ ├── Bytes/ │ │ │ │ │ ├── ByteSizeExtensionsTests.cs │ │ │ │ │ ├── ToFullWordsTests.cs │ │ │ │ │ └── ToStringTests.cs │ │ │ │ ├── CollectionFormatterTests.cs │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── HeadingTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ ├── OrdinalizeTests.cs │ │ │ │ ├── ResourcesTests.cs │ │ │ │ ├── TimeOnlyHumanizeTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── it/ │ │ │ │ ├── CollectionFormatterTests.cs │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ ├── OrdinalizerTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── ja/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── ko-KR/ │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── ku/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── lb/ │ │ │ │ ├── Bytes/ │ │ │ │ │ ├── ByteRateTests.cs │ │ │ │ │ ├── ByteSizeExtensionsTests.cs │ │ │ │ │ ├── ToFullWordsTests.cs │ │ │ │ │ └── ToStringTests.cs │ │ │ │ ├── CollectionFormatterTests.cs │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── DateToOrdinalWordsTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ ├── OrdinalizeTests.cs │ │ │ │ ├── TimeOnlyHumanizeTests.cs │ │ │ │ ├── TimeSpanHumanizeTests.cs │ │ │ │ └── TimeToClockNotationTests.cs │ │ │ ├── lt/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── DateToOrdinalWordsTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── lv/ │ │ │ │ ├── DateToOrdinalWordsTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── ms-MY/ │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── mt/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── nb/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── nb-NO/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── nl/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ ├── OrdinalizeTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── pl/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── pt/ │ │ │ │ ├── Bytes/ │ │ │ │ │ └── ByteSizeExtensionsTests.cs │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ ├── OrdinalizeTests.cs │ │ │ │ ├── TimeSpanHumanizeTests.cs │ │ │ │ ├── TimeToClockNotationTests.cs │ │ │ │ └── TimeUnitToSymbolTests.cs │ │ │ ├── pt-BR/ │ │ │ │ ├── Bytes/ │ │ │ │ │ └── ByteSizeExtensionsTests.cs │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ ├── OrdinalizeTests.cs │ │ │ │ ├── TimeSpanHumanizeTests.cs │ │ │ │ ├── TimeToClockNotationTests.cs │ │ │ │ └── TimeUnitToSymbolTests.cs │ │ │ ├── ro-Ro/ │ │ │ │ ├── CollectionFormatterTests.cs │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ ├── OrdinalizerTests.cs │ │ │ │ └── TimeSpanHumanizerTests.cs │ │ │ ├── ru-RU/ │ │ │ │ ├── Bytes/ │ │ │ │ │ ├── ByteRateTests.cs │ │ │ │ │ ├── ByteSizeExtensionsTests.cs │ │ │ │ │ ├── ToFullWordsTests.cs │ │ │ │ │ └── ToStringTests.cs │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── HeadingTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ ├── OrdinalizeTests.cs │ │ │ │ ├── TimeSpanHumanizeTests.cs │ │ │ │ └── TimeUnitToSymbolTests.cs │ │ │ ├── sk/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── sl/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── sr/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTest.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── sr-Latn/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTest.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── sv/ │ │ │ │ ├── CollectionFormatterTests.cs │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── ta/ │ │ │ │ └── NumberToWordsTests.cs │ │ │ ├── th-TH/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ └── NumberToWordsTests.cs │ │ │ ├── tr/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ ├── OrdinalizeTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── uk-UA/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ ├── OrdinalizeTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── uz-Cyrl-UZ/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── uz-Latn-UZ/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── vi/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── zh-CN/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ ├── NumberToWordsTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── zh-HK/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ ├── zh-Hans/ │ │ │ │ ├── DateHumanizeTests.cs │ │ │ │ └── TimeSpanHumanizeTests.cs │ │ │ └── zh-Hant/ │ │ │ ├── DateHumanizeTests.cs │ │ │ └── TimeSpanHumanizeTests.cs │ │ ├── MetricNumeralTests.cs │ │ ├── ModuleInitializer.cs │ │ ├── NumberToNumberTests.cs │ │ ├── NumberToTimeSpanTests.cs │ │ ├── NumberToWordsTests.cs │ │ ├── OrdinalizeTests.cs │ │ ├── ResourceKeyTests.cs │ │ ├── RomanNumeralTests.cs │ │ ├── StringDehumanizeTests.cs │ │ ├── StringHumanizeTests.cs │ │ ├── TimeOnlyHumanizeTests.cs │ │ ├── TimeSpanHumanizeTests.cs │ │ ├── TimeUnitToSymbolTests.cs │ │ ├── ToQuantityTests.cs │ │ ├── TransformersTests.cs │ │ ├── TruncatorTests.cs │ │ ├── TupleizeTests.cs │ │ ├── UseCultureAttribute.cs │ │ ├── WordsToNumberTests.cs │ │ └── testconfig.json │ ├── fixtures/ │ │ ├── PackageSmoke/ │ │ │ ├── AnalyzerProbe.cs │ │ │ ├── BlazorConsumer/ │ │ │ │ ├── App.razor │ │ │ │ ├── Consumer.csproj.template │ │ │ │ └── Program.cs │ │ │ ├── ConsoleConsumer/ │ │ │ │ ├── Consumer.csproj.template │ │ │ │ └── Program.cs │ │ │ └── WebApiConsumer/ │ │ │ ├── Consumer.csproj.template │ │ │ └── Program.cs │ │ └── WapProjSmoke/ │ │ ├── EntryPointApp/ │ │ │ ├── EntryPointApp.csproj.template │ │ │ └── Program.cs │ │ └── Package/ │ │ ├── Package.appxmanifest │ │ └── Package.wapproj.template │ └── verify-packages.ps1 └── version.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ root = true # EditorConfig: http://EditorConfig.org # top-most EditorConfig file [*] indent_style = space [*.cs] indent_size = 4 charset = utf-8 tab_width = 4 end_of_line = crlf dotnet_style_operator_placement_when_wrapping = beginning_of_line dotnet_style_coalesce_expression = true:suggestion dotnet_style_null_propagation = true:suggestion dotnet_style_prefer_auto_properties = true:silent dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion dotnet_style_collection_initializer = true:suggestion dotnet_style_object_initializer = true:suggestion dotnet_style_prefer_simplified_boolean_expressions = true:suggestion dotnet_style_prefer_conditional_expression_over_assignment = true:silent dotnet_style_prefer_conditional_expression_over_return = true:silent dotnet_style_explicit_tuple_names = true:suggestion dotnet_style_prefer_inferred_tuple_names = true:suggestion dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion dotnet_style_prefer_compound_assignment = true:suggestion dotnet_style_prefer_simplified_interpolation = true:suggestion dotnet_style_prefer_collection_expression = when_types_loosely_match:suggestion dotnet_style_namespace_match_folder = true:suggestion dotnet_style_readonly_field = true:suggestion dotnet_style_predefined_type_for_locals_parameters_members = true:error dotnet_style_predefined_type_for_member_access = true:error dotnet_style_require_accessibility_modifiers = never:error dotnet_style_allow_multiple_blank_lines_experimental = true:silent dotnet_style_allow_statement_immediately_after_block_experimental = true:silent dotnet_code_quality_unused_parameters = all:suggestion dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:none dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:none dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:none dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent dotnet_style_qualification_for_field = false:error dotnet_style_qualification_for_property = false:error dotnet_style_qualification_for_method = false:error dotnet_style_qualification_for_event = false:error dotnet_diagnostic.CA1305.severity = none dotnet_diagnostic.CA1304.severity = none # Microsoft .NET properties trim_trailing_whitespace = true csharp_preferred_modifier_order = public, private, protected, internal, new, static, abstract, virtual, sealed, readonly, override, extern, unsafe, volatile, async:suggestion resharper_namespace_body = file_scoped dotnet_naming_rule.private_constants_rule.severity = warning dotnet_naming_rule.private_constants_rule.style = upper_camel_case_style dotnet_naming_rule.private_constants_rule.symbols = private_constants_symbols dotnet_naming_rule.private_instance_fields_rule.severity = warning dotnet_naming_rule.private_instance_fields_rule.style = lower_camel_case_style dotnet_naming_rule.private_instance_fields_rule.symbols = private_instance_fields_symbols dotnet_naming_rule.private_static_fields_rule.severity = warning dotnet_naming_rule.private_static_fields_rule.style = lower_camel_case_style dotnet_naming_rule.private_static_fields_rule.symbols = private_static_fields_symbols dotnet_naming_rule.private_static_readonly_rule.severity = warning dotnet_naming_rule.private_static_readonly_rule.style = upper_camel_case_style dotnet_naming_rule.private_static_readonly_rule.symbols = private_static_readonly_symbols dotnet_naming_style.lower_camel_case_style.capitalization = camel_case dotnet_naming_style.upper_camel_case_style.capitalization = pascal_case dotnet_naming_symbols.private_constants_symbols.applicable_accessibilities = private dotnet_naming_symbols.private_constants_symbols.applicable_kinds = field dotnet_naming_symbols.private_constants_symbols.required_modifiers = const dotnet_naming_symbols.private_instance_fields_symbols.applicable_accessibilities = private dotnet_naming_symbols.private_instance_fields_symbols.applicable_kinds = field dotnet_naming_symbols.private_static_fields_symbols.applicable_accessibilities = private dotnet_naming_symbols.private_static_fields_symbols.applicable_kinds = field dotnet_naming_symbols.private_static_fields_symbols.required_modifiers = static dotnet_naming_symbols.private_static_readonly_symbols.applicable_accessibilities = private dotnet_naming_symbols.private_static_readonly_symbols.applicable_kinds = field dotnet_naming_symbols.private_static_readonly_symbols.required_modifiers = static, readonly dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:none dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:none dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:none # Sort using and Import directives with System.* appearing first dotnet_sort_system_directives_first = true # Avoid "this." and "Me." if not necessary dotnet_style_qualification_for_field = false:error dotnet_style_qualification_for_property = false:error dotnet_style_qualification_for_method = false:error dotnet_style_qualification_for_event = false:error # Use language keywords instead of framework type names for type references dotnet_style_predefined_type_for_locals_parameters_members = true:error dotnet_style_predefined_type_for_member_access = true:error # Suggest more modern language features when available dotnet_style_object_initializer = true:suggestion dotnet_style_collection_initializer = true:suggestion dotnet_style_coalesce_expression = false:suggestion dotnet_style_null_propagation = true:suggestion dotnet_style_explicit_tuple_names = true:suggestion # Prefer "var" everywhere csharp_style_var_for_built_in_types = true:error csharp_style_var_when_type_is_apparent = true:error csharp_style_var_elsewhere = true:error # Prefer method-like constructs to have a block body csharp_style_expression_bodied_methods = true:error csharp_style_expression_bodied_local_functions = true:error csharp_style_expression_bodied_constructors = true:error csharp_style_expression_bodied_operators = true:error resharper_place_expr_method_on_single_line = false # Prefer property-like constructs to have an expression-body csharp_style_expression_bodied_properties = true:error csharp_style_expression_bodied_indexers = true:error csharp_style_expression_bodied_accessors = true:error # Suggest more modern language features when available csharp_style_pattern_matching_over_is_with_cast_check = true:error csharp_style_pattern_matching_over_as_with_null_check = true:error csharp_style_inlined_variable_declaration = true:suggestion csharp_style_throw_expression = true:suggestion csharp_style_conditional_delegate_call = true:suggestion # Newline settings #csharp_new_line_before_open_brace = all:error csharp_new_line_before_else = true csharp_new_line_before_catch = true csharp_new_line_before_finally = true csharp_new_line_before_members_in_object_initializers = true csharp_new_line_before_members_in_anonymous_types = true dotnet_style_require_accessibility_modifiers = never:error insert_final_newline = false csharp_using_directive_placement = outside_namespace:silent csharp_prefer_simple_using_statement = true:suggestion csharp_prefer_braces = true:silent csharp_style_namespace_declarations = file_scoped:silent csharp_style_prefer_method_group_conversion = true:silent csharp_style_prefer_top_level_statements = true:silent csharp_style_prefer_primary_constructors = true:suggestion csharp_prefer_system_threading_lock = true:suggestion csharp_style_prefer_simple_property_accessors = true:suggestion csharp_style_expression_bodied_lambdas = true:silent csharp_style_prefer_null_check_over_type_check = true:suggestion csharp_prefer_simple_default_expression = true:suggestion csharp_style_prefer_local_over_anonymous_function = true:suggestion csharp_style_prefer_index_operator = true:suggestion csharp_style_prefer_range_operator = true:suggestion csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion csharp_style_prefer_implicitly_typed_lambda_expression = true:suggestion csharp_style_prefer_tuple_swap = true:suggestion csharp_style_prefer_unbound_generic_type_in_nameof = true:suggestion csharp_style_prefer_utf8_string_literals = true:suggestion csharp_style_deconstructed_variable_declaration = true:suggestion csharp_style_unused_value_assignment_preference = discard_variable:suggestion csharp_style_unused_value_expression_statement_preference = discard_variable:silent csharp_prefer_static_local_function = true:suggestion csharp_prefer_static_anonymous_function = true:suggestion csharp_style_prefer_readonly_struct = true:suggestion csharp_style_prefer_readonly_struct_member = true:suggestion csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true:silent csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true:silent csharp_style_prefer_switch_expression = true:suggestion csharp_style_prefer_pattern_matching = true:silent csharp_style_prefer_not_pattern = true:suggestion csharp_style_prefer_extended_property_pattern = true:suggestion # Legacy rules dotnet_diagnostic.CA1001.severity = error dotnet_diagnostic.CA1009.severity = error dotnet_diagnostic.CA1016.severity = error dotnet_diagnostic.CA1033.severity = error dotnet_diagnostic.CA1049.severity = error dotnet_diagnostic.CA1060.severity = error dotnet_diagnostic.CA1061.severity = error dotnet_diagnostic.CA1063.severity = error dotnet_diagnostic.CA1065.severity = error dotnet_diagnostic.CA1301.severity = error dotnet_diagnostic.CA1400.severity = error dotnet_diagnostic.CA1401.severity = error dotnet_diagnostic.CA1403.severity = error dotnet_diagnostic.CA1404.severity = error dotnet_diagnostic.CA1405.severity = error dotnet_diagnostic.CA1410.severity = error dotnet_diagnostic.CA1415.severity = error dotnet_diagnostic.CA1821.severity = error dotnet_diagnostic.CA1900.severity = error dotnet_diagnostic.CA1901.severity = error dotnet_diagnostic.CA2002.severity = error dotnet_diagnostic.CA2100.severity = error dotnet_diagnostic.CA2101.severity = error dotnet_diagnostic.CA2108.severity = error dotnet_diagnostic.CA2111.severity = error dotnet_diagnostic.CA2112.severity = error dotnet_diagnostic.CA2114.severity = error dotnet_diagnostic.CA2116.severity = error dotnet_diagnostic.CA2117.severity = error dotnet_diagnostic.CA2122.severity = error dotnet_diagnostic.CA2123.severity = error dotnet_diagnostic.CA2124.severity = error dotnet_diagnostic.CA2126.severity = error dotnet_diagnostic.CA2131.severity = error dotnet_diagnostic.CA2132.severity = error dotnet_diagnostic.CA2133.severity = error dotnet_diagnostic.CA2134.severity = error dotnet_diagnostic.CA2137.severity = error dotnet_diagnostic.CA2138.severity = error dotnet_diagnostic.CA2140.severity = error dotnet_diagnostic.CA2141.severity = error dotnet_diagnostic.CA2146.severity = error dotnet_diagnostic.CA2147.severity = error dotnet_diagnostic.CA2149.severity = error dotnet_diagnostic.CA2200.severity = error dotnet_diagnostic.CA2202.severity = error dotnet_diagnostic.CA2207.severity = error dotnet_diagnostic.CA2212.severity = error dotnet_diagnostic.CA2213.severity = error dotnet_diagnostic.CA2214.severity = error dotnet_diagnostic.CA2216.severity = error dotnet_diagnostic.CA2220.severity = error dotnet_diagnostic.CA2229.severity = error dotnet_diagnostic.CA2231.severity = error dotnet_diagnostic.CA2232.severity = error dotnet_diagnostic.CA2235.severity = error dotnet_diagnostic.CA2236.severity = error dotnet_diagnostic.CA2237.severity = error dotnet_diagnostic.CA2238.severity = error dotnet_diagnostic.CA2240.severity = error dotnet_diagnostic.CA2241.severity = error dotnet_diagnostic.CA2242.severity = error # Test Projects # IDE0022: Use expression body for method dotnet_diagnostic.IDE0022.severity = silent # IDE0130: Namespace match folder structure dotnet_diagnostic.IDE0130.severity = none [Benchmarks/**/*.cs] dotnet_diagnostic.CA1050.severity = none # CA1050: Declare types in namespaces [**/Humanizer.Tests/**/*.cs] dotnet_diagnostic.CA1050.severity = none # CA1050: Declare types in namespaces # Xml files [*.{xml,config,nuspec,resx,vsixmanifest,csproj,targets,props,fsproj}] indent_size = 2 [*.json] indent_size = 2 ================================================ FILE: .gitattributes ================================================ * text=auto # Custom for Visual Studio *.cs diff=csharp *.sln merge=union *.csproj merge=union *.vbproj merge=union *.fsproj merge=union *.dbproj merge=union *.snk binary # Normalise endings to CRLF *.cs eol=crlf *.xml eol=crlf *.xaml eol=crlf *.xsl eol=crlf *.xsd eol=crlf *.cshtml eol=crlf *.css eol=crlf *.js eol=crlf *.txt eol=crlf *.config eol=crlf *.sql eol=crlf *.sln eol=crlf *.csproj eol=crlf *.vbproj eol=crlf *.fsproj eol=crlf *.dbproj eol=crlf *.nunit eol=crlf *.html eol=crlf *.md eol=crlf *.proj eol=crlf *.bat eol=crlf *.cmd eol=crlf *.nuspec eol=crlf *.targets eol=crlf *.conf eol=crlf *.manifest eol=crlf *.ps1 eol=crlf *.resx eol=crlf *.asax eol=crlf *.aspx eol=crlf *.ncrunchproject eol=crlf *.ncrunchsolution eol=crlf *.msbuild eol=crlf *.template eol=crlf *.settings eol=crlf *.java eol=crlf .gitattributes eol=crlf .classpath eol=crlf .project eol=crlf # Standard to msysgit *.doc diff=astextplain *.DOC diff=astextplain *.docx diff=astextplain *.DOCX diff=astextplain *.dot diff=astextplain *.DOT diff=astextplain *.pdf diff=astextplain *.PDF diff=astextplain *.rtf diff=astextplain *.RTF diff=astextplain *.verified.txt text eol=lf working-tree-encoding=UTF-8 ================================================ FILE: .github/CODE_OF_CONDUCT.md ================================================ # Code of Conduct This project has adopted the code of conduct defined by the Contributor Covenant to clarify expected behavior in our community. For more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct). ================================================ FILE: .github/CONTRIBUTING.md ================================================ ## How to contribute? Your contributions to Humanizer are very welcome. If you find a bug, please raise it as an issue. Even better fix it and send a pull request. If you like to help out with existing bugs and feature requests just check out the list of [issues](https://github.com/Humanizr/Humanizer/issues) and grab and fix one. Some of the issues are labeled as as `jump in`. These issues are generally low hanging fruit so you can start with easier tasks. This project has adopted the code of conduct defined by the [Contributor Covenant](http://contributor-covenant.org/) to clarify expected behavior in our community. For more information see the [.NET Foundation Code of Conduct](http://www.dotnetfoundation.org/code-of-conduct). ### Getting started This project uses C# 8 language features and SDK-style projects, so you'll need any edition of [Visual Studio 2019](https://www.visualstudio.com/downloads/download-visual-studio-vs) to open and compile the project. The free [Community Edition](https://go.microsoft.com/fwlink/?LinkId=532606&clcid=0x409) will work. ### Contribution guideline This project uses [GitHub flow](http://scottchacon.com/2011/08/31/github-flow.html) for pull requests. So if you want to contribute, fork the repo, preferably create a local branch, based off of the `main` branch, to avoid conflicts with other activities, fix an issue, run build.cmd from the root of the project, and send a PR if all is green. Pull requests are code reviewed. Here is a checklist you should tick through before submitting a pull request: - Implementation is clean - Code adheres to the existing coding standards; e.g. no curlies for one-line blocks, no redundant empty lines between methods or code blocks, spaces rather than tabs, etc. There is an `.editorconfig` file that must be respected. - No ReSharper warnings - There is proper unit test coverage - If the code is copied from StackOverflow (or a blog or OSS) full disclosure is included. That includes required license files and/or file headers explaining where the code came from with proper attribution - There are very few or no comments (because comments shouldn't be needed if you write clean code) - Xml documentation is added/updated for the addition/change - Your PR is (re)based on top of the latest commits from the `main` branch (more info below) - Link to the issue(s) you're fixing from your PR description. Use `fixes #` - Readme is updated if you change an existing feature or add a new one - Run either `build.cmd` or `build.ps1` and ensure there are no test failures Please rebase your code on top of the latest `main` branch commits. Before working on your fork make sure you pull the latest so you work on top of the latest commits to avoid merge conflicts. Also before sending the pull request please rebase your code as there is a chance there have been new commits pushed after you pulled last. Please refer to [this guide](https://gist.github.com/jbenet/ee6c9ac48068889b0912#the-workflow) if you're new to git. ### Need your help with localisation One area where Humanizer can always use your help is localisation. Currently Humanizer supports quite a few localisations for `DateTime.Humanize`, `TimeSpan.Humanize`, `ToWords` and `ToOrdinalWords`. Humanizer could definitely do with more translations. To add a translation for `DateTime.Humanize` and `TimeSpan.Humanize`, fork the repository if you haven't done yet, duplicate the [resources.resx](https://github.com/Humanizr/Humanizer/blob/main/src/Humanizer/Properties/Resources.resx) file, add your target [locale code](http://msdn.microsoft.com/en-us/library/hh441729.aspx) to the end (e.g. resources.ru.resx for Russian), translate the values to your language, register your formatter in [FormatterRegistry.cs](https://github.com/Humanizr/Humanizer/blob/main/src/Humanizer/Configuration/FormatterRegistry.cs), write unit tests for the translation, commit, and send a pull request for it. Thanks. Some languages have complex rules when it comes to dealing with numbers; for example, in Romanian "5 days" is "5 zile", while "24 days" is "24 de zile" and in Arabic "2 days" is "يومان" not "2 يوم". Obviously a normal resource file doesn't cut it in these cases as a more complex mapping is required. In cases like this, in addition to creating a resource file, you should also subclass [`DefaultFormatter`](https://github.com/Humanizr/Humanizer/blob/main/src/Humanizer/Localisation/Formatters/DefaultFormatter.cs) in a class that represents your language; e.g. [`RomanianFormatter`](https://github.com/Humanizr/Humanizer/blob/main/src/Humanizer/Localisation/Formatters/RomanianFormatter.cs) and then override the methods that need the complex rules. We think overriding the `GetResourceKey` method should be enough. To see how to do that check out `RomanianFormatter` and `RussianFormatter`. Then you return an instance of your class in the [`Configurator`](https://github.com/Humanizr/Humanizer/blob/main/src/Humanizer/Configuration/Configurator.cs) class in the getter of the [Formatter property](https://github.com/Humanizr/Humanizer/blob/main/src/Humanizer/Configuration/Configurator.cs) based on the current culture. Translations for `ToWords` and `ToOrdinalWords` methods are currently done in code as there is a huge difference between the way different languages deal with number words. Check out [Dutch](https://github.com/Humanizr/Humanizer/blob/main/src/Humanizer/Localisation/NumberToWords/DutchNumberToWordsConverter.cs) and [Russian](https://github.com/Humanizr/Humanizer/blob/main/src/Humanizer/Localisation/NumberToWords/RussianNumberToWordsConverter.cs) localisations for examples of how you can write a Converter for your language. You should then register your converter in the [ConverterFactory](https://github.com/Humanizr/Humanizer/blob/main/src/Humanizer/NumberToWordsExtension.cs#L13) for it to kick in on your locale. Don't forget to write tests for your localisations. Check out the existing [DateHumanizeTests](https://github.com/Humanizr/Humanizer/blob/main/tests/Humanizer.Tests/Localisation/ru-RU/DateHumanizeTests.cs), [TimeSpanHumanizeTests](https://github.com/Humanizr/Humanizer/blob/main/tests/Humanizer.Tests/Localisation/ru-RU/TimeSpanHumanizeTests.cs) and [NumberToWordsTests](https://github.com/Humanizr/Humanizer/blob/main/tests/Humanizer.Tests/Localisation/ru-RU/NumberToWordsTests.cs). ================================================ FILE: .github/PULL_REQUEST_TEMPLATE.md ================================================ Here is a checklist you should tick through before submitting a pull request: - [ ] Implementation is clean - [ ] Code adheres to the existing coding standards; e.g. no curlies for one-line blocks, no redundant empty lines between methods or code blocks, spaces rather than tabs, etc. - [ ] No Code Analysis warnings - [ ] There is proper unit test coverage - [ ] If the code is copied from StackOverflow (or a blog or OSS) full disclosure is included. That includes required license files and/or file headers explaining where the code came from with proper attribution - [ ] There are very few or no comments (because comments shouldn't be needed if you write clean code) - [ ] Xml documentation is added/updated for the addition/change - [ ] Your PR is (re)based on top of the latest commits from the `main` branch (more info below) - [ ] Link to the issue(s) you're fixing from your PR description. Use `fixes #` - [ ] Readme is updated if you change an existing feature or add a new one - [ ] Run either `build.cmd` or `build.ps1` and ensure there are no test failures ================================================ FILE: .github/codeql/codeql-config.yml ================================================ name: humanizer-codeql queries: - uses: security-extended - uses: security-and-quality paths: - src/Humanizer/ paths-ignore: - src/**/bin/** - src/**/obj/** ================================================ FILE: .github/copilot-instructions.md ================================================ # Agent Instructions ## Scope These instructions apply to the entire repository. ## Project Overview - Humanizer is a .NET library for turning numbers, dates, times, enums, quantities, etc. into human-friendly text across many locales. - The main library lives in `src/Humanizer`; tests are under `tests/`. ## Toolchain - Primary language: C# (modern features). - Target frameworks: .NET 8.0, .NET 10.0, and .NET Framework 4.8. - Tests use xUnit and should live alongside similar tests in `tests/Humanizer.Tests`. - Build with the .NET CLI (`dotnet`). Prefer the latest SDK (see install script in `.github/copilot-instructions.md`). ## Coding Guidelines - Respect `.editorconfig`; use spaces, 4-space indentation, and file-scoped namespaces. - Use `var` for obvious types, and language keywords (`string`, `int`, etc.). - Order `using` directives with `System.*` first; prefer existing global usings. - Keep code self-documenting; use comments sparingly. - Never wrap imports in `try/catch`. - Avoid unnecessary `this.` and braces for one-line blocks; trim redundant blank lines. - Follow existing naming conventions (camelCase private fields, PascalCase public members/constants/static readonly). - Add XML documentation for new or modified public APIs. ## Testing Expectations - Every functional change must include or update xUnit tests in `tests/Humanizer.Tests`. - Use culture-specific folders and `UseCulture` attribute for localization tests when applicable. - Run the test suite for the supported .NET targets (`dotnet test --project tests/Humanizer.Tests/Humanizer.Tests.csproj --framework net10.0` and `--framework net8.0`). Avoid invoking the net48 target on Linux, and allow a few minutes for each run to complete. ## Build & Validation - Build command: `dotnet build src/Humanizer/Humanizer.csproj -c Release /t:PackNuSpecs /p:PackageOutputPath=` (from the repository root). It must succeed without warnings or errors. - If you need to reference those newly build packages, create or update `NuGet.config` to use that package output path as a package source--but never commit changes to that file. - When verifying restore, build first, then pass the output path into `tests/verify-packages.ps1`. - When running `tests/verify-packages.ps1`, you can override the default `-MinimumPassingSdkVersion` (`9.0.200`) to mark older SDK/MSBuild restores as expected failures. - Do not introduce new compiler warnings or break existing build/test workflows. ## Localization Guidance - When adding a locale, duplicate and translate the relevant resource files under `src/Humanizer/Properties`. - Register new formatters/converters in the appropriate registries (see `Configuration/FormatterRegistry.cs` and number converter factories). - Cover new localization behavior with targeted tests under `tests/Humanizer.Tests/Localisation/{culture}`. ## Documentation Updates - Update `readme.md`, resource comments, or XML docs when introducing new features or behavior changes. - Provide meaningful examples in documentation and XML summaries where appropriate. ## Pull Request Guidelines - Keep changes focused with clear commit messages. - Follow repository PR template expectations: summarize changes, list tests run, and reference related issues (e.g., `fixes #123`) when applicable. - Ensure the codebase remains backward-compatible unless intentionally introducing a documented breaking change. ================================================ FILE: .github/dependabot.yml ================================================ version: 2 updates: - package-ecosystem: nuget directory: "/" schedule: interval: daily open-pull-requests-limit: 10 ================================================ FILE: .github/workflows/.devskim ================================================ { "Globs": [ "**/.git/**", "**/bin/**", "**/obj/**", "**/nuget.config" // exact file at repo root ] } ================================================ FILE: .github/workflows/benchmarks-baseline-vs-current.yml ================================================ name: Benchmark Baseline vs Current on: workflow_dispatch: inputs: baselineVersion: description: 'NuGet version of Humanizer to use for the baseline run' required: true type: string default: '3.0.0-rc.6' push: paths: - '.github/workflows/benchmarks-baseline-vs-current.yml' pull_request: paths: - '.github/workflows/benchmarks-baseline-vs-current.yml' schedule: - cron: '0 4 * * 1' # Every Monday at 04:00 UTC jobs: benchmark: name: Run Benchmarks (${{ matrix.kind }}) runs-on: ubuntu-latest timeout-minutes: 180 env: BASELINE_VERSION: ${{ inputs.baselineVersion || '3.0.0-rc.6' }} strategy: matrix: kind: [baseline, current] steps: - name: Checkout repository uses: actions/checkout@v5 with: fetch-depth: 0 - name: Setup .NET 8,10 uses: actions/setup-dotnet@v5 with: dotnet-version: | 8.0 10.0 - name: Display run information run: | echo "## Benchmark Run: ${{ matrix.kind }}" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "- **Commit SHA:** ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY echo "- **Baseline Version:** ${{ env.BASELINE_VERSION }}" >> $GITHUB_STEP_SUMMARY echo "- **Run Type:** ${{ matrix.kind }}" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - name: Build Benchmarks (baseline) if: matrix.kind == 'baseline' run: | out="artifacts/baseline" mkdir -p "$out" dotnet run --project src/Benchmarks/Benchmarks.csproj -c Release -f net8.0 -- --filter '*' --artifacts "$out" --envVars UseBaselinePackage:true,BaselinePackageVersion:${{ env.BASELINE_VERSION }} - name: Build Benchmarks (current) if: matrix.kind == 'current' run: | out="artifacts/current" mkdir -p "$out" dotnet run --project src/Benchmarks/Benchmarks.csproj -c Release -f net8.0 -- --filter '*' --artifacts "$out" - name: Append Results to Summary run: | out="artifacts/${{ matrix.kind }}" # Find all markdown files and append them to the summary echo "" >> $GITHUB_STEP_SUMMARY echo "### Benchmark Results (${{ matrix.kind }})" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY while IFS= read -r MD; do cat "$MD" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY done < <(find "$out" -type f -name '*.md') - name: Upload JSON Artifacts uses: actions/upload-artifact@v4 with: name: humanizer-bdn-${{ matrix.kind }}-json path: artifacts/${{ matrix.kind }}/**/*.json retention-days: 7 - name: Upload All Artifacts uses: actions/upload-artifact@v4 with: name: humanizer-bdn-${{ matrix.kind }}-all path: artifacts/${{ matrix.kind }}/ retention-days: 7 compare: name: Compare Baseline vs Current runs-on: ubuntu-latest needs: benchmark env: BASELINE_VERSION: ${{ inputs.baselineVersion || '3.0.0-rc.6' }} steps: - name: Checkout repository uses: actions/checkout@v5 with: fetch-depth: 0 - name: Download Baseline JSON uses: actions/download-artifact@v4 with: name: humanizer-bdn-baseline-json path: baseline - name: Download Current JSON uses: actions/download-artifact@v4 with: name: humanizer-bdn-current-json path: current - name: Setup .NET uses: actions/setup-dotnet@v5 with: dotnet-version: '10.x' - name: Clone and Build ResultsComparer run: | git clone --depth 1 https://github.com/dotnet/performance - name: Split Benchmark Results by TFM run: | set -euo pipefail baseline_results=$(find baseline -type d -name results -print -quit) current_results=$(find current -type d -name results -print -quit) if [ -z "$baseline_results" ]; then echo "Baseline results directory not found under 'baseline'." >&2 exit 1 fi if [ -z "$current_results" ]; then echo "Current results directory not found under 'current'." >&2 exit 1 fi echo "Using baseline results directory: $baseline_results" echo "Using current results directory: $current_results" pwsh -File src/scripts/split-benchmark-results.ps1 -InputDir "$baseline_results" -OutputRoot baseline-split pwsh -File src/scripts/split-benchmark-results.ps1 -InputDir "$current_results" -OutputRoot current-split - name: Run ResultsComparer for each TFM run: | mkdir -p comparisons # Compare each target framework independently for tfm_dir in baseline-split/*; do if [ -d "$tfm_dir" ]; then tfm=$(basename "$tfm_dir") echo "Comparing results for $tfm..." if [ -d "current-split/$tfm" ]; then dotnet run --project performance/src/tools/ResultsComparer/ResultsComparer.csproj -c Release -p:PERFLAB_TARGET_FRAMEWORKS=net10.0 -f net10.0 --base "$tfm_dir" --diff "current-split/$tfm" --threshold "5%" > "comparisons/diff-$tfm.md" || true else echo "⚠️ No current results found for $tfm" > "comparisons/diff-$tfm.md" fi fi done - name: Append Comparison to Summary run: | echo "" >> $GITHUB_STEP_SUMMARY echo "## Performance Comparison: Baseline vs Current" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "**Baseline Version:** ${{ env.BASELINE_VERSION }}" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY # Append comparison for each TFM for diff_file in comparisons/diff-*.md; do if [ -f "$diff_file" ]; then tfm=$(basename "$diff_file" .md | sed 's/diff-//') echo "### Results for $tfm" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY cat "$diff_file" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY fi done if [ ! -f comparisons/diff-*.md ]; then echo "⚠️ No comparison results available" >> $GITHUB_STEP_SUMMARY fi - name: Upload Comparison Report uses: actions/upload-artifact@v4 if: always() with: name: humanizer-bdn-comparison path: comparisons/ retention-days: 7 ================================================ FILE: .github/workflows/codeql.yml ================================================ # For most projects, this workflow file will not need changing; you simply need # to commit it to your repository. # # You may wish to alter this file to override the set of languages analyzed, # or to provide custom queries or build logic. # # ******** NOTE ******** # We have attempted to detect the languages in your repository. Please check # the `language` matrix defined below to confirm you have the correct set of # supported CodeQL languages. # name: "CodeQL Advanced" on: push: branches: - main - 'rel/**' pull_request: branches: - main - 'rel/**' schedule: - cron: '41 11 * * 2' jobs: analyze: name: Analyze C# runs-on: 'windows-latest' permissions: security-events: write packages: read actions: read contents: read steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 fetch-tags: true # Add any setup steps before running the `github/codeql-action/init` action. # This includes steps like installing compilers or runtimes (`actions/setup-node` # or others). This is typically only required for manual builds. # - name: Setup runtime (example) # uses: actions/setup-example@v1 - uses: actions/setup-dotnet@v5 with: global-json-file: global.json # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: languages: csharp build-mode: manual config-file: .github/codeql/codeql-config.yml - name: Build working-directory: src shell: pwsh run: | dotnet build Humanizer/Humanizer.csproj -c Release --nologo --verbosity minimal - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 ================================================ FILE: .github/workflows/copilot-setup-steps.yml ================================================ name: "Copilot Setup Steps" # Automatically run the setup steps when they are changed to allow for easy validation, and # allow manual testing through the repository's "Actions" tab on: workflow_dispatch: push: paths: - .github/workflows/copilot-setup-steps.yml pull_request: paths: - .github/workflows/copilot-setup-steps.yml jobs: # The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot. copilot-setup-steps: runs-on: ubuntu-latest # Set the permissions to the lowest permissions possible needed for your steps. # Copilot will be given its own token for its operations. permissions: # If you want to clone the repository as part of your setup steps, for example to install dependencies, you'll need the `contents: read` permission. If you don't clone the repository in your setup steps, Copilot will do this for you automatically after the steps complete. contents: read # You can define any steps you want, and they will run before the agent starts. # If you do not check out your code, Copilot will do this for you. steps: - name: Checkout code uses: actions/checkout@v5 with: fetch-depth: 0 fetch-tags: true - uses: actions/setup-dotnet@v5 with: global-json-file: global.json ================================================ FILE: .github/workflows/devskim.yml ================================================ # This workflow uses actions that are not certified by GitHub. # They are provided by a third-party and are governed by # separate terms of service, privacy policy, and support # documentation. name: DevSkim on: push: branches: - main - 'rel/**' pull_request: branches: - main - 'rel/**' schedule: - cron: '23 9 * * 2' jobs: lint: name: DevSkim runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write steps: - name: Checkout code uses: actions/checkout@v4 - name: Run DevSkim scanner uses: microsoft/DevSkim-Action@v1 with: options-json: .github/workflows/.devskim.json - name: Upload DevSkim scan results to GitHub Security tab uses: github/codeql-action/upload-sarif@v3 with: sarif_file: devskim-results.sarif ================================================ FILE: .github/workflows/jekyll-gh-pages.yml ================================================ # Sample workflow for building and deploying a Jekyll site to GitHub Pages name: Deploy Jekyll with GitHub Pages dependencies preinstalled on: # Runs on pushes targeting the default branch push: branches: ["main"] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages permissions: contents: read pages: write id-token: write # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. concurrency: group: "pages" cancel-in-progress: false jobs: # Build job build: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Prepare index.md from readme run: | echo "---" > docs/index.md echo "layout: default" >> docs/index.md echo "title: Humanizer" >> docs/index.md echo "---" >> docs/index.md echo "" >> docs/index.md cat readme.md >> docs/index.md - name: Copy logo to docs run: cp logo.png docs/logo.png - name: Setup Pages uses: actions/configure-pages@v5 - name: Build with Jekyll uses: actions/jekyll-build-pages@v1 with: source: ./docs destination: ./_site - name: Upload artifact uses: actions/upload-pages-artifact@v3 # Deployment job deploy: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest needs: build steps: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 ================================================ FILE: .gitignore ================================================ ## -------------------------------------------- ## xUnit.net specific ignores Test*.html Test*.xml *.zip *.exe *.nuget.props *.nuget.targets ## -------------------------------------------- ## Adapted from https://raw.githubusercontent.com/github/gitignore/a4ec7f03ca5ae0bf09fad42c0fb7d1e8346bcf25/VisualStudio.gitignore # User-specific files *.suo *.user *.userosscache *.sln.docstates # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ [Bb]in/ [Oo]bj/ # Visual Studio 2015 cache/options directory .vs/ # Visual Studio test runner [Tt]est[Rr]esult*/ Index.dat Storage.dat # DNX project.lock.json *.lock.json artifacts/ # Visual Studio profiler *.psess *.vsp *.vspx # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user # JetBrains IDE .idea/ # JustCode is a .NET coding add-in .JustCode # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # NCrunch _NCrunch_* .*crunch*.local.xml # NuGet Packages *.nupkg **/packages/* #!**/packages/build/ # Windows Store app package directory AppPackages/ # Visual Studio cache files *.[Cc]ache !*.[Cc]ache/ # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm # local tools .store/ src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.received.txt .DS_Store /samples/Humanizer.MvcSample/Humanizer.MvcSample.sln /src/Humanizer/Properties/launchSettings.json *.received.* # Jekyll docs/_site/ docs/.jekyll-cache/ docs/.sass-cache/ # BenchmarkDotNet artifacts **/BenchmarkDotNet.Artifacts/ ================================================ FILE: AGENTS.md ================================================ # Agent Instructions ## Scope These instructions apply to the entire repository. ## Project Overview - Humanizer is a .NET library for turning numbers, dates, times, enums, quantities, etc. into human-friendly text across many locales. - The main library lives in `src/Humanizer`; tests are under `tests/`. ## Toolchain - Primary language: C# (modern features). - Target frameworks: .NET 8.0, .NET 10.0, and .NET Framework 4.8. - Tests use xUnit and should live alongside similar tests in `tests/Humanizer.Tests`. - Build with the .NET CLI (`dotnet`). Prefer the latest SDK (see install script in `.github/copilot-instructions.md`). ## Coding Guidelines - Respect `.editorconfig`; use spaces, 4-space indentation, and file-scoped namespaces. - Use `var` for obvious types, and language keywords (`string`, `int`, etc.). - Order `using` directives with `System.*` first; prefer existing global usings. - Keep code self-documenting; use comments sparingly. - Never wrap imports in `try/catch`. - Avoid unnecessary `this.` and braces for one-line blocks; trim redundant blank lines. - Follow existing naming conventions (camelCase private fields, PascalCase public members/constants/static readonly). - Add XML documentation for new or modified public APIs. ## Testing Expectations - Every functional change must include or update xUnit tests in `tests/Humanizer.Tests`. - Use culture-specific folders and `UseCulture` attribute for localization tests when applicable. - Run the test suite for the supported .NET targets (`dotnet test --project tests/Humanizer.Tests/Humanizer.Tests.csproj --framework net10.0` and `--framework net8.0`). Avoid invoking the net48 target on Linux, and allow a few minutes for each run to complete. ## Build & Validation - Build command: `dotnet build src/Humanizer/Humanizer.csproj -c Release /t:PackNuSpecs /p:PackageOutputPath=` (from the repository root). It must succeed without warnings or errors. - If you need to reference those newly build packages, create or update `NuGet.config` to use that package output path as a package source--but never commit changes to that file. - When verifying restore, build first, then pass the output path into `tests/verify-packages.ps1`. - When running `tests/verify-packages.ps1`, you can override the default `-MinimumPassingSdkVersion` (`9.0.200`) to mark older SDK/MSBuild restores as expected failures. - Do not introduce new compiler warnings or break existing build/test workflows. ## Localization Guidance - When adding a locale, duplicate and translate the relevant resource files under `src/Humanizer/Properties`. - Register new formatters/converters in the appropriate registries (see `Configuration/FormatterRegistry.cs` and number converter factories). - Cover new localization behavior with targeted tests under `tests/Humanizer.Tests/Localisation/{culture}`. ## Documentation Updates - Update `readme.md`, resource comments, or XML docs when introducing new features or behavior changes. - Provide meaningful examples in documentation and XML summaries where appropriate. ## Pull Request Guidelines - Keep changes focused with clear commit messages. - Follow repository PR template expectations: summarize changes, list tests run, and reference related issues (e.g., `fixes #123`) when applicable. - Ensure the codebase remains backward-compatible unless intentionally introducing a documented breaking change. ================================================ FILE: Directory.Build.props ================================================ preview enable true enable true 1573;1591 true embedded true 0024000004800000940000000602000000240000525341310004000001000100F9104F5F9BDB168AE140366EB1CD84C469B020EA3423D5D29996D5214CE2BD9B7C0BA3EAD1CA545C4399668AB8911E61CC1CC83C7DF6D50FD6B781365B467E65173F40A11C957D27C5AA0CB0F8DA9C91C988203CC8AEF1468C74A472839D0FD870DA8D13A4DC6B3AAFDAF0384D8E18E393C613D88BF02A64467A119902204FCC $(MSBuildThisFileDirectory)Humanizer.snk true true true Minimum true true true Claire Novotny, Mehdi Khalili MIT https://humanizr.net 2.12 Copyright © 2012 - $([System.DateTime]::UtcNow.Year) .NET Foundation and Contributors true true true true ================================================ FILE: Directory.Build.targets ================================================ $(Product) ($(TargetFramework)) false true <_Parameter1>CommitHash <_Parameter2>$(SourceRevisionId) <_Parameter1>CloudBuildNumber <_Parameter2>$(BuildVersionSimple) <_Parameter1>CloudBuildNumber <_Parameter2>$(BuildVersionSimple)$(SemVerBuildSuffix) ================================================ FILE: Directory.Packages.props ================================================  true true 10.0.5 ================================================ FILE: Directory.Solution.targets ================================================  ================================================ FILE: Humanizer.slnx ================================================ ================================================ FILE: NuSpecs/Humanizer.Core.af.nuspec ================================================  Humanizer.Core.af $version$ Humanizer Locale (af) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Afrikaans (af) Copyright (c) .NET Foundation and Contributors MIT af ================================================ FILE: NuSpecs/Humanizer.Core.ar.nuspec ================================================  Humanizer.Core.ar $version$ Humanizer Locale (ar) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Arabic (ar) Copyright (c) .NET Foundation and Contributors MIT ar ================================================ FILE: NuSpecs/Humanizer.Core.az.nuspec ================================================ Humanizer.Core.az $version$ Humanizer Locale (az) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Azerbaijani (az) Copyright (c) .NET Foundation and Contributors MIT az ================================================ FILE: NuSpecs/Humanizer.Core.bg.nuspec ================================================  Humanizer.Core.bg $version$ Humanizer Locale (bg) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Bulgarian (bg) Copyright (c) .NET Foundation and Contributors MIT bg ================================================ FILE: NuSpecs/Humanizer.Core.bn.nuspec ================================================  Humanizer.Core.bn $version$ Humanizer Locale (bn) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Bangla (Bangladesh) (bn) Copyright (c) .NET Foundation and Contributors MIT bn ================================================ FILE: NuSpecs/Humanizer.Core.ca.nuspec ================================================  Humanizer.Core.ca $version$ Humanizer Locale (ca) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Catalan (ca) Copyright (c) .NET Foundation and Contributors MIT ca ================================================ FILE: NuSpecs/Humanizer.Core.cs.nuspec ================================================  Humanizer.Core.cs $version$ Humanizer Locale (cs) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Czech (cs) Copyright (c) .NET Foundation and Contributors MIT cs ================================================ FILE: NuSpecs/Humanizer.Core.da.nuspec ================================================  Humanizer.Core.da $version$ Humanizer Locale (da) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Danish (da) Copyright (c) .NET Foundation and Contributors MIT da ================================================ FILE: NuSpecs/Humanizer.Core.de.nuspec ================================================  Humanizer.Core.de $version$ Humanizer Locale (de) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale German (de) Copyright (c) .NET Foundation and Contributors MIT de ================================================ FILE: NuSpecs/Humanizer.Core.el.nuspec ================================================  Humanizer.Core.el $version$ Humanizer Locale (el) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Greek (el) Copyright (c) .NET Foundation and Contributors MIT el ================================================ FILE: NuSpecs/Humanizer.Core.es.nuspec ================================================  Humanizer.Core.es $version$ Humanizer Locale (es) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Spanish (es) Copyright (c) .NET Foundation and Contributors MIT es ================================================ FILE: NuSpecs/Humanizer.Core.fa.nuspec ================================================  Humanizer.Core.fa $version$ Humanizer Locale (fa) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Persian (fa) Copyright (c) .NET Foundation and Contributors MIT fa ================================================ FILE: NuSpecs/Humanizer.Core.fi.nuspec ================================================  Humanizer.Core.fi $version$ Humanizer Locale (fi) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Finnish (Finland) (fi) Copyright (c) .NET Foundation and Contributors MIT fi ================================================ FILE: NuSpecs/Humanizer.Core.fil.nuspec ================================================  Humanizer.Core.fil $version$ Humanizer Locale (fil) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Filipino (Philippines) (fil) Copyright (c) .NET Foundation and Contributors MIT fil ================================================ FILE: NuSpecs/Humanizer.Core.fr.nuspec ================================================  Humanizer.Core.fr $version$ Humanizer Locale (fr) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale French (fr) Copyright (c) .NET Foundation and Contributors MIT fr ================================================ FILE: NuSpecs/Humanizer.Core.he.nuspec ================================================  Humanizer.Core.he $version$ Humanizer Locale (he) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Hebrew (he) Copyright (c) .NET Foundation and Contributors MIT he ================================================ FILE: NuSpecs/Humanizer.Core.hr.nuspec ================================================  Humanizer.Core.hr $version$ Humanizer Locale (hr) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Croatian (hr) Copyright (c) .NET Foundation and Contributors MIT hr ================================================ FILE: NuSpecs/Humanizer.Core.hu.nuspec ================================================  Humanizer.Core.hu $version$ Humanizer Locale (hu) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Hungarian (hu) Copyright (c) .NET Foundation and Contributors MIT hu ================================================ FILE: NuSpecs/Humanizer.Core.hy.nuspec ================================================  Humanizer.Core.hy $version$ Humanizer Locale (hy) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Armenian (hy) Copyright (c) .NET Foundation and Contributors MIT hy ================================================ FILE: NuSpecs/Humanizer.Core.id.nuspec ================================================  Humanizer.Core.id $version$ Humanizer Locale (id) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Indonesian (id) Copyright (c) .NET Foundation and Contributors MIT id ================================================ FILE: NuSpecs/Humanizer.Core.is.nuspec ================================================  Humanizer.Core.is $version$ Humanizer Locale (is) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Icelandic (is) Copyright (c) .NET Foundation and Contributors MIT is ================================================ FILE: NuSpecs/Humanizer.Core.it.nuspec ================================================  Humanizer.Core.it $version$ Humanizer Locale (it) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Italian (it) Copyright (c) .NET Foundation and Contributors MIT it ================================================ FILE: NuSpecs/Humanizer.Core.ja.nuspec ================================================  Humanizer.Core.ja $version$ Humanizer Locale (ja) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Japanese (ja) Copyright (c) .NET Foundation and Contributors MIT ja ================================================ FILE: NuSpecs/Humanizer.Core.ko.nuspec ================================================  Humanizer.Core.ko $version$ Humanizer Locale (ko) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Korean (South Korea) (ko) Copyright (c) .NET Foundation and Contributors MIT ko ================================================ FILE: NuSpecs/Humanizer.Core.ku.nuspec ================================================  Humanizer.Core.ku $version$ Humanizer Locale (ku) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Central Kurdish (ku) Copyright (c) .NET Foundation and Contributors MIT ku ================================================ FILE: NuSpecs/Humanizer.Core.lb.nuspec ================================================  Humanizer.Core.lb $version$ Humanizer Locale (lb) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Luxembourgish (lb) Copyright (c) .NET Foundation and Contributors MIT lb ================================================ FILE: NuSpecs/Humanizer.Core.lt.nuspec ================================================ Humanizer.Core.lt $version$ Humanizer Locale (lt) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Lithuanian (lt) Copyright (c) .NET Foundation and Contributors MIT lt ================================================ FILE: NuSpecs/Humanizer.Core.lv.nuspec ================================================ Humanizer.Core.lv $version$ Humanizer Locale (lv) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Latvian (lv) Copyright (c) .NET Foundation and Contributors MIT lv ================================================ FILE: NuSpecs/Humanizer.Core.ms.nuspec ================================================  Humanizer.Core.ms $version$ Humanizer Locale (ms) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Malay (Malaysia) (ms) Copyright (c) .NET Foundation and Contributors MIT ms ================================================ FILE: NuSpecs/Humanizer.Core.mt.nuspec ================================================  Humanizer.Core.mt $version$ Humanizer Locale (mt) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Maltese (mt) Copyright (c) .NET Foundation and Contributors MIT mt ================================================ FILE: NuSpecs/Humanizer.Core.nb.nuspec ================================================  Humanizer.Core.nb $version$ Humanizer Locale (nb) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Norwegian Bokmål (nb) Copyright (c) .NET Foundation and Contributors MIT nb ================================================ FILE: NuSpecs/Humanizer.Core.nl.nuspec ================================================  Humanizer.Core.nl $version$ Humanizer Locale (nl) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Dutch (nl) Copyright (c) .NET Foundation and Contributors MIT nl ================================================ FILE: NuSpecs/Humanizer.Core.nuspec ================================================  Humanizer.Core $version$ Humanizer Locale (en) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer core package that contains the library and the neutral language (English) resources Copyright (c) .NET Foundation and Contributors MIT en ================================================ FILE: NuSpecs/Humanizer.Core.pl.nuspec ================================================  Humanizer.Core.pl $version$ Humanizer Locale (pl) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Polish (pl) Copyright (c) .NET Foundation and Contributors MIT pl ================================================ FILE: NuSpecs/Humanizer.Core.pt-BR.nuspec ================================================  Humanizer.Core.pt-BR $version$ Humanizer Locale (pt-BR) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Portuguese, Brazil (pt-BR) Copyright (c) .NET Foundation and Contributors MIT pt-BR ================================================ FILE: NuSpecs/Humanizer.Core.pt.nuspec ================================================  Humanizer.Core.pt $version$ Humanizer Locale (pt) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Portuguese (pt) Copyright (c) .NET Foundation and Contributors MIT pt ================================================ FILE: NuSpecs/Humanizer.Core.ro.nuspec ================================================  Humanizer.Core.ro $version$ Humanizer Locale (ro) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Romanian (ro) Copyright (c) .NET Foundation and Contributors MIT ro ================================================ FILE: NuSpecs/Humanizer.Core.ru.nuspec ================================================  Humanizer.Core.ru $version$ Humanizer Locale (ru) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Russian (ru) Copyright (c) .NET Foundation and Contributors MIT ru ================================================ FILE: NuSpecs/Humanizer.Core.sk.nuspec ================================================  Humanizer.Core.sk $version$ Humanizer Locale (sk) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Slovak (sk) Copyright (c) .NET Foundation and Contributors MIT sk ================================================ FILE: NuSpecs/Humanizer.Core.sl.nuspec ================================================  Humanizer.Core.sl $version$ Humanizer Locale (sl) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Slovenian (sl) Copyright (c) .NET Foundation and Contributors MIT sl ================================================ FILE: NuSpecs/Humanizer.Core.sr-Latn.nuspec ================================================  Humanizer.Core.sr-Latn $version$ Humanizer Locale (sr-Latn) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Serbian (sr-Latn) Copyright (c) .NET Foundation and Contributors MIT sr-Latn ================================================ FILE: NuSpecs/Humanizer.Core.sr.nuspec ================================================  Humanizer.Core.sr $version$ Humanizer Locale (sr) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Serbian (sr) Copyright (c) .NET Foundation and Contributors MIT sr ================================================ FILE: NuSpecs/Humanizer.Core.sv.nuspec ================================================  Humanizer.Core.sv $version$ Humanizer Locale (sv) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Swedish (sv) Copyright (c) .NET Foundation and Contributors MIT sv ================================================ FILE: NuSpecs/Humanizer.Core.ta.nuspec.unused ================================================ Humanizer.Core.ta $version$ Humanizer Locale (ta) Mehdi Khalili, Claire Novotny https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Tamil (ta) Copyright (c) .NET Foundation and Contributors MIT ta ================================================ FILE: NuSpecs/Humanizer.Core.th.nuspec ================================================  Humanizer.Core.th $version$ Humanizer Locale (th-TH) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Thai (Thailand) (th) Copyright (c) .NET Foundation and Contributors MIT th ================================================ FILE: NuSpecs/Humanizer.Core.tr.nuspec ================================================  Humanizer.Core.tr $version$ Humanizer Locale (tr) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Turkish (tr) Copyright (c) .NET Foundation and Contributors MIT tr ================================================ FILE: NuSpecs/Humanizer.Core.uk.nuspec ================================================  Humanizer.Core.uk $version$ Humanizer Locale (uk) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Ukrainian (uk) Copyright (c) .NET Foundation and Contributors MIT uk ================================================ FILE: NuSpecs/Humanizer.Core.uz-Cyrl-UZ.nuspec ================================================  Humanizer.Core.uz-Cyrl-UZ $version$ Humanizer Locale (uz-Cyrl-UZ) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Uzbek (Cyrillic, Uzbekistan) (uz-Cyrl-UZ) Copyright (c) .NET Foundation and Contributors MIT uz-Cyrl-UZ ================================================ FILE: NuSpecs/Humanizer.Core.uz-Latn-UZ.nuspec ================================================  Humanizer.Core.uz-Latn-UZ $version$ Humanizer Locale (uz-Latn-UZ) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Uzbek (Latin, Uzbekistan) (uz-Latn-UZ) Copyright (c) .NET Foundation and Contributors MIT uz-Latn-UZ ================================================ FILE: NuSpecs/Humanizer.Core.vi.nuspec ================================================  Humanizer.Core.vi $version$ Humanizer Locale (vi) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Vietnamese (vi) Copyright (c) .NET Foundation and Contributors MIT vi ================================================ FILE: NuSpecs/Humanizer.Core.zh-CN.nuspec ================================================  Humanizer.Core.zh-CN $version$ Humanizer Locale (zh-CN) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Chinese (China) (zh-CN) Copyright (c) .NET Foundation and Contributors MIT zh-CN ================================================ FILE: NuSpecs/Humanizer.Core.zh-Hans.nuspec ================================================  Humanizer.Core.zh-Hans $version$ Humanizer Locale (zh-Hans) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Chinese (zh-Hans) Copyright (c) .NET Foundation and Contributors MIT zh-Hans ================================================ FILE: NuSpecs/Humanizer.Core.zh-Hant.nuspec ================================================  Humanizer.Core.zh-Hant $version$ Humanizer Locale (zh-Hant) Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer Locale Chinese (zh-Hant) Copyright (c) .NET Foundation and Contributors MIT zh-Hant ================================================ FILE: NuSpecs/Humanizer.nuspec ================================================  Humanizer $version$ Humanizer Claire Novotny, Mehdi Khalili https://github.com/Humanizr/Humanizer logo.png false Humanizer meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities Copyright (c) .NET Foundation and Contributors MIT ================================================ FILE: ResXManager.config.xml ================================================ True ================================================ FILE: azure-pipelines.yml ================================================ trigger: - main - rel/* pr: - main - rel/* variables: BuildConfiguration: Release DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true stages: - stage: Build variables: - group: 'Report Generator License Key' jobs: - job: Build pool: vmImage: windows-latest steps: - task: UseDotNet@2 displayName: 'Use .NET 8 SDK' inputs: version: 8.x - task: UseDotNet@2 displayName: 'Use .NET 9 SDK' inputs: version: 9.x - task: UseDotNet@2 displayName: 'Use .NET 10 SDK' inputs: includePreviewVersions: true version: 10.x - task: UseDotNet@2 displayName: 'Use .NET 11 SDK' inputs: includePreviewVersions: true version: 11.x - task: DotNetCoreCLI@2 inputs: command: custom custom: tool arguments: install --tool-path . nbgv displayName: Install NBGV tool - script: nbgv cloud -c -a displayName: Set Version - task: DotNetCoreCLI@2 inputs: command: build projects: ./src/Humanizer/Humanizer.csproj arguments: -c $(BuildConfiguration) /t:PackNuSpecs /p:PackageOutputPath=$(Build.ArtifactStagingDirectory)/Packages displayName: Restore, Build, and Pack - pwsh: | $(Build.SourcesDirectory)/tests/verify-packages.ps1 ` -PackageVersion '$(NBGV_NuGetPackageVersion)' ` -PackagesDirectory '$(Build.ArtifactStagingDirectory)/Packages' ` -IncludeWapProjSmokeTest displayName: Verify Package Structure and Dependencies failOnStderr: false - task: DotNetCoreCLI@2 inputs: command: test projects: | tests/Humanizer.Tests/Humanizer.Tests.csproj tests/Humanizer.Analyzers.Tests/Humanizer.Analyzers.Tests.csproj arguments: -c $(BuildConfiguration) --coverage --xunit-info displayName: Run Tests # Generate code coverage report # https://danielpalme.github.io/ReportGenerator/ - task: reportgenerator@5 displayName: Generate Code Coverage Report inputs: reports: '$(Agent.TempDirectory)/**/*.cobertura.xml' targetdir: $(Build.ArtifactStagingDirectory)/coverageReports/ reporttypes: HtmlInline_AzurePipelines_Dark;Cobertura;Badges license: '$(ReportGeneratorLicenseKey)' publishCodeCoverageResults: true - publish: $(Build.ArtifactStagingDirectory)/Packages displayName: Publish build packages artifact: BuildPackages - stage: CodeSign dependsOn: Build condition: and(succeeded('Build'), not(eq(variables['build.reason'], 'PullRequest'))) jobs: - job: CodeSign displayName: Code Signing pool: vmImage: windows-latest variables: - group: SignCLI Creds steps: # Retreive unsigned artifacts - download: current artifact: BuildPackages displayName: Download build artifacts - task: UseDotNet@2 displayName: 'Use .NET 10 SDK' inputs: includePreviewVersions: true version: 10.x # Install the code signing tool - task: DotNetCoreCLI@2 inputs: command: custom custom: tool arguments: install --tool-path . --prerelease sign displayName: Install SignTool tool - task: AzureCLI@2 inputs: azureSubscription: 'AzureRM - Humanizr' scriptType: pscore scriptLocation: inlineScript inlineScript: | .\sign code azure-key-vault ` "**/*.nupkg" ` --base-directory "$(Pipeline.Workspace)\BuildPackages" ` --publisher-name "Humanizer" ` --description "Humanizer" ` --description-url "https://github.com/Humanizr/Humanizer" ` --azure-key-vault-certificate "$(SignKeyVaultCertificate)" ` --azure-key-vault-url "$(SignKeyVaultUrl)" displayName: Sign packages # Publish the signed packages - publish: $(Pipeline.Workspace)/BuildPackages displayName: Publish Signed Packages artifact: SignedPackages ================================================ FILE: docs/_config.yml ================================================ # Jekyll configuration for Humanizer GitHub Pages title: Humanizer description: Humanizer meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities baseurl: "" # the subpath of your site, e.g. /blog url: "" # the base hostname & protocol for your site # Build settings markdown: kramdown # Use readme.md as the index page defaults: - scope: path: "" values: layout: "default" ================================================ FILE: docs/_layouts/default.html ================================================ {{ page.title | default: site.title }}

{{ site.title }}

{{ site.description }}

{{ content }}

© {{ 'now' | date: "%Y" }} Humanizer. Licensed under MIT.

GitHub | NuGet

================================================ FILE: docs/assets/css/style.css ================================================ /* Root CSS variables for light mode (default) */ :root { --bg-color: #ffffff; --text-color: #333333; --header-bg: #f8f9fa; --header-border: #e9ecef; --link-color: #0366d6; --link-hover: #0256b9; --code-bg: #f6f8fa; --code-border: #e1e4e8; --footer-bg: #f8f9fa; --footer-text: #586069; --shadow: rgba(0, 0, 0, 0.1); } /* Dark mode variables - automatically applied based on system preference */ @media (prefers-color-scheme: dark) { :root { --bg-color: #0d1117; --text-color: #c9d1d9; --header-bg: #161b22; --header-border: #30363d; --link-color: #58a6ff; --link-hover: #79c0ff; --code-bg: #161b22; --code-border: #30363d; --footer-bg: #161b22; --footer-text: #8b949e; --shadow: rgba(0, 0, 0, 0.3); } } /* Base styles */ * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif; line-height: 1.6; background-color: var(--bg-color); color: var(--text-color); transition: background-color 0.3s ease, color 0.3s ease; } .container { max-width: 1200px; margin: 0 auto; padding: 0 20px; } /* Header styles */ header { background-color: var(--header-bg); border-bottom: 1px solid var(--header-border); padding: 2rem 0; margin-bottom: 2rem; box-shadow: 0 2px 4px var(--shadow); transition: background-color 0.3s ease, border-color 0.3s ease; } header h1 { font-size: 2.5rem; margin-bottom: 0.5rem; font-weight: 600; } header p { font-size: 1.1rem; color: var(--footer-text); } /* Main content */ main { min-height: 60vh; padding: 2rem 0; } /* Typography */ h1, h2, h3, h4, h5, h6 { margin-top: 1.5rem; margin-bottom: 1rem; font-weight: 600; line-height: 1.25; } h1 { font-size: 2rem; } h2 { font-size: 1.75rem; } h3 { font-size: 1.5rem; } h4 { font-size: 1.25rem; } h5 { font-size: 1rem; } h6 { font-size: 0.875rem; } p { margin-bottom: 1rem; } /* Links */ a { color: var(--link-color); text-decoration: none; transition: color 0.2s ease; } a:hover { color: var(--link-hover); text-decoration: underline; } /* Code blocks */ code { background-color: var(--code-bg); border: 1px solid var(--code-border); border-radius: 3px; padding: 0.2em 0.4em; font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace; font-size: 85%; transition: background-color 0.3s ease, border-color 0.3s ease; } pre { background-color: var(--code-bg); border: 1px solid var(--code-border); border-radius: 6px; padding: 1rem; overflow-x: auto; margin-bottom: 1rem; transition: background-color 0.3s ease, border-color 0.3s ease; } pre code { background: none; border: none; padding: 0; } /* Lists */ ul, ol { margin-bottom: 1rem; padding-left: 2rem; } li { margin-bottom: 0.5rem; } /* Footer */ footer { background-color: var(--footer-bg); border-top: 1px solid var(--header-border); margin-top: 3rem; padding: 2rem 0; text-align: center; color: var(--footer-text); transition: background-color 0.3s ease, border-color 0.3s ease; } footer p { margin-bottom: 0.5rem; } footer a { color: var(--link-color); margin: 0 0.5rem; } /* Responsive design */ @media (max-width: 768px) { header h1 { font-size: 2rem; } header p { font-size: 1rem; } .container { padding: 0 15px; } } /* Additional utility classes */ .text-center { text-align: center; } .mt-1 { margin-top: 1rem; } .mt-2 { margin-top: 2rem; } .mb-1 { margin-bottom: 1rem; } .mb-2 { margin-bottom: 2rem; } ================================================ FILE: docs/extensibility.md ================================================ # Extensibility Humanizer is designed to be extensible, allowing you to customize and extend its behavior to meet your specific needs. ## Custom String Transformers Implement `IStringTransformer` to create custom string transformations: ```csharp public interface IStringTransformer { string Transform(string input); } ``` ### Example: Custom Title Case ```csharp public class MyTitleCase : IStringTransformer { private readonly HashSet _articlesAndPrepositions = new() { "a", "an", "the", "and", "but", "or", "for", "nor", "on", "at", "to", "from", "by" }; public string Transform(string input) { var words = input.Split(' '); for (int i = 0; i < words.Length; i++) { // Always capitalize first word if (i == 0 || !_articlesAndPrepositions.Contains(words[i].ToLower())) { words[i] = char.ToUpper(words[i][0]) + words[i].Substring(1).ToLower(); } } return string.Join(" ", words); } } // Usage "the quick brown fox".Transform(new MyTitleCase()); // => "The Quick Brown Fox" ``` The advantage over the built-in `LetterCasing` enum is complete control over the transformation logic. ## Custom Truncators Implement `ITruncator` to create custom truncation strategies: ```csharp public interface ITruncator { string Truncate(string value, int length, string truncationString, TruncateFrom truncateFrom = TruncateFrom.Right); } ``` ### Example: Sentence Boundary Truncator ```csharp public class SentenceTruncator : ITruncator { public string Truncate(string value, int length, string truncationString, TruncateFrom truncateFrom) { if (value.Length <= length) return value; // Find the last sentence boundary before the length limit var truncated = value.Substring(0, length); var lastPeriod = truncated.LastIndexOf('.'); if (lastPeriod > 0) { return truncated.Substring(0, lastPeriod + 1); } // Fall back to word boundary var lastSpace = truncated.LastIndexOf(' '); if (lastSpace > 0) { return truncated.Substring(0, lastSpace) + truncationString; } return truncated + truncationString; } } // Usage "First sentence. Second sentence. Third sentence." .Truncate(30, "...", new SentenceTruncator()); // => "First sentence." ``` ## Custom Vocabularies Extend the pluralization/singularization vocabulary: ```csharp // Add irregular word Vocabularies.Default.AddIrregular("person", "people"); // Add uncountable word Vocabularies.Default.AddUncountable("equipment"); // Add plural rule Vocabularies.Default.AddPlural("(quiz)$", "$1zes"); // Add singular rule Vocabularies.Default.AddSingular("(vert|ind)ices$", "$1ex"); ``` ### Match Ending Control ```csharp // Match only "person" (not "salesperson") Vocabularies.Default.AddIrregular("person", "people", matchEnding: false); // Match "person" and "salesperson" Vocabularies.Default.AddIrregular("person", "people", matchEnding: true); ``` ## Custom Number to Words Converters Implement language-specific number to words conversion: ```csharp public interface INumberToWordsConverter { string Convert(long number); string Convert(long number, GrammaticalGender gender); string ConvertToOrdinal(int number); string ConvertToOrdinal(int number, GrammaticalGender gender); } ``` Register your converter: ```csharp Configurator.NumberToWordsConverters.Register("my-culture", new MyNumberToWordsConverter()); ``` ## Custom Formatters Implement custom date/time/number formatting: ```csharp public interface IFormatter { string DateHumanize(DateTime value, DateTime? comparisonBase, CultureInfo culture); string TimeSpanHumanize(TimeSpan timeSpan, int precision, CultureInfo culture); // ... other methods } ``` Register your formatter: ```csharp Configurator.Formatters.Register("my-culture", new MyFormatter()); ``` ## Configuration Customize Humanizer's behavior globally: ```csharp // Custom enum description property name Configurator.EnumDescriptionPropertyLocator = p => p.Name == "Info"; // Custom collection separator Configurator.CollectionFormatters.Register("my-culture", new MyCollectionFormatter()); ``` ## Best Practices 1. **Implement interfaces rather than extending classes** - This ensures compatibility with future versions 2. **Register custom components at application startup** - Do this once rather than on every use 3. **Thread safety** - Make custom implementations thread-safe if they'll be used concurrently 4. **Test thoroughly** - Custom implementations should have comprehensive test coverage 5. **Consider culture** - If your custom component is culture-specific, register it appropriately ## Related Topics - [Custom Vocabularies](custom-vocabularies.md) - Detailed pluralization customization - [Localization](localization.md) - Multi-language support - [Configuration](configuration.md) - Global configuration options ================================================ FILE: docs/index.md ================================================ # Humanizer Documentation Humanizer meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities. ## Getting Started - [Installation](installation.md) - How to install and configure Humanizer - [Quick Start Guide](quick-start.md) - Get up and running quickly ## Core Features ### String Manipulation - [String Humanization](string-humanization.md) - Transform computerized strings to human-readable text - [String Dehumanization](string-dehumanization.md) - Convert back to PascalCase - [String Transformations](string-transformations.md) - Apply custom transformations with IStringTransformer - [String Truncation](string-truncation.md) - Intelligent truncation strategies ### Enumerations - [Enum Humanization](enum-humanization.md) - Make enums readable - [Enum Dehumanization](enum-dehumanization.md) - Parse strings back to enums ### Date and Time - [DateTime Humanization](datetime-humanization.md) - Relative time ("2 hours ago", "tomorrow") - [TimeSpan Humanization](timespan-humanization.md) - Human-readable durations - [Fluent Date API](fluent-date.md) - Readable date/time construction and manipulation - [DateTime to Ordinal Words](datetime-ordinal-words.md) - "1st of January 2020" - [TimeOnly to Clock Notation](timeonly-clock-notation.md) - "half past two" (.NET 6+) ### Numbers - [Number to Words](number-to-words.md) - "123" → "one hundred twenty-three" - [Number to Ordinal Words](number-to-ordinal-words.md) - "1" → "first" - [Words to Number](words-to-number.md) - "forty-two" → 42 - [Ordinalization](ordinalization.md) - "1" → "1st" - [Roman Numerals](roman-numerals.md) - Convert to/from Roman numerals - [Metric Numerals](metric-numerals.md) - "1230" → "1.23k" - [Number to Numbers](number-to-numbers.md) - Fluent API for large numbers - [Tupleize](tupleize.md) - "2" → "double" ### Collections - [Collection Humanization](collection-humanization.md) - Turn lists into "item1, item2, and item3" - [ToQuantity](to-quantity.md) - "5 cases", "1 man", "2 men" ### Word Manipulation - [Pluralization](pluralization.md) - Handle singular/plural forms - [Singularization](singularization.md) - Convert plurals to singular - [Inflector Methods](inflector-methods.md) - Pascalize, Camelize, Underscore, Kebaberize, etc. ### Specialized Features - [ByteSize](bytesize.md) - Human-readable byte sizes - [Heading](heading.md) - Convert headings to text - [Time Unit Symbols](time-unit-symbols.md) - "ms", "s", "min", etc. ## Advanced Topics - [Localization](localization.md) - Multi-language support - [Custom Vocabularies](custom-vocabularies.md) - Add custom pluralization rules - [Extensibility](extensibility.md) - Implement custom transformers and truncators - [Configuration](configuration.md) - Customize Humanizer behavior ## Migration Guides - [Migrating from 2.14.1 to 3.0.8](migration-v3.md) - Comprehensive breaking changes, patch-line fixes, and known regressions - [Namespace migration details](v3-namespace-migration.md) - Namespace-only migration guidance and analyzer usage ## API Reference - [Complete API Reference](api-reference.md) - Full API documentation ## Contributing - [Contributing Guide](../CONTRIBUTING.md) - How to contribute to Humanizer ================================================ FILE: docs/installation.md ================================================ # Installation ## NuGet Packages Humanizer is available as NuGet packages with different language support options: ### All Languages (Recommended) ```bash dotnet add package Humanizer ``` This package includes all supported languages and pulls in `Humanizer.Core` plus all language satellite packages. ### English Only ```bash dotnet add package Humanizer.Core ``` This package includes only English language support, resulting in a smaller download size. ### Specific Languages You can install `Humanizer.Core` along with specific language packages: ```bash dotnet add package Humanizer.Core dotnet add package Humanizer.Core.fr # French dotnet add package Humanizer.Core.es # Spanish dotnet add package Humanizer.Core.de # German # Add as many language packages as needed ``` Available language packages include: af, ar, az, bg, bn, ca, cs, da, de, el, es, fa, fi, fil, fr, he, hr, hu, hy, id, is, it, ja, ko, ku, lb, lt, lv, ms, mt, nb, nl, pl, pt, pt-BR, ro, ru, sk, sl, sr, sr-Latn, sv, th, tr, uk, uz-Cyrl-UZ, uz-Latn-UZ, vi, zh-CN, zh-Hans, zh-Hant. ## Supported Frameworks Humanizer supports the following .NET target frameworks: - **.NET 10.0** (net10.0) - **.NET 8.0** (net8.0) - **.NET Framework 4.8** (net48) - **.NET Standard 2.0** (netstandard2.0) - Special case for Roslyn Analyzers and MSBuild tasks > **Note:** While .NET Framework versions 4.6.1 through 4.7.2 can technically consume netstandard2.0 libraries, they are **not officially supported** by Humanizer and may not work correctly. Use one of the explicitly supported frameworks above. ## Requirements for Humanizer 3.0 > [!IMPORTANT] > The `Humanizer` metapackage requires the NuGet locale parsing fix shipped in **.NET SDK 9.0.200** and corresponding Visual Studio/MSBuild updates. > > Restore operations must run on: > - .NET SDK 9.0.200 or newer, OR > - Visual Studio 2022/MSBuild versions that include the locale parsing patch > > Older SDKs/MSBuild versions will fail to restore the metapackage because they do not recognize three-letter locale identifiers. > > **Workaround for older tooling:** Reference `Humanizer.Core` directly and add desired `Humanizer.Core.` satellite packages individually. ## Source Link Support Humanizer symbols are source-indexed with [SourceLink](https://github.com/dotnet/sourcelink) and included in the package. This means you can step through Humanizer's source code while debugging your own application. ## Verification After installation, verify Humanizer is working: ```csharp using Humanizer; "PascalCaseString".Humanize(); // Returns "Pascal case string" DateTime.UtcNow.AddHours(-2).Humanize(); // Returns "2 hours ago" ``` ## Next Steps - [Quick Start Guide](quick-start.md) - [Migration from 2.14.1 to 3.0.8](migration-v3.md) - [String Humanization](string-humanization.md) - [DateTime Humanization](datetime-humanization.md) ================================================ FILE: docs/localization.md ================================================ # Localization Humanizer supports over 40 languages and cultures, with localized implementations for most features. ## Supported Languages Humanizer includes localization for: Arabic (ar), Azerbaijani (az), Bulgarian (bg), Bengali (bn-BD), Czech (cs), Danish (da), German (de), Greek (el), Spanish (es), Persian (fa), Finnish (fi), French (fr), Hebrew (he), Croatian (hr), Hungarian (hu), Armenian (hy), Indonesian (id), Icelandic (is), Italian (it), Japanese (ja), Korean (ko), Kurdish (ku), Latvian (lv), Malay (ms-MY), Maltese (mt), Norwegian Bokmål (nb, nb-NO), Dutch (nl), Polish (pl), Portuguese (pt, pt-BR), Romanian (ro), Russian (ru), Slovak (sk), Slovenian (sl), Serbian (sr, sr-Latn), Swedish (sv), Thai (th), Turkish (tr), Ukrainian (uk), Uzbek (uz-Cyrl-UZ, uz-Latn-UZ), Vietnamese (vi), Chinese (zh-CN, zh-Hans, zh-Hant). ## Installing Language Packages ### All Languages ```bash dotnet add package Humanizer ``` ### Specific Languages ```bash dotnet add package Humanizer.Core dotnet add package Humanizer.Core.fr # French dotnet add package Humanizer.Core.es # Spanish dotnet add package Humanizer.Core.de # German ``` ## Using Cultures Most Humanizer methods respect the current thread's `CurrentCulture` or `CurrentUICulture`. You can also explicitly specify a culture: ### DateTime Humanization ```csharp var date = DateTime.UtcNow.AddHours(-2); // Uses current culture date.Humanize(); // Explicit culture date.Humanize(culture: new CultureInfo("fr-FR")); // => "il y a 2 heures" date.Humanize(culture: new CultureInfo("es")); // => "hace 2 horas" ``` ### Number to Words ```csharp 1234.ToWords(); // Uses current culture 1234.ToWords(new CultureInfo("es")); // => "mil doscientos treinta y cuatro" 1234.ToWords(new CultureInfo("fr")); // => "mille deux cent trente-quatre" ``` ### TimeSpan Humanization ```csharp TimeSpan.FromDays(1).Humanize(); // Uses current culture TimeSpan.FromDays(1).Humanize(culture: new CultureInfo("de")); // => "1 Tag" TimeSpan.FromDays(3).Humanize(culture: new CultureInfo("ru")); // => "3 дня" ``` ## Grammatical Features Some languages require additional grammatical information: ### Grammatical Gender ```csharp // Russian 1.ToWords(GrammaticalGender.Masculine, new CultureInfo("ru")); // => "один" 1.ToWords(GrammaticalGender.Feminine, new CultureInfo("ru")); // => "одна" // Portuguese ordinals 1.Ordinalize(GrammaticalGender.Masculine); // => "1º" 1.Ordinalize(GrammaticalGender.Feminine); // => "1ª" ``` ### Grammatical Case ```csharp // Russian - date to ordinal words var date = new DateTime(2020, 1, 1); date.ToOrdinalWords(GrammaticalCase.Nominative); // Different form date.ToOrdinalWords(GrammaticalCase.Genitive); // Different form ``` ### Word Forms ```csharp // Spanish - ordinal variations 3.Ordinalize(GrammaticalGender.Masculine, WordForm.Abbreviation); // => "3.er" 3.Ordinalize(GrammaticalGender.Masculine, WordForm.Normal); // => "3.º" ``` ## Feature Support by Language Not all features are available in all languages: | Feature | Widely Supported | Limited Support | |---------|------------------|-----------------| | String Humanization | All languages | - | | DateTime Humanization | All languages | - | | TimeSpan Humanization | All languages | - | | Number to Words | Most languages | Some Asian languages | | Ordinalization | Most European languages | Limited in Asian languages | | Pluralization | English only | - | Check the specific feature documentation to see which languages are supported. ## Contributing Localizations To contribute a new language or improve existing localizations: 1. Implement the required interfaces (e.g., `IFormatter`, `IDateToOrdinalWordConverter`) 2. Add resource files with translated strings 3. Register the formatter in `Configurator` 4. Add tests for the new language See the [Contributing Guide](../CONTRIBUTING.md) for details. ## Related Topics - [Installation](installation.md) - How to install language packages - [Number to Words](number-to-words.md) - Language-specific number formatting - [DateTime Humanization](datetime-humanization.md) - Relative time in different languages ================================================ FILE: docs/migration-v3.md ================================================ # Migrating from Humanizer 2.14.1 to 3.0.8 This guide is for teams upgrading directly from `2.14.1` to `3.0.8`. This document was added to address [issue #1656](https://github.com/Humanizr/Humanizer/issues/1656) (undocumented v3 breaking changes). Validated against: - Git tag `v2.14.1` - v3 breaking-change commits through `v3.0.1` - v3 patch-line fixes included in `3.0.8`: - Roslyn analyzer compatibility fixes in [PR #1676](https://github.com/Humanizr/Humanizer/pull/1676) - `ToQuantity(int, ...)` compatibility fix in [PR #1679](https://github.com/Humanizr/Humanizer/pull/1679) - `TitleCase` first-word capitalization fix in [PR #1678](https://github.com/Humanizr/Humanizer/pull/1678) ## Quick Upgrade Checklist 1. Update package/tooling prerequisites first (framework and restore requirements). 2. If you are on `3.0.1`, upgrade to `3.0.8` to pick up patch-line compatibility fixes ([#1655](https://github.com/Humanizr/Humanizer/issues/1655), [#1665](https://github.com/Humanizr/Humanizer/issues/1665), [#1672](https://github.com/Humanizr/Humanizer/issues/1672), [#1652](https://github.com/Humanizr/Humanizer/issues/1652), [#1658](https://github.com/Humanizr/Humanizer/issues/1658)). 3. Run the namespace migration analyzer and replace old `using Humanizer.*` directives. 4. Replace removed APIs (`FormatWith`, obsolete `ToMetric` overloads, etc.). 5. Rebuild all assemblies that reference Humanizer (binary compatibility changed in a few APIs). 6. If you implement extensibility points (`IFormatter`, `DefaultFormatter`), update those implementations. 7. Run behavioral regression tests for `Titleize`, `Pascalize`, `Dehumanize`, and enum humanization. ## Breaking Changes ### Namespace Consolidation (source-breaking) All Humanizer APIs were consolidated into the root `Humanizer` namespace. Related: - [PR #1351](https://github.com/Humanizr/Humanizer/pull/1351) - Upgrade impact report: [issue #1656](https://github.com/Humanizr/Humanizer/issues/1656) Before: ```csharp using Humanizer.Bytes; using Humanizer.Localisation; using Humanizer.Configuration; ``` After: ```csharp using Humanizer; ``` Use the built-in analyzer (`HUMANIZER001`) to automate this migration. See also: [Namespace-only migration guide](v3-namespace-migration.md). ### Removed APIs 1. `StringExtensions.FormatWith(...)` was removed. Related: - [PR #1395](https://github.com/Humanizr/Humanizer/pull/1395) - Upgrade impact report: [issue #1656](https://github.com/Humanizr/Humanizer/issues/1656) Before: ```csharp "{0:N2}".FormatWith(culture, value); ``` After: ```csharp string.Format(culture, "{0:N2}", value); ``` 2. Obsolete `ToMetric` overloads were removed: - `ToMetric(this int input, bool hasSpace, bool useSymbol = true, int? decimals = null)` - `ToMetric(this double input, bool hasSpace, bool useSymbol = true, int? decimals = null)` Use `MetricNumeralFormats` instead: ```csharp // Equivalent to: value.ToMetric(hasSpace: true, useSymbol: true, decimals: 2); value.ToMetric(MetricNumeralFormats.WithSpace, decimals: 2); // If you previously passed useSymbol: false: value.ToMetric(MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseName, decimals: 2); ``` Related: - [PR #1389](https://github.com/Humanizr/Humanizer/pull/1389) - Upgrade impact report: [issue #1656](https://github.com/Humanizr/Humanizer/issues/1656) 3. `ToQuantity(this string, int, ...)` overloads were removed in early v3 and later restored in the patch line (`3.0.6+`, including `3.0.8`). Related: - [PR #1338](https://github.com/Humanizr/Humanizer/pull/1338) - Follow-up request and resolution: [issue #1652](https://github.com/Humanizr/Humanizer/issues/1652), [PR #1679](https://github.com/Humanizr/Humanizer/pull/1679) 4. `EnglishArticles` enum was removed. Related: - [PR #1443](https://github.com/Humanizr/Humanizer/pull/1443) 5. `Configurator.EnumDescriptionPropertyLocator` public property was removed. Use `Configurator.UseEnumDescriptionPropertyLocator(...)` instead, and call it early during startup: ```csharp Configurator.UseEnumDescriptionPropertyLocator(p => p.Name == "Info"); ``` `UseEnumDescriptionPropertyLocator(...)` now throws if you call it after enum humanization has already occurred. Related: - Upgrade impact report: [issue #1656](https://github.com/Humanizr/Humanizer/issues/1656) ### Enum API Signature Changes Enum APIs moved from `Enum`-based extension signatures to constrained generics: Before (`2.14.1`): ```csharp public static string Humanize(this Enum input) public static string Humanize(this Enum input, LetterCasing casing) public static TTargetEnum DehumanizeTo(this string input) where TTargetEnum : struct, IComparable, IFormattable ``` After (`3.0.8`): ```csharp public static string Humanize(this T input) where T : struct, Enum public static string Humanize(this T input, LetterCasing casing) where T : struct, Enum public static TTargetEnum DehumanizeTo(this string input) where TTargetEnum : struct, Enum ``` Impact: - Code that stores values as `Enum` (not a concrete enum type) and then calls `.Humanize()` no longer compiles. - Generic callers with non-enum constraints for `DehumanizeTo` no longer compile. Related: - Upgrade impact report: [issue #1656](https://github.com/Humanizr/Humanizer/issues/1656) ### Extensibility Breaks (`IFormatter` / `DefaultFormatter`) If you implement or subclass formatting infrastructure, update your code: 1. `IFormatter` now requires: ```csharp string TimeSpanHumanize_Age(); ``` 2. `DefaultFormatter` override surface changed: Before: ```csharp protected virtual string Format(string resourceKey, int number, bool toWords = false) ``` After: ```csharp protected virtual string Format(TimeUnit unit, string resourceKey, int number, bool toWords = false) ``` If you had custom `DefaultFormatter` subclasses overriding the old signature, they must be migrated. Related: - API introduction that expanded formatter contract: [PR #1068](https://github.com/Humanizr/Humanizer/pull/1068) - Upgrade impact report: [issue #1656](https://github.com/Humanizr/Humanizer/issues/1656) ## Framework, Packaging, and Tooling Breaks ### Target Framework Support Changes Compared to `2.14.1`, v3 removed support for: - `netstandard1.0` - `net462` - `net472` - dedicated `net6.0` assets (consumers on `net6.0`/`net7.0` now resolve `netstandard2.0` assets) `3.0.8` package assets target: - `netstandard2.0` - `net48` - `net8.0` - `net10.0` Related: - `netstandard1.0` removal: [PR #1322](https://github.com/Humanizr/Humanizer/pull/1322) - `net462`/`net472` removal: [PR #1482](https://github.com/Humanizr/Humanizer/pull/1482) - Upgrade impact report: [issue #1656](https://github.com/Humanizr/Humanizer/issues/1656) ### Metapackage Restore Requirement The `Humanizer` metapackage requires NuGet locale parsing support from newer tooling. You need: - .NET SDK `9.0.200+`, or - Visual Studio/MSBuild that includes the same NuGet locale parsing fix. On older tooling, restore can fail for the metapackage. Workaround: reference `Humanizer.Core` directly and install needed locale packages explicitly. Related: - NuGet locale parsing fix dependency note: [NuGet.Client discussion](https://github.com/NuGet/NuGet.Client/pull/6124#issuecomment-3391090183) ### Locale Package ID Changes Several locale package IDs changed between `2.14.1` and `3.0.8`: | `2.14.1` package | `3.0.8` package | | --- | --- | | `Humanizer.Core.bn-BD` | `Humanizer.Core.bn` | | `Humanizer.Core.fi-FI` | `Humanizer.Core.fi` | | `Humanizer.Core.ko-KR` | `Humanizer.Core.ko` | | `Humanizer.Core.ms-MY` | `Humanizer.Core.ms` | | `Humanizer.Core.nb-NO` | `Humanizer.Core.nb` | | `Humanizer.Core.th-TH` | `Humanizer.Core.th` | Removed from the metapackage dependency list (no direct one-to-one replacement): - `Humanizer.Core.fr-BE` Related: - Locale ID normalization change: [commit 7b14ef6f](https://github.com/Humanizr/Humanizer/commit/7b14ef6f) - Upgrade impact report: [issue #1656](https://github.com/Humanizr/Humanizer/issues/1656) ## Behavior Changes to Validate 1. `Pascalize` now treats hyphens (`-`) as delimiters. 2. `Dehumanize` output can differ because it is based on `Humanize().Pascalize()` and inherits `Pascalize` changes. 3. `Humanize` / `Titleize` preserve strings with no recognized letters instead of returning empty string. Related: - `Pascalize` hyphen behavior change: [issue #1282](https://github.com/Humanizr/Humanizer/issues/1282), [PR #1299](https://github.com/Humanizr/Humanizer/pull/1299) - `Dehumanize`/spacing impact reports: [issue #1656](https://github.com/Humanizr/Humanizer/issues/1656), [issue #1668](https://github.com/Humanizr/Humanizer/issues/1668) - `Titleize` no-letter preservation: [issue #385](https://github.com/Humanizr/Humanizer/issues/385), [PR #1611](https://github.com/Humanizr/Humanizer/pull/1611) - `TitleCase` first-word casing regression: [issue #1658](https://github.com/Humanizr/Humanizer/issues/1658) ## Roslyn Analyzer Fixes Included in 3.0.8 `3.0.8` includes analyzer loading compatibility fixes from [PR #1676](https://github.com/Humanizr/Humanizer/pull/1676). | Issue | Status | Impact in 3.0.1 | 3.0.8 result | | --- | --- | --- | --- | | [#1655](https://github.com/Humanizr/Humanizer/issues/1655) | Closed | Analyzer could fail to load on .NET 8 SDK hosts. | Fixed | | [#1665](https://github.com/Humanizr/Humanizer/issues/1665) | Closed | Analyzer load failure due to `System.Memory` binding mismatch. | Fixed | | [#1672](https://github.com/Humanizr/Humanizer/issues/1672) | Closed | Analyzer load failure due to `System.Collections.Immutable` dependency mismatch. | Fixed | ## Compatibility Fixes Included in 3.0.8 | Issue | Status | Patch-line fix | | --- | --- | --- | | [#1652](https://github.com/Humanizr/Humanizer/issues/1652) | Closed | `ToQuantity(int, ...)` compatibility restored via [PR #1679](https://github.com/Humanizr/Humanizer/pull/1679) (in `3.0.6+`, included in `3.0.8`). | | [#1658](https://github.com/Humanizr/Humanizer/issues/1658) | Closed | `TitleCase` first-word capitalization fixed via [PR #1678](https://github.com/Humanizr/Humanizer/pull/1678) (in `3.0.6+`, included in `3.0.8`). | ## Remaining Known Upgrade Issue (as of March 5, 2026) | Issue | Status | Impact | Suggested mitigation | | --- | --- | --- | --- | | [#1668](https://github.com/Humanizr/Humanizer/issues/1668) | Open | Some `Dehumanize()` cases retain underscore before digits (for example `everything_0`). | Pre-normalize affected inputs before `Dehumanize()`, or use custom conversion logic for these patterns. | ## Recommended Validation Pass After migration: 1. Full clean restore with your actual CI SDK image. 2. Full rebuild of all projects that reference Humanizer. 3. Integration tests around string casing, enum formatting/dehumanization, and quantity formatting. 4. Spot-check localized output if you depended on renamed locale packages. ================================================ FILE: docs/quick-start.md ================================================ # Quick Start Guide Get started with Humanizer in minutes. ## Installation Install the Humanizer NuGet package: ```bash dotnet add package Humanizer ``` For English-only: ```bash dotnet add package Humanizer.Core ``` See [Installation](installation.md) for more options. ## Basic Examples ### Humanize Strings ```csharp using Humanizer; "PascalCaseString".Humanize(); // => "Pascal case string" "some_property_name".Humanize(); // => "Some property name" ``` ### Humanize DateTimes ```csharp DateTime.UtcNow.AddHours(-2).Humanize(); // => "2 hours ago" DateTime.UtcNow.AddDays(1).Humanize(); // => "tomorrow" ``` ### Humanize TimeSpans ```csharp TimeSpan.FromDays(1).Humanize(); // => "1 day" TimeSpan.FromMinutes(90).Humanize(); // => "an hour" ``` ### Humanize Enums ```csharp public enum PaymentStatus { PendingApproval, Approved, Declined } PaymentStatus.PendingApproval.Humanize(); // => "Pending approval" ``` ### Pluralization ```csharp "person".Pluralize(); // => "people" "case".ToQuantity(5); // => "5 cases" ``` ### Number Conversions ```csharp 1234.ToWords(); // => "one thousand two hundred and thirty-four" 1.Ordinalize(); // => "1st" 21.Ordinalize(); // => "21st" ``` ### Fluent Dates ```csharp In.January; // => January 1st of current year 2.Days() + 3.Hours(); // => TimeSpan of 2 days and 3 hours DateTime.Now + 2.Weeks(); // => DateTime 2 weeks from now ``` ### Collections ```csharp var items = new[] { "apple", "banana", "cherry" }; items.Humanize(); // => "apple, banana, and cherry" ``` ### Truncation ```csharp "Long text that needs truncating".Truncate(10); // => "Long text…" ``` ## Common Patterns ### Display Property Names in UI ```csharp public class Person { public string FirstName { get; set; } public string LastName { get; set; } public DateTime DateOfBirth { get; set; } } // Generate labels automatically nameof(Person.FirstName).Humanize(); // => "First name" nameof(Person.DateOfBirth).Humanize(); // => "Date of birth" ``` ### Relative Time Display ```csharp var postDate = DateTime.UtcNow.AddHours(-3); $"Posted {postDate.Humanize()}"; // => "Posted 3 hours ago" ``` ### Format Numbers for Display ```csharp var count = 1234567; $"Downloaded {count.ToMetric()} times"; // => "Downloaded 1.23M times" ``` ### Pluralize Based on Count ```csharp var itemCount = 5; $"You have {itemCount} {"item".ToQuantity(itemCount)}"; // => "You have 5 items" var singleItem = 1; $"You have {singleItem} {"item".ToQuantity(singleItem)}"; // => "You have 1 item" ``` ## Next Steps Explore the documentation for detailed information on each feature: - [String Humanization](string-humanization.md) - [DateTime Humanization](datetime-humanization.md) - [Number Conversions](number-to-words.md) - [Pluralization](pluralization.md) - [All Features](index.md) ================================================ FILE: docs/string-dehumanization.md ================================================ # String Dehumanization Convert human-friendly strings back to PascalCase format. ## Overview Dehumanization reverses the humanization process, taking a humanized string and converting it back to PascalCase. This is useful when you need to convert user input or display text back into a format suitable for code identifiers. ## Basic Usage ```csharp "Pascal case input string is turned into sentence".Dehumanize() // => "PascalCaseInputStringIsTurnedIntoSentence" "some string".Dehumanize() // => "SomeString" "Some String".Dehumanize() // => "SomeString" ``` ## Behavior The dehumanization process: 1. Splits the input on spaces 2. Humanizes each word (to handle edge cases) 3. Pascalizes each word (capitalizing first letter) 4. Removes all spaces If the input is already in PascalCase (contains no spaces), it is returned unchanged. ## Examples ```csharp "SomeStringAndAnotherString".Dehumanize() // => "SomeStringAndAnotherString" (unchanged) ``` ## Related Topics - [String Humanization](string-humanization.md) - [Inflector Methods](inflector-methods.md) - Pascalize, Camelize ================================================ FILE: docs/string-humanization.md ================================================ # String Humanization String humanization transforms computerized strings (like class names, method names, or property names) into human-readable text. This is particularly useful when displaying programming identifiers to end users. ## Overview The `Humanize` extension method intelligently handles: - **PascalCase**: `PascalCaseString` → `Pascal case string` - **camelCase**: `camelCaseString` → `Camel case string` - **Underscores**: `underscored_string` → `Underscored string` - **Dashes**: `dash-separated-string` → `Dash separated string` ## Basic Usage ```csharp using Humanizer; "PascalCaseInputStringIsTurnedIntoSentence".Humanize() // => "Pascal case input string is turned into sentence" "Underscored_input_string_is_turned_into_sentence".Humanize() // => "Underscored input string is turned into sentence" "dash-separated-string".Humanize() // => "Dash separated string" ``` ## Acronym Handling Strings containing only uppercase letters are treated as acronyms and left unchanged: ```csharp "HTML".Humanize() // => "HTML" "HUMANIZER".Humanize() // => "HUMANIZER" ``` To force humanization of all-caps strings, use the `Transform` method: ```csharp "HUMANIZER".Transform(To.LowerCase, To.TitleCase) // => "Humanizer" ``` ## Letter Casing Control the output casing: ```csharp "CanReturnTitleCase".Humanize(LetterCasing.Title) // => "Can Return Title Case" "CanReturnLowerCase".Humanize(LetterCasing.LowerCase) // => "can return lower case" "CanHumanizeIntoUpperCase".Humanize(LetterCasing.AllCaps) // => "CAN HUMANIZE INTO UPPER CASE" "some string".Humanize(LetterCasing.Sentence) // => "Some string" ``` Available casing options: - `LetterCasing.Title` - Capitalizes the first letter of each word - `LetterCasing.Sentence` - Capitalizes only the first letter - `LetterCasing.AllCaps` - All uppercase - `LetterCasing.LowerCase` - All lowercase ## How It Works The humanization process applies several rules in order: 1. If the entire input is uppercase (an acronym), it returns unchanged 2. Handles freestanding underscores/dashes (e.g., "some _ string") 3. Splits on underscores and dashes 4. Breaks up PascalCase and camelCase text 5. Capitalizes the first letter of the result ## Real-World Examples ### Display Test Method Names ```csharp // In a testing framework public void ItShouldCalculateTheTotalPrice() { // Test implementation } // Display to user: nameof(ItShouldCalculateTheTotalPrice).Humanize() // => "It should calculate the total price" ``` ### Display Property Names in UI ```csharp public class User { public string FirstName { get; set; } public string LastName { get; set; } public DateTime DateOfBirth { get; set; } } // Generate form labels automatically nameof(User.FirstName).Humanize() // => "First name" nameof(User.DateOfBirth).Humanize() // => "Date of birth" ``` ### Convert API Field Names ```csharp // API returns: "account_status", "last_login_date" var fields = new[] { "account_status", "last_login_date" }; foreach (var field in fields) { Console.WriteLine(field.Humanize()); } // Output: // Account status // Last login date ``` ## Version 3.0 Behavioral Change In version 3.0, `Humanize` and `Titleize` now preserve input strings that contain no recognized letters (e.g., special characters, unrecognized Unicode scripts) instead of returning an empty string: ```csharp // Before v3.0: returned "" // v3.0 and later: returns "@@" "@@".Humanize() // => "@@" // Cyrillic and other Unicode scripts are preserved "Майк".Titleize() // => "Майк" ``` ## Related Topics - [String Dehumanization](string-dehumanization.md) - Convert back to PascalCase - [String Transformations](string-transformations.md) - Custom transformations - [Inflector Methods](inflector-methods.md) - Titleize, Pascalize, Camelize, etc. ================================================ FILE: docs/string-truncation.md ================================================ # String Truncation Humanizer provides intelligent string truncation with multiple strategies to handle different use cases. ## Overview Truncation is useful when you need to limit string length for display purposes while maintaining readability. Humanizer offers several truncation strategies and uses the `…` character (one character) instead of `"..."` (three characters) to maximize visible text. ## Basic Usage ```csharp using Humanizer; "Long text to truncate".Truncate(10) // => "Long text…" "Long text to truncate".Truncate(10, "---") // => "Long te---" ``` ## Truncation Strategies ### Fixed Length (Default) Truncates to a specific total length including the truncation indicator: ```csharp "Long text to truncate".Truncate(10, Truncator.FixedLength) // => "Long text…" "Long text to truncate".Truncate(10, "---", Truncator.FixedLength) // => "Long te---" ``` ### Fixed Number of Characters Truncates to a specific number of alphanumeric characters: ```csharp "Long text to truncate".Truncate(6, Truncator.FixedNumberOfCharacters) // => "Long t…" "Long text to truncate".Truncate(6, "---", Truncator.FixedNumberOfCharacters) // => "Lon---" ``` ### Fixed Number of Words Truncates to a specific number of words: ```csharp "Long text to truncate".Truncate(2, Truncator.FixedNumberOfWords) // => "Long text…" "Long text to truncate".Truncate(2, "---", Truncator.FixedNumberOfWords) // => "Long text---" ``` ### Dynamic Length - Preserve Words Similar to fixed length but attempts to preserve whole words: ```csharp "Long text to truncate".Truncate(10, Truncator.DynamicLengthAndPreserveWords) // => "Long text…" "Long text to truncate".Truncate(10, "---", Truncator.DynamicLengthAndPreserveWords) // => "Long---" ``` ### Dynamic Characters - Preserve Words Similar to fixed number of characters but attempts to preserve whole words: ```csharp "Long text to truncate".Truncate(6, Truncator.DynamicNumberOfCharactersAndPreserveWords) // => "Long…" "Long text to truncate".Truncate(6, "---", Truncator.DynamicNumberOfCharactersAndPreserveWords) // => "---" ``` ## Truncation Direction By default, truncation happens from the right (end) of the string. You can truncate from the left (beginning) using `TruncateFrom.Left`: ```csharp "Long text to truncate".Truncate(10, Truncator.FixedLength, TruncateFrom.Left) // => "… truncate" "Long text to truncate".Truncate(10, "---", Truncator.FixedLength, TruncateFrom.Left) // => "---runcate" "Long text to truncate".Truncate(2, Truncator.FixedNumberOfWords, TruncateFrom.Left) // => "…to truncate" ``` ## Custom Truncation Indicators You can use any string as a truncation indicator: ```csharp "Long text to truncate".Truncate(15, " [more]") // => "Long [more]" "Long text to truncate".Truncate(15, "...") // => "Long text..." ``` ## Custom Truncators Implement the `ITruncator` interface to create custom truncation logic: ```csharp public interface ITruncator { string Truncate(string value, int length, string truncationString, TruncateFrom truncateFrom = TruncateFrom.Right); } ``` Example custom truncator: ```csharp public class SentenceTruncator : ITruncator { public string Truncate(string value, int length, string truncationString, TruncateFrom truncateFrom) { // Custom logic to truncate at sentence boundaries // Implementation details... } } // Usage "First sentence. Second sentence. Third sentence." .Truncate(30, new SentenceTruncator()); ``` ## Real-World Examples ### Truncate Article Previews ```csharp var article = "This is a very long article that needs to be truncated for the preview."; var preview = article.Truncate(50, Truncator.FixedNumberOfWords); // => "This is a very long article that needs to be…" ``` ### Truncate File Names ```csharp var fileName = "Very_Long_File_Name_That_Needs_Truncation.pdf"; var displayName = fileName.Truncate(20, "…", Truncator.DynamicLengthAndPreserveWords); // => "Very_Long_File_Name…" ``` ### Truncate User Comments ```csharp var comment = "This is a user comment that might be too long to display in a notification."; var notification = comment.Truncate(40); // => "This is a user comment that might be…" ``` ## Best Practices 1. **Choose the right strategy**: - Use `FixedLength` for consistent visual length - Use `FixedNumberOfWords` when word boundaries matter - Use dynamic strategies when readability is more important than exact length 2. **Consider the truncation indicator**: - Use `…` (single character) for space efficiency - Use `"..."` if your audience expects it - Use `" [more]"` or similar for clarity 3. **Test with your actual content**: Different text may truncate differently depending on word boundaries ## Related Topics - [String Humanization](string-humanization.md) - [String Transformations](string-transformations.md) ================================================ FILE: docs/v3-namespace-migration.md ================================================ # Humanizer v3 Namespace Migration This document provides guidance on migrating code from Humanizer v2 to v3, focusing on the namespace consolidation changes. > For the full `2.14.1 -> 3.0.8` upgrade path (all breaking changes, package/tooling changes, patch-line fixes, and known regressions), see [migration-v3.md](migration-v3.md). ## What Changed in v3 Humanizer v3 consolidates all sub-namespaces into the root `Humanizer` namespace. This is a **source-breaking change** that requires code updates. ### Consolidated Namespaces All of the following namespaces have been moved into `Humanizer`: - `Humanizer.Bytes` - `Humanizer.Localisation` - `Humanizer.Localisation.Formatters` - `Humanizer.Localisation.NumberToWords` - `Humanizer.DateTimeHumanizeStrategy` - `Humanizer.Configuration` - `Humanizer.Localisation.DateToOrdinalWords` - `Humanizer.Localisation.Ordinalizers` - `Humanizer.Inflections` - `Humanizer.Localisation.CollectionFormatters` - `Humanizer.Localisation.TimeToClockNotation` ### Migration Path **Before (v2):** ```csharp using Humanizer.Bytes; using Humanizer.Localisation; using Humanizer.Configuration; public class Example { public void Method() { var size = ByteSize.FromKilobytes(10); var formatter = new DefaultFormatter("en-US"); Configurator.Localisation = new CultureInfo("en-US"); } } ``` **After (v3):** ```csharp using Humanizer; public class Example { public void Method() { var size = ByteSize.FromKilobytes(10); var formatter = new DefaultFormatter("en-US"); Configurator.Localisation = new CultureInfo("en-US"); } } ``` ## Automated Migration with Roslyn Analyzer Humanizer v3 includes a Roslyn analyzer that automatically detects and fixes namespace usage. No separate installation is required—the analyzer is bundled with the `Humanizer.Core` package starting from v3.0.0. ### Usage Once you have installed or updated to `Humanizer.Core` v3.0.0 or later, the analyzer will be available automatically in your project. The package includes Roslyn-versioned analyzer assets, so modern .NET SDK/Visual Studio toolchains load a compatible analyzer automatically. You should not need to add manual `System.*` package references to make the analyzer load. If you are on `3.0.1` and see analyzer load warnings (for example AD0001) with older SDK/Visual Studio toolchains, upgrade to `3.0.8` and see the analyzer/patch-fix sections in [migration-v3.md](migration-v3.md). ### Usage in Visual Studio / Rider 1. The analyzer will highlight old namespace usages with warnings (HUMANIZER001) 2. Click the lightbulb 💡 icon or press `Ctrl+.` (Windows/Linux) / `Cmd+.` (Mac) 3. Select "Update to Humanizer namespace" 4. To fix all occurrences: - Right-click → Quick Actions and Refactorings - Choose "Fix all occurrences in Document/Project/Solution" ### Usage with dotnet CLI The analyzer runs automatically during build and reports warnings: ```bash # Build and see warnings dotnet build # Apply automatic fixes using dotnet format dotnet format analyzers --diagnostics HUMANIZER001 ``` ## Manual Migration If you prefer to migrate manually or can't use the analyzer: ### Step 1: Find Old Namespaces Search your codebase for using directives: ```bash # Using grep grep -r "using Humanizer\." . --include="*.cs" | grep -v "using Humanizer;" # Using PowerShell Get-ChildItem -Recurse -Filter *.cs | Select-String "using Humanizer\." | Where-Object { $_ -notmatch "using Humanizer;" } ``` ### Step 2: Replace with Single Using Replace all old namespace usings with: ```csharp using Humanizer; ``` ### Step 3: Remove Qualified Names If you use fully qualified names in your code, update them: **Before:** ```csharp var size = Humanizer.Bytes.ByteSize.FromKilobytes(10); ``` **After:** ```csharp var size = Humanizer.ByteSize.FromKilobytes(10); // Or with using directive: using Humanizer; // ... var size = ByteSize.FromKilobytes(10); ``` ### Step 4: Test Your Changes After migration, rebuild and test your application: ```bash dotnet build dotnet test ``` ## Common Migration Scenarios ### Scenario 1: Multiple Old Namespaces **Before:** ```csharp using Humanizer.Bytes; using Humanizer.Localisation; using Humanizer.Configuration; using Humanizer.Inflections; ``` **After:** ```csharp using Humanizer; ``` ### Scenario 2: Mix of Old and New **Before:** ```csharp using Humanizer; using Humanizer.Bytes; using Humanizer.Localisation; ``` **After:** ```csharp using Humanizer; ``` ### Scenario 3: Qualified Names in Code **Before:** ```csharp public Humanizer.Bytes.ByteSize GetFileSize(string path) { var info = new FileInfo(path); return Humanizer.Bytes.ByteSize.FromBytes(info.Length); } ``` **After:** ```csharp public Humanizer.ByteSize GetFileSize(string path) { var info = new FileInfo(path); return Humanizer.ByteSize.FromBytes(info.Length); } // Or better with using: using Humanizer; public ByteSize GetFileSize(string path) { var info = new FileInfo(path); return ByteSize.FromBytes(info.Length); } ``` ## Troubleshooting ### "The type or namespace name could not be found" If you get compiler errors after migration, ensure: 1. You've updated to Humanizer v3 2. You have `using Humanizer;` at the top of your file 3. You're targeting a supported framework (net8.0, net10.0, or net48) ### Analyzer Not Showing Warnings If the analyzer doesn't show warnings: 1. Rebuild your solution (`dotnet clean && dotnet build`) 2. Restart your IDE 3. Check that the analyzer package is correctly referenced 4. Ensure you're using a compatible IDE/editor (VS 2022, Rider, VS Code with C# extension) ### Can't Use the Analyzer If you can't use the Roslyn analyzer (e.g., older IDE, build system limitations): 1. Use the manual migration steps above 2. Use find/replace in your editor 3. Use command-line tools (grep, sed, PowerShell) to find and replace ## Support - **Documentation:** See [Humanizer README](../readme.md) - **Issues:** [GitHub Issues](https://github.com/Humanizr/Humanizer/issues) - **Discussions:** [GitHub Discussions](https://github.com/Humanizr/Humanizer/discussions) ## Summary - ✅ **Recommended:** Use `Humanizer.Analyzers` for automatic detection and fixing - ✅ **Alternative:** Manual migration using find/replace - ⚠️ **Breaking Change:** Old namespaces will not work in v3 - 📦 **Minimal Change:** Usually just need to update using directives to `using Humanizer;` - 🎯 **Goal:** All Humanizer types are now in the root `Humanizer` namespace ================================================ FILE: global.json ================================================ { "sdk": { "version": "10.0.100", "rollForward": "latestFeature" }, "test": { "runner": "Microsoft.Testing.Platform" } } ================================================ FILE: license.txt ================================================ The MIT License (MIT) Copyright (c) .NET Foundation and Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================== Inflector (https://github.com/srkirkland/Inflector) The MIT License (MIT) Copyright (c) 2013 Scott Kirkland ============================================================================== ByteSize (https://github.com/omar/ByteSize) The MIT License (MIT) Copyright (c) 2013-2014 Omar Khudeira (http://omar.io) ============================================================================== ================================================ FILE: nuget.config ================================================  ================================================ FILE: readme.md ================================================ # Humanizer [![Build Status](https://dev.azure.com/dotnet/Humanizer/_apis/build/status/Humanizer-CI?branchName=main)](https://dev.azure.com/dotnet/Humanizer/_build?definitionId=14) [![NuGet version](https://img.shields.io/nuget/v/Humanizer.svg?logo=nuget&cacheSeconds=300)](https://www.nuget.org/packages/Humanizer) [![NuGet version prerelease](https://img.shields.io/nuget/vpre/Humanizer.svg?logo=nuget&cacheSeconds=300)](https://img.shields.io/nuget/vpre/Humanizer.Core) [![NuGet downloads](https://img.shields.io/nuget/dt/Humanizer.Core.svg?logo=nuget&cacheSeconds=300)](https://www.nuget.org/packages/Humanizer.Core) Humanizer meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities. > **📚 Full Documentation**: See the [documentation folder](docs/index.md) for comprehensive guides, examples, and API reference. ## Install You can install Humanizer as [a NuGet package](https://www.nuget.org/packages/Humanizer): **English only**: `Humanizer.Core` All languages: `Humanizer` ### Supported frameworks **Supported frameworks:** net10.0, net8.0, net48 **netstandard2.0:** The NuGet package also targets netstandard2.0 as a special case to support specific scenarios such as Roslyn Analyzers and MSBuild tasks that require netstandard2.0. **Unsupported versions:** While other .NET Framework versions (net4.6.1 through net4.7.2) can technically consume netstandard2.0 libraries, they are **not officially supported** by Humanizer and may not work correctly. Please use one of the explicitly supported frameworks listed above for the best experience. Humanizer symbols are source-indexed with [SourceLink](https://github.com/dotnet/sourcelink) and included in the package, which means you can step through Humanizer's source code while debugging your own application. > [!IMPORTANT] > **Humanizer 3.0 restore requirements**: The `Humanizer` metapackage now requires the NuGet locale parsing fix shipped in [.NET SDK 9.0.200 and corresponding Visual Studio/MSBuild updates](https://github.com/NuGet/NuGet.Client/pull/6124#issuecomment-3391090183). Restore operations must run on .NET SDK 9.0.200 or newer, or on Visual Studio 2022/MSBuild versions that include that patch. Older SDKs/MSBuild builds will fail to restore the metapackage because they do not recognize three-letter locale identifiers. As a workaround, reference `Humanizer.Core` directly and add the desired `Humanizer.Core.` satellite packages individually when targeting older tooling. > Upgrading from `2.14.1` to `3.0.8`? See [docs/migration-v3.md](docs/migration-v3.md) for the complete breaking-change checklist, patch-line fix notes, and known regression status. ### Specify Languages (Optional) You choose which packages based on what NuGet package(s) you install. By default, the main `Humanizer` package installs all supported languages. If you're not sure, then just use the main `Humanizer` package. Here are the options: | Option | Package Name | Install Command | Included Languages | |--------|--------------|-----------------|-------------------| | **All languages** | `Humanizer` | `dotnet add package Humanizer` | All supported languages (pulls in `Humanizer.Core` and all language packages) | | **English only** | `Humanizer.Core` | `dotnet add package Humanizer.Core` | English only | | **Specific languages** | `Humanizer.Core.` | `dotnet add package Humanizer.Core.fr` (French example) | Install as many language-specific packages as needed | For example, for French use `Humanizer.Core.fr`, for Spanish use `Humanizer.Core.es`, etc. You can include multiple languages by installing however many language packages you want. The detailed explanation for how this works is in the comments [here](https://github.com/Humanizr/Humanizer/issues/59#issuecomment-152546079). ## Features ### Humanize String String humanization is a core feature that transforms computerized strings into readable, human-friendly text. This is particularly valuable when you need to display programming identifiers (class names, method names, properties) to end users in a readable format. The foundation of this feature was originally developed for the [BDDfy framework](https://github.com/TestStack/TestStack.BDDfy) to turn test method names into readable test descriptions. `Humanize` intelligently handles PascalCase, camelCase, underscored_strings, and dash-separated-strings. ```csharp "PascalCaseInputStringIsTurnedIntoSentence".Humanize() => "Pascal case input string is turned into sentence" "Underscored_input_string_is_turned_into_sentence".Humanize() => "Underscored input string is turned into sentence" "dash-separated-string".Humanize() => "Dash separated string" ``` **Acronym Handling**: Strings containing only uppercase letters are treated as acronyms and left unchanged. To humanize any string, use the `Transform` method: ```csharp "HTML".Humanize() => "HTML" // Acronym preserved "HUMANIZER".Humanize() => "HUMANIZER" // All caps preserved // Force humanization with Transform "HUMANIZER".Transform(To.LowerCase, To.TitleCase) => "Humanizer" ``` **Letter Casing**: Control the output casing directly: ```csharp "CanReturnTitleCase".Humanize(LetterCasing.Title) => "Can Return Title Case" "CanReturnLowerCase".Humanize(LetterCasing.LowerCase) => "can return lower case" "CanHumanizeIntoUpperCase".Humanize(LetterCasing.AllCaps) => "CAN HUMANIZE INTO UPPER CASE" "some string".Humanize(LetterCasing.Sentence) => "Some string" ``` #### Version 3.0 Behavioral Change In version 3.0, `Humanize` and `Titleize` now preserve input strings that contain no recognized letters (e.g., special characters, unrecognized Unicode scripts) instead of returning an empty string: ```csharp // Before v3.0: returned "" // v3.0 and later: returns "@@" "@@".Humanize() => "@@" // Cyrillic and other Unicode scripts are also preserved "Майк".Titleize() => "Майк" ``` ### Dehumanize String Reverse the humanization process by converting human-friendly strings back to PascalCase: ```csharp "Pascal case input string is turned into sentence".Dehumanize() => "PascalCaseInputStringIsTurnedIntoSentence" "some string".Dehumanize() => "SomeString" "Some String".Dehumanize() => "SomeString" ``` ### Transform String The `Transform` method provides a flexible, extensible way to apply string transformations. Unlike the legacy `LetterCasing` enum which limits you to built-in options, `IStringTransformer` is an interface you can implement in your codebase for domain-specific transformations. ```csharp "Sentence casing".Transform(To.LowerCase) => "sentence casing" "Sentence casing".Transform(To.SentenceCase) => "Sentence casing" "Sentence casing".Transform(To.TitleCase) => "Sentence Casing" "Sentence casing".Transform(To.UpperCase) => "SENTENCE CASING" ``` ### Truncate String Intelligently truncate strings with multiple strategies. The default uses the `…` character (one character) instead of `"..."` (three characters) to maximize visible text before truncation. You can also implement custom `ITruncator` strategies for specialized truncation logic. ```csharp "Long text to truncate".Truncate(10) => "Long text…" "Long text to truncate".Truncate(10, "---") => "Long te---" // Fixed length (default) "Long text to truncate".Truncate(10, Truncator.FixedLength) => "Long text…" // Fixed number of words "Long text to truncate".Truncate(2, Truncator.FixedNumberOfWords) => "Long text…" // Truncate from the left "Long text to truncate".Truncate(10, Truncator.FixedLength, TruncateFrom.Left) => "… truncate" ``` ### Humanize Enums Enum humanization eliminates the need to manually add spaces between words in enum member names. While you could use `DescriptionAttribute` on every enum member, Humanizer automatically handles the common case of simply needing to add spaces. When `DescriptionAttribute` (or any attribute with a `Description` property) is present, it takes precedence, making it easy to provide custom text only when needed. ```csharp public enum UserType { [Description("Custom description")] MemberWithDescriptionAttribute, MemberWithoutDescriptionAttribute, ALLCAPITALS } // DescriptionAttribute value is used UserType.MemberWithDescriptionAttribute.Humanize() => "Custom description" // Automatic humanization when no attribute UserType.MemberWithoutDescriptionAttribute.Humanize() => "Member without description attribute" // Apply casing transformations UserType.MemberWithoutDescriptionAttribute.Humanize().Transform(To.TitleCase) => "Member Without Description Attribute" ``` Humanizer works with any attribute containing a `Description` property and supports localized `DisplayAttribute` for multi-language scenarios. This helps you avoid littering enums with unnecessary attributes while still providing customization when needed. ### Dehumanize Enums Convert humanized strings back to their original enum values: ```csharp "Member without description attribute".DehumanizeTo() => UserType.MemberWithoutDescriptionAttribute // Non-generic version for runtime types "Member without description attribute".DehumanizeTo(typeof(UserType)) => UserType.MemberWithoutDescriptionAttribute // Handle missing matches gracefully "Invalid".DehumanizeTo(OnNoMatch.ReturnsNull) => null ``` The method honors `DescriptionAttribute` and is case-insensitive. ### Humanize DateTime Get relative time descriptions for `DateTime` and `DateTimeOffset` values: ```csharp DateTime.UtcNow.AddHours(-2).Humanize() => "2 hours ago" DateTime.UtcNow.AddHours(-30).Humanize() => "yesterday" DateTime.UtcNow.AddHours(2).Humanize() => "2 hours from now" DateTime.UtcNow.AddHours(30).Humanize() => "tomorrow" DateTimeOffset.UtcNow.AddHours(1).Humanize() => "an hour from now" ``` Supports both UTC and local times, with optional culture specification and custom comparison dates. ```csharp public static string Humanize(this DateTime input, bool utcDate = true, DateTime? dateToCompareAgainst = null, CultureInfo culture = null) public static string Humanize(this DateTimeOffset input, DateTimeOffset? dateToCompareAgainst = null, CultureInfo culture = null) ``` Many localizations are available for this method. Here are a few examples: ```csharp // In ar culture DateTime.UtcNow.AddDays(-1).Humanize() => "أمس" DateTime.UtcNow.AddDays(-2).Humanize() => "منذ يومين" DateTime.UtcNow.AddDays(-3).Humanize() => "منذ 3 أيام" DateTime.UtcNow.AddDays(-11).Humanize() => "منذ 11 يوم" // In ru-RU culture DateTime.UtcNow.AddMinutes(-1).Humanize() => "минуту назад" DateTime.UtcNow.AddMinutes(-2).Humanize() => "2 минуты назад" DateTime.UtcNow.AddMinutes(-10).Humanize() => "10 минут назад" DateTime.UtcNow.AddMinutes(-21).Humanize() => "21 минуту назад" DateTime.UtcNow.AddMinutes(-22).Humanize() => "22 минуты назад" DateTime.UtcNow.AddMinutes(-40).Humanize() => "40 минут назад" ``` There are two strategies for `DateTime.Humanize`: the default one as seen above and a precision based one. To use the precision based strategy you need to configure it: ```csharp Configurator.DateTimeHumanizeStrategy = new PrecisionDateTimeHumanizeStrategy(precision: .75); Configurator.DateTimeOffsetHumanizeStrategy = new PrecisionDateTimeOffsetHumanizeStrategy(precision: .75); // configure when humanizing DateTimeOffset ``` The default precision is set to .75, but you can pass your desired precision too. With precision set to 0.75: ```csharp 44 seconds => 44 seconds ago/from now 45 seconds => one minute ago/from now 104 seconds => one minute ago/from now 105 seconds => two minutes ago/from now 25 days => a month ago/from now ``` **No dehumanization for dates as `Humanize` is a lossy transformation and the human friendly date is not reversible** ### Humanize TimeSpan You can call `Humanize` on a `TimeSpan` to a get human friendly representation for it: ```csharp TimeSpan.FromMilliseconds(1).Humanize() => "1 millisecond" TimeSpan.FromMilliseconds(2).Humanize() => "2 milliseconds" TimeSpan.FromDays(1).Humanize() => "1 day" TimeSpan.FromDays(16).Humanize() => "2 weeks" ``` There is an optional `precision` parameter for `TimeSpan.Humanize` which allows you to specify the precision of the returned value. The default value of `precision` is 1 which means only the largest time unit is returned like you saw in `TimeSpan.FromDays(16).Humanize()`. Here are a few examples of specifying precision: ```csharp TimeSpan.FromDays(1).Humanize(precision:2) => "1 day" // no difference when there is only one unit in the provided TimeSpan TimeSpan.FromDays(16).Humanize(2) => "2 weeks, 2 days" // the same TimeSpan value with different precision returns different results TimeSpan.FromMilliseconds(1299630020).Humanize() => "2 weeks" TimeSpan.FromMilliseconds(1299630020).Humanize(3) => "2 weeks, 1 day, 1 hour" TimeSpan.FromMilliseconds(1299630020).Humanize(4) => "2 weeks, 1 day, 1 hour, 30 seconds" TimeSpan.FromMilliseconds(1299630020).Humanize(5) => "2 weeks, 1 day, 1 hour, 30 seconds, 20 milliseconds" ``` By default, when using `precision` parameter empty time units are not counted towards the precision of the returned value. If this behavior isn't desired for you, you can use the overloaded `TimeSpan.Humanize` method with `countEmptyUnits` parameter. Leading empty time units never count. Here is an example showing the difference of counting empty units: ```csharp TimeSpan.FromMilliseconds(3603001).Humanize(3) => "1 hour, 3 seconds, 1 millisecond" TimeSpan.FromMilliseconds(3603001).Humanize(3, countEmptyUnits:true) => "1 hour, 3 seconds" ``` Many localizations are available for this method: ```csharp // in de-DE culture TimeSpan.FromDays(1).Humanize() => "Ein Tag" TimeSpan.FromDays(2).Humanize() => "2 Tage" // in sk-SK culture TimeSpan.FromMilliseconds(1).Humanize() => "1 milisekunda" TimeSpan.FromMilliseconds(2).Humanize() => "2 milisekundy" TimeSpan.FromMilliseconds(5).Humanize() => "5 milisekúnd" ``` Culture to use can be specified explicitly. If it is not, current thread's current UI culture is used. Example: ```csharp TimeSpan.FromDays(1).Humanize(culture: "ru-RU") => "один день" ``` In addition, a minimum unit of time may be specified to avoid rolling down to a smaller unit. For example: ```csharp TimeSpan.FromMilliseconds(122500).Humanize(minUnit: TimeUnit.Second) => "2 minutes, 2 seconds" // instead of 2 minutes, 2 seconds, 500 milliseconds TimeSpan.FromHours(25).Humanize(minUnit: TimeUnit.Day) => "1 Day" //instead of 1 Day, 1 Hour ``` In addition, a maximum unit of time may be specified to avoid rolling up to the next largest unit. For example: ```csharp TimeSpan.FromDays(7).Humanize(maxUnit: TimeUnit.Day) => "7 days" // instead of 1 week TimeSpan.FromMilliseconds(2000).Humanize(maxUnit: TimeUnit.Millisecond) => "2000 milliseconds" // instead of 2 seconds ``` The default maxUnit is `TimeUnit.Week` because it gives exact results. You can increase this value to `TimeUnit.Month` or `TimeUnit.Year` which will give you an approximation based on 365.2425 days a year and 30.436875 days a month. Therefore, the months are alternating between 30 and 31 days in length and every fourth year is 366 days long. ```csharp TimeSpan.FromDays(486).Humanize(maxUnit: TimeUnit.Year, precision: 7) => "1 year, 3 months, 29 days" // One day further is 1 year, 4 month TimeSpan.FromDays(517).Humanize(maxUnit: TimeUnit.Year, precision: 7) => "1 year, 4 months, 30 days" // This month has 30 days and one day further is 1 year, 5 months ``` When there are multiple time units, they are combined using the `", "` string: ```csharp TimeSpan.FromMilliseconds(1299630020).Humanize(3) => "2 weeks, 1 day, 1 hour" ``` When `TimeSpan` is zero, the default behavior will return "0" plus whatever the minimum time unit is. However, if you assign `true` to `toWords` when calling `Humanize`, then the method returns "no time". For example: ```csharp TimeSpan.Zero.Humanize(1) => "0 milliseconds" TimeSpan.Zero.Humanize(1, toWords: true) => "no time" TimeSpan.Zero.Humanize(1, minUnit: Humanizer.Localisation.TimeUnit.Second) => "0 seconds" ``` Using the `collectionSeparator` parameter, you can specify your own separator string: ```csharp TimeSpan.FromMilliseconds(1299630020).Humanize(3, collectionSeparator: " - ") => "2 weeks - 1 day - 1 hour" ```` It is also possible to use the current culture's collection formatter to combine the time units. To do so, specify `null` as the `collectionSeparator` parameter: ```csharp // in en-US culture TimeSpan.FromMilliseconds(1299630020).Humanize(3, collectionSeparator: null) => "2 weeks, 1 day, and 1 hour" // in de-DE culture TimeSpan.FromMilliseconds(1299630020).Humanize(3, collectionSeparator: null) => "2 Wochen, Ein Tag und Eine Stunde" ``` If words are preferred to numbers, a `toWords: true` parameter can be set to convert the numbers in a humanized TimeSpan to words: ```csharp TimeSpan.FromMilliseconds(1299630020).Humanize(3, toWords: true) => "two weeks, one day, one hour" ``` By calling `ToAge`, a `TimeSpan` can also be expressed as an age. For cultures that do not define an age expression, the result will be the same as calling `Humanize` _(but with a default `maxUnit` equal to `TimeUnit.Year`)_. ```csharp // in en-US culture TimeSpan.FromDays(750).ToAge() => "2 years old" // in fr culture TimeSpan.FromDays(750).ToAge() => "2 ans" ``` ### Humanize Collections You can call `Humanize` on any `IEnumerable` to get a nicely formatted string representing the objects in the collection. By default `ToString()` will be called on each item to get its representation but a formatting function may be passed to `Humanize` instead. Additionally, a default separator is provided ("and" in English), but a different separator may be passed into `Humanize`. For instance: ```csharp class SomeClass { public string SomeString; public int SomeInt; public override string ToString() { return "Specific String"; } } string FormatSomeClass(SomeClass sc) { return string.Format("SomeObject #{0} - {1}", sc.SomeInt, sc.SomeString); } var collection = new List { new SomeClass { SomeInt = 1, SomeString = "One" }, new SomeClass { SomeInt = 2, SomeString = "Two" }, new SomeClass { SomeInt = 3, SomeString = "Three" } }; collection.Humanize() // "Specific String, Specific String, and Specific String" collection.Humanize("or") // "Specific String, Specific String, or Specific String" collection.Humanize(FormatSomeClass) // "SomeObject #1 - One, SomeObject #2 - Two, and SomeObject #3 - Three" collection.Humanize(sc => sc.SomeInt.Ordinalize(), "or") // "1st, 2nd, or 3rd" ``` Items are trimmed and blank (NullOrWhitespace) items are skipped. This results in clean comma punctuation. (If there is a custom formatter function, this applies only to the formatter's output.) You can provide your own collection formatter by implementing `ICollectionFormatter` and registering it with `Configurator.CollectionFormatters`. ### Inflector methods Inflector methods handle the complexities of English pluralization and singularization rules, including irregular words (man/men, person/people) and uncountable words (fish, equipment). These methods save you from maintaining your own word lists and rules. #### Pluralize Intelligently pluralize words, handling irregular and uncountable forms: ```csharp "Man".Pluralize() => "Men" "string".Pluralize() => "strings" "person".Pluralize() => "people" // Uncertain plurality? Use the optional parameter "Men".Pluralize(inputIsKnownToBeSingular: false) => "Men" "string".Pluralize(inputIsKnownToBeSingular: false) => "strings" ``` #### Singularize Convert plural words to singular form: ```csharp "Men".Singularize() => "Man" "strings".Singularize() => "string" "people".Singularize() => "person" // Uncertain plurality? Use the optional parameter "Man".Singularize(inputIsKnownToBePlural: false) => "Man" ``` ## Adding Words Sometimes, you may need to add a rule from the singularization/pluralization vocabulary (the examples below are already in the `DefaultVocabulary` used by `Inflector`): ```csharp // Adds a word to the vocabulary which cannot easily be pluralized/singularized by RegEx. // Will match both "salesperson" and "person". Vocabularies.Default.AddIrregular("person", "people"); // To only match "person" and not "salesperson" you would pass false for the 'matchEnding' parameter. Vocabularies.Default.AddIrregular("person", "people", matchEnding: false); // Adds an uncountable word to the vocabulary. Will be ignored when plurality is changed: Vocabularies.Default.AddUncountable("fish"); // Adds a rule to the vocabulary that does not follow trivial rules for pluralization: Vocabularies.Default.AddPlural("bus", "buses"); // Adds a rule to the vocabulary that does not follow trivial rules for singularization // (will match both "vertices" -> "vertex" and "indices" -> "index"): Vocabularies.Default.AddSingular("(vert|ind)ices$", "$1ex"); ``` #### ToQuantity Combine numbers with properly pluralized/singularized words: ```csharp "case".ToQuantity(0) => "0 cases" "case".ToQuantity(1) => "1 case" "case".ToQuantity(5) => "5 cases" "man".ToQuantity(2) => "2 men" // Display quantity as words or hide it "case".ToQuantity(5, ShowQuantityAs.Words) => "five cases" "case".ToQuantity(5, ShowQuantityAs.None) => "cases" // Format with custom number formatting "dollar".ToQuantity(2, "C0", new CultureInfo("en-US")) => "$2 dollars" "cases".ToQuantity(12000, "N0") => "12,000 cases" ``` #### Ordinalize Convert numbers to ordinal strings (1st, 2nd, 3rd, etc.): ```csharp 1.Ordinalize() => "1st" 5.Ordinalize() => "5th" 21.Ordinalize() => "21st" "21".Ordinalize() => "21st" // Supports grammatical gender (culture-specific) 1.Ordinalize(GrammaticalGender.Feminine) => "1ª" // Brazilian Portuguese 1.Ordinalize(GrammaticalGender.Masculine) => "1º" // Brazilian Portuguese ``` #### Titleize, Pascalize, Camelize Convert strings to various coding conventions: ```csharp // Titleize: Title Case with spaces "some_title".Titleize() => "Some Title" // Pascalize: UpperCamelCase without spaces "some_title for something".Pascalize() => "SomeTitleForSomething" // Camelize: lowerCamelCase without spaces "some_title for something".Camelize() => "someTitleForSomething" ``` #### Underscore, Dasherize, Kebaberize Transform to common naming conventions: ```csharp // Underscore: snake_case "SomeTitle".Underscore() => "some_title" // Dasherize/Hyphenate: Replace underscores with dashes "some_title".Dasherize() => "some-title" "some_title".Hyphenate() => "some-title" // Kebaberize: kebab-case (lowercase with hyphens) "SomeText".Kebaberize() => "some-text" "some property name".Kebaberize() => "some-property-name" ``` ### Fluent Date Fluent date methods make time-based code dramatically more readable. Instead of verbose `DateTime.Now.AddDays(2).AddHours(3)` calls, you can write `DateTime.Now + 2.Days() + 3.Hours()`. This improves code clarity and reduces errors. **TimeSpan methods:** ```csharp 2.Milliseconds() => TimeSpan.FromMilliseconds(2) 5.Seconds() => TimeSpan.FromSeconds(5) 3.Minutes() => TimeSpan.FromMinutes(3) 4.Hours() => TimeSpan.FromHours(4) 7.Days() => TimeSpan.FromDays(7) 2.Weeks() => TimeSpan.FromDays(14) ``` **Use fluent syntax instead of verbose `Add` methods:** ```csharp // Instead of this: DateTime.Now.AddDays(2).AddHours(3).AddMinutes(-5) // Write this: DateTime.Now + 2.Days() + 3.Hours() - 5.Minutes() ``` **DateTime construction:** ```csharp In.TheYear(2010) => new DateTime(2010, 1, 1) In.January => January 1st of current year In.FebruaryOf(2009) => February 1st, 2009 On.January.The4th => January 4th of current year On.February.The(12) => February 12th of current year ``` **DateTime manipulation:** ```csharp var date = new DateTime(2011, 2, 10, 5, 25, 45, 125); date.In(2008) => Changes year to 2008 date.At(2, 20, 15) => Changes time to 2:20:15.125 date.AtNoon() => Changes time to 12:00:00 date.AtMidnight() => Changes time to 00:00:00 ``` ### Number to numbers Create large numbers with readable fluent syntax: ```csharp 3.Thousands() => 3000 5.Millions() => 5000000 1.25.Billions() => 1250000000 // Chain for complex values 3.Hundreds().Thousands() => 300000 ``` ### Number to words Convert numbers to their word representation: ```csharp 1.ToWords() => "one" 10.ToWords() => "ten" 122.ToWords() => "one hundred and twenty-two" 3501.ToWords() => "three thousand five hundred and one" // Grammatical gender support (culture-specific) 1.ToWords(GrammaticalGender.Masculine, new CultureInfo("ru")) => "один" 1.ToWords(GrammaticalGender.Feminine, new CultureInfo("ru")) => "одна" // Control "and" usage 3501.ToWords(addAnd: false) => "three thousand five hundred one" ``` ### Number to ordinal words Convert numbers to ordinal word form (first, second, third, etc.): ```csharp 0.ToOrdinalWords() => "zeroth" 1.ToOrdinalWords() => "first" 2.ToOrdinalWords() => "second" 10.ToOrdinalWords() => "tenth" 21.ToOrdinalWords() => "twenty first" 121.ToOrdinalWords() => "hundred and twenty first" // Grammatical gender support (culture-specific) 1.ToOrdinalWords(GrammaticalGender.Masculine, new CultureInfo("pt-BR")) => "primeiro" 1.ToOrdinalWords(GrammaticalGender.Feminine, new CultureInfo("pt-BR")) => "primeira" ``` ### Words to Number Conversion Convert English words to numbers (currently English-only): ```csharp "twenty".ToNumber(new CultureInfo("en")) => 20 "one hundred and five".ToNumber(new CultureInfo("en")) => 105 "three thousand two hundred".ToNumber(new CultureInfo("en")) => 3200 // Try pattern for safe conversion if ("forty-two".TryToNumber(out var number, new CultureInfo("en"))) Console.WriteLine(number); // Outputs: 42 // Get unrecognized words on failure if (!"tenn".TryToNumber(out var invalid, new CultureInfo("en"), out var badWord)) Console.WriteLine($"Unrecognized word: {badWord}"); // Outputs: Unrecognized word: tenn ``` > **Note:** Only English (`en`) is currently supported. Other languages throw `NotSupportedException`. ### DateTime to ordinal words Convert dates to ordinal word format: ```csharp // English UK new DateTime(2015, 1, 1).ToOrdinalWords() => "1st January 2015" new DateTime(2015, 3, 22).ToOrdinalWords() => "22nd March 2015" // English US new DateTime(2015, 1, 1).ToOrdinalWords() => "January 1st, 2015" new DateTime(2015, 2, 12).ToOrdinalWords() => "February 12th, 2015" // Grammatical case support (culture-specific) new DateTime(2015, 1, 1).ToOrdinalWords(GrammaticalCase.Genitive) ``` ### TimeOnly to Clock Notation Convert `TimeOnly` to readable clock notation (.NET 6+): ```csharp // English US new TimeOnly(3, 0).ToClockNotation() => "three o'clock" new TimeOnly(12, 0).ToClockNotation() => "noon" new TimeOnly(14, 30).ToClockNotation() => "half past two" // Brazilian Portuguese new TimeOnly(3, 0).ToClockNotation() => "três em ponto" new TimeOnly(14, 30).ToClockNotation() => "duas e meia" // Round to nearest 5 minutes new TimeOnly(15, 7).ToClockNotation(ClockNotationRounding.NearestFiveMinutes) => "five past three" ``` ### Roman numerals Convert between integers and Roman numerals: ```csharp // To Roman (supports 1-3999) 1.ToRoman() => "I" 4.ToRoman() => "IV" 10.ToRoman() => "X" 1990.ToRoman() => "MCMXC" // From Roman "XIV".FromRoman() => 14 "MCMXC".FromRoman() => 1990 ``` ### Metric numerals Convert between numbers and metric notation: ```csharp // To Metric 1d.ToMetric() => "1" 1230d.ToMetric() => "1.23k" 0.1d.ToMetric() => "100m" 456789.ToMetric(decimals: 2) => "456.79k" // From Metric "1.23k".FromMetric() => 1230 "100m".FromMetric() => 0.1 ``` ### ByteSize Humanizer includes a port of the brilliant [ByteSize](https://github.com/omar/ByteSize) library. Quite a few changes and additions are made on `ByteSize` to make the interaction with `ByteSize` easier and more consistent with the Humanizer API. Here are a few examples of how you can convert from numbers to byte sizes and between size magnitudes: ```c# var fileSize = (10).Kilobytes(); fileSize.Bits => 81920 fileSize.Bytes => 10240 fileSize.Kilobytes => 10 fileSize.Megabytes => 0.009765625 fileSize.Gigabytes => 9.53674316e-6 fileSize.Terabytes => 9.31322575e-9 ``` There are a few extension methods that allow you to turn a number into a ByteSize instance: ```csharp 3.Bits(); 5.Bytes(); (10.5).Kilobytes(); (2.5).Megabytes(); (10.2).Gigabytes(); (4.7).Terabytes(); ``` You can also add/subtract the values using +/- operators and Add/Subtract methods: ```csharp var total = (10).Gigabytes() + (512).Megabytes() - (2.5).Gigabytes(); total.Subtract((2500).Kilobytes()).Add((25).Megabytes()); ``` A `ByteSize` object contains two properties that represent the largest metric prefix symbol and value: ```csharp var maxFileSize = (10).Kilobytes(); maxFileSize.LargestWholeNumberSymbol; // "KB" maxFileSize.LargestWholeNumberValue; // 10 ``` If you want a string representation you can call `ToString` or `Humanize` interchangeably on the `ByteSize` instance: ```csharp 7.Bits().ToString(); // 7 b 8.Bits().ToString(); // 1 B (.5).Kilobytes().Humanize(); // 512 B (1000).Kilobytes().ToString(); // 1000 KB (1024).Kilobytes().Humanize(); // 1 MB (.5).Gigabytes().Humanize(); // 512 MB (1024).Gigabytes().ToString(); // 1 TB ``` You can also optionally provide a format for the expected string representation. The formatter can contain the symbol of the value to display: `b`, `B`, `KB`, `MB`, `GB`, `TB`. The formatter uses the built in [`double.ToString` method](https://docs.microsoft.com/dotnet/api/system.double.tostring) with `#.##` as the default format which rounds the number to two decimal places: ```csharp var b = (10.505).Kilobytes(); // Default number format is #.## b.ToString("KB"); // 10.52 KB b.Humanize("MB"); // .01 MB b.Humanize("b"); // 86057 b // Default symbol is the largest metric prefix value >= 1 b.ToString("#.#"); // 10.5 KB // All valid values of double.ToString(string format) are acceptable b.ToString("0.0000"); // 10.5050 KB b.Humanize("000.00"); // 010.51 KB // You can include number format and symbols b.ToString("#.#### MB"); // .0103 MB b.Humanize("0.00 GB"); // 0 GB b.Humanize("#.## B"); // 10757.12 B ``` If you want a string representation with full words you can call `ToFullWords` on the `ByteSize` instance: ```csharp 7.Bits().ToFullWords(); // 7 bits 8.Bits().ToFullWords(); // 1 byte (.5).Kilobytes().ToFullWords(); // 512 bytes (1000).Kilobytes().ToFullWords(); // 1000 kilobytes (1024).Kilobytes().ToFullWords(); // 1 megabyte (.5).Gigabytes().ToFullWords(); // 512 megabytes (1024).Gigabytes().ToFullWords(); // 1 terabyte ``` There isn't a `Dehumanize` method to turn a string representation back into a `ByteSize` instance; but you can use `Parse` and `TryParse` on `ByteSize` to do that. Like other `TryParse` methods, `ByteSize.TryParse` returns `boolean` value indicating whether the parsing was successful. If the value is parsed it is output to the `out` parameter supplied: ```csharp ByteSize output; ByteSize.TryParse("1.5mb", out output); // Invalid ByteSize.Parse("1.5 b"); // Can't have partial bits // Valid ByteSize.Parse("5b"); ByteSize.Parse("1.55B"); ByteSize.Parse("1.55KB"); ByteSize.Parse("1.55 kB "); // Spaces are trimmed ByteSize.Parse("1.55 kb"); ByteSize.Parse("1.55 MB"); ByteSize.Parse("1.55 mB"); ByteSize.Parse("1.55 mb"); ByteSize.Parse("1.55 GB"); ByteSize.Parse("1.55 gB"); ByteSize.Parse("1.55 gb"); ByteSize.Parse("1.55 TB"); ByteSize.Parse("1.55 tB"); ByteSize.Parse("1.55 tb"); ``` Finally, if you need to calculate the rate at which a quantity of bytes has been transferred, you can use the `Per` method of `ByteSize`. The `Per` method accepts one argument - the measurement interval for the bytes; this is the amount of time it took to transfer the bytes. The `Per` method returns a `ByteRate` class which has a `Humanize` method. By default, rates are given in seconds (eg, MB/s). However, if desired, a TimeUnit may be passed to `Humanize` for an alternate interval. Valid intervals are `TimeUnit.Second`, `TimeUnit.Minute`, and `TimeUnit.Hour`. Examples of each interval and example byte rate usage is below. ```csharp var size = ByteSize.FromMegabytes(10); var measurementInterval = TimeSpan.FromSeconds(1); var text = size.Per(measurementInterval).Humanize(); // 10 MB/s text = size.Per(measurementInterval).Humanize(TimeUnit.Minute); // 600 MB/min text = size.Per(measurementInterval).Humanize(TimeUnit.Hour); // 35.15625 GB/hour ``` You can specify a format for the bytes part of the humanized output: ```csharp 19854651984.Bytes().Per(1.Seconds()).Humanize("#.##"); // 18.49 GB/s ``` ### Heading to words Humanizer includes methods to change a numeric heading to words. The heading can be a `double` whereas the result will be a string. You can choose whether to return a full representation of the heading (e.g. north, east, south or west), a short representation (e.g. N, E, S, W) or a Unicode arrow character (e.g. ↑, →, ↓, ←). ```csharp 360.ToHeading(); // N 720.ToHeading(); // N ``` To retrieve a full version of the heading, use the following call: ```csharp 180.ToHeading(HeadingStyle.Full); // south 360.ToHeading(HeadingStyle.Full); // north ``` Please note that a textual representation has a maximum deviation of 11.25°. The methods above all have an overload with which you can provide a `CultureInfo` object in order to determine the localized result to return. To retrieve an arrow representing the heading use the following method: ```csharp 90.ToHeadingArrow(); // → 225.ToHeadingArrow(); // ↙ ``` The arrow representation of the heading has a maximum deviation of 22.5°. In order to retrieve a heading based on the short text representation (e.g. N, E, S, W), the following method can be used: ```csharp "S".FromShortHeading(); // 180 "SW".FromShortHeading(); // 225 ``` ### Tupleize Humanizer can change whole numbers into their 'tuple' using `Tupleize`. For example: ```csharp 1.Tupleize(); // single 3.Tupleize(); // triple 100.Tupleize(); // centuple ``` The numbers 1-10, 100 and 1000 will be converted into a 'named' tuple (i.e. "single", "double" etc.). Any other number "n" will be converted to "n-tuple". ### Time unit to symbol Humanizer can translate time units to their symbols: ```csharp TimeUnit.Day.ToSymbol(); // d TimeUnit.Week.ToSymbol(); // week TimeUnit.Year.ToSymbol(); // y ``` ## Mix this into your framework to simplify your life This is just a baseline, and you can use this to simplify your day-to-day job. For example, in Asp.Net MVC we keep chucking `Display` attribute on ViewModel properties so `HtmlHelper` can generate correct labels for us; but, just like enums, in the vast majority of cases we just need a space between the words in property name - so why not use `"string".Humanize` for that?! You may find an ASP.NET MVC sample [in the code](https://github.com/Humanizr/Humanizer/tree/v2.7.9/samples/Humanizer.MvcSample) that does that (although the project is excluded from the solution file to make the NuGet package available for .NET 3.5 too). This is achieved using a custom `DataAnnotationsModelMetadataProvider` I called [HumanizerMetadataProvider](https://github.com/Humanizr/Humanizer/blob/v2.7.9/samples/Humanizer.MvcSample/HumanizerMetadataProvider.cs). It is small enough to repeat here; so here we go: ```csharp using System; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Web.Mvc; using Humanizer; public class HumanizerMetadataProvider : DataAnnotationsModelMetadataProvider { protected override ModelMetadata CreateMetadata( IEnumerable attributes, Type containerType, Func modelAccessor, Type modelType, string propertyName) { var propertyAttributes = attributes.ToList(); var modelMetadata = base.CreateMetadata(propertyAttributes, containerType, modelAccessor, modelType, propertyName); if (IsTransformRequired(modelMetadata, propertyAttributes)) modelMetadata.DisplayName = modelMetadata.PropertyName.Humanize(); return modelMetadata; } private static bool IsTransformRequired(ModelMetadata modelMetadata, IList propertyAttributes) { if (string.IsNullOrEmpty(modelMetadata.PropertyName)) return false; if (propertyAttributes.OfType().Any()) return false; if (propertyAttributes.OfType().Any()) return false; return true; } } ``` This class calls the base class to extract the metadata and then, if required, humanizes the property name. It is checking if the property already has a `DisplayName` or `Display` attribute on it in which case the metadata provider will just honor the attribute and leave the property alone. For other properties it will Humanize the property name. That is all. Now you need to register this metadata provider with Asp.Net MVC. Make sure you use `System.Web.Mvc.ModelMetadataProviders`, and not `System.Web.ModelBinding.ModelMetadataProviders`: ```csharp ModelMetadataProviders.Current = new HumanizerMetadataProvider(); ``` ... and now you can replace: ```csharp public class RegisterModel { [Display(Name = "User name")] public string UserName { get; set; } [Display(Name = "Email address")] public string EmailAddress { get; set; } [Display(Name = "Confirm password")] public string ConfirmPassword { get; set; } } ``` with: ```csharp public class RegisterModel { public string UserName { get; set; } public string EmailAddress { get; set; } public string ConfirmPassword { get; set; } } ``` ... and the "metadata humanizer" will take care of the rest. No need to mention that if you want title casing for your labels you can chain the method with `Transform`: ```csharp modelMetadata.DisplayName = modelMetadata.PropertyName.Humanize().Transform(To.TitleCase); ``` ## Use in ASP.NET 4.x MVC Views Humanizer is a Portable Class Library. There is currently [an issue](https://stackoverflow.com/questions/16675171/what-does-the-web-config-compilation-assemblies-element-do) if you try to use PCL's in an MVC view since the MVC views do not share the same build system as the regular project. You must specify all references in the `web.config` file, including ones the project system normally automatically adds. If you encounter errors saying that you must add a reference to either `System.Runtime` or `System.Globalization`, this applies to you. The solution is to add the contract references to your `web.config` as listed [here](https://stackoverflow.com/a/19942274/738188). Note that this applies to any PCL you use in an MVC view, not just Humanizer. ## Continuous Integration from Azure DevOps The Humanizer project is built & tested continuously by Azure DevOps (more details [here](https://dev.azure.com/dotnet/Humanizer/_build?definitionId=14)). That applies to pull requests too. Shortly after you submit a PR you can check the build and test status notification on your PR. The current build status on the CI server is [![Build status](https://dev.azure.com/dotnet/Humanizer/_apis/build/status/Humanizer-CI?branchName=main)](https://dev.azure.com/dotnet/Humanizer/_build?definitionId=14) ## Related projects Below is a list of related open-source projects: ### Humanizer ReSharper Annotations If using ReSharper, annotations for Humanizer are available in the [Humanizer.Annotations package](https://resharper-plugins.jetbrains.com/packages/Humanizer.Annotations/), which you can obtain via the ReSharper Extension Manager. These annotations do not yet cover the entire library, but [pull requests are always welcome!](https://github.com/enduracode/humanizer-annotations). ### PowerShell Humanizer [PowerShell Humanizer](https://github.com/dfinke/PowerShellHumanizer) is a PowerShell module that wraps Humanizer. ### Humanizer JVM [Humanizer.jvm](https://github.com/MehdiK/Humanizer.jvm) is an adaptation of the Humanizer framework for .Net which is made for the jvm and is written in Kotlin. Humanizer.jvm meets all your jvm needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities. ### Humanizer.node [Humanizer.node](https://github.com/fakoua/humanizer.node) is a TypeScript port of the Humanizer framework. ## Contributing We welcome contributions! If you'd like to contribute to Humanizer: - **Found a bug?** Please [open an issue](https://github.com/Humanizr/Humanizer/issues/new) - **Have a feature idea?** Create an issue to discuss it - **Want to submit code?** Read our [contribution guidelines](.github/CONTRIBUTING.md) and submit a pull request Please read our [Code of Conduct](.github/CODE_OF_CONDUCT.md) before contributing. ## License Humanizer is licensed under the [MIT License](license.txt). Copyright (c) .NET Foundation and Contributors ## Reporting Issues If you encounter any bugs or have feature requests, please: 1. Check if the issue already exists in our [issue tracker](https://github.com/Humanizr/Humanizer/issues) 2. If not, [create a new issue](https://github.com/Humanizr/Humanizer/issues/new) with: - A clear description of the problem or feature request - Steps to reproduce (for bugs) - Expected vs actual behavior (for bugs) - Your environment details (OS, .NET version, Humanizer version) ## Icon The icon was created by [Tyrone Rieschiek](https://twitter.com/Inkventive) ================================================ FILE: release_notes.md ================================================ # v2.2 - [#634](https://github.com/Humanizr/Humanizer/pull/634) - Added support for Greek language in resources contributed by Christos Matskas ([cmatskas](https://github.com/cmatskas)) - [#633](https://github.com/Humanizr/Humanizer/pull/633) - #632 Continued: Fuzzy month years logic for time span humanize extensions contributed by Claire Novotny ([onovotny](https://github.com/onovotny)) +enhancement - [#632](https://github.com/Humanizr/Humanizer/pull/632) - Fuzzy month years logic for time span humanize extensions contributed by Martin Strecker ([MaStr11](https://github.com/MaStr11)) - [#631](https://github.com/Humanizr/Humanizer/pull/631) - Latvian localization contributed by Dmitry Bogatykh ([bogatykh](https://github.com/bogatykh)) - [#630](https://github.com/Humanizr/Humanizer/pull/630) - billions and millions greater than 2 contributed by Rafael Bianchi ([rafaellfontana](https://github.com/rafaellfontana)) - [#628](https://github.com/Humanizr/Humanizer/pull/628) - IsDefined is prefered contributed by Shimmy ([weitzhandler](https://github.com/weitzhandler)) - [#623](https://github.com/Humanizr/Humanizer/issues/623) - Wrongful commit to master. What to do? - [#620](https://github.com/Humanizr/Humanizer/issues/620) - Double Barrel Name conversion - [#619](https://github.com/Humanizr/Humanizer/pull/619) - Update readme.md contributed by Tyler Brinkley ([TylerBrinkley](https://github.com/TylerBrinkley)) - [#617](https://github.com/Humanizr/Humanizer/pull/617) - issue 611: added the method Kebaberize contributed by ([klaus78](https://github.com/klaus78)) - [#616](https://github.com/Humanizr/Humanizer/issues/616) - English verb (Past Participle) tense conversion "x" => "xed" feasibility? - [#613](https://github.com/Humanizr/Humanizer/issues/613) - Humanizer.Core not working correctly, show localized strings instead of english - [#612](https://github.com/Humanizr/Humanizer/pull/612) - Added Swedish collection formatter contributed by Māris Brenčuks ([brencuks](https://github.com/brencuks)) - [#610](https://github.com/Humanizr/Humanizer/pull/610) - adding parameter decimals toMetric(). Fixes #609 contributed by ([klaus78](https://github.com/klaus78)) - [#609](https://github.com/Humanizr/Humanizer/issues/609) - add .ToMetric() rounding +enhancement - [#608](https://github.com/Humanizr/Humanizer/pull/608) - 605: Fix enum no display attrib contributed by Thomas Bo Nielsen ([basildk](https://github.com/basildk)) - [#605](https://github.com/Humanizr/Humanizer/issues/605) - enum with DisplayAttribute but no Description attribute fails +fix - [#603](https://github.com/Humanizr/Humanizer/pull/603) - Syntax correction in readme.md contributed by Brian MacKay ([kinetiq](https://github.com/kinetiq)) - [#602](https://github.com/Humanizr/Humanizer/pull/602) - Register Portuguese translations as `pt` contributed by ([hangy](https://github.com/hangy)) - [#601](https://github.com/Humanizr/Humanizer/issues/601) - Humanize pt-PT problem - [#600](https://github.com/Humanizr/Humanizer/pull/600) - Revert "Add Esperanto support to NumberToWords. Fixes #558" contributed by Claire Novotny ([onovotny](https://github.com/onovotny)) - [#598](https://github.com/Humanizr/Humanizer/pull/598) - Workaround for Croatian TimeSpan localization bug contributed by ([hangy](https://github.com/hangy)) - [#597](https://github.com/Humanizr/Humanizer/issues/597) - Croatian localization of TimeSpan fails with >1 day - [#596](https://github.com/Humanizr/Humanizer/issues/596) - Can not add Humanizer 2.1.0 in Class library (.Net Core) - [#595](https://github.com/Humanizr/Humanizer/pull/595) - Add new overload for Ordinalize that accepts a CultureInfo contributed by Thijs Brobbel ([tiesmaster](https://github.com/tiesmaster)) - [#590](https://github.com/Humanizr/Humanizer/pull/590) - English contributed by ([stevotennis](https://github.com/stevotennis)) - [#589](https://github.com/Humanizr/Humanizer/pull/589) - Fix CONTRIBUTING.md of broken links. contributed by Sho Sato ([cssho](https://github.com/cssho)) - [#588](https://github.com/Humanizr/Humanizer/pull/588) - Add resource value validation for DefaultFormatter contributed by Krisztián Bodrogi ([Chrissx](https://github.com/Chrissx)) - [#586](https://github.com/Humanizr/Humanizer/pull/586) - added translation for DateHumanize_Now contributed by Daniel Katz ([danielkatz](https://github.com/danielkatz)) - [#583](https://github.com/Humanizr/Humanizer/issues/583) - TimeSpan.Humanize does not behave as expected +enhancement - [#582](https://github.com/Humanizr/Humanizer/pull/582) - Pass through the content of the "Letter, other" Unicode category. contributed by ([hangy](https://github.com/hangy)) - [#581](https://github.com/Humanizr/Humanizer/pull/581) - Fix misspelling contributed by Cameron Sjo ([cameron-sjo](https://github.com/cameron-sjo)) - [#578](https://github.com/Humanizr/Humanizer/issues/578) - .Humanize() on "Arabic" letters returns empty string (or any other casing) - [#577](https://github.com/Humanizr/Humanizer/issues/577) - .NET Core 1.0 Support? - [#576](https://github.com/Humanizr/Humanizer/pull/576) - Fixed incorrect locale in readme contributed by ([fishchisel](https://github.com/fishchisel)) - [#575](https://github.com/Humanizr/Humanizer/issues/575) - not installable for projects that targets .NET client profile - [#574](https://github.com/Humanizr/Humanizer/issues/574) - Difference Dasherize and Hyphenate - [#573](https://github.com/Humanizr/Humanizer/issues/573) - Humanizer.Core 2.1.0 breaks compatibility with PCL Profile 259 - [#569](https://github.com/Humanizr/Humanizer/pull/569) - Add Esperanto support to NumberToWords. Fixes #558 contributed by Alois ([aloisdg](https://github.com/aloisdg)) - [#558](https://github.com/Humanizr/Humanizer/issues/558) - Add Esperanto support for NumberToWords - [#504](https://github.com/Humanizr/Humanizer/pull/504) - Add support for long to ToQuantity contributed by Robert Pethick ([RobPethick](https://github.com/RobPethick)) +enhancement - [#503](https://github.com/Humanizr/Humanizer/issues/503) - ToQuantity does not support long quantities +enhancement - [#500](https://github.com/Humanizr/Humanizer/pull/500) - Add ToOrdinalWords extension with gender overload contributed by Robert Pethick ([RobPethick](https://github.com/RobPethick)) - [#328](https://github.com/Humanizr/Humanizer/issues/328) - Ordinal number suffixes [Commits](https://github.com/Humanizr/Humanizer/compare/v2.1...v2.2) # vNext ### v2.1 - 2016-07-04 [Fixed issues](https://github.com/Humanizr/Humanizer/issues?q=is%3Aclosed+milestone%3Av2.1) [Commits](https://github.com/Humanizr/Humanizer/compare/v2.0.1...v2.1) ### v2.0.1 - 2016-02-07 - [#520](https://github.com/Humanizr/Humanizer/issues/520) Humanizer.Core package does not install on Xamarin [Commits](https://github.com/Humanizr/Humanizer/compare/v2.0...v2.0.1) ### v2.0.0 - 2016-01-30 - [#507](https://github.com/Humanizr/Humanizer/issues/507) Remove obsolete members - [#517](https://github.com/Humanizr/Humanizer/pull/517) Allow formatted byte size when humanizing `ByteRate` - [#497](https://github.com/Humanizr/Humanizer/issues/497) Add option to customize list of time indicators of humanized timespans [Commits](https://github.com/Humanizr/Humanizer/compare/v1.37.0...v2.0) ### v2.0.0-beta02 - 2015-12-30 - [#59](https://github.com/Humanizr/Humanizer/issues/59) Getting only needed resources on nuget install - [#101](https://github.com/Humanizr/Humanizer/issues/101) Add precision to DateTime.Humanize - [#234](https://github.com/Humanizr/Humanizer/issues/234) Remove Plurality enum - [#238](https://github.com/Humanizr/Humanizer/issues/238) Change DefaultDateTimeHumanizeStrategy to turn 60 min to one hour not 45 - [#470](https://github.com/Humanizr/Humanizer/issues/470) & [#492](https://github.com/Humanizr/Humanizer/issues/492): Build warning fixes [Commits](https://github.com/Humanizr/Humanizer/compare/v2.0.0-beta01...v2.0.0-beta02) ### v2.0.0-beta0001 - 2015-11-01 - [#451](https://github.com/Humanizr/Humanizer/issues/451): Support `dotnet` TFM. Includes support for CoreCLR - [#465](https://github.com/Humanizr/Humanizer/issues/465): Dropped .NET 4 and Silverlight 5 support. - [#462](https://github.com/Humanizr/Humanizer/pull/462): Implemented Spanish cardinal feminines - [#459](https://github.com/Humanizr/Humanizer/pull/459): Add support of metric numeral expressions - Enable source debugging via [GitLink](https://github.com/GitTools/GitLink) [Commits](https://github.com/Humanizr/Humanizer/compare/v1.37.0...v2.0.0-beta01) ### v1.37.0 - 2015-07-03 - [#416](https://github.com/Humanizr/Humanizer/pull/416): Change BrazilianPortugueseOrdinalizer to PortugueseOrdinalizer - [#419](https://github.com/Humanizr/Humanizer/pull/419): Added Dutch Ordinalizer - [#432](https://github.com/Humanizr/Humanizer/pull/432): Added the 'xunit.runner.visualstudio' nuget package to the test project - [#431](https://github.com/Humanizr/Humanizer/pull/431): Added build target for .NET 4.0 Client Profile - [#435](https://github.com/Humanizr/Humanizer/pull/435): Added Afrikaans localization - [#438](https://github.com/Humanizr/Humanizer/pull/438): Fixed the bug with negative TimeSpan Humanize - [#421](https://github.com/Humanizr/Humanizer/pull/421) & [#425](https://github.com/Humanizr/Humanizer/pull/425): Fixed StringExentions -> StringExtensions [Commits](https://github.com/Humanizr/Humanizer/compare/v1.36.0...v1.37.0) ### v1.36.0 - 2015-05-24 - [#403](https://github.com/Humanizr/Humanizer/pull/403): Added TimeSpan minUnit option - [#417](https://github.com/Humanizr/Humanizer/pull/417): Support for Serbian language, ToWords() - [#414](https://github.com/Humanizr/Humanizer/pull/414): Add Ukraininan language - [#408](https://github.com/Humanizr/Humanizer/pull/408): Added support for adding/removing rules from singular/pluralization by adding `Vocabulary` class and `Vocabularies.Default` [Commits](https://github.com/Humanizr/Humanizer/compare/v1.35.0...v1.36.0) ### v1.35.0 - 2015-03-29 - [#399](https://github.com/Humanizr/Humanizer/pull/399): Added support for humanizing DateTimeOffset - [#395](https://github.com/Humanizr/Humanizer/pull/395): Added support for Xamarin platforms to PCL - [#397](https://github.com/Humanizr/Humanizer/pull/397): Added is/are to inflector rules - [#392](https://github.com/Humanizr/Humanizer/pull/394): Default implementation for collection formatter using regular style instead of an exception. Default separator is ampercent. - [#377](https://github.com/Humanizr/Humanizer/pull/377): Added culture specific decimal separator [Commits](https://github.com/Humanizr/Humanizer/compare/v1.34.0...v1.35.0) ### v1.34.0 - 2015-03-04 - [#381](https://github.com/Humanizr/Humanizer/pull/381): Fixes trailing question mark reported in #378. - [#382](https://github.com/Humanizr/Humanizer/pull/382): Fix 90000th and -thousandth in RussianNumberToWordsConverter. - [#386](https://github.com/Humanizr/Humanizer/pull/386): Collection formatter support for German, Danish, Dutch, Portuguese and Norwegian - [#384](https://github.com/Humanizr/Humanizer/pull/384): Added maximum TimeUnit to TimeSpanHumanizeExtensions.Humanize to enable prevention of rolling up the next largest unit of time. [Commits](https://github.com/Humanizr/Humanizer/compare/v1.33.7...v1.34.0) ### v1.33.7 - 2015-02-03 - [#376](https://github.com/Humanizr/Humanizer/pull/376): Fixes the IConvertible warning thrown on Windows Phone reported on #317 [Commits](https://github.com/Humanizr/Humanizer/compare/v1.33.0...v1.33.7) ### v1.33.0 - 2015-01-26 - [#374](https://github.com/Humanizr/Humanizer/pull/374): **BREAKING CHANGE**: Fixed Chinese locale code: CHS to Hans & CHT to Hant - [#366](https://github.com/Humanizr/Humanizer/pull/366): Removed UnitPreposition to avoid warnings in Win 8.1 apps - [#365](https://github.com/Humanizr/Humanizer/pull/365): Added ByteSizeExtensions method for long inputs - [#364](https://github.com/Humanizr/Humanizer/pull/364): Added "campuses" as plural of "campus" - [#363](https://github.com/Humanizr/Humanizer/pull/363): Use RegexOptions.Compiled if available [Commits](https://github.com/Humanizr/Humanizer/compare/v1.32.0...v1.33.0) ### v1.32.0 - 2014-12-18 - [#354](https://github.com/Humanizr/Humanizer/pull/354): Removed unnecessary Regex constructors - [#356](https://github.com/Humanizr/Humanizer/pull/356): Added missing values for ro and changed the RomanianFormatter implementation so as to avoid duplicate resources - [#357](https://github.com/Humanizr/Humanizer/pull/357): Added Chinese localisation - [#350](https://github.com/Humanizr/Humanizer/pull/350): Added missing values for nl - [#359](https://github.com/Humanizr/Humanizer/pull/359): Added special case resources to neutral language - [#362](https://github.com/Humanizr/Humanizer/pull/362): Fixed arithmatic operations in ByteSize - [#361](https://github.com/Humanizr/Humanizer/pull/361): Added 'criteria' as the irregular plural of 'criterion' - [#355](https://github.com/Humanizr/Humanizer/pull/355): Added 'waves' as plural of 'wave' [Commits](https://github.com/Humanizr/Humanizer/compare/v1.31.0...v1.32.0) ###v1.31.0 - 2014-11-08 - [#340](https://github.com/Humanizr/Humanizer/pull/340): Fixed TimeSpan humanization precision skips units after the largest one when they're zero until it finds a non-zero unit - [#347](https://github.com/Humanizr/Humanizer/pull/347): Changed één to 1 for dutch language. [Commits](https://github.com/Humanizr/Humanizer/compare/v1.30.0...v1.31.0) ### v1.30.0 - 2014-11-01 - [#341](https://github.com/Humanizr/Humanizer/pull/341): Added logic to properly treat underscores, dashes and spaces. - [#342](https://github.com/Humanizr/Humanizer/pull/342): Added complete Uzbek localisation [Commits](https://github.com/Humanizr/Humanizer/compare/v1.29.0...v1.30.0) ### v1.29.0 - 2014-09-12 - [#320](https://github.com/Humanizr/Humanizer/pull/320): Fixed Dehumanize actually humanizing an already dehumanized string - [#322](https://github.com/Humanizr/Humanizer/pull/322): DefaultFormatter.TimeSpanHumanize throws a more meaningful exception when called with TimeUnits larger than TimeUnit.Week - [#314](https://github.com/Humanizr/Humanizer/pull/314): Added ByteRate class and supporting members to facilitate calculation of byte transfer rates - [#333](https://github.com/Humanizr/Humanizer/pull/333): Added support to humanize enums from resource strings - [#332](https://github.com/Humanizr/Humanizer/pull/332): Added Italian localisation and tests: date and time Resources, CollectionFormatter, NumberToWordsConverter (cardinal and ordinal), Ordinalizer [Commits](https://github.com/Humanizr/Humanizer/compare/v1.28.0...v1.29.0) ### v1.28.0 - 2014-07-06 - [#309](https://github.com/Humanizr/Humanizer/pull/309): Fixed the bug with DateTime.Humanize returning tomorrow when it's not actually tomorrow - [#306](https://github.com/Humanizr/Humanizer/pull/306): Added Singularize/Pluralize overload without using obsolete plurality enum - [#303](https://github.com/Humanizr/Humanizer/pull/303): Added support for all integer types in ByteSize extensions - [#307](https://github.com/Humanizr/Humanizer/pull/307): Added support to string.FormatWith for the explicit culture parameter - [#312](https://github.com/Humanizr/Humanizer/pull/312): Added Turkish ToWord, ToOrdinalWord and Ordinalize implementation - [#173](https://github.com/Humanizr/Humanizer/pull/173): Added support for Window Phone 8.1 [Commits](https://github.com/Humanizr/Humanizer/compare/v1.27.0...v1.28.0) ### v1.27.0 - 2014-06-21 - [#301](https://github.com/Humanizr/Humanizer/pull/301): Added Bangla (Bangladesh) localisation - [#300](https://github.com/Humanizr/Humanizer/pull/300): Added optional Culture parameter to NumberToWords - [#297](https://github.com/Humanizr/Humanizer/pull/297): Added support for all integer types in Fluent Date - [#294](https://github.com/Humanizr/Humanizer/pull/294): Added support for untyped comparison of ByteSize - [#277](https://github.com/Humanizr/Humanizer/pull/277): Added support for custom enum description attribute property names - [#276](https://github.com/Humanizr/Humanizer/pull/276): Added Farsi ToOrdinalWords - [#281](https://github.com/Humanizr/Humanizer/pull/281): Changed the logic for handling hyphenation and large numbers ending in twelve for English ordinal words; e.g. before "twenty first" now "twenty-first" - [#278](https://github.com/Humanizr/Humanizer/pull/278): Changed DefaultDateTimeHumanizeStrategy to turn 60 min to one hour not 45 - [#283](https://github.com/Humanizr/Humanizer/pull/283): Added Neutral nb support for DateTime and TimeSpan Humanize - [#286](https://github.com/Humanizr/Humanizer/pull/286): Added optional Culture parameter to DateTime.Humanize & TimeSpan.Humanize [Commits](https://github.com/Humanizr/Humanizer/compare/v1.26.1...v1.27.0) ### v1.26.1 - 2014-05-20 - [#257](https://github.com/Humanizr/Humanizer/pull/257): Added German localisation for ToOrdinalWords and Ordinalize - [#261](https://github.com/Humanizr/Humanizer/pull/261): Added future dates to Portuguese - Brazil - [#269](https://github.com/Humanizr/Humanizer/pull/269): Added Vietnamese localisation - [#268](https://github.com/Humanizr/Humanizer/pull/268): Added humanization of collections [Commits](https://github.com/Humanizr/Humanizer/compare/v1.25.4...v1.26.1) ### v1.25.4 - 2014-04-27 - [#236](https://github.com/Humanizr/Humanizer/pull/236): Added Turkish localisation - [#239](https://github.com/Humanizr/Humanizer/pull/239): Added Serbian localisation - [#241](https://github.com/Humanizr/Humanizer/pull/241): Added German ToWords localisation - [#244](https://github.com/Humanizr/Humanizer/pull/244): Added Slovenian localisation - [#247](https://github.com/Humanizr/Humanizer/pull/247): Added Slovenian number to words localisation - [#227](https://github.com/Humanizr/Humanizer/pull/227) & [#243](https://github.com/Humanizr/Humanizer/pull/243): Moved localiser registry to their own classes, allowed public access via Configurator, and made the default registrations lazy loaded [Commits](https://github.com/Humanizr/Humanizer/compare/v1.24.1...v1.25.4) ### v1.24.1 - 2014-04-21 - [#232](https://github.com/Humanizr/Humanizer/pull/232): Adding code & tests to handle Arabic numbers to ordinal - [#235](https://github.com/Humanizr/Humanizer/pull/235): Fixed the conversion for "1 millon" in SpanishNumberToWordsConverter - [#233](https://github.com/Humanizr/Humanizer/pull/233): Added build.cmd and Verify build configuration for strict project build and analysis [Commits](https://github.com/Humanizr/Humanizer/compare/v1.23.1...v1.24.1) ### v1.23.1 - 2014-04-19 - [#217](https://github.com/Humanizr/Humanizer/pull/217): Added pt-BR and Spanish Ordinalize localisation. - [#220](https://github.com/Humanizr/Humanizer/pull/220): Added string formatting options to ToQuantity - [#219](https://github.com/Humanizr/Humanizer/pull/219): Added Japanese translation for date and timespan - [#221](https://github.com/Humanizr/Humanizer/pull/221): Added Russian ordinalizer - [#228](https://github.com/Humanizr/Humanizer/pull/228): Fixed the "twenties" in SpanishNumberToWordsConverter - [#231](https://github.com/Humanizr/Humanizer/pull/231): Added more settings for FromNow, Dual and Plural (Arabic) - [#222](https://github.com/Humanizr/Humanizer/pull/222): Updated Ordinalize and ToOrdinalWords to account for special exceptions with 1 and 3. [Commits](https://github.com/Humanizr/Humanizer/compare/v1.22.1...v1.23.1) ### v1.22.1 - 2014-04-14 - [#188](https://github.com/Humanizr/Humanizer/pull/188): Added Spanish ToOrdinalWords translations - [#166](https://github.com/Humanizr/Humanizer/pull/166): Added Dutch (NL) Number to words and ordinals - [#199](https://github.com/Humanizr/Humanizer/pull/199): Added Hebrew Number to words (both genders) - [#202](https://github.com/Humanizr/Humanizer/pull/202): Fixed typo sekunttia -> sekuntia (Finnish translation) - [#203](https://github.com/Humanizr/Humanizer/pull/203): Added feminine gender for french ordinal words - [#208](https://github.com/Humanizr/Humanizer/pull/208): Added Hebrew implementation of future DateTime [Commits](https://github.com/Humanizr/Humanizer/compare/v1.21.1...v1.22.1) ### v1.21.1 - 2014-04-12 - [#196](https://github.com/Humanizr/Humanizer/pull/196): Added Gender for ToOrdinalWords (needed for Brazilian Portuguese). Added pt-br OrdinalToWords localisation - [#194](https://github.com/Humanizr/Humanizer/pull/194): Added pt-BR NumberToWords localisation - [#147](https://github.com/Humanizr/Humanizer/pull/147): Added Russian translation for ToWords - [#190](https://github.com/Humanizr/Humanizer/pull/190): Added French translation for ToWords and ToOrdinalWords - [#179](https://github.com/Humanizr/Humanizer/pull/179): Added Hungarian localisation - [#181](https://github.com/Humanizr/Humanizer/pull/181): Added Bulgarian localization, date and timespan tests - [#141](https://github.com/Humanizr/Humanizer/pull/141): Added Indonesian localization - [#148](https://github.com/Humanizr/Humanizer/pull/148): Added Hebrew localization for date and timespan [Commits](https://github.com/Humanizr/Humanizer/compare/v1.20.15...v1.21.1) ### v1.20.15 - 2014-04-12 - [#186](https://github.com/Humanizr/Humanizer/pull/186): Refactored `ToOrdinalWords` to use existing `NumberToWordsExtension` to prepare for Ordinal localization - [#193](https://github.com/Humanizr/Humanizer/pull/193): Fixed the NullException error on DateTime.Humanize [Commits](https://github.com/Humanizr/Humanizer/compare/v1.20.2...v1.20.15) ### v1.20.2 - 2014-04-11 - [#171](https://github.com/Humanizr/Humanizer/pull/171): T4-Template fix: Using EnglishNumberToWordsConverter instead of 'ToWords()' while dogfooding the template with the library. - [#165](https://github.com/Humanizr/Humanizer/pull/165): Added precision based `DateTime.Humanize` strategy - [#155](https://github.com/Humanizr/Humanizer/pull/155): French and Belgian French localisation - [#151](https://github.com/Humanizr/Humanizer/pull/151): Added Spanish ToWords Translations - [#172](https://github.com/Humanizr/Humanizer/pull/172): Added Polish translation for ToWords - [#184](https://github.com/Humanizr/Humanizer/pull/184): Fixed spelling error with forth/fourth in EnglishNumberToWordsConverter [Commits](https://github.com/Humanizr/Humanizer/compare/v1.19.1...v1.20.2) ### v1.19.1 - 2014-04-10 - [#149](https://github.com/Humanizr/Humanizer/pull/149): Improved & refactored number to words localisation - [#143](https://github.com/Humanizr/Humanizer/pull/143): Added Russian translation for future DateTime, TimeSpan and Now - [#144](https://github.com/Humanizr/Humanizer/pull/144): Added Danish localization (strings, tests) - [#146](https://github.com/Humanizr/Humanizer/pull/146): Added Spanish translation for future DateTime, TimeSpan and Now [Commits](https://github.com/Humanizr/Humanizer/compare/v1.18.1...v1.19.1) ### v1.18.1 - 2014-04-09 - [#137](https://github.com/Humanizr/Humanizer/pull/137): Fixed grammar error in `nb-NO` resource file & added missing Norwegian resource strings (mainly `DateHumanize_*FromNow`) - [#135](https://github.com/Humanizr/Humanizer/pull/135): Added Swedish localization (strings, tests) - [#140](https://github.com/Humanizr/Humanizer/pull/140): Added Polish localization (strings, formatter, tests) [Commits](https://github.com/Humanizr/Humanizer/compare/v1.17.1...v1.18.1) ### v1.17.1 - 2014-04-06 - [#124](https://github.com/Humanizr/Humanizer/pull/124): Added Slovak localization (strings, formatter, tests) - [#130](https://github.com/Humanizr/Humanizer/pull/130): Added Czech localization (strings, formatter, tests) - [#131](https://github.com/Humanizr/Humanizer/pull/131): Clean date humanize tests and renamed `TimeUnitTense` to `Tense` [Commits](https://github.com/Humanizr/Humanizer/compare/v1.16.4...v1.17.1) ### v1.16.4 - 2014-04-04 - [#129](https://github.com/Humanizr/Humanizer/pull/129): Removed all but PCL references - [#121](https://github.com/Humanizr/Humanizer/pull/121): Added Farsi translation for DateTime, TimeSpan and NumberToWords - [#120](https://github.com/Humanizr/Humanizer/pull/120): Added German translation for DateTime and TimeSpan - [#117](https://github.com/Humanizr/Humanizer/pull/117): Added `FormatWith` string extension [Commits](https://github.com/Humanizr/Humanizer/compare/v1.15.1...v1.16.4) ### v1.15.1 - 2014-03-28 - [#113](https://github.com/Humanizr/Humanizer/pull/113): Added `Truncate` feature - [#109](https://github.com/Humanizr/Humanizer/pull/109): Made Dutch (NL) localization a neutral culture, not just for Belgium [Commits](https://github.com/Humanizr/Humanizer/compare/v1.14.1...v1.15.1) ### v1.14.1 - 2014-03-26 - [#108](https://github.com/Humanizr/Humanizer/pull/108): Added support for custom description attributes - [#106](https://github.com/Humanizr/Humanizer/pull/106): - Refactored IFormatter and DefaultFormatter - Refactored `DateTime.Humanize` and `TimeSpan.Humanize` - Changed `ResourceKeys` to use a dynamic key generation - Fixed the intermittent failing tests on `DateTime.Humanize` [Commits](https://github.com/Humanizr/Humanizer/compare/v1.13.2...v1.14.1) ### v1.13.2 - 2014-03-17 - [#99](https://github.com/Humanizr/Humanizer/pull/99): Added `ByteSize` feature [Commits](https://github.com/Humanizr/Humanizer/compare/v1.12.4...v1.13.2) ### v1.12.4 - 2014-02-25 - [#95](https://github.com/Humanizr/Humanizer/pull/95): Added NoMatch optional parameter to DehumanizeTo & renamed `CannotMapToTargetException` to `NoMatchFoundException` #### Breaking Changes If you were catching `CannotMapToTargetException` on a `DehumanizeTo` call, that's been renamed to `NoMatchFoundException` to make it more generic. [Commits](https://github.com/Humanizr/Humanizer/compare/v1.11.3...v1.12.4) ### v1.11.3 - 2014-02-18 - [#93](https://github.com/Humanizr/Humanizer/pull/93): added non-generic DehumanizeTo for Enums unknown at compile time [Commits](https://github.com/Humanizr/Humanizer/compare/v1.10.1...v1.11.3) ### v1.10.1 - 2014-02-15 - [#89](https://github.com/Humanizr/Humanizer/pull/89): added `ToRoman` and `FromRoman` extensions - [#82](https://github.com/Humanizr/Humanizer/pull/82): fixed Greek locale code [Commits](https://github.com/Humanizr/Humanizer/compare/v1.9.1...v1.10.1) ### v1.9.1 - 2014-02-12 - [#78](https://github.com/Humanizr/Humanizer/pull/78): added support for billions to `ToWords` [Commits](https://github.com/Humanizr/Humanizer/compare/v1.8.1...v1.9.1) ### v1.8.16 - 2014-02-12 - [#81](https://github.com/Humanizr/Humanizer/pull/81): fixed issue with localised methods returning null in Windows Store apps - Created [Humanizr.net](http://humanizr.net) website as GitHub pages [Commits](https://github.com/Humanizr/Humanizer/compare/v1.8.1...v1.8.16) ### v1.8.1 - 2014-02-04 - [#73](https://github.com/Humanizr/Humanizer/pull/73): added `ToWords` implementation for Arabic [Commits](https://github.com/Humanizr/Humanizer/compare/v1.7.1...v1.8.1) ### v1.7.1 - 2014-02-31 - [#68](https://github.com/Humanizr/Humanizer/pull/68): `DateTime.Humanize()` now supports future dates [Commits](https://github.com/Humanizr/Humanizer/compare/v1.6.1...v1.7.1) ### v1.6.1 - 2014-01-27 - [#69](https://github.com/Humanizr/Humanizer/pull/69): changed the return type of `DehumanizeTo` to `TTargetEnum` #### Potential breaking change The return type of `DehumanizeTo` was changed from `Enum` to `TTargetEnum` to make the API a lot easier to work with. That also potentially means that your calls to the old method may be broken. Depending on how you were using the method you might have to either drop the now redundant cast to `TTargetEnum` in your code, or fix it based on your requirements. [Commits](https://github.com/Humanizr/Humanizer/compare/v1.5.1...v1.6.1) ### v1.5.1 - 2014-01-23 - [#65](https://github.com/Humanizr/Humanizer/pull/65): added precision to `TimeSpan.Humanize` [Commits](https://github.com/Humanizr/Humanizer/compare/v1.4.1...v1.5.1) ### v1.4.1 - 2014-01-20 - [#62](https://github.com/Humanizr/Humanizer/pull/62): added `ShowQuantityAs` parameter to `ToQuantity` [Commits](https://github.com/Humanizr/Humanizer/compare/v1.3.1...v1.4.1) ### v1.3.1 - 2014-14-01 - [#51](https://github.com/Humanizr/Humanizer/pull/51): added Spanish translation for `DateTime.Humanize` - [#52](https://github.com/Humanizr/Humanizer/pull/52): added Arabic translation for `DateTime.Humanize` - [#53](https://github.com/Humanizr/Humanizer/pull/53): added `Hyphenate` as an overload for `Dasherize` - [#54](https://github.com/Humanizr/Humanizer/pull/54): added Portuguese translation for `DateTime.Humanize` - [#55](https://github.com/Humanizr/Humanizer/pull/55): added Arabic translation for `TimeSpan.Humanize` [Commits](https://github.com/Humanizr/Humanizer/compare/v1.1.0...v1.3.1) ### v1.1.0 - 2014-01-01 - [#37](https://github.com/Humanizr/Humanizer/pull/37): added `ToQuantity` method - [#43](https://github.com/Humanizr/Humanizer/pull/43): - added `Plurality` enum - can call `Singularize` on singular and `Pluralize` on plural words - `ToQuantity` can be called on words with unknown plurality [Commits](https://github.com/Humanizr/Humanizer/compare/v1.0.29...v1.1.0) ### v1.0.29 - 2013-12-25 - [#26](https://github.com/Humanizr/Humanizer/pull/26): added Norwegian (nb-NO) localization for `DateTime.Humanize()` - [#33](https://github.com/Humanizr/Humanizer/pull/33): - changed to Portable Class Library with support for .Net 4+, SilverLight 5, Windows Phone 8 and Win Store applications - symbols nuget package is published so you can step through Humanizer code while debugging your code [Commits](https://github.com/Humanizr/Humanizer/compare/v1.0.0...v1.0.29) ### v1.0.0 - 2013-11-10 No release history before this point: check out http://www.mehdi-khalili.com/humanizer-v1 for the feature-set at V1 Commits: ... ================================================ FILE: src/Benchmarks/.editorconfig ================================================ [*.cs] dotnet_diagnostic.CA1050.severity = none # CA1050: Declare types in namespaces # CA1861: Avoid constant arrays as arguments dotnet_diagnostic.CA1861.severity = silent # IDE1006: Naming Styles dotnet_diagnostic.IDE1006.severity = none # CA1822: Mark members as static dotnet_diagnostic.CA1822.severity = none ================================================ FILE: src/Benchmarks/Benchmarks.csproj ================================================  Exe net10.0;net8.0 false 3.0.0-rc.6 false ================================================ FILE: src/Benchmarks/EnglishArticleBenchmarks.cs ================================================ [MemoryDiagnoser(false)] public class EnglishArticleBenchmarks { [Benchmark] public string[] AppendArticlePrefix() => EnglishArticle.AppendArticlePrefix(["Ant", "The Theater", "The apple", "Fox", "Bear"]); [Benchmark] public string[] PrependArticleSuffix() => EnglishArticle.PrependArticleSuffix(["Ant", "apple The", "Bear", "Fox", "Theater The"]); } ================================================ FILE: src/Benchmarks/EnglishToWordsBenchmark.cs ================================================ [MemoryDiagnoser] public class EnglishToWordsBenchmark { readonly EnglishNumberToWordsConverter converter = new(); [Benchmark] public string ToWords() => converter.Convert(int.MaxValue); [Benchmark] public string ToWordsOrdinal() => converter.ConvertToOrdinal(int.MaxValue); } ================================================ FILE: src/Benchmarks/EnumBenchmarks.cs ================================================ [MemoryDiagnoser(false)] public class EnumBenchmarks { public enum EnumUnderTest { [Description("The description")] MemberWithDescriptionAttribute, MemberWithoutDescriptionAttribute, [Display(Description = "Display value")] MemberWithDisplayAttribute, } [Benchmark(Description = "Enum.Humanize")] public string Humanize() => EnumUnderTest.MemberWithDisplayAttribute.Humanize(); [Benchmark(Description = "Enum.DehumanizeTo")] public EnumUnderTest Dehumanize() => "Display value".DehumanizeTo(); } ================================================ FILE: src/Benchmarks/GlobalUsings.cs ================================================ global using System.ComponentModel; global using System.ComponentModel.DataAnnotations; global using BenchmarkDotNet.Attributes; global using BenchmarkDotNet.Running; global using Humanizer; ================================================ FILE: src/Benchmarks/InflectorBenchmarks.cs ================================================ using BenchmarkDotNet.Attributes; using Humanizer; namespace Benchmarks; /// /// Benchmarks for InflectorExtensions - demonstrates source-generated regex performance /// [MemoryDiagnoser] public class InflectorBenchmarks { [Benchmark(Description = "Pascalize")] public string Pascalize() => "some_title for_an article".Pascalize(); [Benchmark(Description = "Camelize")] public string Camelize() => "some_title for_an article".Camelize(); [Benchmark(Description = "Underscore")] public string Underscore() => "SomeClassName".Underscore(); [Benchmark(Description = "Dasherize")] public string Dasherize() => "some_text_string".Dasherize(); [Benchmark(Description = "Kebaberize")] public string Kebaberize() => "PascalCaseString".Kebaberize(); [Benchmark(Description = "Titleize")] public string Titleize() => "some_title for_an article".Titleize(); [Benchmark(Description = "Pluralize")] public string Pluralize() => "person".Pluralize(); [Benchmark(Description = "Singularize")] public string Singularize() => "people".Singularize(); } ================================================ FILE: src/Benchmarks/ItalianNumberBenchmarks.cs ================================================ using System.Globalization; [MemoryDiagnoser(false)] public class ItalianNumberBenchmarks { static readonly CultureInfo culture = new("it"); [Benchmark(Description = "ItalianNumber.ToOrdinalWords")] public void ToOrdinalWords() { foreach (var number in numbers) { number.ToOrdinalWords(culture); number.ToOrdinalWords(GrammaticalGender.Feminine, culture); } } static readonly int[] numbers = [ 0, 1, 2, 9, 10, 11, 15, 18, 20, 21, 22, 28, 30, 44, 55, 60, 63, 66, 77, 88, 99, 100, 101, 102, 105, 109, 110, 119, 120, 121, 200, 201, 240, 300, 900, 1000, 1001, 1002, 1003, 1009, 1010, 1021, 2000, 2001, 3000, 10000, 10001, 10121, 100000, 100001, 1000000, 1000001, 1000002, 2000000, 10000000, 100000000, 1000000000, 2000000000, ]; } ================================================ FILE: src/Benchmarks/MetricNumeralBenchmarks.cs ================================================ using BenchmarkDotNet.Attributes; using Humanizer; namespace Benchmarks; /// /// Benchmarks for MetricNumeralExtensions - demonstrates FrozenDictionary performance /// [MemoryDiagnoser] public class MetricNumeralBenchmarks { [Benchmark(Description = "ToMetric small")] public string ToMetricSmall() => 123.ToMetric(); [Benchmark(Description = "ToMetric kilo")] public string ToMetricKilo() => 1000.ToMetric(); [Benchmark(Description = "ToMetric mega")] public string ToMetricMega() => 1000000.ToMetric(); [Benchmark(Description = "ToMetric milli")] public string ToMetricMilli() => 0.001.ToMetric(); [Benchmark(Description = "FromMetric kilo")] public double FromMetricKilo() => "1k".FromMetric(); [Benchmark(Description = "FromMetric mega")] public double FromMetricMega() => "5M".FromMetric(); [Benchmark(Description = "FromMetric micro")] public double FromMetricMicro() => "100μ".FromMetric(); } ================================================ FILE: src/Benchmarks/NumberToWordsBenchmarks.cs ================================================ using BenchmarkDotNet.Attributes; using Humanizer; namespace Benchmarks; /// /// Benchmarks for number-to-words conversions - demonstrates FrozenDictionary performance /// [MemoryDiagnoser] public class NumberToWordsBenchmarks { [Benchmark(Description = "English ToWords small")] public string EnglishToWordsSmall() => 42.ToWords(); [Benchmark(Description = "English ToWords large")] public string EnglishToWordsLarge() => int.MaxValue.ToWords(); [Benchmark(Description = "English ToOrdinalWords")] public string EnglishToOrdinalWords() => 42.ToOrdinalWords(); [Benchmark(Description = "Turkish ToWords")] public string TurkishToWords() => 42.ToWords(new System.Globalization.CultureInfo("tr")); [Benchmark(Description = "Greek ToWords")] public string GreekToWords() => 42.ToWords(new System.Globalization.CultureInfo("el")); [Benchmark(Description = "Korean ToWords")] public string KoreanToWords() => 42.ToWords(new System.Globalization.CultureInfo("ko")); [Benchmark(Description = "Finnish ToWords")] public string FinnishToWords() => 42.ToWords(new System.Globalization.CultureInfo("fi")); } ================================================ FILE: src/Benchmarks/OrdinalBenchmarks.cs ================================================ using BenchmarkDotNet.Attributes; using Humanizer; using System.Globalization; namespace Benchmarks; /// /// Benchmarks for ordinal operations - demonstrates SearchValues and FrozenDictionary performance /// [MemoryDiagnoser] public class OrdinalBenchmarks { [Benchmark(Description = "English Ordinalize")] public string EnglishOrdinalize() => 42.Ordinalize(); [Benchmark(Description = "Dutch Ordinalize")] public string DutchOrdinalize() => 42.Ordinalize(new CultureInfo("nl")); [Benchmark(Description = "Turkish Ordinalize")] public string TurkishOrdinalize() => 42.Ordinalize(new CultureInfo("tr")); [Benchmark(Description = "Greek Ordinalize")] public string GreekOrdinalize() => 42.Ordinalize(new CultureInfo("el")); [Benchmark(Description = "Finnish Ordinalize")] public string FinnishOrdinalize() => 42.Ordinalize(new CultureInfo("fi")); } ================================================ FILE: src/Benchmarks/Program.cs ================================================ using BenchmarkDotNet.Configs; using BenchmarkDotNet.Diagnosers; using BenchmarkDotNet.Environments; using BenchmarkDotNet.Exporters; using BenchmarkDotNet.Exporters.Json; using BenchmarkDotNet.Jobs; var config = ManualConfig.Create(DefaultConfig.Instance) .AddJob(Job.Default .WithRuntime(CoreRuntime.Core10_0)) .AddJob(Job.Default .AsBaseline() .WithRuntime(CoreRuntime.Core80)) .AddExporter(JsonExporter.Full) .AddExporter(MarkdownExporter.GitHub) .AddDiagnoser(MemoryDiagnoser.Default); BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args, config); ================================================ FILE: src/Benchmarks/README.md ================================================ # Humanizer Benchmarks This project contains comprehensive benchmarks for the Humanizer library, demonstrating performance improvements from recent optimizations. ## Running the Benchmarks ### Locally Run all benchmarks: ```bash cd src/Benchmarks dotnet run -c Release -- --filter * ``` Run specific benchmarks: ```bash dotnet run -c Release -- --filter *StringHumanize* ``` ### Baseline Comparison (GitHub Actions) A manual GitHub Actions workflow is available to compare performance between a baseline NuGet package version and the current source code: 1. Go to **Actions** → **Benchmark Baseline vs Current** 2. Click **Run workflow** 3. Enter the baseline version (default: 2.14.1) 4. The workflow will: - Run benchmarks against the baseline package in parallel - Run benchmarks against the current source code in parallel - Compare results using ResultsComparer - Publish detailed reports as artifacts - Display results and comparison in the job summary **How it works:** - **Baseline run**: Builds benchmarks with `UseBaselinePackage=true` to reference the NuGet package - **Current run**: Builds benchmarks with `UseBaselinePackage=false` to reference the local source code - **Comparison**: Downloads both JSON results and uses `dotnet/performance` ResultsComparer tool to generate a diff table **Artifacts available after each run:** - `humanizer-bdn-baseline-json` - Full JSON results from baseline - `humanizer-bdn-current-json` - Full JSON results from current code - `humanizer-bdn-baseline-all` - Complete BenchmarkDotNet artifacts (baseline) - `humanizer-bdn-current-all` - Complete BenchmarkDotNet artifacts (current) - `humanizer-bdn-comparison` - ResultsComparer diff report ## Benchmark Suites ### 1. StringHumanizeBenchmarks **Optimizations tested**: Source-generated regex (NET7+) Tests the performance of string humanization operations which use regex patterns to split and transform strings: - PascalCase → "Pascal case" - underscore_case → "Underscore case" - Mixed formats with special handling **Expected improvements**: 5-10x faster on .NET 7+ with zero allocations ### 2. InflectorBenchmarks **Optimizations tested**: Source-generated regex (NET7+) Tests various string transformation methods that rely on regex patterns: - `Pascalize()` - converts to PascalCase - `Camelize()` - converts to camelCase - `Underscore()` - converts to underscore_case - `Kebaberize()` - converts to kebab-case - `Titleize()` - converts to Title Case - `Pluralize()` / `Singularize()` - word pluralization **Expected improvements**: 5-10x faster on .NET 7+ with zero allocations ### 3. RomanNumeralBenchmarks **Optimizations tested**: Source-generated regex (NET7+) Tests conversion between integers and Roman numerals: - `ToRoman()` - converts integers to Roman numerals - `FromRoman()` - converts Roman numerals to integers (with regex validation) **Expected improvements**: 5-10x faster validation on .NET 7+ ### 4. NumberToWordsBenchmarks **Optimizations tested**: FrozenDictionary (all frameworks) Tests number-to-words conversion across multiple locales: - English, Turkish, Greek, Korean, Finnish locales - Small and large numbers - Ordinal words **Expected improvements**: 2-3x faster lookups with reduced memory usage ### 5. WordsToNumberBenchmarks **Optimizations tested**: FrozenDictionary + source-generated regex Tests converting word representations to numbers: - Simple words ("five") - Compound words ("forty-two") - Complex numbers ("one thousand two hundred thirty-four") **Expected improvements**: Combined benefits of both optimizations ### 6. MetricNumeralBenchmarks **Optimizations tested**: FrozenDictionary (all frameworks) Tests metric prefix conversions: - `ToMetric()` - converts numbers to metric notation (1000 → "1k") - `FromMetric()` - parses metric notation back to numbers **Expected improvements**: 2-3x faster lookups ### 7. OrdinalBenchmarks **Optimizations tested**: SearchValues (NET8+), FrozenDictionary Tests ordinal number generation across locales: - Dutch (uses SearchValues for character set matching) - Turkish, Greek, Finnish (use FrozenDictionary) **Expected improvements**: - Dutch: 2-5x faster on .NET 8+ (hardware-accelerated) - Others: 2-3x faster lookups ### 8. VocabularyBenchmarks **Optimizations tested**: Source-generated regex (NET7+) Tests pluralization/singularization with vocabulary rules: - Batch operations on multiple words - Common and irregular words **Expected improvements**: 5-10x faster on .NET 7+ ### 9. EnumBenchmarks (existing) Tests enum humanization and dehumanization ### 10. EnglishArticleBenchmarks (existing) Tests English article sorting operations ### 11. EnglishToWordsBenchmark (existing) Tests English number-to-words conversion ### 12. TransformersBenchmarks (existing) Tests string transformation operations ## Performance Optimization Summary | Optimization | Target Framework | Typical Improvement | Benchmarks | |--------------|------------------|---------------------|------------| | Source-Generated Regex | .NET 7+ | 5-10x faster, zero allocations | StringHumanize, Inflector, RomanNumeral, Vocabulary, WordsToNumber | | FrozenDictionary | All (via polyfill) | 2-3x faster lookups | NumberToWords, MetricNumeral, Ordinal, WordsToNumber | | SearchValues | .NET 8+ | 2-5x faster (hardware-accelerated) | Ordinal (Dutch) | ## Baseline Comparison To compare against the pre-optimization performance, you can: 1. Check out the commit before optimizations: `git checkout 97432f62` 2. Run benchmarks and save results 3. Return to current branch: `git checkout -` 4. Run benchmarks again and compare Or use BenchmarkDotNet's baseline feature: ```csharp [Benchmark(Baseline = true)] public string OldImplementation() { ... } [Benchmark] public string NewImplementation() { ... } ``` ## Memory Diagnostics All benchmarks include `[MemoryDiagnoser]` to track allocations. The optimizations significantly reduce or eliminate allocations in hot paths: - Regex operations: Zero allocations on .NET 7+ (source-generated) - Dictionary lookups: Reduced memory footprint (FrozenDictionary) - Character searches: Zero allocations on .NET 8+ (SearchValues) ## Notes - Benchmarks run on .NET 10.0 to demonstrate maximum performance - Performance improvements are most significant on modern frameworks - Older frameworks (.NET 4.8, netstandard2.0) still benefit from FrozenDictionary via polyfills - Results may vary based on hardware and workload characteristics ================================================ FILE: src/Benchmarks/RomanNumeralBenchmarks.cs ================================================ using BenchmarkDotNet.Attributes; using Humanizer; namespace Benchmarks; /// /// Benchmarks for RomanNumeralExtensions - demonstrates source-generated regex performance /// [MemoryDiagnoser] public class RomanNumeralBenchmarks { [Benchmark(Description = "ToRoman small")] public string ToRomanSmall() => 42.ToRoman(); [Benchmark(Description = "ToRoman medium")] public string ToRomanMedium() => 1987.ToRoman(); [Benchmark(Description = "ToRoman large")] public string ToRomanLarge() => 3999.ToRoman(); [Benchmark(Description = "FromRoman small")] public int FromRomanSmall() => "XLII".FromRoman(); [Benchmark(Description = "FromRoman medium")] public int FromRomanMedium() => "MCMLXXXVII".FromRoman(); [Benchmark(Description = "FromRoman large")] public int FromRomanLarge() => "MMMCMXCIX".FromRoman(); } ================================================ FILE: src/Benchmarks/StringHumanizeBenchmarks.cs ================================================ using BenchmarkDotNet.Attributes; using Humanizer; namespace Benchmarks; /// /// Benchmarks for StringHumanizeExtensions - demonstrates source-generated regex performance /// [MemoryDiagnoser] public class StringHumanizeBenchmarks { [Benchmark(Description = "Humanize PascalCase")] public string HumanizePascalCase() => "PascalCaseInputStringToBeHumanized".Humanize(); [Benchmark(Description = "Humanize with underscore")] public string HumanizeUnderscore() => "Underscored_input_string_is_turned_INTO_sentence".Humanize(); [Benchmark(Description = "Humanize with dashes")] public string HumanizeDashes() => "Dashed-input-string-is-turned-INTO-sentence".Humanize(); [Benchmark(Description = "Humanize with casing")] public string HumanizeWithCasing() => "PascalCaseInputString".Humanize(LetterCasing.AllCaps); [Benchmark(Description = "Humanize mixed format")] public string HumanizeMixed() => "HTML_to_JSON_Converter".Humanize(); } ================================================ FILE: src/Benchmarks/TimeOnlyToClockNotationConverterBenchmarks.cs ================================================ [MemoryDiagnoser(false)] public class TimeOnlyToClockNotationConverterBenchmarks { static readonly TimeOnly time = new(13, 6, 2, 88, 987); static readonly EsTimeOnlyToClockNotationConverter esConverter = new(); [Benchmark] public void EsClockNotationConverter() { esConverter.Convert(time, ClockNotationRounding.None); esConverter.Convert(time, ClockNotationRounding.NearestFiveMinutes); } static readonly BrazilianPortugueseTimeOnlyToClockNotationConverter brazilianConverter = new(); [Benchmark] public void BrazilianPortugueseClockNotationConverter() { brazilianConverter.Convert(time, ClockNotationRounding.None); brazilianConverter.Convert(time, ClockNotationRounding.NearestFiveMinutes); } static readonly FrTimeOnlyToClockNotationConverter frConverter = new(); [Benchmark] public void FrClockNotationConverter() { frConverter.Convert(time, ClockNotationRounding.None); frConverter.Convert(time, ClockNotationRounding.NearestFiveMinutes); } static readonly LbTimeOnlyToClockNotationConverter lbConverter = new(); [Benchmark] public void LbClockNotationConverter() { lbConverter.Convert(time, ClockNotationRounding.None); lbConverter.Convert(time, ClockNotationRounding.NearestFiveMinutes); } static readonly DefaultTimeOnlyToClockNotationConverter defaultConverter = new(); [Benchmark] public void DefaultClockNotationConverter() { defaultConverter.Convert(time, ClockNotationRounding.None); defaultConverter.Convert(time, ClockNotationRounding.NearestFiveMinutes); } } ================================================ FILE: src/Benchmarks/ToQuantityBenchmarks.cs ================================================ using BenchmarkDotNet.Attributes; using Humanizer; namespace Benchmarks; /// /// Benchmarks for ToQuantity - demonstrates string.Create performance optimization /// [MemoryDiagnoser] public class ToQuantityBenchmarks { [Benchmark(Description = "ToQuantity Numeric - Plural")] public string ToQuantityNumericPlural() => "request".ToQuantity(5); [Benchmark(Description = "ToQuantity Numeric - Singular")] public string ToQuantityNumericSingular() => "request".ToQuantity(1); [Benchmark(Description = "ToQuantity Words")] public string ToQuantityWords() => "process".ToQuantity(123, ShowQuantityAs.Words); [Benchmark(Description = "ToQuantity Double")] public string ToQuantityDouble() => "item".ToQuantity(2.5); [Benchmark(Description = "ToQuantity Formatted")] public string ToQuantityFormatted() => "request".ToQuantity(10000, "N0"); } ================================================ FILE: src/Benchmarks/TransformersBenchmarks.cs ================================================ [MemoryDiagnoser(false)] public class TransformersBenchmarks { // hard-coded seed ensures the same random strings are generated each time. const int RAND_SEED = 17432; static readonly char[] Alphabet = [.. Enumerable .Repeat((int)' ', 12) .Concat(Enumerable.Range('a', 'z' - 'a')) .Concat(Enumerable.Range('A', 'Z' - 'A')) .Concat(Enumerable.Range('0', '9' - '0')) .Concat([ '.', ',', '(', ')', '!', '$' ]) .Select(x => (char)x)]; readonly Random random = new(RAND_SEED); string input = null!; [Params(10, 100, 1000)] public int StringLen; [GlobalSetup] public void GlobalSetup() { var chars = new char[StringLen]; for (var i = 0; i < StringLen; i++) { chars[i] = Alphabet[random.Next(0, Alphabet.Length)]; } input = new(chars); } [Benchmark] public string AllTransforms() => input.Transform(To.LowerCase, To.UpperCase, To.SentenceCase, To.TitleCase); [Benchmark] public string LowerCase() => input.Transform(To.LowerCase); [Benchmark] public string UpperCase() => input.Transform(To.UpperCase); [Benchmark] public string SentenceCase() => input.Transform(To.SentenceCase); [Benchmark] public string TitleCase() => input.Transform(To.TitleCase); } ================================================ FILE: src/Benchmarks/VocabularyBenchmarks.cs ================================================ using BenchmarkDotNet.Attributes; using Humanizer; namespace Benchmarks; /// /// Benchmarks for Vocabulary operations - demonstrates source-generated regex performance /// [MemoryDiagnoser] public class VocabularyBenchmarks { readonly string[] testWords = [ "person", "man", "woman", "child", "tooth", "foot", "mouse", "goose", "sheep", "deer", "fish", "species", "series", "movie", "index", "matrix", "vertex", "ox" ]; [Benchmark(Description = "Pluralize various words")] public void PluralizeBatch() { foreach (var word in testWords) { _ = word.Pluralize(); } } [Benchmark(Description = "Singularize various words")] public void SingularizeBatch() { foreach (var word in testWords) { _ = word.Singularize(); } } [Benchmark(Description = "Pluralize single common")] public string PluralizeCommon() => "person".Pluralize(); [Benchmark(Description = "Pluralize single irregular")] public string PluralizeIrregular() => "mouse".Pluralize(); [Benchmark(Description = "Singularize single common")] public string SingularizeCommon() => "people".Singularize(); [Benchmark(Description = "Singularize single irregular")] public string SingularizeIrregular() => "mice".Singularize(); } ================================================ FILE: src/Benchmarks/WordsToNumberBenchmarks.cs ================================================ using BenchmarkDotNet.Attributes; using Humanizer; using System.Globalization; namespace Benchmarks; /// /// Benchmarks for words-to-number conversions - demonstrates FrozenDictionary and source-generated regex /// [MemoryDiagnoser] public class WordsToNumberBenchmarks { static readonly CultureInfo EnglishCulture = new("en-US"); [Benchmark(Description = "Simple word")] public int SimpleWord() => "five".ToNumber(EnglishCulture); [Benchmark(Description = "Compound word")] public int CompoundWord() => "forty-two".ToNumber(EnglishCulture); [Benchmark(Description = "Complex number")] public int ComplexNumber() => "one thousand two hundred thirty-four".ToNumber(EnglishCulture); [Benchmark(Description = "Ordinal word")] public int OrdinalWord() => "fifth".ToNumber(EnglishCulture); [Benchmark(Description = "Large number")] public int LargeNumber() => "nine hundred ninety-nine million".ToNumber(EnglishCulture); } ================================================ FILE: src/Humanizer/ArticlePrefixSort.cs ================================================ namespace Humanizer; /// /// Contains methods for removing, appending and prepending article prefixes for sorting strings ignoring the article. /// public static partial class EnglishArticle { private const string ArticlePattern = @"^((The)|(the)|(a)|(A)|(An)|(an))\s\w+"; #if NET7_0_OR_GREATER [GeneratedRegex(ArticlePattern)] private static partial Regex ArticleRegexGenerated(); private static Regex ArticleRegex() => ArticleRegexGenerated(); #else private static readonly Regex ArticleRegexField = new(ArticlePattern, RegexOptions.Compiled); private static Regex ArticleRegex() => ArticleRegexField; #endif /// /// Removes the prefixed article and appends it to the same string. /// /// The input array of strings /// Sorted string array public static string[] AppendArticlePrefix(string[] items) { if (items.Length == 0) { throw new ArgumentOutOfRangeException(nameof(items)); } var transformed = new string[items.Length]; for (var i = 0; i < items.Length; i++) { var item = items[i] .AsSpan(); if (ArticleRegex().IsMatch(item)) { var indexOf = item.IndexOf(' '); var removed = item[indexOf..] .TrimStart(); var article = item[..indexOf] .TrimEnd(); transformed[i] = $"{removed} {article}"; } else { transformed[i] = item .Trim() .ToString(); } } Array.Sort(transformed); return transformed; } /// /// Removes the previously appended article and prepends it to the same string. /// /// Sorted string array /// String array public static string[] PrependArticleSuffix(string[] appended) { var inserted = new string[appended.Length]; for (var i = 0; i < appended.Length; i++) { var item = appended[i]; var append = item.AsSpan(); // Check for " the" (4 chars total including space) if (append.Length > 4 && append[^4] == ' ') { var lastThree = append[^3..]; if (lastThree.Equals("the", StringComparison.OrdinalIgnoreCase)) { inserted[i] = RearrangeArticle(item, suffixLength: 3, totalLength: 4); continue; } } // Check for " an" (3 chars total including space) if (append.Length > 3 && append[^3] == ' ') { var lastTwo = append[^2..]; if (lastTwo.Equals("an", StringComparison.OrdinalIgnoreCase)) { inserted[i] = RearrangeArticle(item, suffixLength: 2, totalLength: 3); continue; } } // Check for " a" (2 chars total including space) if (append.Length > 2 && append[^2] == ' ') { var lastOne = append[^1..]; if (lastOne.Equals("a", StringComparison.OrdinalIgnoreCase)) { inserted[i] = RearrangeArticle(item, suffixLength: 1, totalLength: 2); continue; } } inserted[i] = item; } return inserted; } static string RearrangeArticle(string item, int suffixLength, int totalLength) { #if NET6_0_OR_GREATER return string.Create(item.Length, (item, suffixLength, totalLength), (span, state) => { var source = state.item.AsSpan(); var suffix = source[^state.suffixLength..]; var prefix = source[..^state.totalLength]; suffix.CopyTo(span); span[suffix.Length] = ' '; prefix.CopyTo(span[(suffix.Length + 1)..]); }); #else var source = item.AsSpan(); var suffix = source[^suffixLength..]; var prefix = source[..^totalLength]; return $"{suffix} {prefix}"; #endif } } ================================================ FILE: src/Humanizer/Bytes/ByteRate.cs ================================================ namespace Humanizer; /// /// Class to hold a ByteSize and a measurement interval, for the purpose of calculating the rate of transfer /// /// /// Create a ByteRate with given quantity of bytes across an interval /// public class ByteRate(ByteSize size, TimeSpan interval) { /// /// Quantity of bytes /// public ByteSize Size { get; } = size; /// /// Interval that bytes were transferred in /// public TimeSpan Interval { get; } = interval; /// /// Calculate rate for the quantity of bytes and interval defined by this instance /// /// Unit of time to calculate rate for (defaults is per second) public string Humanize(TimeUnit timeUnit = TimeUnit.Second) => Humanize(null, timeUnit); /// /// Calculate rate for the quantity of bytes and interval defined by this instance /// /// Unit of time to calculate rate for (defaults is per second) /// The string format to use for the number of bytes /// Culture to use. If null, current thread's UI culture is used. public string Humanize(string? format, TimeUnit timeUnit = TimeUnit.Second, CultureInfo? culture = null) { var displayInterval = timeUnit switch { TimeUnit.Second => TimeSpan.FromSeconds(1), TimeUnit.Minute => TimeSpan.FromMinutes(1), TimeUnit.Hour => TimeSpan.FromHours(1), _ => throw new NotSupportedException("timeUnit must be Second, Minute, or Hour"), }; return new ByteSize(Size.Bytes / Interval.TotalSeconds * displayInterval.TotalSeconds) .Humanize(format, culture) + '/' + timeUnit.ToSymbol(culture); } } ================================================ FILE: src/Humanizer/Bytes/ByteSize.cs ================================================ //The MIT License (MIT) //Copyright (c) 2013-2014 Omar Khudeira (http://omar.io) //Permission is hereby granted, free of charge, to any person obtaining a copy //of this software and associated documentation files (the "Software"), to deal //in the Software without restriction, including without limitation the rights //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell //copies of the Software, and to permit persons to whom the Software is //furnished to do so, subject to the following conditions: //The above copyright notice and this permission notice shall be included in //all copies or substantial portions of the Software. //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN //THE SOFTWARE. using System.Diagnostics; using System.Runtime.CompilerServices; using static System.Globalization.NumberStyles; namespace Humanizer; #pragma warning disable 1591 public struct ByteSize(double byteSize) : IComparable, IEquatable, IComparable, IFormattable { static readonly ConditionalWeakTable> NumberFormatSpecialCharsCache = new(); public static readonly ByteSize MinValue = FromBits(long.MinValue); public static readonly ByteSize MaxValue = FromBits(long.MaxValue); public const long BitsInByte = 8; public const long BytesInKilobyte = 1024; public const long BytesInMegabyte = 1048576; public const long BytesInGigabyte = 1073741824; public const long BytesInTerabyte = 1099511627776; public const string BitSymbol = "b"; public const string Bit = "bit"; public const string ByteSymbol = "B"; public const string Byte = "byte"; public const string KilobyteSymbol = "KB"; public const string Kilobyte = "kilobyte"; public const string MegabyteSymbol = "MB"; public const string Megabyte = "megabyte"; public const string GigabyteSymbol = "GB"; public const string Gigabyte = "gigabyte"; public const string TerabyteSymbol = "TB"; public const string Terabyte = "terabyte"; public long Bits { get; } = (long)Math.Ceiling(byteSize * BitsInByte); public double Bytes { get; } = byteSize; public double Kilobytes { get; } = byteSize / BytesInKilobyte; public double Megabytes { get; } = byteSize / BytesInMegabyte; public double Gigabytes { get; } = byteSize / BytesInGigabyte; public double Terabytes { get; } = byteSize / BytesInTerabyte; public readonly string LargestWholeNumberSymbol => GetLargestWholeNumberSymbol(); public readonly string GetLargestWholeNumberSymbol(IFormatProvider? provider = null) { var cultureFormatter = Configurator.GetFormatter(provider as CultureInfo); // Absolute value is used to deal with negative values if (Math.Abs(Terabytes) >= 1) { return cultureFormatter.DataUnitHumanize(DataUnit.Terabyte, Terabytes, toSymbol: true); } if (Math.Abs(Gigabytes) >= 1) { return cultureFormatter.DataUnitHumanize(DataUnit.Gigabyte, Gigabytes, toSymbol: true); } if (Math.Abs(Megabytes) >= 1) { return cultureFormatter.DataUnitHumanize(DataUnit.Megabyte, Megabytes, toSymbol: true); } if (Math.Abs(Kilobytes) >= 1) { return cultureFormatter.DataUnitHumanize(DataUnit.Kilobyte, Kilobytes, toSymbol: true); } if (Math.Abs(Bytes) >= 1) { return cultureFormatter.DataUnitHumanize(DataUnit.Byte, Bytes, toSymbol: true); } return cultureFormatter.DataUnitHumanize(DataUnit.Bit, Bits, toSymbol: true); } public readonly string LargestWholeNumberFullWord => GetLargestWholeNumberFullWord(); public readonly string GetLargestWholeNumberFullWord(IFormatProvider? provider = null) { var cultureFormatter = Configurator.GetFormatter(provider as CultureInfo); // Absolute value is used to deal with negative values if (Math.Abs(Terabytes) >= 1) { return cultureFormatter.DataUnitHumanize(DataUnit.Terabyte, Terabytes, toSymbol: false); } if (Math.Abs(Gigabytes) >= 1) { return cultureFormatter.DataUnitHumanize(DataUnit.Gigabyte, Gigabytes, toSymbol: false); } if (Math.Abs(Megabytes) >= 1) { return cultureFormatter.DataUnitHumanize(DataUnit.Megabyte, Megabytes, toSymbol: false); } if (Math.Abs(Kilobytes) >= 1) { return cultureFormatter.DataUnitHumanize(DataUnit.Kilobyte, Kilobytes, toSymbol: false); } if (Math.Abs(Bytes) >= 1) { return cultureFormatter.DataUnitHumanize(DataUnit.Byte, Bytes, toSymbol: false); } return cultureFormatter.DataUnitHumanize(DataUnit.Bit, Bits, toSymbol: false); } public readonly double LargestWholeNumberValue { get { // Absolute value is used to deal with negative values if (Math.Abs(Terabytes) >= 1) { return Terabytes; } if (Math.Abs(Gigabytes) >= 1) { return Gigabytes; } if (Math.Abs(Megabytes) >= 1) { return Megabytes; } if (Math.Abs(Kilobytes) >= 1) { return Kilobytes; } if (Math.Abs(Bytes) >= 1) { return Bytes; } return Bits; } } // Get ceiling because bis are whole units public static ByteSize FromBits(long value) => new(value / (double)BitsInByte); public static ByteSize FromBytes(double value) => new(value); public static ByteSize FromKilobytes(double value) => new(value * BytesInKilobyte); public static ByteSize FromMegabytes(double value) => new(value * BytesInMegabyte); public static ByteSize FromGigabytes(double value) => new(value * BytesInGigabyte); public static ByteSize FromTerabytes(double value) => new(value * BytesInTerabyte); /// /// Converts the value of the current ByteSize object to a string. /// The metric prefix symbol (bit, byte, kilo, mega, giga, tera) used is /// the largest metric prefix such that the corresponding value is greater /// than or equal to one. /// public readonly override string ToString() => ToString(NumberFormatInfo.CurrentInfo); public readonly string ToString(IFormatProvider? provider) { provider ??= CultureInfo.CurrentCulture; return string.Format(provider, "{0:0.##} {1}", LargestWholeNumberValue, GetLargestWholeNumberSymbol(provider)); } public readonly string ToString(string? format) => ToString(format, NumberFormatInfo.CurrentInfo); public readonly string ToString(string? format, IFormatProvider? provider) => ToString(format, provider, toSymbol: true); readonly string ToString(string? format, IFormatProvider? provider, bool toSymbol) { format ??= "G"; provider ??= CultureInfo.CurrentCulture; if (format == "G") { format = "0.##"; } if (format.IndexOfAny(['#', '0']) < 0) { format = "0.## " + format; } format = format.Replace("#.##", "0.##"); var culture = provider as CultureInfo ?? CultureInfo.CurrentCulture; bool has(string s) => culture.CompareInfo.IndexOf(format, s, CompareOptions.IgnoreCase) != -1; string output(double n) => n.ToString(format, provider); var cultureFormatter = Configurator.GetFormatter(provider as CultureInfo); if (has(TerabyteSymbol)) { format = format.Replace(TerabyteSymbol, cultureFormatter.DataUnitHumanize(DataUnit.Terabyte, Terabytes, toSymbol)); return output(Terabytes); } if (has(GigabyteSymbol)) { format = format.Replace(GigabyteSymbol, cultureFormatter.DataUnitHumanize(DataUnit.Gigabyte, Gigabytes, toSymbol)); return output(Gigabytes); } if (has(MegabyteSymbol)) { format = format.Replace(MegabyteSymbol, cultureFormatter.DataUnitHumanize(DataUnit.Megabyte, Megabytes, toSymbol)); return output(Megabytes); } if (has(KilobyteSymbol)) { format = format.Replace(KilobyteSymbol, cultureFormatter.DataUnitHumanize(DataUnit.Kilobyte, Kilobytes, toSymbol)); return output(Kilobytes); } // Byte and Bit symbol look must be case-sensitive if (format.Contains(ByteSymbol, StringComparison.Ordinal)) { format = format.Replace(ByteSymbol, cultureFormatter.DataUnitHumanize(DataUnit.Byte, Bytes, toSymbol)); return output(Bytes); } if (format.Contains(BitSymbol, StringComparison.Ordinal)) { format = format.Replace(BitSymbol, cultureFormatter.DataUnitHumanize(DataUnit.Bit, Bits, toSymbol)); return output(Bits); } var formattedLargeWholeNumberValue = LargestWholeNumberValue.ToString(format, provider); formattedLargeWholeNumberValue = formattedLargeWholeNumberValue.Equals(string.Empty) ? "0" : formattedLargeWholeNumberValue; return $"{formattedLargeWholeNumberValue} {(toSymbol ? GetLargestWholeNumberSymbol(provider) : GetLargestWholeNumberFullWord(provider))}"; } /// /// Converts the value of the current ByteSize object to a string with /// full words. The metric prefix symbol (bit, byte, kilo, mega, giga, /// tera) used is the largest metric prefix such that the corresponding /// value is greater than or equal to one. /// public readonly string ToFullWords(string? format = null, IFormatProvider? provider = null) => ToString(format, provider, toSymbol: false); public readonly override bool Equals(object? value) { if (value == null) { return false; } ByteSize other; if (value is ByteSize size) { other = size; } else { return false; } return Equals(other); } public readonly bool Equals(ByteSize value) => Bits == value.Bits; public readonly override int GetHashCode() => Bits.GetHashCode(); public readonly int CompareTo(object? obj) { if (obj == null) { return 1; } if (obj is ByteSize size) { return CompareTo(size); } throw new ArgumentException("Object is not a ByteSize"); } public readonly int CompareTo(ByteSize other) => Bits.CompareTo(other.Bits); public readonly ByteSize Add(ByteSize bs) => new(Bytes + bs.Bytes); public readonly ByteSize AddBits(long value) => this + FromBits(value); public readonly ByteSize AddBytes(double value) => this + FromBytes(value); public readonly ByteSize AddKilobytes(double value) => this + FromKilobytes(value); public readonly ByteSize AddMegabytes(double value) => this + FromMegabytes(value); public readonly ByteSize AddGigabytes(double value) => this + FromGigabytes(value); public readonly ByteSize AddTerabytes(double value) => this + FromTerabytes(value); public readonly ByteSize Subtract(ByteSize bs) => new(Bytes - bs.Bytes); public static ByteSize operator +(ByteSize b1, ByteSize b2) => new(b1.Bytes + b2.Bytes); public static ByteSize operator -(ByteSize b1, ByteSize b2) => new(b1.Bytes - b2.Bytes); public static ByteSize operator ++(ByteSize b) => new(b.Bytes + 1); public static ByteSize operator -(ByteSize b) => new(-b.Bytes); public static ByteSize operator --(ByteSize b) => new(b.Bytes - 1); public static bool operator ==(ByteSize b1, ByteSize b2) => b1.Bits == b2.Bits; public static bool operator !=(ByteSize b1, ByteSize b2) => b1.Bits != b2.Bits; public static bool operator <(ByteSize b1, ByteSize b2) => b1.Bits < b2.Bits; public static bool operator <=(ByteSize b1, ByteSize b2) => b1.Bits <= b2.Bits; public static bool operator >(ByteSize b1, ByteSize b2) => b1.Bits > b2.Bits; public static bool operator >=(ByteSize b1, ByteSize b2) => b1.Bits >= b2.Bits; public static bool TryParse(string? s, out ByteSize result) => TryParse(s, null, out result); public static bool TryParse(CharSpan s, out ByteSize result) => TryParse(s, null, out result); public static bool TryParse(string? s, IFormatProvider? formatProvider, out ByteSize result) => TryParse(s.AsSpan(), formatProvider, out result); public static bool TryParse(CharSpan s, IFormatProvider? formatProvider, out ByteSize result) { // Arg checking s = s.TrimStart(); // Protect against leading spaces if (s.IsEmpty) { result = default; return false; } // Acquiring culture-specific parsing info var numberFormat = NumberFormatInfo.GetInstance(formatProvider); // Get or create cached set of special characters from number format strings // Note: These can be multi-character strings in some cultures (e.g., Arabic) var specialCharsSet = NumberFormatSpecialCharsCache.GetValue( numberFormat, static nfi => new HashSet( nfi.NumberDecimalSeparator .Concat(nfi.NumberGroupSeparator) .Concat(nfi.PositiveSign) .Concat(nfi.NegativeSign) ) ); // Setup the result result = default; // Pick first non-digit number int lastNumber; for (lastNumber = 0; lastNumber < s.Length; lastNumber++) { if (!(char.IsDigit(s[lastNumber]) || specialCharsSet.Contains(s[lastNumber]))) { break; } } if (lastNumber == s.Length) { return false; } // Cut the input string in half var numberPart = s [..lastNumber] .Trim(); var sizePart = s[lastNumber..] .Trim(); if (sizePart.Length is not (1 or 2)) { return false; } // Get the numeric part const NumberStyles numberStyles = AllowDecimalPoint | AllowThousands | AllowLeadingSign; if (!double.TryParse( #if NET numberPart, #else numberPart.ToString(), #endif numberStyles, formatProvider, out var number)) { return false; } Span sizePartUpper = stackalloc char[sizePart.Length]; var upperLength = sizePart.ToUpperInvariant(sizePartUpper); Debug.Assert(sizePartUpper.Length == upperLength); // Get the magnitude part switch (sizePartUpper) { case ByteSymbol: if (sizePart.SequenceEqual(BitSymbol)) { if (!double.IsFinite(number)) { return false; } if (number != Math.Truncate(number)) { return false; } if (number < long.MinValue || number > long.MaxValue) { return false; } result = FromBits((long)number); } else { result = FromBytes(number); } break; case KilobyteSymbol: result = FromKilobytes(number); break; case MegabyteSymbol: result = FromMegabytes(number); break; case GigabyteSymbol: result = FromGigabytes(number); break; case TerabyteSymbol: result = FromTerabytes(number); break; default: return false; } return true; } public static ByteSize Parse(string s) => Parse(s, null); public static ByteSize Parse(string s, IFormatProvider? formatProvider) { ArgumentNullException.ThrowIfNull(s); if (TryParse(s, formatProvider, out var result)) { return result; } throw new FormatException("Value is not in the correct format"); } } #pragma warning restore 1591 ================================================ FILE: src/Humanizer/Bytes/ByteSizeExtensions.cs ================================================ // ReSharper disable once CheckNamespace namespace Humanizer; /// /// Provides extension methods for ByteSize /// public static class ByteSizeExtensions { /// /// Considers input as bits /// public static ByteSize Bits(this byte input) => ByteSize.FromBits(input); /// /// Considers input as bits /// public static ByteSize Bits(this sbyte input) => ByteSize.FromBits(input); /// /// Considers input as bits /// public static ByteSize Bits(this short input) => ByteSize.FromBits(input); /// /// Considers input as bits /// public static ByteSize Bits(this ushort input) => ByteSize.FromBits(input); /// /// Considers input as bits /// public static ByteSize Bits(this int input) => ByteSize.FromBits(input); /// /// Considers input as bits /// public static ByteSize Bits(this uint input) => ByteSize.FromBits(input); /// /// Considers input as bits /// public static ByteSize Bits(this long input) => ByteSize.FromBits(input); /// /// Considers input as bytes /// public static ByteSize Bytes(this byte input) => ByteSize.FromBytes(input); /// /// Considers input as bytes /// public static ByteSize Bytes(this sbyte input) => ByteSize.FromBytes(input); /// /// Considers input as bytes /// public static ByteSize Bytes(this short input) => ByteSize.FromBytes(input); /// /// Considers input as bytes /// public static ByteSize Bytes(this ushort input) => ByteSize.FromBytes(input); /// /// Considers input as bytes /// public static ByteSize Bytes(this int input) => ByteSize.FromBytes(input); /// /// Considers input as bytes /// public static ByteSize Bytes(this uint input) => ByteSize.FromBytes(input); /// /// Considers input as bytes /// public static ByteSize Bytes(this double input) => ByteSize.FromBytes(input); /// /// Considers input as bytes /// public static ByteSize Bytes(this long input) => ByteSize.FromBytes(input); /// /// Considers input as kilobytes /// public static ByteSize Kilobytes(this byte input) => ByteSize.FromKilobytes(input); /// /// Considers input as kilobytes /// public static ByteSize Kilobytes(this sbyte input) => ByteSize.FromKilobytes(input); /// /// Considers input as kilobytes /// public static ByteSize Kilobytes(this short input) => ByteSize.FromKilobytes(input); /// /// Considers input as kilobytes /// public static ByteSize Kilobytes(this ushort input) => ByteSize.FromKilobytes(input); /// /// Considers input as kilobytes /// public static ByteSize Kilobytes(this int input) => ByteSize.FromKilobytes(input); /// /// Considers input as kilobytes /// public static ByteSize Kilobytes(this uint input) => ByteSize.FromKilobytes(input); /// /// Considers input as kilobytes /// public static ByteSize Kilobytes(this double input) => ByteSize.FromKilobytes(input); /// /// Considers input as kilobytes /// public static ByteSize Kilobytes(this long input) => ByteSize.FromKilobytes(input); /// /// Considers input as megabytes /// public static ByteSize Megabytes(this byte input) => ByteSize.FromMegabytes(input); /// /// Considers input as megabytes /// public static ByteSize Megabytes(this sbyte input) => ByteSize.FromMegabytes(input); /// /// Considers input as megabytes /// public static ByteSize Megabytes(this short input) => ByteSize.FromMegabytes(input); /// /// Considers input as megabytes /// public static ByteSize Megabytes(this ushort input) => ByteSize.FromMegabytes(input); /// /// Considers input as megabytes /// public static ByteSize Megabytes(this int input) => ByteSize.FromMegabytes(input); /// /// Considers input as megabytes /// public static ByteSize Megabytes(this uint input) => ByteSize.FromMegabytes(input); /// /// Considers input as megabytes /// public static ByteSize Megabytes(this double input) => ByteSize.FromMegabytes(input); /// /// Considers input as megabytes /// public static ByteSize Megabytes(this long input) => ByteSize.FromMegabytes(input); /// /// Considers input as gigabytes /// public static ByteSize Gigabytes(this byte input) => ByteSize.FromGigabytes(input); /// /// Considers input as gigabytes /// public static ByteSize Gigabytes(this sbyte input) => ByteSize.FromGigabytes(input); /// /// Considers input as gigabytes /// public static ByteSize Gigabytes(this short input) => ByteSize.FromGigabytes(input); /// /// Considers input as gigabytes /// public static ByteSize Gigabytes(this ushort input) => ByteSize.FromGigabytes(input); /// /// Considers input as gigabytes /// public static ByteSize Gigabytes(this int input) => ByteSize.FromGigabytes(input); /// /// Considers input as gigabytes /// public static ByteSize Gigabytes(this uint input) => ByteSize.FromGigabytes(input); /// /// Considers input as gigabytes /// public static ByteSize Gigabytes(this double input) => ByteSize.FromGigabytes(input); /// /// Considers input as gigabytes /// public static ByteSize Gigabytes(this long input) => ByteSize.FromGigabytes(input); /// /// Considers input as terabytes /// public static ByteSize Terabytes(this byte input) => ByteSize.FromTerabytes(input); /// /// Considers input as terabytes /// public static ByteSize Terabytes(this sbyte input) => ByteSize.FromTerabytes(input); /// /// Considers input as terabytes /// public static ByteSize Terabytes(this short input) => ByteSize.FromTerabytes(input); /// /// Considers input as terabytes /// public static ByteSize Terabytes(this ushort input) => ByteSize.FromTerabytes(input); /// /// Considers input as terabytes /// public static ByteSize Terabytes(this int input) => ByteSize.FromTerabytes(input); /// /// Considers input as terabytes /// public static ByteSize Terabytes(this uint input) => ByteSize.FromTerabytes(input); /// /// Considers input as terabytes /// public static ByteSize Terabytes(this double input) => ByteSize.FromTerabytes(input); /// /// Considers input as terabytes /// public static ByteSize Terabytes(this long input) => ByteSize.FromTerabytes(input); /// /// Turns a byte quantity into human readable form, eg 2 GB /// /// The string format to use public static string Humanize(this ByteSize input, string? format = null) => string.IsNullOrWhiteSpace(format) ? input.ToString() : input.ToString(format); /// /// Turns a byte quantity into human readable form, eg 2 GB /// /// The format provider to use public static string Humanize(this ByteSize input, IFormatProvider formatProvider) => input.ToString(formatProvider); /// /// Turns a byte quantity into human readable form, eg 2 GB /// /// The string format to use /// The format provider to use public static string Humanize(this ByteSize input, string? format, IFormatProvider? formatProvider) => string.IsNullOrWhiteSpace(format) ? input.ToString(formatProvider) : input.ToString(format, formatProvider); /// /// Turns a quantity of bytes in a given interval into a rate that can be manipulated /// /// Quantity of bytes /// Interval to create rate for public static ByteRate Per(this ByteSize size, TimeSpan interval) => new(size, interval); } ================================================ FILE: src/Humanizer/Bytes/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2013-2017 Omar Khudeira (http://omar.io) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: src/Humanizer/CasingExtensions.cs ================================================ namespace Humanizer; /// /// ApplyCase method to allow changing the case of a sentence easily /// public static class CasingExtensions { /// /// Applies the specified letter casing transformation to the input string. /// /// The string to transform. Must not be null. /// The desired letter casing style to apply to the input string. /// /// A new string with the specified casing applied. /// - : Each word is capitalized (e.g., "Some String") /// - : All letters are lowercase (e.g., "some string") /// - : All letters are uppercase (e.g., "SOME STRING") /// - : First letter capitalized, rest lowercase (e.g., "Some string") /// /// Thrown when an invalid value is provided. /// /// /// "some string".ApplyCase(LetterCasing.Title) => "Some String" /// "SOME STRING".ApplyCase(LetterCasing.LowerCase) => "some string" /// "some string".ApplyCase(LetterCasing.AllCaps) => "SOME STRING" /// "some string".ApplyCase(LetterCasing.Sentence) => "Some string" /// /// public static string ApplyCase(this string input, LetterCasing casing) => casing switch { LetterCasing.Title => input.Transform(To.TitleCase), LetterCasing.LowerCase => input.Transform(To.LowerCase), LetterCasing.AllCaps => input.Transform(To.UpperCase), LetterCasing.Sentence => input.Transform(To.SentenceCase), _ => throw new ArgumentOutOfRangeException(nameof(casing)) }; } ================================================ FILE: src/Humanizer/ClockNotationRounding.cs ================================================ namespace Humanizer; /// /// Options for specifying readable clock notation /// public enum ClockNotationRounding { /// /// Do not round minutes /// None, /// /// Round time to nearest five minutes /// NearestFiveMinutes } ================================================ FILE: src/Humanizer/CollectionHumanizeExtensions.cs ================================================ namespace Humanizer; /// /// Humanizes an IEnumerable into a human readable list /// public static class CollectionHumanizeExtensions { /// /// Transforms a collection into a human-readable string representation by calling /// on each element and combining them with the default separator for the current culture (typically ", " with /// "and" before the last item). /// /// The type of elements in the collection. /// The collection to be humanized. Must not be null. /// /// A formatted string representation of the collection elements separated by culture-specific separators. /// For English, this typically produces: "item1, item2 and item3". /// /// Thrown when is null. /// /// /// new[] { 1, 2, 3 }.Humanize() => "1, 2 and 3" /// new[] { "Alice", "Bob", "Charlie" }.Humanize() => "Alice, Bob and Charlie" /// new[] { "single" }.Humanize() => "single" /// new string[] { }.Humanize() => "" /// /// public static string Humanize(this IEnumerable collection) => Configurator.CollectionFormatter.Humanize(collection); /// /// Transforms a collection into a human-readable string representation using a custom formatter function /// for each element, combined with the default separator for the current culture. /// /// The type of elements in the collection. /// The collection to be humanized. Must not be null. /// /// A function that converts each element of type to a string representation. /// Must not be null. /// /// /// A formatted string representation of the collection elements, where each element is formatted /// using and separated by culture-specific separators. /// /// /// Thrown when or is null. /// /// /// /// var people = new[] { new Person { Name = "Alice", Age = 30 }, new Person { Name = "Bob", Age = 25 } }; /// people.Humanize(p => p.Name) => "Alice and Bob" /// people.Humanize(p => $"{p.Name} ({p.Age})") => "Alice (30) and Bob (25)" /// /// public static string Humanize(this IEnumerable collection, Func displayFormatter) { ArgumentNullException.ThrowIfNull(displayFormatter); return Configurator.CollectionFormatter.Humanize(collection, displayFormatter); } /// /// Transforms a collection into a human-readable string representation using a custom formatter function /// that returns an object for each element (which will be converted to string), combined with the default /// separator for the current culture. /// /// The type of elements in the collection. /// The collection to be humanized. Must not be null. /// /// A function that converts each element of type to an object that will be /// converted to its string representation. Must not be null. /// /// /// A formatted string representation of the collection elements, where each element is formatted /// using and separated by culture-specific separators. /// /// /// Thrown when or is null. /// /// /// /// var numbers = new[] { 1, 2, 3 }; /// numbers.Humanize(n => n * 2) => "2, 4 and 6" /// /// public static string Humanize(this IEnumerable collection, Func displayFormatter) { ArgumentNullException.ThrowIfNull(displayFormatter); return Configurator.CollectionFormatter.Humanize(collection, displayFormatter); } /// /// Transforms a collection into a string representation by calling /// on each element and combining them with the specified separator. /// /// The type of elements in the collection. /// The collection to be humanized. Must not be null. /// The string to use as a separator between elements. /// /// A string representation of the collection elements separated by the specified separator. /// /// Thrown when is null. /// /// /// new[] { 1, 2, 3 }.Humanize(" | ") => "1 | 2 | 3" /// new[] { "Alice", "Bob" }.Humanize("; ") => "Alice; Bob" /// /// public static string Humanize(this IEnumerable collection, string separator) => Configurator.CollectionFormatter.Humanize(collection, separator); /// /// Transforms a collection into a string representation using a custom formatter function /// for each element, combined with the specified separator. /// /// The type of elements in the collection. /// The collection to be humanized. Must not be null. /// /// A function that converts each element of type to a string representation. /// Must not be null. /// /// The string to use as a separator between formatted elements. /// /// A string representation of the collection elements, where each element is formatted /// using and separated by the specified separator. /// /// /// Thrown when or is null. /// /// /// /// var people = new[] { new Person { Name = "Alice" }, new Person { Name = "Bob" } }; /// people.Humanize(p => p.Name, " | ") => "Alice | Bob" /// /// public static string Humanize(this IEnumerable collection, Func displayFormatter, string separator) { ArgumentNullException.ThrowIfNull(displayFormatter); return Configurator.CollectionFormatter.Humanize(collection, displayFormatter, separator); } /// /// Transforms a collection into a string representation using a custom formatter function /// that returns an object for each element (which will be converted to string), combined with the specified separator. /// /// The type of elements in the collection. /// The collection to be humanized. Must not be null. /// /// A function that converts each element of type to an object that will be /// converted to its string representation. Must not be null. /// /// The string to use as a separator between formatted elements. /// /// A string representation of the collection elements, where each element is formatted /// using and separated by the specified separator. /// /// /// Thrown when or is null. /// /// /// /// var numbers = new[] { 1, 2, 3 }; /// numbers.Humanize(n => n * 2, " - ") => "2 - 4 - 6" /// /// public static string Humanize(this IEnumerable collection, Func displayFormatter, string separator) { ArgumentNullException.ThrowIfNull(displayFormatter); return Configurator.CollectionFormatter.Humanize(collection, displayFormatter, separator); } } ================================================ FILE: src/Humanizer/Configuration/CollectionFormatterRegistry.cs ================================================ namespace Humanizer; class CollectionFormatterRegistry : LocaliserRegistry { public CollectionFormatterRegistry() : base(_ => new DefaultCollectionFormatter("&")) { Register("en", _ => new OxfordStyleCollectionFormatter()); Register("it", _ => new DefaultCollectionFormatter("e")); Register("de", _ => new DefaultCollectionFormatter("und")); Register("dk", _ => new DefaultCollectionFormatter("og")); Register("nl", _ => new DefaultCollectionFormatter("en")); Register("pt", _ => new DefaultCollectionFormatter("e")); Register("ro", _ => new DefaultCollectionFormatter("și")); Register("nn", _ => new DefaultCollectionFormatter("og")); Register("nb", _ => new DefaultCollectionFormatter("og")); Register("sv", _ => new DefaultCollectionFormatter("och")); Register("is", _ => new DefaultCollectionFormatter("og")); Register("es", _ => new DefaultCollectionFormatter("y")); Register("lb", _ => new DefaultCollectionFormatter("an")); Register("ca", _ => new DefaultCollectionFormatter("i")); } } ================================================ FILE: src/Humanizer/Configuration/Configurator.cs ================================================ namespace Humanizer; /// /// Provides a configuration point for Humanizer /// public static class Configurator { /// /// A registry of formatters used to format collections based on the current locale /// public static LocaliserRegistry CollectionFormatters { get; } = new CollectionFormatterRegistry(); /// /// A registry of formatters used to format strings based on the current locale /// public static LocaliserRegistry Formatters { get; } = new FormatterRegistry(); /// /// A registry of number to words converters used to localise ToWords and ToOrdinalWords methods /// public static LocaliserRegistry NumberToWordsConverters { get; } = new NumberToWordsConverterRegistry(); /// /// Registry of converters that transform words into numbers for english language /// private static LocaliserRegistry WordsToNumberConverters { get; } = new WordsToNumberConverterRegistry(); /// /// A registry of ordinalizers used to localise Ordinalize method /// public static LocaliserRegistry Ordinalizers { get; } = new OrdinalizerRegistry(); /// /// A registry of ordinalizers used to localise Ordinalize method /// public static LocaliserRegistry DateToOrdinalWordsConverters { get; } = new DateToOrdinalWordsConverterRegistry(); #if NET6_0_OR_GREATER /// /// A registry of ordinalizers used to localise Ordinalize method /// public static LocaliserRegistry DateOnlyToOrdinalWordsConverters { get; } = new DateOnlyToOrdinalWordsConverterRegistry(); /// /// A registry of time to clock notation converters used to localise ToClockNotation methods /// public static LocaliserRegistry TimeOnlyToClockNotationConverters { get; } = new TimeOnlyToClockNotationConvertersRegistry(); #endif internal static ICollectionFormatter CollectionFormatter => CollectionFormatters.ResolveForUiCulture(); /// /// The formatter to be used /// /// The culture to retrieve formatter for. Null means that current thread's UI culture should be used. internal static IFormatter GetFormatter(CultureInfo? culture) => Formatters.ResolveForCulture(culture); /// /// The converter to be used /// /// The culture to retrieve number to words converter for. Null means that current thread's UI culture should be used. internal static INumberToWordsConverter GetNumberToWordsConverter(CultureInfo? culture) => NumberToWordsConverters.ResolveForCulture(culture); internal static IWordsToNumberConverter GetWordsToNumberConverter(CultureInfo culture) => WordsToNumberConverters.ResolveForCulture(culture); /// /// The ordinalizer to be used /// internal static IOrdinalizer Ordinalizer => Ordinalizers.ResolveForUiCulture(); /// /// The ordinalizer to be used /// internal static IDateToOrdinalWordConverter DateToOrdinalWordsConverter => DateToOrdinalWordsConverters.ResolveForUiCulture(); #if NET6_0_OR_GREATER /// /// The ordinalizer to be used /// internal static IDateOnlyToOrdinalWordConverter DateOnlyToOrdinalWordsConverter => DateOnlyToOrdinalWordsConverters.ResolveForUiCulture(); internal static ITimeOnlyToClockNotationConverter TimeOnlyToClockNotationConverter => TimeOnlyToClockNotationConverters.ResolveForUiCulture(); #endif /// /// The strategy to be used for DateTime.Humanize /// /// /// This property should be set only once during application startup before any humanization operations occur. /// For thread-safety, use volatile reads or appropriate synchronization when accessing this property in multi-threaded scenarios. /// In production applications, avoid changing this value after the application has started serving requests. /// public static IDateTimeHumanizeStrategy DateTimeHumanizeStrategy { get; set; } = new DefaultDateTimeHumanizeStrategy(); /// /// The strategy to be used for DateTimeOffset.Humanize /// /// /// This property should be set only once during application startup before any humanization operations occur. /// For thread-safety, use volatile reads or appropriate synchronization when accessing this property in multi-threaded scenarios. /// In production applications, avoid changing this value after the application has started serving requests. /// public static IDateTimeOffsetHumanizeStrategy DateTimeOffsetHumanizeStrategy { get; set; } = new DefaultDateTimeOffsetHumanizeStrategy(); #if NET6_0_OR_GREATER /// /// The strategy to be used for DateOnly.Humanize /// /// /// This property should be set only once during application startup before any humanization operations occur. /// For thread-safety, use volatile reads or appropriate synchronization when accessing this property in multi-threaded scenarios. /// In production applications, avoid changing this value after the application has started serving requests. /// public static IDateOnlyHumanizeStrategy DateOnlyHumanizeStrategy { get; set; } = new DefaultDateOnlyHumanizeStrategy(); /// /// The strategy to be used for TimeOnly.Humanize /// /// /// This property should be set only once during application startup before any humanization operations occur. /// For thread-safety, use volatile reads or appropriate synchronization when accessing this property in multi-threaded scenarios. /// In production applications, avoid changing this value after the application has started serving requests. /// public static ITimeOnlyHumanizeStrategy TimeOnlyHumanizeStrategy { get; set; } = new DefaultTimeOnlyHumanizeStrategy(); #endif static readonly Func DefaultEnumDescriptionPropertyLocator = p => p.Name == "Description"; static readonly object EnumDescriptionPropertyLocatorLock = new(); static volatile Func enumDescriptionPropertyLocator = DefaultEnumDescriptionPropertyLocator; static volatile bool enumDescriptionPropertyLocatorHasBeenUsed; internal static Func EnumDescriptionPropertyLocator { get { enumDescriptionPropertyLocatorHasBeenUsed = true; return enumDescriptionPropertyLocator; } private set => enumDescriptionPropertyLocator = value; } /// /// Use a predicate function for description property of attribute to use for Enum.Humanize /// public static void UseEnumDescriptionPropertyLocator(Func func) { lock (EnumDescriptionPropertyLocatorLock) { if (enumDescriptionPropertyLocatorHasBeenUsed) { throw new("UseEnumDescriptionPropertyLocator must be called before any Enum.Humanize has already been. Move the call to UseEnumDescriptionPropertyLocator to the app startup or a ModuleInitializer."); } EnumDescriptionPropertyLocator = func; } } internal static void ResetUseEnumDescriptionPropertyLocator() { lock (EnumDescriptionPropertyLocatorLock) { enumDescriptionPropertyLocatorHasBeenUsed = false; EnumDescriptionPropertyLocator = DefaultEnumDescriptionPropertyLocator; } } } ================================================ FILE: src/Humanizer/Configuration/DateOnlyToOrdinalWordsConverterRegistry.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; class DateOnlyToOrdinalWordsConverterRegistry : LocaliserRegistry { public DateOnlyToOrdinalWordsConverterRegistry() : base(_ => new DefaultDateOnlyToOrdinalWordConverter()) { Register("en-US", _ => new UsDateOnlyToOrdinalWordsConverter()); Register("fr", _ => new FrDateOnlyToOrdinalWordsConverter()); Register("es", _ => new EsDateOnlyToOrdinalWordsConverter()); Register("lt", _ => new LtDateOnlyToOrdinalWordsConverter()); Register("ca", _ => new CaDateOnlyToOrdinalWordsConverter()); } } #endif ================================================ FILE: src/Humanizer/Configuration/DateToOrdinalWordsConverterRegistry.cs ================================================ namespace Humanizer; class DateToOrdinalWordsConverterRegistry : LocaliserRegistry { public DateToOrdinalWordsConverterRegistry() : base(_ => new DefaultDateToOrdinalWordConverter()) { Register("en-US", _ => new UsDateToOrdinalWordsConverter()); Register("fr", _ => new FrDateToOrdinalWordsConverter()); Register("es", _ => new EsDateToOrdinalWordsConverter()); Register("lt", _ => new LtDateToOrdinalWordsConverter()); Register("ca", _ => new CaDateToOrdinalWordsConverter()); } } ================================================ FILE: src/Humanizer/Configuration/FormatterRegistry.cs ================================================ namespace Humanizer; class FormatterRegistry : LocaliserRegistry { public FormatterRegistry() : base(c => new DefaultFormatter(c)) { Register("ar", c => new ArabicFormatter(c)); Register("de", c => new GermanFormatter(c)); Register("he", c => new HebrewFormatter(c)); Register("ro", c => new RomanianFormatter(c)); Register("ru", c => new RussianFormatter(c)); Register("sl", c => new SlovenianFormatter(c)); Register("hr", c => new CroatianFormatter(c)); Register("sr", c => new SerbianFormatter(c)); Register("uk", c => new UkrainianFormatter(c)); Register("fr", c => new FrenchFormatter(c)); RegisterCzechSlovakPolishFormatter("cs"); RegisterCzechSlovakPolishFormatter("pl"); RegisterCzechSlovakPolishFormatter("sk"); Register("bg", c => new BulgarianFormatter(c)); RegisterDefaultFormatter("ku"); RegisterDefaultFormatter("pt"); RegisterDefaultFormatter("sv"); RegisterDefaultFormatter("tr"); RegisterDefaultFormatter("vi"); RegisterDefaultFormatter("en"); RegisterDefaultFormatter("af"); RegisterDefaultFormatter("az"); RegisterDefaultFormatter("da"); RegisterDefaultFormatter("el"); RegisterDefaultFormatter("es"); RegisterDefaultFormatter("fa"); RegisterDefaultFormatter("fi"); RegisterDefaultFormatter("fil"); RegisterDefaultFormatter("hu"); RegisterDefaultFormatter("hy"); RegisterDefaultFormatter("id"); Register("is", c => new IcelandicFormatter(c)); RegisterDefaultFormatter("ja"); RegisterDefaultFormatter("ko"); RegisterDefaultFormatter("lv"); Register("mt", c => new MalteseFormatter(c)); RegisterDefaultFormatter("ms"); RegisterDefaultFormatter("nb"); RegisterDefaultFormatter("nl"); RegisterDefaultFormatter("bn"); RegisterDefaultFormatter("it"); RegisterDefaultFormatter("ta"); RegisterDefaultFormatter("uz-Latn-UZ"); RegisterDefaultFormatter("uz-Cyrl-UZ"); RegisterDefaultFormatter("zh-CN"); RegisterDefaultFormatter("zh-Hans"); RegisterDefaultFormatter("zh-Hant"); RegisterDefaultFormatter("th"); Register("lt", c => new LithuanianFormatter(c)); Register("lb", c => new LuxembourgishFormatter(c)); Register("ca", c => new CatalanFormatter(c)); } void RegisterDefaultFormatter(string localeCode) => Register(localeCode, c => new DefaultFormatter(c)); void RegisterCzechSlovakPolishFormatter(string localeCode) => Register(localeCode, c => new CzechSlovakPolishFormatter(c)); } ================================================ FILE: src/Humanizer/Configuration/LocaliserRegistry.cs ================================================ namespace Humanizer; /// /// A registry of localised system components with their associated locales /// public class LocaliserRegistry where TLocaliser : class { readonly Dictionary> localisersBuilder = []; readonly object lockObject = new(); volatile FrozenDictionary>? frozenLocalisers; readonly Func defaultLocaliser; readonly ConcurrentDictionary cultureSpecificCache = new(); /// /// Creates a localiser registry with the default localiser set to the provided value /// public LocaliserRegistry(TLocaliser defaultLocaliser) => this.defaultLocaliser = _ => defaultLocaliser; /// /// Creates a localiser registry with the default localiser factory set to the provided value /// public LocaliserRegistry(Func defaultLocaliser) => this.defaultLocaliser = defaultLocaliser; /// /// Gets the localiser for the current thread's UI culture /// public TLocaliser ResolveForUiCulture() => ResolveForCulture(null); /// /// Gets the localiser for the specified culture /// /// The culture to retrieve localiser for. If not specified, current thread's UI culture is used. public TLocaliser ResolveForCulture(CultureInfo? culture) { var cultureInfo = culture ?? CultureInfo.CurrentUICulture; var cultureName = cultureInfo.Name; // Use ConcurrentDictionary with culture name (string) as key to avoid CultureInfo equality checks // and reduce allocations when the same culture is requested multiple times return cultureSpecificCache.GetOrAdd(cultureName, _ => { var factory = FindLocaliser(cultureInfo); return factory(cultureInfo); }); } /// /// Registers the localiser for the culture provided /// public void Register(string localeCode, TLocaliser localiser) { lock (lockObject) { if (frozenLocalisers != null) { throw new InvalidOperationException("Cannot register localisers after the registry has been used."); } localisersBuilder[localeCode] = _ => localiser; } } /// /// Registers the localiser factory for the culture provided /// public void Register(string localeCode, Func localiser) { lock (lockObject) { if (frozenLocalisers != null) { throw new InvalidOperationException("Cannot register localisers after the registry has been used."); } localisersBuilder[localeCode] = localiser; } } Func FindLocaliser(CultureInfo culture) { // Check if already frozen (fast path without lock) var frozen = frozenLocalisers; if (frozen == null) { lock (lockObject) { // Double-check after acquiring lock frozen = frozenLocalisers; if (frozen == null) { // Freeze the dictionary on first use for better read performance frozen = localisersBuilder.ToFrozenDictionary(); frozenLocalisers = frozen; } } } for (var c = culture; !string.IsNullOrEmpty(c.Name); c = c.Parent) { if (frozen.TryGetValue(c.Name, out var localiser)) { return localiser; } } return defaultLocaliser; } } ================================================ FILE: src/Humanizer/Configuration/NumberToWordsConverterRegistry.cs ================================================ namespace Humanizer; class NumberToWordsConverterRegistry : LocaliserRegistry { public NumberToWordsConverterRegistry() : base(_ => new EnglishNumberToWordsConverter()) { Register("af", _ => new AfrikaansNumberToWordsConverter()); Register("en", _ => new EnglishNumberToWordsConverter()); Register("ar", _ => new ArabicNumberToWordsConverter()); Register("cs", c => new CzechNumberToWordsConverter(c)); Register("fa", _ => new FarsiNumberToWordsConverter()); Register("es", _ => new SpanishNumberToWordsConverter()); Register("pl", c => new PolishNumberToWordsConverter(c)); Register("pt", _ => new PortugueseNumberToWordsConverter()); Register("pt-BR", _ => new BrazilianPortugueseNumberToWordsConverter()); Register("ro", _ => new RomanianNumberToWordsConverter()); Register("ru", _ => new RussianNumberToWordsConverter()); Register("fi", _ => new FinnishNumberToWordsConverter()); Register("fr-BE", _ => new FrenchBelgianNumberToWordsConverter()); Register("fr-CH", _ => new FrenchSwissNumberToWordsConverter()); Register("fr", _ => new FrenchNumberToWordsConverter()); Register("nl", _ => new DutchNumberToWordsConverter()); Register("he", c => new HebrewNumberToWordsConverter(c)); Register("sl", c => new SlovenianNumberToWordsConverter(c)); Register("de", _ => new GermanNumberToWordsConverter()); Register("de-CH", _ => new GermanSwissLiechtensteinNumberToWordsConverter()); Register("de-LI", _ => new GermanSwissLiechtensteinNumberToWordsConverter()); Register("bn", _ => new BanglaNumberToWordsConverter()); Register("tr", _ => new TurkishNumberToWordConverter()); Register("is", _ => new IcelandicNumberToWordsConverter()); Register("it", _ => new ItalianNumberToWordsConverter()); Register("mt", _ => new MalteseNumberToWordsConvertor()); Register("uk", _ => new UkrainianNumberToWordsConverter()); Register("uz-Latn-UZ", _ => new UzbekLatnNumberToWordConverter()); Register("uz-Cyrl-UZ", _ => new UzbekCyrlNumberToWordConverter()); Register("sv", _ => new SwedishNumberToWordsConverter()); Register("sr", c => new SerbianCyrlNumberToWordsConverter(c)); Register("sr-Latn", c => new SerbianNumberToWordsConverter(c)); Register("ta", _ => new TamilNumberToWordsConverter()); Register("hr", c => new CroatianNumberToWordsConverter(c)); Register("nb", _ => new NorwegianBokmalNumberToWordsConverter()); Register("vi", _ => new VietnameseNumberToWordsConverter()); Register("zh-CN", _ => new ChineseNumberToWordsConverter()); Register("zh-Hans", _ => new ChineseNumberToWordsConverter()); Register("zh-Hant", _ => new ChineseNumberToWordsConverter()); Register("bg", _ => new BulgarianNumberToWordsConverter()); Register("hy", _ => new ArmenianNumberToWordsConverter()); Register("az", _ => new AzerbaijaniNumberToWordsConverter()); Register("ja", _ => new JapaneseNumberToWordsConverter()); Register("ku", _ => new CentralKurdishNumberToWordsConverter()); Register("el", _ => new GreekNumberToWordsConverter()); Register("th", _ => new ThaiNumberToWordsConverter()); Register("lv", _ => new LatvianNumberToWordsConverter()); Register("ko", _ => new KoreanNumberToWordsConverter()); Register("en-IN", _ => new IndianNumberToWordsConverter()); Register("lt", _ => new LithuanianNumberToWordsConverter()); Register("lb", _ => new LuxembourgishNumberToWordsConverter()); Register("hu", _ => new HungarianNumberToWordsConverter()); Register("ca", _ => new CatalanNumberToWordsConverter()); } } ================================================ FILE: src/Humanizer/Configuration/OrdinalizerRegistry.cs ================================================ namespace Humanizer; class OrdinalizerRegistry : LocaliserRegistry { public OrdinalizerRegistry() : base(_ => new DefaultOrdinalizer()) { Register("de", _ => new GermanOrdinalizer()); Register("en", _ => new EnglishOrdinalizer()); Register("es", c => new SpanishOrdinalizer(c)); Register("fr", _ => new FrenchOrdinalizer()); Register("is", _ => new IcelandicOrdinalizer()); Register("it", _ => new ItalianOrdinalizer()); Register("nl", _ => new DutchOrdinalizer()); Register("pt", _ => new PortugueseOrdinalizer()); Register("ro", _ => new RomanianOrdinalizer()); Register("ru", _ => new RussianOrdinalizer()); Register("tr", _ => new TurkishOrdinalizer()); Register("uk", _ => new UkrainianOrdinalizer()); Register("hy", _ => new ArmenianOrdinalizer()); Register("az", _ => new AzerbaijaniOrdinalizer()); Register("lb", _ => new LuxembourgishOrdinalizer()); Register("hu", _ => new HungarianOrdinalizer()); Register("ca", _ => new CatalanOrdinalizer()); } } ================================================ FILE: src/Humanizer/Configuration/TimeOnlyToClockNotationConvertersRegistry.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; class TimeOnlyToClockNotationConvertersRegistry : LocaliserRegistry { public TimeOnlyToClockNotationConvertersRegistry() : base(_ => new DefaultTimeOnlyToClockNotationConverter()) { Register("pt-BR", _ => new BrazilianPortugueseTimeOnlyToClockNotationConverter()); Register("fr", _ => new FrTimeOnlyToClockNotationConverter()); Register("de", _ => new GermanTimeOnlyToClockNotationConverter()); Register("es", _ => new EsTimeOnlyToClockNotationConverter()); Register("lb", _ => new LbTimeOnlyToClockNotationConverter()); Register("pt", _ => new PortugueseTimeOnlyToClockNotationConverter()); Register("ca", _ => new CaTimeOnlyToClockNotationConverter()); } } #endif ================================================ FILE: src/Humanizer/Configuration/WordsToNumberConverterRegistry.cs ================================================ namespace Humanizer; internal class WordsToNumberConverterRegistry : LocaliserRegistry { public WordsToNumberConverterRegistry() : base(culture => culture.TwoLetterISOLanguageName == "en" ? new EnglishWordsToNumberConverter() : new DefaultWordsToNumberConverter(culture)) => Register("en", _ => new EnglishWordsToNumberConverter()); } ================================================ FILE: src/Humanizer/DateHumanizeExtensions.cs ================================================ namespace Humanizer; /// /// Humanizes DateTime into human readable sentence /// public static class DateHumanizeExtensions { /// /// Turns the current or provided date into a human readable sentence /// /// The date to be humanized /// Nullable boolean value indicating whether the date is in UTC or local. If null, current date is used with the same DateTimeKind of input /// Date to compare the input against. If null, current date is used as base /// Culture to use. If null, current thread's UI culture is used. /// distance of time in words public static string Humanize(this DateTime input, bool? utcDate = null, DateTime? dateToCompareAgainst = null, CultureInfo? culture = null) { var comparisonBase = dateToCompareAgainst ?? DateTime.UtcNow; utcDate ??= input.Kind != DateTimeKind.Local; comparisonBase = utcDate.Value ? comparisonBase.ToUniversalTime() : comparisonBase.ToLocalTime(); return Configurator.DateTimeHumanizeStrategy.Humanize(input, comparisonBase, culture); } /// /// Turns the current or provided date into a human readable sentence, overload for the nullable DateTime, returning 'never' in case null /// /// The date to be humanized /// Nullable boolean value indicating whether the date is in UTC or local. If null, current date is used with the same DateTimeKind of input /// Date to compare the input against. If null, current date is used as base /// Culture to use. If null, current thread's UI culture is used. /// distance of time in words public static string Humanize(this DateTime? input, bool? utcDate = null, DateTime? dateToCompareAgainst = null, CultureInfo? culture = null) { if (input.HasValue) { return Humanize(input.Value, utcDate, dateToCompareAgainst, culture); } return Configurator .GetFormatter(culture) .DateHumanize_Never(); } /// /// Turns the current or provided date into a human readable sentence /// /// The date to be humanized /// Date to compare the input against. If null, current date is used as base /// Culture to use. If null, current thread's UI culture is used. /// distance of time in words public static string Humanize(this DateTimeOffset input, DateTimeOffset? dateToCompareAgainst = null, CultureInfo? culture = null) { var comparisonBase = dateToCompareAgainst ?? DateTimeOffset.UtcNow; return Configurator.DateTimeOffsetHumanizeStrategy.Humanize(input, comparisonBase, culture); } /// /// Turns the current or provided date into a human readable sentence, overload for the nullable DateTimeOffset, returning 'never' in case null /// /// The date to be humanized /// Date to compare the input against. If null, current date is used as base /// Culture to use. If null, current thread's UI culture is used. /// distance of time in words public static string Humanize(this DateTimeOffset? input, DateTimeOffset? dateToCompareAgainst = null, CultureInfo? culture = null) { if (input.HasValue) { return Humanize(input.Value, dateToCompareAgainst, culture); } return Configurator .GetFormatter(culture) .DateHumanize_Never(); } #if NET6_0_OR_GREATER /// /// Turns the current or provided date into a human readable sentence /// /// The date to be humanized /// Date to compare the input against. If null, current date is used as base /// Culture to use. If null, current thread's UI culture is used. /// distance of time in words public static string Humanize(this DateOnly input, DateOnly? dateToCompareAgainst = null, CultureInfo? culture = null) { var comparisonBase = dateToCompareAgainst ?? DateOnly.FromDateTime(DateTime.UtcNow); return Configurator.DateOnlyHumanizeStrategy.Humanize(input, comparisonBase, culture); } /// /// Turns the current or provided date into a human readable sentence, overload for the nullable DateTime, returning 'never' in case null /// /// The date to be humanized /// Date to compare the input against. If null, current date is used as base /// Culture to use. If null, current thread's UI culture is used. /// distance of time in words public static string Humanize(this DateOnly? input, DateOnly? dateToCompareAgainst = null, CultureInfo? culture = null) { if (input.HasValue) { return Humanize(input.Value, dateToCompareAgainst, culture); } return Configurator .GetFormatter(culture) .DateHumanize_Never(); } /// /// Turns the current or provided time into a human readable sentence /// /// The date to be humanized /// If is null, used to determine if the current time is UTC or local. Defaults to UTC. /// Date to compare the input against. If null, current date is used as base /// Culture to use. If null, current thread's UI culture is used. /// distance of time in words public static string Humanize(this TimeOnly input, TimeOnly? timeToCompareAgainst = null, bool useUtc = true, CultureInfo? culture = null) { var comparisonBase = timeToCompareAgainst ?? TimeOnly.FromDateTime(useUtc ? DateTime.UtcNow : DateTime.Now); return Configurator.TimeOnlyHumanizeStrategy.Humanize(input, comparisonBase, culture); } /// /// Turns the current or provided time into a human readable sentence, overload for the nullable TimeOnly, returning 'never' in case null /// /// The date to be humanized /// If is null, used to determine if the current time is UTC or local. Defaults to UTC. /// Time to compare the input against. If null, current date is used as base /// Culture to use. If null, current thread's UI culture is used. /// distance of time in words public static string Humanize(this TimeOnly? input, TimeOnly? timeToCompareAgainst = null, bool useUtc = true, CultureInfo? culture = null) { if (input.HasValue) { return Humanize(input.Value, timeToCompareAgainst, useUtc, culture); } return Configurator .GetFormatter(culture) .DateHumanize_Never(); } #endif } ================================================ FILE: src/Humanizer/DateTimeHumanizeStrategy/DateTimeHumanizeAlgorithms.cs ================================================ namespace Humanizer; /// /// Algorithms used to convert distance between two dates into words. /// static class DateTimeHumanizeAlgorithms { /// /// Returns localized & humanized distance of time between two dates; given a specific precision. /// public static string PrecisionHumanize(DateTime input, DateTime comparisonBase, double precision, CultureInfo? culture) { var ts = new TimeSpan(Math.Abs(comparisonBase.Ticks - input.Ticks)); var tense = input > comparisonBase ? Tense.Future : Tense.Past; return PrecisionHumanize(ts, tense, precision, culture); } #if NET6_0_OR_GREATER /// /// Returns localized & humanized distance of time between two dates; given a specific precision. /// public static string PrecisionHumanize(DateOnly input, DateOnly comparisonBase, double precision, CultureInfo? culture) { var diffDays = Math.Abs(comparisonBase.DayOfYear - input.DayOfYear); var ts = new TimeSpan(diffDays, 0, 0, 0); var tense = input > comparisonBase ? Tense.Future : Tense.Past; return PrecisionHumanize(ts, tense, precision, culture); } /// /// Returns localized & humanized distance of time between two times; given a specific precision. /// public static string PrecisionHumanize(TimeOnly input, TimeOnly comparisonBase, double precision, CultureInfo? culture) { var ts = new TimeSpan(Math.Abs(comparisonBase.Ticks - input.Ticks)); var tense = input > comparisonBase ? Tense.Future : Tense.Past; return PrecisionHumanize(ts, tense, precision, culture); } #endif static string PrecisionHumanize(TimeSpan ts, Tense tense, double precision, CultureInfo? culture) { int seconds = ts.Seconds, minutes = ts.Minutes, hours = ts.Hours, days = ts.Days; int years = 0, months = 0; // start approximate from smaller units towards bigger ones if (ts.Milliseconds >= 999 * precision) { seconds += 1; } if (seconds >= 59 * precision) { minutes += 1; } if (minutes >= 59 * precision) { hours += 1; } if (hours >= 23 * precision) { days += 1; } // month calculation if (days >= 30 * precision & days <= 31) { months = 1; } if (days > 31 && days < 365 * precision) { var factor = Convert.ToInt32(Math.Floor((double)days / 30)); var maxMonths = Convert.ToInt32(Math.Ceiling((double)days / 30)); months = days >= 30 * (factor + precision) ? maxMonths : maxMonths - 1; } // year calculation if (days >= 365 * precision && days <= 366) { years = 1; } if (days > 365) { var factor = Convert.ToInt32(Math.Floor((double)days / 365)); var maxMonths = Convert.ToInt32(Math.Ceiling((double)days / 365)); years = days >= 365 * (factor + precision) ? maxMonths : maxMonths - 1; } // start computing result from larger units to smaller ones var formatter = Configurator.GetFormatter(culture); if (years > 0) { return formatter.DateHumanize(TimeUnit.Year, tense, years); } if (months > 0) { return formatter.DateHumanize(TimeUnit.Month, tense, months); } if (days > 0) { return formatter.DateHumanize(TimeUnit.Day, tense, days); } if (hours > 0) { return formatter.DateHumanize(TimeUnit.Hour, tense, hours); } if (minutes > 0) { return formatter.DateHumanize(TimeUnit.Minute, tense, minutes); } if (seconds > 0) { return formatter.DateHumanize(TimeUnit.Second, tense, seconds); } return formatter.DateHumanize(TimeUnit.Millisecond, tense, 0); } // http://stackoverflow.com/questions/11/how-do-i-calculate-relative-time /// /// Calculates the distance of time in words between two provided dates /// public static string DefaultHumanize(DateTime input, DateTime comparisonBase, CultureInfo? culture) { var tense = input > comparisonBase ? Tense.Future : Tense.Past; var ts = new TimeSpan(Math.Abs(comparisonBase.Ticks - input.Ticks)); var sameMonth = comparisonBase.Date.AddMonths(tense == Tense.Future ? 1 : -1) == input.Date; var days = Math.Abs((input.Date - comparisonBase.Date).Days); return DefaultHumanize(ts, sameMonth, days, tense, culture); } #if NET6_0_OR_GREATER /// /// Calculates the distance of time in words between two provided dates /// public static string DefaultHumanize(DateOnly input, DateOnly comparisonBase, CultureInfo? culture) { var tense = input > comparisonBase ? Tense.Future : Tense.Past; var diffDays = Math.Abs(comparisonBase.DayNumber - input.DayNumber); var ts = new TimeSpan(diffDays, 0, 0, 0); var sameMonth = comparisonBase.AddMonths(tense == Tense.Future ? 1 : -1) == input; var days = Math.Abs(input.DayNumber - comparisonBase.DayNumber); return DefaultHumanize(ts, sameMonth, days, tense, culture); } /// /// Calculates the distance of time in words between two provided times /// public static string DefaultHumanize(TimeOnly input, TimeOnly comparisonBase, CultureInfo? culture) { var tense = input > comparisonBase ? Tense.Future : Tense.Past; var ts = new TimeSpan(Math.Abs(comparisonBase.Ticks - input.Ticks)); return DefaultHumanize(ts, true, 0, tense, culture); } #endif static string DefaultHumanize(TimeSpan ts, bool sameMonth, int days, Tense tense, CultureInfo? culture) { var formatter = Configurator.GetFormatter(culture); if (ts.TotalMilliseconds < 500) { return formatter.DateHumanize(TimeUnit.Millisecond, tense, 0); } if (ts.TotalSeconds < 60) { return formatter.DateHumanize(TimeUnit.Second, tense, ts.Seconds); } if (ts.TotalSeconds < 120) { return formatter.DateHumanize(TimeUnit.Minute, tense, 1); } if (ts.TotalMinutes < 60) { return formatter.DateHumanize(TimeUnit.Minute, tense, ts.Minutes); } if (ts.TotalMinutes < 90) { return formatter.DateHumanize(TimeUnit.Hour, tense, 1); } if (ts.TotalHours < 24) { return formatter.DateHumanize(TimeUnit.Hour, tense, ts.Hours); } if (ts.TotalHours < 48) { return formatter.DateHumanize(TimeUnit.Day, tense, days); } if (ts.TotalDays < 28) { return formatter.DateHumanize(TimeUnit.Day, tense, ts.Days); } if (ts.TotalDays is >= 28 and < 30) { if (sameMonth) { return formatter.DateHumanize(TimeUnit.Month, tense, 1); } return formatter.DateHumanize(TimeUnit.Day, tense, ts.Days); } if (ts.TotalDays < 345) { var months = Convert.ToInt32(Math.Floor(ts.TotalDays / 29.5)); return formatter.DateHumanize(TimeUnit.Month, tense, months); } var years = Convert.ToInt32(Math.Floor(ts.TotalDays / 365)); if (years == 0) { years = 1; } return formatter.DateHumanize(TimeUnit.Year, tense, years); } } ================================================ FILE: src/Humanizer/DateTimeHumanizeStrategy/DefaultDateOnlyHumanizeStrategy.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; /// /// The default 'distance of time' -> words calculator. /// public class DefaultDateOnlyHumanizeStrategy : IDateOnlyHumanizeStrategy { /// /// Calculates the distance of time in words between two provided dates /// public string Humanize(DateOnly input, DateOnly comparisonBase, CultureInfo? culture) => DateTimeHumanizeAlgorithms.DefaultHumanize(input, comparisonBase, culture); } #endif ================================================ FILE: src/Humanizer/DateTimeHumanizeStrategy/DefaultDateTimeHumanizeStrategy.cs ================================================ namespace Humanizer; /// /// The default 'distance of time' -> words calculator. /// public class DefaultDateTimeHumanizeStrategy : IDateTimeHumanizeStrategy { /// /// Calculates the distance of time in words between two provided dates /// public string Humanize(DateTime input, DateTime comparisonBase, CultureInfo? culture) => DateTimeHumanizeAlgorithms.DefaultHumanize(input, comparisonBase, culture); } ================================================ FILE: src/Humanizer/DateTimeHumanizeStrategy/DefaultDateTimeOffsetHumanizeStrategy.cs ================================================ namespace Humanizer; /// /// The default 'distance of time' -> words calculator. /// public class DefaultDateTimeOffsetHumanizeStrategy : IDateTimeOffsetHumanizeStrategy { /// /// Calculates the distance of time in words between two provided dates /// public string Humanize(DateTimeOffset input, DateTimeOffset comparisonBase, CultureInfo? culture) => DateTimeHumanizeAlgorithms.DefaultHumanize(input.UtcDateTime, comparisonBase.UtcDateTime, culture); } ================================================ FILE: src/Humanizer/DateTimeHumanizeStrategy/DefaultTimeOnlyHumanizeStrategy.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; /// /// The default 'distance of time' -> words calculator. /// public class DefaultTimeOnlyHumanizeStrategy : ITimeOnlyHumanizeStrategy { /// /// Calculates the distance of time in words between two provided times /// public string Humanize(TimeOnly input, TimeOnly comparisonBase, CultureInfo? culture) => DateTimeHumanizeAlgorithms.DefaultHumanize(input, comparisonBase, culture); } #endif ================================================ FILE: src/Humanizer/DateTimeHumanizeStrategy/IDateOnlyHumanizeStrategy.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; /// /// Implement this interface to create a new strategy for DateOnly.Humanize and hook it in the Configurator.DateOnlyHumanizeStrategy /// public interface IDateOnlyHumanizeStrategy { /// /// Calculates the distance of time in words between two provided dates used for DateOnly.Humanize /// string Humanize(DateOnly input, DateOnly comparisonBase, CultureInfo? culture); } #endif ================================================ FILE: src/Humanizer/DateTimeHumanizeStrategy/IDateTimeHumanizeStrategy.cs ================================================ namespace Humanizer; /// /// Implement this interface to create a new strategy for DateTime.Humanize and hook it in the Configurator.DateTimeHumanizeStrategy /// public interface IDateTimeHumanizeStrategy { /// /// Calculates the distance of time in words between two provided dates used for DateTime.Humanize /// string Humanize(DateTime input, DateTime comparisonBase, CultureInfo? culture); } ================================================ FILE: src/Humanizer/DateTimeHumanizeStrategy/IDateTimeOffsetHumanizeStrategy.cs ================================================ namespace Humanizer; /// /// Implement this interface to create a new strategy for DateTime.Humanize and hook it in the Configurator.DateTimeOffsetHumanizeStrategy /// public interface IDateTimeOffsetHumanizeStrategy { /// /// Calculates the distance of time in words between two provided dates used for DateTimeOffset.Humanize /// string Humanize(DateTimeOffset input, DateTimeOffset comparisonBase, CultureInfo? culture); } ================================================ FILE: src/Humanizer/DateTimeHumanizeStrategy/ITimeOnlyHumanizeStrategy.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; /// /// Implement this interface to create a new strategy for TimeOnly.Humanize and hook it in the Configurator.TimeOnlyHumanizeStrategy /// public interface ITimeOnlyHumanizeStrategy { /// /// Calculates the distance of time in words between two provided dates used for TimeOnly.Humanize /// string Humanize(TimeOnly input, TimeOnly comparisonBase, CultureInfo? culture); } #endif ================================================ FILE: src/Humanizer/DateTimeHumanizeStrategy/PrecisionDateOnlyHumanizeStrategy.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; /// /// Precision-based calculator for distance between two times /// /// /// Constructs a precision-based calculator for distance of time with default precision 0.75. /// /// precision of approximation, if not provided 0.75 will be used as a default precision. public class PrecisionDateOnlyHumanizeStrategy(double precision = .75) : IDateOnlyHumanizeStrategy { readonly double precision = precision; /// /// Returns localized & humanized distance of time between two dates; given a specific precision. /// public string Humanize(DateOnly input, DateOnly comparisonBase, CultureInfo? culture) => DateTimeHumanizeAlgorithms.PrecisionHumanize(input, comparisonBase, precision, culture); } #endif ================================================ FILE: src/Humanizer/DateTimeHumanizeStrategy/PrecisionDateTimeHumanizeStrategy.cs ================================================ namespace Humanizer; /// /// Precision-based calculator for distance between two times /// /// /// Constructs a precision-based calculator for distance of time with default precision 0.75. /// /// precision of approximation, if not provided 0.75 will be used as a default precision. public class PrecisionDateTimeHumanizeStrategy(double precision = .75) : IDateTimeHumanizeStrategy { readonly double precision = precision; /// /// Returns localized & humanized distance of time between two dates; given a specific precision. /// public string Humanize(DateTime input, DateTime comparisonBase, CultureInfo? culture) => DateTimeHumanizeAlgorithms.PrecisionHumanize(input, comparisonBase, precision, culture); } ================================================ FILE: src/Humanizer/DateTimeHumanizeStrategy/PrecisionDateTimeOffsetHumanizeStrategy.cs ================================================ namespace Humanizer; /// /// Precision-based calculator for distance between two times /// /// /// Constructs a precision-based calculator for distance of time with default precision 0.75. /// /// precision of approximation, if not provided 0.75 will be used as a default precision. public class PrecisionDateTimeOffsetHumanizeStrategy(double precision = .75) : IDateTimeOffsetHumanizeStrategy { readonly double precision = precision; /// /// Returns localized & humanized distance of time between two dates; given a specific precision. /// public string Humanize(DateTimeOffset input, DateTimeOffset comparisonBase, CultureInfo? culture) => DateTimeHumanizeAlgorithms.PrecisionHumanize(input.UtcDateTime, comparisonBase.UtcDateTime, precision, culture); } ================================================ FILE: src/Humanizer/DateTimeHumanizeStrategy/PrecisionTimeOnlyHumanizeStrategy.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; /// /// Precision-based calculator for distance between two times /// /// /// Constructs a precision-based calculator for distance of time with default precision 0.75. /// /// precision of approximation, if not provided 0.75 will be used as a default precision. public class PrecisionTimeOnlyHumanizeStrategy(double precision = .75) : ITimeOnlyHumanizeStrategy { readonly double precision = precision; /// /// Returns localized & humanized distance of time between two dates; given a specific precision. /// public string Humanize(TimeOnly input, TimeOnly comparisonBase, CultureInfo? culture) => DateTimeHumanizeAlgorithms.PrecisionHumanize(input, comparisonBase, precision, culture); } #endif ================================================ FILE: src/Humanizer/DateToOrdinalWordsExtensions.cs ================================================ namespace Humanizer; /// /// Humanizes DateTime into human readable sentence /// public static class DateToOrdinalWordsExtensions { /// /// Converts a to its ordinal words representation (e.g., "1st of January, 2023"). /// /// The date to be converted to ordinal words. /// /// A string containing the date expressed in ordinal words format, culture-specific. /// For English: "1st of January, 2023", "22nd of December, 2020", etc. /// /// /// The format and style of ordinal words depends on the current culture. /// Uses the configured date-to-ordinal-words converter for conversion. /// /// /// /// new DateTime(2023, 1, 1).ToOrdinalWords() => "1st of January, 2023" (in en-US culture) /// new DateTime(2020, 12, 22).ToOrdinalWords() => "22nd of December, 2020" (in en-US culture) /// /// public static string ToOrdinalWords(this DateTime input) => Configurator.DateToOrdinalWordsConverter.Convert(input); /// /// Converts a to its ordinal words representation using the specified grammatical case. /// /// The date to be converted to ordinal words. /// /// The grammatical case to use for the output words (e.g., Nominative, Genitive, etc.). /// This is particularly important for languages with case systems like Russian, Polish, etc. /// /// /// A string containing the date expressed in ordinal words format in the specified grammatical case. /// /// /// The grammatical case parameter is primarily used by languages that have case systems. /// For languages without grammatical cases (like English), this parameter has no effect. /// /// /// /// // In Russian culture: /// date.ToOrdinalWords(GrammaticalCase.Nominative) => different form than /// date.ToOrdinalWords(GrammaticalCase.Genitive) /// /// public static string ToOrdinalWords(this DateTime input, GrammaticalCase grammaticalCase) => Configurator.DateToOrdinalWordsConverter.Convert(input, grammaticalCase); #if NET6_0_OR_GREATER /// /// Converts a to its ordinal words representation (e.g., "1st of January, 2023"). /// /// The date to be converted to ordinal words. /// /// A string containing the date expressed in ordinal words format, culture-specific. /// For English: "1st of January, 2023", "22nd of December, 2020", etc. /// /// /// The format and style of ordinal words depends on the current culture. /// Uses the configured date-only-to-ordinal-words converter for conversion. /// This method is available only on .NET 6.0 and later. /// /// /// /// new DateOnly(2023, 1, 1).ToOrdinalWords() => "1st of January, 2023" (in en-US culture) /// new DateOnly(2020, 12, 22).ToOrdinalWords() => "22nd of December, 2020" (in en-US culture) /// /// public static string ToOrdinalWords(this DateOnly input) => Configurator.DateOnlyToOrdinalWordsConverter.Convert(input); /// /// Converts a to its ordinal words representation using the specified grammatical case. /// /// The date to be converted to ordinal words. /// /// The grammatical case to use for the output words (e.g., Nominative, Genitive, etc.). /// This is particularly important for languages with case systems like Russian, Polish, etc. /// /// /// A string containing the date expressed in ordinal words format in the specified grammatical case. /// /// /// The grammatical case parameter is primarily used by languages that have case systems. /// For languages without grammatical cases (like English), this parameter has no effect. /// This method is available only on .NET 6.0 and later. /// /// /// /// // In Russian culture: /// date.ToOrdinalWords(GrammaticalCase.Nominative) => different form than /// date.ToOrdinalWords(GrammaticalCase.Genitive) /// /// public static string ToOrdinalWords(this DateOnly input, GrammaticalCase grammaticalCase) => Configurator.DateOnlyToOrdinalWordsConverter.Convert(input, grammaticalCase); #endif } ================================================ FILE: src/Humanizer/EnumCache.cs ================================================ using System.ComponentModel.DataAnnotations; namespace Humanizer; static class EnumCache<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] T> where T : struct, Enum { [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] static readonly Type TypeOfT = typeof(T); static readonly (T Zero, FrozenDictionary Humanized, FrozenDictionary Dehumanized, FrozenSet Values, bool IsBitFieldEnum) Info = CreateInfo(); private static (T Zero, FrozenDictionary Humanized, FrozenDictionary Dehumanized, FrozenSet Values, bool IsBitFieldEnum) CreateInfo() { var valuesArray = Enum.GetValues(); var zero = (T)Convert.ChangeType(Enum.ToObject(TypeOfT, 0), TypeOfT); var count = valuesArray.Length; var humanized = new Dictionary(count); var dehumanized = new Dictionary(count, StringComparer.OrdinalIgnoreCase); foreach (var value in valuesArray) { var description = GetDescription(value); humanized[value] = description; dehumanized[description] = value; } var isBitFieldEnum = TypeOfT.GetCustomAttribute() != null; return ( zero, humanized.ToFrozenDictionary(), dehumanized.ToFrozenDictionary(StringComparer.OrdinalIgnoreCase), valuesArray.ToFrozenSet(), isBitFieldEnum); } public static (T Zero, FrozenDictionary Humanized, FrozenSet Values) GetInfo() => (Info.Zero, Info.Humanized, Info.Values); public static FrozenDictionary GetDehumanized() => Info.Dehumanized; public static bool TreatAsFlags(T input) { if (!Info.IsBitFieldEnum) { return false; } return !Enum.IsDefined(TypeOfT, input); } static string GetDescription(T input) { #if NET5_0_OR_GREATER var caseName = Enum.GetName(input)!; #else var caseName = Enum.GetName(TypeOfT, input)!; #endif var member = TypeOfT.GetField(caseName)!; if (TryGetDescription(member, out var description)) { return description; } return caseName.Humanize(); } [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = "Reflection over attribute properties is intentional and documented.")] static bool TryGetDescription(MemberInfo member, [NotNullWhen(true)] out string? description) { var displayAttribute = member.GetCustomAttribute(); if (displayAttribute != null) { description = displayAttribute.GetDescription() ?? displayAttribute.GetName(); return description != null; } foreach (var attr in member.GetCustomAttributes()) { #pragma warning disable IL2072 // Target parameter argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The return value of the source method does not have matching annotations. var attrType = attr.GetType(); foreach (var property in attrType.GetRuntimeProperties()) #pragma warning restore IL2072 { if (property.PropertyType == typeof(string) && Configurator.EnumDescriptionPropertyLocator(property)) { description = (string)property.GetValue(attr, null)!; return true; } } } description = null; return false; } } ================================================ FILE: src/Humanizer/EnumDehumanizeExtensions.cs ================================================ namespace Humanizer; /// /// Contains extension methods for dehumanizing Enum string values. /// public static class EnumDehumanizeExtensions { /// /// Converts a humanized string back to its original enum value by matching it against enum member names /// and their humanized representations (including values). /// /// The enum type to convert to. Must be a struct and implement . /// The humanized string to be converted back to an enum value. Must not be null. /// /// The enum value that matches the input string. /// /// Thrown when is not an enum type. /// /// Thrown when no enum member matches the input string (including checking member names, /// humanized names, and description attributes). /// /// /// The method attempts to match the input string against: /// 1. The exact enum member name /// 2. The humanized version of the enum member name /// 3. Any value on the enum member /// Matching is case-sensitive. /// /// /// /// enum UserType { AnonymousUser, RegisteredUser } /// "Anonymous user".DehumanizeTo<UserType>() => UserType.AnonymousUser /// "Registered user".DehumanizeTo<UserType>() => UserType.RegisteredUser /// "AnonymousUser".DehumanizeTo<UserType>() => UserType.AnonymousUser /// /// public static TTargetEnum DehumanizeTo<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] TTargetEnum>(this string input) where TTargetEnum : struct, Enum => DehumanizeToPrivate(input, OnNoMatch.ThrowsException)!.Value; /// /// Converts a humanized string back to its original enum value with configurable behavior when no match is found. /// /// The enum type to convert to. Must be a struct and implement . /// The humanized string to be converted back to an enum value. Must not be null. /// /// Specifies what to do when no matching enum member is found. /// Default is . /// /// /// The enum value that matches the input string, or null if no match is found and /// is set to . /// /// Thrown when is not an enum type. /// /// Thrown when no enum member matches the input string and is set to /// . /// /// /// This overload provides more control over error handling compared to the parameterless version. /// /// /// /// enum UserType { AnonymousUser, RegisteredUser } /// "Anonymous user".DehumanizeTo<UserType>() => UserType.AnonymousUser /// "Invalid".DehumanizeTo<UserType>(OnNoMatch.ReturnsNull) => null /// "Invalid".DehumanizeTo<UserType>(OnNoMatch.ThrowsException) => throws NoMatchFoundException /// /// public static TTargetEnum? DehumanizeTo<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] TTargetEnum>(this string input, OnNoMatch onNoMatch = OnNoMatch.ThrowsException) where TTargetEnum : struct, Enum => DehumanizeToPrivate(input, onNoMatch); #if NET6_0_OR_GREATER [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "The method is only used by DehumanizeTo which already has RequiresUnreferencedCode")] [UnconditionalSuppressMessage("Trimming", "IL2111", Justification = "The method is only used by DehumanizeTo which already has RequiresUnreferencedCode")] [UnconditionalSuppressMessage("AOT", "IL3050", Justification = "The method is only used by DehumanizeTo which already has RequiresDynamicCode")] #endif static MethodInfo GetDehumanizeToMethodInfo() => typeof(EnumDehumanizeExtensions).GetMethod("DehumanizeTo", [typeof(string), typeof(OnNoMatch)])!; static readonly Lazy DehumanizeToMethod = new(GetDehumanizeToMethodInfo); /// /// Converts a humanized string back to its original enum value using runtime type information. /// This is a non-generic overload that accepts the target enum type as a parameter. /// /// The humanized string to be converted back to an enum value. Must not be null. /// /// The of the target enum. Must be an enum type. /// /// /// Specifies what to do when no matching enum member is found. /// Default is . /// /// /// The enum value (as ) that matches the input string. /// /// /// Thrown when no enum member matches the input string and is set to /// . /// /// Thrown when is not an enum type. /// /// This method uses reflection and is less type-safe than the generic overload. Use the generic /// method when the target enum type is known at compile time. /// /// /// /// enum UserType { AnonymousUser, RegisteredUser } /// "Anonymous user".DehumanizeTo(typeof(UserType)) => UserType.AnonymousUser (as Enum) /// /// #if NET6_0_OR_GREATER [RequiresDynamicCode("The native code for the target enumeration might not be available at runtime.")] [RequiresUnreferencedCode("The native code for the target enumeration might not be available at runtime.")] [DynamicDependency(DynamicallyAccessedMemberTypes.PublicMethods, typeof(EnumDehumanizeExtensions))] #endif public static Enum DehumanizeTo(this string input, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] Type targetEnum, OnNoMatch onNoMatch = OnNoMatch.ThrowsException) { var genericMethod = DehumanizeToMethod.Value.MakeGenericMethod(targetEnum); try { return (Enum)genericMethod.Invoke(null, [input, onNoMatch])!; } catch (TargetInvocationException exception) { throw exception.InnerException!; } } static T? DehumanizeToPrivate<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] T>(string input, OnNoMatch onNoMatch) where T : struct, Enum { var dehumanized = EnumCache.GetDehumanized(); if (dehumanized.TryGetValue(input, out var value)) { return value; } if (onNoMatch != OnNoMatch.ThrowsException) { return null; } throw new NoMatchFoundException($"Couldn't find any enum member that matches the string '{input}'"); } } ================================================ FILE: src/Humanizer/EnumHumanizeExtensions.cs ================================================ namespace Humanizer; /// /// Contains extension methods for humanizing Enums /// public static class EnumHumanizeExtensions { /// /// Converts an enum value to a human-readable string by intelligently formatting the enum member name /// and respecting any applied to the member. /// /// The enum type. Must be a struct and implement . /// The enum value to be humanized. /// /// A human-readable string representation of the enum value. /// If the enum has the and multiple flags are set, returns a humanized, /// comma-separated list of the flag values. /// If a is present on the enum member, its value is returned. /// Otherwise, the enum member name is humanized (e.g., "AnonymousUser" becomes "Anonymous user"). /// /// /// For flags enums, only non-zero flags are included in the output, and each flag is humanized individually. /// The humanization process converts PascalCase to space-separated text with appropriate capitalization. /// /// /// /// enum UserType { AnonymousUser, RegisteredUser } /// UserType.AnonymousUser.Humanize() => "Anonymous user" /// /// [Flags] /// enum Permission { None = 0, Read = 1, Write = 2, Delete = 4 } /// (Permission.Read | Permission.Write).Humanize() => "Read, Write" /// /// enum Status /// { /// [Description("Currently active")] /// Active /// } /// Status.Active.Humanize() => "Currently active" /// /// public static string Humanize<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] T>(this T input) where T : struct, Enum { var (zero, humanized, values) = EnumCache.GetInfo(); if (EnumCache.TreatAsFlags(input)) { // Avoid LINQ allocations by manually iterating and building the list List? flagValues = null; foreach (var value in values) { if (value.CompareTo(zero) != 0 && input.HasFlag(value)) { flagValues ??= new List(); flagValues.Add(humanized[value]); } } return flagValues?.Humanize() ?? string.Empty; } return humanized[input]; } /// /// Converts an enum value to a human-readable string with the specified letter casing applied. /// Respects any applied to the enum member. /// /// The enum type. Must be a struct and implement . /// The enum value to be humanized. /// The desired letter casing to apply to the humanized enum value. /// /// A human-readable string representation of the enum value with the specified casing applied. /// If a is present, its value is used and then cased. /// /// /// This is a convenience method that combines with . /// /// /// /// enum UserType { AnonymousUser, RegisteredUser } /// UserType.AnonymousUser.Humanize(LetterCasing.AllCaps) => "ANONYMOUS USER" /// UserType.AnonymousUser.Humanize(LetterCasing.Title) => "Anonymous User" /// UserType.AnonymousUser.Humanize(LetterCasing.LowerCase) => "anonymous user" /// /// public static string Humanize<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] T>(this T input, LetterCasing casing) where T : struct, Enum { var humanizedEnum = Humanize(input); return humanizedEnum.ApplyCase(casing); } } ================================================ FILE: src/Humanizer/FluentDate/In.Months.cs ================================================ namespace Humanizer; public partial class In { /// /// Returns 1st of January of the current year /// public static DateTime January => new(DateTime.UtcNow.Year, 1, 1); /// /// Returns 1st of January of the year passed in /// public static DateTime JanuaryOf(int year) => new(year, 1, 1); /// /// Returns 1st of February of the current year /// public static DateTime February => new(DateTime.UtcNow.Year, 2, 1); /// /// Returns 1st of February of the year passed in /// public static DateTime FebruaryOf(int year) => new(year, 2, 1); /// /// Returns 1st of March of the current year /// public static DateTime March => new(DateTime.UtcNow.Year, 3, 1); /// /// Returns 1st of March of the year passed in /// public static DateTime MarchOf(int year) => new(year, 3, 1); /// /// Returns 1st of April of the current year /// public static DateTime April => new(DateTime.UtcNow.Year, 4, 1); /// /// Returns 1st of April of the year passed in /// public static DateTime AprilOf(int year) => new(year, 4, 1); /// /// Returns 1st of May of the current year /// public static DateTime May => new(DateTime.UtcNow.Year, 5, 1); /// /// Returns 1st of May of the year passed in /// public static DateTime MayOf(int year) => new(year, 5, 1); /// /// Returns 1st of June of the current year /// public static DateTime June => new(DateTime.UtcNow.Year, 6, 1); /// /// Returns 1st of June of the year passed in /// public static DateTime JuneOf(int year) => new(year, 6, 1); /// /// Returns 1st of July of the current year /// public static DateTime July => new(DateTime.UtcNow.Year, 7, 1); /// /// Returns 1st of July of the year passed in /// public static DateTime JulyOf(int year) => new(year, 7, 1); /// /// Returns 1st of August of the current year /// public static DateTime August => new(DateTime.UtcNow.Year, 8, 1); /// /// Returns 1st of August of the year passed in /// public static DateTime AugustOf(int year) => new(year, 8, 1); /// /// Returns 1st of September of the current year /// public static DateTime September => new(DateTime.UtcNow.Year, 9, 1); /// /// Returns 1st of September of the year passed in /// public static DateTime SeptemberOf(int year) => new(year, 9, 1); /// /// Returns 1st of October of the current year /// public static DateTime October => new(DateTime.UtcNow.Year, 10, 1); /// /// Returns 1st of October of the year passed in /// public static DateTime OctoberOf(int year) => new(year, 10, 1); /// /// Returns 1st of November of the current year /// public static DateTime November => new(DateTime.UtcNow.Year, 11, 1); /// /// Returns 1st of November of the year passed in /// public static DateTime NovemberOf(int year) => new(year, 11, 1); /// /// Returns 1st of December of the current year /// public static DateTime December => new(DateTime.UtcNow.Year, 12, 1); /// /// Returns 1st of December of the year passed in /// public static DateTime DecemberOf(int year) => new(year, 12, 1); } ================================================ FILE: src/Humanizer/FluentDate/In.Months.tt ================================================ <#@ template debug="true" hostSpecific="true" #> <#@ output extension=".cs" #> <#@ Assembly Name="System.Core" #> <#@ Assembly Name="System.Windows.Forms" #> <#@ import namespace="System" #> namespace Humanizer; public partial class In { <#var now = DateTime.Now; for (var i = 0; i < 12; i++){ var monthName = new DateTime(now.Year, i + 1, 1).ToString("MMMM"); #> /// /// Returns 1st of <#= monthName #> of the current year /// public static DateTime <#= monthName #> => new(DateTime.UtcNow.Year, <#= i + 1 #>, 1); /// /// Returns 1st of <#= monthName #> of the year passed in /// public static DateTime <#= monthName#>Of(int year) => new(year, <#= i + 1 #>, 1); <#} #> } ================================================ FILE: src/Humanizer/FluentDate/In.SomeTimeFrom.cs ================================================ namespace Humanizer; /// /// public partial class In { /// /// public static class One { /// /// 1 seconds from now /// public static DateTime Second => DateTime.UtcNow.AddSeconds(1); /// /// 1 seconds from the provided date /// public static DateTime SecondFrom(DateTime date) => date.AddSeconds(1); /// /// 1 minutes from now /// public static DateTime Minute => DateTime.UtcNow.AddMinutes(1); /// /// 1 minutes from the provided date /// public static DateTime MinuteFrom(DateTime date) => date.AddMinutes(1); /// /// 1 hours from now /// public static DateTime Hour => DateTime.UtcNow.AddHours(1); /// /// 1 hours from the provided date /// public static DateTime HourFrom(DateTime date) => date.AddHours(1); /// /// 1 days from now /// public static DateTime Day => DateTime.UtcNow.AddDays(1); /// /// 1 days from the provided date /// public static DateTime DayFrom(DateTime date) => date.AddDays(1); /// /// 1 weeks from now /// public static DateTime Week => DateTime.UtcNow.AddDays(7); /// /// 1 weeks from the provided date /// public static DateTime WeekFrom(DateTime date) => date.AddDays(7); /// /// 1 months from now /// public static DateTime Month => DateTime.UtcNow.AddMonths(1); /// /// 1 months from the provided date /// public static DateTime MonthFrom(DateTime date) => date.AddMonths(1); /// /// 1 years from now /// public static DateTime Year => DateTime.UtcNow.AddYears(1); /// /// 1 years from the provided date /// public static DateTime YearFrom(DateTime date) => date.AddYears(1); } /// /// public static class Two { /// /// 2 seconds from now /// public static DateTime Seconds => DateTime.UtcNow.AddSeconds(2); /// /// 2 seconds from the provided date /// public static DateTime SecondsFrom(DateTime date) => date.AddSeconds(2); /// /// 2 minutes from now /// public static DateTime Minutes => DateTime.UtcNow.AddMinutes(2); /// /// 2 minutes from the provided date /// public static DateTime MinutesFrom(DateTime date) => date.AddMinutes(2); /// /// 2 hours from now /// public static DateTime Hours => DateTime.UtcNow.AddHours(2); /// /// 2 hours from the provided date /// public static DateTime HoursFrom(DateTime date) => date.AddHours(2); /// /// 2 days from now /// public static DateTime Days => DateTime.UtcNow.AddDays(2); /// /// 2 days from the provided date /// public static DateTime DaysFrom(DateTime date) => date.AddDays(2); /// /// 2 weeks from now /// public static DateTime Weeks => DateTime.UtcNow.AddDays(14); /// /// 2 weeks from the provided date /// public static DateTime WeeksFrom(DateTime date) => date.AddDays(14); /// /// 2 months from now /// public static DateTime Months => DateTime.UtcNow.AddMonths(2); /// /// 2 months from the provided date /// public static DateTime MonthsFrom(DateTime date) => date.AddMonths(2); /// /// 2 years from now /// public static DateTime Years => DateTime.UtcNow.AddYears(2); /// /// 2 years from the provided date /// public static DateTime YearsFrom(DateTime date) => date.AddYears(2); } /// /// public static class Three { /// /// 3 seconds from now /// public static DateTime Seconds => DateTime.UtcNow.AddSeconds(3); /// /// 3 seconds from the provided date /// public static DateTime SecondsFrom(DateTime date) => date.AddSeconds(3); /// /// 3 minutes from now /// public static DateTime Minutes => DateTime.UtcNow.AddMinutes(3); /// /// 3 minutes from the provided date /// public static DateTime MinutesFrom(DateTime date) => date.AddMinutes(3); /// /// 3 hours from now /// public static DateTime Hours => DateTime.UtcNow.AddHours(3); /// /// 3 hours from the provided date /// public static DateTime HoursFrom(DateTime date) => date.AddHours(3); /// /// 3 days from now /// public static DateTime Days => DateTime.UtcNow.AddDays(3); /// /// 3 days from the provided date /// public static DateTime DaysFrom(DateTime date) => date.AddDays(3); /// /// 3 weeks from now /// public static DateTime Weeks => DateTime.UtcNow.AddDays(21); /// /// 3 weeks from the provided date /// public static DateTime WeeksFrom(DateTime date) => date.AddDays(21); /// /// 3 months from now /// public static DateTime Months => DateTime.UtcNow.AddMonths(3); /// /// 3 months from the provided date /// public static DateTime MonthsFrom(DateTime date) => date.AddMonths(3); /// /// 3 years from now /// public static DateTime Years => DateTime.UtcNow.AddYears(3); /// /// 3 years from the provided date /// public static DateTime YearsFrom(DateTime date) => date.AddYears(3); } /// /// public static class Four { /// /// 4 seconds from now /// public static DateTime Seconds => DateTime.UtcNow.AddSeconds(4); /// /// 4 seconds from the provided date /// public static DateTime SecondsFrom(DateTime date) => date.AddSeconds(4); /// /// 4 minutes from now /// public static DateTime Minutes => DateTime.UtcNow.AddMinutes(4); /// /// 4 minutes from the provided date /// public static DateTime MinutesFrom(DateTime date) => date.AddMinutes(4); /// /// 4 hours from now /// public static DateTime Hours => DateTime.UtcNow.AddHours(4); /// /// 4 hours from the provided date /// public static DateTime HoursFrom(DateTime date) => date.AddHours(4); /// /// 4 days from now /// public static DateTime Days => DateTime.UtcNow.AddDays(4); /// /// 4 days from the provided date /// public static DateTime DaysFrom(DateTime date) => date.AddDays(4); /// /// 4 weeks from now /// public static DateTime Weeks => DateTime.UtcNow.AddDays(28); /// /// 4 weeks from the provided date /// public static DateTime WeeksFrom(DateTime date) => date.AddDays(28); /// /// 4 months from now /// public static DateTime Months => DateTime.UtcNow.AddMonths(4); /// /// 4 months from the provided date /// public static DateTime MonthsFrom(DateTime date) => date.AddMonths(4); /// /// 4 years from now /// public static DateTime Years => DateTime.UtcNow.AddYears(4); /// /// 4 years from the provided date /// public static DateTime YearsFrom(DateTime date) => date.AddYears(4); } /// /// public static class Five { /// /// 5 seconds from now /// public static DateTime Seconds => DateTime.UtcNow.AddSeconds(5); /// /// 5 seconds from the provided date /// public static DateTime SecondsFrom(DateTime date) => date.AddSeconds(5); /// /// 5 minutes from now /// public static DateTime Minutes => DateTime.UtcNow.AddMinutes(5); /// /// 5 minutes from the provided date /// public static DateTime MinutesFrom(DateTime date) => date.AddMinutes(5); /// /// 5 hours from now /// public static DateTime Hours => DateTime.UtcNow.AddHours(5); /// /// 5 hours from the provided date /// public static DateTime HoursFrom(DateTime date) => date.AddHours(5); /// /// 5 days from now /// public static DateTime Days => DateTime.UtcNow.AddDays(5); /// /// 5 days from the provided date /// public static DateTime DaysFrom(DateTime date) => date.AddDays(5); /// /// 5 weeks from now /// public static DateTime Weeks => DateTime.UtcNow.AddDays(35); /// /// 5 weeks from the provided date /// public static DateTime WeeksFrom(DateTime date) => date.AddDays(35); /// /// 5 months from now /// public static DateTime Months => DateTime.UtcNow.AddMonths(5); /// /// 5 months from the provided date /// public static DateTime MonthsFrom(DateTime date) => date.AddMonths(5); /// /// 5 years from now /// public static DateTime Years => DateTime.UtcNow.AddYears(5); /// /// 5 years from the provided date /// public static DateTime YearsFrom(DateTime date) => date.AddYears(5); } /// /// public static class Six { /// /// 6 seconds from now /// public static DateTime Seconds => DateTime.UtcNow.AddSeconds(6); /// /// 6 seconds from the provided date /// public static DateTime SecondsFrom(DateTime date) => date.AddSeconds(6); /// /// 6 minutes from now /// public static DateTime Minutes => DateTime.UtcNow.AddMinutes(6); /// /// 6 minutes from the provided date /// public static DateTime MinutesFrom(DateTime date) => date.AddMinutes(6); /// /// 6 hours from now /// public static DateTime Hours => DateTime.UtcNow.AddHours(6); /// /// 6 hours from the provided date /// public static DateTime HoursFrom(DateTime date) => date.AddHours(6); /// /// 6 days from now /// public static DateTime Days => DateTime.UtcNow.AddDays(6); /// /// 6 days from the provided date /// public static DateTime DaysFrom(DateTime date) => date.AddDays(6); /// /// 6 weeks from now /// public static DateTime Weeks => DateTime.UtcNow.AddDays(42); /// /// 6 weeks from the provided date /// public static DateTime WeeksFrom(DateTime date) => date.AddDays(42); /// /// 6 months from now /// public static DateTime Months => DateTime.UtcNow.AddMonths(6); /// /// 6 months from the provided date /// public static DateTime MonthsFrom(DateTime date) => date.AddMonths(6); /// /// 6 years from now /// public static DateTime Years => DateTime.UtcNow.AddYears(6); /// /// 6 years from the provided date /// public static DateTime YearsFrom(DateTime date) => date.AddYears(6); } /// /// public static class Seven { /// /// 7 seconds from now /// public static DateTime Seconds => DateTime.UtcNow.AddSeconds(7); /// /// 7 seconds from the provided date /// public static DateTime SecondsFrom(DateTime date) => date.AddSeconds(7); /// /// 7 minutes from now /// public static DateTime Minutes => DateTime.UtcNow.AddMinutes(7); /// /// 7 minutes from the provided date /// public static DateTime MinutesFrom(DateTime date) => date.AddMinutes(7); /// /// 7 hours from now /// public static DateTime Hours => DateTime.UtcNow.AddHours(7); /// /// 7 hours from the provided date /// public static DateTime HoursFrom(DateTime date) => date.AddHours(7); /// /// 7 days from now /// public static DateTime Days => DateTime.UtcNow.AddDays(7); /// /// 7 days from the provided date /// public static DateTime DaysFrom(DateTime date) => date.AddDays(7); /// /// 7 weeks from now /// public static DateTime Weeks => DateTime.UtcNow.AddDays(49); /// /// 7 weeks from the provided date /// public static DateTime WeeksFrom(DateTime date) => date.AddDays(49); /// /// 7 months from now /// public static DateTime Months => DateTime.UtcNow.AddMonths(7); /// /// 7 months from the provided date /// public static DateTime MonthsFrom(DateTime date) => date.AddMonths(7); /// /// 7 years from now /// public static DateTime Years => DateTime.UtcNow.AddYears(7); /// /// 7 years from the provided date /// public static DateTime YearsFrom(DateTime date) => date.AddYears(7); } /// /// public static class Eight { /// /// 8 seconds from now /// public static DateTime Seconds => DateTime.UtcNow.AddSeconds(8); /// /// 8 seconds from the provided date /// public static DateTime SecondsFrom(DateTime date) => date.AddSeconds(8); /// /// 8 minutes from now /// public static DateTime Minutes => DateTime.UtcNow.AddMinutes(8); /// /// 8 minutes from the provided date /// public static DateTime MinutesFrom(DateTime date) => date.AddMinutes(8); /// /// 8 hours from now /// public static DateTime Hours => DateTime.UtcNow.AddHours(8); /// /// 8 hours from the provided date /// public static DateTime HoursFrom(DateTime date) => date.AddHours(8); /// /// 8 days from now /// public static DateTime Days => DateTime.UtcNow.AddDays(8); /// /// 8 days from the provided date /// public static DateTime DaysFrom(DateTime date) => date.AddDays(8); /// /// 8 weeks from now /// public static DateTime Weeks => DateTime.UtcNow.AddDays(56); /// /// 8 weeks from the provided date /// public static DateTime WeeksFrom(DateTime date) => date.AddDays(56); /// /// 8 months from now /// public static DateTime Months => DateTime.UtcNow.AddMonths(8); /// /// 8 months from the provided date /// public static DateTime MonthsFrom(DateTime date) => date.AddMonths(8); /// /// 8 years from now /// public static DateTime Years => DateTime.UtcNow.AddYears(8); /// /// 8 years from the provided date /// public static DateTime YearsFrom(DateTime date) => date.AddYears(8); } /// /// public static class Nine { /// /// 9 seconds from now /// public static DateTime Seconds => DateTime.UtcNow.AddSeconds(9); /// /// 9 seconds from the provided date /// public static DateTime SecondsFrom(DateTime date) => date.AddSeconds(9); /// /// 9 minutes from now /// public static DateTime Minutes => DateTime.UtcNow.AddMinutes(9); /// /// 9 minutes from the provided date /// public static DateTime MinutesFrom(DateTime date) => date.AddMinutes(9); /// /// 9 hours from now /// public static DateTime Hours => DateTime.UtcNow.AddHours(9); /// /// 9 hours from the provided date /// public static DateTime HoursFrom(DateTime date) => date.AddHours(9); /// /// 9 days from now /// public static DateTime Days => DateTime.UtcNow.AddDays(9); /// /// 9 days from the provided date /// public static DateTime DaysFrom(DateTime date) => date.AddDays(9); /// /// 9 weeks from now /// public static DateTime Weeks => DateTime.UtcNow.AddDays(63); /// /// 9 weeks from the provided date /// public static DateTime WeeksFrom(DateTime date) => date.AddDays(63); /// /// 9 months from now /// public static DateTime Months => DateTime.UtcNow.AddMonths(9); /// /// 9 months from the provided date /// public static DateTime MonthsFrom(DateTime date) => date.AddMonths(9); /// /// 9 years from now /// public static DateTime Years => DateTime.UtcNow.AddYears(9); /// /// 9 years from the provided date /// public static DateTime YearsFrom(DateTime date) => date.AddYears(9); } /// /// public static class Ten { /// /// 10 seconds from now /// public static DateTime Seconds => DateTime.UtcNow.AddSeconds(10); /// /// 10 seconds from the provided date /// public static DateTime SecondsFrom(DateTime date) => date.AddSeconds(10); /// /// 10 minutes from now /// public static DateTime Minutes => DateTime.UtcNow.AddMinutes(10); /// /// 10 minutes from the provided date /// public static DateTime MinutesFrom(DateTime date) => date.AddMinutes(10); /// /// 10 hours from now /// public static DateTime Hours => DateTime.UtcNow.AddHours(10); /// /// 10 hours from the provided date /// public static DateTime HoursFrom(DateTime date) => date.AddHours(10); /// /// 10 days from now /// public static DateTime Days => DateTime.UtcNow.AddDays(10); /// /// 10 days from the provided date /// public static DateTime DaysFrom(DateTime date) => date.AddDays(10); /// /// 10 weeks from now /// public static DateTime Weeks => DateTime.UtcNow.AddDays(70); /// /// 10 weeks from the provided date /// public static DateTime WeeksFrom(DateTime date) => date.AddDays(70); /// /// 10 months from now /// public static DateTime Months => DateTime.UtcNow.AddMonths(10); /// /// 10 months from the provided date /// public static DateTime MonthsFrom(DateTime date) => date.AddMonths(10); /// /// 10 years from now /// public static DateTime Years => DateTime.UtcNow.AddYears(10); /// /// 10 years from the provided date /// public static DateTime YearsFrom(DateTime date) => date.AddYears(10); } } ================================================ FILE: src/Humanizer/FluentDate/In.SomeTimeFrom.tt ================================================ <#@ template debug="true" hostSpecific="true" culture="en-US"#> <#@ output extension=".cs" #> <#@ Assembly Name="System.Core" #> <#@ Assembly Name="System.Globalization" #> <#@ Assembly Name="System.Windows.Forms" #> <#@ assembly name="$(TargetPath)" #> <#@ import namespace="Humanizer" #> namespace Humanizer; /// /// public partial class In { <#for (var i = 1; i <= 10; i++){ var plural = i > 1 ? "s" : ""; var second = "Second" + plural; var minute = "Minute" + plural; var hour = "Hour" + plural; var day = "Day" + plural; var week = "Week" + plural; var month = "Month" + plural; var year = "Year" + plural; #> /// /// public static class <#= i.ToWords().Dehumanize() #> { /// /// <#= i #> seconds from now /// public static DateTime <#= second #> => DateTime.UtcNow.AddSeconds(<#= i #>); /// /// <#= i #> seconds from the provided date /// public static DateTime <#= second #>From(DateTime date) => date.AddSeconds(<#= i #>); /// /// <#= i #> minutes from now /// public static DateTime <#= minute #> => DateTime.UtcNow.AddMinutes(<#= i #>); /// /// <#= i #> minutes from the provided date /// public static DateTime <#= minute #>From(DateTime date) => date.AddMinutes(<#= i #>); /// /// <#= i #> hours from now /// public static DateTime <#= hour #> => DateTime.UtcNow.AddHours(<#= i #>); /// /// <#= i #> hours from the provided date /// public static DateTime <#= hour #>From(DateTime date) => date.AddHours(<#= i #>); /// /// <#= i #> days from now /// public static DateTime <#= day #> => DateTime.UtcNow.AddDays(<#= i #>); /// /// <#= i #> days from the provided date /// public static DateTime <#= day #>From(DateTime date) => date.AddDays(<#= i #>); /// /// <#= i #> weeks from now /// public static DateTime <#= week #> => DateTime.UtcNow.AddDays(<#= i * 7 #>); /// /// <#= i #> weeks from the provided date /// public static DateTime <#= week #>From(DateTime date) => date.AddDays(<#= i * 7 #>); /// /// <#= i #> months from now /// public static DateTime <#= month #> => DateTime.UtcNow.AddMonths(<#= i #>); /// /// <#= i #> months from the provided date /// public static DateTime <#= month #>From(DateTime date) => date.AddMonths(<#= i #>); /// /// <#= i #> years from now /// public static DateTime <#= year #> => DateTime.UtcNow.AddYears(<#= i #>); /// /// <#= i #> years from the provided date /// public static DateTime <#= year #>From(DateTime date) => date.AddYears(<#= i #>); } <#}#> } ================================================ FILE: src/Humanizer/FluentDate/In.cs ================================================ namespace Humanizer; public partial class In { /// /// Returns the first of January of the provided year /// public static DateTime TheYear(int year) => new(year, 1, 1); } ================================================ FILE: src/Humanizer/FluentDate/InDate.Months.cs ================================================  #if NET6_0_OR_GREATER namespace Humanizer; public partial class InDate { /// /// Returns 1st of January of the current year /// public static DateOnly January => new(DateTime.UtcNow.Year, 1, 1); /// /// Returns 1st of January of the year passed in /// public static DateOnly JanuaryOf(int year) => new(year, 1, 1); /// /// Returns 1st of February of the current year /// public static DateOnly February => new(DateTime.UtcNow.Year, 2, 1); /// /// Returns 1st of February of the year passed in /// public static DateOnly FebruaryOf(int year) => new(year, 2, 1); /// /// Returns 1st of March of the current year /// public static DateOnly March => new(DateTime.UtcNow.Year, 3, 1); /// /// Returns 1st of March of the year passed in /// public static DateOnly MarchOf(int year) => new(year, 3, 1); /// /// Returns 1st of April of the current year /// public static DateOnly April => new(DateTime.UtcNow.Year, 4, 1); /// /// Returns 1st of April of the year passed in /// public static DateOnly AprilOf(int year) => new(year, 4, 1); /// /// Returns 1st of May of the current year /// public static DateOnly May => new(DateTime.UtcNow.Year, 5, 1); /// /// Returns 1st of May of the year passed in /// public static DateOnly MayOf(int year) => new(year, 5, 1); /// /// Returns 1st of June of the current year /// public static DateOnly June => new(DateTime.UtcNow.Year, 6, 1); /// /// Returns 1st of June of the year passed in /// public static DateOnly JuneOf(int year) => new(year, 6, 1); /// /// Returns 1st of July of the current year /// public static DateOnly July => new(DateTime.UtcNow.Year, 7, 1); /// /// Returns 1st of July of the year passed in /// public static DateOnly JulyOf(int year) => new(year, 7, 1); /// /// Returns 1st of August of the current year /// public static DateOnly August => new(DateTime.UtcNow.Year, 8, 1); /// /// Returns 1st of August of the year passed in /// public static DateOnly AugustOf(int year) => new(year, 8, 1); /// /// Returns 1st of September of the current year /// public static DateOnly September => new(DateTime.UtcNow.Year, 9, 1); /// /// Returns 1st of September of the year passed in /// public static DateOnly SeptemberOf(int year) => new(year, 9, 1); /// /// Returns 1st of October of the current year /// public static DateOnly October => new(DateTime.UtcNow.Year, 10, 1); /// /// Returns 1st of October of the year passed in /// public static DateOnly OctoberOf(int year) => new(year, 10, 1); /// /// Returns 1st of November of the current year /// public static DateOnly November => new(DateTime.UtcNow.Year, 11, 1); /// /// Returns 1st of November of the year passed in /// public static DateOnly NovemberOf(int year) => new(year, 11, 1); /// /// Returns 1st of December of the current year /// public static DateOnly December => new(DateTime.UtcNow.Year, 12, 1); /// /// Returns 1st of December of the year passed in /// public static DateOnly DecemberOf(int year) => new(year, 12, 1); } #endif ================================================ FILE: src/Humanizer/FluentDate/InDate.Months.tt ================================================ <#@ template debug="true" hostSpecific="true" #> <#@ output extension=".cs" #> <#@ Assembly Name="System.Core" #> <#@ Assembly Name="System.Windows.Forms" #> <#@ import namespace="System" #> #if NET6_0_OR_GREATER namespace Humanizer; public partial class InDate { <#var now = DateTime.Now; for (var i = 0; i < 12; i++){ var monthName = new DateTime(now.Year, i + 1, 1).ToString("MMMM"); #> /// /// Returns 1st of <#= monthName #> of the current year /// public static DateOnly <#= monthName #> => new(DateTime.UtcNow.Year, <#= i + 1 #>, 1); /// /// Returns 1st of <#= monthName #> of the year passed in /// public static DateOnly <#= monthName#>Of(int year) => new(year, <#= i + 1 #>, 1); <# } #> } #endif ================================================ FILE: src/Humanizer/FluentDate/InDate.SomeTimeFrom.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; /// /// public partial class InDate { /// /// public static class One { /// /// 1 days from now /// public static DateOnly Day => DateOnly.FromDateTime(DateTime.UtcNow.AddDays(1)); /// /// 1 days from the provided date /// public static DateOnly DayFrom(DateOnly date) => date.AddDays(1); /// /// 1 days from the provided date /// public static DateOnly DayFrom(DateTime date) => DateOnly.FromDateTime(date.AddDays(1)); /// /// 1 weeks from now /// public static DateOnly Week => DateOnly.FromDateTime(DateTime.UtcNow.AddDays(7)); /// /// 1 weeks from the provided date /// public static DateOnly WeekFrom(DateOnly date) => date.AddDays(7); /// /// 1 weeks from the provided date /// public static DateOnly WeekFrom(DateTime date) => DateOnly.FromDateTime(date.AddDays(7)); /// /// 1 months from now /// public static DateOnly Month => DateOnly.FromDateTime(DateTime.UtcNow.AddMonths(1)); /// /// 1 months from the provided date /// public static DateOnly MonthFrom(DateOnly date) => date.AddMonths(1); /// /// 1 months from the provided date /// public static DateOnly MonthFrom(DateTime date) => DateOnly.FromDateTime(date.AddMonths(1)); /// /// 1 years from now /// public static DateOnly Year => DateOnly.FromDateTime(DateTime.UtcNow.AddYears(1)); /// /// 1 years from the provided date /// public static DateOnly YearFrom(DateOnly date) => date.AddYears(1); /// /// 1 years from the provided date /// public static DateOnly YearFrom(DateTime date) => DateOnly.FromDateTime(date.AddYears(1)); } /// /// public static class Two { /// /// 2 days from now /// public static DateOnly Days => DateOnly.FromDateTime(DateTime.UtcNow.AddDays(2)); /// /// 2 days from the provided date /// public static DateOnly DaysFrom(DateOnly date) => date.AddDays(2); /// /// 2 days from the provided date /// public static DateOnly DaysFrom(DateTime date) => DateOnly.FromDateTime(date.AddDays(2)); /// /// 2 weeks from now /// public static DateOnly Weeks => DateOnly.FromDateTime(DateTime.UtcNow.AddDays(14)); /// /// 2 weeks from the provided date /// public static DateOnly WeeksFrom(DateOnly date) => date.AddDays(14); /// /// 2 weeks from the provided date /// public static DateOnly WeeksFrom(DateTime date) => DateOnly.FromDateTime(date.AddDays(14)); /// /// 2 months from now /// public static DateOnly Months => DateOnly.FromDateTime(DateTime.UtcNow.AddMonths(2)); /// /// 2 months from the provided date /// public static DateOnly MonthsFrom(DateOnly date) => date.AddMonths(2); /// /// 2 months from the provided date /// public static DateOnly MonthsFrom(DateTime date) => DateOnly.FromDateTime(date.AddMonths(2)); /// /// 2 years from now /// public static DateOnly Years => DateOnly.FromDateTime(DateTime.UtcNow.AddYears(2)); /// /// 2 years from the provided date /// public static DateOnly YearsFrom(DateOnly date) => date.AddYears(2); /// /// 2 years from the provided date /// public static DateOnly YearsFrom(DateTime date) => DateOnly.FromDateTime(date.AddYears(2)); } /// /// public static class Three { /// /// 3 days from now /// public static DateOnly Days => DateOnly.FromDateTime(DateTime.UtcNow.AddDays(3)); /// /// 3 days from the provided date /// public static DateOnly DaysFrom(DateOnly date) => date.AddDays(3); /// /// 3 days from the provided date /// public static DateOnly DaysFrom(DateTime date) => DateOnly.FromDateTime(date.AddDays(3)); /// /// 3 weeks from now /// public static DateOnly Weeks => DateOnly.FromDateTime(DateTime.UtcNow.AddDays(21)); /// /// 3 weeks from the provided date /// public static DateOnly WeeksFrom(DateOnly date) => date.AddDays(21); /// /// 3 weeks from the provided date /// public static DateOnly WeeksFrom(DateTime date) => DateOnly.FromDateTime(date.AddDays(21)); /// /// 3 months from now /// public static DateOnly Months => DateOnly.FromDateTime(DateTime.UtcNow.AddMonths(3)); /// /// 3 months from the provided date /// public static DateOnly MonthsFrom(DateOnly date) => date.AddMonths(3); /// /// 3 months from the provided date /// public static DateOnly MonthsFrom(DateTime date) => DateOnly.FromDateTime(date.AddMonths(3)); /// /// 3 years from now /// public static DateOnly Years => DateOnly.FromDateTime(DateTime.UtcNow.AddYears(3)); /// /// 3 years from the provided date /// public static DateOnly YearsFrom(DateOnly date) => date.AddYears(3); /// /// 3 years from the provided date /// public static DateOnly YearsFrom(DateTime date) => DateOnly.FromDateTime(date.AddYears(3)); } /// /// public static class Four { /// /// 4 days from now /// public static DateOnly Days => DateOnly.FromDateTime(DateTime.UtcNow.AddDays(4)); /// /// 4 days from the provided date /// public static DateOnly DaysFrom(DateOnly date) => date.AddDays(4); /// /// 4 days from the provided date /// public static DateOnly DaysFrom(DateTime date) => DateOnly.FromDateTime(date.AddDays(4)); /// /// 4 weeks from now /// public static DateOnly Weeks => DateOnly.FromDateTime(DateTime.UtcNow.AddDays(28)); /// /// 4 weeks from the provided date /// public static DateOnly WeeksFrom(DateOnly date) => date.AddDays(28); /// /// 4 weeks from the provided date /// public static DateOnly WeeksFrom(DateTime date) => DateOnly.FromDateTime(date.AddDays(28)); /// /// 4 months from now /// public static DateOnly Months => DateOnly.FromDateTime(DateTime.UtcNow.AddMonths(4)); /// /// 4 months from the provided date /// public static DateOnly MonthsFrom(DateOnly date) => date.AddMonths(4); /// /// 4 months from the provided date /// public static DateOnly MonthsFrom(DateTime date) => DateOnly.FromDateTime(date.AddMonths(4)); /// /// 4 years from now /// public static DateOnly Years => DateOnly.FromDateTime(DateTime.UtcNow.AddYears(4)); /// /// 4 years from the provided date /// public static DateOnly YearsFrom(DateOnly date) => date.AddYears(4); /// /// 4 years from the provided date /// public static DateOnly YearsFrom(DateTime date) => DateOnly.FromDateTime(date.AddYears(4)); } /// /// public static class Five { /// /// 5 days from now /// public static DateOnly Days => DateOnly.FromDateTime(DateTime.UtcNow.AddDays(5)); /// /// 5 days from the provided date /// public static DateOnly DaysFrom(DateOnly date) => date.AddDays(5); /// /// 5 days from the provided date /// public static DateOnly DaysFrom(DateTime date) => DateOnly.FromDateTime(date.AddDays(5)); /// /// 5 weeks from now /// public static DateOnly Weeks => DateOnly.FromDateTime(DateTime.UtcNow.AddDays(35)); /// /// 5 weeks from the provided date /// public static DateOnly WeeksFrom(DateOnly date) => date.AddDays(35); /// /// 5 weeks from the provided date /// public static DateOnly WeeksFrom(DateTime date) => DateOnly.FromDateTime(date.AddDays(35)); /// /// 5 months from now /// public static DateOnly Months => DateOnly.FromDateTime(DateTime.UtcNow.AddMonths(5)); /// /// 5 months from the provided date /// public static DateOnly MonthsFrom(DateOnly date) => date.AddMonths(5); /// /// 5 months from the provided date /// public static DateOnly MonthsFrom(DateTime date) => DateOnly.FromDateTime(date.AddMonths(5)); /// /// 5 years from now /// public static DateOnly Years => DateOnly.FromDateTime(DateTime.UtcNow.AddYears(5)); /// /// 5 years from the provided date /// public static DateOnly YearsFrom(DateOnly date) => date.AddYears(5); /// /// 5 years from the provided date /// public static DateOnly YearsFrom(DateTime date) => DateOnly.FromDateTime(date.AddYears(5)); } /// /// public static class Six { /// /// 6 days from now /// public static DateOnly Days => DateOnly.FromDateTime(DateTime.UtcNow.AddDays(6)); /// /// 6 days from the provided date /// public static DateOnly DaysFrom(DateOnly date) => date.AddDays(6); /// /// 6 days from the provided date /// public static DateOnly DaysFrom(DateTime date) => DateOnly.FromDateTime(date.AddDays(6)); /// /// 6 weeks from now /// public static DateOnly Weeks => DateOnly.FromDateTime(DateTime.UtcNow.AddDays(42)); /// /// 6 weeks from the provided date /// public static DateOnly WeeksFrom(DateOnly date) => date.AddDays(42); /// /// 6 weeks from the provided date /// public static DateOnly WeeksFrom(DateTime date) => DateOnly.FromDateTime(date.AddDays(42)); /// /// 6 months from now /// public static DateOnly Months => DateOnly.FromDateTime(DateTime.UtcNow.AddMonths(6)); /// /// 6 months from the provided date /// public static DateOnly MonthsFrom(DateOnly date) => date.AddMonths(6); /// /// 6 months from the provided date /// public static DateOnly MonthsFrom(DateTime date) => DateOnly.FromDateTime(date.AddMonths(6)); /// /// 6 years from now /// public static DateOnly Years => DateOnly.FromDateTime(DateTime.UtcNow.AddYears(6)); /// /// 6 years from the provided date /// public static DateOnly YearsFrom(DateOnly date) => date.AddYears(6); /// /// 6 years from the provided date /// public static DateOnly YearsFrom(DateTime date) => DateOnly.FromDateTime(date.AddYears(6)); } /// /// public static class Seven { /// /// 7 days from now /// public static DateOnly Days => DateOnly.FromDateTime(DateTime.UtcNow.AddDays(7)); /// /// 7 days from the provided date /// public static DateOnly DaysFrom(DateOnly date) => date.AddDays(7); /// /// 7 days from the provided date /// public static DateOnly DaysFrom(DateTime date) => DateOnly.FromDateTime(date.AddDays(7)); /// /// 7 weeks from now /// public static DateOnly Weeks => DateOnly.FromDateTime(DateTime.UtcNow.AddDays(49)); /// /// 7 weeks from the provided date /// public static DateOnly WeeksFrom(DateOnly date) => date.AddDays(49); /// /// 7 weeks from the provided date /// public static DateOnly WeeksFrom(DateTime date) => DateOnly.FromDateTime(date.AddDays(49)); /// /// 7 months from now /// public static DateOnly Months => DateOnly.FromDateTime(DateTime.UtcNow.AddMonths(7)); /// /// 7 months from the provided date /// public static DateOnly MonthsFrom(DateOnly date) => date.AddMonths(7); /// /// 7 months from the provided date /// public static DateOnly MonthsFrom(DateTime date) => DateOnly.FromDateTime(date.AddMonths(7)); /// /// 7 years from now /// public static DateOnly Years => DateOnly.FromDateTime(DateTime.UtcNow.AddYears(7)); /// /// 7 years from the provided date /// public static DateOnly YearsFrom(DateOnly date) => date.AddYears(7); /// /// 7 years from the provided date /// public static DateOnly YearsFrom(DateTime date) => DateOnly.FromDateTime(date.AddYears(7)); } /// /// public static class Eight { /// /// 8 days from now /// public static DateOnly Days => DateOnly.FromDateTime(DateTime.UtcNow.AddDays(8)); /// /// 8 days from the provided date /// public static DateOnly DaysFrom(DateOnly date) => date.AddDays(8); /// /// 8 days from the provided date /// public static DateOnly DaysFrom(DateTime date) => DateOnly.FromDateTime(date.AddDays(8)); /// /// 8 weeks from now /// public static DateOnly Weeks => DateOnly.FromDateTime(DateTime.UtcNow.AddDays(56)); /// /// 8 weeks from the provided date /// public static DateOnly WeeksFrom(DateOnly date) => date.AddDays(56); /// /// 8 weeks from the provided date /// public static DateOnly WeeksFrom(DateTime date) => DateOnly.FromDateTime(date.AddDays(56)); /// /// 8 months from now /// public static DateOnly Months => DateOnly.FromDateTime(DateTime.UtcNow.AddMonths(8)); /// /// 8 months from the provided date /// public static DateOnly MonthsFrom(DateOnly date) => date.AddMonths(8); /// /// 8 months from the provided date /// public static DateOnly MonthsFrom(DateTime date) => DateOnly.FromDateTime(date.AddMonths(8)); /// /// 8 years from now /// public static DateOnly Years => DateOnly.FromDateTime(DateTime.UtcNow.AddYears(8)); /// /// 8 years from the provided date /// public static DateOnly YearsFrom(DateOnly date) => date.AddYears(8); /// /// 8 years from the provided date /// public static DateOnly YearsFrom(DateTime date) => DateOnly.FromDateTime(date.AddYears(8)); } /// /// public static class Nine { /// /// 9 days from now /// public static DateOnly Days => DateOnly.FromDateTime(DateTime.UtcNow.AddDays(9)); /// /// 9 days from the provided date /// public static DateOnly DaysFrom(DateOnly date) => date.AddDays(9); /// /// 9 days from the provided date /// public static DateOnly DaysFrom(DateTime date) => DateOnly.FromDateTime(date.AddDays(9)); /// /// 9 weeks from now /// public static DateOnly Weeks => DateOnly.FromDateTime(DateTime.UtcNow.AddDays(63)); /// /// 9 weeks from the provided date /// public static DateOnly WeeksFrom(DateOnly date) => date.AddDays(63); /// /// 9 weeks from the provided date /// public static DateOnly WeeksFrom(DateTime date) => DateOnly.FromDateTime(date.AddDays(63)); /// /// 9 months from now /// public static DateOnly Months => DateOnly.FromDateTime(DateTime.UtcNow.AddMonths(9)); /// /// 9 months from the provided date /// public static DateOnly MonthsFrom(DateOnly date) => date.AddMonths(9); /// /// 9 months from the provided date /// public static DateOnly MonthsFrom(DateTime date) => DateOnly.FromDateTime(date.AddMonths(9)); /// /// 9 years from now /// public static DateOnly Years => DateOnly.FromDateTime(DateTime.UtcNow.AddYears(9)); /// /// 9 years from the provided date /// public static DateOnly YearsFrom(DateOnly date) => date.AddYears(9); /// /// 9 years from the provided date /// public static DateOnly YearsFrom(DateTime date) => DateOnly.FromDateTime(date.AddYears(9)); } /// /// public static class Ten { /// /// 10 days from now /// public static DateOnly Days => DateOnly.FromDateTime(DateTime.UtcNow.AddDays(10)); /// /// 10 days from the provided date /// public static DateOnly DaysFrom(DateOnly date) => date.AddDays(10); /// /// 10 days from the provided date /// public static DateOnly DaysFrom(DateTime date) => DateOnly.FromDateTime(date.AddDays(10)); /// /// 10 weeks from now /// public static DateOnly Weeks => DateOnly.FromDateTime(DateTime.UtcNow.AddDays(70)); /// /// 10 weeks from the provided date /// public static DateOnly WeeksFrom(DateOnly date) => date.AddDays(70); /// /// 10 weeks from the provided date /// public static DateOnly WeeksFrom(DateTime date) => DateOnly.FromDateTime(date.AddDays(70)); /// /// 10 months from now /// public static DateOnly Months => DateOnly.FromDateTime(DateTime.UtcNow.AddMonths(10)); /// /// 10 months from the provided date /// public static DateOnly MonthsFrom(DateOnly date) => date.AddMonths(10); /// /// 10 months from the provided date /// public static DateOnly MonthsFrom(DateTime date) => DateOnly.FromDateTime(date.AddMonths(10)); /// /// 10 years from now /// public static DateOnly Years => DateOnly.FromDateTime(DateTime.UtcNow.AddYears(10)); /// /// 10 years from the provided date /// public static DateOnly YearsFrom(DateOnly date) => date.AddYears(10); /// /// 10 years from the provided date /// public static DateOnly YearsFrom(DateTime date) => DateOnly.FromDateTime(date.AddYears(10)); } } #endif ================================================ FILE: src/Humanizer/FluentDate/InDate.SomeTimeFrom.tt ================================================ <#@ template debug="true" hostSpecific="true" culture="en-US"#> <#@ output extension=".cs" #> <#@ Assembly Name="System.Core" #> <#@ Assembly Name="System.Globalization" #> <#@ Assembly Name="System.Windows.Forms" #> <#@ assembly name="$(TargetPath)" #> <#@ import namespace="Humanizer" #> #if NET6_0_OR_GREATER namespace Humanizer; /// /// public partial class InDate { <#for (var i = 1; i <= 10; i++){ var plural = i > 1 ? "s" : ""; var day = "Day" + plural; var week = "Week" + plural; var month = "Month" + plural; var year = "Year" + plural; #> /// /// public static class <#= i.ToWords().Dehumanize() #> { /// /// <#= i #> days from now /// public static DateOnly <#= day #> => DateOnly.FromDateTime(DateTime.UtcNow.AddDays(<#= i #>)); /// /// <#= i #> days from the provided date /// public static DateOnly <#= day #>From(DateOnly date) => date.AddDays(<#= i #>); /// /// <#= i #> days from the provided date /// public static DateOnly <#= day #>From(DateTime date) => DateOnly.FromDateTime(date.AddDays(<#= i #>)); /// /// <#= i #> weeks from now /// public static DateOnly <#= week #> => DateOnly.FromDateTime(DateTime.UtcNow.AddDays(<#= i * 7 #>)); /// /// <#= i #> weeks from the provided date /// public static DateOnly <#= week #>From(DateOnly date) => date.AddDays(<#= i * 7 #>); /// /// <#= i #> weeks from the provided date /// public static DateOnly <#= week #>From(DateTime date) => DateOnly.FromDateTime(date.AddDays(<#= i * 7 #>)); /// /// <#= i #> months from now /// public static DateOnly <#= month #> => DateOnly.FromDateTime(DateTime.UtcNow.AddMonths(<#= i #>)); /// /// <#= i #> months from the provided date /// public static DateOnly <#= month #>From(DateOnly date) => date.AddMonths(<#= i #>); /// /// <#= i #> months from the provided date /// public static DateOnly <#= month #>From(DateTime date) => DateOnly.FromDateTime(date.AddMonths(<#= i #>)); /// /// <#= i #> years from now /// public static DateOnly <#= year #> => DateOnly.FromDateTime(DateTime.UtcNow.AddYears(<#= i #>)); /// /// <#= i #> years from the provided date /// public static DateOnly <#= year #>From(DateOnly date) => date.AddYears(<#= i #>); /// /// <#= i #> years from the provided date /// public static DateOnly <#= year #>From(DateTime date) => DateOnly.FromDateTime(date.AddYears(<#= i #>)); } <#}#> } #endif ================================================ FILE: src/Humanizer/FluentDate/InDate.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; public partial class InDate { /// /// Returns the first of January of the provided year /// public static DateOnly TheYear(int year) => new(year, 1, 1); } #endif ================================================ FILE: src/Humanizer/FluentDate/On.Days.cs ================================================ namespace Humanizer; public class On { /// /// Provides fluent date accessors for January /// public class January { /// /// The nth day of January of the current year /// public static DateTime The(int dayNumber) => new(DateTime.Now.Year, 1, dayNumber); /// /// The 1st day of January of the current year /// public static DateTime The1st => new(DateTime.Now.Year, 1, 1); /// /// The 2nd day of January of the current year /// public static DateTime The2nd => new(DateTime.Now.Year, 1, 2); /// /// The 3rd day of January of the current year /// public static DateTime The3rd => new(DateTime.Now.Year, 1, 3); /// /// The 4th day of January of the current year /// public static DateTime The4th => new(DateTime.Now.Year, 1, 4); /// /// The 5th day of January of the current year /// public static DateTime The5th => new(DateTime.Now.Year, 1, 5); /// /// The 6th day of January of the current year /// public static DateTime The6th => new(DateTime.Now.Year, 1, 6); /// /// The 7th day of January of the current year /// public static DateTime The7th => new(DateTime.Now.Year, 1, 7); /// /// The 8th day of January of the current year /// public static DateTime The8th => new(DateTime.Now.Year, 1, 8); /// /// The 9th day of January of the current year /// public static DateTime The9th => new(DateTime.Now.Year, 1, 9); /// /// The 10th day of January of the current year /// public static DateTime The10th => new(DateTime.Now.Year, 1, 10); /// /// The 11th day of January of the current year /// public static DateTime The11th => new(DateTime.Now.Year, 1, 11); /// /// The 12th day of January of the current year /// public static DateTime The12th => new(DateTime.Now.Year, 1, 12); /// /// The 13th day of January of the current year /// public static DateTime The13th => new(DateTime.Now.Year, 1, 13); /// /// The 14th day of January of the current year /// public static DateTime The14th => new(DateTime.Now.Year, 1, 14); /// /// The 15th day of January of the current year /// public static DateTime The15th => new(DateTime.Now.Year, 1, 15); /// /// The 16th day of January of the current year /// public static DateTime The16th => new(DateTime.Now.Year, 1, 16); /// /// The 17th day of January of the current year /// public static DateTime The17th => new(DateTime.Now.Year, 1, 17); /// /// The 18th day of January of the current year /// public static DateTime The18th => new(DateTime.Now.Year, 1, 18); /// /// The 19th day of January of the current year /// public static DateTime The19th => new(DateTime.Now.Year, 1, 19); /// /// The 20th day of January of the current year /// public static DateTime The20th => new(DateTime.Now.Year, 1, 20); /// /// The 21st day of January of the current year /// public static DateTime The21st => new(DateTime.Now.Year, 1, 21); /// /// The 22nd day of January of the current year /// public static DateTime The22nd => new(DateTime.Now.Year, 1, 22); /// /// The 23rd day of January of the current year /// public static DateTime The23rd => new(DateTime.Now.Year, 1, 23); /// /// The 24th day of January of the current year /// public static DateTime The24th => new(DateTime.Now.Year, 1, 24); /// /// The 25th day of January of the current year /// public static DateTime The25th => new(DateTime.Now.Year, 1, 25); /// /// The 26th day of January of the current year /// public static DateTime The26th => new(DateTime.Now.Year, 1, 26); /// /// The 27th day of January of the current year /// public static DateTime The27th => new(DateTime.Now.Year, 1, 27); /// /// The 28th day of January of the current year /// public static DateTime The28th => new(DateTime.Now.Year, 1, 28); /// /// The 29th day of January of the current year /// public static DateTime The29th => new(DateTime.Now.Year, 1, 29); /// /// The 30th day of January of the current year /// public static DateTime The30th => new(DateTime.Now.Year, 1, 30); /// /// The 31st day of January of the current year /// public static DateTime The31st => new(DateTime.Now.Year, 1, 31); } /// /// Provides fluent date accessors for February /// public class February { /// /// The nth day of February of the current year /// public static DateTime The(int dayNumber) => new(DateTime.Now.Year, 2, dayNumber); /// /// The 1st day of February of the current year /// public static DateTime The1st => new(DateTime.Now.Year, 2, 1); /// /// The 2nd day of February of the current year /// public static DateTime The2nd => new(DateTime.Now.Year, 2, 2); /// /// The 3rd day of February of the current year /// public static DateTime The3rd => new(DateTime.Now.Year, 2, 3); /// /// The 4th day of February of the current year /// public static DateTime The4th => new(DateTime.Now.Year, 2, 4); /// /// The 5th day of February of the current year /// public static DateTime The5th => new(DateTime.Now.Year, 2, 5); /// /// The 6th day of February of the current year /// public static DateTime The6th => new(DateTime.Now.Year, 2, 6); /// /// The 7th day of February of the current year /// public static DateTime The7th => new(DateTime.Now.Year, 2, 7); /// /// The 8th day of February of the current year /// public static DateTime The8th => new(DateTime.Now.Year, 2, 8); /// /// The 9th day of February of the current year /// public static DateTime The9th => new(DateTime.Now.Year, 2, 9); /// /// The 10th day of February of the current year /// public static DateTime The10th => new(DateTime.Now.Year, 2, 10); /// /// The 11th day of February of the current year /// public static DateTime The11th => new(DateTime.Now.Year, 2, 11); /// /// The 12th day of February of the current year /// public static DateTime The12th => new(DateTime.Now.Year, 2, 12); /// /// The 13th day of February of the current year /// public static DateTime The13th => new(DateTime.Now.Year, 2, 13); /// /// The 14th day of February of the current year /// public static DateTime The14th => new(DateTime.Now.Year, 2, 14); /// /// The 15th day of February of the current year /// public static DateTime The15th => new(DateTime.Now.Year, 2, 15); /// /// The 16th day of February of the current year /// public static DateTime The16th => new(DateTime.Now.Year, 2, 16); /// /// The 17th day of February of the current year /// public static DateTime The17th => new(DateTime.Now.Year, 2, 17); /// /// The 18th day of February of the current year /// public static DateTime The18th => new(DateTime.Now.Year, 2, 18); /// /// The 19th day of February of the current year /// public static DateTime The19th => new(DateTime.Now.Year, 2, 19); /// /// The 20th day of February of the current year /// public static DateTime The20th => new(DateTime.Now.Year, 2, 20); /// /// The 21st day of February of the current year /// public static DateTime The21st => new(DateTime.Now.Year, 2, 21); /// /// The 22nd day of February of the current year /// public static DateTime The22nd => new(DateTime.Now.Year, 2, 22); /// /// The 23rd day of February of the current year /// public static DateTime The23rd => new(DateTime.Now.Year, 2, 23); /// /// The 24th day of February of the current year /// public static DateTime The24th => new(DateTime.Now.Year, 2, 24); /// /// The 25th day of February of the current year /// public static DateTime The25th => new(DateTime.Now.Year, 2, 25); /// /// The 26th day of February of the current year /// public static DateTime The26th => new(DateTime.Now.Year, 2, 26); /// /// The 27th day of February of the current year /// public static DateTime The27th => new(DateTime.Now.Year, 2, 27); /// /// The 28th day of February of the current year /// public static DateTime The28th => new(DateTime.Now.Year, 2, 28); /// /// The 29th day of February of the current year /// public static DateTime The29th => new(DateTime.Now.Year, 2, 29); } /// /// Provides fluent date accessors for March /// public class March { /// /// The nth day of March of the current year /// public static DateTime The(int dayNumber) => new(DateTime.Now.Year, 3, dayNumber); /// /// The 1st day of March of the current year /// public static DateTime The1st => new(DateTime.Now.Year, 3, 1); /// /// The 2nd day of March of the current year /// public static DateTime The2nd => new(DateTime.Now.Year, 3, 2); /// /// The 3rd day of March of the current year /// public static DateTime The3rd => new(DateTime.Now.Year, 3, 3); /// /// The 4th day of March of the current year /// public static DateTime The4th => new(DateTime.Now.Year, 3, 4); /// /// The 5th day of March of the current year /// public static DateTime The5th => new(DateTime.Now.Year, 3, 5); /// /// The 6th day of March of the current year /// public static DateTime The6th => new(DateTime.Now.Year, 3, 6); /// /// The 7th day of March of the current year /// public static DateTime The7th => new(DateTime.Now.Year, 3, 7); /// /// The 8th day of March of the current year /// public static DateTime The8th => new(DateTime.Now.Year, 3, 8); /// /// The 9th day of March of the current year /// public static DateTime The9th => new(DateTime.Now.Year, 3, 9); /// /// The 10th day of March of the current year /// public static DateTime The10th => new(DateTime.Now.Year, 3, 10); /// /// The 11th day of March of the current year /// public static DateTime The11th => new(DateTime.Now.Year, 3, 11); /// /// The 12th day of March of the current year /// public static DateTime The12th => new(DateTime.Now.Year, 3, 12); /// /// The 13th day of March of the current year /// public static DateTime The13th => new(DateTime.Now.Year, 3, 13); /// /// The 14th day of March of the current year /// public static DateTime The14th => new(DateTime.Now.Year, 3, 14); /// /// The 15th day of March of the current year /// public static DateTime The15th => new(DateTime.Now.Year, 3, 15); /// /// The 16th day of March of the current year /// public static DateTime The16th => new(DateTime.Now.Year, 3, 16); /// /// The 17th day of March of the current year /// public static DateTime The17th => new(DateTime.Now.Year, 3, 17); /// /// The 18th day of March of the current year /// public static DateTime The18th => new(DateTime.Now.Year, 3, 18); /// /// The 19th day of March of the current year /// public static DateTime The19th => new(DateTime.Now.Year, 3, 19); /// /// The 20th day of March of the current year /// public static DateTime The20th => new(DateTime.Now.Year, 3, 20); /// /// The 21st day of March of the current year /// public static DateTime The21st => new(DateTime.Now.Year, 3, 21); /// /// The 22nd day of March of the current year /// public static DateTime The22nd => new(DateTime.Now.Year, 3, 22); /// /// The 23rd day of March of the current year /// public static DateTime The23rd => new(DateTime.Now.Year, 3, 23); /// /// The 24th day of March of the current year /// public static DateTime The24th => new(DateTime.Now.Year, 3, 24); /// /// The 25th day of March of the current year /// public static DateTime The25th => new(DateTime.Now.Year, 3, 25); /// /// The 26th day of March of the current year /// public static DateTime The26th => new(DateTime.Now.Year, 3, 26); /// /// The 27th day of March of the current year /// public static DateTime The27th => new(DateTime.Now.Year, 3, 27); /// /// The 28th day of March of the current year /// public static DateTime The28th => new(DateTime.Now.Year, 3, 28); /// /// The 29th day of March of the current year /// public static DateTime The29th => new(DateTime.Now.Year, 3, 29); /// /// The 30th day of March of the current year /// public static DateTime The30th => new(DateTime.Now.Year, 3, 30); /// /// The 31st day of March of the current year /// public static DateTime The31st => new(DateTime.Now.Year, 3, 31); } /// /// Provides fluent date accessors for April /// public class April { /// /// The nth day of April of the current year /// public static DateTime The(int dayNumber) => new(DateTime.Now.Year, 4, dayNumber); /// /// The 1st day of April of the current year /// public static DateTime The1st => new(DateTime.Now.Year, 4, 1); /// /// The 2nd day of April of the current year /// public static DateTime The2nd => new(DateTime.Now.Year, 4, 2); /// /// The 3rd day of April of the current year /// public static DateTime The3rd => new(DateTime.Now.Year, 4, 3); /// /// The 4th day of April of the current year /// public static DateTime The4th => new(DateTime.Now.Year, 4, 4); /// /// The 5th day of April of the current year /// public static DateTime The5th => new(DateTime.Now.Year, 4, 5); /// /// The 6th day of April of the current year /// public static DateTime The6th => new(DateTime.Now.Year, 4, 6); /// /// The 7th day of April of the current year /// public static DateTime The7th => new(DateTime.Now.Year, 4, 7); /// /// The 8th day of April of the current year /// public static DateTime The8th => new(DateTime.Now.Year, 4, 8); /// /// The 9th day of April of the current year /// public static DateTime The9th => new(DateTime.Now.Year, 4, 9); /// /// The 10th day of April of the current year /// public static DateTime The10th => new(DateTime.Now.Year, 4, 10); /// /// The 11th day of April of the current year /// public static DateTime The11th => new(DateTime.Now.Year, 4, 11); /// /// The 12th day of April of the current year /// public static DateTime The12th => new(DateTime.Now.Year, 4, 12); /// /// The 13th day of April of the current year /// public static DateTime The13th => new(DateTime.Now.Year, 4, 13); /// /// The 14th day of April of the current year /// public static DateTime The14th => new(DateTime.Now.Year, 4, 14); /// /// The 15th day of April of the current year /// public static DateTime The15th => new(DateTime.Now.Year, 4, 15); /// /// The 16th day of April of the current year /// public static DateTime The16th => new(DateTime.Now.Year, 4, 16); /// /// The 17th day of April of the current year /// public static DateTime The17th => new(DateTime.Now.Year, 4, 17); /// /// The 18th day of April of the current year /// public static DateTime The18th => new(DateTime.Now.Year, 4, 18); /// /// The 19th day of April of the current year /// public static DateTime The19th => new(DateTime.Now.Year, 4, 19); /// /// The 20th day of April of the current year /// public static DateTime The20th => new(DateTime.Now.Year, 4, 20); /// /// The 21st day of April of the current year /// public static DateTime The21st => new(DateTime.Now.Year, 4, 21); /// /// The 22nd day of April of the current year /// public static DateTime The22nd => new(DateTime.Now.Year, 4, 22); /// /// The 23rd day of April of the current year /// public static DateTime The23rd => new(DateTime.Now.Year, 4, 23); /// /// The 24th day of April of the current year /// public static DateTime The24th => new(DateTime.Now.Year, 4, 24); /// /// The 25th day of April of the current year /// public static DateTime The25th => new(DateTime.Now.Year, 4, 25); /// /// The 26th day of April of the current year /// public static DateTime The26th => new(DateTime.Now.Year, 4, 26); /// /// The 27th day of April of the current year /// public static DateTime The27th => new(DateTime.Now.Year, 4, 27); /// /// The 28th day of April of the current year /// public static DateTime The28th => new(DateTime.Now.Year, 4, 28); /// /// The 29th day of April of the current year /// public static DateTime The29th => new(DateTime.Now.Year, 4, 29); /// /// The 30th day of April of the current year /// public static DateTime The30th => new(DateTime.Now.Year, 4, 30); } /// /// Provides fluent date accessors for May /// public class May { /// /// The nth day of May of the current year /// public static DateTime The(int dayNumber) => new(DateTime.Now.Year, 5, dayNumber); /// /// The 1st day of May of the current year /// public static DateTime The1st => new(DateTime.Now.Year, 5, 1); /// /// The 2nd day of May of the current year /// public static DateTime The2nd => new(DateTime.Now.Year, 5, 2); /// /// The 3rd day of May of the current year /// public static DateTime The3rd => new(DateTime.Now.Year, 5, 3); /// /// The 4th day of May of the current year /// public static DateTime The4th => new(DateTime.Now.Year, 5, 4); /// /// The 5th day of May of the current year /// public static DateTime The5th => new(DateTime.Now.Year, 5, 5); /// /// The 6th day of May of the current year /// public static DateTime The6th => new(DateTime.Now.Year, 5, 6); /// /// The 7th day of May of the current year /// public static DateTime The7th => new(DateTime.Now.Year, 5, 7); /// /// The 8th day of May of the current year /// public static DateTime The8th => new(DateTime.Now.Year, 5, 8); /// /// The 9th day of May of the current year /// public static DateTime The9th => new(DateTime.Now.Year, 5, 9); /// /// The 10th day of May of the current year /// public static DateTime The10th => new(DateTime.Now.Year, 5, 10); /// /// The 11th day of May of the current year /// public static DateTime The11th => new(DateTime.Now.Year, 5, 11); /// /// The 12th day of May of the current year /// public static DateTime The12th => new(DateTime.Now.Year, 5, 12); /// /// The 13th day of May of the current year /// public static DateTime The13th => new(DateTime.Now.Year, 5, 13); /// /// The 14th day of May of the current year /// public static DateTime The14th => new(DateTime.Now.Year, 5, 14); /// /// The 15th day of May of the current year /// public static DateTime The15th => new(DateTime.Now.Year, 5, 15); /// /// The 16th day of May of the current year /// public static DateTime The16th => new(DateTime.Now.Year, 5, 16); /// /// The 17th day of May of the current year /// public static DateTime The17th => new(DateTime.Now.Year, 5, 17); /// /// The 18th day of May of the current year /// public static DateTime The18th => new(DateTime.Now.Year, 5, 18); /// /// The 19th day of May of the current year /// public static DateTime The19th => new(DateTime.Now.Year, 5, 19); /// /// The 20th day of May of the current year /// public static DateTime The20th => new(DateTime.Now.Year, 5, 20); /// /// The 21st day of May of the current year /// public static DateTime The21st => new(DateTime.Now.Year, 5, 21); /// /// The 22nd day of May of the current year /// public static DateTime The22nd => new(DateTime.Now.Year, 5, 22); /// /// The 23rd day of May of the current year /// public static DateTime The23rd => new(DateTime.Now.Year, 5, 23); /// /// The 24th day of May of the current year /// public static DateTime The24th => new(DateTime.Now.Year, 5, 24); /// /// The 25th day of May of the current year /// public static DateTime The25th => new(DateTime.Now.Year, 5, 25); /// /// The 26th day of May of the current year /// public static DateTime The26th => new(DateTime.Now.Year, 5, 26); /// /// The 27th day of May of the current year /// public static DateTime The27th => new(DateTime.Now.Year, 5, 27); /// /// The 28th day of May of the current year /// public static DateTime The28th => new(DateTime.Now.Year, 5, 28); /// /// The 29th day of May of the current year /// public static DateTime The29th => new(DateTime.Now.Year, 5, 29); /// /// The 30th day of May of the current year /// public static DateTime The30th => new(DateTime.Now.Year, 5, 30); /// /// The 31st day of May of the current year /// public static DateTime The31st => new(DateTime.Now.Year, 5, 31); } /// /// Provides fluent date accessors for June /// public class June { /// /// The nth day of June of the current year /// public static DateTime The(int dayNumber) => new(DateTime.Now.Year, 6, dayNumber); /// /// The 1st day of June of the current year /// public static DateTime The1st => new(DateTime.Now.Year, 6, 1); /// /// The 2nd day of June of the current year /// public static DateTime The2nd => new(DateTime.Now.Year, 6, 2); /// /// The 3rd day of June of the current year /// public static DateTime The3rd => new(DateTime.Now.Year, 6, 3); /// /// The 4th day of June of the current year /// public static DateTime The4th => new(DateTime.Now.Year, 6, 4); /// /// The 5th day of June of the current year /// public static DateTime The5th => new(DateTime.Now.Year, 6, 5); /// /// The 6th day of June of the current year /// public static DateTime The6th => new(DateTime.Now.Year, 6, 6); /// /// The 7th day of June of the current year /// public static DateTime The7th => new(DateTime.Now.Year, 6, 7); /// /// The 8th day of June of the current year /// public static DateTime The8th => new(DateTime.Now.Year, 6, 8); /// /// The 9th day of June of the current year /// public static DateTime The9th => new(DateTime.Now.Year, 6, 9); /// /// The 10th day of June of the current year /// public static DateTime The10th => new(DateTime.Now.Year, 6, 10); /// /// The 11th day of June of the current year /// public static DateTime The11th => new(DateTime.Now.Year, 6, 11); /// /// The 12th day of June of the current year /// public static DateTime The12th => new(DateTime.Now.Year, 6, 12); /// /// The 13th day of June of the current year /// public static DateTime The13th => new(DateTime.Now.Year, 6, 13); /// /// The 14th day of June of the current year /// public static DateTime The14th => new(DateTime.Now.Year, 6, 14); /// /// The 15th day of June of the current year /// public static DateTime The15th => new(DateTime.Now.Year, 6, 15); /// /// The 16th day of June of the current year /// public static DateTime The16th => new(DateTime.Now.Year, 6, 16); /// /// The 17th day of June of the current year /// public static DateTime The17th => new(DateTime.Now.Year, 6, 17); /// /// The 18th day of June of the current year /// public static DateTime The18th => new(DateTime.Now.Year, 6, 18); /// /// The 19th day of June of the current year /// public static DateTime The19th => new(DateTime.Now.Year, 6, 19); /// /// The 20th day of June of the current year /// public static DateTime The20th => new(DateTime.Now.Year, 6, 20); /// /// The 21st day of June of the current year /// public static DateTime The21st => new(DateTime.Now.Year, 6, 21); /// /// The 22nd day of June of the current year /// public static DateTime The22nd => new(DateTime.Now.Year, 6, 22); /// /// The 23rd day of June of the current year /// public static DateTime The23rd => new(DateTime.Now.Year, 6, 23); /// /// The 24th day of June of the current year /// public static DateTime The24th => new(DateTime.Now.Year, 6, 24); /// /// The 25th day of June of the current year /// public static DateTime The25th => new(DateTime.Now.Year, 6, 25); /// /// The 26th day of June of the current year /// public static DateTime The26th => new(DateTime.Now.Year, 6, 26); /// /// The 27th day of June of the current year /// public static DateTime The27th => new(DateTime.Now.Year, 6, 27); /// /// The 28th day of June of the current year /// public static DateTime The28th => new(DateTime.Now.Year, 6, 28); /// /// The 29th day of June of the current year /// public static DateTime The29th => new(DateTime.Now.Year, 6, 29); /// /// The 30th day of June of the current year /// public static DateTime The30th => new(DateTime.Now.Year, 6, 30); } /// /// Provides fluent date accessors for July /// public class July { /// /// The nth day of July of the current year /// public static DateTime The(int dayNumber) => new(DateTime.Now.Year, 7, dayNumber); /// /// The 1st day of July of the current year /// public static DateTime The1st => new(DateTime.Now.Year, 7, 1); /// /// The 2nd day of July of the current year /// public static DateTime The2nd => new(DateTime.Now.Year, 7, 2); /// /// The 3rd day of July of the current year /// public static DateTime The3rd => new(DateTime.Now.Year, 7, 3); /// /// The 4th day of July of the current year /// public static DateTime The4th => new(DateTime.Now.Year, 7, 4); /// /// The 5th day of July of the current year /// public static DateTime The5th => new(DateTime.Now.Year, 7, 5); /// /// The 6th day of July of the current year /// public static DateTime The6th => new(DateTime.Now.Year, 7, 6); /// /// The 7th day of July of the current year /// public static DateTime The7th => new(DateTime.Now.Year, 7, 7); /// /// The 8th day of July of the current year /// public static DateTime The8th => new(DateTime.Now.Year, 7, 8); /// /// The 9th day of July of the current year /// public static DateTime The9th => new(DateTime.Now.Year, 7, 9); /// /// The 10th day of July of the current year /// public static DateTime The10th => new(DateTime.Now.Year, 7, 10); /// /// The 11th day of July of the current year /// public static DateTime The11th => new(DateTime.Now.Year, 7, 11); /// /// The 12th day of July of the current year /// public static DateTime The12th => new(DateTime.Now.Year, 7, 12); /// /// The 13th day of July of the current year /// public static DateTime The13th => new(DateTime.Now.Year, 7, 13); /// /// The 14th day of July of the current year /// public static DateTime The14th => new(DateTime.Now.Year, 7, 14); /// /// The 15th day of July of the current year /// public static DateTime The15th => new(DateTime.Now.Year, 7, 15); /// /// The 16th day of July of the current year /// public static DateTime The16th => new(DateTime.Now.Year, 7, 16); /// /// The 17th day of July of the current year /// public static DateTime The17th => new(DateTime.Now.Year, 7, 17); /// /// The 18th day of July of the current year /// public static DateTime The18th => new(DateTime.Now.Year, 7, 18); /// /// The 19th day of July of the current year /// public static DateTime The19th => new(DateTime.Now.Year, 7, 19); /// /// The 20th day of July of the current year /// public static DateTime The20th => new(DateTime.Now.Year, 7, 20); /// /// The 21st day of July of the current year /// public static DateTime The21st => new(DateTime.Now.Year, 7, 21); /// /// The 22nd day of July of the current year /// public static DateTime The22nd => new(DateTime.Now.Year, 7, 22); /// /// The 23rd day of July of the current year /// public static DateTime The23rd => new(DateTime.Now.Year, 7, 23); /// /// The 24th day of July of the current year /// public static DateTime The24th => new(DateTime.Now.Year, 7, 24); /// /// The 25th day of July of the current year /// public static DateTime The25th => new(DateTime.Now.Year, 7, 25); /// /// The 26th day of July of the current year /// public static DateTime The26th => new(DateTime.Now.Year, 7, 26); /// /// The 27th day of July of the current year /// public static DateTime The27th => new(DateTime.Now.Year, 7, 27); /// /// The 28th day of July of the current year /// public static DateTime The28th => new(DateTime.Now.Year, 7, 28); /// /// The 29th day of July of the current year /// public static DateTime The29th => new(DateTime.Now.Year, 7, 29); /// /// The 30th day of July of the current year /// public static DateTime The30th => new(DateTime.Now.Year, 7, 30); /// /// The 31st day of July of the current year /// public static DateTime The31st => new(DateTime.Now.Year, 7, 31); } /// /// Provides fluent date accessors for August /// public class August { /// /// The nth day of August of the current year /// public static DateTime The(int dayNumber) => new(DateTime.Now.Year, 8, dayNumber); /// /// The 1st day of August of the current year /// public static DateTime The1st => new(DateTime.Now.Year, 8, 1); /// /// The 2nd day of August of the current year /// public static DateTime The2nd => new(DateTime.Now.Year, 8, 2); /// /// The 3rd day of August of the current year /// public static DateTime The3rd => new(DateTime.Now.Year, 8, 3); /// /// The 4th day of August of the current year /// public static DateTime The4th => new(DateTime.Now.Year, 8, 4); /// /// The 5th day of August of the current year /// public static DateTime The5th => new(DateTime.Now.Year, 8, 5); /// /// The 6th day of August of the current year /// public static DateTime The6th => new(DateTime.Now.Year, 8, 6); /// /// The 7th day of August of the current year /// public static DateTime The7th => new(DateTime.Now.Year, 8, 7); /// /// The 8th day of August of the current year /// public static DateTime The8th => new(DateTime.Now.Year, 8, 8); /// /// The 9th day of August of the current year /// public static DateTime The9th => new(DateTime.Now.Year, 8, 9); /// /// The 10th day of August of the current year /// public static DateTime The10th => new(DateTime.Now.Year, 8, 10); /// /// The 11th day of August of the current year /// public static DateTime The11th => new(DateTime.Now.Year, 8, 11); /// /// The 12th day of August of the current year /// public static DateTime The12th => new(DateTime.Now.Year, 8, 12); /// /// The 13th day of August of the current year /// public static DateTime The13th => new(DateTime.Now.Year, 8, 13); /// /// The 14th day of August of the current year /// public static DateTime The14th => new(DateTime.Now.Year, 8, 14); /// /// The 15th day of August of the current year /// public static DateTime The15th => new(DateTime.Now.Year, 8, 15); /// /// The 16th day of August of the current year /// public static DateTime The16th => new(DateTime.Now.Year, 8, 16); /// /// The 17th day of August of the current year /// public static DateTime The17th => new(DateTime.Now.Year, 8, 17); /// /// The 18th day of August of the current year /// public static DateTime The18th => new(DateTime.Now.Year, 8, 18); /// /// The 19th day of August of the current year /// public static DateTime The19th => new(DateTime.Now.Year, 8, 19); /// /// The 20th day of August of the current year /// public static DateTime The20th => new(DateTime.Now.Year, 8, 20); /// /// The 21st day of August of the current year /// public static DateTime The21st => new(DateTime.Now.Year, 8, 21); /// /// The 22nd day of August of the current year /// public static DateTime The22nd => new(DateTime.Now.Year, 8, 22); /// /// The 23rd day of August of the current year /// public static DateTime The23rd => new(DateTime.Now.Year, 8, 23); /// /// The 24th day of August of the current year /// public static DateTime The24th => new(DateTime.Now.Year, 8, 24); /// /// The 25th day of August of the current year /// public static DateTime The25th => new(DateTime.Now.Year, 8, 25); /// /// The 26th day of August of the current year /// public static DateTime The26th => new(DateTime.Now.Year, 8, 26); /// /// The 27th day of August of the current year /// public static DateTime The27th => new(DateTime.Now.Year, 8, 27); /// /// The 28th day of August of the current year /// public static DateTime The28th => new(DateTime.Now.Year, 8, 28); /// /// The 29th day of August of the current year /// public static DateTime The29th => new(DateTime.Now.Year, 8, 29); /// /// The 30th day of August of the current year /// public static DateTime The30th => new(DateTime.Now.Year, 8, 30); /// /// The 31st day of August of the current year /// public static DateTime The31st => new(DateTime.Now.Year, 8, 31); } /// /// Provides fluent date accessors for September /// public class September { /// /// The nth day of September of the current year /// public static DateTime The(int dayNumber) => new(DateTime.Now.Year, 9, dayNumber); /// /// The 1st day of September of the current year /// public static DateTime The1st => new(DateTime.Now.Year, 9, 1); /// /// The 2nd day of September of the current year /// public static DateTime The2nd => new(DateTime.Now.Year, 9, 2); /// /// The 3rd day of September of the current year /// public static DateTime The3rd => new(DateTime.Now.Year, 9, 3); /// /// The 4th day of September of the current year /// public static DateTime The4th => new(DateTime.Now.Year, 9, 4); /// /// The 5th day of September of the current year /// public static DateTime The5th => new(DateTime.Now.Year, 9, 5); /// /// The 6th day of September of the current year /// public static DateTime The6th => new(DateTime.Now.Year, 9, 6); /// /// The 7th day of September of the current year /// public static DateTime The7th => new(DateTime.Now.Year, 9, 7); /// /// The 8th day of September of the current year /// public static DateTime The8th => new(DateTime.Now.Year, 9, 8); /// /// The 9th day of September of the current year /// public static DateTime The9th => new(DateTime.Now.Year, 9, 9); /// /// The 10th day of September of the current year /// public static DateTime The10th => new(DateTime.Now.Year, 9, 10); /// /// The 11th day of September of the current year /// public static DateTime The11th => new(DateTime.Now.Year, 9, 11); /// /// The 12th day of September of the current year /// public static DateTime The12th => new(DateTime.Now.Year, 9, 12); /// /// The 13th day of September of the current year /// public static DateTime The13th => new(DateTime.Now.Year, 9, 13); /// /// The 14th day of September of the current year /// public static DateTime The14th => new(DateTime.Now.Year, 9, 14); /// /// The 15th day of September of the current year /// public static DateTime The15th => new(DateTime.Now.Year, 9, 15); /// /// The 16th day of September of the current year /// public static DateTime The16th => new(DateTime.Now.Year, 9, 16); /// /// The 17th day of September of the current year /// public static DateTime The17th => new(DateTime.Now.Year, 9, 17); /// /// The 18th day of September of the current year /// public static DateTime The18th => new(DateTime.Now.Year, 9, 18); /// /// The 19th day of September of the current year /// public static DateTime The19th => new(DateTime.Now.Year, 9, 19); /// /// The 20th day of September of the current year /// public static DateTime The20th => new(DateTime.Now.Year, 9, 20); /// /// The 21st day of September of the current year /// public static DateTime The21st => new(DateTime.Now.Year, 9, 21); /// /// The 22nd day of September of the current year /// public static DateTime The22nd => new(DateTime.Now.Year, 9, 22); /// /// The 23rd day of September of the current year /// public static DateTime The23rd => new(DateTime.Now.Year, 9, 23); /// /// The 24th day of September of the current year /// public static DateTime The24th => new(DateTime.Now.Year, 9, 24); /// /// The 25th day of September of the current year /// public static DateTime The25th => new(DateTime.Now.Year, 9, 25); /// /// The 26th day of September of the current year /// public static DateTime The26th => new(DateTime.Now.Year, 9, 26); /// /// The 27th day of September of the current year /// public static DateTime The27th => new(DateTime.Now.Year, 9, 27); /// /// The 28th day of September of the current year /// public static DateTime The28th => new(DateTime.Now.Year, 9, 28); /// /// The 29th day of September of the current year /// public static DateTime The29th => new(DateTime.Now.Year, 9, 29); /// /// The 30th day of September of the current year /// public static DateTime The30th => new(DateTime.Now.Year, 9, 30); } /// /// Provides fluent date accessors for October /// public class October { /// /// The nth day of October of the current year /// public static DateTime The(int dayNumber) => new(DateTime.Now.Year, 10, dayNumber); /// /// The 1st day of October of the current year /// public static DateTime The1st => new(DateTime.Now.Year, 10, 1); /// /// The 2nd day of October of the current year /// public static DateTime The2nd => new(DateTime.Now.Year, 10, 2); /// /// The 3rd day of October of the current year /// public static DateTime The3rd => new(DateTime.Now.Year, 10, 3); /// /// The 4th day of October of the current year /// public static DateTime The4th => new(DateTime.Now.Year, 10, 4); /// /// The 5th day of October of the current year /// public static DateTime The5th => new(DateTime.Now.Year, 10, 5); /// /// The 6th day of October of the current year /// public static DateTime The6th => new(DateTime.Now.Year, 10, 6); /// /// The 7th day of October of the current year /// public static DateTime The7th => new(DateTime.Now.Year, 10, 7); /// /// The 8th day of October of the current year /// public static DateTime The8th => new(DateTime.Now.Year, 10, 8); /// /// The 9th day of October of the current year /// public static DateTime The9th => new(DateTime.Now.Year, 10, 9); /// /// The 10th day of October of the current year /// public static DateTime The10th => new(DateTime.Now.Year, 10, 10); /// /// The 11th day of October of the current year /// public static DateTime The11th => new(DateTime.Now.Year, 10, 11); /// /// The 12th day of October of the current year /// public static DateTime The12th => new(DateTime.Now.Year, 10, 12); /// /// The 13th day of October of the current year /// public static DateTime The13th => new(DateTime.Now.Year, 10, 13); /// /// The 14th day of October of the current year /// public static DateTime The14th => new(DateTime.Now.Year, 10, 14); /// /// The 15th day of October of the current year /// public static DateTime The15th => new(DateTime.Now.Year, 10, 15); /// /// The 16th day of October of the current year /// public static DateTime The16th => new(DateTime.Now.Year, 10, 16); /// /// The 17th day of October of the current year /// public static DateTime The17th => new(DateTime.Now.Year, 10, 17); /// /// The 18th day of October of the current year /// public static DateTime The18th => new(DateTime.Now.Year, 10, 18); /// /// The 19th day of October of the current year /// public static DateTime The19th => new(DateTime.Now.Year, 10, 19); /// /// The 20th day of October of the current year /// public static DateTime The20th => new(DateTime.Now.Year, 10, 20); /// /// The 21st day of October of the current year /// public static DateTime The21st => new(DateTime.Now.Year, 10, 21); /// /// The 22nd day of October of the current year /// public static DateTime The22nd => new(DateTime.Now.Year, 10, 22); /// /// The 23rd day of October of the current year /// public static DateTime The23rd => new(DateTime.Now.Year, 10, 23); /// /// The 24th day of October of the current year /// public static DateTime The24th => new(DateTime.Now.Year, 10, 24); /// /// The 25th day of October of the current year /// public static DateTime The25th => new(DateTime.Now.Year, 10, 25); /// /// The 26th day of October of the current year /// public static DateTime The26th => new(DateTime.Now.Year, 10, 26); /// /// The 27th day of October of the current year /// public static DateTime The27th => new(DateTime.Now.Year, 10, 27); /// /// The 28th day of October of the current year /// public static DateTime The28th => new(DateTime.Now.Year, 10, 28); /// /// The 29th day of October of the current year /// public static DateTime The29th => new(DateTime.Now.Year, 10, 29); /// /// The 30th day of October of the current year /// public static DateTime The30th => new(DateTime.Now.Year, 10, 30); /// /// The 31st day of October of the current year /// public static DateTime The31st => new(DateTime.Now.Year, 10, 31); } /// /// Provides fluent date accessors for November /// public class November { /// /// The nth day of November of the current year /// public static DateTime The(int dayNumber) => new(DateTime.Now.Year, 11, dayNumber); /// /// The 1st day of November of the current year /// public static DateTime The1st => new(DateTime.Now.Year, 11, 1); /// /// The 2nd day of November of the current year /// public static DateTime The2nd => new(DateTime.Now.Year, 11, 2); /// /// The 3rd day of November of the current year /// public static DateTime The3rd => new(DateTime.Now.Year, 11, 3); /// /// The 4th day of November of the current year /// public static DateTime The4th => new(DateTime.Now.Year, 11, 4); /// /// The 5th day of November of the current year /// public static DateTime The5th => new(DateTime.Now.Year, 11, 5); /// /// The 6th day of November of the current year /// public static DateTime The6th => new(DateTime.Now.Year, 11, 6); /// /// The 7th day of November of the current year /// public static DateTime The7th => new(DateTime.Now.Year, 11, 7); /// /// The 8th day of November of the current year /// public static DateTime The8th => new(DateTime.Now.Year, 11, 8); /// /// The 9th day of November of the current year /// public static DateTime The9th => new(DateTime.Now.Year, 11, 9); /// /// The 10th day of November of the current year /// public static DateTime The10th => new(DateTime.Now.Year, 11, 10); /// /// The 11th day of November of the current year /// public static DateTime The11th => new(DateTime.Now.Year, 11, 11); /// /// The 12th day of November of the current year /// public static DateTime The12th => new(DateTime.Now.Year, 11, 12); /// /// The 13th day of November of the current year /// public static DateTime The13th => new(DateTime.Now.Year, 11, 13); /// /// The 14th day of November of the current year /// public static DateTime The14th => new(DateTime.Now.Year, 11, 14); /// /// The 15th day of November of the current year /// public static DateTime The15th => new(DateTime.Now.Year, 11, 15); /// /// The 16th day of November of the current year /// public static DateTime The16th => new(DateTime.Now.Year, 11, 16); /// /// The 17th day of November of the current year /// public static DateTime The17th => new(DateTime.Now.Year, 11, 17); /// /// The 18th day of November of the current year /// public static DateTime The18th => new(DateTime.Now.Year, 11, 18); /// /// The 19th day of November of the current year /// public static DateTime The19th => new(DateTime.Now.Year, 11, 19); /// /// The 20th day of November of the current year /// public static DateTime The20th => new(DateTime.Now.Year, 11, 20); /// /// The 21st day of November of the current year /// public static DateTime The21st => new(DateTime.Now.Year, 11, 21); /// /// The 22nd day of November of the current year /// public static DateTime The22nd => new(DateTime.Now.Year, 11, 22); /// /// The 23rd day of November of the current year /// public static DateTime The23rd => new(DateTime.Now.Year, 11, 23); /// /// The 24th day of November of the current year /// public static DateTime The24th => new(DateTime.Now.Year, 11, 24); /// /// The 25th day of November of the current year /// public static DateTime The25th => new(DateTime.Now.Year, 11, 25); /// /// The 26th day of November of the current year /// public static DateTime The26th => new(DateTime.Now.Year, 11, 26); /// /// The 27th day of November of the current year /// public static DateTime The27th => new(DateTime.Now.Year, 11, 27); /// /// The 28th day of November of the current year /// public static DateTime The28th => new(DateTime.Now.Year, 11, 28); /// /// The 29th day of November of the current year /// public static DateTime The29th => new(DateTime.Now.Year, 11, 29); /// /// The 30th day of November of the current year /// public static DateTime The30th => new(DateTime.Now.Year, 11, 30); } /// /// Provides fluent date accessors for December /// public class December { /// /// The nth day of December of the current year /// public static DateTime The(int dayNumber) => new(DateTime.Now.Year, 12, dayNumber); /// /// The 1st day of December of the current year /// public static DateTime The1st => new(DateTime.Now.Year, 12, 1); /// /// The 2nd day of December of the current year /// public static DateTime The2nd => new(DateTime.Now.Year, 12, 2); /// /// The 3rd day of December of the current year /// public static DateTime The3rd => new(DateTime.Now.Year, 12, 3); /// /// The 4th day of December of the current year /// public static DateTime The4th => new(DateTime.Now.Year, 12, 4); /// /// The 5th day of December of the current year /// public static DateTime The5th => new(DateTime.Now.Year, 12, 5); /// /// The 6th day of December of the current year /// public static DateTime The6th => new(DateTime.Now.Year, 12, 6); /// /// The 7th day of December of the current year /// public static DateTime The7th => new(DateTime.Now.Year, 12, 7); /// /// The 8th day of December of the current year /// public static DateTime The8th => new(DateTime.Now.Year, 12, 8); /// /// The 9th day of December of the current year /// public static DateTime The9th => new(DateTime.Now.Year, 12, 9); /// /// The 10th day of December of the current year /// public static DateTime The10th => new(DateTime.Now.Year, 12, 10); /// /// The 11th day of December of the current year /// public static DateTime The11th => new(DateTime.Now.Year, 12, 11); /// /// The 12th day of December of the current year /// public static DateTime The12th => new(DateTime.Now.Year, 12, 12); /// /// The 13th day of December of the current year /// public static DateTime The13th => new(DateTime.Now.Year, 12, 13); /// /// The 14th day of December of the current year /// public static DateTime The14th => new(DateTime.Now.Year, 12, 14); /// /// The 15th day of December of the current year /// public static DateTime The15th => new(DateTime.Now.Year, 12, 15); /// /// The 16th day of December of the current year /// public static DateTime The16th => new(DateTime.Now.Year, 12, 16); /// /// The 17th day of December of the current year /// public static DateTime The17th => new(DateTime.Now.Year, 12, 17); /// /// The 18th day of December of the current year /// public static DateTime The18th => new(DateTime.Now.Year, 12, 18); /// /// The 19th day of December of the current year /// public static DateTime The19th => new(DateTime.Now.Year, 12, 19); /// /// The 20th day of December of the current year /// public static DateTime The20th => new(DateTime.Now.Year, 12, 20); /// /// The 21st day of December of the current year /// public static DateTime The21st => new(DateTime.Now.Year, 12, 21); /// /// The 22nd day of December of the current year /// public static DateTime The22nd => new(DateTime.Now.Year, 12, 22); /// /// The 23rd day of December of the current year /// public static DateTime The23rd => new(DateTime.Now.Year, 12, 23); /// /// The 24th day of December of the current year /// public static DateTime The24th => new(DateTime.Now.Year, 12, 24); /// /// The 25th day of December of the current year /// public static DateTime The25th => new(DateTime.Now.Year, 12, 25); /// /// The 26th day of December of the current year /// public static DateTime The26th => new(DateTime.Now.Year, 12, 26); /// /// The 27th day of December of the current year /// public static DateTime The27th => new(DateTime.Now.Year, 12, 27); /// /// The 28th day of December of the current year /// public static DateTime The28th => new(DateTime.Now.Year, 12, 28); /// /// The 29th day of December of the current year /// public static DateTime The29th => new(DateTime.Now.Year, 12, 29); /// /// The 30th day of December of the current year /// public static DateTime The30th => new(DateTime.Now.Year, 12, 30); /// /// The 31st day of December of the current year /// public static DateTime The31st => new(DateTime.Now.Year, 12, 31); } } ================================================ FILE: src/Humanizer/FluentDate/On.Days.tt ================================================ <#@ template debug="true" hostSpecific="true" #> <#@ output extension=".cs" #> <#@ Assembly Name="System.Core" #> <#@ Assembly Name="System.Windows.Forms" #> <#@ assembly name="$(TargetPath)" #> <#@ import namespace="System" #> <#@ import namespace="Humanizer" #> namespace Humanizer; public class On { <# const int leapYear = 2012; for (var month = 1; month <= 12; month++) { var firstDayOfMonth = new DateTime(leapYear, month, 1); var monthName = firstDayOfMonth.ToString("MMMM");#> /// /// Provides fluent date accessors for <#= monthName #> /// public class <#= monthName #> { /// /// The nth day of <#= monthName #> of the current year /// public static DateTime The(int dayNumber) => new(DateTime.Now.Year, <#= month #>, dayNumber); <#for (var day = 1; day <= DateTime.DaysInMonth(leapYear, month); day++) { var ordinalDay = day.Ordinalize();#> /// /// The <#= ordinalDay #> day of <#= monthName #> of the current year /// public static DateTime The<#= ordinalDay #> => new(DateTime.Now.Year, <#= month #>, <#= day #>); <#}#> } <#}#> } ================================================ FILE: src/Humanizer/FluentDate/OnDate.Days.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; public class OnDate { /// /// Provides fluent date accessors for January /// public class January { /// /// The nth day of January of the current year /// public static DateOnly The(int dayNumber) => new(DateTime.Now.Year, 1, dayNumber); /// /// The 1st day of January of the current year /// public static DateOnly The1st => new(DateTime.Now.Year, 1, 1); /// /// The 2nd day of January of the current year /// public static DateOnly The2nd => new(DateTime.Now.Year, 1, 2); /// /// The 3rd day of January of the current year /// public static DateOnly The3rd => new(DateTime.Now.Year, 1, 3); /// /// The 4th day of January of the current year /// public static DateOnly The4th => new(DateTime.Now.Year, 1, 4); /// /// The 5th day of January of the current year /// public static DateOnly The5th => new(DateTime.Now.Year, 1, 5); /// /// The 6th day of January of the current year /// public static DateOnly The6th => new(DateTime.Now.Year, 1, 6); /// /// The 7th day of January of the current year /// public static DateOnly The7th => new(DateTime.Now.Year, 1, 7); /// /// The 8th day of January of the current year /// public static DateOnly The8th => new(DateTime.Now.Year, 1, 8); /// /// The 9th day of January of the current year /// public static DateOnly The9th => new(DateTime.Now.Year, 1, 9); /// /// The 10th day of January of the current year /// public static DateOnly The10th => new(DateTime.Now.Year, 1, 10); /// /// The 11th day of January of the current year /// public static DateOnly The11th => new(DateTime.Now.Year, 1, 11); /// /// The 12th day of January of the current year /// public static DateOnly The12th => new(DateTime.Now.Year, 1, 12); /// /// The 13th day of January of the current year /// public static DateOnly The13th => new(DateTime.Now.Year, 1, 13); /// /// The 14th day of January of the current year /// public static DateOnly The14th => new(DateTime.Now.Year, 1, 14); /// /// The 15th day of January of the current year /// public static DateOnly The15th => new(DateTime.Now.Year, 1, 15); /// /// The 16th day of January of the current year /// public static DateOnly The16th => new(DateTime.Now.Year, 1, 16); /// /// The 17th day of January of the current year /// public static DateOnly The17th => new(DateTime.Now.Year, 1, 17); /// /// The 18th day of January of the current year /// public static DateOnly The18th => new(DateTime.Now.Year, 1, 18); /// /// The 19th day of January of the current year /// public static DateOnly The19th => new(DateTime.Now.Year, 1, 19); /// /// The 20th day of January of the current year /// public static DateOnly The20th => new(DateTime.Now.Year, 1, 20); /// /// The 21st day of January of the current year /// public static DateOnly The21st => new(DateTime.Now.Year, 1, 21); /// /// The 22nd day of January of the current year /// public static DateOnly The22nd => new(DateTime.Now.Year, 1, 22); /// /// The 23rd day of January of the current year /// public static DateOnly The23rd => new(DateTime.Now.Year, 1, 23); /// /// The 24th day of January of the current year /// public static DateOnly The24th => new(DateTime.Now.Year, 1, 24); /// /// The 25th day of January of the current year /// public static DateOnly The25th => new(DateTime.Now.Year, 1, 25); /// /// The 26th day of January of the current year /// public static DateOnly The26th => new(DateTime.Now.Year, 1, 26); /// /// The 27th day of January of the current year /// public static DateOnly The27th => new(DateTime.Now.Year, 1, 27); /// /// The 28th day of January of the current year /// public static DateOnly The28th => new(DateTime.Now.Year, 1, 28); /// /// The 29th day of January of the current year /// public static DateOnly The29th => new(DateTime.Now.Year, 1, 29); /// /// The 30th day of January of the current year /// public static DateOnly The30th => new(DateTime.Now.Year, 1, 30); /// /// The 31st day of January of the current year /// public static DateOnly The31st => new(DateTime.Now.Year, 1, 31); } /// /// Provides fluent date accessors for February /// public class February { /// /// The nth day of February of the current year /// public static DateOnly The(int dayNumber) => new(DateTime.Now.Year, 2, dayNumber); /// /// The 1st day of February of the current year /// public static DateOnly The1st => new(DateTime.Now.Year, 2, 1); /// /// The 2nd day of February of the current year /// public static DateOnly The2nd => new(DateTime.Now.Year, 2, 2); /// /// The 3rd day of February of the current year /// public static DateOnly The3rd => new(DateTime.Now.Year, 2, 3); /// /// The 4th day of February of the current year /// public static DateOnly The4th => new(DateTime.Now.Year, 2, 4); /// /// The 5th day of February of the current year /// public static DateOnly The5th => new(DateTime.Now.Year, 2, 5); /// /// The 6th day of February of the current year /// public static DateOnly The6th => new(DateTime.Now.Year, 2, 6); /// /// The 7th day of February of the current year /// public static DateOnly The7th => new(DateTime.Now.Year, 2, 7); /// /// The 8th day of February of the current year /// public static DateOnly The8th => new(DateTime.Now.Year, 2, 8); /// /// The 9th day of February of the current year /// public static DateOnly The9th => new(DateTime.Now.Year, 2, 9); /// /// The 10th day of February of the current year /// public static DateOnly The10th => new(DateTime.Now.Year, 2, 10); /// /// The 11th day of February of the current year /// public static DateOnly The11th => new(DateTime.Now.Year, 2, 11); /// /// The 12th day of February of the current year /// public static DateOnly The12th => new(DateTime.Now.Year, 2, 12); /// /// The 13th day of February of the current year /// public static DateOnly The13th => new(DateTime.Now.Year, 2, 13); /// /// The 14th day of February of the current year /// public static DateOnly The14th => new(DateTime.Now.Year, 2, 14); /// /// The 15th day of February of the current year /// public static DateOnly The15th => new(DateTime.Now.Year, 2, 15); /// /// The 16th day of February of the current year /// public static DateOnly The16th => new(DateTime.Now.Year, 2, 16); /// /// The 17th day of February of the current year /// public static DateOnly The17th => new(DateTime.Now.Year, 2, 17); /// /// The 18th day of February of the current year /// public static DateOnly The18th => new(DateTime.Now.Year, 2, 18); /// /// The 19th day of February of the current year /// public static DateOnly The19th => new(DateTime.Now.Year, 2, 19); /// /// The 20th day of February of the current year /// public static DateOnly The20th => new(DateTime.Now.Year, 2, 20); /// /// The 21st day of February of the current year /// public static DateOnly The21st => new(DateTime.Now.Year, 2, 21); /// /// The 22nd day of February of the current year /// public static DateOnly The22nd => new(DateTime.Now.Year, 2, 22); /// /// The 23rd day of February of the current year /// public static DateOnly The23rd => new(DateTime.Now.Year, 2, 23); /// /// The 24th day of February of the current year /// public static DateOnly The24th => new(DateTime.Now.Year, 2, 24); /// /// The 25th day of February of the current year /// public static DateOnly The25th => new(DateTime.Now.Year, 2, 25); /// /// The 26th day of February of the current year /// public static DateOnly The26th => new(DateTime.Now.Year, 2, 26); /// /// The 27th day of February of the current year /// public static DateOnly The27th => new(DateTime.Now.Year, 2, 27); /// /// The 28th day of February of the current year /// public static DateOnly The28th => new(DateTime.Now.Year, 2, 28); /// /// The 29th day of February of the current year /// public static DateOnly The29th => new(DateTime.Now.Year, 2, 29); } /// /// Provides fluent date accessors for March /// public class March { /// /// The nth day of March of the current year /// public static DateOnly The(int dayNumber) => new(DateTime.Now.Year, 3, dayNumber); /// /// The 1st day of March of the current year /// public static DateOnly The1st => new(DateTime.Now.Year, 3, 1); /// /// The 2nd day of March of the current year /// public static DateOnly The2nd => new(DateTime.Now.Year, 3, 2); /// /// The 3rd day of March of the current year /// public static DateOnly The3rd => new(DateTime.Now.Year, 3, 3); /// /// The 4th day of March of the current year /// public static DateOnly The4th => new(DateTime.Now.Year, 3, 4); /// /// The 5th day of March of the current year /// public static DateOnly The5th => new(DateTime.Now.Year, 3, 5); /// /// The 6th day of March of the current year /// public static DateOnly The6th => new(DateTime.Now.Year, 3, 6); /// /// The 7th day of March of the current year /// public static DateOnly The7th => new(DateTime.Now.Year, 3, 7); /// /// The 8th day of March of the current year /// public static DateOnly The8th => new(DateTime.Now.Year, 3, 8); /// /// The 9th day of March of the current year /// public static DateOnly The9th => new(DateTime.Now.Year, 3, 9); /// /// The 10th day of March of the current year /// public static DateOnly The10th => new(DateTime.Now.Year, 3, 10); /// /// The 11th day of March of the current year /// public static DateOnly The11th => new(DateTime.Now.Year, 3, 11); /// /// The 12th day of March of the current year /// public static DateOnly The12th => new(DateTime.Now.Year, 3, 12); /// /// The 13th day of March of the current year /// public static DateOnly The13th => new(DateTime.Now.Year, 3, 13); /// /// The 14th day of March of the current year /// public static DateOnly The14th => new(DateTime.Now.Year, 3, 14); /// /// The 15th day of March of the current year /// public static DateOnly The15th => new(DateTime.Now.Year, 3, 15); /// /// The 16th day of March of the current year /// public static DateOnly The16th => new(DateTime.Now.Year, 3, 16); /// /// The 17th day of March of the current year /// public static DateOnly The17th => new(DateTime.Now.Year, 3, 17); /// /// The 18th day of March of the current year /// public static DateOnly The18th => new(DateTime.Now.Year, 3, 18); /// /// The 19th day of March of the current year /// public static DateOnly The19th => new(DateTime.Now.Year, 3, 19); /// /// The 20th day of March of the current year /// public static DateOnly The20th => new(DateTime.Now.Year, 3, 20); /// /// The 21st day of March of the current year /// public static DateOnly The21st => new(DateTime.Now.Year, 3, 21); /// /// The 22nd day of March of the current year /// public static DateOnly The22nd => new(DateTime.Now.Year, 3, 22); /// /// The 23rd day of March of the current year /// public static DateOnly The23rd => new(DateTime.Now.Year, 3, 23); /// /// The 24th day of March of the current year /// public static DateOnly The24th => new(DateTime.Now.Year, 3, 24); /// /// The 25th day of March of the current year /// public static DateOnly The25th => new(DateTime.Now.Year, 3, 25); /// /// The 26th day of March of the current year /// public static DateOnly The26th => new(DateTime.Now.Year, 3, 26); /// /// The 27th day of March of the current year /// public static DateOnly The27th => new(DateTime.Now.Year, 3, 27); /// /// The 28th day of March of the current year /// public static DateOnly The28th => new(DateTime.Now.Year, 3, 28); /// /// The 29th day of March of the current year /// public static DateOnly The29th => new(DateTime.Now.Year, 3, 29); /// /// The 30th day of March of the current year /// public static DateOnly The30th => new(DateTime.Now.Year, 3, 30); /// /// The 31st day of March of the current year /// public static DateOnly The31st => new(DateTime.Now.Year, 3, 31); } /// /// Provides fluent date accessors for April /// public class April { /// /// The nth day of April of the current year /// public static DateOnly The(int dayNumber) => new(DateTime.Now.Year, 4, dayNumber); /// /// The 1st day of April of the current year /// public static DateOnly The1st => new(DateTime.Now.Year, 4, 1); /// /// The 2nd day of April of the current year /// public static DateOnly The2nd => new(DateTime.Now.Year, 4, 2); /// /// The 3rd day of April of the current year /// public static DateOnly The3rd => new(DateTime.Now.Year, 4, 3); /// /// The 4th day of April of the current year /// public static DateOnly The4th => new(DateTime.Now.Year, 4, 4); /// /// The 5th day of April of the current year /// public static DateOnly The5th => new(DateTime.Now.Year, 4, 5); /// /// The 6th day of April of the current year /// public static DateOnly The6th => new(DateTime.Now.Year, 4, 6); /// /// The 7th day of April of the current year /// public static DateOnly The7th => new(DateTime.Now.Year, 4, 7); /// /// The 8th day of April of the current year /// public static DateOnly The8th => new(DateTime.Now.Year, 4, 8); /// /// The 9th day of April of the current year /// public static DateOnly The9th => new(DateTime.Now.Year, 4, 9); /// /// The 10th day of April of the current year /// public static DateOnly The10th => new(DateTime.Now.Year, 4, 10); /// /// The 11th day of April of the current year /// public static DateOnly The11th => new(DateTime.Now.Year, 4, 11); /// /// The 12th day of April of the current year /// public static DateOnly The12th => new(DateTime.Now.Year, 4, 12); /// /// The 13th day of April of the current year /// public static DateOnly The13th => new(DateTime.Now.Year, 4, 13); /// /// The 14th day of April of the current year /// public static DateOnly The14th => new(DateTime.Now.Year, 4, 14); /// /// The 15th day of April of the current year /// public static DateOnly The15th => new(DateTime.Now.Year, 4, 15); /// /// The 16th day of April of the current year /// public static DateOnly The16th => new(DateTime.Now.Year, 4, 16); /// /// The 17th day of April of the current year /// public static DateOnly The17th => new(DateTime.Now.Year, 4, 17); /// /// The 18th day of April of the current year /// public static DateOnly The18th => new(DateTime.Now.Year, 4, 18); /// /// The 19th day of April of the current year /// public static DateOnly The19th => new(DateTime.Now.Year, 4, 19); /// /// The 20th day of April of the current year /// public static DateOnly The20th => new(DateTime.Now.Year, 4, 20); /// /// The 21st day of April of the current year /// public static DateOnly The21st => new(DateTime.Now.Year, 4, 21); /// /// The 22nd day of April of the current year /// public static DateOnly The22nd => new(DateTime.Now.Year, 4, 22); /// /// The 23rd day of April of the current year /// public static DateOnly The23rd => new(DateTime.Now.Year, 4, 23); /// /// The 24th day of April of the current year /// public static DateOnly The24th => new(DateTime.Now.Year, 4, 24); /// /// The 25th day of April of the current year /// public static DateOnly The25th => new(DateTime.Now.Year, 4, 25); /// /// The 26th day of April of the current year /// public static DateOnly The26th => new(DateTime.Now.Year, 4, 26); /// /// The 27th day of April of the current year /// public static DateOnly The27th => new(DateTime.Now.Year, 4, 27); /// /// The 28th day of April of the current year /// public static DateOnly The28th => new(DateTime.Now.Year, 4, 28); /// /// The 29th day of April of the current year /// public static DateOnly The29th => new(DateTime.Now.Year, 4, 29); /// /// The 30th day of April of the current year /// public static DateOnly The30th => new(DateTime.Now.Year, 4, 30); } /// /// Provides fluent date accessors for May /// public class May { /// /// The nth day of May of the current year /// public static DateOnly The(int dayNumber) => new(DateTime.Now.Year, 5, dayNumber); /// /// The 1st day of May of the current year /// public static DateOnly The1st => new(DateTime.Now.Year, 5, 1); /// /// The 2nd day of May of the current year /// public static DateOnly The2nd => new(DateTime.Now.Year, 5, 2); /// /// The 3rd day of May of the current year /// public static DateOnly The3rd => new(DateTime.Now.Year, 5, 3); /// /// The 4th day of May of the current year /// public static DateOnly The4th => new(DateTime.Now.Year, 5, 4); /// /// The 5th day of May of the current year /// public static DateOnly The5th => new(DateTime.Now.Year, 5, 5); /// /// The 6th day of May of the current year /// public static DateOnly The6th => new(DateTime.Now.Year, 5, 6); /// /// The 7th day of May of the current year /// public static DateOnly The7th => new(DateTime.Now.Year, 5, 7); /// /// The 8th day of May of the current year /// public static DateOnly The8th => new(DateTime.Now.Year, 5, 8); /// /// The 9th day of May of the current year /// public static DateOnly The9th => new(DateTime.Now.Year, 5, 9); /// /// The 10th day of May of the current year /// public static DateOnly The10th => new(DateTime.Now.Year, 5, 10); /// /// The 11th day of May of the current year /// public static DateOnly The11th => new(DateTime.Now.Year, 5, 11); /// /// The 12th day of May of the current year /// public static DateOnly The12th => new(DateTime.Now.Year, 5, 12); /// /// The 13th day of May of the current year /// public static DateOnly The13th => new(DateTime.Now.Year, 5, 13); /// /// The 14th day of May of the current year /// public static DateOnly The14th => new(DateTime.Now.Year, 5, 14); /// /// The 15th day of May of the current year /// public static DateOnly The15th => new(DateTime.Now.Year, 5, 15); /// /// The 16th day of May of the current year /// public static DateOnly The16th => new(DateTime.Now.Year, 5, 16); /// /// The 17th day of May of the current year /// public static DateOnly The17th => new(DateTime.Now.Year, 5, 17); /// /// The 18th day of May of the current year /// public static DateOnly The18th => new(DateTime.Now.Year, 5, 18); /// /// The 19th day of May of the current year /// public static DateOnly The19th => new(DateTime.Now.Year, 5, 19); /// /// The 20th day of May of the current year /// public static DateOnly The20th => new(DateTime.Now.Year, 5, 20); /// /// The 21st day of May of the current year /// public static DateOnly The21st => new(DateTime.Now.Year, 5, 21); /// /// The 22nd day of May of the current year /// public static DateOnly The22nd => new(DateTime.Now.Year, 5, 22); /// /// The 23rd day of May of the current year /// public static DateOnly The23rd => new(DateTime.Now.Year, 5, 23); /// /// The 24th day of May of the current year /// public static DateOnly The24th => new(DateTime.Now.Year, 5, 24); /// /// The 25th day of May of the current year /// public static DateOnly The25th => new(DateTime.Now.Year, 5, 25); /// /// The 26th day of May of the current year /// public static DateOnly The26th => new(DateTime.Now.Year, 5, 26); /// /// The 27th day of May of the current year /// public static DateOnly The27th => new(DateTime.Now.Year, 5, 27); /// /// The 28th day of May of the current year /// public static DateOnly The28th => new(DateTime.Now.Year, 5, 28); /// /// The 29th day of May of the current year /// public static DateOnly The29th => new(DateTime.Now.Year, 5, 29); /// /// The 30th day of May of the current year /// public static DateOnly The30th => new(DateTime.Now.Year, 5, 30); /// /// The 31st day of May of the current year /// public static DateOnly The31st => new(DateTime.Now.Year, 5, 31); } /// /// Provides fluent date accessors for June /// public class June { /// /// The nth day of June of the current year /// public static DateOnly The(int dayNumber) => new(DateTime.Now.Year, 6, dayNumber); /// /// The 1st day of June of the current year /// public static DateOnly The1st => new(DateTime.Now.Year, 6, 1); /// /// The 2nd day of June of the current year /// public static DateOnly The2nd => new(DateTime.Now.Year, 6, 2); /// /// The 3rd day of June of the current year /// public static DateOnly The3rd => new(DateTime.Now.Year, 6, 3); /// /// The 4th day of June of the current year /// public static DateOnly The4th => new(DateTime.Now.Year, 6, 4); /// /// The 5th day of June of the current year /// public static DateOnly The5th => new(DateTime.Now.Year, 6, 5); /// /// The 6th day of June of the current year /// public static DateOnly The6th => new(DateTime.Now.Year, 6, 6); /// /// The 7th day of June of the current year /// public static DateOnly The7th => new(DateTime.Now.Year, 6, 7); /// /// The 8th day of June of the current year /// public static DateOnly The8th => new(DateTime.Now.Year, 6, 8); /// /// The 9th day of June of the current year /// public static DateOnly The9th => new(DateTime.Now.Year, 6, 9); /// /// The 10th day of June of the current year /// public static DateOnly The10th => new(DateTime.Now.Year, 6, 10); /// /// The 11th day of June of the current year /// public static DateOnly The11th => new(DateTime.Now.Year, 6, 11); /// /// The 12th day of June of the current year /// public static DateOnly The12th => new(DateTime.Now.Year, 6, 12); /// /// The 13th day of June of the current year /// public static DateOnly The13th => new(DateTime.Now.Year, 6, 13); /// /// The 14th day of June of the current year /// public static DateOnly The14th => new(DateTime.Now.Year, 6, 14); /// /// The 15th day of June of the current year /// public static DateOnly The15th => new(DateTime.Now.Year, 6, 15); /// /// The 16th day of June of the current year /// public static DateOnly The16th => new(DateTime.Now.Year, 6, 16); /// /// The 17th day of June of the current year /// public static DateOnly The17th => new(DateTime.Now.Year, 6, 17); /// /// The 18th day of June of the current year /// public static DateOnly The18th => new(DateTime.Now.Year, 6, 18); /// /// The 19th day of June of the current year /// public static DateOnly The19th => new(DateTime.Now.Year, 6, 19); /// /// The 20th day of June of the current year /// public static DateOnly The20th => new(DateTime.Now.Year, 6, 20); /// /// The 21st day of June of the current year /// public static DateOnly The21st => new(DateTime.Now.Year, 6, 21); /// /// The 22nd day of June of the current year /// public static DateOnly The22nd => new(DateTime.Now.Year, 6, 22); /// /// The 23rd day of June of the current year /// public static DateOnly The23rd => new(DateTime.Now.Year, 6, 23); /// /// The 24th day of June of the current year /// public static DateOnly The24th => new(DateTime.Now.Year, 6, 24); /// /// The 25th day of June of the current year /// public static DateOnly The25th => new(DateTime.Now.Year, 6, 25); /// /// The 26th day of June of the current year /// public static DateOnly The26th => new(DateTime.Now.Year, 6, 26); /// /// The 27th day of June of the current year /// public static DateOnly The27th => new(DateTime.Now.Year, 6, 27); /// /// The 28th day of June of the current year /// public static DateOnly The28th => new(DateTime.Now.Year, 6, 28); /// /// The 29th day of June of the current year /// public static DateOnly The29th => new(DateTime.Now.Year, 6, 29); /// /// The 30th day of June of the current year /// public static DateOnly The30th => new(DateTime.Now.Year, 6, 30); } /// /// Provides fluent date accessors for July /// public class July { /// /// The nth day of July of the current year /// public static DateOnly The(int dayNumber) => new(DateTime.Now.Year, 7, dayNumber); /// /// The 1st day of July of the current year /// public static DateOnly The1st => new(DateTime.Now.Year, 7, 1); /// /// The 2nd day of July of the current year /// public static DateOnly The2nd => new(DateTime.Now.Year, 7, 2); /// /// The 3rd day of July of the current year /// public static DateOnly The3rd => new(DateTime.Now.Year, 7, 3); /// /// The 4th day of July of the current year /// public static DateOnly The4th => new(DateTime.Now.Year, 7, 4); /// /// The 5th day of July of the current year /// public static DateOnly The5th => new(DateTime.Now.Year, 7, 5); /// /// The 6th day of July of the current year /// public static DateOnly The6th => new(DateTime.Now.Year, 7, 6); /// /// The 7th day of July of the current year /// public static DateOnly The7th => new(DateTime.Now.Year, 7, 7); /// /// The 8th day of July of the current year /// public static DateOnly The8th => new(DateTime.Now.Year, 7, 8); /// /// The 9th day of July of the current year /// public static DateOnly The9th => new(DateTime.Now.Year, 7, 9); /// /// The 10th day of July of the current year /// public static DateOnly The10th => new(DateTime.Now.Year, 7, 10); /// /// The 11th day of July of the current year /// public static DateOnly The11th => new(DateTime.Now.Year, 7, 11); /// /// The 12th day of July of the current year /// public static DateOnly The12th => new(DateTime.Now.Year, 7, 12); /// /// The 13th day of July of the current year /// public static DateOnly The13th => new(DateTime.Now.Year, 7, 13); /// /// The 14th day of July of the current year /// public static DateOnly The14th => new(DateTime.Now.Year, 7, 14); /// /// The 15th day of July of the current year /// public static DateOnly The15th => new(DateTime.Now.Year, 7, 15); /// /// The 16th day of July of the current year /// public static DateOnly The16th => new(DateTime.Now.Year, 7, 16); /// /// The 17th day of July of the current year /// public static DateOnly The17th => new(DateTime.Now.Year, 7, 17); /// /// The 18th day of July of the current year /// public static DateOnly The18th => new(DateTime.Now.Year, 7, 18); /// /// The 19th day of July of the current year /// public static DateOnly The19th => new(DateTime.Now.Year, 7, 19); /// /// The 20th day of July of the current year /// public static DateOnly The20th => new(DateTime.Now.Year, 7, 20); /// /// The 21st day of July of the current year /// public static DateOnly The21st => new(DateTime.Now.Year, 7, 21); /// /// The 22nd day of July of the current year /// public static DateOnly The22nd => new(DateTime.Now.Year, 7, 22); /// /// The 23rd day of July of the current year /// public static DateOnly The23rd => new(DateTime.Now.Year, 7, 23); /// /// The 24th day of July of the current year /// public static DateOnly The24th => new(DateTime.Now.Year, 7, 24); /// /// The 25th day of July of the current year /// public static DateOnly The25th => new(DateTime.Now.Year, 7, 25); /// /// The 26th day of July of the current year /// public static DateOnly The26th => new(DateTime.Now.Year, 7, 26); /// /// The 27th day of July of the current year /// public static DateOnly The27th => new(DateTime.Now.Year, 7, 27); /// /// The 28th day of July of the current year /// public static DateOnly The28th => new(DateTime.Now.Year, 7, 28); /// /// The 29th day of July of the current year /// public static DateOnly The29th => new(DateTime.Now.Year, 7, 29); /// /// The 30th day of July of the current year /// public static DateOnly The30th => new(DateTime.Now.Year, 7, 30); /// /// The 31st day of July of the current year /// public static DateOnly The31st => new(DateTime.Now.Year, 7, 31); } /// /// Provides fluent date accessors for August /// public class August { /// /// The nth day of August of the current year /// public static DateOnly The(int dayNumber) => new(DateTime.Now.Year, 8, dayNumber); /// /// The 1st day of August of the current year /// public static DateOnly The1st => new(DateTime.Now.Year, 8, 1); /// /// The 2nd day of August of the current year /// public static DateOnly The2nd => new(DateTime.Now.Year, 8, 2); /// /// The 3rd day of August of the current year /// public static DateOnly The3rd => new(DateTime.Now.Year, 8, 3); /// /// The 4th day of August of the current year /// public static DateOnly The4th => new(DateTime.Now.Year, 8, 4); /// /// The 5th day of August of the current year /// public static DateOnly The5th => new(DateTime.Now.Year, 8, 5); /// /// The 6th day of August of the current year /// public static DateOnly The6th => new(DateTime.Now.Year, 8, 6); /// /// The 7th day of August of the current year /// public static DateOnly The7th => new(DateTime.Now.Year, 8, 7); /// /// The 8th day of August of the current year /// public static DateOnly The8th => new(DateTime.Now.Year, 8, 8); /// /// The 9th day of August of the current year /// public static DateOnly The9th => new(DateTime.Now.Year, 8, 9); /// /// The 10th day of August of the current year /// public static DateOnly The10th => new(DateTime.Now.Year, 8, 10); /// /// The 11th day of August of the current year /// public static DateOnly The11th => new(DateTime.Now.Year, 8, 11); /// /// The 12th day of August of the current year /// public static DateOnly The12th => new(DateTime.Now.Year, 8, 12); /// /// The 13th day of August of the current year /// public static DateOnly The13th => new(DateTime.Now.Year, 8, 13); /// /// The 14th day of August of the current year /// public static DateOnly The14th => new(DateTime.Now.Year, 8, 14); /// /// The 15th day of August of the current year /// public static DateOnly The15th => new(DateTime.Now.Year, 8, 15); /// /// The 16th day of August of the current year /// public static DateOnly The16th => new(DateTime.Now.Year, 8, 16); /// /// The 17th day of August of the current year /// public static DateOnly The17th => new(DateTime.Now.Year, 8, 17); /// /// The 18th day of August of the current year /// public static DateOnly The18th => new(DateTime.Now.Year, 8, 18); /// /// The 19th day of August of the current year /// public static DateOnly The19th => new(DateTime.Now.Year, 8, 19); /// /// The 20th day of August of the current year /// public static DateOnly The20th => new(DateTime.Now.Year, 8, 20); /// /// The 21st day of August of the current year /// public static DateOnly The21st => new(DateTime.Now.Year, 8, 21); /// /// The 22nd day of August of the current year /// public static DateOnly The22nd => new(DateTime.Now.Year, 8, 22); /// /// The 23rd day of August of the current year /// public static DateOnly The23rd => new(DateTime.Now.Year, 8, 23); /// /// The 24th day of August of the current year /// public static DateOnly The24th => new(DateTime.Now.Year, 8, 24); /// /// The 25th day of August of the current year /// public static DateOnly The25th => new(DateTime.Now.Year, 8, 25); /// /// The 26th day of August of the current year /// public static DateOnly The26th => new(DateTime.Now.Year, 8, 26); /// /// The 27th day of August of the current year /// public static DateOnly The27th => new(DateTime.Now.Year, 8, 27); /// /// The 28th day of August of the current year /// public static DateOnly The28th => new(DateTime.Now.Year, 8, 28); /// /// The 29th day of August of the current year /// public static DateOnly The29th => new(DateTime.Now.Year, 8, 29); /// /// The 30th day of August of the current year /// public static DateOnly The30th => new(DateTime.Now.Year, 8, 30); /// /// The 31st day of August of the current year /// public static DateOnly The31st => new(DateTime.Now.Year, 8, 31); } /// /// Provides fluent date accessors for September /// public class September { /// /// The nth day of September of the current year /// public static DateOnly The(int dayNumber) => new(DateTime.Now.Year, 9, dayNumber); /// /// The 1st day of September of the current year /// public static DateOnly The1st => new(DateTime.Now.Year, 9, 1); /// /// The 2nd day of September of the current year /// public static DateOnly The2nd => new(DateTime.Now.Year, 9, 2); /// /// The 3rd day of September of the current year /// public static DateOnly The3rd => new(DateTime.Now.Year, 9, 3); /// /// The 4th day of September of the current year /// public static DateOnly The4th => new(DateTime.Now.Year, 9, 4); /// /// The 5th day of September of the current year /// public static DateOnly The5th => new(DateTime.Now.Year, 9, 5); /// /// The 6th day of September of the current year /// public static DateOnly The6th => new(DateTime.Now.Year, 9, 6); /// /// The 7th day of September of the current year /// public static DateOnly The7th => new(DateTime.Now.Year, 9, 7); /// /// The 8th day of September of the current year /// public static DateOnly The8th => new(DateTime.Now.Year, 9, 8); /// /// The 9th day of September of the current year /// public static DateOnly The9th => new(DateTime.Now.Year, 9, 9); /// /// The 10th day of September of the current year /// public static DateOnly The10th => new(DateTime.Now.Year, 9, 10); /// /// The 11th day of September of the current year /// public static DateOnly The11th => new(DateTime.Now.Year, 9, 11); /// /// The 12th day of September of the current year /// public static DateOnly The12th => new(DateTime.Now.Year, 9, 12); /// /// The 13th day of September of the current year /// public static DateOnly The13th => new(DateTime.Now.Year, 9, 13); /// /// The 14th day of September of the current year /// public static DateOnly The14th => new(DateTime.Now.Year, 9, 14); /// /// The 15th day of September of the current year /// public static DateOnly The15th => new(DateTime.Now.Year, 9, 15); /// /// The 16th day of September of the current year /// public static DateOnly The16th => new(DateTime.Now.Year, 9, 16); /// /// The 17th day of September of the current year /// public static DateOnly The17th => new(DateTime.Now.Year, 9, 17); /// /// The 18th day of September of the current year /// public static DateOnly The18th => new(DateTime.Now.Year, 9, 18); /// /// The 19th day of September of the current year /// public static DateOnly The19th => new(DateTime.Now.Year, 9, 19); /// /// The 20th day of September of the current year /// public static DateOnly The20th => new(DateTime.Now.Year, 9, 20); /// /// The 21st day of September of the current year /// public static DateOnly The21st => new(DateTime.Now.Year, 9, 21); /// /// The 22nd day of September of the current year /// public static DateOnly The22nd => new(DateTime.Now.Year, 9, 22); /// /// The 23rd day of September of the current year /// public static DateOnly The23rd => new(DateTime.Now.Year, 9, 23); /// /// The 24th day of September of the current year /// public static DateOnly The24th => new(DateTime.Now.Year, 9, 24); /// /// The 25th day of September of the current year /// public static DateOnly The25th => new(DateTime.Now.Year, 9, 25); /// /// The 26th day of September of the current year /// public static DateOnly The26th => new(DateTime.Now.Year, 9, 26); /// /// The 27th day of September of the current year /// public static DateOnly The27th => new(DateTime.Now.Year, 9, 27); /// /// The 28th day of September of the current year /// public static DateOnly The28th => new(DateTime.Now.Year, 9, 28); /// /// The 29th day of September of the current year /// public static DateOnly The29th => new(DateTime.Now.Year, 9, 29); /// /// The 30th day of September of the current year /// public static DateOnly The30th => new(DateTime.Now.Year, 9, 30); } /// /// Provides fluent date accessors for October /// public class October { /// /// The nth day of October of the current year /// public static DateOnly The(int dayNumber) => new(DateTime.Now.Year, 10, dayNumber); /// /// The 1st day of October of the current year /// public static DateOnly The1st => new(DateTime.Now.Year, 10, 1); /// /// The 2nd day of October of the current year /// public static DateOnly The2nd => new(DateTime.Now.Year, 10, 2); /// /// The 3rd day of October of the current year /// public static DateOnly The3rd => new(DateTime.Now.Year, 10, 3); /// /// The 4th day of October of the current year /// public static DateOnly The4th => new(DateTime.Now.Year, 10, 4); /// /// The 5th day of October of the current year /// public static DateOnly The5th => new(DateTime.Now.Year, 10, 5); /// /// The 6th day of October of the current year /// public static DateOnly The6th => new(DateTime.Now.Year, 10, 6); /// /// The 7th day of October of the current year /// public static DateOnly The7th => new(DateTime.Now.Year, 10, 7); /// /// The 8th day of October of the current year /// public static DateOnly The8th => new(DateTime.Now.Year, 10, 8); /// /// The 9th day of October of the current year /// public static DateOnly The9th => new(DateTime.Now.Year, 10, 9); /// /// The 10th day of October of the current year /// public static DateOnly The10th => new(DateTime.Now.Year, 10, 10); /// /// The 11th day of October of the current year /// public static DateOnly The11th => new(DateTime.Now.Year, 10, 11); /// /// The 12th day of October of the current year /// public static DateOnly The12th => new(DateTime.Now.Year, 10, 12); /// /// The 13th day of October of the current year /// public static DateOnly The13th => new(DateTime.Now.Year, 10, 13); /// /// The 14th day of October of the current year /// public static DateOnly The14th => new(DateTime.Now.Year, 10, 14); /// /// The 15th day of October of the current year /// public static DateOnly The15th => new(DateTime.Now.Year, 10, 15); /// /// The 16th day of October of the current year /// public static DateOnly The16th => new(DateTime.Now.Year, 10, 16); /// /// The 17th day of October of the current year /// public static DateOnly The17th => new(DateTime.Now.Year, 10, 17); /// /// The 18th day of October of the current year /// public static DateOnly The18th => new(DateTime.Now.Year, 10, 18); /// /// The 19th day of October of the current year /// public static DateOnly The19th => new(DateTime.Now.Year, 10, 19); /// /// The 20th day of October of the current year /// public static DateOnly The20th => new(DateTime.Now.Year, 10, 20); /// /// The 21st day of October of the current year /// public static DateOnly The21st => new(DateTime.Now.Year, 10, 21); /// /// The 22nd day of October of the current year /// public static DateOnly The22nd => new(DateTime.Now.Year, 10, 22); /// /// The 23rd day of October of the current year /// public static DateOnly The23rd => new(DateTime.Now.Year, 10, 23); /// /// The 24th day of October of the current year /// public static DateOnly The24th => new(DateTime.Now.Year, 10, 24); /// /// The 25th day of October of the current year /// public static DateOnly The25th => new(DateTime.Now.Year, 10, 25); /// /// The 26th day of October of the current year /// public static DateOnly The26th => new(DateTime.Now.Year, 10, 26); /// /// The 27th day of October of the current year /// public static DateOnly The27th => new(DateTime.Now.Year, 10, 27); /// /// The 28th day of October of the current year /// public static DateOnly The28th => new(DateTime.Now.Year, 10, 28); /// /// The 29th day of October of the current year /// public static DateOnly The29th => new(DateTime.Now.Year, 10, 29); /// /// The 30th day of October of the current year /// public static DateOnly The30th => new(DateTime.Now.Year, 10, 30); /// /// The 31st day of October of the current year /// public static DateOnly The31st => new(DateTime.Now.Year, 10, 31); } /// /// Provides fluent date accessors for November /// public class November { /// /// The nth day of November of the current year /// public static DateOnly The(int dayNumber) => new(DateTime.Now.Year, 11, dayNumber); /// /// The 1st day of November of the current year /// public static DateOnly The1st => new(DateTime.Now.Year, 11, 1); /// /// The 2nd day of November of the current year /// public static DateOnly The2nd => new(DateTime.Now.Year, 11, 2); /// /// The 3rd day of November of the current year /// public static DateOnly The3rd => new(DateTime.Now.Year, 11, 3); /// /// The 4th day of November of the current year /// public static DateOnly The4th => new(DateTime.Now.Year, 11, 4); /// /// The 5th day of November of the current year /// public static DateOnly The5th => new(DateTime.Now.Year, 11, 5); /// /// The 6th day of November of the current year /// public static DateOnly The6th => new(DateTime.Now.Year, 11, 6); /// /// The 7th day of November of the current year /// public static DateOnly The7th => new(DateTime.Now.Year, 11, 7); /// /// The 8th day of November of the current year /// public static DateOnly The8th => new(DateTime.Now.Year, 11, 8); /// /// The 9th day of November of the current year /// public static DateOnly The9th => new(DateTime.Now.Year, 11, 9); /// /// The 10th day of November of the current year /// public static DateOnly The10th => new(DateTime.Now.Year, 11, 10); /// /// The 11th day of November of the current year /// public static DateOnly The11th => new(DateTime.Now.Year, 11, 11); /// /// The 12th day of November of the current year /// public static DateOnly The12th => new(DateTime.Now.Year, 11, 12); /// /// The 13th day of November of the current year /// public static DateOnly The13th => new(DateTime.Now.Year, 11, 13); /// /// The 14th day of November of the current year /// public static DateOnly The14th => new(DateTime.Now.Year, 11, 14); /// /// The 15th day of November of the current year /// public static DateOnly The15th => new(DateTime.Now.Year, 11, 15); /// /// The 16th day of November of the current year /// public static DateOnly The16th => new(DateTime.Now.Year, 11, 16); /// /// The 17th day of November of the current year /// public static DateOnly The17th => new(DateTime.Now.Year, 11, 17); /// /// The 18th day of November of the current year /// public static DateOnly The18th => new(DateTime.Now.Year, 11, 18); /// /// The 19th day of November of the current year /// public static DateOnly The19th => new(DateTime.Now.Year, 11, 19); /// /// The 20th day of November of the current year /// public static DateOnly The20th => new(DateTime.Now.Year, 11, 20); /// /// The 21st day of November of the current year /// public static DateOnly The21st => new(DateTime.Now.Year, 11, 21); /// /// The 22nd day of November of the current year /// public static DateOnly The22nd => new(DateTime.Now.Year, 11, 22); /// /// The 23rd day of November of the current year /// public static DateOnly The23rd => new(DateTime.Now.Year, 11, 23); /// /// The 24th day of November of the current year /// public static DateOnly The24th => new(DateTime.Now.Year, 11, 24); /// /// The 25th day of November of the current year /// public static DateOnly The25th => new(DateTime.Now.Year, 11, 25); /// /// The 26th day of November of the current year /// public static DateOnly The26th => new(DateTime.Now.Year, 11, 26); /// /// The 27th day of November of the current year /// public static DateOnly The27th => new(DateTime.Now.Year, 11, 27); /// /// The 28th day of November of the current year /// public static DateOnly The28th => new(DateTime.Now.Year, 11, 28); /// /// The 29th day of November of the current year /// public static DateOnly The29th => new(DateTime.Now.Year, 11, 29); /// /// The 30th day of November of the current year /// public static DateOnly The30th => new(DateTime.Now.Year, 11, 30); } /// /// Provides fluent date accessors for December /// public class December { /// /// The nth day of December of the current year /// public static DateOnly The(int dayNumber) => new(DateTime.Now.Year, 12, dayNumber); /// /// The 1st day of December of the current year /// public static DateOnly The1st => new(DateTime.Now.Year, 12, 1); /// /// The 2nd day of December of the current year /// public static DateOnly The2nd => new(DateTime.Now.Year, 12, 2); /// /// The 3rd day of December of the current year /// public static DateOnly The3rd => new(DateTime.Now.Year, 12, 3); /// /// The 4th day of December of the current year /// public static DateOnly The4th => new(DateTime.Now.Year, 12, 4); /// /// The 5th day of December of the current year /// public static DateOnly The5th => new(DateTime.Now.Year, 12, 5); /// /// The 6th day of December of the current year /// public static DateOnly The6th => new(DateTime.Now.Year, 12, 6); /// /// The 7th day of December of the current year /// public static DateOnly The7th => new(DateTime.Now.Year, 12, 7); /// /// The 8th day of December of the current year /// public static DateOnly The8th => new(DateTime.Now.Year, 12, 8); /// /// The 9th day of December of the current year /// public static DateOnly The9th => new(DateTime.Now.Year, 12, 9); /// /// The 10th day of December of the current year /// public static DateOnly The10th => new(DateTime.Now.Year, 12, 10); /// /// The 11th day of December of the current year /// public static DateOnly The11th => new(DateTime.Now.Year, 12, 11); /// /// The 12th day of December of the current year /// public static DateOnly The12th => new(DateTime.Now.Year, 12, 12); /// /// The 13th day of December of the current year /// public static DateOnly The13th => new(DateTime.Now.Year, 12, 13); /// /// The 14th day of December of the current year /// public static DateOnly The14th => new(DateTime.Now.Year, 12, 14); /// /// The 15th day of December of the current year /// public static DateOnly The15th => new(DateTime.Now.Year, 12, 15); /// /// The 16th day of December of the current year /// public static DateOnly The16th => new(DateTime.Now.Year, 12, 16); /// /// The 17th day of December of the current year /// public static DateOnly The17th => new(DateTime.Now.Year, 12, 17); /// /// The 18th day of December of the current year /// public static DateOnly The18th => new(DateTime.Now.Year, 12, 18); /// /// The 19th day of December of the current year /// public static DateOnly The19th => new(DateTime.Now.Year, 12, 19); /// /// The 20th day of December of the current year /// public static DateOnly The20th => new(DateTime.Now.Year, 12, 20); /// /// The 21st day of December of the current year /// public static DateOnly The21st => new(DateTime.Now.Year, 12, 21); /// /// The 22nd day of December of the current year /// public static DateOnly The22nd => new(DateTime.Now.Year, 12, 22); /// /// The 23rd day of December of the current year /// public static DateOnly The23rd => new(DateTime.Now.Year, 12, 23); /// /// The 24th day of December of the current year /// public static DateOnly The24th => new(DateTime.Now.Year, 12, 24); /// /// The 25th day of December of the current year /// public static DateOnly The25th => new(DateTime.Now.Year, 12, 25); /// /// The 26th day of December of the current year /// public static DateOnly The26th => new(DateTime.Now.Year, 12, 26); /// /// The 27th day of December of the current year /// public static DateOnly The27th => new(DateTime.Now.Year, 12, 27); /// /// The 28th day of December of the current year /// public static DateOnly The28th => new(DateTime.Now.Year, 12, 28); /// /// The 29th day of December of the current year /// public static DateOnly The29th => new(DateTime.Now.Year, 12, 29); /// /// The 30th day of December of the current year /// public static DateOnly The30th => new(DateTime.Now.Year, 12, 30); /// /// The 31st day of December of the current year /// public static DateOnly The31st => new(DateTime.Now.Year, 12, 31); } } #endif ================================================ FILE: src/Humanizer/FluentDate/OnDate.Days.tt ================================================ <#@ template debug="true" hostSpecific="true" #> <#@ output extension=".cs" #> <#@ Assembly Name="System.Core" #> <#@ Assembly Name="System.Windows.Forms" #> <#@ assembly name="$(TargetPath)" #> <#@ import namespace="System" #> <#@ import namespace="Humanizer" #> #if NET6_0_OR_GREATER namespace Humanizer; public class OnDate { <# const int leapYear = 2012; for (var month = 1; month <= 12; month++) { var firstDayOfMonth = new DateTime(leapYear, month, 1); var monthName = firstDayOfMonth.ToString("MMMM");#> /// /// Provides fluent date accessors for <#= monthName #> /// public class <#= monthName #> { /// /// The nth day of <#= monthName #> of the current year /// public static DateOnly The(int dayNumber) => new(DateTime.Now.Year, <#= month #>, dayNumber); <#for (var day = 1; day <= DateTime.DaysInMonth(leapYear, month); day++) { var ordinalDay = day.Ordinalize();#> /// /// The <#= ordinalDay #> day of <#= monthName #> of the current year /// public static DateOnly The<#= ordinalDay #> => new(DateTime.Now.Year, <#= month #>, <#= day #>); <#}#> } <#}#> } #endif ================================================ FILE: src/Humanizer/FluentDate/PrepositionsExtensions.cs ================================================ namespace Humanizer; /// /// extensions related to spatial or temporal relations /// public static class PrepositionsExtensions { /// /// Returns a new with the specified hour and, optionally /// provided minutes, seconds, and milliseconds. /// public static DateTime At(this DateTime date, int hour, int min = 0, int second = 0, int millisecond = 0) => new(date.Year, date.Month, date.Day, hour, min, second, millisecond); /// /// Returns a new instance of DateTime based on the provided date where the time is set to midnight /// public static DateTime AtMidnight(this DateTime date) => date.At(0); /// /// Returns a new instance of DateTime based on the provided date where the time is set to noon /// public static DateTime AtNoon(this DateTime date) => date.At(12); /// /// Returns a new instance of DateTime based on the provided date where the year is set to the provided year /// public static DateTime In(this DateTime date, int year) => new(year, date.Month, date.Day, date.Hour, date.Minute, date.Second, date.Millisecond); } ================================================ FILE: src/Humanizer/GlobalUsings.cs ================================================ global using System; global using System.Buffers; global using System.Collections.Concurrent; global using System.Collections.Frozen; global using System.Globalization; global using System.Reflection; global using System.Text; global using System.Text.RegularExpressions; global using System.Diagnostics.CodeAnalysis; global using System.Linq; ================================================ FILE: src/Humanizer/GrammaticalCase.cs ================================================ namespace Humanizer; /// /// Options for specifying the desired grammatical case for the output words /// public enum GrammaticalCase { /// /// Indicates the subject of a finite verb /// Nominative, /// /// Indicates the possessor of another noun /// Genitive, /// /// Indicates the indirect object of a verb /// Dative, /// /// Indicates the direct object of a verb /// Accusative, /// /// Indicates an object used in performing an action /// Instrumental, /// /// Indicates the object of a preposition /// Prepositional, } ================================================ FILE: src/Humanizer/GrammaticalGender.cs ================================================ namespace Humanizer; /// /// Options for specifying the desired grammatical gender for the output words /// public enum GrammaticalGender { /// /// Indicates masculine grammatical gender /// Masculine, /// /// Indicates feminine grammatical gender /// Feminine, /// /// Indicates neuter grammatical gender /// Neuter } ================================================ FILE: src/Humanizer/HeadingExtensions.cs ================================================ namespace Humanizer; /// /// Style for the cardinal direction humanization /// public enum HeadingStyle { /// /// Returns an abbreviated format /// Abbreviated, /// /// Returns the full format /// Full } /// /// Contains extensions to transform a number indicating a heading into the /// textual representation of the heading. /// public static class HeadingExtensions { internal static readonly string[] Headings = ["N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"]; internal static readonly string[] HeadingsShort = ["N_Short", "NNE_Short", "NE_Short", "ENE_Short", "E_Short", "ESE_Short", "SE_Short", "SSE_Short", "S_Short", "SSW_Short", "SW_Short", "WSW_Short", "W_Short", "WNW_Short", "NW_Short", "NNW_Short"]; internal static readonly char[] HeadingArrows = ['↑', '↗', '→', '↘', '↓', '↙', '←', '↖']; // https://stackoverflow.com/a/7490772/1720761 /// /// Returns a textual representation of the heading. /// /// This representation has a maximum deviation of 11.25 degrees. /// /// A textual representation of the heading /// The heading value /// Whether to return a short result or not. /// The culture to return the textual representation in public static string ToHeading(this double heading, HeadingStyle style = HeadingStyle.Abbreviated, CultureInfo? culture = null) { var val = (int)(heading / 22.5 + .5); var headingsIndex = val % 16; return Resources.GetResource( style == HeadingStyle.Abbreviated ? HeadingsShort[headingsIndex] : Headings[headingsIndex], culture); } /// /// Returns a char arrow indicating the heading. /// /// This representation has a maximum deviation of 22.5 degrees. /// /// The heading arrow. public static char ToHeadingArrow(this double heading) { var val = (int)(heading / 45 + .5); return HeadingArrows[val % 8]; } /// /// Returns a heading based on the short textual representation of the heading. /// /// The short textual representation of a heading /// The heading. -1 if the heading could not be parsed. public static double FromAbbreviatedHeading(this string heading) => heading.FromAbbreviatedHeading(null); /// /// Returns a heading based on the short textual representation of the heading. /// /// The short textual representation of a heading /// The culture of the heading /// The heading. -1 if the heading could not be parsed. public static double FromAbbreviatedHeading(this string heading, CultureInfo? culture = null) { ArgumentNullException.ThrowIfNull(heading); culture ??= CultureInfo.CurrentCulture; var upperCaseHeading = culture.TextInfo.ToUpper(heading); for (var index = 0; index < HeadingsShort.Length; ++index) { var localizedShortHeading = Resources.GetResource(HeadingsShort[index], culture); if (culture.CompareInfo.Compare(upperCaseHeading, localizedShortHeading) == 0) { return index * 22.5; } } return -1; } /// /// Returns a heading based on the heading arrow. /// public static double FromHeadingArrow(this char heading) { var index = Array.IndexOf(HeadingArrows, heading); if (index == -1) { return -1; } return index * 45.0; } /// /// Returns a heading based on the heading arrow. /// public static double FromHeadingArrow(this string heading) { ArgumentNullException.ThrowIfNull(heading); if (heading.Length != 1) { return -1; } return heading[0] .FromHeadingArrow(); } } ================================================ FILE: src/Humanizer/Humanizer.csproj ================================================  net10.0;net8.0;net48;netstandard2.0 A micro-framework that turns your normal strings, type names, enum fields, date fields, etc, into a human friendly format Humanizer InDate.Months.cs TextTemplatingFileGenerator TextTemplatingFileGenerator On.Days.cs On.Days.tt TextTemplatingFileGenerator In.Months.cs In.Months.tt $(NoWarn);NU5128 false true $(MSBuildThisFileDirectory)..\..\artifacts\$(Configuration)\ $(MSBuildThisFileDirectory)..\ version=$(NuGetPackageVersion);RepositoryType=git;RepositoryCommit=$(GitCommitId);RepositoryUrl=https://github.com/Humanizr/Humanizer ================================================ FILE: src/Humanizer/Inflections/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2013 Scott Kirkland Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: src/Humanizer/Inflections/Vocabularies.cs ================================================ namespace Humanizer; /// /// Container for registered Vocabularies. At present, only a single vocabulary is supported: Default. /// public static class Vocabularies { static readonly Lazy Instance = new(BuildDefault, LazyThreadSafetyMode.PublicationOnly); /// /// The default vocabulary used for singular/plural irregularities. /// Rules can be added to this vocabulary and will be picked up by called to Singularize() and Pluralize(). /// At this time, multiple vocabularies and removing existing rules are not supported. /// public static Vocabulary Default => Instance.Value; static Vocabulary BuildDefault() { var _default = new Vocabulary(); _default.AddPlural("$", "s"); _default.AddPlural("s$", "s"); _default.AddPlural("(ax|test)is$", "$1es"); _default.AddPlural("(octop|vir|alumn|fung|cact|foc|hippopotam|radi|stimul|syllab|nucle)us$", "$1i"); _default.AddPlural("(alias|bias|iris|status|campus|apparatus|virus|walrus|trellis)$", "$1es"); _default.AddPlural("(buffal|tomat|volcan|ech|embarg|her|mosquit|potat|torped|vet)o$", "$1oes"); _default.AddPlural("([dti])um$", "$1a"); _default.AddPlural("sis$", "ses"); _default.AddPlural("(?:([^f])fe|([lr])f)$", "$1$2ves"); _default.AddPlural("(hive)$", "$1s"); _default.AddPlural("([^aeiouy]|qu)y$", "$1ies"); _default.AddPlural("(x|ch|ss|sh)$", "$1es"); _default.AddPlural("(matr|vert|ind|d)(ix|ex)$", "$1ices"); _default.AddPlural("(^[m|l])ouse$", "$1ice"); _default.AddPlural("^(ox)$", "$1en"); _default.AddPlural("(quiz)$", "$1zes"); _default.AddPlural("(buz|blit|walt)z$", "$1zes"); _default.AddPlural("(hoo|lea|loa|thie)f$", "$1ves"); _default.AddPlural("(alumn|alg|larv|vertebr)a$", "$1ae"); _default.AddPlural("(criteri|phenomen)on$", "$1a"); _default.AddSingular("s$", ""); _default.AddSingular("(n)ews$", "$1ews"); _default.AddSingular("([dti])a$", "$1um"); _default.AddSingular("(analy|ba|diagno|parenthe|progno|synop|the|ellip|empha|neuro|oa|paraly)ses$", "$1sis"); _default.AddSingular("([^f])ves$", "$1fe"); _default.AddSingular("(hive)s$", "$1"); _default.AddSingular("(tive)s$", "$1"); _default.AddSingular("([lr]|hoo|lea|loa|thie)ves$", "$1f"); _default.AddSingular("(^zomb)?([^aeiouy]|qu)ies$", "$2y"); _default.AddSingular("(s)eries$", "$1eries"); _default.AddSingular("(m)ovies$", "$1ovie"); _default.AddSingular("(x|ch|ss|sh)es$", "$1"); _default.AddSingular("(^[m|l])ice$", "$1ouse"); _default.AddSingular("(? /// A container for exceptions to simple pluralization/singularization rules. /// Vocabularies.Default contains an extensive list of rules for US English. /// At this time, multiple vocabularies and removing existing rules are not supported. /// public partial class Vocabulary { internal Vocabulary() { } readonly List plurals = []; readonly List singulars = []; readonly HashSet uncountables = new(StringComparer.CurrentCultureIgnoreCase); private const string LetterSPattern = "^([sS])[sS]*$"; #if NET7_0_OR_GREATER [GeneratedRegex(LetterSPattern)] private static partial Regex LetterSRegexGenerated(); private static Regex LetterSRegex() => LetterSRegexGenerated(); #else private static readonly Regex LetterSRegexField = new(LetterSPattern, RegexOptions.Compiled); private static Regex LetterSRegex() => LetterSRegexField; #endif /// /// Adds a word to the vocabulary which cannot easily be pluralized/singularized by RegEx, e.g. "person" and "people". /// /// The singular form of the irregular word, e.g. "person". /// The plural form of the irregular word, e.g. "people". /// True to match these words on their own as well as at the end of longer words. False, otherwise. public void AddIrregular(string singular, string plural, bool matchEnding = true) { if (matchEnding) { var singularSubstring = singular[1..]; var pluralSubString = plural[1..]; AddPlural($"({singular[0]}){singularSubstring}$", $"$1{pluralSubString}"); AddSingular($"({plural[0]}){pluralSubString}$", $"$1{singularSubstring}"); } else { AddPlural($"^{singular}$", plural); AddSingular($"^{plural}$", singular); } } /// /// Adds an uncountable word to the vocabulary, e.g. "fish". Will be ignored when plurality is changed. /// /// Word to be added to the list of uncountables. public void AddUncountable(string word) => uncountables.Add(word); /// /// Adds a rule to the vocabulary that does not follow trivial rules for pluralization, e.g. "bus" -> "buses" /// /// RegEx to be matched, case insensitive, e.g. "(bus)es$" /// RegEx replacement e.g. "$1" public void AddPlural(string rule, string replacement) => plurals.Add(new(rule, replacement)); /// /// Adds a rule to the vocabulary that does not follow trivial rules for singularization, e.g. "vertices/indices -> "vertex/index" /// /// RegEx to be matched, case insensitive, e.g. ""(vert|ind)ices$"" /// RegEx replacement e.g. "$1ex" public void AddSingular(string rule, string replacement) => singulars.Add(new(rule, replacement)); /// /// Pluralizes the provided input considering irregular words /// /// Word to be pluralized /// Normally you call Pluralize on singular words; but if you're unsure call it with false [return: NotNullIfNotNull(nameof(word))] public string? Pluralize(string? word, bool inputIsKnownToBeSingular = true) { if (word == null) { return null; } var s = LetterS(word); if (s != null) { return s + "s"; } var result = ApplyRules(plurals, word, false); if (inputIsKnownToBeSingular) { return result ?? word; } var asSingular = ApplyRules(singulars, word, false); var asSingularAsPlural = ApplyRules(plurals, asSingular, false); if (asSingular != null && asSingular != word && asSingular + "s" != word && asSingularAsPlural == word && result != word) { return word; } return result!; } /// /// Singularizes the provided input considering irregular words /// /// Word to be singularized /// Normally you call Singularize on plural words; but if you're unsure call it with false /// Skip singularizing single words that have an 's' on the end [return: NotNullIfNotNull(nameof(word))] public string? Singularize(string? word, bool inputIsKnownToBePlural = true, bool skipSimpleWords = false) { if (word == null) { return null; } var s = LetterS(word); if (s != null) { return s; } var result = ApplyRules(singulars, word, skipSimpleWords); if (inputIsKnownToBePlural) { return result ?? word; } // the Plurality is unknown so we should check all possibilities var asPlural = ApplyRules(plurals, word, false); if (asPlural == word || word + "s" == asPlural) { return result ?? word; } var asPluralAsSingular = ApplyRules(singulars, asPlural, false); if (asPluralAsSingular != word || result == word) { return result ?? word; } return word; } string? ApplyRules(IList rules, string? word, bool skipFirstRule) { if (word == null) { return null; } if (word.Length < 1) { return word; } if (IsUncountable(word)) { return word; } var result = word; var end = skipFirstRule ? 1 : 0; for (var i = rules.Count - 1; i >= end; i--) { if ((result = rules[i].Apply(word)) != null) { break; } } if (result == null) { return null; } return MatchUpperCase(word, result); } bool IsUncountable(string word) => uncountables.Contains(word); static string MatchUpperCase(string word, string replacement) => char.IsUpper(word[0]) && char.IsLower(replacement[0]) ? StringHumanizeExtensions.Concat(char.ToUpper(replacement[0]), replacement.AsSpan(1)) : replacement; /// /// If the word is the letter s, singular or plural, return the letter s singular /// static string? LetterS(string word) { var s = LetterSRegex().Match(word); return s.Groups.Count > 1 ? s.Groups[1].Value : null; } class Rule(string pattern, string replacement) { readonly Regex regex = new(pattern, RegexOptions.IgnoreCase | RegexOptions.Compiled); public string? Apply(string word) { if (!regex.IsMatch(word)) { return null; } return regex.Replace(word, replacement); } } } ================================================ FILE: src/Humanizer/InflectorExtensions.cs ================================================ //The Inflector class was cloned from Inflector (https://github.com/srkirkland/Inflector) //The MIT License (MIT) //Copyright (c) 2013 Scott Kirkland //Permission is hereby granted, free of charge, to any person obtaining a copy of //this software and associated documentation files (the "Software"), to deal in //the Software without restriction, including without limitation the rights to //use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of //the Software, and to permit persons to whom the Software is furnished to do so, //subject to the following conditions: //The above copyright notice and this permission notice shall be included in all //copies or substantial portions of the Software. //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS //FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR //COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER //IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN //CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. namespace Humanizer; public static partial class InflectorExtensions { private const string PascalizePattern = @"(?:[ _-]+|^)(.)"; private const string UnderscorePattern1 = @"([\p{Lu}]+)([\p{Lu}][\p{Ll}])"; private const string UnderscorePattern2 = @"([\p{Ll}\d])([\p{Lu}])"; private const string UnderscorePattern3 = @"[-\s]"; #if NET7_0_OR_GREATER [GeneratedRegex(PascalizePattern)] private static partial Regex PascalizeRegexGenerated(); private static Regex PascalizeRegex() => PascalizeRegexGenerated(); [GeneratedRegex(UnderscorePattern1)] private static partial Regex UnderscoreRegex1Generated(); private static Regex UnderscoreRegex1() => UnderscoreRegex1Generated(); [GeneratedRegex(UnderscorePattern2)] private static partial Regex UnderscoreRegex2Generated(); private static Regex UnderscoreRegex2() => UnderscoreRegex2Generated(); [GeneratedRegex(UnderscorePattern3)] private static partial Regex UnderscoreRegex3Generated(); private static Regex UnderscoreRegex3() => UnderscoreRegex3Generated(); #else private static readonly Regex PascalizeRegexField = new(PascalizePattern, RegexOptions.Compiled); private static Regex PascalizeRegex() => PascalizeRegexField; private static readonly Regex UnderscoreRegex1Field = new(UnderscorePattern1, RegexOptions.Compiled); private static Regex UnderscoreRegex1() => UnderscoreRegex1Field; private static readonly Regex UnderscoreRegex2Field = new(UnderscorePattern2, RegexOptions.Compiled); private static Regex UnderscoreRegex2() => UnderscoreRegex2Field; private static readonly Regex UnderscoreRegex3Field = new(UnderscorePattern3, RegexOptions.Compiled); private static Regex UnderscoreRegex3() => UnderscoreRegex3Field; #endif /// /// Converts a singular word to its plural form, handling both regular and irregular pluralizations. /// /// The word to be pluralized. Can be null. /// /// Indicates whether the input is known to be in singular form. /// Set to true (default) if you're certain the word is singular. /// Set to false if the word might already be plural, in which case the method will check and avoid double-pluralization. /// /// /// The plural form of the word, or null if the input was null. /// Handles irregular plurals (e.g., "person" → "people", "child" → "children") and regular plurals (e.g., "cat" → "cats"). /// /// /// Uses the default vocabulary which includes English pluralization rules and common irregular forms. /// /// /// /// "person".Pluralize() => "people" /// "cat".Pluralize() => "cats" /// "box".Pluralize() => "boxes" /// "man".Pluralize() => "men" /// "cats".Pluralize(inputIsKnownToBeSingular: false) => "cats" (avoids double pluralization) /// /// [return: NotNullIfNotNull(nameof(word))] public static string? Pluralize(this string? word, bool inputIsKnownToBeSingular = true) => Vocabularies.Default.Pluralize(word, inputIsKnownToBeSingular); /// /// Converts a plural word to its singular form, handling both regular and irregular singularizations. /// /// The word to be singularized. Must not be null. /// /// Indicates whether the input is known to be in plural form. /// Set to true (default) if you're certain the word is plural. /// Set to false if the word might already be singular, in which case the method will check and avoid incorrect singularization. /// /// /// When true, skips singularization of simple words that just end in 's'. /// This helps avoid incorrectly singularizing words like "ross" to "ros". /// /// /// The singular form of the word. /// Handles irregular singulars (e.g., "people" → "person", "children" → "child") and regular singulars (e.g., "cats" → "cat"). /// /// /// Uses the default vocabulary which includes English singularization rules and common irregular forms. /// /// /// /// "people".Singularize() => "person" /// "cats".Singularize() => "cat" /// "boxes".Singularize() => "box" /// "men".Singularize() => "man" /// "person".Singularize(inputIsKnownToBePlural: false) => "person" (avoids incorrect singularization) /// /// public static string Singularize(this string word, bool inputIsKnownToBePlural = true, bool skipSimpleWords = false) => Vocabularies.Default.Singularize(word, inputIsKnownToBePlural, skipSimpleWords); /// /// Converts a string to title case by humanizing it first and then applying title casing. /// Each word in the result will start with an uppercase letter. /// /// The string to be converted to title case. Must not be null. /// /// A humanized string with each word capitalized (title case). /// If humanization produces an empty string, returns the original input unchanged. /// /// /// This method first humanizes the input (breaking up PascalCase, underscores, etc.) and then applies title casing. /// /// /// /// "some_title".Titleize() => "Some Title" /// "someTitle".Titleize() => "Some Title" /// "some-package_name".Titleize() => "Some Package Name" /// /// public static string Titleize(this string input) { var humanized = input.Humanize(); // If humanization returns empty string (no recognized letters), preserve original input return humanized.Length == 0 ? input : humanized.ApplyCase(LetterCasing.Title); } /// /// Converts a string to PascalCase (UpperCamelCase) by capitalizing the first letter of each word /// and removing spaces, underscores, and dashes. /// /// The string to be pascalized. Must not be null. /// /// A PascalCase version of the input where each word starts with an uppercase letter and /// spaces, underscores, and dashes are removed. /// /// /// PascalCase (also known as UpperCamelCase) is commonly used for class names and type names in .NET. /// /// /// /// "some_property_name".Pascalize() => "SomePropertyName" /// "some property name".Pascalize() => "SomePropertyName" /// "some-property-name".Pascalize() => "SomePropertyName" /// /// public static string Pascalize(this string input) => PascalizeRegex().Replace(input, match => match .Groups[1] .Value.ToUpper()); /// /// Converts a string to camelCase (lowerCamelCase) by capitalizing the first letter of each word /// except the first word, and removing spaces, underscores, and dashes. /// /// The string to be camelized. Must not be null. /// /// A camelCase version of the input where the first word starts with a lowercase letter, /// subsequent words start with uppercase letters, and spaces, underscores, and dashes are removed. /// /// /// camelCase is the same as PascalCase except the first character is lowercase. /// It's commonly used for variable and method parameter names in .NET. /// /// /// /// "some_property_name".Camelize() => "somePropertyName" /// "some property name".Camelize() => "somePropertyName" /// "SomePropertyName".Camelize() => "somePropertyName" /// /// public static string Camelize(this string input) { var word = input.Pascalize(); return word.Length > 0 ? StringHumanizeExtensions.Concat( char.ToLower(word[0]), word.AsSpan(1)) : word; } /// /// Converts a string to lowercase and separates words with underscores, transforming /// PascalCase, camelCase, and spaces into underscore_case. /// /// The string to be underscored. Must not be null. /// /// A lowercase string with words separated by underscores instead of spaces, case changes, or dashes. /// /// /// This transformation is commonly used for database column names, file names, and URL slugs in some conventions. /// /// /// /// "SomePropertyName".Underscore() => "some_property_name" /// "somePropertyName".Underscore() => "some_property_name" /// "some-property-name".Underscore() => "some_property_name" /// "some property name".Underscore() => "some_property_name" /// /// public static string Underscore(this string input) => UnderscoreRegex3() .Replace( UnderscoreRegex2().Replace( UnderscoreRegex1().Replace(input, "$1_$2"), "$1_$2"), "_") .ToLower(); /// /// Replaces all underscores in the string with dashes (hyphens). /// /// The string containing underscores to be replaced with dashes. Must not be null. /// /// A string with all underscores replaced by dashes. /// /// /// This is typically used after calling to convert from underscore_case to dash-case (kebab-case). /// /// /// /// "some_property_name".Dasherize() => "some-property-name" /// "some_longer_property_name".Dasherize() => "some-longer-property-name" /// /// public static string Dasherize(this string underscoredWord) => underscoredWord.Replace('_', '-'); /// /// Replaces all underscores in the string with hyphens. This is an alias for . /// /// The string containing underscores to be replaced with hyphens. Must not be null. /// /// A string with all underscores replaced by hyphens. /// /// /// This method is functionally identical to and is provided for API clarity. /// /// /// /// "some_property_name".Hyphenate() => "some-property-name" /// /// public static string Hyphenate(this string underscoredWord) => Dasherize(underscoredWord); /// /// Converts a string to kebab-case (lowercase words separated by hyphens), transforming /// PascalCase, camelCase, spaces, and underscores into hyphenated lowercase text. /// /// The string to be converted to kebab-case. Must not be null. /// /// A lowercase string with words separated by hyphens. /// /// /// Kebab-case is commonly used for CSS class names, HTML attributes, and URL slugs. /// This is equivalent to calling followed by . /// /// /// /// "SomePropertyName".Kebaberize() => "some-property-name" /// "somePropertyName".Kebaberize() => "some-property-name" /// "some property name".Kebaberize() => "some-property-name" /// "some_property_name".Kebaberize() => "some-property-name" /// /// public static string Kebaberize(this string input) => Underscore(input) .Dasherize(); } ================================================ FILE: src/Humanizer/LetterCasing.cs ================================================ namespace Humanizer; /// /// Options for specifying the desired letter casing for the output string /// public enum LetterCasing { /// /// SomeString -> Some String /// Title, /// /// SomeString -> SOME STRING /// AllCaps, /// /// SomeString -> some string /// LowerCase, /// /// SomeString -> Some string /// Sentence, } ================================================ FILE: src/Humanizer/Localisation/CollectionFormatters/DefaultCollectionFormatter.cs ================================================ namespace Humanizer; class DefaultCollectionFormatter(string defaultSeparator) : ICollectionFormatter { protected string DefaultSeparator = defaultSeparator; public virtual string Humanize(IEnumerable collection) => Humanize(collection, o => o?.ToString(), DefaultSeparator); public virtual string Humanize(IEnumerable collection, Func objectFormatter) => Humanize(collection, objectFormatter, DefaultSeparator); public string Humanize(IEnumerable collection, Func objectFormatter) => Humanize(collection, objectFormatter, DefaultSeparator); public virtual string Humanize(IEnumerable collection, string separator) => Humanize(collection, o => o?.ToString(), separator); public virtual string Humanize(IEnumerable collection, Func objectFormatter, string separator) { ArgumentNullException.ThrowIfNull(collection); ArgumentNullException.ThrowIfNull(objectFormatter); return HumanizeDisplayStrings( collection.Select(objectFormatter), separator); } public string Humanize(IEnumerable collection, Func objectFormatter, string separator) { ArgumentNullException.ThrowIfNull(collection); ArgumentNullException.ThrowIfNull(objectFormatter); return HumanizeDisplayStrings( collection .Select(objectFormatter) .Select(o => o?.ToString()), separator); } string HumanizeDisplayStrings(IEnumerable strings, string separator) { // Try to avoid ToArray for small known collections var itemsArray = strings .Select(item => item == null ? string.Empty : item.Trim()) .Where(item => !string.IsNullOrWhiteSpace(item)) .ToArray(); var count = itemsArray.Length; if (count == 0) { return ""; } if (count == 1) { return itemsArray[0]; } var conjunctionFormat = GetConjunctionFormatString(count); if (conjunctionFormat == "{0} {1} {2}") { // Fast path: avoid string.Format for default format return string.Concat( string.Join(", ", itemsArray, 0, itemsArray.Length - 1), " ", separator, " ", itemsArray[^1]); } return string.Format(conjunctionFormat, string.Join(", ", itemsArray, 0, itemsArray.Length - 1), separator, itemsArray[^1]); } protected virtual string GetConjunctionFormatString(int itemCount) => "{0} {1} {2}"; } ================================================ FILE: src/Humanizer/Localisation/CollectionFormatters/ICollectionFormatter.cs ================================================ namespace Humanizer; /// /// An interface you should implement to localize Humanize for collections /// public interface ICollectionFormatter { /// /// Formats the collection for display, calling ToString() on each object. /// string Humanize(IEnumerable collection); /// /// Formats the collection for display, calling on each element. /// string Humanize(IEnumerable collection, Func objectFormatter); /// /// Formats the collection for display, calling on each element. /// string Humanize(IEnumerable collection, Func objectFormatter); /// /// Formats the collection for display, calling ToString() on each object /// and using before the final item. /// string Humanize(IEnumerable collection, string separator); /// /// Formats the collection for display, calling on each element. /// and using before the final item. /// string Humanize(IEnumerable collection, Func objectFormatter, string separator); /// /// Formats the collection for display, calling on each element. /// and using before the final item. /// string Humanize(IEnumerable collection, Func objectFormatter, string separator); } ================================================ FILE: src/Humanizer/Localisation/CollectionFormatters/OxfordStyleCollectionFormatter.cs ================================================ namespace Humanizer; class OxfordStyleCollectionFormatter() : DefaultCollectionFormatter("and") { protected override string GetConjunctionFormatString(int itemCount) => itemCount > 2 ? "{0}, {1} {2}" : "{0} {1} {2}"; } ================================================ FILE: src/Humanizer/Localisation/DataUnit.cs ================================================ namespace Humanizer; public enum DataUnit { Bit, Byte, Kilobyte, Megabyte, Gigabyte, Terabyte } ================================================ FILE: src/Humanizer/Localisation/DateToOrdinalWords/CaDateOnlyToOrdinalWordsConverter.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; class CaDateOnlyToOrdinalWordsConverter : DefaultDateOnlyToOrdinalWordConverter { public override string Convert(DateOnly date) { var equivalentDateTime = date.ToDateTime(TimeOnly.MinValue); return Configurator.DateToOrdinalWordsConverter.Convert(equivalentDateTime); } } #endif ================================================ FILE: src/Humanizer/Localisation/DateToOrdinalWords/CaDateToOrdinalWordsConverter.cs ================================================ namespace Humanizer; class CaDateToOrdinalWordsConverter : DefaultDateToOrdinalWordConverter { public override string Convert(DateTime date) => date.ToString("d MMMM 'de' yyyy"); } ================================================ FILE: src/Humanizer/Localisation/DateToOrdinalWords/DefaultDateOnlyToOrdinalWordConverter.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; class DefaultDateOnlyToOrdinalWordConverter : IDateOnlyToOrdinalWordConverter { public virtual string Convert(DateOnly date) => date.Day.Ordinalize() + date.ToString(" MMMM yyyy"); public virtual string Convert(DateOnly date, GrammaticalCase grammaticalCase) => Convert(date); } #endif ================================================ FILE: src/Humanizer/Localisation/DateToOrdinalWords/DefaultDateToOrdinalWordConverter.cs ================================================ namespace Humanizer; class DefaultDateToOrdinalWordConverter : IDateToOrdinalWordConverter { public virtual string Convert(DateTime date) => date.Day.Ordinalize() + date.ToString(" MMMM yyyy"); public virtual string Convert(DateTime date, GrammaticalCase grammaticalCase) => Convert(date); } ================================================ FILE: src/Humanizer/Localisation/DateToOrdinalWords/EsDateOnlyToOrdinalWordsConverter.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; class EsDateOnlyToOrdinalWordsConverter : DefaultDateOnlyToOrdinalWordConverter { public override string Convert(DateOnly date) { var equivalentDateTime = date.ToDateTime(TimeOnly.MinValue); return Configurator.DateToOrdinalWordsConverter.Convert(equivalentDateTime); } } #endif ================================================ FILE: src/Humanizer/Localisation/DateToOrdinalWords/EsDateToOrdinalWordsConverter.cs ================================================ namespace Humanizer; class EsDateToOrdinalWordsConverter : DefaultDateToOrdinalWordConverter { public override string Convert(DateTime date) => date.ToString("d 'de' MMMM 'de' yyyy"); } ================================================ FILE: src/Humanizer/Localisation/DateToOrdinalWords/FrDateOnlyToOrdinalWordsConverter.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; class FrDateOnlyToOrdinalWordsConverter : DefaultDateOnlyToOrdinalWordConverter { public override string Convert(DateOnly date) { var day = date.Day > 1 ? date.Day.ToString() : date.Day.Ordinalize(); return day + date.ToString(" MMMM yyyy"); } } #endif ================================================ FILE: src/Humanizer/Localisation/DateToOrdinalWords/FrDateToOrdinalWordsConverter.cs ================================================ namespace Humanizer; class FrDateToOrdinalWordsConverter : DefaultDateToOrdinalWordConverter { public override string Convert(DateTime date) { var day = date.Day > 1 ? date.Day.ToString() : date.Day.Ordinalize(); return day + date.ToString(" MMMM yyyy"); } } ================================================ FILE: src/Humanizer/Localisation/DateToOrdinalWords/IDateOnlyToOrdinalWordConverter.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; /// /// The interface used to localise the ToOrdinalWords method. /// public interface IDateOnlyToOrdinalWordConverter { /// /// Converts the date to Ordinal Words /// string Convert(DateOnly date); /// /// Converts the date to Ordinal Words using the provided grammatical case /// string Convert(DateOnly date, GrammaticalCase grammaticalCase); } #endif ================================================ FILE: src/Humanizer/Localisation/DateToOrdinalWords/IDateToOrdinalWordConverter.cs ================================================ namespace Humanizer; /// /// The interface used to localise the ToOrdinalWords method. /// public interface IDateToOrdinalWordConverter { /// /// Converts the date to Ordinal Words /// string Convert(DateTime date); /// /// Converts the date to Ordinal Words using the provided grammatical case /// string Convert(DateTime date, GrammaticalCase grammaticalCase); } ================================================ FILE: src/Humanizer/Localisation/DateToOrdinalWords/LtDateOnlyToOrdinalWordsConverter.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; class LtDateOnlyToOrdinalWordsConverter : IDateOnlyToOrdinalWordConverter { public string Convert(DateOnly date) => date.ToString("yyyy 'm.' MMMM d 'd.'"); public string Convert(DateOnly date, GrammaticalCase grammaticalCase) => Convert(date); } #endif ================================================ FILE: src/Humanizer/Localisation/DateToOrdinalWords/LtDateToOrdinalWordsConverter.cs ================================================ namespace Humanizer; class LtDateToOrdinalWordsConverter : IDateToOrdinalWordConverter { public string Convert(DateTime date) => date.ToString("yyyy 'm.' MMMM d 'd.'"); public string Convert(DateTime date, GrammaticalCase grammaticalCase) => Convert(date); } ================================================ FILE: src/Humanizer/Localisation/DateToOrdinalWords/UsDateOnlyToOrdinalWordsConverter.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; class UsDateOnlyToOrdinalWordsConverter : DefaultDateOnlyToOrdinalWordConverter { public override string Convert(DateOnly date) => date.ToString("MMMM ") + date.Day.Ordinalize() + date.ToString(", yyyy"); } #endif ================================================ FILE: src/Humanizer/Localisation/DateToOrdinalWords/UsDateToOrdinalWordsConverter.cs ================================================ namespace Humanizer; class UsDateToOrdinalWordsConverter : DefaultDateToOrdinalWordConverter { public override string Convert(DateTime date) => date.ToString("MMMM ") + date.Day.Ordinalize() + date.ToString(", yyyy"); } ================================================ FILE: src/Humanizer/Localisation/Formatters/ArabicFormatter.cs ================================================ namespace Humanizer; class ArabicFormatter(CultureInfo culture) : DefaultFormatter(culture) { const string DualPostfix = "_Dual"; const string PluralPostfix = "_Plural"; protected override string GetResourceKey(string resourceKey, int number) { //In Arabic pluralization 2 entities gets a different word. if (number == 2) { return resourceKey + DualPostfix; } //In Arabic pluralization entities where the count is between 3 and 10 gets a different word. if (number is >= 3 and <= 10) { return resourceKey + PluralPostfix; } return resourceKey; } } ================================================ FILE: src/Humanizer/Localisation/Formatters/BulgarianFormatter.cs ================================================ namespace Humanizer; class BulgarianFormatter(CultureInfo culture) : DefaultFormatter(culture) { protected override string NumberToWords(TimeUnit unit, int number, CultureInfo culture) => number.ToWords(GetUnitGender(unit), culture); static GrammaticalGender GetUnitGender(TimeUnit unit) => unit switch { TimeUnit.Hour or TimeUnit.Day or TimeUnit.Month => GrammaticalGender.Masculine, _ => GrammaticalGender.Feminine }; } ================================================ FILE: src/Humanizer/Localisation/Formatters/CatalanFormatter.cs ================================================ namespace Humanizer; class CatalanFormatter(CultureInfo culture) : DefaultFormatter(culture) { protected override string Format(TimeUnit unit, string resourceKey, int number, bool toWords = false) { var resolvedKey = GetResourceKey(resourceKey, number); var resourceString = Resources.GetResource(resolvedKey, Culture); var gender = unit switch { TimeUnit.Hour or TimeUnit.Week => GrammaticalGender.Feminine, _ => GrammaticalGender.Masculine }; return string.Format(resourceString, toWords ? number.ToWords(gender, Culture) : number); } } ================================================ FILE: src/Humanizer/Localisation/Formatters/CroatianFormatter.cs ================================================ namespace Humanizer; class CroatianFormatter(CultureInfo culture) : DefaultFormatter(culture) { const string PaucalPostfix = "_Paucal"; protected override string GetResourceKey(string resourceKey, int number) { var mod10 = number % 10; if (mod10 is > 1 and < 5 && number != 12 && number != 13 && number != 14) { return resourceKey + PaucalPostfix; } return resourceKey; } } ================================================ FILE: src/Humanizer/Localisation/Formatters/CzechSlovakPolishFormatter.cs ================================================ namespace Humanizer; class CzechSlovakPolishFormatter(CultureInfo culture) : DefaultFormatter(culture) { const string PaucalPostfix = "_Paucal"; protected override string GetResourceKey(string resourceKey, int number) { if (number is > 1 and < 5) { return resourceKey + PaucalPostfix; } return resourceKey; } } ================================================ FILE: src/Humanizer/Localisation/Formatters/DefaultFormatter.cs ================================================ namespace Humanizer; /// /// Default implementation of IFormatter interface. /// public class DefaultFormatter(CultureInfo culture) : IFormatter { protected CultureInfo Culture { get; } = culture; public DefaultFormatter(string localeCode) : this(new CultureInfo(localeCode)) { } public virtual string DateHumanize_Now() => GetResourceForDate(TimeUnit.Millisecond, Tense.Past, 0); public virtual string DateHumanize_Never() => Format(ResourceKeys.DateHumanize.Never); /// /// Returns the string representation of the provided DateTime /// public virtual string DateHumanize(TimeUnit timeUnit, Tense timeUnitTense, int unit) => GetResourceForDate(timeUnit, timeUnitTense, unit); /// /// 0 seconds /// /// Returns 0 seconds as the string representation of Zero TimeSpan public virtual string TimeSpanHumanize_Zero() => GetResourceForTimeSpan(TimeUnit.Millisecond, 0, true); /// /// Returns the string representation of the provided TimeSpan /// /// A time unit to represent. /// Is thrown when timeUnit is larger than TimeUnit.Week public virtual string TimeSpanHumanize(TimeUnit timeUnit, int unit, bool toWords = false) => GetResourceForTimeSpan(timeUnit, unit, toWords); /// public virtual string TimeSpanHumanize_Age() { if (Resources.TryGetResource("TimeSpanHumanize_Age", Culture, out var ageFormat)) { return ageFormat; } return "{0}"; } /// public virtual string DataUnitHumanize(DataUnit dataUnit, double count, bool toSymbol = true) { var resourceKey = (toSymbol, dataUnit) switch { (true, DataUnit.Bit) => "DataUnit_BitSymbol", (true, DataUnit.Byte) => "DataUnit_ByteSymbol", (true, DataUnit.Kilobyte) => "DataUnit_KilobyteSymbol", (true, DataUnit.Megabyte) => "DataUnit_MegabyteSymbol", (true, DataUnit.Gigabyte) => "DataUnit_GigabyteSymbol", (true, DataUnit.Terabyte) => "DataUnit_TerabyteSymbol", (true, _) => $"DataUnit_{dataUnit}Symbol", (false, DataUnit.Bit) => "DataUnit_Bit", (false, DataUnit.Byte) => "DataUnit_Byte", (false, DataUnit.Kilobyte) => "DataUnit_Kilobyte", (false, DataUnit.Megabyte) => "DataUnit_Megabyte", (false, DataUnit.Gigabyte) => "DataUnit_Gigabyte", (false, DataUnit.Terabyte) => "DataUnit_Terabyte", (false, _) => $"DataUnit_{dataUnit}", }; var resourceValue = Format(resourceKey); if (!toSymbol && count > 1) { resourceValue += "s"; } return resourceValue; } /// public virtual string TimeUnitHumanize(TimeUnit timeUnit) { var resourceKey = ResourceKeys.TimeUnitSymbol.GetResourceKey(timeUnit); return Format(resourceKey); } string GetResourceForDate(TimeUnit unit, Tense timeUnitTense, int count) { var resourceKey = ResourceKeys.DateHumanize.GetResourceKey(unit, timeUnitTense: timeUnitTense, count: count); return count == 1 ? Format(resourceKey) : Format(unit, resourceKey, count); } string GetResourceForTimeSpan(TimeUnit unit, int count, bool toWords = false) { var resourceKey = ResourceKeys.TimeSpanHumanize.GetResourceKey(unit, count, toWords); return count == 1 ? Format(resourceKey + (toWords ? "_Words" : "")) : Format(unit, resourceKey, count, toWords); } /// /// Formats the specified resource key. /// /// The resource key. /// If the resource not exists on the specified culture. protected virtual string Format(string resourceKey) { var resolvedKey = GetResourceKey(resourceKey); return Resources.GetResource(resolvedKey, Culture); } /// /// Formats the specified resource key. /// /// /// The resource key. /// The number. /// /// If the resource not exists on the specified culture. protected virtual string Format(TimeUnit unit, string resourceKey, int number, bool toWords = false) { var resolvedKey = GetResourceKey(resourceKey, number); var resourceString = Resources.GetResource(resolvedKey, Culture); return string.Format(resourceString, toWords ? NumberToWords(unit, number, Culture) : number); } protected virtual string NumberToWords(TimeUnit unit, int number, CultureInfo culture) => number.ToWords(culture); /// /// Override this method if your locale has complex rules around multiple units; e.g. Arabic, Russian /// /// The resource key that's being in formatting /// The number of the units being used in formatting protected virtual string GetResourceKey(string resourceKey, int number) => resourceKey; protected virtual string GetResourceKey(string resourceKey) => resourceKey; } ================================================ FILE: src/Humanizer/Localisation/Formatters/FrenchFormatter.cs ================================================ namespace Humanizer; class FrenchFormatter(CultureInfo culture) : DefaultFormatter(culture) { const string DualPostfix = "_Dual"; protected override string GetResourceKey(string resourceKey, int number) { if (number == 2 && resourceKey is "DateHumanize_MultipleDaysAgo" or "DateHumanize_MultipleDaysFromNow") { return resourceKey + DualPostfix; } if (number == 0 && resourceKey.StartsWith("TimeSpanHumanize_Multiple")) { return resourceKey + "_Singular"; } return resourceKey; } } ================================================ FILE: src/Humanizer/Localisation/Formatters/GermanFormatter.cs ================================================ namespace Humanizer; class GermanFormatter(CultureInfo culture) : DefaultFormatter(culture) { /// public override string DataUnitHumanize(DataUnit dataUnit, double count, bool toSymbol = true) => base.DataUnitHumanize(dataUnit, count, toSymbol).TrimEnd('s'); } ================================================ FILE: src/Humanizer/Localisation/Formatters/HebrewFormatter.cs ================================================ namespace Humanizer; class HebrewFormatter(CultureInfo culture) : DefaultFormatter(culture) { const string DualPostfix = "_Dual"; const string PluralPostfix = "_Plural"; protected override string GetResourceKey(string resourceKey, int number) { //In Hebrew pluralization 2 entities gets a different word. if (number == 2) { return resourceKey + DualPostfix; } //In Hebrew pluralization entities where the count is between 3 and 10 gets a different word. //See http://lib.cet.ac.il/pages/item.asp?item=21585 for explanation if (number is >= 3 and <= 10) { return resourceKey + PluralPostfix; } return resourceKey; } } ================================================ FILE: src/Humanizer/Localisation/Formatters/IFormatter.cs ================================================ namespace Humanizer; /// /// Implement this interface if your language has complex rules around dealing with numbers. /// For example in Romanian "5 days" is "5 zile", while "24 days" is "24 de zile" and /// in Arabic 2 days is يومين not 2 يوم /// public interface IFormatter { string DateHumanize_Now(); string DateHumanize_Never(); /// /// Returns the string representation of the provided DateTime /// string DateHumanize(TimeUnit timeUnit, Tense timeUnitTense, int unit); /// /// 0 seconds /// /// Returns 0 seconds as the string representation of Zero TimeSpan string TimeSpanHumanize_Zero(); /// /// Returns the string representation of the provided TimeSpan /// string TimeSpanHumanize(TimeUnit timeUnit, int unit, bool toWords = false); /// /// Returns the age format that converts a humanized TimeSpan string to an age expression. /// For instance, in English that format adds the " old" suffix, so that "40 years" becomes "40 years old". /// /// Age format string TimeSpanHumanize_Age(); /// /// Returns the string representation of the provided DataUnit, either as a symbol or full word /// /// Data unit /// Number of said units, to adjust for singular/plural forms /// Indicates whether the data unit should be expressed as symbol or full word /// String representation of the provided DataUnit string DataUnitHumanize(DataUnit dataUnit, double count, bool toSymbol = true); /// /// Returns the symbol for the given TimeUnit /// /// Time unit /// String representation of the provided TimeUnit string TimeUnitHumanize(TimeUnit timeUnit); } ================================================ FILE: src/Humanizer/Localisation/Formatters/IcelandicFormatter.cs ================================================ namespace Humanizer; class IcelandicFormatter(CultureInfo culture) : DefaultFormatter(culture) { public override string DataUnitHumanize(DataUnit dataUnit, double count, bool toSymbol = true) => base.DataUnitHumanize(dataUnit, count, toSymbol).TrimEnd('s'); protected override string NumberToWords(TimeUnit unit, int number, CultureInfo culture) => number.ToWords(GetUnitGender(unit), culture); static GrammaticalGender GetUnitGender(TimeUnit unit) => unit switch { TimeUnit.Day or TimeUnit.Month => GrammaticalGender.Masculine, TimeUnit.Year => GrammaticalGender.Neuter, _ => GrammaticalGender.Feminine }; } ================================================ FILE: src/Humanizer/Localisation/Formatters/LithuanianFormatter.cs ================================================ namespace Humanizer; class LithuanianFormatter(CultureInfo culture) : DefaultFormatter(culture) { private static readonly HashSet KeysWithoutNumberForms = ["TimeSpanHumanize_Zero", "DateHumanize_Now"]; protected override string GetResourceKey(string resourceKey, int number) { if (KeysWithoutNumberForms.Contains(resourceKey)) { return resourceKey; } var grammaticalNumber = LithuanianNumberFormDetector.Detect(number); var suffix = GetSuffix(grammaticalNumber); return resourceKey + suffix; } static string GetSuffix(LithuanianNumberForm form) { if (form == LithuanianNumberForm.Singular) { return "_Singular"; } if (form == LithuanianNumberForm.GenitivePlural) { return "_Plural"; } return ""; } } ================================================ FILE: src/Humanizer/Localisation/Formatters/LuxembourgishFormatter.cs ================================================ namespace Humanizer; class LuxembourgishFormatter(CultureInfo culture) : DefaultFormatter(culture) { const string DualPostfix = "_Dual"; // https://lb.wikipedia.org/wiki/Eifeler_Reegel const char EifelerRuleSuffix = 'n'; #if NET8_0_OR_GREATER static readonly SearchValues EifelerRuleCharacters = SearchValues.Create("unitedzohay"); #else const string EifelerRuleCharacters = "unitedzohay"; #endif public override string DataUnitHumanize(DataUnit dataUnit, double count, bool toSymbol = true) => base .DataUnitHumanize(dataUnit, count, toSymbol) .TrimEnd('s'); public static string ApplyEifelerRule(string word) => word.TrimEnd(EifelerRuleSuffix); public static string CheckForAndApplyEifelerRule(string word, string nextWord) => DoesEifelerRuleApply(nextWord.AsSpan()) ? word.TrimEnd(EifelerRuleSuffix) : word; public static bool DoesEifelerRuleApply(CharSpan nextWord) => !nextWord.IsWhiteSpace() && !EifelerRuleCharacters.Contains(nextWord[0]); protected override string Format(TimeUnit unit, string resourceKey, int number, bool toWords = false) { var resourceString = Resources.GetResource(GetResourceKey(resourceKey, number), Culture); var numberAsWord = number.ToWords(GetUnitGender(unit), Culture); return string.Format(resourceString, toWords ? numberAsWord : number, DoesEifelerRuleApply(numberAsWord.AsSpan()) ? "" : EifelerRuleSuffix); } protected override string GetResourceKey(string resourceKey, int number) { if (number == 2 && resourceKey is "DateHumanize_MultipleDaysAgo" or "DateHumanize_MultipleDaysFromNow") { return resourceKey + DualPostfix; } return resourceKey; } static GrammaticalGender GetUnitGender(TimeUnit unit) => unit switch { TimeUnit.Day or TimeUnit.Month or TimeUnit.Year => GrammaticalGender.Masculine, _ => GrammaticalGender.Feminine }; } ================================================ FILE: src/Humanizer/Localisation/Formatters/MalteseFormatter.cs ================================================ namespace Humanizer; class MalteseFormatter(CultureInfo culture) : DefaultFormatter(culture) { protected override string GetResourceKey(string resourceKey, int number) { if (number != 2) { return resourceKey; } return resourceKey switch { "DateHumanize_MultipleDaysAgo" => "DateHumanize_MultipleDaysAgo_Dual", "DateHumanize_MultipleDaysFromNow" => "DateHumanize_MultipleDaysFromNow_Dual", "DateHumanize_MultipleHoursAgo" => "DateHumanize_MultipleHoursAgo_Dual", "DateHumanize_MultipleHoursFromNow" => "DateHumanize_MultipleHoursFromNow_Dual", "DateHumanize_MultipleMonthsAgo" => "DateHumanize_MultipleMonthsAgo_Dual", "DateHumanize_MultipleMonthsFromNow" => "DateHumanize_MultipleMonthsFromNow_Dual", "DateHumanize_MultipleYearsAgo" => "DateHumanize_MultipleYearsAgo_Dual", "DateHumanize_MultipleYearsFromNow" => "DateHumanize_MultipleYearsFromNow_Dual", "TimeSpanHumanize_MultipleDays" => "TimeSpanHumanize_MultipleDays_Dual", "TimeSpanHumanize_MultipleYears" => "TimeSpanHumanize_MultipleYears_Dual", "TimeSpanHumanize_MultipleMonths" => "TimeSpanHumanize_MultipleMonths_Dual", "TimeSpanHumanize_MultipleHours" => "TimeSpanHumanize_MultipleHours_Dual", "TimeSpanHumanize_MultipleWeeks" => "TimeSpanHumanize_MultipleWeeks_Dual", _ => resourceKey, }; } } ================================================ FILE: src/Humanizer/Localisation/Formatters/RomanianFormatter.cs ================================================ namespace Humanizer; class RomanianFormatter(CultureInfo culture) : DefaultFormatter(culture) { const int PrepositionIndicatingDecimals = 2; const int MaxNumeralWithNoPreposition = 19; const int MinNumeralWithNoPreposition = 1; const string UnitPreposition = " de"; static readonly double Divider = Math.Pow(10, PrepositionIndicatingDecimals); protected override string Format(TimeUnit unit, string resourceKey, int number, bool toWords = false) { var format = Resources.GetResource(GetResourceKey(resourceKey, number), Culture); var preposition = ShouldUsePreposition(number) ? UnitPreposition : string.Empty; return string.Format(format, number, preposition); } static bool ShouldUsePreposition(int number) { var prepositionIndicatingNumeral = Math.Abs(number % Divider); return prepositionIndicatingNumeral is < MinNumeralWithNoPreposition or > MaxNumeralWithNoPreposition; } } ================================================ FILE: src/Humanizer/Localisation/Formatters/RussianFormatter.cs ================================================ namespace Humanizer; class RussianFormatter(CultureInfo culture) : DefaultFormatter(culture) { /// public override string DataUnitHumanize(DataUnit dataUnit, double count, bool toSymbol = true) => base.DataUnitHumanize(dataUnit, count, toSymbol).TrimEnd('s'); protected override string GetResourceKey(string resourceKey, int number) { var grammaticalNumber = RussianGrammaticalNumberDetector.Detect(number); return grammaticalNumber switch { RussianGrammaticalNumber.Singular => resourceKey + "_Singular", RussianGrammaticalNumber.Paucal => resourceKey + "_Paucal", _ => resourceKey }; } protected override string NumberToWords(TimeUnit unit, int number, CultureInfo culture) => number.ToWords(GetUnitGender(unit), culture); static GrammaticalGender GetUnitGender(TimeUnit unit) => unit switch { TimeUnit.Hour or TimeUnit.Day or TimeUnit.Month or TimeUnit.Year => GrammaticalGender.Masculine, _ => GrammaticalGender.Feminine }; } ================================================ FILE: src/Humanizer/Localisation/Formatters/SerbianFormatter.cs ================================================ namespace Humanizer; class SerbianFormatter(CultureInfo culture) : DefaultFormatter(culture) { const string PaucalPostfix = "_Paucal"; protected override string GetResourceKey(string resourceKey, int number) { var mod10 = number % 10; if (mod10 is > 1 and < 5) { return resourceKey + PaucalPostfix; } return resourceKey; } } ================================================ FILE: src/Humanizer/Localisation/Formatters/SlovenianFormatter.cs ================================================ namespace Humanizer; class SlovenianFormatter(CultureInfo culture) : DefaultFormatter(culture) { const string DualPostfix = "_Dual"; const string TrialQuadralPostfix = "_Paucal"; protected override string GetResourceKey(string resourceKey, int number) { if (number == 2) { return resourceKey + DualPostfix; } // When the count is three or four some words have a different form when counting in Slovenian language if (number is 3 or 4) { return resourceKey + TrialQuadralPostfix; } return resourceKey; } } ================================================ FILE: src/Humanizer/Localisation/Formatters/UkrainianFormatter.cs ================================================ namespace Humanizer; class UkrainianFormatter(CultureInfo culture) : DefaultFormatter(culture) { protected override string GetResourceKey(string resourceKey, int number) { var grammaticalNumber = RussianGrammaticalNumberDetector.Detect(number); return grammaticalNumber switch { RussianGrammaticalNumber.Singular => resourceKey + "_Singular", RussianGrammaticalNumber.Paucal => resourceKey + "_Paucal", _ => resourceKey }; } protected override string NumberToWords(TimeUnit unit, int number, CultureInfo culture) => number.ToWords(GetUnitGender(unit), culture); static GrammaticalGender GetUnitGender(TimeUnit unit) => unit switch { TimeUnit.Day or TimeUnit.Week or TimeUnit.Month or TimeUnit.Year => GrammaticalGender.Masculine, _ => GrammaticalGender.Feminine }; } ================================================ FILE: src/Humanizer/Localisation/GrammaticalNumber/LithuanianNumberForm.cs ================================================ namespace Humanizer; enum LithuanianNumberForm { Singular, Plural, GenitivePlural } ================================================ FILE: src/Humanizer/Localisation/GrammaticalNumber/LithuanianNumberFormDetector.cs ================================================ namespace Humanizer; static class LithuanianNumberFormDetector { public static LithuanianNumberForm Detect(long number) { var tens = number % 100 / 10; var units = number % 10; if (tens == 1 || units == 0) // 10-19, 20, 30, 40 ... 100, 110 .. { return LithuanianNumberForm.GenitivePlural; } if (units == 1) // 1, 21, 31, 41 ... 91, 101, 121 ... { return LithuanianNumberForm.Singular; } // 2-9, 22-29, 32 ... return LithuanianNumberForm.Plural; } } ================================================ FILE: src/Humanizer/Localisation/GrammaticalNumber/RussianGrammaticalNumber.cs ================================================ namespace Humanizer; enum RussianGrammaticalNumber { Singular, Paucal, Plural } ================================================ FILE: src/Humanizer/Localisation/GrammaticalNumber/RussianGrammaticalNumberDetector.cs ================================================ namespace Humanizer; static class RussianGrammaticalNumberDetector { public static RussianGrammaticalNumber Detect(long number) { var tens = number % 100 / 10; if (tens != 1) { var unity = number % 10; if (unity == 1) // 1, 21, 31, 41 ... 91, 101, 121 ... { return RussianGrammaticalNumber.Singular; } if (unity is > 1 and < 5) // 2, 3, 4, 22, 23, 24 ... { return RussianGrammaticalNumber.Paucal; } } return RussianGrammaticalNumber.Plural; } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/AfrikaansNumberToWordsConverter.cs ================================================ namespace Humanizer; class AfrikaansNumberToWordsConverter : GenderlessNumberToWordsConverter { static readonly string[] UnitsMap = ["nul", "een", "twee", "drie", "vier", "vyf", "ses", "sewe", "agt", "nege", "tien", "elf", "twaalf", "dertien", "veertien", "vyftien", "sestien", "sewentien", "agtien", "negentien"]; static readonly string[] TensMap = ["nul", "tien", "twintig", "dertig", "veertig", "vyftig", "sestig", "sewentig", "tagtig", "negentig"]; static readonly FrozenDictionary OrdinalExceptions = new Dictionary { { 0, "nulste" }, { 1, "eerste" }, { 3, "derde" }, { 7, "sewende" }, { 8, "agste" }, { 9, "negende" }, { 10, "tiende" }, { 14, "veertiende" }, { 17, "sewentiende" }, { 19, "negentiende" } }.ToFrozenDictionary(); public override string Convert(long number) { if (number is > int.MaxValue or < int.MinValue) { throw new NotImplementedException(); } return Convert((int)number, false); } public override string ConvertToOrdinal(int number) => Convert(number, true); string Convert(int number, bool isOrdinal) { if (number == 0) { return GetUnitValue(0, isOrdinal); } if (number < 0) { return $"minus {Convert(-number)}"; } var parts = new List(); if (number / 1000000000 > 0) { parts.Add($"{Convert(number / 1000000000)} miljard"); number %= 1000000000; } if (number / 1000000 > 0) { parts.Add($"{Convert(number / 1000000)} miljoen"); number %= 1000000; } if (number / 1000 > 0) { parts.Add($"{Convert(number / 1000)} duisend"); number %= 1000; } if (number / 100 > 0) { parts.Add($"{Convert(number / 100)} honderd"); number %= 100; } if (number > 0) { //if (parts.Count != 0) // parts.Add("en"); if (number < 20) { if (parts.Count > 0) { parts.Add("en"); } parts.Add(GetUnitValue(number, isOrdinal)); } else { var lastPartValue = number / 10 * 10; var lastPart = TensMap[number / 10]; if (number % 10 > 0) { lastPart = $"{GetUnitValue(number % 10, false)} en {(isOrdinal ? GetUnitValue(lastPartValue, true) : lastPart)}"; } else if (number % 10 == 0) { lastPart = $"{(parts.Count > 0 ? "en " : "")}{lastPart}{(isOrdinal ? "ste" : "")}"; } else if (isOrdinal) { lastPart = lastPart.TrimEnd('~') + "ste"; } parts.Add(lastPart); } } else if (isOrdinal) { parts[^1] += "ste"; } var toWords = string.Join(" ", parts); if (isOrdinal) { toWords = RemoveOnePrefix(toWords); } return toWords; } static string GetUnitValue(int number, bool isOrdinal) { if (isOrdinal) { if (ExceptionNumbersToWords(number, out var exceptionString)) { return exceptionString; } if (number > 19) { return TensMap[number / 10] + "ste"; } return UnitsMap[number] + "de"; } return UnitsMap[number]; } static string RemoveOnePrefix(string toWords) { // one hundred => hundredth if (toWords.StartsWith("een", StringComparison.Ordinal) && !toWords.StartsWith("een en", StringComparison.Ordinal)) { toWords = toWords[4..]; } return toWords; } static bool ExceptionNumbersToWords(int number, [NotNullWhen(true)] out string? words) => OrdinalExceptions.TryGetValue(number, out words); } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/ArabicNumberToWordsConverter.cs ================================================ namespace Humanizer; class ArabicNumberToWordsConverter : GenderedNumberToWordsConverter { static readonly string[] Groups = ["مئة", "ألف", "مليون", "مليار", "تريليون", "كوادريليون", "كوينتليون", "سكستيليون"]; static readonly string[] AppendedGroups = ["", "ألفاً", "مليوناً", "ملياراً", "تريليوناً", "كوادريليوناً", "كوينتليوناً", "سكستيليوناً"]; static readonly string[] PluralGroups = ["", "آلاف", "ملايين", "مليارات", "تريليونات", "كوادريليونات", "كوينتليونات", "سكستيليونات"]; static readonly string[] OnesGroup = ["", "واحد", "اثنان", "ثلاثة", "أربعة", "خمسة", "ستة", "سبعة", "ثمانية", "تسعة", "عشرة", "أحد عشر", "اثنا عشر", "ثلاثة عشر", "أربعة عشر", "خمسة عشر", "ستة عشر", "سبعة عشر", "ثمانية عشر", "تسعة عشر"]; static readonly string[] TensGroup = ["", "عشرة", "عشرون", "ثلاثون", "أربعون", "خمسون", "ستون", "سبعون", "ثمانون", "تسعون"]; static readonly string[] HundredsGroup = ["", "مئة", "مئتان", "ثلاث مئة", "أربع مئة", "خمس مئة", "ست مئة", "سبع مئة", "ثمان مئة", "تسع مئة"]; static readonly string[] AppendedTwos = ["مئتان", "ألفان", "مليونان", "ملياران", "تريليونان", "كوادريليونان", "كوينتليونان", "سكستيليونلن"]; static readonly string[] Twos = ["مئتان", "ألفان", "مليونان", "ملياران", "تريليونان", "كوادريليونان", "كوينتليونان", "سكستيليونان"]; static readonly string[] FeminineOnesGroup = ["", "واحدة", "اثنتان", "ثلاث", "أربع", "خمس", "ست", "سبع", "ثمان", "تسع", "عشر", "إحدى عشرة", "اثنتا عشرة", "ثلاث عشرة", "أربع عشرة", "خمس عشرة", "ست عشرة", "سبع عشرة", "ثمان عشرة", "تسع عشرة"]; public override string Convert(long number, GrammaticalGender gender, bool addAnd = true) { if (number == 0) { return "صفر"; } if (number < 0) { return $"سالب {Convert(-number, gender)}"; } var result = string.Empty; var groupLevel = 0; while (number >= 1) { var groupNumber = number % 1000; number /= 1000; var tens = groupNumber % 100; var hundreds = groupNumber / 100; var process = string.Empty; if (hundreds > 0) { if (tens == 0 && hundreds == 2) { process = AppendedTwos[0]; } else { process = HundredsGroup[hundreds]; } } if (tens > 0) { if (tens < 20) { if (tens == 2 && hundreds == 0 && groupLevel > 0) { if (number is 2000 or 2000000 or 2000000000) { process = AppendedTwos[groupLevel]; } else { process = Twos[groupLevel]; } } else { if (process != string.Empty) { process += " و "; } if (tens == 1 && groupLevel > 0 && hundreds == 0) { process += " "; } else { process += gender == GrammaticalGender.Feminine && groupLevel == 0 ? FeminineOnesGroup[tens] : OnesGroup[tens]; } } } else { var ones = tens % 10; tens /= 10; if (ones > 0) { if (process != string.Empty) { process += " و "; } process += gender == GrammaticalGender.Feminine ? FeminineOnesGroup[ones] : OnesGroup[ones]; } if (process != string.Empty) { process += " و "; } process += TensGroup[tens]; } } if (process != string.Empty) { if (groupLevel > 0) { if (result != string.Empty) { result = $"و {result}"; } if (groupNumber != 2) { if (groupNumber % 100 != 1) { if (groupNumber is >= 3 and <= 10) { result = $"{PluralGroups[groupLevel]} {result}"; } else { result = $"{(result != string.Empty ? AppendedGroups[groupLevel] : Groups[groupLevel])} {result}"; } } else { result = $"{Groups[groupLevel]} {result}"; } } } result = $"{process} {result}"; } groupLevel++; } return result.Trim(); } static readonly Dictionary OrdinalExceptions = new() { { "واحد", "الحادي" }, { "أحد", "الحادي" }, { "اثنان", "الثاني" }, { "اثنا", "الثاني" }, { "ثلاثة", "الثالث" }, { "أربعة", "الرابع" }, { "خمسة", "الخامس" }, { "ستة", "السادس" }, { "سبعة", "السابع" }, { "ثمانية", "الثامن" }, { "تسعة", "التاسع" }, { "عشرة", "العاشر" }, }; static readonly Dictionary FeminineOrdinalExceptions = new() { { "واحدة", "الحادية" }, { "إحدى", "الحادية" }, { "اثنتان", "الثانية" }, { "اثنتا", "الثانية" }, { "ثلاث", "الثالثة" }, { "أربع", "الرابعة" }, { "خمس", "الخامسة" }, { "ست", "السادسة" }, { "سبع", "السابعة" }, { "ثمان", "الثامنة" }, { "تسع", "التاسعة" }, { "عشر", "العاشرة" }, }; public override string ConvertToOrdinal(int number, GrammaticalGender gender) { if (number == 0) { return "الصفر"; } var beforeOneHundredNumber = number % 100; var overTensPart = number / 100 * 100; var beforeOneHundredWord = string.Empty; var overTensWord = string.Empty; if (beforeOneHundredNumber > 0) { beforeOneHundredWord = Convert(beforeOneHundredNumber, gender); beforeOneHundredWord = ParseNumber(beforeOneHundredWord, beforeOneHundredNumber, gender); } if (overTensPart > 0) { overTensWord = Convert(overTensPart); overTensWord = ParseNumber(overTensWord, overTensPart, gender); } var word = beforeOneHundredWord + (overTensPart > 0 ? (string.IsNullOrWhiteSpace(beforeOneHundredWord) ? string.Empty : " بعد ") + overTensWord : string.Empty); return word.Trim(); } static string ParseNumber(string word, int number, GrammaticalGender gender) { if (number == 1) { return gender == GrammaticalGender.Feminine ? "الأولى" : "الأول"; } if (number <= 10) { var ordinals = gender == GrammaticalGender.Feminine ? FeminineOrdinalExceptions : OrdinalExceptions; foreach (var kv in ordinals.Where(kv => word.EndsWith(kv.Key))) { // replace word with exception return StringHumanizeExtensions.Concat( word.AsSpan(0, word.Length - kv.Key.Length), kv.Value.AsSpan()); } } else if (number is > 10 and < 100) { var parts = word.Split(' '); var newParts = new string[parts.Length]; var count = 0; foreach (var part in parts) { var newPart = part; var oldPart = part; var ordinals = gender == GrammaticalGender.Feminine ? FeminineOrdinalExceptions : OrdinalExceptions; foreach (var kv in ordinals.Where(kv => oldPart.EndsWith(kv.Key))) { // replace word with exception newPart = StringHumanizeExtensions.Concat( oldPart.AsSpan(0, oldPart.Length - kv.Key.Length), kv.Value.AsSpan()); } if (number > 19 && newPart == oldPart && oldPart.Length > 1) { newPart = "ال" + oldPart; } newParts[count++] = newPart; } word = string.Join(" ", newParts); } else { word = "ال" + word; } return word; } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/ArmenianNumberToWordsConverter.cs ================================================ namespace Humanizer; class ArmenianNumberToWordsConverter : GenderlessNumberToWordsConverter { static readonly string[] UnitsMap = ["զրո", "մեկ", "երկու", "երեք", "չորս", "հինգ", "վեց", "յոթ", "ութ", "ինը", "տաս", "տասնմեկ", "տասներկու", "տասներեք", "տասնչորս", "տասնհինգ", "տասնվեց", "տասնյոթ", "տասնութ", "տասնինը"]; static readonly string[] TensMap = ["զրո", "տաս", "քսան", "երեսուն", "քառասուն", "հիսուն", "վաթսուն", "յոթանասուն", "ութսուն", "իննսուն"]; static readonly FrozenDictionary OrdinalExceptions = new Dictionary { { 0, "զրոյական" }, { 1, "առաջին" }, { 2, "երկրորդ" }, { 3, "երրորդ" }, { 4, "չորրորդ" } }.ToFrozenDictionary(); public override string Convert(long number) => ConvertImpl(number, false); public override string ConvertToOrdinal(int number) { if (ExceptionNumbersToWords(number, out var exceptionString)) { return exceptionString; } return ConvertImpl(number, true); } string ConvertImpl(long number, bool isOrdinal) { if (number == 0) { return GetUnitValue(0, isOrdinal); } if (number == long.MinValue) { return "մինուս ինը քվինտիլիոն " + "երկու հարյուր քսաներեք կվադրիլիոն " + "երեք հարյուր յոթանասուներկու տրիլիոն " + "երեսունվեց միլիարդ " + "ութ հարյուր հիսունչորս միլիոն " + "յոթ հարյուր յոթանասունհինգ հազար " + "ութ հարյուր ութ"; } if (number < 0) { return $"մինուս {ConvertImpl(-number, isOrdinal)}"; } var parts = new List(); if (number / 1000000000000000000 > 0) { parts.Add($"{Convert(number / 1000000000000000000)} քվինտիլիոն"); number %= 1000000000000000000; } if (number / 1000000000000000 > 0) { parts.Add($"{Convert(number / 1000000000000000)} կվադրիլիոն"); number %= 1000000000000000; } if (number / 1000000000000 > 0) { parts.Add($"{Convert(number / 1000000000000)} տրիլիոն"); number %= 1000000000000; } if (number / 1000000000 > 0) { parts.Add($"{Convert(number / 1000000000)} միլիարդ"); number %= 1000000000; } if (number / 1000000 > 0) { parts.Add($"{Convert(number / 1000000)} միլիոն"); number %= 1000000; } if (number / 1000 > 0) { if (number / 1000 == 1) { parts.Add("հազար"); } else { parts.Add($"{Convert(number / 1000)} հազար"); } number %= 1000; } if (number / 100 > 0) { if (number / 100 == 1) { parts.Add("հարյուր"); } else { parts.Add($"{Convert(number / 100)} հարյուր"); } number %= 100; } if (number > 0) { if (number < 20) { parts.Add(GetUnitValue(number, isOrdinal)); } else { var lastPart = TensMap[number / 10]; if (number % 10 > 0) { lastPart += $"{GetUnitValue(number % 10, isOrdinal)}"; } else if (isOrdinal) { lastPart += "երորդ"; } parts.Add(lastPart); } } else if (isOrdinal) { parts[^1] += "երորդ"; } var toWords = string.Join(" ", parts); //if (isOrdinal) //{ // toWords = RemoveOnePrefix(toWords); //} return toWords; } static string GetUnitValue(long number, bool isOrdinal) { if (isOrdinal) { return UnitsMap[number] + "երորդ"; } return UnitsMap[number]; } static bool ExceptionNumbersToWords(long number, [NotNullWhen(true)] out string? words) => OrdinalExceptions.TryGetValue(number, out words); } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/AzerbaijaniNumberToWordsConverter.cs ================================================ namespace Humanizer; class AzerbaijaniNumberToWordsConverter : GenderlessNumberToWordsConverter { static readonly string[] UnitsMap = ["sıfır", "bir", "iki", "üç", "dörd", "beş", "altı", "yeddi", "səkkiz", "doqquz"]; static readonly string[] TensMap = ["sıfır", "on", "iyirmi", "otuz", "qırx", "əlli", "altmış", "yetmiş", "səksən", "doxsan"]; static readonly FrozenDictionary OrdinalSuffix = new Dictionary { { 'ı', "ıncı" }, { 'i', "inci" }, { 'u', "uncu" }, { 'ü', "üncü" }, { 'o', "uncu" }, { 'ö', "üncü" }, { 'e', "inci" }, { 'a', "ıncı" }, { 'ə', "inci" }, }.ToFrozenDictionary(); public override string Convert(long input) { if (input is > int.MaxValue or < int.MinValue) { throw new NotImplementedException(); } var number = (int)input; if (number == 0) { return UnitsMap[0]; } if (number < 0) { return $"mənfi {Convert(-number)}"; } var parts = new List(); if (number / 1000000000 > 0) { parts.Add($"{Convert(number / 1000000000)} milyard"); number %= 1000000000; } if (number / 1000000 > 0) { parts.Add($"{Convert(number / 1000000)} milyon"); number %= 1000000; } var thousand = number / 1000; if (thousand > 0) { parts.Add($"{(thousand > 1 ? Convert(thousand) : "")} min".Trim()); number %= 1000; } var hundred = number / 100; if (hundred > 0) { parts.Add($"{(hundred > 1 ? Convert(hundred) : "")} yüz".Trim()); number %= 100; } if (number / 10 > 0) { parts.Add(TensMap[number / 10]); number %= 10; } if (number > 0) { parts.Add(UnitsMap[number]); } var toWords = string.Join(" ", parts); return toWords; } public override string ConvertToOrdinal(int number) { var word = Convert(number); var wordSuffix = string.Empty; var suffixFoundOnLastVowel = false; for (var i = word.Length - 1; i >= 0; i--) { if (OrdinalSuffix.TryGetValue(word[i], out wordSuffix)) { suffixFoundOnLastVowel = i == word.Length - 1; break; } } if (word[^1] == 't') { word = StringHumanizeExtensions.Concat(word.AsSpan(0, word.Length - 1), 'd'); } if (suffixFoundOnLastVowel) { word = word[..^1]; } return $"{word}{wordSuffix}"; } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/BanglaNumberToWordsConverter.cs ================================================ namespace Humanizer; class BanglaNumberToWordsConverter : GenderlessNumberToWordsConverter { static readonly string[] UnitsMap = [ "শূন্য", "এক", "দুই", "তিন", "চার", "পাঁচ", "ছয়", "সাত", "আট", "নয়", "দশ", "এগারো", "বারো", "তেরো", "চোদ্দ", "পনেরো", "ষোল", "সতেরো", "আঠারো", "উনিশ", "বিশ", "একুশ", "বাইশ", "তেইশ", "চব্বিশ", "পঁচিশ", "ছাব্বিশ", "সাতাশ", "আঠাশ", "উনতিরিশ", "তিরিশ", "একতিরিশ", "বত্রিশ", "তেত্রিশ", "চৌঁতিরিশ", "পঁয়তিরিশ", "ছত্রিশ", "সাঁইতিরিশ", "আটতিরিশ", "উনচল্লিশ", "চল্লিশ", "একচল্লিশ", "বিয়াল্লিশ", "তেতাল্লিশ", "চুয়াল্লিশ", "পঁয়তাল্লিশ", "ছেচাল্লিশ", "সাতচল্লিশ", "আটচল্লিশ", "উনপঞ্চাশ", "পঞ্চাশ", "একান্ন", "বাহান্ন", "তিপ্পান্ন", "চুয়ান্ন", "পঞ্চান্ন", "ছাপ্পান্ন", "সাতান্ন", "আটান্ন", "উনষাট", "ষাট", "একষট্টি", "বাষট্টি", "তেষট্টি", "চৌষট্টি", "পঁয়ষট্টি", "ছেষট্টি", "সাতষট্টি", "আটষট্টি", "উনসত্তর", "সত্তর", "একাত্তর", "বাহাত্তর", "তিয়াত্তর", "চুয়াত্তর", "পঁচাত্তর", "ছিয়াত্তর", "সাতাত্তর", "আটাত্তর", "উনআশি", "আশি", "একাশি", "বিরাশি", "তিরাশি", "চুরাশি", "পঁচাশি", "ছিয়াশি", "সাতাশি", "আটাশি", "উননব্বই", "নব্বই", "একানব্বই", "বিরানব্বই", "তিরানব্বিই", "চুরানব্বই", "পঁচানব্বই", "ছিয়ানব্বই", "সাতানব্বই", "আটানব্বই", "নিরানব্বই" ]; static readonly string[] HundredsMap = [ "শূন্য", "একশ", "দুইশ", "তিনশ", "চারশ", "পাঁচশ", "ছয়শ", "সাতশ", "আটশ", "নয়শ" ]; static readonly FrozenDictionary OrdinalExceptions = new Dictionary { { 1, "প্রথম" }, { 2, "দ্বিতীয়" }, { 3, "তৃতীয়" }, { 4, "চতুর্থ" }, { 5, "পঞ্চম" }, { 6, "ষষ্ট" }, { 7, "সপ্তম" }, { 8, "অষ্টম" }, { 9, "নবম" }, { 10, "দশম" }, { 11, "একাদশ" }, { 12, "দ্বাদশ" }, { 13, "ত্রয়োদশ" }, { 14, "চতুর্দশ" }, { 15, "পঞ্চদশ" }, { 16, "ষোড়শ" }, { 17, "সপ্তদশ" }, { 18, "অষ্টাদশ" }, { 100, "শত তম" }, { 1000, "হাজার তম" }, { 100000, "লক্ষ তম" }, { 10000000, "কোটি তম" }, }.ToFrozenDictionary(); public override string ConvertToOrdinal(int number) { if (ExceptionNumbersToWords(number, out var exceptionString)) { return exceptionString; } return Convert(number) + " তম"; } public override string Convert(long input) { if (input is > int.MaxValue or < int.MinValue) { throw new NotImplementedException(); } var number = (int)input; if (number == 0) { return UnitsMap[0]; } if (number < 0) { return $"ঋণাত্মক {Convert(-number)}"; } var parts = new List(); if (number / 10000000 > 0) { parts.Add($"{Convert(number / 10000000)} কোটি"); number %= 10000000; } if (number / 100000 > 0) { parts.Add($"{Convert(number / 100000)} লক্ষ"); number %= 100000; } if (number / 1000 > 0) { parts.Add($"{Convert(number / 1000)} হাজার"); number %= 1000; } if (number / 100 > 0) { parts.Add($"{HundredsMap[number / 100]}"); number %= 100; } if (number > 0) { parts.Add(UnitsMap[number]); } return string.Join(" ", parts); } static bool ExceptionNumbersToWords(int number, [NotNullWhen(true)] out string? words) => OrdinalExceptions.TryGetValue(number, out words); } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/BrazilianPortugueseNumberToWordsConverter.cs ================================================ namespace Humanizer; class BrazilianPortugueseNumberToWordsConverter : GenderedNumberToWordsConverter { static readonly string[] UnitsMap = ["zero", "um", "dois", "três", "quatro", "cinco", "seis", "sete", "oito", "nove", "dez", "onze", "doze", "treze", "quatorze", "quinze", "dezesseis", "dezessete", "dezoito", "dezenove"]; static readonly string[] TensMap = ["zero", "dez", "vinte", "trinta", "quarenta", "cinquenta", "sessenta", "setenta", "oitenta", "noventa"]; static readonly string[] HundredsMap = ["zero", "cento", "duzentos", "trezentos", "quatrocentos", "quinhentos", "seiscentos", "setecentos", "oitocentos", "novecentos"]; static readonly string[] OrdinalUnitsMap = ["zero", "primeiro", "segundo", "terceiro", "quarto", "quinto", "sexto", "sétimo", "oitavo", "nono"]; static readonly string[] OrdinalTensMap = ["zero", "décimo", "vigésimo", "trigésimo", "quadragésimo", "quinquagésimo", "sexagésimo", "septuagésimo", "octogésimo", "nonagésimo"]; static readonly string[] OrdinalHundredsMap = ["zero", "centésimo", "ducentésimo", "trecentésimo", "quadringentésimo", "quingentésimo", "sexcentésimo", "septingentésimo", "octingentésimo", "noningentésimo"]; public override string Convert(long input, GrammaticalGender gender, bool addAnd = true) { if (input is > 999999999999 or < -999999999999) { throw new NotImplementedException(); } var number = input; if (number == 0) { return "zero"; } if (number < 0) { return $"menos {Convert(Math.Abs(number), gender)}"; } var parts = new List(); if (number / 1000000000 > 0) { // gender is not applied for billions parts.Add(number / 1000000000 >= 2 ? $"{Convert(number / 1000000000, GrammaticalGender.Masculine)} bilhões" : $"{Convert(number / 1000000000, GrammaticalGender.Masculine)} bilhão"); number %= 1000000000; } if (number / 1000000 > 0) { // gender is not applied for millions parts.Add(number / 1000000 >= 2 ? $"{Convert(number / 1000000, GrammaticalGender.Masculine)} milhões" : $"{Convert(number / 1000000, GrammaticalGender.Masculine)} milhão"); number %= 1000000; } if (number / 1000 > 0) { // gender is not applied for thousands parts.Add(number / 1000 == 1 ? "mil" : $"{Convert(number / 1000, GrammaticalGender.Masculine)} mil"); number %= 1000; } if (number / 100 > 0) { if (number == 100) { parts.Add(parts.Count > 0 ? "e cem" : "cem"); } else { // Gender is applied to hundreds starting from 200 parts.Add(ApplyGender(HundredsMap[number / 100], gender)); } number %= 100; } if (number > 0) { if (parts.Count != 0) { parts.Add("e"); } if (number < 20) { parts.Add(ApplyGender(UnitsMap[number], gender)); } else { var lastPart = TensMap[number / 10]; if (number % 10 > 0) { lastPart += $" e {ApplyGender(UnitsMap[number % 10], gender)}"; } parts.Add(lastPart); } } return string.Join(" ", parts); } public override string ConvertToOrdinal(int number, GrammaticalGender gender) { // N/A in Portuguese ordinal if (number == 0) { return "zero"; } var parts = new List(); if (number / 1000000000 > 0) { parts.Add(number / 1000000000 == 1 ? ApplyOrdinalGender("bilionésimo", gender) : string.Format("{0} " + ApplyOrdinalGender("bilionésimo", gender), ConvertToOrdinal(number / 1000000000, gender))); number %= 1000000000; } if (number / 1000000 > 0) { parts.Add(number / 1000000 == 1 ? ApplyOrdinalGender("milionésimo", gender) : string.Format("{0}" + ApplyOrdinalGender("milionésimo", gender), ConvertToOrdinal(number / 1000000000, gender))); number %= 1000000; } if (number / 1000 > 0) { parts.Add(number / 1000 == 1 ? ApplyOrdinalGender("milésimo", gender) : string.Format("{0} " + ApplyOrdinalGender("milésimo", gender), ConvertToOrdinal(number / 1000, gender))); number %= 1000; } if (number / 100 > 0) { parts.Add(ApplyOrdinalGender(OrdinalHundredsMap[number / 100], gender)); number %= 100; } if (number / 10 > 0) { parts.Add(ApplyOrdinalGender(OrdinalTensMap[number / 10], gender)); number %= 10; } if (number > 0) { parts.Add(ApplyOrdinalGender(OrdinalUnitsMap[number], gender)); } return string.Join(" ", parts); } static string ApplyGender(string toWords, GrammaticalGender gender) { if (gender != GrammaticalGender.Feminine) { return toWords; } if (toWords.EndsWith("os")) { return StringHumanizeExtensions.Concat(toWords.AsSpan(0, toWords.Length - 2), "as".AsSpan()); } if (toWords.EndsWith("um")) { return StringHumanizeExtensions.Concat(toWords.AsSpan(0, toWords.Length - 2), "uma".AsSpan()); } if (toWords.EndsWith("dois")) { return StringHumanizeExtensions.Concat(toWords.AsSpan(0, toWords.Length - 4), "duas".AsSpan()); } return toWords; } static string ApplyOrdinalGender(string toWords, GrammaticalGender gender) { if (gender == GrammaticalGender.Feminine) { return StringHumanizeExtensions.Concat( toWords.AsSpan().TrimEnd('o'), 'a'); } return toWords; } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/BulgarianNumberToWordsConverter.cs ================================================ namespace Humanizer; class BulgarianNumberToWordsConverter() : GenderedNumberToWordsConverter(GrammaticalGender.Neuter) { static readonly string[] UnitsMap = [ "нула", "едно", "две", "три", "четири", "пет", "шест", "седем", "осем", "девет", "десет", "единадесет", "дванадесет", "тринадесет", "четиринадесет", "петнадесет", "шестнадесет", "седемнадесет", "осемнадесет", "деветнадесет" ]; static readonly string[] TensMap = [ "нула", "десет", "двадесет", "тридесет", "четиридесет", "петдесет", "шестдесет", "седемдесет", "осемдесет", "деветдесет" ]; static readonly string[] HundredsMap = [ "нула", "сто", "двеста", "триста", "четиристотин", "петстотин", "шестстотин", "седемстотин", "осемстотин", "деветстотин" ]; static readonly string[] HundredsOrdinalMap = [ string.Empty, "стот", "двестот", "тристот", "четиристот", "петстот", "шестстот", "седемстот", "осемстот", "деветстот" ]; static readonly string[] UnitsOrdinal = [ string.Empty, "първ", "втор", "трет", "четвърт", "пет", "шест", "седм", "осм", "девeт", "десeт", "единадесет", "дванадесет", "тринадесет", "четиринадесет", "петнадесет", "шестнадесет", "седемнадесет", "осемнадесет", "деветнадесет" ]; public override string Convert(long input, GrammaticalGender gender, bool addAnd = true) => InnerConvert(input, gender, false); public override string ConvertToOrdinal(int input, GrammaticalGender gender) => InnerConvert(input, gender, true); static string InnerConvert(long input, GrammaticalGender gender, bool isOrdinal) { if (input == 0) { return isOrdinal ? OrdinalZero(gender) : "нула"; } var parts = new List(); if (input < 0) { parts.Add("минус"); input = -input; } CollectParts(parts, ref input, isOrdinal, 1_000_000_000_000_000_000, GrammaticalGender.Masculine, "квинтилион", "квадрилиона", ToOrdinalOverAHundred("квинтилион", gender)); CollectParts(parts, ref input, isOrdinal, 1_000_000_000_000_000, GrammaticalGender.Masculine, "квадрилион", "квадрилиона", ToOrdinalOverAHundred("квадрилион", gender)); CollectParts(parts, ref input, isOrdinal, 1_000_000_000_000, GrammaticalGender.Masculine, "трилион", "трилиона", ToOrdinalOverAHundred("трилион", gender)); CollectParts(parts, ref input, isOrdinal, 1_000_000_000, GrammaticalGender.Masculine, "милиард", "милиарда", ToOrdinalOverAHundred("милиард", gender)); CollectParts(parts, ref input, isOrdinal, 1_000_000, GrammaticalGender.Masculine, "милион", "милиона", ToOrdinalOverAHundred("милион", gender)); CollectParts(parts, ref input, isOrdinal, 1_000, GrammaticalGender.Feminine, "хиляда", "хиляди", ToOrdinalOverAHundred("хиляд", gender)); CollectPartsUnderOneThousand(parts, ref input, isOrdinal, gender); return string.Join(" ", parts); } static void CollectParts(List parts, ref long number, bool isOrdinal, long divisor, GrammaticalGender gender, string singular, string plural, string ordinal) { if (number < divisor) { return; } var result = number / divisor; if (parts.Count > 0) { parts.Add("и"); } CollectPartsUnderOneThousand(parts, ref result, false, gender); number %= divisor; if (number == 0 && isOrdinal) { parts.Add(ordinal); } else { parts.Add(result == 1 ? singular : plural); } } static void CollectPartsUnderOneThousand(List parts, ref long number, bool isOrdinal, GrammaticalGender gender) { if (number == 0) { return; } if (number >= 100) { var hundreds = number / 100; number %= 100; if (number == 0 && isOrdinal) { parts.Add(ToOrdinalOverAHundred(HundredsOrdinalMap[hundreds], gender)); } else { parts.Add(HundredsMap[hundreds]); } } if (number >= 20) { var tens = number / 10; number %= 10; if (number == 0 && isOrdinal) { parts.Add(ToOrdinalUnitsAndTens(TensMap[tens], gender)); } else { parts.Add(TensMap[tens]); } } if (number > 0) { if (isOrdinal) { parts.Add(ToOrdinalUnitsAndTens(UnitsOrdinal[number], gender)); } else { parts.Add(GetUnit(number, gender)); } } if (parts.Count > 1) { parts.Insert(parts.Count - 1, "и"); } } static string GetUnit(long number, GrammaticalGender gender) => (number, gender) switch { (1, GrammaticalGender.Masculine) => "един", (1, GrammaticalGender.Feminine) => "една", (2, GrammaticalGender.Masculine) => "два", _ => UnitsMap[number], }; static string OrdinalZero(GrammaticalGender gender) => gender switch { GrammaticalGender.Masculine => "нулев", GrammaticalGender.Feminine => "нулева", GrammaticalGender.Neuter => "нулево", _ => throw new ArgumentOutOfRangeException(nameof(gender), gender, null) }; static string ToOrdinalOverAHundred(string word, GrammaticalGender gender) => gender switch { GrammaticalGender.Masculine => $"{word}ен", GrammaticalGender.Feminine => $"{word}на", GrammaticalGender.Neuter => $"{word}но", _ => throw new ArgumentOutOfRangeException(nameof(gender)) }; static string ToOrdinalUnitsAndTens(string word, GrammaticalGender gender) => gender switch { GrammaticalGender.Masculine => $"{word}и", GrammaticalGender.Feminine => $"{word}а", GrammaticalGender.Neuter => $"{word}о", _ => throw new ArgumentOutOfRangeException(nameof(gender)) }; } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/CatalanNumberToWordsConverter.cs ================================================ namespace Humanizer; class CatalanNumberToWordsConverter : GenderedNumberToWordsConverter { // Cardinal units private static readonly string[] UnitsMasculine = [ "", "un", "dos", "tres", "quatre", "cinc", "sis", "set", "vuit", "nou" ]; private static readonly string[] UnitsFeminine = [ "", "una", "dues", "tres", "quatre", "cinc", "sis", "set", "vuit", "nou" ]; // Special cases for teens (10-19) private static readonly string[] Teens = [ "deu", "onze", "dotze", "tretze", "catorze", "quinze", "setze", "disset", "divuit", "dinou" ]; // Decenas: exact tens and for composition private static readonly string[] Tens = [ "", "deu", "vint", "trenta", "quaranta", "cinquanta", "seixanta", "setanta", "vuitanta", "noranta" ]; // Centenas (masculino y femenino) private static readonly string[] HundredsMasculine = [ "", "cent", "dos-cents", "tres-cents", "quatre-cents", "cinc-cents", "sis-cents", "set-cents", "vuit-cents", "nou-cents" ]; private static readonly string[] HundredsFeminine = [ "", "cent", "dues-centes", "tres-centes", "quatre-centes", "cinc-centes", "sis-centes", "set-centes", "vuit-centes", "nou-centes" ]; static readonly string[] TupleMap = [ "zero vegades", "una vegada", "doble", "triple", "qüàdruple", "quíntuple", "sèxtuple", "sèptuple", "òctuple", "nònuple", "dècuple", "undècuple", "duodècuple", "tercidecuple" ]; #region Convert public override string Convert(long number, GrammaticalGender gender, bool addAnd = true) { if (number == 0) { return "zero"; } if (number < 0) { return "menys " + Convert(-number, gender); } if (number < 10) { return GetUnit((int)number, gender); } if (number < 20) { return Teens[number - 10]; } if (number < 100) { return GetTens((int)number, gender); } if (number < 1000) { return GetHundreds((int)number, gender); } if (number < 1000000) { return GetThousands((int)number, gender); } if (number < 1000000000) { return GetMillions((int)number, gender); } throw new NotImplementedException("Nombres més grans de mil milions no estan implementats."); } private static string GetUnit(int number, GrammaticalGender gender) => gender == GrammaticalGender.Feminine ? UnitsFeminine[number] : UnitsMasculine[number]; private static string GetTens(int number, GrammaticalGender gender) { var tens = number / 10; var units = number % 10; if (number < 20) { return Teens[number - 10]; } if (units == 0) { return Tens[tens]; } // "vint-i-un", "trenta-dos" var conjunction = tens == 2 ? "-i-" : "-"; var num = (units == 1) && gender == GrammaticalGender.Masculine ? "u" : GetUnit(units, gender); return $"{Tens[tens]}{conjunction}{num}"; } private static string GetHundreds(int number, GrammaticalGender gender) { var hundreds = number / 100; var rest = number % 100; var hundredPart = gender == GrammaticalGender.Feminine ? HundredsFeminine[hundreds] : HundredsMasculine[hundreds]; if (rest == 0) { return hundredPart; } var num = rest == 1 && gender == GrammaticalGender.Masculine ? "u" : (rest < 10 ? GetUnit(rest, gender) : GetTens(rest, gender)); return $"{hundredPart} {num}"; } private string GetThousands(int number, GrammaticalGender gender) { var thousands = number / 1000; var rest = number % 1000; string thousandPart; if (thousands == 1) { thousandPart = "mil"; } else { thousandPart = $"{Convert(thousands, gender)} mil"; } if (rest == 0) { return thousandPart; } var num = rest == 1 && gender == GrammaticalGender.Masculine ? "u" : Convert(rest, gender); return $"{thousandPart} {num}"; } private string GetMillions(int number, GrammaticalGender gender) { var millions = number / 1000000; var rest = number % 1000000; string millionPart; if (millions == 1) { millionPart = "un milió"; } else { millionPart = $"{Convert(millions, GrammaticalGender.Masculine)} milions"; } if (rest == 0) { return millionPart; } var num = rest == 1 && gender == GrammaticalGender.Masculine ? "u" : Convert(rest, gender); return $"{millionPart} {num}"; } #endregion #region ConvertToOrdinal public override string ConvertToOrdinal(int number, GrammaticalGender gender) { if (number < 0) { return "menys " + ConvertToOrdinal(-number, gender); } if (number == 0) { return "zero"; } // Ordinales simples string[] masc = ["", "primer", "segon", "tercer", "quart", "cinquè", "sisè", "setè", "vuitè", "novè", "desè", "onzè", "dotzè", "tretzè", "catorzè", "quinzè"]; string[] fem = ["", "primera", "segona", "tercera", "quarta", "cinquena", "sisena", "setena", "vuitena", "novena", "desena", "onzena", "dotzena", "tretzena", "catorzena", "quinzena"]; if (number < masc.Length) { return gender == GrammaticalGender.Feminine ? fem[number] : masc[number]; } if (number < 100) { return GetOrdinalTens(number, gender); } if (number < 1000) { return GetOrdinalHundreds(number, gender); } if (number < 1000000) { return GetOrdinalThousands(number, gender); } if (number < 1000000000) { return GetOrdinalMillions(number, gender); } throw new NotImplementedException("Ordinal més gran de cent milions no implementat."); } // Helpers private static string GetOrdinalTens(int number, GrammaticalGender gender) { var dec = number / 10; var rem = number % 10; string[] tens = ["", "", "vint", "trenta", "quaranta", "cinquanta", "seixanta", "setanta", "vuitanta", "noranta"]; var ordSuf = gender == GrammaticalGender.Feminine ? "ena" : "è"; if (rem == 0) { var tensDec = tens[dec]; if (dec == 3 || dec == 6 || dec == 7 || dec == 8 || dec == 9) { tensDec = tensDec[..^1]; // } return tensDec + ordSuf; } var unitRoots = new[] { "", "un", "dos", "tres", "quatr", "cinqu", "sis", "set", "vuit", "nov" }; var num = $"{unitRoots[rem]}{ordSuf}"; if (rem == 1) { num = gender == GrammaticalGender.Feminine ? "una" : "un"; } var conj = dec == 2 ? "-i-" : "-"; return $"{tens[dec]}{conj}{num}"; } private string GetOrdinalHundreds(int number, GrammaticalGender gender) { var centenas = number / 100; var rest = number % 100; var hundred = gender == GrammaticalGender.Feminine ? new[] { "", "cent", "dues-centes", "tres-centes", "quatre-centes", "cinc-centes", "sis-centes", "set-centes", "vuit-centes", "nou-centes" }[centenas] : new[] { "", "cent", "dos-cents", "tres-cents", "quatre-cents", "cinc-cents", "sis-cents", "set-cents", "vuit-cents", "nou-cents" }[centenas]; if (rest == 0 && centenas == 1) { return $"{hundred}{(gender == GrammaticalGender.Feminine ? "ena" : "è")}"; } if (rest == 0) { return hundred; } string? num; if (centenas == 1 && rest % 10 != 0) { num = ConvertToOrdinal(rest, gender); } else { num = Convert(rest, gender); if (gender == GrammaticalGender.Masculine && rest != 1 && rest % 10 == 1) { num += "n"; } } return $"{hundred} {num}"; } private string GetOrdinalThousands(int number, GrammaticalGender gender) { var mils = number / 1000; var rest = number % 1000; var milStr = mils == 1 ? "mil" : $"{Convert(mils, gender)} mil"; if (rest == 0) { return milStr; } if (rest == 100) { return $"{milStr} cent"; } var num = Convert(rest, gender); if (gender == GrammaticalGender.Masculine && rest != 1 && rest % 10 == 1) { num += "n"; } return $"{milStr} {num}"; } private string GetOrdinalMillions(int number, GrammaticalGender gender) { var mills = number / 1000000; var rest = number % 1000000; var millsStr = mills == 1 ? "un milió" : $"{Convert(mills, GrammaticalGender.Masculine)} milions"; if (rest == 0) { return millsStr; } var num = Convert(rest, gender); if (gender == GrammaticalGender.Masculine && rest != 1 && rest % 10 == 1) { num += "n"; } return $"{millsStr} {num}"; } public override string ConvertToOrdinal(int number, GrammaticalGender gender, WordForm wordForm) { // ordinal (Ej: 1r, 1a, 2n, 2a, 11è, 11a, etc.) if (wordForm == WordForm.Abbreviation) { if (number == 1) { return gender == GrammaticalGender.Feminine ? "1a" : "1r"; } if (number == 2) { return gender == GrammaticalGender.Feminine ? "2a" : "2n"; } if (number == 3) { return gender == GrammaticalGender.Feminine ? "3a" : "3r"; } if (number == 22) { return gender == GrammaticalGender.Feminine ? "22a" : "22n"; } if (number == 31) { return gender == GrammaticalGender.Feminine ? "31a" : "31r"; } if (number == 11 || number == 100 || number == 999) { return number + (gender == GrammaticalGender.Feminine ? "a" : "è"); } if (number == 101) { return gender == GrammaticalGender.Feminine ? "101a" : "101r"; } if (number == 999) { return gender == GrammaticalGender.Feminine ? "999a" : "999è"; } // Comportamiento genérico if (gender == GrammaticalGender.Feminine) { return number + "a"; } return number + ( (number % 10 == 1 || number % 10 == 3) ? "r" : (number % 10 == 2 || number % 10 == 7) ? "n" : "è" ); } return ConvertToOrdinal(number, gender); } #endregion public override string ConvertToTuple(int number) { number = Math.Abs(number); if (number < TupleMap.Length) { return TupleMap[number]; } return Convert(number) + " vegades"; } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/CentralKurdishNumberToWordsConverter.cs ================================================ namespace Humanizer; class CentralKurdishNumberToWordsConverter : GenderlessNumberToWordsConverter { static readonly string[] KurdishHundredsMap = ["سفر", "سەد", "دوو سەد", "سێ سەد", "چوار سەد", "پێنج سەد", "شەش سەد", "حەوت سەد", "هەشت سەد", "نۆ سەد"]; static readonly string[] KurdishTensMap = ["سفر", "دە", "بیست", "سی", "چل", "پەنجا", "شەست", "حەفتا", "هەشتا", "نەوەد"]; static readonly string[] KurdishUnitsMap = ["سفر", "یەک", "دوو", "سێ", "چوار", "پێنج", "شەش", "حەوت", "هەشت", "نۆ", "دە", "یازدە", "دوازدە", "سێزدە", "چواردە", "پازدە", "شازدە", "حەڤدە", "هەژدە", "نۆزدە"]; public override string Convert(long number) { var largestNumber = Math.Pow(10, 15) * 1000 - 1; if (number > largestNumber || number < -largestNumber) { throw new NotImplementedException(); } if (number < 0) { return $"نێگەتیڤ {Convert(-number)}"; } if (number == 0) { return "سفر"; } var kurdishGroupsMap = new Dictionary> { { (long) Math.Pow(10, 15), n => $"{Convert(n)} کوادریلیۆن" }, { (long) Math.Pow(10, 12), n => $"{Convert(n)} تریلیۆن" }, { (long) Math.Pow(10, 9), n => $"{Convert(n)} میلیارد" }, { (long) Math.Pow(10, 6), n => $"{Convert(n)} میلیۆن" }, { (long) Math.Pow(10, 3), n => $"{Convert(n)} هەزار" }, { (long) Math.Pow(10, 2), n => KurdishHundredsMap[n] } }; var parts = new List(); foreach (var group in kurdishGroupsMap.Keys) { if (number / group > 0) { parts.Add(kurdishGroupsMap[group](number / group)); number %= group; } } if (number >= 20) { parts.Add(KurdishTensMap[number / 10]); number %= 10; } if (number > 0) { parts.Add(KurdishUnitsMap[number]); } var sentence = string.Join(" و ", parts); if (sentence.StartsWith("یەک هەزار")) { return sentence[" یەک".Length..]; } return sentence; } public override string ConvertToOrdinal(int number) { var word = Convert(number); return $"{word}{(IsVowel(word[^1]) ? "یەم" : "ەم")}"; } static bool IsVowel(char c) => c is 'ا' or 'ێ' or 'ۆ' or 'ە' or 'ی'; } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/ChineseNumberToWordsConverter.cs ================================================ namespace Humanizer; class ChineseNumberToWordsConverter : GenderlessNumberToWordsConverter { static readonly string[] UnitsMap = ["零", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十"]; public override string Convert(long number) => Convert(number, false, IsSpecial(number)); public override string ConvertToOrdinal(int number) => Convert(number, true, IsSpecial(number)); static bool IsSpecial(long number) => number is > 10 and < 20; static string Convert(long number, bool isOrdinal, bool isSpecial) { if (number == 0) { return UnitsMap[0]; } if (number < 0) { return $"负 {Convert(-number, false, false)}"; } var parts = new List(); if (number / 1000000000000 > 0) { var format = "{0}兆"; if (number % 1000000000000 < 100000000000 && number % 1000000000000 > 0) { format = "{0}兆零"; } parts.Add(string.Format(format, Convert(number / 1000000000000, false, false))); number %= 1000000000000; } if (number / 100000000 > 0) { var format = "{0}亿"; if (number % 100000000 < 10000000 && number % 100000000 > 0) { format = "{0}亿零"; } parts.Add(string.Format(format, Convert(number / 100000000, false, false))); number %= 100000000; } if (number / 10000 > 0) { var format = "{0}万"; if (number % 10000 < 1000 && number % 10000 > 0) { format = "{0}万零"; } parts.Add(string.Format(format, Convert(number / 10000, false, false))); number %= 10000; } if (number / 1000 > 0) { var format = "{0}千"; if (number % 1000 < 100 && number % 1000 > 0) { format = "{0}千零"; } parts.Add(string.Format(format, Convert(number / 1000, false, false))); number %= 1000; } if (number / 100 > 0) { var format = "{0}百"; if (number % 100 < 10 && number % 100 > 0) { format = "{0}百零"; } parts.Add(string.Format(format, Convert(number / 100, false, false))); number %= 100; } if (number > 0) { if (number <= 10) { parts.Add(UnitsMap[number]); } else { var lastPart = $"{UnitsMap[number / 10]}十"; if (number % 10 > 0) { lastPart += $"{UnitsMap[number % 10]}"; } parts.Add(lastPart); } } var toWords = string.Concat(parts); if (isSpecial) { toWords = toWords[1..]; } if (isOrdinal) { toWords = $"第 {toWords}"; } return toWords; } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/CroatianNumberToWordsConverter.cs ================================================ namespace Humanizer; class CroatianNumberToWordsConverter(CultureInfo culture) : GenderlessNumberToWordsConverter { static readonly string[] UnitsMap = [ "nula", "jedan", "dva", "tri", "četiri", "pet", "šest", "sedam", "osam", "devet", "deset", "jedanaest", "dvanaest", "trinaest", "četrnaest", "petnaest", "šesnaest", "sedamnaest", "osamnaest", "devetnaest" ]; static readonly string[] TensMap = [ "nula", "deset", "dvadeset", "trideset", "četrdeset", "pedeset", "šezdeset", "sedamdeset", "osamdeset", "devedeset" ]; public override string Convert(long number) { switch (number) { case 0: return "nula"; case < 0: return number != long.MinValue ? $"minus {Convert(-number)}" : "minus devet trilijuna dvjesto dvadeset tri bilijarde tristo sedamdeset dva bilijuna trideset šest milijardi osamsto pedeset četiri milijuna sedamsto sedamdeset pet tisuća osamsto osam"; } var parts = new List(); var quintillions = number / 1000000000000000000; if (quintillions > 0) { var part = quintillions switch { 1 => "trilijun", _ => $"{Convert(quintillions)} trilijuna" }; parts.Add(part); number %= 1000000000000000000; if (number > 0) { parts.Add(" "); } } var quadrillions = number / 1000000000000000; if (quadrillions > 0) { string part; switch (quadrillions) { case 1: part = "bilijarda"; break; case 2: part = "dvije bilijarde"; break; case 3: case 4: part = $"{Convert(quadrillions)} bilijarde"; break; default: { if (quadrillions % 100 is > 4 and < 21) { part = $"{Convert(quadrillions)} bilijardi"; break; } part = (quadrillions % 10) switch { 1 => $"{Convert(quadrillions - 1)} jedna bilijarda", 2 => $"{Convert(quadrillions - 2)} dvije bilijarde", 3 or 4 => $"{Convert(quadrillions)} bilijarde", _ => $"{Convert(quadrillions)} bilijardi", }; break; } } parts.Add(part); number %= 1000000000000000; if (number > 0) { parts.Add(" "); } } var trillions = number / 1000000000000; if (trillions > 0) { string part; switch (trillions) { case 1: part = "bilijun"; break; default: { if (trillions % 100 == 11 || trillions % 10 != 1) { part = $"{Convert(trillions)} bilijuna"; break; } part = $"{Convert(trillions)} bilijun"; break; } } parts.Add(part); number %= 1000000000000; if (number > 0) { parts.Add(" "); } } var billions = number / 1000000000; if (billions > 0) { string part; switch (billions) { case 1: part = "milijarda"; break; case 2: part = "dvije milijarde"; break; case 3: case 4: part = $"{Convert(billions)} milijarde"; break; default: { if (billions % 100 is > 4 and < 21) { part = $"{Convert(billions)} milijardi"; break; } part = (billions % 10) switch { 1 => $"{Convert(billions - 1)} jedna milijarda", 2 => $"{Convert(billions - 2)} dvije milijarde", 3 or 4 => $"{Convert(billions)} milijarde", _ => $"{Convert(billions)} milijardi", }; break; } } parts.Add(part); number %= 1000000000; if (number > 0) { parts.Add(" "); } } var millions = number / 1000000; if (millions > 0) { string part; switch (millions) { case 1: part = "milijun"; break; default: { if (millions % 100 == 11 || millions % 10 != 1) { part = $"{Convert(millions)} milijuna"; break; } part = $"{Convert(millions)} milijun"; break; } } parts.Add(part); number %= 1000000; if (number > 0) { parts.Add(" "); } } var thousands = number / 1000; if (thousands > 0) { string part; switch (thousands) { case 1: part = "tisuću"; break; case 2: part = "dvije tisuće"; break; case 3: case 4: part = $"{Convert(thousands)} tisuće"; break; default: { if (thousands % 100 is > 4 and < 21) { part = $"{Convert(thousands)} tisuća"; break; } part = (thousands % 10) switch { 1 => $"{Convert(thousands - 1)} jedna tisuća", 2 => $"{Convert(thousands - 2)} dvije tisuće", 3 or 4 => $"{Convert(thousands)} tisuće", _ => $"{Convert(thousands)} tisuća", }; break; } } parts.Add(part); number %= 1000; if (number > 0) { parts.Add(" "); } } var hundreds = number / 100; if (hundreds > 0) { var part = hundreds switch { 1 => "sto", 2 => "dvjesto", _ => $"{Convert(hundreds)}sto" }; parts.Add(part); number %= 100; if (number > 0) { parts.Add(" "); } } switch (number) { case <= 0: return string.Concat(parts); case < 20: parts.Add(UnitsMap[number]); break; default: { parts.Add(TensMap[number / 10]); var units = number % 10; if (units > 0) { parts.Add($" {UnitsMap[units]}"); } break; } } return string.Concat(parts); } public override string ConvertToOrdinal(int number) => //TODO: In progress number.ToString(culture); } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/CzechNumberToWordsConverter.cs ================================================ namespace Humanizer; class CzechNumberToWordsConverter(CultureInfo culture) : GenderedNumberToWordsConverter { static readonly string[] BillionsMap = ["miliarda", "miliardy", "miliard"]; static readonly string[] MillionsMap = ["milion", "miliony", "milionů"]; static readonly string[] ThousandsMap = ["tisíc", "tisíce", "tisíc"]; static readonly string[] HundredsMap = ["nula", "sto", "dvě stě", "tři sta", "čtyři sta", "pět set", "šest set", "sedm set", "osm set", "devět set"]; static readonly string[] TensMap = ["nula", "deset", "dvacet", "třicet", "čtyřicet", "padesát", "šedesát", "sedmdesát", "osmdesát", "devadesát"]; static readonly string[] UnitsMap = ["nula", "jeden", "dva", "tři", "čtyři", "pět", "šest", "sedm", "osm", "devět", "deset", "jedenáct", "dvanáct", "třináct", "čtrnáct", "patnáct", "šestnáct", "sedmnáct", "osmnáct", "devatenáct"]; static readonly string[] UnitsMasculineOverrideMap = ["jeden", "dva"]; static readonly string[] UnitsFeminineOverrideMap = ["jedna", "dvě"]; static readonly string[] UnitsNeuterOverride = ["jedno", "dvě"]; static readonly string[] UnitsIntraOverride = ["jedna", "dva"]; public override string Convert(long number, GrammaticalGender gender, bool addAnd = true) { if (number == 0) { return UnitByGender(number, gender); } var parts = new List(); if (number < 0) { parts.Add("mínus"); number = -number; } CollectThousandAndAbove(parts, ref number, 1_000_000_000, GrammaticalGender.Feminine, BillionsMap); CollectThousandAndAbove(parts, ref number, 1_000_000, GrammaticalGender.Masculine, MillionsMap); CollectThousandAndAbove(parts, ref number, 1_000, GrammaticalGender.Masculine, ThousandsMap); CollectLessThanThousand(parts, number, gender); return string.Join(" ", parts); } public override string ConvertToOrdinal(int number, GrammaticalGender gender) => number.ToString(culture); static string UnitByGender(long number, GrammaticalGender? gender) { if (number != 1 && number != 2) { return UnitsMap[number]; } return gender switch { GrammaticalGender.Masculine => UnitsMasculineOverrideMap[number - 1], GrammaticalGender.Feminine => UnitsFeminineOverrideMap[number - 1], GrammaticalGender.Neuter => UnitsNeuterOverride[number - 1], null => UnitsIntraOverride[number - 1], _ => throw new ArgumentOutOfRangeException(nameof(gender)), }; } static void CollectLessThanThousand(List parts, long number, GrammaticalGender? gender) { if (number >= 100) { parts.Add(HundredsMap[number / 100]); number %= 100; } if (number >= 20) { parts.Add(TensMap[number / 10]); number %= 10; } if (number > 0) { parts.Add(UnitByGender(number, gender)); } } static void CollectThousandAndAbove(List parts, ref long number, long divisor, GrammaticalGender gender, string[] map) { var n = number / divisor; if (n <= 0) { return; } CollectLessThanThousand(parts, n, n < 19 ? gender : null); var units = n % 1000; if (units == 1) { parts.Add(map[0]); } else if (units is > 1 and < 5) { parts.Add(map[1]); } else { parts.Add(map[2]); } number %= divisor; } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/DefaultNumberToWordsConverter.cs ================================================ namespace Humanizer; /// /// Constructor. /// /// Culture to use. class DefaultNumberToWordsConverter(CultureInfo? culture) : GenderlessNumberToWordsConverter { readonly CultureInfo? culture = culture; /// /// 3501.ToWords() -> "three thousand five hundred and one" /// /// Number to be turned to words public override string Convert(long number) => number.ToString(culture); /// /// 1.ToOrdinalWords() -> "first" /// /// Number to be turned to ordinal words public override string ConvertToOrdinal(int number) => number.ToString(culture); } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/DutchNumberToWordsConverter.cs ================================================ namespace Humanizer; /// /// Dutch spelling of numbers is not really officially regulated. /// There are a few different rules that can be applied. /// Used the rules as stated here. /// http://www.beterspellen.nl/website/?pag=110 /// class DutchNumberToWordsConverter : GenderlessNumberToWordsConverter { static readonly string[] UnitsMap = ["nul", "een", "twee", "drie", "vier", "vijf", "zes", "zeven", "acht", "negen", "tien", "elf", "twaalf", "dertien", "veertien", "vijftien", "zestien", "zeventien", "achttien", "negentien"]; static readonly string[] TensMap = ["nul", "tien", "twintig", "dertig", "veertig", "vijftig", "zestig", "zeventig", "tachtig", "negentig"]; class Fact { public long Value { get; set; } public required string Name { get; set; } public required string Prefix { get; set; } public required string Postfix { get; set; } public bool DisplayOneUnit { get; set; } } static readonly Fact[] Hunderds = [ new() { Value = 1_000_000_000_000_000_000L, Name = "triljoen", Prefix = " ", Postfix = " ", DisplayOneUnit = true }, new() { Value = 1_000_000_000_000_000L, Name = "biljard", Prefix = " ", Postfix = " ", DisplayOneUnit = true }, new() { Value = 1_000_000_000_000L, Name = "biljoen", Prefix = " ", Postfix = " ", DisplayOneUnit = true }, new() { Value = 1000000000, Name = "miljard", Prefix = " ", Postfix = " ", DisplayOneUnit = true }, new() { Value = 1000000, Name = "miljoen", Prefix = " ", Postfix = " ", DisplayOneUnit = true }, new() { Value = 1000, Name = "duizend", Prefix = "", Postfix = " ", DisplayOneUnit = false }, new() { Value = 100, Name = "honderd", Prefix = "", Postfix = "", DisplayOneUnit = false } ]; public override string Convert(long input) { var number = input; if (number == 0) { return UnitsMap[0]; } if (number < 0) { return $"min {Convert(-number)}"; } var word = ""; foreach (var m in Hunderds) { var divided = number / m.Value; if (divided <= 0) { continue; } if (divided == 1 && !m.DisplayOneUnit) { word += m.Name; } else { word += Convert(divided) + m.Prefix + m.Name; } number %= m.Value; if (number > 0) { word += m.Postfix; } } if (number > 0) { if (number < 20) { word += UnitsMap[number]; } else { var tens = TensMap[number / 10]; var unit = number % 10; if (unit > 0) { var units = UnitsMap[unit]; var trema = units.EndsWith('e'); word += units + (trema ? "ën" : "en") + tens; } else { word += tens; } } } return word; } static readonly Dictionary OrdinalExceptions = new() { { "een", "eerste" }, { "drie", "derde" }, { "miljoen", "miljoenste" }, }; #if NET8_0_OR_GREATER static readonly SearchValues EndingCharForSte = SearchValues.Create(['t', 'g', 'd']); #else static readonly char[] EndingCharForSte = ['t', 'g', 'd']; #endif public override string ConvertToOrdinal(int number) { var word = Convert(number); foreach (var kv in OrdinalExceptions.Where(kv => word.EndsWith(kv.Key))) { // replace word with exception return StringHumanizeExtensions.Concat(word.AsSpan(0, word.Length - kv.Key.Length), kv.Value.AsSpan()); } // achtste // twintigste, dertigste, veertigste, ... // honderdste, duizendste, ... #if NET8_0_OR_GREATER if (word.AsSpan().LastIndexOfAny(EndingCharForSte) == word.Length - 1) #else if (word.LastIndexOfAny(EndingCharForSte) == word.Length - 1) #endif { return word + "ste"; } return word + "de"; } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/EnglishNumberToWordsConverter.cs ================================================ namespace Humanizer; class EnglishNumberToWordsConverter : GenderlessNumberToWordsConverter { static readonly string[] UnitsMap = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"]; static readonly string[] UnitsMapTh = ["zeroth", "first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth", "tenth", "eleventh", "twelfth", "thirteenth", "fourteenth", "fifteenth", "sixteenth", "seventeenth", "eighteenth", "nineteenth"]; static readonly string[] TensMap = ["zero", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"]; public override string Convert(long number) => Convert(number, false); public override string Convert(long number, bool addAnd = true) => Convert(number, false, addAnd); public override string ConvertToOrdinal(int number) => Convert(number, true); string Convert(long number, bool isOrdinal, bool addAnd = true) { if (number == 0) { return GetUnitValue(0, isOrdinal); } if (number < 0) { return $"minus {Convert(-number)}"; } var parts = new List(20); CollectParts(parts, ref number, isOrdinal, 1_000_000_000_000_000_000, "quintillion", "quintillionth"); CollectParts(parts, ref number, isOrdinal, 1_000_000_000_000_000, "quadrillion", "quadrillionth"); CollectParts(parts, ref number, isOrdinal, 1_000_000_000_000, "trillion", "trillionth"); CollectParts(parts, ref number, isOrdinal, 1_000_000_000, "billion", "billionth"); CollectParts(parts, ref number, isOrdinal, 1_000_000, "million", "millionth"); CollectParts(parts, ref number, isOrdinal, 1_000, "thousand", "thousandth"); CollectPartsUnderAThousand(parts, number, isOrdinal, addAnd); if (isOrdinal && parts[0] == "one") { // one hundred => hundredth parts.RemoveAt(0); } return string.Join(" ", parts); } static void CollectParts(List parts, ref long number, bool isOrdinal, long divisor, string word, string ordinal) { var result = number / divisor; if (result == 0) { return; } CollectPartsUnderAThousand(parts, result); number %= divisor; parts.Add(number == 0 && isOrdinal ? ordinal : word); } static void CollectPartsUnderAThousand(List parts, long number, bool isOrdinal = false, bool addAnd = true) { if (number >= 100) { parts.Add(GetUnitValue(number / 100, false)); number %= 100; parts.Add(number == 0 && isOrdinal ? "hundredth" : "hundred"); } if (number == 0) { return; } if (parts.Count > 0 && addAnd) { parts.Add("and"); } if (number >= 20) { var tens = TensMap[number / 10]; var units = number % 10; if (units == 0) { parts.Add(isOrdinal ? $"{tens.TrimEnd('y')}ieth" : tens); } else { parts.Add($"{tens}-{GetUnitValue(units, isOrdinal)}"); } } else { parts.Add(GetUnitValue(number, isOrdinal)); } } static string GetUnitValue(long number, bool isOrdinal) => isOrdinal ? UnitsMapTh[number] : UnitsMap[number]; public override string ConvertToTuple(int number) => number switch { 1 => "single", 2 => "double", 3 => "triple", 4 => "quadruple", 5 => "quintuple", 6 => "sextuple", 7 => "septuple", 8 => "octuple", 9 => "nonuple", 10 => "decuple", 100 => "centuple", 1000 => "milluple", _ => $"{number}-tuple" }; } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/FarsiNumberToWordsConverter.cs ================================================ namespace Humanizer; class FarsiNumberToWordsConverter : GenderlessNumberToWordsConverter { static readonly string[] FarsiHundredsMap = ["صفر", "صد", "دویست", "سیصد", "چهارصد", "پانصد", "ششصد", "هفتصد", "هشتصد", "نهصد"]; static readonly string[] FarsiTensMap = ["صفر", "ده", "بیست", "سی", "چهل", "پنجاه", "شصت", "هفتاد", "هشتاد", "نود"]; static readonly string[] FarsiUnitsMap = ["صفر", "یک", "دو", "سه", "چهار", "پنج", "شش", "هفت", "هشت", "نه", "ده", "یازده", "دوازده", "سیزده", "چهارده", "پانزده", "شانزده", "هفده", "هجده", "نوزده"]; public override string Convert(long number) { if (number < 0) { return $"منفی {Convert(-number)}"; } if (number == 0) { return "صفر"; } var farsiGroupsMap = new Dictionary> { { (long) Math.Pow(10, 18), n => $"{Convert(n)} تریلیون" }, { (long) Math.Pow(10, 15), n => $"{Convert(n)} بیلیارد" }, { (long) Math.Pow(10, 12), n => $"{Convert(n)} بیلیون" }, { (long) Math.Pow(10, 9), n => $"{Convert(n)} میلیارد" }, { (long) Math.Pow(10, 6), n => $"{Convert(n)} میلیون" }, { (long) Math.Pow(10, 3), n => $"{Convert(n)} هزار" }, { (long) Math.Pow(10, 2), n => FarsiHundredsMap[n] } }; var parts = new List(); foreach (var group in farsiGroupsMap.Keys) { if (number / group > 0) { parts.Add(farsiGroupsMap[group](number / group)); number %= group; } } if (number >= 20) { parts.Add(FarsiTensMap[number / 10]); number %= 10; } if (number > 0) { parts.Add(FarsiUnitsMap[number]); } return string.Join(" و ", parts); } public override string ConvertToOrdinal(int number) { if (number == 1) { return "اول"; } if (number == 3) { return "سوم"; } if (number % 10 == 3 && number != 13) { return Convert(number / 10 * 10) + " و سوم"; } var word = Convert(number); return $"{word}{(word.EndsWith('ی') ? " ام" : "م")}"; } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/FinnishNumberToWordsConverter.cs ================================================ namespace Humanizer; class FinnishNumberToWordsConverter : GenderlessNumberToWordsConverter { static readonly string[] UnitsMap = ["nolla", "yksi", "kaksi", "kolme", "neljä", "viisi", "kuusi", "seitsemän", "kahdeksan", "yhdeksän", "kymmenen"]; static readonly string[] OrdinalUnitsMap = ["nollas", "ensimmäinen", "toinen", "kolmas", "neljäs", "viides", "kuudes", "seitsemäs", "kahdeksas", "yhdeksäs", "kymmenes"]; static readonly FrozenDictionary OrdinalExceptions = new Dictionary { {1, "yhdes" }, {2, "kahdes" } }.ToFrozenDictionary(); public override string Convert(long input) { if (input is > int.MaxValue or < int.MinValue) { throw new NotImplementedException(); } var number = (int)input; if (number < 0) { return $"miinus {Convert(-number)}"; } if (number == 0) { return UnitsMap[0]; } var parts = new List(); if (number / 1000000000 > 0) { parts.Add(number / 1000000000 == 1 ? "miljardi " : $"{Convert(number / 1000000000)}miljardia "); number %= 1000000000; } if (number / 1000000 > 0) { parts.Add(number / 1000000 == 1 ? "miljoona " : $"{Convert(number / 1000000)}miljoonaa "); number %= 1000000; } if (number / 1000 > 0) { parts.Add(number / 1000 == 1 ? "tuhat " : $"{Convert(number / 1000)}tuhatta "); number %= 1000; } if (number / 100 > 0) { parts.Add(number / 100 == 1 ? "sata" : $"{Convert(number / 100)}sataa"); number %= 100; } if (number >= 20) { parts.Add($"{Convert(number / 10)}kymmentä"); number %= 10; } else if (number is > 10 and < 20) { parts.Add($"{UnitsMap[number % 10]}toista"); } if (number is > 0 and <= 10) { parts.Add(UnitsMap[number]); } return string.Concat(parts).Trim(); } static string GetOrdinalUnit(int number, bool useExceptions) { if (useExceptions && OrdinalExceptions.TryGetValue(number, out var unit)) { return unit; } return OrdinalUnitsMap[number]; } static string ToOrdinal(int number, bool useExceptions) { if (number == 0) { return OrdinalUnitsMap[0]; } var parts = new List(); if (number / 1000000000 > 0) { parts.Add($"{(number / 1000000000 == 1 ? "" : ToOrdinal(number / 1000000000, true))}miljardis"); number %= 1000000000; } if (number / 1000000 > 0) { parts.Add($"{(number / 1000000 == 1 ? "" : ToOrdinal(number / 1000000, true))}miljoonas"); number %= 1000000; } if (number / 1000 > 0) { parts.Add($"{(number / 1000 == 1 ? "" : ToOrdinal(number / 1000, true))}tuhannes"); number %= 1000; } if (number / 100 > 0) { parts.Add($"{(number / 100 == 1 ? "" : ToOrdinal(number / 100, true))}sadas"); number %= 100; } if (number >= 20) { parts.Add($"{ToOrdinal(number / 10, true)}kymmenes"); number %= 10; } else if (number is > 10 and < 20) { parts.Add($"{GetOrdinalUnit(number % 10, true)}toista"); } if (number is > 0 and <= 10) { parts.Add(GetOrdinalUnit(number, useExceptions)); } return string.Concat(parts); } public override string ConvertToOrdinal(int number) => ToOrdinal(number, false); } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/FrenchBelgianNumberToWordsConverter.cs ================================================ namespace Humanizer; class FrenchBelgianNumberToWordsConverter : FrenchNumberToWordsConverterBase { protected override void CollectPartsUnderAHundred(List parts, ref long number, GrammaticalGender gender, bool pluralize) { if (number == 80) { parts.Add(pluralize ? "quatre-vingts" : "quatre-vingt"); } else if (number == 81) { parts.Add(gender == GrammaticalGender.Feminine ? "quatre-vingt-une" : "quatre-vingt-un"); } else { base.CollectPartsUnderAHundred(parts, ref number, gender, pluralize); } } protected override string GetTens(long tens) { if (tens == 8) { return "quatre-vingt"; } return base.GetTens(tens); } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/FrenchNumberToWordsConverter.cs ================================================ namespace Humanizer; class FrenchNumberToWordsConverter : FrenchNumberToWordsConverterBase { protected override void CollectPartsUnderAHundred(List parts, ref long number, GrammaticalGender gender, bool pluralize) { if (number == 71) { parts.Add("soixante et onze"); } else if (number == 80) { parts.Add(pluralize ? "quatre-vingts" : "quatre-vingt"); } else if (number >= 70) { var @base = number < 80 ? 60 : 80; var units = number - @base; var tens = @base / 10; parts.Add($"{GetTens(tens)}-{GetUnits(units, gender)}"); } else { base.CollectPartsUnderAHundred(parts, ref number, gender, pluralize); } } protected override string GetTens(long tens) { if (tens == 8) { return "quatre-vingt"; } return base.GetTens(tens); } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/FrenchNumberToWordsConverterBase.cs ================================================ namespace Humanizer; abstract class FrenchNumberToWordsConverterBase : GenderedNumberToWordsConverter { static readonly string[] UnitsMap = ["zéro", "un", "deux", "trois", "quatre", "cinq", "six", "sept", "huit", "neuf", "dix", "onze", "douze", "treize", "quatorze", "quinze", "seize", "dix-sept", "dix-huit", "dix-neuf"]; static readonly string[] TensMap = ["zéro", "dix", "vingt", "trente", "quarante", "cinquante", "soixante", "septante", "octante", "nonante"]; public override string Convert(long number, GrammaticalGender gender, bool addAnd = true) { if (number == 0) { return UnitsMap[0]; } var parts = new List(); if (number < 0) { parts.Add("moins"); number = -number; } CollectParts(parts, ref number, 1000000000000000000, "trillion"); CollectParts(parts, ref number, 1000000000000000, "billiard"); CollectParts(parts, ref number, 1000000000000, "billion"); CollectParts(parts, ref number, 1000000000, "milliard"); CollectParts(parts, ref number, 1000000, "million"); CollectThousands(parts, ref number, 1000, "mille"); CollectPartsUnderAThousand(parts, number, gender, true); return string.Join(" ", parts); } public override string ConvertToOrdinal(int number, GrammaticalGender gender) { if (number == 1) { return gender == GrammaticalGender.Feminine ? "première" : "premier"; } var convertedNumber = Convert(number); if (convertedNumber.EndsWith('s') && !convertedNumber.EndsWith("trois")) { convertedNumber = convertedNumber.TrimEnd('s'); } else if (convertedNumber.EndsWith("cinq")) { convertedNumber += "u"; } else if (convertedNumber.EndsWith("neuf")) { convertedNumber = convertedNumber.TrimEnd('f') + "v"; } if (convertedNumber.StartsWith("un ")) { convertedNumber = convertedNumber[3..]; } if (number == 0) { convertedNumber += "t"; } convertedNumber = convertedNumber.TrimEnd('e'); convertedNumber += "ième"; return convertedNumber; } protected static string GetUnits(long number, GrammaticalGender gender) { if (number == 1 && gender == GrammaticalGender.Feminine) { return "une"; } return UnitsMap[number]; } static void CollectHundreds(List parts, ref long number, long d, string form, bool pluralize) { if (number < d) { return; } var result = number / d; if (result == 1) { parts.Add(form); } else { parts.Add(GetUnits(result, GrammaticalGender.Masculine)); if (number % d == 0 && pluralize) { parts.Add(form + "s"); } else { parts.Add(form); } } number %= d; } void CollectParts(List parts, ref long number, long d, string form) { if (number < d) { return; } var result = number / d; CollectPartsUnderAThousand(parts, result, GrammaticalGender.Masculine, true); if (result == 1) { parts.Add(form); } else { parts.Add(form + "s"); } number %= d; } void CollectPartsUnderAThousand(List parts, long number, GrammaticalGender gender, bool pluralize) { CollectHundreds(parts, ref number, 100, "cent", pluralize); if (number > 0) { CollectPartsUnderAHundred(parts, ref number, gender, pluralize); } } void CollectThousands(List parts, ref long number, int d, string form) { if (number < d) { return; } var result = number / d; if (result > 1) { CollectPartsUnderAThousand(parts, result, GrammaticalGender.Masculine, false); } parts.Add(form); number %= d; } protected virtual void CollectPartsUnderAHundred(List parts, ref long number, GrammaticalGender gender, bool pluralize) { if (number < 20) { parts.Add(GetUnits(number, gender)); } else { var units = number % 10; var tens = GetTens(number / 10); if (units == 0) { parts.Add(tens); } else if (units == 1) { parts.Add(tens); parts.Add("et"); parts.Add(GetUnits(1, gender)); } else { parts.Add($"{tens}-{GetUnits(units, gender)}"); } } } protected virtual string GetTens(long tens) => TensMap[tens]; } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/FrenchSwissNumberToWordsConverter.cs ================================================ namespace Humanizer; class FrenchSwissNumberToWordsConverter : FrenchNumberToWordsConverterBase; ================================================ FILE: src/Humanizer/Localisation/NumberToWords/GenderedNumberToWordsConverter.cs ================================================ namespace Humanizer; abstract class GenderedNumberToWordsConverter(GrammaticalGender defaultGender = GrammaticalGender.Masculine) : INumberToWordsConverter { readonly GrammaticalGender defaultGender = defaultGender; /// public string Convert(long number) => Convert(number, defaultGender); /// public string Convert(long number, WordForm wordForm) => Convert(number, wordForm, defaultGender); /// public string Convert(long number, bool addAnd) => Convert(number, defaultGender); /// public string Convert(long number, bool addAnd, WordForm wordForm) => Convert(number, wordForm, defaultGender, addAnd); /// public abstract string Convert(long number, GrammaticalGender gender, bool addAnd = true); /// public virtual string Convert(long number, WordForm wordForm, GrammaticalGender gender, bool addAnd = true) => Convert(number, gender, addAnd); /// public string ConvertToOrdinal(int number) => ConvertToOrdinal(number, defaultGender); /// public abstract string ConvertToOrdinal(int number, GrammaticalGender gender); /// public string ConvertToOrdinal(int number, WordForm wordForm) => ConvertToOrdinal(number, defaultGender, wordForm); /// public virtual string ConvertToOrdinal(int number, GrammaticalGender gender, WordForm wordForm) => ConvertToOrdinal(number, gender); /// public virtual string ConvertToTuple(int number) => Convert(number); } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/GenderlessNumberToWordsConverter.cs ================================================ namespace Humanizer; abstract class GenderlessNumberToWordsConverter : INumberToWordsConverter { /// public abstract string Convert(long number); public string Convert(long number, WordForm wordForm) => Convert(number); public virtual string Convert(long number, bool addAnd) => Convert(number); public string Convert(long number, bool addAnd, WordForm wordForm) => Convert(number, wordForm); public virtual string Convert(long number, GrammaticalGender gender, bool addAnd = true) => Convert(number); public virtual string Convert(long number, WordForm wordForm, GrammaticalGender gender, bool addAnd = true) => Convert(number, addAnd, wordForm); public abstract string ConvertToOrdinal(int number); public string ConvertToOrdinal(int number, GrammaticalGender gender) => ConvertToOrdinal(number); public virtual string ConvertToOrdinal(int number, WordForm wordForm) => ConvertToOrdinal(number); public virtual string ConvertToOrdinal(int number, GrammaticalGender gender, WordForm wordForm) => ConvertToOrdinal(number, wordForm); public virtual string ConvertToTuple(int number) => Convert(number); } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/GermanNumberToWordsConverter.cs ================================================ namespace Humanizer; class GermanNumberToWordsConverter : GermanNumberToWordsConverterBase; ================================================ FILE: src/Humanizer/Localisation/NumberToWords/GermanNumberToWordsConverterBase.cs ================================================ namespace Humanizer; abstract class GermanNumberToWordsConverterBase : GenderedNumberToWordsConverter { 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"]; static readonly string[] TensMap = ["null", "zehn", "zwanzig", "dreißig", "vierzig", "fünfzig", "sechzig", "siebzig", "achtzig", "neunzig"]; 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"]; static readonly string[] HundredOrdinalSingular = ["einhundert"]; static readonly string[] HundredOrdinalPlural = ["{0}hundert"]; static readonly string[] ThousandOrdinalSingular = ["eintausend"]; static readonly string[] ThousandOrdinalPlural = ["{0}tausend"]; static readonly string[] MillionOrdinalSingular = ["einmillion", "einemillion"]; static readonly string[] MillionOrdinalPlural = ["{0}million", "{0}millionen"]; static readonly string[] BillionOrdinalSingular = ["einmilliard", "einemilliarde"]; static readonly string[] BillionOrdinalPlural = ["{0}milliard", "{0}milliarden"]; public override string Convert(long number, GrammaticalGender gender, bool addAnd = true) { 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 if (number == 1) { parts.Add($"{UnitsMap[number]}s"); } else { parts.Add(UnitsMap[number]); } } else { var units = number % 10; if (units > 0) { parts.Add($"{UnitsMap[units]}und"); } parts.Add(GetTens(number / 10)); } } return string.Concat(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 is 0 or >= 20) { parts.Add("s"); } parts.Add(GetEndingForGender(gender)); return string.Concat(parts); } void CollectParts(List 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(" "); } } } void CollectOrdinalParts(List 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; } } string Part(string pluralFormat, string singular, long number) { if (number == 1) { return singular; } return string.Format(pluralFormat, Convert(number)); } static int NoRestIndex(int number) => number == 0 ? 0 : 1; static string GetEndingForGender(GrammaticalGender gender) => gender switch { GrammaticalGender.Masculine => "ter", GrammaticalGender.Feminine => "te", GrammaticalGender.Neuter => "tes", _ => throw new ArgumentOutOfRangeException(nameof(gender)) }; protected virtual string GetTens(long tens) => TensMap[tens]; } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/GermanSwissLiechtensteinNumberToWordsConverter.cs ================================================ namespace Humanizer; class GermanSwissLiechtensteinNumberToWordsConverter : GermanNumberToWordsConverterBase { protected override string GetTens(long tens) { if (tens == 3) { return "dreissig"; } return base.GetTens(tens); } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/GreekNumberToWordsConverter.cs ================================================ namespace Humanizer; class GreekNumberToWordsConverter : GenderlessNumberToWordsConverter { static readonly string[] UnitMap = ["μηδέν", "ένα", "δύο", "τρία", "τέσσερα", "πέντε", "έξι", "επτά", "οκτώ", "εννέα", "δέκα", "έντεκα", "δώδεκα"]; static readonly string[] UnitsMap = ["μηδέν", "ένα", "δύο", "τρείς", "τέσσερις", "πέντε", "έξι", "επτά", "οκτώ", "εννέα", "δέκα", "έντεκα", "δώδεκα"]; static readonly string[] TensMap = ["", "δέκα", "είκοσι", "τριάντα", "σαράντα", "πενήντα", "εξήντα", "εβδομήντα", "ογδόντα", "ενενήντα"]; static readonly string[] TensNoDiacriticsMap = ["", "δεκα", "εικοσι", "τριαντα", "σαραντα", "πενηντα", "εξηντα", "εβδομηντα", "ογδοντα", "ενενηντα"]; static readonly string[] HundredMap = ["", "εκατό", "διακόσια", "τριακόσια", "τετρακόσια", "πεντακόσια", "εξακόσια", "επτακόσια", "οκτακόσια", "εννιακόσια"]; static readonly string[] HundredsMap = ["", "εκατόν", "διακόσιες", "τριακόσιες", "τετρακόσιες", "πεντακόσιες", "εξακόσιες", "επτακόσιες", "οκτακόσιες", "εννιακόσιες"]; static readonly FrozenDictionary ΟrdinalMap = new Dictionary { { 0, string.Empty }, { 1, "πρώτος" }, { 2, "δεύτερος" }, { 3, "τρίτος" }, { 4, "τέταρτος" }, { 5, "πέμπτος" }, { 6, "έκτος" }, { 7, "έβδομος" }, { 8, "όγδοος" }, { 9, "ένατος" }, { 10, "δέκατος" }, { 20, "εικοστός" }, { 30, "τριακοστός" }, { 40, "τεσσαρακοστός" }, { 50, "πεντηκοστός" }, { 60, "εξηκοστός" }, { 70, "εβδομηκοστός" }, { 80, "ογδοηκοστός" }, { 90, "ενενηκοστός" }, { 100, "εκατοστός" }, { 200, "διακοσιοστός" }, { 300, "τριακοσιοστός" }, { 400, "τετρακοσιστός" }, { 500, "πεντακοσιοστός" }, { 600, "εξακοσιοστός" }, { 700, "εφτακοσιοστός" }, { 800, "οχτακοσιοστός" }, { 900, "εννιακοσιοστός" }, { 1000, "χιλιοστός" } }.ToFrozenDictionary(); public override string Convert(long number) => ConvertImpl(number, false); public override string ConvertToOrdinal(int number) { if (number / 10 == 0) { return GetOneDigitOrdinal(number); } if (number / 10 > 0 && number / 10 < 10) { return GetTwoDigitOrdinal(number); } if (number / 100 > 0 && number / 100 < 10) { return GetThreeDigitOrdinal(number); } if (number / 1000 > 0 && number / 1000 < 10) { return GetFourDigitOrdinal(number); } return string.Empty; } static string GetOneDigitOrdinal(int number) { if (ΟrdinalMap.TryGetValue(number, out var output)) { return output; } return string.Empty; } static string GetTwoDigitOrdinal(int number) { if (number == 11) { return "ενδέκατος"; } if (number == 12) { return "δωδέκατος"; } var decades = number / 10; if (!ΟrdinalMap.TryGetValue(decades * 10, out var decadesString)) { return string.Empty; } if (number - decades * 10 > 0) { return decadesString + " " + GetOneDigitOrdinal(number - decades * 10); } return decadesString; } static string GetThreeDigitOrdinal(int number) { var hundreds = number / 100; if (!ΟrdinalMap.TryGetValue(hundreds * 100, out var hundredsString)) { return string.Empty; } if (number - hundreds * 100 > 10) { return hundredsString + " " + GetTwoDigitOrdinal(number - hundreds * 100); } if (number - hundreds * 100 > 0) { return hundredsString + " " + GetOneDigitOrdinal(number - hundreds * 100); } return hundredsString; } static string GetFourDigitOrdinal(int number) { var thousands = number / 1000; if (!ΟrdinalMap.TryGetValue(thousands * 1000, out var thousandsString)) { return string.Empty; } if (number - thousands * 1000 > 100) { return thousandsString + " " + GetThreeDigitOrdinal(number - thousands * 1000); } if (number - thousands * 1000 > 10) { return thousandsString + " " + GetTwoDigitOrdinal(number - thousands * 1000); } if (number - thousands * 1000 > 0) { return thousandsString + " " + GetOneDigitOrdinal(number - thousands * 1000); } return thousandsString; } string ConvertImpl(long number, bool returnPluralized) { if (number < 13) { return ConvertIntB13(number, returnPluralized); } if (number < 100) { return ConvertIntBH(number, returnPluralized); } if (number < 1000) { return ConvertIntBT(number, returnPluralized); } if (number < 1000000) { return ConvertIntBM(number); } if (number < 1000000000) { return ConvertIntBB(number); } if (number < 1000000000000) { return ConvertIntBTR(number); } return ""; } static string ConvertIntB13(long number, bool returnPluralized) => returnPluralized ? UnitsMap[number] : UnitMap[number]; string ConvertIntBH(long number, bool returnPluralized) { var result = number / 10 == 1 ? TensNoDiacriticsMap[number / 10] : TensMap[number / 10]; if (number % 10 != 0) { if (number / 10 != 1) { result += " "; } result += ConvertImpl(number % 10, returnPluralized) .ToLower(); } return result; } string ConvertIntBT(long number, bool returnPluralized) { string result; if (number / 100 == 1) { if (number % 100 == 0) { return HundredMap[number / 100]; } result = HundredsMap[number / 100]; } else { result = returnPluralized ? HundredsMap[number / 100] : HundredMap[number / 100]; } if (number % 100 != 0) { result += $" {ConvertImpl(number % 100, returnPluralized).ToLower()}"; } return result; } string ConvertIntBM(long number) { if (number / 1000 == 1) { if (number % 1000 == 0) { return "χίλια"; } return $"χίλια {ConvertImpl(number % 1000, false).ToLower()}"; } var result = $"{ConvertImpl(number / 1000, true)} χιλιάδες"; if (number % 1000 != 0) { result += $" {ConvertImpl(number % 1000, false).ToLower()}"; } return result; } string ConvertIntBB(long number) { if (number / 1000000 == 1) { if (number % 1000000 == 0) { return "ένα εκατομμύριο"; } return $"ένα εκατομμύριο {ConvertImpl(number % 1000000, true).ToLower()}"; } var result = $"{ConvertImpl(number / 1000000, false)} εκατομμύρια"; if (number % 1000000 != 0) { result += $" {ConvertImpl(number % 1000000, false).ToLower()}"; } return result; } string ConvertIntBTR(long number) { if (number / 1000000000 == 1) { if (number % 1000000000 == 0) { return "ένα δισεκατομμύριο"; } return $"ένα δισεκατομμύριο {ConvertImpl(number % 1000000000, true).ToLower()}"; } var result = $"{ConvertImpl(number / 1000000000, false)} δισεκατομμύρια"; if (number % 1000000000 != 0) { result += $" {ConvertImpl(number % 1000000000, false).ToLower()}"; } return result; } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/HebrewNumberToWordsConverter.cs ================================================ namespace Humanizer; class HebrewNumberToWordsConverter(CultureInfo culture) : GenderedNumberToWordsConverter(GrammaticalGender.Feminine) { static readonly string[] UnitsFeminine = ["אפס", "אחת", "שתיים", "שלוש", "ארבע", "חמש", "שש", "שבע", "שמונה", "תשע", "עשר"]; static readonly string[] UnitsMasculine = ["אפס", "אחד", "שניים", "שלושה", "ארבעה", "חמישה", "שישה", "שבעה", "שמונה", "תשעה", "עשרה"]; static readonly string[] TensUnit = ["עשר", "עשרים", "שלושים", "ארבעים", "חמישים", "שישים", "שבעים", "שמונים", "תשעים"]; [AttributeUsage(AttributeTargets.Field)] class DescriptionAttribute(string description) : Attribute { public string Description { get; set; } = description; } enum Group { Hundreds = 100, Thousands = 1000, [Description("מיליון")] Millions = 1000000, [Description("מיליארד")] Billions = 1000000000 } public override string Convert(long input, GrammaticalGender gender, bool addAnd = true) { if (input is > int.MaxValue or < int.MinValue) { throw new NotImplementedException(); } var number = (int)input; if (number < 0) { return $"מינוס {Convert(-number, gender)}"; } if (number == 0) { return UnitsFeminine[0]; } var parts = new List(); if (number >= (int)Group.Billions) { ToBigNumber(number, Group.Billions, parts); number %= (int)Group.Billions; } if (number >= (int)Group.Millions) { ToBigNumber(number, Group.Millions, parts); number %= (int)Group.Millions; } if (number >= (int)Group.Thousands) { ToThousands(number, parts); number %= (int)Group.Thousands; } if (number >= (int)Group.Hundreds) { ToHundreds(number, parts); number %= (int)Group.Hundreds; } if (number > 0) { var appendAnd = parts.Count != 0; if (number <= 10) { var unit = gender == GrammaticalGender.Masculine ? UnitsMasculine[number] : UnitsFeminine[number]; if (appendAnd) { unit = "ו" + unit; } parts.Add(unit); } else if (number < 20) { var unit = Convert(number % 10, gender); unit = unit.Replace("יי", "י"); unit = $"{unit} {(gender == GrammaticalGender.Masculine ? "עשר" : "עשרה")}"; if (appendAnd) { unit = "ו" + unit; } parts.Add(unit); } else { var tenUnit = TensUnit[number / 10 - 1]; if (number % 10 == 0) { parts.Add(tenUnit); } else { var unit = Convert(number % 10, gender); parts.Add($"{tenUnit} ו{unit}"); } } } return string.Join(" ", parts); } public override string ConvertToOrdinal(int number, GrammaticalGender gender) => number.ToString(culture); void ToBigNumber(int number, Group group, List parts) { // Big numbers (million and above) always use the masculine form // See https://www.safa-ivrit.org/dikduk/numbers.php var digits = number / (int)group; if (digits == 2) { parts.Add("שני"); } else if (digits > 2) { parts.Add(Convert(digits, GrammaticalGender.Masculine)); } parts.Add(group.Humanize()); } void ToThousands(int number, List parts) { var thousands = number / (int)Group.Thousands; if (thousands == 1) { parts.Add("אלף"); } else if (thousands == 2) { parts.Add("אלפיים"); } else if (thousands == 8) { parts.Add("שמונת אלפים"); } else if (thousands <= 10) { parts.Add(UnitsFeminine[thousands] + "ת" + " אלפים"); } else { parts.Add(Convert(thousands) + " אלף"); } } static void ToHundreds(int number, List parts) { // For hundreds, Hebrew is using the feminine form // See https://www.safa-ivrit.org/dikduk/numbers.php var hundreds = number / (int)Group.Hundreds; if (hundreds == 1) { parts.Add("מאה"); } else if (hundreds == 2) { parts.Add("מאתיים"); } else { parts.Add(UnitsFeminine[hundreds] + " מאות"); } } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/HungarianNumberToWordsConverter.cs ================================================ namespace Humanizer; class HungarianNumberToWordsConverter : GenderlessNumberToWordsConverter { // Units private static readonly string[] UnitsMap = ["", "egy", "kettő", "három", "négy", "öt", "hat", "hét", "nyolc", "kilenc"]; private static readonly string[] OrdinalUnitsMap = ["", "első", "második", "harmadik", "negyedik", "ötödik", "hatodik", "hetedik", "nyolcadik", "kilencedik"]; // Tens private static readonly string[] TensMap = ["", "tizen", "huszon", "harminc", "negyven", "ötven", "hatvan", "hetven", "nyolcvan", "kilencven"]; private static readonly string[] OrdinalTensMap = ["", "tizedik", "huszadik", "harmincadik", "negyvenedik", "ötvenedik", "hatvanadik", "hetvenedik", "nyolcvanadik", "kilencvenedik"]; // Hundreds private static readonly string[] HundredsMap = ["", "száz", "kétszáz", "háromszáz", "négyszáz", "ötszáz", "hatszáz", "hétszáz", "nyolcszáz", "kilencszáz"]; // Exceptional single numbers when used as ordinal numbers and the whole number is greater than 10 private static readonly Dictionary OrdinalUnitsExceptions = new() { { 1, "egyedik" }, { 2, "kettedik" } }; // Exceptional ten numbers when the number divided by 10 gives no remainder private static readonly Dictionary WholeTensExceptions = new() { { 10, "tíz" }, { 20, "húsz" } }; public override string Convert(long number) => ConvertInternal(number, false); public override string ConvertToOrdinal(int number) => ConvertInternal(number, true); private static string ConvertInternal(long number, bool isOrdinal) { // Handle zero and negative numbers switch (number) { case 0: return isOrdinal ? "nulladik" : "nulla"; case < 0: return $"mínusz {ConvertInternal(-number, isOrdinal)}"; } var isLessThanTen = number < 10; var parts = new List(10); CollectParts(parts, ref number, isOrdinal, isLessThanTen, 1_000_000_000_000_000_000, "trillió", "trilliomodik"); CollectParts(parts, ref number, isOrdinal, isLessThanTen, 1_000_000_000_000_000, "billiárd", "billiárdodik"); CollectParts(parts, ref number, isOrdinal, isLessThanTen, 1_000_000_000_000, "billió", "billiomodik"); CollectParts(parts, ref number, isOrdinal, isLessThanTen, 1_000_000_000, "milliárd", "milliárdodik"); CollectParts(parts, ref number, isOrdinal, isLessThanTen, 1_000_000, "millió", "milliomodik"); // All numbers above 2000 should be separated by dashes per thousands if (2_000 <= number) { CollectParts(parts, ref number, isOrdinal, isLessThanTen, 1_000, "ezer", "ezredik"); var underAThousandPart = GetUnderAThousandPart(number, isOrdinal, false, isLessThanTen); if (underAThousandPart != string.Empty) { parts.Add(underAThousandPart); } } else { // In hungarian there is no separator between one thousand and the rest of the numbers var lastPart = 1_000 <= number ? GetOneThousandPart(ref number, isOrdinal) : ""; lastPart += GetUnderAThousandPart(number, isOrdinal, false, isLessThanTen); if (lastPart != string.Empty) { parts.Add(lastPart); } } return string.Join("-", parts); } // Thousands part for numbers between 1000 and 1999 static string GetOneThousandPart(ref long number, bool isOrdinal) { const int divisor = 1_000; var oneThousandPart = isOrdinal && number == divisor ? "ezredik" : "ezer"; number %= divisor; return oneThousandPart; } private static void CollectParts(List parts, ref long number, bool isOrdinal, bool isLessThanTen, long divisor, string word, string ordinal) { var result = number / divisor; if (result == 0) { return; } var prefixNumber = GetUnderAThousandPart(result, isOrdinal, true, isLessThanTen); number %= divisor; parts.Add(number == 0 && isOrdinal ? prefixNumber + ordinal : prefixNumber + word); } private static string GetUnderAThousandPart(long number, bool isOrdinal, bool isPrefix, bool originalLessThanTen) { var numberString = ""; if (100 <= number) { // Return hundred + "adik" if the number is exactly one of hundreds e.g.: századik, hétszázadik if (isOrdinal && number % 100 == 0) { return HundredsMap[number / 100] + "adik"; } numberString += HundredsMap[number / 100]; number %= 100; } if (10 <= number) { // Return an ordinal ten if the number is exactly one of tens if (isOrdinal && number % 10 == 0) { return numberString + OrdinalTensMap[number / 10]; } numberString += WholeTensExceptions.TryGetValue(number, out var value) ? value : TensMap[number / 10]; number %= 10; } if (isOrdinal && !isPrefix) { numberString += GetOrdinalOnes(number, originalLessThanTen); } else { numberString += isPrefix && number == 2 ? "két" : UnitsMap[number]; } return numberString; } private static string GetOrdinalOnes(long number, bool lessThanTen) { if (lessThanTen) { return OrdinalUnitsMap[number]; } return OrdinalUnitsExceptions.TryGetValue(number, out var value) ? value : OrdinalUnitsMap[number]; } public override string ConvertToTuple(int number) => number switch { 1 => "szimpla", 2 => "dupla", 3 => "tripla", 4 => "kvadrupla", 5 => "pentapla", 6 => "hexapla", 7 => "heptapla", 8 => "octapla", 9 => "nonapla", 10 => "dekapla", 100 => "hektapla", 1000 => "kiliapla", _ => $"{number}" }; } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/INumberToWordsConverter.cs ================================================ namespace Humanizer; /// /// An interface you should implement to localise ToWords and ToOrdinalWords methods /// public interface INumberToWordsConverter { /// /// Converts the number to string using the locale's default grammatical gender /// string Convert(long number); /// /// Converts the number to a specific string form using the locale's default grammatical gender. /// string Convert(long number, WordForm wordForm); /// /// Converts the number to string using the locale's default grammatical gender with or without adding 'And' /// /// Specify with our without adding "And" string Convert(long number, bool addAnd); /// /// Converts the number to a specific string form using the locale's default grammatical gender with or without adding 'And' /// string Convert(long number, bool addAnd, WordForm wordForm); /// /// Converts the number to string using the provided grammatical gender /// string Convert(long number, GrammaticalGender gender, bool addAnd = true); /// /// Converts the number to a specific string form using the provided grammatical gender. /// string Convert(long number, WordForm wordForm, GrammaticalGender gender, bool addAnd = true); /// /// Converts the number to ordinal string using the locale's default grammatical gender /// string ConvertToOrdinal(int number); /// /// Converts the number to a specific ordinal string form using the locale's default grammatical gender. /// string ConvertToOrdinal(int number, WordForm wordForm); /// /// Converts the number to ordinal string using the provided grammatical gender /// string ConvertToOrdinal(int number, GrammaticalGender gender); /// /// Converts the number to a specific ordinal string form using the provided grammatical gender. /// string ConvertToOrdinal(int number, GrammaticalGender gender, WordForm wordForm); /// /// Converts integer to named tuple (e.g. 'single', 'double' etc.). /// string ConvertToTuple(int number); } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/IcelandicNumberToWordsConverter.cs ================================================ namespace Humanizer; class IcelandicNumberToWordsConverter : GenderedNumberToWordsConverter { static readonly string[] UnitsMap = ["núll", string.Empty, string.Empty, string.Empty, string.Empty, "fimm", "sex", "sjö", "átta", "níu", "tíu", "ellefu", "tólf", "þrettán", "fjórtán", "fimmtán", "sextán", "sautján", "átján", "nítján"]; static readonly string[] FeminineUnitsMap = [string.Empty, "ein", "tvær", "þrjár", "fjórar"]; static readonly string[] MasculineUnitsMap = [string.Empty, "einn", "tveir", "þrír", "fjórir"]; static readonly string[] NeuterUnitsMap = [string.Empty, "eitt", "tvö", "þrjú", "fjögur"]; static readonly string[] TensMap = [string.Empty, "tíu", "tuttugu", "þrjátíu", "fjörutíu", "fimmtíu", "sextíu", "sjötíu", "áttatíu", "níutíu"]; static readonly string[] UnitsOrdinalPrefixes = ["núllt", "fyrst", string.Empty, "þriðj", "fjórð", "fimmt", "sjött", "sjöund", "áttund", "níund", "tíund", "elleft", "tólft", "þrettánd", "fjórtánd", "fimmtánd", "sextánd", "sautjánd", "átjánd", "nítjánd"]; static readonly string[] TensOrdinalPrefixes = [string.Empty, "tíund", "tuttugast", "þrítugast", "fertugast", "fimmtugast", "sextugast", "sjötugast", "áttugast", "nítugast"]; const string AndSplit = "og"; class Fact { public long Power { get; set; } public GrammaticalGender Gender { get; set; } public required string Plural { get; set; } public required string Single { get; set; } public required string OrdinalPrefix { get; set; } } static readonly Dictionary PowerOfTenMap = new() { { 0, new() { Power = 0, Single = string.Empty, Plural = string.Empty, OrdinalPrefix = string.Empty, Gender = GrammaticalGender.Neuter } }, { 2, new() { Power = 2, Single = "hundrað", Plural = "hundruð", OrdinalPrefix = "hundruðast", Gender = GrammaticalGender.Neuter } }, { 3, new() { Power = 1000, Single = "eitt þúsund", Plural = "þúsund", OrdinalPrefix = "þúsundast", Gender = GrammaticalGender.Neuter } }, { 6, new() { Power = 1000000, Single = "ein milljón", Plural = "milljónir", OrdinalPrefix = "milljónast", Gender = GrammaticalGender.Feminine } }, { 9, new() { Power = 1000000000, Single = "einn milljarður", Plural = "milljarðar", OrdinalPrefix = "milljarðast", Gender = GrammaticalGender.Masculine } }, { 12, new() { Power = 1000000000000, Single = "ein billjón", Plural = "billjónir", OrdinalPrefix = "billjónast", Gender = GrammaticalGender.Feminine } }, { 15, new() { Power = 1000000000000000, Single = "einn billjarður", Plural = "billjarðar", OrdinalPrefix = "billjarðast", Gender = GrammaticalGender.Masculine } }, { 18, new() { Power = 1000000000000000000, Single = "ein trilljón", Plural = "trilljónir", OrdinalPrefix = "trilljónast", Gender = GrammaticalGender.Feminine } } }; static bool IsAndSplitNeeded(int number) => number <= 20 || number % 10 == 0 && number < 100 || number % 100 == 0; static string GetOrdinalEnding(GrammaticalGender gender) => gender == GrammaticalGender.Masculine ? "i" : "a"; static void GetUnits(List builder, long number, GrammaticalGender gender) { if (number is > 0 and < 5) { var genderedForm = gender switch { GrammaticalGender.Masculine => MasculineUnitsMap[number], GrammaticalGender.Neuter => NeuterUnitsMap[number], GrammaticalGender.Feminine => FeminineUnitsMap[number], _ => throw new ArgumentOutOfRangeException(nameof(gender)) }; builder.Add(genderedForm); } else { builder.Add(UnitsMap[number]); } } static void CollectOrdinalParts(List builder, int threeDigitPart, Fact conversionRule, GrammaticalGender partGender, GrammaticalGender ordinalGender) { var hundreds = threeDigitPart / 100; var hundredRemainder = threeDigitPart % 100; var units = hundredRemainder % 10; var decade = hundredRemainder / 10 * 10; var hasThousand = conversionRule.Power > 100; if (hundreds != 0) { GetUnits(builder, hundreds, GrammaticalGender.Neuter); var hundredPrefix = hundreds == 1 ? PowerOfTenMap[2].Single : PowerOfTenMap[2].Plural; if (hundredRemainder < 20 && false == hasThousand) { var genderedFormWithPostfix = partGender switch { GrammaticalGender.Masculine => hundredPrefix + "asti", GrammaticalGender.Neuter => hundredPrefix + "asta", GrammaticalGender.Feminine => hundredPrefix + "asta", _ => throw new ArgumentOutOfRangeException(nameof(partGender)) }; builder.Add(genderedFormWithPostfix); } else { builder.Add(hundredPrefix); } } if (decade >= 20) { if (units != 0) { builder.Add(CollectOrdinalPartsUnderAHundred(decade, partGender)); builder.Add(AndSplit); builder.Add(CollectOrdinalPartsUnderAHundred(units, partGender)); } else { if (hundreds != 0) { builder.Add(AndSplit); } builder.Add(CollectOrdinalPartsUnderAHundred(decade, partGender)); } } else if (hundredRemainder != 0) { if (hundreds != 0) { builder.Add(AndSplit); } if (hasThousand) { GetUnits(builder, hundredRemainder, conversionRule.Gender); } else { builder.Add(CollectOrdinalPartsUnderAHundred(hundredRemainder, partGender)); } } if (hasThousand) { builder.Add(conversionRule.OrdinalPrefix + GetOrdinalEnding(ordinalGender)); } } static string? CollectOrdinalPartsUnderAHundred(int number, GrammaticalGender gender) { if (number is >= 0 and < 20) { if (number == 2) { return gender switch { GrammaticalGender.Masculine => "annar", GrammaticalGender.Feminine => "önnur", GrammaticalGender.Neuter => "annað", _ => throw new ArgumentOutOfRangeException(nameof(gender)) }; } return UnitsOrdinalPrefixes[number] + GetOrdinalEnding(gender); } if (number < 100 && number % 10 == 0) { return TensOrdinalPrefixes[number / 10] + GetOrdinalEnding(gender); } return null; } static void CollectParts(List parts, ref long number, ref bool needsAnd, Fact rule) { var remainder = number / rule.Power; if (remainder > 0) { number %= rule.Power; var prevLen = parts.Count; CollectPart(parts, remainder, rule); if (number == 0 && needsAnd && false == parts .Skip(prevLen) .Contains(AndSplit)) { parts.Insert(prevLen, AndSplit); } needsAnd = true; } } static void CollectPart(List parts, long number, Fact rule) { if (number == 1) { parts.Add(rule.Single); } else { CollectPartUnderOneThousand(parts, number, rule.Gender); parts.Add(rule.Plural); } } static void CollectPartUnderOneThousand(List builder, long number, GrammaticalGender gender) { var hundreds = number / 100; var hundredRemainder = number % 100; var units = hundredRemainder % 10; var tens = hundredRemainder / 10; if (hundreds != 0) { GetUnits(builder, hundreds, GrammaticalGender.Neuter); builder.Add(hundreds == 1 ? PowerOfTenMap[2].Single : PowerOfTenMap[2].Plural); } if (tens >= 2) { if (units != 0) { builder.Add(TensMap[tens]); builder.Add(AndSplit); GetUnits(builder, units, gender); } else { if (hundreds != 0) { builder.Add(AndSplit); } builder.Add(TensMap[tens]); } } else if (hundredRemainder != 0) { if (hundreds != 0) { builder.Add(AndSplit); } GetUnits(builder, hundredRemainder, gender); } } static void CollectOrdinal(List parts, ref int number, ref bool needsAnd, Fact rule, GrammaticalGender gender) { var remainder = number / rule.Power; if (remainder > 0) { number %= (int)rule.Power; // https://malfar.arnastofnun.is/grein/65658 if (number > 0 && (number > 19 || (number % 100 > 10 && number % 100 % 10 == 0))) { if (remainder == 1) { parts.Add(rule.Single); } else { CollectPartUnderOneThousand(parts, remainder, rule.Gender); if (rule.Power > 0) { parts.Add(rule.Plural); } } } else { var prevLen = parts.Count; CollectOrdinalParts(parts, (int)remainder, rule, rule.Gender, gender); if (number == 0 && needsAnd && false == parts .Skip(prevLen) .Contains(AndSplit)) { parts.Insert(prevLen, AndSplit); } } needsAnd = true; } } public override string Convert(long number, GrammaticalGender gender, bool addAnd = true) { if (number == 0) { return UnitsMap[number]; } var parts = new List(); if (number < 0) { parts.Add("mínus"); number = -number; } var needsAnd = false; CollectParts(parts, ref number, ref needsAnd, PowerOfTenMap[18]); CollectParts(parts, ref number, ref needsAnd, PowerOfTenMap[15]); CollectParts(parts, ref number, ref needsAnd, PowerOfTenMap[12]); CollectParts(parts, ref number, ref needsAnd, PowerOfTenMap[9]); CollectParts(parts, ref number, ref needsAnd, PowerOfTenMap[6]); CollectParts(parts, ref number, ref needsAnd, PowerOfTenMap[3]); if (number > 0) { if (needsAnd && IsAndSplitNeeded((int)number)) { parts.Add(AndSplit); } CollectPartUnderOneThousand(parts, number, gender); } return string.Join(" ", parts); } public override string ConvertToOrdinal(int number, GrammaticalGender gender) { if (number == 0) { return UnitsOrdinalPrefixes[number] + GetOrdinalEnding(gender); } var parts = new List(); var needsAnd = false; CollectOrdinal(parts, ref number, ref needsAnd, PowerOfTenMap[12], gender); CollectOrdinal(parts, ref number, ref needsAnd, PowerOfTenMap[9], gender); CollectOrdinal(parts, ref number, ref needsAnd, PowerOfTenMap[6], gender); CollectOrdinal(parts, ref number, ref needsAnd, PowerOfTenMap[3], gender); if (number > 0) { if (needsAnd && IsAndSplitNeeded(number)) { parts.Add(AndSplit); } CollectOrdinalParts(parts, number, PowerOfTenMap[0], gender, gender); } return string.Join(" ", parts); } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/IndianNumberToWordsConverter.cs ================================================ namespace Humanizer; class IndianNumberToWordsConverter : GenderlessNumberToWordsConverter { static readonly string[] Tillnineteen = [ "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" ]; static readonly string[] Tens = [ "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" ]; public override string Convert(long number) => NumberToText(number) .Trim(); public override string ConvertToOrdinal(int number) { var result = NumberToText(number) .Trim(); return result; } static string NumberToText(long number) { if (number < 0) { return "(Negative) " + NumberToText(-number); } if (number == 0) { return ""; } if (number <= 19) { return Tillnineteen[number - 1] + " "; } if (number <= 99) { return Tens[number / 10 - 2] + " " + NumberToText(number % 10); } if (number <= 199) { return ("one hundred " + (number % 100 > 0 ? "and " : "") + NumberToText(number % 100)).Trim(); } if (number <= 999) { return NumberToText(number / 100) + "hundred " + (number % 100 > 0 ? "and " : "") + NumberToText(number % 100); } if (number <= 1999) { return "one thousand " + NumberToText(number % 1000); } if (number <= 99999) { return NumberToText(number / 1000) + "thousand " + NumberToText(number % 1000); } if (number <= 199999) { return ("one lakh " + NumberToText(number % 100000)).Trim(); } if (number <= 9999999) { return NumberToText(number / 100000) + "lakh " + NumberToText(number % 100000); } if (number <= 19999999) { return "one crore " + NumberToText(number % 10000000); } return NumberToText(number / 10000000) .Trim() + " crore " + NumberToText(number % 10000000); } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/Italian/ItalianCardinalNumberCruncher.cs ================================================ namespace Humanizer; class ItalianCardinalNumberCruncher(int number, GrammaticalGender gender) { public string Convert() { // it's easier to treat zero as a completely distinct case if (fullNumber == 0) { return "zero"; } var words = string.Empty; foreach (var part in threeDigitParts) { var partToString = GetNextPartConverter(); if (partToString != null) { words = partToString(part) + words; } } // remove trailing spaces if there are only millions or billions return words.TrimEnd(); } readonly int fullNumber = number; readonly List threeDigitParts = SplitEveryThreeDigits(number); readonly GrammaticalGender gender = gender; protected ThreeDigitSets _nextSet = ThreeDigitSets.Units; /// /// Splits a number into a sequence of three-digits numbers, starting /// from units, then thousands, millions, and so on. /// /// The number to split. /// The sequence of three-digit numbers. static List SplitEveryThreeDigits(int number) { var parts = new List(); var rest = number; while (rest > 0) { var threeDigit = rest % 1000; parts.Add(threeDigit); rest /= 1000; } return parts; } /// /// During number conversion to text, finds out the converter to use /// for the next three-digit set. /// /// The next conversion function to use. Func? GetNextPartConverter() { Func? converter; switch (_nextSet) { case ThreeDigitSets.Units: converter = UnitsConverter; _nextSet = ThreeDigitSets.Thousands; break; case ThreeDigitSets.Thousands: converter = ThousandsConverter; _nextSet = ThreeDigitSets.Millions; break; case ThreeDigitSets.Millions: converter = MillionsConverter; _nextSet = ThreeDigitSets.Billions; break; case ThreeDigitSets.Billions: converter = BillionsConverter; _nextSet = ThreeDigitSets.More; break; case ThreeDigitSets.More: converter = null; break; default: throw new ArgumentOutOfRangeException("Unknow ThreeDigitSet: " + _nextSet); } return converter; } /// /// Converts a three-digit set to text. /// /// The three-digit set to convert. /// True if the current three-digit set is the last in the word. /// The same three-digit set expressed as text. static string ThreeDigitSetConverter(int number, bool thisIsLastSet = false) { if (number == 0) { return string.Empty; } // grab lowest two digits var tensAndUnits = number % 100; // grab third digit var hundreds = number / 100; // grab also first and second digits separately var units = tensAndUnits % 10; var tens = tensAndUnits / 10; var words = string.Empty; // append text for hundreds words += HundredNumberToText[hundreds]; // append text for tens, only those from twenty upward words += TensOver20NumberToText[tens]; if (tensAndUnits <= 9) { // simple case for units, under 10 words += UnitsNumberToText[tensAndUnits]; } else if (tensAndUnits <= 19) { // special case for 'teens', from 10 to 19 words += TeensUnder20NumberToText[tensAndUnits - 10]; } else { // just append units text, with some corner cases // truncate tens last vowel before 'uno' (1) and 'otto' (8) if (units is 1 or 8) { words = words[..^1]; } // if this is the last set, an accent could be due var unitsText = thisIsLastSet && units == 3 ? "tré" : UnitsNumberToText[units]; words += unitsText; } return words; } /// /// Converts a three-digit number, as units, to text. /// /// The three-digit number, as units, to convert. /// The same three-digit number, as units, expressed as text. string UnitsConverter(int number) { // being a unique case, it's easier to treat unity feminine gender as a completely distinct case if (gender == GrammaticalGender.Feminine && fullNumber == 1) { return "una"; } return ThreeDigitSetConverter(number, true); } /// /// Converts a thousands three-digit number to text. /// /// The three-digit number, as thousands, to convert. /// The same three-digit number of thousands expressed as text. static string ThousandsConverter(int number) { if (number == 0) { return string.Empty; } if (number == 1) { return "mille"; } return ThreeDigitSetConverter(number) + "mila"; } /// /// Converts a millions three-digit number to text. /// /// The three-digit number, as millions, to convert. /// The same three-digit number of millions expressed as text. static string MillionsConverter(int number) { if (number == 0) { return string.Empty; } if (number == 1) { return "un milione "; } return ThreeDigitSetConverter(number, true) + " milioni "; } /// /// Converts a billions three-digit number to text. /// /// The three-digit number, as billions, to convert. /// The same three-digit number of billions expressed as text. static string BillionsConverter(int number) { if (number == 1) { return "un miliardo "; } return ThreeDigitSetConverter(number) + " miliardi "; } /// /// Lookup table converting units number to text. Index 1 for 1, index 2 for 2, up to index 9. /// static readonly string[] UnitsNumberToText = [ string.Empty, "uno", "due", "tre", "quattro", "cinque", "sei", "sette", "otto", "nove" ]; /// /// Lookup table converting tens number to text. Index 2 for 20, index 3 for 30, up to index 9 for 90. /// static readonly string[] TensOver20NumberToText = [ string.Empty, string.Empty, "venti", "trenta", "quaranta", "cinquanta", "sessanta", "settanta", "ottanta", "novanta" ]; /// /// Lookup table converting teens number to text. Index 0 for 10, index 1 for 11, up to index 9 for 19. /// static readonly string[] TeensUnder20NumberToText = [ "dieci", "undici", "dodici", "tredici", "quattordici", "quindici", "sedici", "diciassette", "diciotto", "diciannove" ]; /// /// Lookup table converting hundreds number to text. Index 0 for no hundreds, index 1 for 100, up to index 9. /// static readonly string[] HundredNumberToText = [ string.Empty, "cento", "duecento", "trecento", "quattrocento", "cinquecento", "seicento", "settecento", "ottocento", "novecento" ]; /// /// Enumerates sets of three-digits having distinct conversion to text. /// protected enum ThreeDigitSets { /// /// Lowest three-digits set, from 1 to 999. /// Units, /// /// Three-digits set counting the thousands, from 1'000 to 999'000. /// Thousands, /// /// Three-digits set counting millions, from 1'000'000 to 999'000'000. /// Millions, /// /// Three-digits set counting billions, from 1'000'000'000 to 999'000'000'000. /// Billions, /// /// Three-digits set beyond 999 billions, from 1'000'000'000'000 onward. /// More } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/Italian/ItalianOrdinalNumberCruncher.cs ================================================ namespace Humanizer; class ItalianOrdinalNumberCruncher(int number, GrammaticalGender gender) { public string Convert() { // it's easier to treat zero as a completely distinct case if (fullNumber == 0) { return "zero"; } if (fullNumber <= 9) { // units ordinals, 1 to 9, are totally different than the rest: treat them as a distinct case return UnitsUnder10NumberToText[fullNumber] + genderSuffix; } var cardinalCruncher = new ItalianCardinalNumberCruncher(fullNumber, gender); var words = cardinalCruncher.Convert(); var tensAndUnits = fullNumber % 100; if (tensAndUnits == 10) { // for numbers ending in 10, cardinal and ordinal endings are different, suffix doesn't work words = words[..^LengthOf10AsCardinal] + "decim" + genderSuffix; } else { // truncate last vowel words = words[..^1]; var units = fullNumber % 10; // reintroduce *unaccented* last vowel in some corner cases if (units == 3) { words += 'e'; } else if (units == 6) { words += 'i'; } var lowestThreeDigits = fullNumber % 1000; var lowestSixDigits = fullNumber % 1000000; var lowestNineDigits = fullNumber % 1000000000; if (lowestNineDigits == 0) { // if exact billions, cardinal number words are joined words = words.Replace(" miliard", "miliard"); // if 1 billion, numeral prefix is removed completely if (fullNumber == 1000000000) { words = words.Replace("un", string.Empty); } } else if (lowestSixDigits == 0) { // if exact millions, cardinal number words are joined words = words.Replace(" milion", "milion"); // if 1 million, numeral prefix is removed completely if (fullNumber == 1000000) { words = words.Replace("un", string.Empty); } } else if (lowestThreeDigits == 0 && fullNumber > 1000) { // if exact thousands, double the final 'l', apart from 1000 already having that words += 'l'; } // append common ordinal suffix words += "esim" + genderSuffix; } return words; } readonly int fullNumber = number; readonly GrammaticalGender gender = gender; readonly string genderSuffix = gender == GrammaticalGender.Feminine ? "a" : "o"; /// /// Lookup table converting units number to text. Index 1 for 1, index 2 for 2, up to index 9. /// static readonly string[] UnitsUnder10NumberToText = [ string.Empty, "prim", "second", "terz", "quart", "quint", "sest", "settim", "ottav", "non" ]; static readonly int LengthOf10AsCardinal = "dieci".Length; } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/ItalianNumberToWordsConverter.cs ================================================ namespace Humanizer; class ItalianNumberToWordsConverter : GenderedNumberToWordsConverter { public override string Convert(long input, GrammaticalGender gender, bool addAnd = true) { if (input is > int.MaxValue or < int.MinValue) { throw new NotImplementedException(); } var number = (int)input; if (number < 0) { return "meno " + Convert(Math.Abs(number), gender); } var cruncher = new ItalianCardinalNumberCruncher(number, gender); return cruncher.Convert(); } public override string ConvertToOrdinal(int number, GrammaticalGender gender) { var cruncher = new ItalianOrdinalNumberCruncher(number, gender); return cruncher.Convert(); } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/JapaneseNumberToWordsConverter.cs ================================================ namespace Humanizer; class JapaneseNumberToWordsConverter : GenderlessNumberToWordsConverter { static readonly string[] UnitsMap1 = ["", "", "二", "三", "四", "五", "六", "七", "八", "九"]; static readonly string[] UnitsMap2 = ["", "十", "百", "千"]; static readonly string[] UnitsMap3 = [ "", "万", "億", "兆", "京", "垓", "𥝱", "穣", "溝", "澗", "正", "載", "極", "恒河沙", "阿僧祇", "那由他", "不可思議", "無量大数" ]; public override string Convert(long number) => ConvertImpl(number, false); public override string ConvertToOrdinal(int number) => ConvertImpl(number, true); static string ConvertImpl(long number, bool isOrdinal) { if (number == 0) { return isOrdinal ? "〇番目" : "〇"; } if (number < 0) { return $"マイナス {ConvertImpl(-number, false)}"; } var parts = new List(); var groupLevel = 0; while (number > 0) { var groupNumber = number % 10000; number /= 10000; var n0 = groupNumber % 10; var n1 = (groupNumber % 100 - groupNumber % 10) / 10; var n2 = (groupNumber % 1000 - groupNumber % 100) / 100; var n3 = (groupNumber - groupNumber % 1000) / 1000; parts.Add( UnitsMap1[n3] + (n3 == 0 ? "" : UnitsMap2[3]) + UnitsMap1[n2] + (n2 == 0 ? "" : UnitsMap2[2]) + UnitsMap1[n1] + (n1 == 0 ? "" : UnitsMap2[1]) + (n0 == 1 ? "一" : UnitsMap1[n0]) + (groupNumber == 0 ? "" : UnitsMap3[groupLevel]) ); groupLevel++; } parts.Reverse(); var toWords = string.Concat(parts); if (isOrdinal) { toWords = $"{toWords}番目"; } return toWords; } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/KoreanNumberToWordsConverter.cs ================================================ namespace Humanizer; class KoreanNumberToWordsConverter : GenderlessNumberToWordsConverter { static readonly string[] UnitsMap1 = ["", "", "이", "삼", "사", "오", "육", "칠", "팔", "구"]; static readonly string[] UnitsMap2 = ["", "십", "백", "천"]; static readonly string[] UnitsMap3 = ["", "만", "억", "조", "경", "해", "자", "양", "구", "간", "정", "재", "극", "항하사", "아승기", "나유타", "불가사의", "무량대수"]; static readonly FrozenDictionary OrdinalExceptions = new Dictionary { { 0, "영번째" }, { 1, "첫번째" }, { 2, "두번째" }, { 3, "세번째" }, { 4, "네번째" }, { 5, "다섯번째" }, { 6, "여섯번째" }, { 7, "일곱번째" }, { 8, "여덟번째" }, { 9, "아홉번째" }, { 10, "열번째" }, { 11, "열한번째" }, { 12, "열두번째" }, { 13, "열세번째" }, { 14, "열네번째" }, { 15, "열다섯번째" }, { 16, "열여섯번째" }, { 17, "열일곱번째" }, { 18, "열여덟번째" }, { 19, "열아홉째" }, }.ToFrozenDictionary(); public override string Convert(long number) => ConvertImpl(number, false); public override string ConvertToOrdinal(int number) => ConvertImpl(number, true); static string ConvertImpl(long number, bool isOrdinal) { if (isOrdinal && number < 20) { if (OrdinalExceptions.TryGetValue(number, out var words)) { return words; } } if (number == 0) { return "영"; } if (number < 0) { return $"마이너스 {ConvertImpl(-number, false)}"; } var parts = new List(); var groupLevel = 0; while (number > 0) { var groupNumber = number % 10000; number /= 10000; var n0 = groupNumber % 10; var n1 = (groupNumber % 100 - groupNumber % 10) / 10; var n2 = (groupNumber % 1000 - groupNumber % 100) / 100; var n3 = (groupNumber - groupNumber % 1000) / 1000; parts.Add( UnitsMap1[n3] + (n3 == 0 ? "" : UnitsMap2[3]) + UnitsMap1[n2] + (n2 == 0 ? "" : UnitsMap2[2]) + UnitsMap1[n1] + (n1 == 0 ? "" : UnitsMap2[1]) + (n0 == 1 ? "일" : UnitsMap1[n0]) + (groupNumber == 0 ? "" : UnitsMap3[groupLevel]) ); groupLevel++; } parts.Reverse(); var toWords = string.Concat(parts); if (isOrdinal) { toWords = $"{toWords}번째"; } return toWords; } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/LatvianNumberToWordsConverter.cs ================================================ namespace Humanizer; class LatvianNumberToWordsConverter : GenderedNumberToWordsConverter { static readonly string[] UnitsMap = ["nulle", "vien", "div", "trīs", "četr", "piec", "seš", "septiņ", "astoņ", "deviņ", "desmit", "vienpadsmit", "divpadsmit", "trīspadsmit", "četrpadsmit", "piecpadsmit", "sešpadsmit", "septiņpadsmit", "astoņpadsmit", "deviņpadsmit"]; static readonly string[] TensMap = ["nulle", "desmit", "divdesmit", "trīsdesmit", "četrdesmit", "piecdesmit", "sešdesmit", "septiņdesmit", "astoņdesmit", "deviņdesmit"]; static readonly string[] HundredsMap = ["nulle", "simt", "divsimt", "trīssimt", "četrsimt", "piecsimt", "sešsimt", "septiņsimt", "astoņsimt", "deviņsimt"]; static readonly string[] UnitsOrdinal = [string.Empty, "pirm", "otr", "treš", "ceturt", "piekt", "sest", "septīt", "astot", "devīt", "desmit", "vienpadsmit", "divpadsmit", "trīspadsmit", "četrpadsmit", "piecpadsmit", "sešpadsmit", "septiņpadsmit", "astoņpadsmit", "deviņpadsmit", "divdesmit"]; public override string Convert(long input, GrammaticalGender gender, bool addAnd = true) { if (input is > int.MaxValue or < int.MinValue) { throw new NotImplementedException(); } var parts = new List(); if (input / 1000000 > 0) { string millionPart; if (input == 1000000) { millionPart = "miljons"; } else { millionPart = Convert(input / 1000000, GrammaticalGender.Masculine) + " miljoni"; } input %= 1000000; parts.Add(millionPart); } if (input / 1000 > 0) { string thousandsPart; if (input == 1000) { thousandsPart = "tūkstotis"; } else if (input is > 1000 and < 2000) { thousandsPart = "tūkstoš"; } else { thousandsPart = Convert(input / 1000, GrammaticalGender.Masculine) + " tūkstoši"; } parts.Add(thousandsPart); input %= 1000; } if (input / 100 > 0) { string hundredsPart; if (input == 100) { hundredsPart = parts.Contains("tūkstoš") ? "viens simts" : "simts"; } else if (input is > 100 and < 200) { hundredsPart = "simtu"; } else { hundredsPart = Convert(input / 100, GrammaticalGender.Masculine) + " simti"; } parts.Add(hundredsPart); input %= 100; } if (input > 19) { var tensPart = TensMap[input / 10]; parts.Add(tensPart); input %= 10; } if (input > 0) { parts.Add(UnitsMap[input] + GetCardinalEndingForGender(gender, input)); } return string.Join(" ", parts); } public override string ConvertToOrdinal(int input, GrammaticalGender gender) { if (input == 0) { return "nulle"; } var parts = new List(); if (input < 0) { parts.Add("mīnus"); input = -input; } if (input / 1000000 > 0) { string millionPart; if (input == 1000000) { millionPart = "miljon" + GetOrdinalEndingForGender(gender); } else { millionPart = Convert(input / 1000000, GrammaticalGender.Masculine) + " miljon" + GetOrdinalEndingForGender(gender); } input %= 1000000; parts.Add(millionPart); } if (input / 1000 > 0) { string thousandsPart; if (input % 1000 == 0) { if (input == 1000) { thousandsPart = "tūkstoš" + GetOrdinalEndingForGender(gender); } else { thousandsPart = Convert(input / 1000, GrammaticalGender.Masculine) + " tūkstoš" + GetOrdinalEndingForGender(gender); } } else { if (input is > 1000 and < 2000) { thousandsPart = "tūkstoš"; } else { thousandsPart = Convert(input / 1000, GrammaticalGender.Masculine) + " tūkstoši"; } } parts.Add(thousandsPart); input %= 1000; } if (input / 100 > 0) { string hundredsPart; if (input % 100 == 0) { hundredsPart = HundredsMap[input / 100] + GetOrdinalEndingForGender(gender); } else { if (input is > 100 and < 200) { hundredsPart = "simtu"; } else { hundredsPart = Convert(input / 100, GrammaticalGender.Masculine) + " simti"; } } parts.Add(hundredsPart); input %= 100; } if (input > 19) { var tensPart = TensMap[input / 10]; if (input % 10 == 0) { tensPart += GetOrdinalEndingForGender(gender); } parts.Add(tensPart); input %= 10; } if (input > 0) { parts.Add(UnitsOrdinal[input] + GetOrdinalEndingForGender(gender)); } return string.Join(" ", parts); } static string GetOrdinalEndingForGender(GrammaticalGender gender) => gender switch { GrammaticalGender.Masculine => "ais", GrammaticalGender.Feminine => "ā", _ => throw new ArgumentOutOfRangeException(nameof(gender)) }; static string GetCardinalEndingForGender(GrammaticalGender gender, long number) { switch (gender) { case GrammaticalGender.Masculine: if (number == 1) { return "s"; } if (number != 3 && number < 10) { return "i"; } return ""; case GrammaticalGender.Feminine: if (number == 1) { return "a"; } if (number != 3 && number < 10) { return "as"; } return ""; default: throw new ArgumentOutOfRangeException(nameof(gender)); } } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/LithuanianNumberToWordsConverter.cs ================================================ namespace Humanizer; class LithuanianNumberToWordsConverter : GenderedNumberToWordsConverter { static readonly string[] UnitsMap = ["nulis", "vienas", "du", "trys", "keturi", "penki", "šeši", "septyni", "aštuoni", "devyni", "dešimt", "vienuolika", "dvylika", "trylika", "keturiolika", "penkiolika", "šešiolika", "septyniolika", "aštuoniolika", "devyniolika"]; static readonly string[] TensMap = [string.Empty, "dešimt", "dvidešimt", "trisdešimt", "keturiasdešimt", "penkiasdešimt", "šešiasdešimt", "septyniasdešimt", "aštuoniasdešimt", "devyniasdešimt"]; static readonly string[] HundredsMap = [string.Empty, "šimtas", "du šimtai", "trys šimtai", "keturi šimtai", "penki šimtai", "šeši šimtai", "septyni šimtai", "aštuoni šimtai", "devyni šimtai"]; static readonly string[] OrdinalUnitsMap = [string.Empty, "pirm", "antr", "treči", "ketvirt", "penkt", "šešt", "septint", "aštunt", "devint", "dešimt", "vienuolikt", "dvylikt", "trylikt", "keturiolikt", "penkiolikt", "šešiolikt", "septyniolikt", "aštuoniolikt", "devyniolikt", "dvidešimt"]; static readonly string[] OrdinalTensMap = [string.Empty, "dešimt", "dvidešimt", "trisdešimt", "keturiasdešimt", "penkiasdešimt", "šešiasdešimt", "septyniasdešimt", "aštuoniasdešimt", "devyniasdešimt"]; static readonly string[] OrdinalHundredsMap = [string.Empty, "šimt", "du šimt", "trys šimt", "keturi šimt", "penki šimt", "šeši šimt", "septyni šimt", "aštuoni šimt", "devyni šimt"]; public override string Convert(long input, GrammaticalGender gender, bool addAnd = true) { if (gender == GrammaticalGender.Neuter) { throw new NotSupportedException(); } var parts = new List(); var number = input; HandleNegative(parts, ref number); CollectParts(parts, ref number, 1000000000000000000, GrammaticalGender.Masculine, "kvintilijonas", "kvintilijonai", "kvintilijonų"); CollectParts(parts, ref number, 1000000000000000, GrammaticalGender.Masculine, "kvadrilijonas", "kvadrilijonai", "kvadrilijonų"); CollectParts(parts, ref number, 1000000000000, GrammaticalGender.Masculine, "trilijonas", "trilijonai", "trilijonų"); CollectParts(parts, ref number, 1000000000, GrammaticalGender.Masculine, "milijardas", "milijardai", "milijardų"); CollectParts(parts, ref number, 1000000, GrammaticalGender.Masculine, "milijonas", "milijonai", "milijonų"); CollectParts(parts, ref number, 1000, GrammaticalGender.Masculine, "tūkstantis", "tūkstančiai", "tūkstančių"); CollectPartsUnderOneThousand(parts, number, gender); return string.Join(" ", parts); } public override string ConvertToOrdinal(int input, GrammaticalGender gender) { if (gender == GrammaticalGender.Neuter) { throw new NotSupportedException(); } var parts = new List(); var number = (long)input; HandleNegative(parts, ref number); CollectOrdinalParts(parts, ref number, 1000000000, GrammaticalGender.Masculine, "milijard" + GetOrdinalEndingForGender(gender), "milijardas", "milijardai", "milijardų"); CollectOrdinalParts(parts, ref number, 1000000, GrammaticalGender.Masculine, "milijon" + GetOrdinalEndingForGender(gender), "milijonas", "milijonai", "milijonų"); CollectOrdinalParts(parts, ref number, 1000, GrammaticalGender.Masculine, "tūkstant" + GetOrdinalEndingForGender(gender), "tūkstantis", "tūkstančiai", "tūkstančių"); CollectOrdinalPartsUnderOneThousand(parts, number, gender, true); return string.Join(" ", parts); } static void HandleNegative(List parts, ref long number) { if (number < 0) { parts.Add("minus"); number = -number; } } static void CollectParts(List parts, ref long number, long divisor, GrammaticalGender gender, params string[] forms) { var result = number / divisor; if (result == 0) { return; } number %= divisor; if (result > 1) { CollectPartsUnderOneThousand(parts, result, gender); } parts.Add(ChooseForm(result, forms)); } static void CollectOrdinalParts(List parts, ref long number, long divisor, GrammaticalGender gender, string ordinalForm, params string[] forms) { var result = number / divisor; if (result == 0) { return; } number %= divisor; if (result > 1) { CollectOrdinalPartsUnderOneThousand(parts, result, gender); } parts.Add(ChooseCardinalOrOrdinalForm(result, ordinalForm, forms, useOrdinalForm: number == 0)); } static void CollectPartsUnderOneThousand(List parts, long number, GrammaticalGender gender) { if (number >= 100) { var hundreds = number / 100; number %= 100; parts.Add(HundredsMap[hundreds]); } if (number >= 20) { var tens = number / 10; parts.Add(TensMap[tens]); number %= 10; } if (number > 0 || parts.Count == 0) { parts.Add(GetCardinalNumberForGender(UnitsMap[number], gender)); } } static void CollectOrdinalPartsUnderOneThousand(List parts, long number, GrammaticalGender gender, bool lastNumber = false) { if (number >= 100) { var hundreds = number / 100; number %= 100; parts.Add(!lastNumber || number > 0 ? HundredsMap[hundreds] : OrdinalHundredsMap[hundreds] + GetOrdinalEndingForGender(gender)); } if (number >= 20) { var tens = number / 10; number %= 10; parts.Add(!lastNumber || number > 0 ? TensMap[tens] : OrdinalTensMap[tens] + GetOrdinalEndingForGender(gender)); } if (number > 0) { parts.Add(!lastNumber ? UnitsMap[number] : OrdinalUnitsMap[number] + GetOrdinalEndingForGender(gender)); } else if (number == 0 && parts.Count == 0) { parts.Add(gender == GrammaticalGender.Masculine ? "nulinis" : "nulinė"); } } static string ChooseForm(long number, string[] forms) => forms[GetFormIndex(number)]; static string ChooseCardinalOrOrdinalForm(long number, string ordinalForm, string[] cardinalForms, bool useOrdinalForm = false) { if (useOrdinalForm) { return ordinalForm; } return ChooseForm(number, cardinalForms); } static int GetFormIndex(long number) { var form = LithuanianNumberFormDetector.Detect(number); return form switch { LithuanianNumberForm.Singular => 0, LithuanianNumberForm.Plural => 1, LithuanianNumberForm.GenitivePlural => 2, _ => throw new ArgumentOutOfRangeException(nameof(number)) }; } static string GetCardinalNumberForGender(string number, GrammaticalGender gender) { if (gender == GrammaticalGender.Masculine) { return number; } if (gender == GrammaticalGender.Feminine) { if (number == "du") { return "dvi"; } if (number.EndsWith("as")) { return number[..^1]; } if (number.EndsWith('i')) { return number + "os"; } return number; } throw new ArgumentOutOfRangeException(nameof(gender)); } static string GetOrdinalEndingForGender(GrammaticalGender gender) => gender switch { GrammaticalGender.Masculine => "as", GrammaticalGender.Feminine => "a", _ => throw new ArgumentOutOfRangeException(nameof(gender)) }; } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/LuxembourgishNumberToWordsConverter.cs ================================================ namespace Humanizer; class LuxembourgishNumberToWordsConverter : GenderedNumberToWordsConverter { static readonly string[] UnitsMap = ["null", "een", "zwee", "dräi", "véier", "fënnef", "sechs", "siwen", "aacht", "néng", "zéng", "eelef", "zwielef", "dräizéng", "véierzéng", "fofzéng", "siechzéng", "siwwenzéng", "uechtzéng", "nonzéng"]; static readonly string[] TensMap = ["null", "zéng", "zwanzeg", "drësseg", "véierzeg", "fofzeg", "sechzeg", "siwwenzeg", "achtzeg", "nonzeg"]; static readonly string[] UnitsOrdinal = [string.Empty, "éisch", "zwee", "drët", "véier", "fënnef", "sechs", "siwen", "aach", "néng", "zéng", "eelef", "zwielef", "dräizéng", "véierzéng", "fofzéng", "siechzéng", "siwwenzéng", "uechtzéng", "nonzéng"]; static readonly string[] HundredOrdinalSingular = ["eenhonnert"]; static readonly string[] HundredOrdinalPlural = ["{0}honnert"]; static readonly string[] ThousandOrdinalSingular = ["eendausend"]; static readonly string[] ThousandOrdinalPlural = ["{0}dausend"]; static readonly string[] MillionOrdinalSingular = ["eemillioun", "engmillioun"]; static readonly string[] MillionOrdinalPlural = ["{0}millioun", "{0}milliounen"]; static readonly string[] BillionOrdinalSingular = ["eemilliard", "engmilliard"]; static readonly string[] BillionOrdinalPlural = ["{0}milliard", "{0}milliarden"]; public override string Convert(long number, GrammaticalGender gender, bool addAnd = true) => Convert(number, WordForm.Normal, gender, addAnd); public override string Convert(long number, WordForm wordForm, GrammaticalGender gender, bool addAnd = true) { 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} Trilliounen", "eng Trillioun"); CollectParts(parts, ref number, 1000000000000000, true, "{0} Billiarden", "eng Billiard"); CollectParts(parts, ref number, 1000000000000, true, "{0} Billiounen", "eng Billioun"); CollectParts(parts, ref number, 1000000000, true, "{0} Milliarden", "eng Milliard"); CollectParts(parts, ref number, 1000000, true, "{0} Milliounen", "eng Millioun"); CollectParts(parts, ref number, 1000, false, "{0}dausend", "eendausend"); CollectParts(parts, ref number, 100, false, "{0}honnert", "eenhonnert"); if (number <= 0) { return string.Concat(parts); } if (number < 20) { switch (number) { case 1 when gender == GrammaticalGender.Feminine: parts.Add("eng"); break; case 2 when gender == GrammaticalGender.Feminine: parts.Add("zwou"); break; case 1 or 7: parts.Add(wordForm is WordForm.Eifeler ? LuxembourgishFormatter.ApplyEifelerRule(UnitsMap[number]) : UnitsMap[number]); break; default: parts.Add(UnitsMap[number]); break; } } else { var units = number % 10; var tens = TensMap[number / 10]; if (units > 0) { var andPart = LuxembourgishFormatter.CheckForAndApplyEifelerRule("an", tens); parts.Add($"{UnitsMap[units]}{andPart}"); } parts.Add(tens); } return string.Concat(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 is 0 or >= 20) { parts.Add("s"); } parts.Add(GetEndingForGender(gender)); return string.Concat(parts); } private void CollectParts(List parts, ref long number, long divisor, bool addSpaceBeforeNextPart, string pluralFormat, string singular) { if (number / divisor <= 0) { return; } parts.Add(Part(pluralFormat, singular, number / divisor, divisor)); number %= divisor; if (addSpaceBeforeNextPart && number > 0) { parts.Add(" "); } } private void CollectOrdinalParts(List parts, ref int number, int divisor, bool evaluateNoRest, string[] pluralFormats, string[] singulars) { if (number / divisor <= 0) { return; } var noRest = evaluateNoRest ? NoRestIndex(number % divisor) : 0; parts.Add(Part(pluralFormats[noRest], singulars[noRest], number / divisor, divisor)); number %= divisor; } private string Part(string pluralFormat, string singular, long number, long divisor) => number switch { 1 => singular, 2 when divisor >= 1000000 => string.Format(pluralFormat, Convert(number, GrammaticalGender.Feminine)), 7 => GetPartWithEifelerRule(pluralFormat, number, GrammaticalGender.Masculine), _ => string.Format(pluralFormat, Convert(number)) }; private static int NoRestIndex(int number) => number == 0 ? 0 : 1; private static string GetEndingForGender(GrammaticalGender gender) => gender switch { GrammaticalGender.Masculine => "ten", GrammaticalGender.Feminine => "t", GrammaticalGender.Neuter => "t", _ => throw new ArgumentOutOfRangeException(nameof(gender)) }; private string GetPartWithEifelerRule(string pluralFormat, long number, GrammaticalGender gender) { var nextWord = pluralFormat .AsSpan(3, pluralFormat.Length - 3) .TrimStart(); var wordForm = LuxembourgishFormatter.DoesEifelerRuleApply(nextWord) ? WordForm.Eifeler : WordForm.Normal; return string.Format(pluralFormat, Convert(number, wordForm, gender)); } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/MalteseNumberToWordsConvertor.cs ================================================ namespace Humanizer; class MalteseNumberToWordsConvertor : GenderedNumberToWordsConverter { static readonly string[] OrdinalOverrideMap = [ "0", "l-ewwel", "it-tieni", "it-tielet", "ir-raba'", "il-ħames", "is-sitt", "is-seba'", "it-tmien", "id-disa'", "l-għaxar", "il-ħdax", "it-tnax", "it-tlettax", "l-erbatax", "il-ħmistax", "is-sittax", "is-sbatax", "it-tmintax", "id-dsatax", "l-għoxrin" ]; static readonly string[] UnitsMap = [ "żero", "wieħed", "tnejn", "tlieta", "erbgħa", "ħamsa", "sitta", "sebgħa", "tmienja", "disgħa", "għaxra", "ħdax", "tnax", "tlettax", "erbatax", "ħmistax", "sittax", "sbatax", "tmintax", "dsatax" ]; static readonly string[] TensMap = ["zero", "għaxra", "għoxrin", "tletin", "erbgħin", "ħamsin", "sittin", "sebgħin", "tmenin", "disgħin"]; static readonly string[] HundredsMap = [ string.Empty, string.Empty, string.Empty, "tlett", "erbgħa", "ħames", "sitt", "sebgħa", "tminn", "disgħa", "għaxar" ]; static readonly string[] PrefixMap = [ string.Empty, string.Empty, string.Empty, "tlett", "erbat", "ħamest", "sitt", "sebat", "tmint", "disat", "għaxart", "ħdax-il", "tnax-il", "tletax-il", "erbatax-il", "ħmistax-il", "sittax-il", "sbatax-il", "tmintax-il", "dsatax-il" ]; public override string Convert(long input, GrammaticalGender gender, bool addAnd = true) { var negativeNumber = false; if (input < 0) { negativeNumber = true; input *= -1; } if (input < 1000000000) { return GetMillions(input, gender) + (negativeNumber ? " inqas minn żero" : string.Empty); } var billions = input / 1000000000; var tensInBillions = billions % 100; var millions = input % 1000000000; var billionsText = GetPrefixText(billions, tensInBillions, "biljun", "żewġ biljuni", "biljuni", false, gender); var millionsText = GetMillions(millions, gender); if (millions == 0) { return billionsText; } return $"{billionsText} u {millionsText}" + (negativeNumber ? " inqas minn żero" : string.Empty); } public override string ConvertToOrdinal(int number, GrammaticalGender gender) { if (number <= 20) { return OrdinalOverrideMap[number]; } var ordinal = Convert(number, gender); if (ordinal.StartsWith('d')) { return $"id-{Convert(number, gender)}"; } if (ordinal.StartsWith('s')) { return $"is-{Convert(number, gender)}"; } if (ordinal.StartsWith('t')) { return $"it-{Convert(number, gender)}"; } if (ordinal.StartsWith('e')) { return $"l-{Convert(number, gender)}"; } return $"il-{Convert(number, gender)}"; } static string GetTens(long value, bool usePrefixMap, bool usePrefixMapForLowerDigits, GrammaticalGender gender) { if (value == 1 && gender == GrammaticalGender.Feminine) { return "waħda"; } if (value < 11 && usePrefixMap && usePrefixMapForLowerDigits) { return PrefixMap[value]; } if (value < 11 && usePrefixMap && !usePrefixMapForLowerDigits) { return HundredsMap[value]; } if (value is > 10 and < 20 && usePrefixMap) { return PrefixMap[value]; } if (value < 20) { return UnitsMap[value]; } var single = value % 10; var numberOfTens = value / 10; if (single == 0) { return TensMap[numberOfTens]; } return $"{UnitsMap[single]} u {TensMap[numberOfTens]}"; } static string GetHundreds(long value, bool usePrefixMap, bool usePrefixMapForLowerValueDigits, GrammaticalGender gender) { if (value < 100) { return GetTens(value, usePrefixMap, usePrefixMapForLowerValueDigits, gender); } var tens = value % 100; var numberOfHundreds = value / 100; string hundredsText; if (numberOfHundreds == 1) { hundredsText = "mija"; } else if (numberOfHundreds == 2) { hundredsText = "mitejn"; } else { hundredsText = HundredsMap[numberOfHundreds] + " mija"; } if (tens == 0) { return hundredsText; } return $"{hundredsText} u {GetTens(tens, usePrefixMap, usePrefixMapForLowerValueDigits, gender)}"; } static string GetThousands(long value, GrammaticalGender gender) { if (value < 1000) { return GetHundreds(value, false, false, gender); } var thousands = value / 1000; var tensInThousands = thousands % 100; var hundreds = value % 1000; var thousandsInText = GetPrefixText(thousands, tensInThousands, "elf", "elfejn", "elef", true, gender); var hundredsInText = GetHundreds(hundreds, false, false, gender); if (hundreds == 0) { return thousandsInText; } return $"{thousandsInText} u {hundredsInText}"; } static string GetMillions(long value, GrammaticalGender gender) { if (value < 1000000) { return GetThousands(value, gender); } var millions = value / 1000000; var tensInMillions = millions % 100; var thousands = value % 1000000; var millionsText = GetPrefixText(millions, tensInMillions, "miljun", "żewġ miljuni", "miljuni", false, gender); var thousandsText = GetThousands(thousands, gender); if (thousands == 0) { return millionsText; } return $"{millionsText} u {thousandsText}"; } static string GetPrefixText(long thousands, long tensInThousands, string singular, string dual, string plural, bool usePrefixMapForLowerValueDigits, GrammaticalGender gender) { if (thousands == 1) { return singular; } if (thousands == 2) { return dual; } if (tensInThousands > 10) { return $"{GetHundreds(thousands, true, usePrefixMapForLowerValueDigits, gender)} {singular}"; } if (thousands == 100) { return $"mitt {singular}"; } if (thousands == 101) { return $"mija u {singular}"; } return $"{GetHundreds(thousands, true, usePrefixMapForLowerValueDigits, gender)} {plural}"; } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/NorwegianBokmalNumberToWordsConverter.cs ================================================ namespace Humanizer; class NorwegianBokmalNumberToWordsConverter : GenderedNumberToWordsConverter { static readonly string[] UnitsMap = ["null", "en", "to", "tre", "fire", "fem", "seks", "sju", "åtte", "ni", "ti", "elleve", "tolv", "tretten", "fjorten", "femten", "seksten", "sytten", "atten", "nitten"]; static readonly string[] TensMap = ["null", "ti", "tjue", "tretti", "førti", "femti", "seksti", "sytti", "åtti", "nitti"]; static readonly FrozenDictionary OrdinalExceptions = new Dictionary { { 0, "nullte" }, { 1, "første" }, { 2, "andre" }, { 3, "tredje" }, { 4, "fjerde" }, { 5, "femte" }, { 6, "sjette" }, { 11, "ellevte" }, { 12, "tolvte" } }.ToFrozenDictionary(); public override string Convert(long number, GrammaticalGender gender, bool addAnd = true) { if (number is > int.MaxValue or < int.MinValue) { throw new NotImplementedException(); } return Convert((int)number, false, gender); } public override string ConvertToOrdinal(int number, GrammaticalGender gender) => Convert(number, true, gender); string Convert(int number, bool isOrdinal, GrammaticalGender gender) { if (number == 0) { return GetUnitValue(0, isOrdinal); } if (number < 0) { return $"minus {Convert(-number, isOrdinal, gender)}"; } if (number == 1) { switch (gender) { case GrammaticalGender.Feminine: return "ei"; case GrammaticalGender.Neuter: return "et"; } } var parts = new List(); var millionOrMore = false; const int billion = 1000000000; if (number / billion > 0) { millionOrMore = true; var isExactOrdinal = isOrdinal && number % billion == 0; parts.Add(Part("{0} milliard" + (isExactOrdinal ? "" : "er"), (isExactOrdinal ? "" : "en ") + "milliard", number / billion, !isExactOrdinal)); number %= billion; } const int million = 1000000; if (number / million > 0) { millionOrMore = true; var isExactOrdinal = isOrdinal && number % million == 0; parts.Add(Part("{0} million" + (isExactOrdinal ? "" : "er"), (isExactOrdinal ? "" : "en ") + "million", number / million, !isExactOrdinal)); number %= million; } var thousand = false; if (number / 1000 > 0) { thousand = true; parts.Add(Part("{0}tusen", number % 1000 < 100 ? "tusen" : "ettusen", number / 1000)); number %= 1000; } var hundred = false; if (number / 100 > 0) { hundred = true; parts.Add(Part("{0}hundre", thousand || millionOrMore ? "ethundre" : "hundre", number / 100)); number %= 100; } if (number > 0) { if (parts.Count != 0) { if (millionOrMore && !hundred && !thousand) { parts.Add("og "); } else { parts.Add("og"); } } if (number < 20) { parts.Add(GetUnitValue(number, isOrdinal)); } else { var lastPart = TensMap[number / 10]; if (number % 10 > 0) { lastPart += $"{GetUnitValue(number % 10, isOrdinal)}"; } else if (isOrdinal) { lastPart = lastPart.TrimEnd('e') + "ende"; } parts.Add(lastPart); } } else if (isOrdinal) { parts[^1] += (number == 0 ? "" : "en") + (millionOrMore ? "te" : "de"); } var toWords = string .Concat(parts) .Trim(); return toWords; } static string GetUnitValue(int number, bool isOrdinal) { if (isOrdinal) { if (ExceptionNumbersToWords(number, out var exceptionString)) { return exceptionString; } if (number < 13) { return UnitsMap[number] .TrimEnd('e') + "ende"; } return UnitsMap[number] + "de"; } return UnitsMap[number]; } static bool ExceptionNumbersToWords(int number, [NotNullWhen(true)] out string? words) => OrdinalExceptions.TryGetValue(number, out words); string Part(string pluralFormat, string singular, int number, bool postfixSpace = false) { var postfix = postfixSpace ? " " : ""; if (number == 1) { return singular + postfix; } return string.Format(pluralFormat, Convert(number)) + postfix; } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/PolishNumberToWordsConverter.cs ================================================ namespace Humanizer; class PolishNumberToWordsConverter(CultureInfo culture) : GenderedNumberToWordsConverter { static readonly string[] HundredsMap = [ "zero", "sto", "dwieście", "trzysta", "czterysta", "pięćset", "sześćset", "siedemset", "osiemset", "dziewięćset" ]; static readonly string[] TensMap = [ "zero", "dziesięć", "dwadzieścia", "trzydzieści", "czterdzieści", "pięćdziesiąt", "sześćdziesiąt", "siedemdziesiąt", "osiemdziesiąt", "dziewięćdziesiąt" ]; static readonly string[] UnitsMap = [ "zero", "jeden", "dwa", "trzy", "cztery", "pięć", "sześć", "siedem", "osiem", "dziewięć", "dziesięć", "jedenaście", "dwanaście", "trzynaście", "czternaście", "piętnaście", "szesnaście", "siedemnaście", "osiemnaście", "dziewiętnaście" ]; static readonly string[][] PowersOfThousandMap = [ ["tysiąc", "tysiące", "tysięcy"], ["milion", "miliony", "milionów"], ["miliard", "miliardy", "miliardów"], ["bilion", "biliony", "bilionów"], ["biliard", "biliardy", "biliardów"], ["trylion", "tryliony", "trylionów"] ]; const long MaxPossibleDivisor = 1_000_000_000_000_000_000; public override string Convert(long input, GrammaticalGender gender, bool addAnd = true) { if (input == 0) { return "zero"; } var parts = new List(); CollectParts(parts, input, gender); return string.Join(" ", parts); } public override string ConvertToOrdinal(int number, GrammaticalGender gender) => number.ToString(culture); static void CollectParts(List parts, long input, GrammaticalGender gender) { var inputSign = 1; if (input < 0) { parts.Add("minus"); inputSign = -1; } var number = input; var divisor = MaxPossibleDivisor; var power = PowersOfThousandMap.Length - 1; while (divisor > 0) { var multiplier = (int)Math.Abs(number / divisor); if (divisor > 1) { if (multiplier > 1) { CollectPartsUnderThousand(parts, multiplier, GrammaticalGender.Masculine); } if (multiplier > 0) { parts.Add(GetPowerOfThousandNameForm(multiplier, power)); } } else if (multiplier > 0) { if (multiplier == 1 && Math.Abs(input) != 1) { gender = GrammaticalGender.Masculine; } CollectPartsUnderThousand(parts, multiplier, gender); } number -= multiplier * divisor * inputSign; divisor /= 1000; power--; } } static void CollectPartsUnderThousand(List parts, int number, GrammaticalGender gender) { var hundredsDigit = number / 100; var tensDigit = number % 100 / 10; var unitsDigit = number % 10; if (hundredsDigit >= 1) { parts.Add(HundredsMap[hundredsDigit]); } if (tensDigit >= 2) { parts.Add(TensMap[tensDigit]); } if (tensDigit != 1 && unitsDigit == 2) { var genderedForm = gender == GrammaticalGender.Feminine ? "dwie" : "dwa"; parts.Add(genderedForm); } else if (number == 1) { var genderedForm = gender switch { GrammaticalGender.Masculine => "jeden", GrammaticalGender.Feminine => "jedna", GrammaticalGender.Neuter => "jedno", _ => throw new ArgumentOutOfRangeException(nameof(gender)) }; parts.Add(genderedForm); } else { var unit = unitsDigit + 10 * (tensDigit == 1 ? 1 : 0); if (unit > 0) { parts.Add(UnitsMap[unit]); } } } static string GetPowerOfThousandNameForm(int multiplier, int power) { const int singularIndex = 0; const int pluralIndex = 1; const int genitiveIndex = 2; if (multiplier == 1) { return PowersOfThousandMap[power][singularIndex]; } var multiplierUnitsDigit = multiplier % 10; var multiplierTensDigit = multiplier % 100 / 10; if (multiplierTensDigit == 1 || multiplierUnitsDigit <= 1 || multiplierUnitsDigit >= 5) { return PowersOfThousandMap[power][genitiveIndex]; } return PowersOfThousandMap[power][pluralIndex]; } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/PortugueseNumberToWordsConverter.cs ================================================ namespace Humanizer; class PortugueseNumberToWordsConverter : GenderedNumberToWordsConverter { static readonly string[] PortugueseUnitsMap = ["zero", "um", "dois", "três", "quatro", "cinco", "seis", "sete", "oito", "nove", "dez", "onze", "doze", "treze", "quatorze", "quinze", "dezasseis", "dezassete", "dezoito", "dezanove"]; static readonly string[] PortugueseTensMap = ["zero", "dez", "vinte", "trinta", "quarenta", "cinquenta", "sessenta", "setenta", "oitenta", "noventa"]; static readonly string[] PortugueseHundredsMap = ["zero", "cento", "duzentos", "trezentos", "quatrocentos", "quinhentos", "seiscentos", "setecentos", "oitocentos", "novecentos"]; static readonly string[] PortugueseOrdinalUnitsMap = ["zero", "primeiro", "segundo", "terceiro", "quarto", "quinto", "sexto", "sétimo", "oitavo", "nono"]; static readonly string[] PortugueseOrdinalTensMap = ["zero", "décimo", "vigésimo", "trigésimo", "quadragésimo", "quinquagésimo", "sexagésimo", "septuagésimo", "octogésimo", "nonagésimo"]; static readonly string[] PortugueseOrdinalHundredsMap = ["zero", "centésimo", "ducentésimo", "trecentésimo", "quadringentésimo", "quingentésimo", "sexcentésimo", "septingentésimo", "octingentésimo", "noningentésimo"]; public override string Convert(long input, GrammaticalGender gender, bool addAnd = true) { if (input is > 999999999999 or < -999999999999) { throw new NotImplementedException(); } var number = input; if (number == 0) { return "zero"; } if (number < 0) { return $"menos {Convert(Math.Abs(number), gender)}"; } var parts = new List(); if (number / 1000000000 > 0) { // gender is not applied for billions parts.Add(number / 1000000000 == 1 ? "mil milhões" : $"{Convert(number / 1000000000)} mil milhões"); number %= 1000000000; } if (number / 1000000 > 0) { // gender is not applied for millions parts.Add(number / 1000000 >= 2 ? $"{Convert(number / 1000000, GrammaticalGender.Masculine)} milhões" : $"{Convert(number / 1000000, GrammaticalGender.Masculine)} milhão"); number %= 1000000; } if (number / 1000 > 0) { // gender is not applied for thousands parts.Add(number / 1000 == 1 ? "mil" : $"{Convert(number / 1000, GrammaticalGender.Masculine)} mil"); number %= 1000; } if (number / 100 > 0) { if (number == 100) { parts.Add(parts.Count > 0 ? "e cem" : "cem"); } else { // Gender is applied to hundreds starting from 200 parts.Add(ApplyGender(PortugueseHundredsMap[number / 100], gender)); } number %= 100; } if (number > 0) { if (parts.Count != 0) { parts.Add("e"); } if (number < 20) { parts.Add(ApplyGender(PortugueseUnitsMap[number], gender)); } else { var lastPart = PortugueseTensMap[number / 10]; if (number % 10 > 0) { lastPart += $" e {ApplyGender(PortugueseUnitsMap[number % 10], gender)}"; } parts.Add(lastPart); } } return string.Join(" ", parts); } public override string ConvertToOrdinal(int number, GrammaticalGender gender) { // N/A in Portuguese ordinal if (number == 0) { return "zero"; } var parts = new List(); if (number / 1000000000 > 0) { parts.Add(number / 1000000000 == 1 ? $"{ApplyOrdinalGender("milésimo", gender)} {ApplyOrdinalGender("milionésimo", gender)}" : $"{Convert(number / 1000000000)} {ApplyOrdinalGender("milésimo", gender)} {ApplyOrdinalGender("milionésimo", gender)}"); number %= 1000000000; } if (number / 1000000 > 0) { parts.Add(number / 1000000 == 1 ? ApplyOrdinalGender("milionésimo", gender) : string.Format("{0} " + ApplyOrdinalGender("milionésimo", gender), ConvertToOrdinal(number / 1000000000, gender))); number %= 1000000; } if (number / 1000 > 0) { parts.Add(number / 1000 == 1 ? ApplyOrdinalGender("milésimo", gender) : string.Format("{0} " + ApplyOrdinalGender("milésimo", gender), ConvertToOrdinal(number / 1000, gender))); number %= 1000; } if (number / 100 > 0) { parts.Add(ApplyOrdinalGender(PortugueseOrdinalHundredsMap[number / 100], gender)); number %= 100; } if (number / 10 > 0) { parts.Add(ApplyOrdinalGender(PortugueseOrdinalTensMap[number / 10], gender)); number %= 10; } if (number > 0) { parts.Add(ApplyOrdinalGender(PortugueseOrdinalUnitsMap[number], gender)); } return string.Join(" ", parts); } static string ApplyGender(string toWords, GrammaticalGender gender) { if (gender != GrammaticalGender.Feminine) { return toWords; } if (toWords.EndsWith("os")) { return StringHumanizeExtensions.Concat(toWords.AsSpan(0, toWords.Length - 2), "as".AsSpan()); } if (toWords.EndsWith("um")) { return StringHumanizeExtensions.Concat(toWords.AsSpan(0, toWords.Length - 2), "uma".AsSpan()); } if (toWords.EndsWith("dois")) { return StringHumanizeExtensions.Concat(toWords.AsSpan(0, toWords.Length - 4), "duas".AsSpan()); } return toWords; } static string ApplyOrdinalGender(string toWords, GrammaticalGender gender) { if (gender == GrammaticalGender.Feminine) { return toWords.TrimEnd('o') + 'a'; } return toWords; } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/Romanian/RomanianCardinalNumberConverter.cs ================================================ namespace Humanizer; class RomanianCardinalNumberConverter { /// /// Lookup table converting units number to text. Index 1 for 1, index 2 for 2, up to index 9 for 9. /// readonly string[] units = [ string.Empty, "unu|una|unu", "doi|două|două", "trei", "patru", "cinci", "șase", "șapte", "opt", "nouă" ]; /// /// Lookup table converting teens number to text. Index 0 for 10, index 1 for 11, up to index 9 for 19. /// readonly string[] teensUnder20NumberToText = [ "zece", "unsprezece", "doisprezece|douăsprezece|douăsprezece", "treisprezece", "paisprezece", "cincisprezece", "șaisprezece", "șaptesprezece", "optsprezece", "nouăsprezece" ]; /// /// Lookup table converting tens number to text. Index 2 for 20, index 3 for 30, up to index 9 for 90. /// readonly string[] tensOver20NumberToText = [ string.Empty, string.Empty, "douăzeci", "treizeci", "patruzeci", "cincizeci", "șaizeci", "șaptezeci", "optzeci", "nouăzeci" ]; readonly string feminineSingular = "o"; readonly string masculineSingular = "un"; readonly string joinGroups = "și"; readonly string joinAbove20 = "de"; readonly string minusSign = "minus"; /// /// Enumerates sets of three-digits having distinct conversion to text. /// enum ThreeDigitSets { /// /// Lowest three-digits set, from 1 to 999. /// Units = 0, /// /// Three-digits set counting the thousands, from 1'000 to 999'000. /// Thousands = 1, /// /// Three-digits set counting millions, from 1'000'000 to 999'000'000. /// Millions = 2, /// /// Three-digits set counting billions, from 1'000'000'000 to 999'000'000'000. /// Billions = 3, /// /// Three-digits set beyond 999 billions, from 1'000'000'000'000 onward. /// More = 4 } public string Convert(int number, GrammaticalGender gender) { if (number == 0) { return "zero"; } var words = string.Empty; var prefixMinusSign = false; if (number < 0) { prefixMinusSign = true; number = -number; } var _threeDigitParts = SplitEveryThreeDigits(number); for (var i = 0; i < _threeDigitParts.Count; i++) { var currentSet = (ThreeDigitSets)Enum.ToObject(typeof(ThreeDigitSets), i); var partToString = GetNextPartConverter(currentSet); if (partToString != null) { words = partToString(_threeDigitParts[i], gender) .Trim() + " " + words.Trim(); } } if (prefixMinusSign) { words = minusSign + " " + words; } // remove extra spaces return words .TrimEnd() .Replace(" ", " "); } /// /// Splits a number into a sequence of three-digits numbers, /// starting from units, then thousands, millions, and so on. /// /// The number to split. /// The sequence of three-digit numbers. static List SplitEveryThreeDigits(int number) { var parts = new List(); var rest = number; while (rest > 0) { var threeDigit = rest % 1000; parts.Add(threeDigit); rest /= 1000; } return parts; } /// /// During number conversion to text, finds out the converter /// to use for the next three-digit set. /// /// The next conversion function to use. Func? GetNextPartConverter(ThreeDigitSets currentSet) => currentSet switch { ThreeDigitSets.Units => UnitsConverter, ThreeDigitSets.Thousands => ThousandsConverter, ThreeDigitSets.Millions => MillionsConverter, ThreeDigitSets.Billions => BillionsConverter, ThreeDigitSets.More => null, _ => throw new ArgumentOutOfRangeException("Unknow ThreeDigitSet: " + currentSet) }; /// /// Converts a three-digit set to text. /// /// The three-digit set to convert. /// The grammatical gender to convert to. /// The same three-digit set expressed as text. string ThreeDigitSetConverter(int number, GrammaticalGender gender) { if (number == 0) { return string.Empty; } // grab lowest two digits var tensAndUnits = number % 100; // grab third digit var hundreds = number / 100; // grab also first and second digits separately var units = tensAndUnits % 10; var tens = tensAndUnits / 10; var words = string.Empty; // append text for hundreds words += HundredsToText(hundreds); // append text for tens, only those from twenty upward words += (tens >= 2 ? " " : string.Empty) + tensOver20NumberToText[tens]; if (tensAndUnits <= 9) { // simple case for units, under 10 words += " " + GetPartByGender(this.units[tensAndUnits], gender); } else if (tensAndUnits <= 19) { // special case for 'teens', from 10 to 19 words += " " + GetPartByGender(teensUnder20NumberToText[tensAndUnits - 10], gender); } else { // exception for zero var unitsText = units == 0 ? string.Empty : " " + joinGroups + " " + GetPartByGender(this.units[units], gender); words += unitsText; } return words; } static string GetPartByGender(string multiGenderPart, GrammaticalGender gender) { if (multiGenderPart.Contains('|')) { var parts = multiGenderPart.Split('|'); if (gender == GrammaticalGender.Feminine) { return parts[1]; } if (gender == GrammaticalGender.Neuter) { return parts[2]; } return parts[0]; } return multiGenderPart; } static bool IsAbove20(int number) => number >= 20; string HundredsToText(int hundreds) { if (hundreds == 0) { return string.Empty; } if (hundreds == 1) { return feminineSingular + " sută"; } return GetPartByGender(units[hundreds], GrammaticalGender.Feminine) + " sute"; } /// /// Converts a three-digit number, as units, to text. /// /// The three-digit number, as units, to convert. /// The grammatical gender to convert to. /// The same three-digit number, as units, expressed as text. string UnitsConverter(int number, GrammaticalGender gender) => ThreeDigitSetConverter(number, gender); /// /// Converts a thousands three-digit number to text. /// /// The three-digit number, as thousands, to convert. /// The grammatical gender to convert to. /// The same three-digit number of thousands expressed as text. string ThousandsConverter(int number, GrammaticalGender gender) { if (number == 0) { return string.Empty; } if (number == 1) { return feminineSingular + " mie"; } return ThreeDigitSetConverter(number, GrammaticalGender.Feminine) + (IsAbove20(number) ? " " + joinAbove20 : string.Empty) + " mii"; } // Large numbers (above 10^6) use a combined form of the long and short scales. /* Singular Plural Order Scale ----------------------------------------------- zece zeci 10^1 - sută sute 10^2 - mie mii 10^3 - milion milioane 10^6 short/long miliard miliarde 10^9 long trilion trilioane 10^12 short */ /// /// Converts a millions three-digit number to text. /// /// The three-digit number, as millions, to convert. /// The grammatical gender to convert to. /// The same three-digit number of millions expressed as text. string MillionsConverter(int number, GrammaticalGender gender) { if (number == 0) { return string.Empty; } if (number == 1) { return masculineSingular + " milion"; } return ThreeDigitSetConverter(number, GrammaticalGender.Feminine) + (IsAbove20(number) ? " " + joinAbove20 : string.Empty) + " milioane"; } /// /// Converts a billions three-digit number to text. /// /// The three-digit number, as billions, to convert. /// The grammatical gender to convert to. /// The same three-digit number of billions expressed as text. string BillionsConverter(int number, GrammaticalGender gender) { if (number == 1) { return masculineSingular + " miliard"; } return ThreeDigitSetConverter(number, GrammaticalGender.Feminine) + (IsAbove20(number) ? " " + joinAbove20 : string.Empty) + " miliarde"; } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/Romanian/RomanianOrdinalNumberConverter.cs ================================================ namespace Humanizer; class RomanianOrdinalNumberConverter { /// /// Lookup table converting units number to text. Index 1 for 1, index 2 for 2, up to index 9. /// readonly Dictionary ordinalsUnder10 = new() { { 1, "primul|prima" }, { 2, "doilea|doua" }, { 3, "treilea|treia" }, { 4, "patrulea|patra" }, { 5, "cincilea|cincea" }, { 6, "șaselea|șasea" }, { 7, "șaptelea|șaptea" }, { 8, "optulea|opta" }, { 9, "nouălea|noua" }, }; readonly string femininePrefix = "a"; readonly string masculinePrefix = "al"; readonly string feminineSuffix = "a"; readonly string masculineSuffix = "lea"; public string Convert(int number, GrammaticalGender gender) { // it's easier to treat zero as a completely distinct case if (number == 0) { return "zero"; } if (number == 1) { // no prefixes for primul/prima return GetPartByGender(ordinalsUnder10[number], gender); } if (number <= 9) { // units ordinals, 2 to 9, are totally different than the rest: treat them as a distinct case return string.Format("{0} {1}", gender == GrammaticalGender.Feminine ? femininePrefix : masculinePrefix, GetPartByGender(ordinalsUnder10[number], gender) ); } var coverter = new RomanianCardinalNumberConverter(); var words = coverter.Convert(number, gender); // remove 'de' preposition words = words.Replace(" de ", " "); if (gender == GrammaticalGender.Feminine && words.EndsWith("zeci")) { words = StringHumanizeExtensions.Concat(words.AsSpan(0, words.Length - 4), "zece".AsSpan()); } else if (gender == GrammaticalGender.Feminine && words.Contains("zeci") && (words.Contains("milioane") || words.Contains("miliarde"))) { words = words.Replace("zeci", "zecea"); } if (gender == GrammaticalGender.Feminine && words.StartsWith("un ")) { words = words .AsSpan(2) .TrimStart() .ToString(); } if (words.EndsWith("milioane")) { if (gender == GrammaticalGender.Feminine) { words = StringHumanizeExtensions.Concat(words.AsSpan(0, words.Length - 8), "milioana".AsSpan()); } } var customMasculineSuffix = masculineSuffix; if (words.EndsWith("milion")) { if (gender == GrammaticalGender.Feminine) { words = StringHumanizeExtensions.Concat(words.AsSpan(0, words.Length - 6), "milioana".AsSpan()); } else { customMasculineSuffix = "u" + masculineSuffix; } } else if (words.EndsWith("miliard")) { if (gender == GrammaticalGender.Masculine) { customMasculineSuffix = "u" + masculineSuffix; } } // trim last letter if (gender == GrammaticalGender.Feminine && !words.EndsWith("zece") && (words.EndsWith('a') || words.EndsWith('ă') || words.EndsWith('e') || words.EndsWith('i'))) { words = words[..^1]; } return string.Format("{0} {1}{2}", gender == GrammaticalGender.Feminine ? femininePrefix : masculinePrefix, words, gender == GrammaticalGender.Feminine ? feminineSuffix : customMasculineSuffix ); } static string GetPartByGender(string multiGenderPart, GrammaticalGender gender) { if (multiGenderPart.Contains('|')) { var parts = multiGenderPart.Split('|'); if (gender == GrammaticalGender.Feminine) { return parts[1]; } return parts[0]; } return multiGenderPart; } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/RomanianNumberToWordsConverter.cs ================================================ namespace Humanizer; class RomanianNumberToWordsConverter : GenderedNumberToWordsConverter { public override string Convert(long number, GrammaticalGender gender, bool addAnd = true) { if (number is > int.MaxValue or < int.MinValue) { throw new NotImplementedException(); } var converter = new RomanianCardinalNumberConverter(); return converter.Convert((int)number, gender); } public override string ConvertToOrdinal(int number, GrammaticalGender gender) { var converter = new RomanianOrdinalNumberConverter(); return converter.Convert(number, gender); } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/RussianNumberToWordsConverter.cs ================================================ namespace Humanizer; class RussianNumberToWordsConverter : GenderedNumberToWordsConverter { static readonly string[] HundredsMap = ["ноль", "сто", "двести", "триста", "четыреста", "пятьсот", "шестьсот", "семьсот", "восемьсот", "девятьсот"]; static readonly string[] TensMap = ["ноль", "десять", "двадцать", "тридцать", "сорок", "пятьдесят", "шестьдесят", "семьдесят", "восемьдесят", "девяносто"]; static readonly string[] UnitsMap = ["ноль", "один", "два", "три", "четыре", "пять", "шесть", "семь", "восемь", "девять", "десять", "одиннадцать", "двенадцать", "тринадцать", "четырнадцать", "пятнадцать", "шестнадцать", "семнадцать", "восемнадцать", "девятнадцать"]; static readonly string[] UnitsOrdinalPrefixes = [string.Empty, string.Empty, "двух", "трёх", "четырёх", "пяти", "шести", "семи", "восьми", "девяти", "десяти", "одиннадцати", "двенадцати", "тринадцати", "четырнадцати", "пятнадцати", "шестнадцати", "семнадцати", "восемнадцати", "девятнадцати"]; static readonly string[] TensOrdinalPrefixes = [string.Empty, "десяти", "двадцати", "тридцати", "сорока", "пятидесяти", "шестидесяти", "семидесяти", "восьмидесяти", "девяносто"]; static readonly string[] TensOrdinal = [string.Empty, "десят", "двадцат", "тридцат", "сороков", "пятидесят", "шестидесят", "семидесят", "восьмидесят", "девяност"]; static readonly string[] UnitsOrdinal = [string.Empty, "перв", "втор", "трет", "четверт", "пят", "шест", "седьм", "восьм", "девят", "десят", "одиннадцат", "двенадцат", "тринадцат", "четырнадцат", "пятнадцат", "шестнадцат", "семнадцат", "восемнадцат", "девятнадцат"]; public override string Convert(long input, GrammaticalGender gender, bool addAnd = true) { if (input == 0) { return "ноль"; } var parts = new List(); if (input < 0) { parts.Add("минус"); } CollectParts(parts, ref input, 1000000000000000000, GrammaticalGender.Masculine, "квинтиллион", "квинтиллиона", "квинтиллионов"); CollectParts(parts, ref input, 1000000000000000, GrammaticalGender.Masculine, "квадриллион", "квадриллиона", "квадриллионов"); CollectParts(parts, ref input, 1000000000000, GrammaticalGender.Masculine, "триллион", "триллиона", "триллионов"); CollectParts(parts, ref input, 1000000000, GrammaticalGender.Masculine, "миллиард", "миллиарда", "миллиардов"); CollectParts(parts, ref input, 1000000, GrammaticalGender.Masculine, "миллион", "миллиона", "миллионов"); CollectParts(parts, ref input, 1000, GrammaticalGender.Feminine, "тысяча", "тысячи", "тысяч"); if (input != 0) { CollectPartsUnderOneThousand(parts, Math.Abs(input), gender); } return string.Join(" ", parts); } public override string ConvertToOrdinal(int input, GrammaticalGender gender) { if (input == 0) { return "нулев" + GetEndingForGender(gender, input); } var parts = new List(); if (input < 0) { parts.Add("минус"); input = -input; } var number = (long)input; CollectOrdinalParts(parts, ref number, 1000000000, GrammaticalGender.Masculine, "миллиардн" + GetEndingForGender(gender, number), "миллиард", "миллиарда", "миллиардов"); CollectOrdinalParts(parts, ref number, 1000000, GrammaticalGender.Masculine, "миллионн" + GetEndingForGender(gender, number), "миллион", "миллиона", "миллионов"); CollectOrdinalParts(parts, ref number, 1000, GrammaticalGender.Feminine, "тысячн" + GetEndingForGender(gender, number), "тысяча", "тысячи", "тысяч"); if (number >= 100) { var ending = GetEndingForGender(gender, number); var hundreds = number / 100; number %= 100; if (number == 0) { parts.Add(UnitsOrdinalPrefixes[hundreds] + "сот" + ending); } else { parts.Add(HundredsMap[hundreds]); } } if (number >= 20) { var ending = GetEndingForGender(gender, number); var tens = number / 10; number %= 10; if (number == 0) { parts.Add(TensOrdinal[tens] + ending); } else { parts.Add(TensMap[tens]); } } if (number > 0) { parts.Add(UnitsOrdinal[number] + GetEndingForGender(gender, number)); } return string.Join(" ", parts); } static void CollectPartsUnderOneThousand(List parts, long number, GrammaticalGender gender) { if (number >= 100) { var hundreds = number / 100; number %= 100; parts.Add(HundredsMap[hundreds]); } if (number >= 20) { var tens = number / 10; parts.Add(TensMap[tens]); number %= 10; } if (number > 0) { if (number == 1 && gender == GrammaticalGender.Feminine) { parts.Add("одна"); } else if (number == 1 && gender == GrammaticalGender.Neuter) { parts.Add("одно"); } else if (number == 2 && gender == GrammaticalGender.Feminine) { parts.Add("две"); } else if (number < 20) { parts.Add(UnitsMap[number]); } } } static string GetPrefix(long number) { var parts = new List(); if (number >= 100) { var hundreds = number / 100; number %= 100; if (hundreds != 1) { parts.Add(UnitsOrdinalPrefixes[hundreds] + "сот"); } else { parts.Add("сто"); } } if (number >= 20) { var tens = number / 10; number %= 10; parts.Add(TensOrdinalPrefixes[tens]); } if (number > 0) { parts.Add(number == 1 ? "одно" : UnitsOrdinalPrefixes[number]); } return string.Concat(parts); } static void CollectParts(List parts, ref long number, long divisor, GrammaticalGender gender, params string[] forms) { var result = Math.Abs(number / divisor); if (result == 0) { return; } CollectPartsUnderOneThousand(parts, result, gender); parts.Add(ChooseOneForGrammaticalNumber(result, forms)); number = Math.Abs(number % divisor); } static void CollectOrdinalParts(List parts, ref long number, int divisor, GrammaticalGender gender, string prefixedForm, params string[] forms) { if (number < divisor) { return; } var result = number / divisor; number %= divisor; if (number == 0) { if (result == 1) { parts.Add(prefixedForm); } else { parts.Add(GetPrefix(result) + prefixedForm); } } else { CollectPartsUnderOneThousand(parts, result, gender); parts.Add(ChooseOneForGrammaticalNumber(result, forms)); } } static int GetIndex(RussianGrammaticalNumber number) { if (number == RussianGrammaticalNumber.Singular) { return 0; } if (number == RussianGrammaticalNumber.Paucal) { return 1; } return 2; } static string ChooseOneForGrammaticalNumber(long number, string[] forms) => forms[GetIndex(RussianGrammaticalNumberDetector.Detect(number))]; static string GetEndingForGender(GrammaticalGender gender, long number) { switch (gender) { case GrammaticalGender.Masculine: if (number is 0 or 2 or 6 or 7 or 8 or 40) { return "ой"; } if (number == 3) { return "ий"; } return "ый"; case GrammaticalGender.Feminine: if (number == 3) { return "ья"; } return "ая"; case GrammaticalGender.Neuter: if (number == 3) { return "ье"; } return "ое"; default: throw new ArgumentOutOfRangeException(nameof(gender)); } } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/SerbianCyrlNumberToWordsConverter.cs ================================================ namespace Humanizer; class SerbianCyrlNumberToWordsConverter(CultureInfo culture) : GenderlessNumberToWordsConverter { static readonly string[] UnitsMap = ["нула", "један", "два", "три", "четири", "пет", "шест", "седам", "осам", "девет", "десет", "једанест", "дванаест", "тринаест", "четрнаест", "петнаест", "шеснаест", "седамнаест", "осамнаест", "деветнаест"]; static readonly string[] TensMap = ["нула", "десет", "двадесет", "тридесет", "четрдесет", "петдесет", "шестдесет", "седамдесет", "осамдесет", "деветдесет"]; public override string Convert(long input) { if (input is > int.MaxValue or < int.MinValue) { throw new NotImplementedException(); } var number = (int)input; if (number == 0) { return "нула"; } if (number < 0) { return $"- {Convert(-number)}"; } var parts = new List(); var billions = number / 1000000000; if (billions > 0) { parts.Add(Part("милијарда", "две милијарде", "{0} милијарде", "{0} милијарда", billions)); number %= 1000000000; if (number > 0) { parts.Add(" "); } } var millions = number / 1000000; if (millions > 0) { parts.Add(Part("милион", "два милиона", "{0} милиона", "{0} милиона", millions)); number %= 1000000; if (number > 0) { parts.Add(" "); } } var thousands = number / 1000; if (thousands > 0) { parts.Add(Part("хиљаду", "две хиљаде", "{0} хиљаде", "{0} хиљада", thousands)); number %= 1000; if (number > 0) { parts.Add(" "); } } var hundreds = number / 100; if (hundreds > 0) { parts.Add(Part("сто", "двесто", "{0}сто", "{0}сто", hundreds)); number %= 100; if (number > 0) { parts.Add(" "); } } if (number > 0) { if (number < 20) { parts.Add(UnitsMap[number]); } else { parts.Add(TensMap[number / 10]); var units = number % 10; if (units > 0) { parts.Add($" {UnitsMap[units]}"); } } } return string.Concat(parts); } public override string ConvertToOrdinal(int number) => //TODO: In progress number.ToString(culture); string Part(string singular, string dual, string trialQuadral, string plural, int number) { return number switch { 1 => singular, 2 => dual, 3 or 4 => string.Format(trialQuadral, Convert(number)), _ => string.Format(plural, Convert(number)), }; } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/SerbianNumberToWordsConverter.cs ================================================ namespace Humanizer; class SerbianNumberToWordsConverter(CultureInfo culture) : GenderlessNumberToWordsConverter { static readonly string[] UnitsMap = ["nula", "jedan", "dva", "tri", "četiri", "pet", "šest", "sedam", "osam", "devet", "deset", "jedanaest", "dvanaest", "trinaest", "četrnaest", "petnaest", "šestnaest", "sedemnaest", "osemnaest", "devetnaest"]; static readonly string[] TensMap = ["nula", "deset", "dvadeset", "trideset", "četrdeset", "petdeset", "šestdeset", "sedamdeset", "osamdeset", "devetdeset"]; public override string Convert(long input) { if (input is > int.MaxValue or < int.MinValue) { throw new NotImplementedException(); } var number = (int)input; if (number == 0) { return "nula"; } if (number < 0) { return $"- {Convert(-number)}"; } var parts = new List(); var billions = number / 1000000000; if (billions > 0) { parts.Add(Part("milijarda", "dve milijarde", "{0} milijarde", "{0} milijarda", billions)); number %= 1000000000; if (number > 0) { parts.Add(" "); } } var millions = number / 1000000; if (millions > 0) { parts.Add(Part("milion", "dva miliona", "{0} miliona", "{0} miliona", millions)); number %= 1000000; if (number > 0) { parts.Add(" "); } } var thousands = number / 1000; if (thousands > 0) { parts.Add(Part("hiljadu", "dve hiljade", "{0} hiljade", "{0} hiljada", thousands)); number %= 1000; if (number > 0) { parts.Add(" "); } } var hundreds = number / 100; if (hundreds > 0) { parts.Add(Part("sto", "dvesto", "{0}sto", "{0}sto", hundreds)); number %= 100; if (number > 0) { parts.Add(" "); } } if (number > 0) { if (number < 20) { parts.Add(UnitsMap[number]); } else { parts.Add(TensMap[number / 10]); var units = number % 10; if (units > 0) { parts.Add($" {UnitsMap[units]}"); } } } return string.Concat(parts); } public override string ConvertToOrdinal(int number) => //TODO: In progress number.ToString(culture); string Part(string singular, string dual, string trialQuadral, string plural, int number) { return number switch { 1 => singular, 2 => dual, 3 or 4 => string.Format(trialQuadral, Convert(number)), _ => string.Format(plural, Convert(number)), }; } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/SlovenianNumberToWordsConverter.cs ================================================ namespace Humanizer; class SlovenianNumberToWordsConverter(CultureInfo culture) : GenderlessNumberToWordsConverter { static readonly string[] UnitsMap = ["nič", "ena", "dva", "tri", "štiri", "pet", "šest", "sedem", "osem", "devet", "deset", "enajst", "dvanajst", "trinajst", "štirinajst", "petnajst", "šestnajst", "sedemnajst", "osemnajst", "devetnajst"]; static readonly string[] TensMap = ["nič", "deset", "dvajset", "trideset", "štirideset", "petdeset", "šestdeset", "sedemdeset", "osemdeset", "devetdeset"]; public override string Convert(long input) { if (input is > int.MaxValue or < int.MinValue) { throw new NotImplementedException(); } var number = (int)input; if (number == 0) { return "nič"; } if (number < 0) { return $"minus {Convert(-number)}"; } var parts = new List(); var billions = number / 1000000000; if (billions > 0) { parts.Add(Part("milijarda", "dve milijardi", "{0} milijarde", "{0} milijard", billions)); number %= 1000000000; if (number > 0) { parts.Add(" "); } } var millions = number / 1000000; if (millions > 0) { parts.Add(Part("milijon", "dva milijona", "{0} milijone", "{0} milijonov", millions)); number %= 1000000; if (number > 0) { parts.Add(" "); } } var thousands = number / 1000; if (thousands > 0) { parts.Add(Part("tisoč", "dva tisoč", "{0} tisoč", "{0} tisoč", thousands)); number %= 1000; if (number > 0) { parts.Add(" "); } } var hundreds = number / 100; if (hundreds > 0) { parts.Add(Part("sto", "dvesto", "{0}sto", "{0}sto", hundreds)); number %= 100; if (number > 0) { parts.Add(" "); } } if (number > 0) { if (number < 20) { if (number > 1) { parts.Add(UnitsMap[number]); } else { parts.Add("ena"); } } else { var units = number % 10; if (units > 0) { parts.Add($"{UnitsMap[units]}in"); } parts.Add(TensMap[number / 10]); } } return string.Concat(parts); } public override string ConvertToOrdinal(int number) => number.ToString(culture); string Part(string singular, string dual, string trialQuadral, string plural, int number) { if (number == 1) { return singular; } if (number == 2) { return dual; } if (number is 3 or 4) { return string.Format(trialQuadral, Convert(number)); } return string.Format(plural, Convert(number)); } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/SpanishNumberToWordsConverter.cs ================================================ namespace Humanizer; class SpanishNumberToWordsConverter : GenderedNumberToWordsConverter { static readonly string[] HundredsRootMap = [ "cero", "ciento", "doscient", "trescient", "cuatrocient", "quinient", "seiscient", "setecient", "ochocient", "novecient" ]; static readonly string[] HundredthsRootMap = [ "", "centésim", "ducentésim", "tricentésim", "cuadringentésim", "quingentésim", "sexcentésim", "septingentésim", "octingentésim", "noningentésim" ]; static readonly string[] OrdinalsRootMap = [ "", "primer", "segund", "tercer", "cuart", "quint", "sext", "séptim", "octav", "noven" ]; static readonly string[] TensMap = [ "cero", "diez", "veinte", "treinta", "cuarenta", "cincuenta", "sesenta", "setenta", "ochenta", "noventa" ]; static readonly string[] TenthsRootMap = [ "", "décim", "vigésim", "trigésim", "cuadragésim", "quincuagésim", "sexagésim", "septuagésim", "octogésim", "nonagésim" ]; static readonly string[] ThousandthsRootMap = [ "", "milésim", "dosmilésim", "tresmilésim", "cuatromilésim", "cincomilésim", "seismilésim", "sietemilésim", "ochomilésim", "nuevemilésim" ]; static readonly string[] TupleMap = [ "cero veces", "una vez", "doble", "triple", "cuádruple", "quíntuple", "séxtuple", "séptuple", "óctuple", "nonuplo", "décuplo", "undécuplo", "duodécuplo", "terciodécuplo" ]; static readonly string[] UnitsMap = [ "cero", "uno", "dos", "tres", "cuatro", "cinco", "seis", "siete", "ocho", "nueve", "diez", "once", "doce", "trece", "catorce", "quince", "dieciséis", "diecisiete", "dieciocho", "diecinueve", "veinte", "veintiuno", "veintidós", "veintitrés", "veinticuatro", "veinticinco", "veintiséis", "veintisiete", "veintiocho", "veintinueve" ]; public override string Convert(long input, GrammaticalGender gender, bool addAnd = true) => Convert(input, WordForm.Normal, gender, addAnd); public override string Convert(long number, WordForm wordForm, GrammaticalGender gender, bool addAnd = true) { List wordBuilder = []; if (number == 0) { return "cero"; } if (number == long.MinValue) { return "menos nueve trillones doscientos veintitrés mil trescientos setenta y dos billones treinta y seis mil " + "ochocientos cincuenta y cuatro millones setecientos setenta y cinco mil ochocientos ocho"; } if (number < 0) { return $"menos {Convert(-number)}"; } wordBuilder.Add(ConvertGreaterThanMillion(number, out var remainder)); wordBuilder.Add(ConvertThousands(remainder, out remainder, gender)); wordBuilder.Add(ConvertHundreds(remainder, out remainder, gender)); wordBuilder.Add(ConvertUnits(remainder, gender, wordForm)); return BuildWord(wordBuilder); } public override string ConvertToOrdinal(int number, GrammaticalGender gender) => ConvertToOrdinal(number, gender, WordForm.Normal); public override string ConvertToOrdinal(int number, GrammaticalGender gender, WordForm wordForm) { List wordBuilder = []; if (number is 0 or int.MinValue) { return "cero"; } if (number < 0) { return ConvertToOrdinal(Math.Abs(number), gender); } if (IsRoundBillion(number)) { return ConvertRoundBillionths(number, gender); } if (IsRoundMillion(number)) { return ConvertToOrdinal(number / 1000, gender) .Replace("milésim", "millonésim"); } wordBuilder.Add(ConvertTensAndHunderdsOfThousandths(number, out var remainder, gender)); wordBuilder.Add(ConvertThousandths(remainder, out remainder, gender)); wordBuilder.Add(ConvertHundredths(remainder, out remainder, gender)); wordBuilder.Add(ConvertTenths(remainder, out remainder, gender)); wordBuilder.Add(ConvertOrdinalUnits(remainder, gender, wordForm)); return BuildWord(wordBuilder); } public override string ConvertToTuple(int number) { number = Math.Abs(number); if (number < TupleMap.Length) { return TupleMap[number]; } return Convert(number) + " veces"; } static string BuildWord(List wordParts) { wordParts.RemoveAll(string.IsNullOrEmpty); return string.Join(" ", wordParts); } static string ConvertHundreds(in long inputNumber, out long remainder, GrammaticalGender gender) { var wordPart = string.Empty; remainder = inputNumber; if (inputNumber / 100 > 0) { wordPart = inputNumber == 100 ? "cien" : GetGenderedHundredsMap(gender)[(int)(inputNumber / 100)]; remainder = inputNumber % 100; } return wordPart; } static string ConvertHundredths(in int number, out int remainder, GrammaticalGender gender) => ConvertMappedOrdinalNumber(number, 100, HundredthsRootMap, out remainder, gender); static string ConvertMappedOrdinalNumber( in int number, in int divisor, string[] map, out int remainder, GrammaticalGender gender) { var wordPart = string.Empty; remainder = number; if (number / divisor > 0) { var genderedEnding = gender == GrammaticalGender.Feminine ? "a" : "o"; wordPart = map[number / divisor] + genderedEnding; remainder = number % divisor; } return wordPart; } static string ConvertOrdinalUnits(in int number, GrammaticalGender gender, WordForm wordForm) { if (number is <= 0 or >= 10) { return string.Empty; } switch (gender) { case GrammaticalGender.Masculine: case GrammaticalGender.Neuter: if (HasOrdinalAbbreviation(number, wordForm)) { return OrdinalsRootMap[number]; } return OrdinalsRootMap[number] + 'o'; case GrammaticalGender.Feminine: return OrdinalsRootMap[number] + "a"; default: throw new ArgumentOutOfRangeException(nameof(gender), gender, null); } } static string ConvertTenths(in int number, out int remainder, GrammaticalGender gender) => ConvertMappedOrdinalNumber(number, 10, TenthsRootMap, out remainder, gender); static string ConvertThousandths(in int number, out int remainder, GrammaticalGender gender) => ConvertMappedOrdinalNumber(number, 1000, ThousandthsRootMap, out remainder, gender); static string ConvertUnits(long inputNumber, GrammaticalGender gender, WordForm wordForm = WordForm.Normal) { if (inputNumber <= 0) { return string.Empty; } UnitsMap[1] = GetGenderedOne(gender, wordForm); UnitsMap[21] = GetGenderedTwentyOne(gender, wordForm); if (inputNumber < 30) { return UnitsMap[inputNumber]; } var wordPart = TensMap[inputNumber / 10]; if (inputNumber % 10 <= 0) { return wordPart; } return wordPart + $" y {UnitsMap[inputNumber % 10]}"; } static List GetGenderedHundredsMap(GrammaticalGender gender) { var genderedEnding = gender == GrammaticalGender.Feminine ? "as" : "os"; var map = new List(); map.AddRange(HundredsRootMap.Take(2)); for (var i = 2; i < HundredsRootMap.Length; i++) { map.Add(HundredsRootMap[i] + genderedEnding); } return map; } static string GetGenderedOne(GrammaticalGender gender, WordForm wordForm = WordForm.Normal) { return gender switch { GrammaticalGender.Masculine or GrammaticalGender.Neuter => wordForm == WordForm.Abbreviation ? "un" : "uno", GrammaticalGender.Feminine => "una", _ => throw new ArgumentOutOfRangeException(nameof(gender), gender, null), }; } static string GetGenderedTwentyOne(GrammaticalGender gender, WordForm wordForm = WordForm.Normal) { return gender switch { GrammaticalGender.Masculine or GrammaticalGender.Neuter => wordForm == WordForm.Abbreviation ? "veintiún" : "veintiuno", GrammaticalGender.Feminine => "veintiuna", _ => throw new ArgumentOutOfRangeException(nameof(gender), gender, null), }; } static bool HasOrdinalAbbreviation(int number, WordForm wordForm) => number is 1 or 3 && wordForm == WordForm.Abbreviation; static bool IsRoundBillion(int number) => number >= 1000_000_000 && number % 1_000_000 == 0; static bool IsRoundMillion(int number) => number >= 1000000 && number % 1000000 == 0; static string PluralizeGreaterThanMillion(string singularWord) => singularWord.TrimEnd('ó', 'n') + "ones"; static readonly KeyValuePair[] NumbersAndWordsDict = [ new("trillón", 1_000_000_000_000_000_000), new("billón", 1_000_000_000_000), new("millón", 1_000_000), ]; string ConvertGreaterThanMillion(in long inputNumber, out long remainder) { List wordBuilder = []; remainder = inputNumber; foreach (var numberAndWord in NumbersAndWordsDict) { if (remainder / numberAndWord.Value > 0) { if (remainder / numberAndWord.Value == 1) { wordBuilder.Add($"un {numberAndWord.Key}"); } else { wordBuilder.Add(remainder / numberAndWord.Value % 10 == 1 ? $"{Convert(remainder / numberAndWord.Value, WordForm.Abbreviation, GrammaticalGender.Masculine)} {PluralizeGreaterThanMillion(numberAndWord.Key)}" : $"{Convert(remainder / numberAndWord.Value)} {PluralizeGreaterThanMillion(numberAndWord.Key)}"); } remainder %= numberAndWord.Value; } } return BuildWord(wordBuilder); } string ConvertRoundBillionths(int number, GrammaticalGender gender) { var cardinalPart = Convert(number / 1_000_000, WordForm.Abbreviation, gender); var sep = number == 1_000_000_000 ? "" : " "; var ordinalPart = ConvertToOrdinal(1_000_000, gender); return cardinalPart + sep + ordinalPart; } string ConvertTensAndHunderdsOfThousandths(in int number, out int remainder, GrammaticalGender gender) { var wordPart = string.Empty; remainder = number; if (number / 10000 > 0) { wordPart = Convert(number / 1000 * 1000, gender); if (number < 30000 || IsRoundNumber(number)) { if (number == 21000) { wordPart = wordPart .Replace("a", "") .Replace("ú", "u"); } wordPart = wordPart.Remove(wordPart.LastIndexOf(' '), 1); } wordPart += "ésim" + (gender == GrammaticalGender.Masculine ? "o" : "a"); remainder = number % 1000; } return wordPart; static bool IsRoundNumber(int number) => (number % 10000 == 0 && number < 100000) || (number % 100000 == 0 && number < 1000000) || (number % 1000000 == 0 && number < 10000000) || (number % 10000000 == 0 && number < 100000000) || (number % 100000000 == 0 && number < 1000000000) || (number % 1000000000 == 0 && number < int.MaxValue); } string ConvertThousands(in long inputNumber, out long remainder, GrammaticalGender gender) { var wordPart = string.Empty; remainder = inputNumber; if (inputNumber / 1000 > 0) { if (inputNumber / 1000 == 1) { wordPart = "mil"; } else { wordPart = gender == GrammaticalGender.Feminine ? $"{Convert(inputNumber / 1000, GrammaticalGender.Feminine)} mil" : $"{Convert(inputNumber / 1000, WordForm.Abbreviation, gender)} mil"; } remainder = inputNumber % 1000; } return wordPart; } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/SwedishNumberToWordsConverter.cs ================================================ namespace Humanizer; class SwedishNumberToWordsConverter : GenderlessNumberToWordsConverter { static readonly string[] UnitsMap = ["noll", "ett", "två", "tre", "fyra", "fem", "sex", "sju", "åtta", "nio", "tio", "elva", "tolv", "tretton", "fjorton", "femton", "sexton", "sjutton", "arton", "nitton"]; static readonly string[] TensMap = ["noll", "tio", "tjugo", "trettio", "fyrtio", "femtio", "sextio", "sjuttio", "åttio", "nittio", "hundra"]; class Fact { public int Value { get; set; } public required string Name { get; set; } public required string Prefix { get; set; } public required string Postfix { get; set; } public bool DisplayOneUnit { get; set; } public GrammaticalGender Gender { get; set; } = GrammaticalGender.Neuter; } static readonly Fact[] Hunderds = [ new() { Value = 1000000000, Name = "miljard", Prefix = " ", Postfix = " ", DisplayOneUnit = true, Gender = GrammaticalGender.Masculine }, new() { Value = 1000000, Name = "miljon", Prefix = " ", Postfix = " ", DisplayOneUnit = true, Gender = GrammaticalGender.Masculine }, new() { Value = 1000, Name = "tusen", Prefix = " ", Postfix = " ", DisplayOneUnit = true }, new() { Value = 100, Name = "hundra", Prefix = "", Postfix = "", DisplayOneUnit = false } ]; public override string Convert(long input, GrammaticalGender gender, bool addAnd = true) { if (input is > int.MaxValue or < int.MinValue) { throw new NotImplementedException(); } var number = (int)input; if (number == 0) { return UnitsMap[0]; } if (number < 0) { return $"minus {Convert(-number, gender)}"; } var word = ""; foreach (var m in Hunderds) { var divided = number / m.Value; if (divided <= 0) { continue; } if (divided == 1 && !m.DisplayOneUnit) { word += m.Name; } else { word += Convert(divided, m.Gender) + m.Prefix + m.Name; } // pluralise 1M+ if (divided > 1 && input >= 1_000_000) { word += "er"; } number %= m.Value; if (number > 0) { word += m.Postfix; } } if (number > 0) { if (number < 20) { if (number == 1 && gender == GrammaticalGender.Masculine) { word += "en"; } else { word += UnitsMap[number]; } } else { var tens = TensMap[number / 10]; var unit = number % 10; if (unit > 0) { var units = UnitsMap[unit]; word += tens + units; } else { word += tens; } } } return word; } public override string Convert(long input) => Convert(input, GrammaticalGender.Neuter); static readonly string[] OrdinalNumbers = [ "nollte", "första", "andra", "tredje", "fjärde", "femte", "sjätte", "sjunde", "åttonde", "nionde", "tionde", "elfte", "tolfte", "trettonde", "fjortonde", "femtonde", "sextonde", "sjuttonde", "artonde", "nittonde", "tjugonde" ]; public override string ConvertToOrdinal(int number) { var word = ""; if (number < 0) { return $"minus {ConvertToOrdinal(-number)}"; } if (number <= 20) { return OrdinalNumbers[number]; } // 21+ if (number <= 100) { var tens = TensMap[number / 10]; var unit = number % 10; if (unit > 0) { word += tens + ConvertToOrdinal(unit); } else if (number == 100) { word += tens + "de"; } else { word += tens + "nde"; } return word; } // 101+ foreach (var m in Hunderds) { var divided = number / m.Value; if (divided <= 0) { continue; } if (divided == 1 && !m.DisplayOneUnit) { word += m.Name; } else { word += Convert(divided, m.Gender) + m.Prefix + m.Name; } // suffix -de/-te if (number % m.Value == 0) { word += number switch { 1_000_000 => "te", _ => "de" }; } number %= m.Value; if (number > 0) { word += ConvertToOrdinal(number); } } return word; } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/TamilNumberToWordsConverter.cs ================================================ namespace Humanizer; class TamilNumberToWordsConverter : GenderlessNumberToWordsConverter { static readonly string[] UnitsMap = ["சுழியம்", "ஒன்று", "இரண்டு", "மூன்று", "நான்கு", "ஐந்து", "ஆறு", "ஏழு", "எட்டு", "ஒன்பது", "பத்து", "பதினொன்று", "பனிரெண்டு", "பதிமூன்று", "பதினான்கு", "பதினைந்து", "பதினாறு", "பதினேழு", "பதினெட்டு", "பத்தொன்பது"]; static readonly string[] TensMap = ["சுழியம்", "பத்து", "இருப", "முப்ப", "நாற்ப", "ஐம்ப", "அறுப", "எழுப", "எண்ப", "தொண்ணூ"]; static readonly string[] HundredsMap = ["நூ", "இருநூ", "முன்னூ", "நானூ", "ஐந்நூ", "அறுநூ", "எழுநூ", "எண்ணூ", "தொள்ளாயிர"]; static readonly string[] ThousandsMap = ["ஆ", "இரண்டா", "மூன்றா", "நான்கா", "ஐந்தா", "ஆறா", "ஏழா", "எட்டா", "ஒன்பதா", "பத்தா", "பதினொன்றா", "பனிரெண்டா", "பதிமூன்றா", "பதினான்கா", "பதினைந்தா", "பதினாறா", "பதினேழா", "பதினெட்டா", "பத்தொன்பதா"]; static readonly string[] LakhsMap = ["இலட்ச"]; static readonly FrozenDictionary OrdinalExceptions = new Dictionary { { 1, "முதலாவது" }, { 2, "இரண்டாவது" }, { 3, "மூன்றாவது" }, { 4, "நான்காவது" }, { 5, "ஐந்தாவது" }, { 8, "எட்டாவது" }, { 9, "ஒன்பதாவது" }, { 12, "பனிரெண்டாவது" }, }.ToFrozenDictionary(); public override string Convert(long number) => ConvertImpl(number, false); public override string ConvertToOrdinal(int number) => ConvertImpl(number, true); string ConvertImpl(long number, bool isOrdinal) { if (number == 0) { return GetUnitValue(0, isOrdinal); } if (number < 0) { return $"கழித்தல் {Convert(-number)}"; } var parts = new List(); if (number / 1000000000000000000 > 0) { parts.Add($"{Convert(number / 1000000000000000000)} quintillion"); number %= 1000000000000000000; } if (number / 1000000000000000 > 0) { parts.Add($"{Convert(number / 1000000000000000)} quadrillion"); number %= 1000000000000000; } //if ((number / 1000000000000) > 0) //{ // parts.Add(string.Format("{0} trillion", Convert(number / 1000000000000))); // number %= 1000000000000; //} //if ((number / 1000000000) > 0) //{ // parts.Add(string.Format("{0} பில்லியன்", Convert(number / 1000000000))); // number %= 1000000000; //} //if ((number / 1000000) > 0) //{ // parts.Add(string.Format("{0} மில்லியன்", Convert(number / 1000000))); // number %= 1000000; //} if (number / 10000000 > 0) { parts.Add(GetCroresValue(ref number)); } if (number / 100000 > 0) { parts.Add(GetLakhsValue(ref number, isOrdinal)); } if (number / 1000 > 0) { parts.Add(GetThousandsValue(ref number)); } if (number / 100 > 0) { parts.Add(GetHundredsValue(ref number)); } if (number > 0) { parts.Add(GetTensValue(number, isOrdinal)); } else if (isOrdinal) { parts[^1] += "வது"; } var toWords = string.Join(" ", parts); if (isOrdinal) { toWords = RemoveOnePrefix(toWords); } return toWords; } static string GetUnitValue(long number, bool isOrdinal) { if (isOrdinal) { if (ExceptionNumbersToWords(number, out var exceptionString)) { return exceptionString; } return UnitsMap[number] + "வது"; } return UnitsMap[number]; } static string GetTensValue(long number, bool isOrdinal, bool isThousand = false) { var local_word = ""; if (number < 20) { local_word = GetUnitValue(number, isOrdinal); } else if (number is >= 20 and <= 99) { var lastPart = TensMap[number / 10]; var quot = number / 10; if (number % 10 > 0) { if (quot == 9) { lastPart += "ற்றி "; } else if (quot is 7 or 8 or 4) { lastPart += "த்தி "; } else { lastPart += "த்து "; } if (!isThousand) { lastPart += $"{GetUnitValue(number % 10, isOrdinal)}"; } } else if (number % 10 == 0) { if (isThousand) { if (quot == 9) { lastPart += "றா"; } else { lastPart += "தா"; } } else { if (quot == 9) { lastPart += "று"; } else { lastPart += "து"; } } } else if (isOrdinal) { lastPart = lastPart.TrimEnd('y') + "ieth"; } local_word = lastPart; } return local_word; } static string GetLakhsValue(ref long number, bool isOrdinal) { var num_above_10 = number / 100000; var local_word = ""; if (num_above_10 >= 20) { local_word = GetTensValue(num_above_10, false, false); local_word += " " + LakhsMap[0]; } else if (num_above_10 == 1) { local_word = "ஒரு " + LakhsMap[0]; } else { local_word += GetTensValue(number / 100000, isOrdinal) + " " + LakhsMap[0]; } if (number % 1000000 == 0 || number % 100000 == 0) { local_word += "ம்"; } else { local_word += "த்து"; } number %= 100000; return local_word; } static string GetCroresValue(ref long number) { var local_word = ""; var num_above_10 = number / 10000000; var str_crore = "கோடி"; if (num_above_10 is > 99999 and <= 9999999) { local_word = GetLakhsValue(ref num_above_10, false); local_word += " "; } if (num_above_10 is > 999 and <= 99999) { local_word += GetThousandsValue(ref num_above_10); local_word += " "; } if (num_above_10 is > 99 and <= 999) { local_word += GetHundredsValue(ref num_above_10); local_word += " "; } if (num_above_10 >= 20) { local_word += GetTensValue(num_above_10, false, false); local_word += " "; } else if (num_above_10 == 1) { local_word = "ஒரு "; } else if (num_above_10 > 0) { local_word += GetTensValue(num_above_10, false) + " "; } local_word = local_word.TrimEnd() + " " + str_crore; if (number % 10000000 == 0 || number % 100000000 == 0) { local_word += ""; } else { local_word += "யே"; } number %= 10000000; return local_word; } static string GetThousandsValue(ref long number) { var num_above_10 = number / 1000; var local_word = ""; if (num_above_10 >= 20) { local_word = GetTensValue(num_above_10, false, true); if (num_above_10 % 10 == 1) { local_word += "ஓரா"; } else if (num_above_10 % 10 > 1) { local_word += ThousandsMap[num_above_10 % 10 - 1]; } } else { local_word += ThousandsMap[number / 1000 - 1]; } number %= 1000; if (number > 0) { local_word += "யிரத்து"; } else { local_word += "யிரம்"; } return local_word; } static string GetHundredsValue(ref long number) { var local_word = HundredsMap[number / 100 - 1]; if (number / 100 == 9) { if (number % 100 == 0) { local_word += "ம்"; } else { local_word += "த்து"; } } else if (number % 100 >= 1) { local_word += "ற்று"; } else { local_word += "று"; } number %= 100; return local_word; } static string RemoveOnePrefix(string toWords) { // one hundred => hundredth if (toWords.StartsWith("one", StringComparison.Ordinal)) { toWords = toWords[4..]; } return toWords; } static bool ExceptionNumbersToWords(long number, [NotNullWhen(true)] out string? words) => OrdinalExceptions.TryGetValue(number, out words); } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/ThaiNumberToWordsConverter.cs ================================================ namespace Humanizer; class ThaiNumberToWordsConverter : GenderlessNumberToWordsConverter { public override string Convert(long numbermoney) { var Textreturn = ""; if (numbermoney == 0) { return "ศูนย์"; } if (numbermoney < 0) { Textreturn = "ลบ"; numbermoney = -numbermoney; } if (numbermoney / 1000000 > 0) { Textreturn += Convert(numbermoney / 1000000) + "ล้าน"; numbermoney %= 1000000; } if (numbermoney / 100000 > 0) { Textreturn += Convert(numbermoney / 100000) + "แสน"; numbermoney %= 100000; } if (numbermoney / 10000 > 0) { Textreturn += Convert(numbermoney / 10000) + "หมื่น"; numbermoney %= 10000; } if (numbermoney / 1000 > 0) { Textreturn += Convert(numbermoney / 1000) + "พัน"; numbermoney %= 1000; } if (numbermoney / 100 > 0) { Textreturn += Convert(numbermoney / 100) + "ร้อย"; numbermoney %= 100; } if (numbermoney > 0) { if (Textreturn != "") { Textreturn += ""; } var unitsMap = new[] { "ศูนย์", "หนึ่ง", "สอง", "สาม", "สี่", "ห้า", "หก", "เจ็ด", "เเปด", "เก้า", "สิบ", "สิบเอ็ด", "สิบสอง", "สิบสาม", "สิบสี่", "สิบห้า", "สิบหก", "สิบเจ็ด", "สิบเเปด", "สิบเก้า" }; var tensMap = new[] { "ศูนย์", "สิบ", "ยี่สิบ", "สามสิบ", "สี่สิบ", "ห้าสิบ", "หกสิบ", "เจ็ดสิบ", "แปดสิบ", "เก้าสิบ" }; if (numbermoney < 20) { Textreturn += unitsMap[numbermoney]; } else { Textreturn += tensMap[numbermoney / 10]; if (numbermoney % 10 > 0) { Textreturn += "" + unitsMap[numbermoney % 10]; } } } return Textreturn; } public override string ConvertToOrdinal(int number) => Convert(number); } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/TurkishNumberToWordConverter.cs ================================================ namespace Humanizer; class TurkishNumberToWordConverter : GenderlessNumberToWordsConverter { static readonly string[] UnitsMap = ["sıfır", "bir", "iki", "üç", "dört", "beş", "altı", "yedi", "sekiz", "dokuz"]; static readonly string[] TensMap = ["sıfır", "on", "yirmi", "otuz", "kırk", "elli", "altmış", "yetmiş", "seksen", "doksan"]; static readonly FrozenDictionary OrdinalSuffix = new Dictionary { { 'ı', "ıncı" }, { 'i', "inci" }, { 'u', "uncu" }, { 'ü', "üncü" }, { 'o', "uncu" }, { 'ö', "üncü" }, { 'e', "inci" }, { 'a', "ıncı" }, }.ToFrozenDictionary(); static readonly FrozenDictionary TupleSuffix = new Dictionary { { 'ı', "lı" }, { 'i', "li" }, { 'u', "lu" }, { 'ü', "lü" }, { 'o', "lu" }, { 'ö', "lü" }, { 'e', "li" }, { 'a', "lı" }, }.ToFrozenDictionary(); public override string Convert(long input) { var number = input; if (number == 0) { return UnitsMap[0]; } if (number < 0) { return $"eksi {Convert(-number)}"; } var parts = new List(); if (number / 1000000000000000000 > 0) { parts.Add($"{Convert(number / 1000000000000000000)} kentilyon"); number %= 1000000000000000000; } if (number / 1000000000000000 > 0) { parts.Add($"{Convert(number / 1000000000000000)} katrilyon"); number %= 1000000000000000; } if (number / 1000000000000 > 0) { parts.Add($"{Convert(number / 1000000000000)} trilyon"); number %= 1000000000000; } if (number / 1000000000 > 0) { parts.Add($"{Convert(number / 1000000000)} milyar"); number %= 1000000000; } if (number / 1000000 > 0) { parts.Add($"{Convert(number / 1000000)} milyon"); number %= 1000000; } var thousand = number / 1000; if (thousand > 0) { parts.Add($"{(thousand > 1 ? Convert(thousand) : "")} bin".Trim()); number %= 1000; } var hundred = number / 100; if (hundred > 0) { parts.Add($"{(hundred > 1 ? Convert(hundred) : "")} yüz".Trim()); number %= 100; } if (number / 10 > 0) { parts.Add(TensMap[number / 10]); number %= 10; } if (number > 0) { parts.Add(UnitsMap[number]); } var toWords = string.Join(" ", parts); return toWords; } public override string ConvertToOrdinal(int number) { var word = Convert(number); var wordSuffix = string.Empty; var suffixFoundOnLastVowel = false; for (var i = word.Length - 1; i >= 0; i--) { if (OrdinalSuffix.TryGetValue(word[i], out wordSuffix)) { suffixFoundOnLastVowel = i == word.Length - 1; break; } } if (word[^1] == 't') { word = StringHumanizeExtensions.Concat(word.AsSpan(0, word.Length - 1), 'd'); } if (suffixFoundOnLastVowel) { word = word[..^1]; } return $"{word}{wordSuffix}"; } public override string ConvertToTuple(int number) { switch (number) { case 1: return "tek"; case 2: return "çift"; default: var word = Convert(number); var wordSuffix = string.Empty; for (var i = word.Length - 1; i >= 0; i--) { if (TupleSuffix.TryGetValue(word[i], out wordSuffix)) { break; } } return $"{word}{wordSuffix}"; } } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/UkrainianNumberToWordsConverter.cs ================================================ namespace Humanizer; class UkrainianNumberToWordsConverter : GenderedNumberToWordsConverter { static readonly string[] HundredsMap = ["нуль", "сто", "двісті", "триста", "чотириста", "п'ятсот", "шістсот", "сімсот", "вісімсот", "дев'ятсот"]; static readonly string[] TensMap = ["нуль", "десять", "двадцять", "тридцять", "сорок", "п'ятдесят", "шістдесят", "сімдесят", "вісімдесят", "дев'яносто"]; static readonly string[] UnitsMap = ["нуль", "один", "два", "три", "чотири", "п'ять", "шість", "сім", "вісім", "дев'ять", "десять", "одинадцять", "дванадцять", "тринадцять", "чотирнадцять", "п'ятнадцять", "шістнадцять", "сімнадцять", "вісімнадцять", "дев'ятнадцять"]; static readonly string[] UnitsOrdinalPrefixes = [string.Empty, string.Empty, "двох", "трьох", "чотирьох", "п'яти", "шести", "семи", "восьми", "дев'яти", "десяти", "одинадцяти", "дванадцяти", "тринадцяти", "чотирнадцяти", "п'ятнадцяти", "шістнадцяти", "сімнадцяти", "вісімнадцяти", "дев'ятнадцяти", "двадцяти"]; static readonly string[] TensOrdinalPrefixes = [string.Empty, "десяти", "двадцяти", "тридцяти", "сорока", "п'ятдесяти", "шістдесяти", "сімдесяти", "вісімдесяти", "дев'яносто"]; static readonly string[] TensOrdinal = [string.Empty, "десят", "двадцят", "тридцят", "сороков", "п'ятдесят", "шістдесят", "сімдесят", "вісімдесят", "дев'яност"]; static readonly string[] UnitsOrdinal = ["нульов", "перш", "друг", "трет", "четверт", "п'ят", "шост", "сьом", "восьм", "дев'ят", "десят", "одинадцят", "дванадцят", "тринадцят", "чотирнадцят", "п'ятнадцят", "шістнадцят", "сімнадцят", "вісімнадцят", "дев'ятнадцят"]; public override string Convert(long input, GrammaticalGender gender, bool addAnd = true) { if (input == 0) { return "нуль"; } var parts = new List(); if (input < 0) { parts.Add("мінус"); } CollectParts(parts, ref input, 1000000000000000000, GrammaticalGender.Masculine, "квінтильйон", "квінтильйона", "квінтильйонів"); CollectParts(parts, ref input, 1000000000000000, GrammaticalGender.Masculine, "квадрильйон", "квадрильйона", "квадрильйонів"); CollectParts(parts, ref input, 1000000000000, GrammaticalGender.Masculine, "трильйон", "трильйона", "трильйонів"); CollectParts(parts, ref input, 1000000000, GrammaticalGender.Masculine, "мільярд", "мільярда", "мільярдів"); CollectParts(parts, ref input, 1000000, GrammaticalGender.Masculine, "мільйон", "мільйона", "мільйонів"); CollectParts(parts, ref input, 1000, GrammaticalGender.Feminine, "тисяча", "тисячі", "тисяч"); if (input != 0) { CollectPartsUnderOneThousand(parts, Math.Abs(input), gender); } return string.Join(" ", parts); } public override string ConvertToOrdinal(int number, GrammaticalGender gender) { if (number == 0) { return "нульов" + GetEndingForGender(gender, number); } var parts = new List(); if (number < 0) { parts.Add("мінус"); number = -number; } CollectOrdinalParts(parts, ref number, 1000000000, GrammaticalGender.Masculine, "мільярдн" + GetEndingForGender(gender, number), "мільярд", "мільярда", "мільярдів"); CollectOrdinalParts(parts, ref number, 1000000, GrammaticalGender.Masculine, "мільйонн" + GetEndingForGender(gender, number), "мільйон", "мільйона", "мільйонів"); CollectOrdinalParts(parts, ref number, 1000, GrammaticalGender.Feminine, "тисячн" + GetEndingForGender(gender, number), "тисяча", "тисячі", "тисяч"); if (number >= 100) { var ending = GetEndingForGender(gender, number); var hundreds = number / 100; number %= 100; if (number == 0) { parts.Add(UnitsOrdinalPrefixes[hundreds] + "сот" + ending); } else { parts.Add(HundredsMap[hundreds]); } } if (number >= 20) { var ending = GetEndingForGender(gender, number); var tens = number / 10; number %= 10; if (number == 0) { parts.Add(TensOrdinal[tens] + ending); } else { parts.Add(TensMap[tens]); } } if (number > 0) { parts.Add(UnitsOrdinal[number] + GetEndingForGender(gender, number)); } return string.Join(" ", parts); } static void CollectPartsUnderOneThousand(List parts, long number, GrammaticalGender gender) { if (number >= 100) { var hundreds = number / 100; number %= 100; parts.Add(HundredsMap[hundreds]); } if (number >= 20) { var tens = number / 10; parts.Add(TensMap[tens]); number %= 10; } if (number > 0) { if (number == 1 && gender == GrammaticalGender.Feminine) { parts.Add("одна"); } else if (number == 1 && gender == GrammaticalGender.Neuter) { parts.Add("одне"); } else if (number == 2 && gender == GrammaticalGender.Feminine) { parts.Add("дві"); } else if (number < 20) { parts.Add(UnitsMap[number]); } } } static string GetPrefix(int number) { var parts = new List(); if (number >= 100) { var hundreds = number / 100; number %= 100; if (hundreds != 1) { parts.Add(UnitsOrdinalPrefixes[hundreds] + "сот"); } else { parts.Add("сто"); } } if (number >= 20) { var tens = number / 10; number %= 10; parts.Add(TensOrdinalPrefixes[tens]); } if (number > 0) { parts.Add(number == 1 ? "одно" : UnitsOrdinalPrefixes[number]); } return string.Concat(parts); } static void CollectParts(List parts, ref long number, long divisor, GrammaticalGender gender, params string[] forms) { var result = Math.Abs(number / divisor); if (result == 0) { return; } CollectPartsUnderOneThousand(parts, result, gender); parts.Add(ChooseOneForGrammaticalNumber(result, forms)); number = Math.Abs(number % divisor); } static void CollectOrdinalParts(List parts, ref int number, int divisor, GrammaticalGender gender, string prefixedForm, params string[] forms) { if (number < divisor) { return; } var result = number / divisor; number %= divisor; if (number == 0) { if (result == 1) { parts.Add(prefixedForm); } else { parts.Add(GetPrefix(result) + prefixedForm); } } else { CollectPartsUnderOneThousand(parts, result, gender); parts.Add(ChooseOneForGrammaticalNumber(result, forms)); } } static int GetIndex(RussianGrammaticalNumber number) { if (number == RussianGrammaticalNumber.Singular) { return 0; } if (number == RussianGrammaticalNumber.Paucal) { return 1; } return 2; } static string ChooseOneForGrammaticalNumber(long number, string[] forms) => forms[GetIndex(RussianGrammaticalNumberDetector.Detect(number))]; static string GetEndingForGender(GrammaticalGender gender, int number) { switch (gender) { case GrammaticalGender.Masculine: if (number == 3) { return "ій"; } return "ий"; case GrammaticalGender.Feminine: if (number == 3) { return "я"; } return "а"; case GrammaticalGender.Neuter: if (number == 3) { return "є"; } return "е"; default: throw new ArgumentOutOfRangeException(nameof(gender)); } } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/UzbekCyrlNumberToWordConverter.cs ================================================ namespace Humanizer; class UzbekCyrlNumberToWordConverter : GenderlessNumberToWordsConverter { static readonly string[] UnitsMap = ["нол", "бир", "икки", "уч", "тўрт", "беш", "олти", "етти", "саккиз", "тўққиз"]; static readonly string[] TensMap = ["нол", "ўн", "йигирма", "ўттиз", "қирқ", "эллик", "олтмиш", "етмиш", "саксон", "тўқсон"]; static readonly string[] OrdinalSuffixes = ["инчи", "нчи"]; public override string Convert(long input) { if (input is > int.MaxValue or < int.MinValue) { throw new NotImplementedException(); } var number = (int)input; if (number < 0) { return $"минус {Convert(-number, true)}"; } return Convert(number, true); } static string Convert(int number, bool checkForHundredRule) { if (number == 0) { return UnitsMap[0]; } if (checkForHundredRule && number == 100) { return "юз"; } var sb = new StringBuilder(); if (number / 1000000000 > 0) { sb.AppendFormat("{0} миллиард ", Convert(number / 1000000000, false)); number %= 1000000000; } if (number / 1000000 > 0) { sb.AppendFormat("{0} миллион ", Convert(number / 1000000, true)); number %= 1000000; } var thousand = number / 1000; if (thousand > 0) { sb.AppendFormat("{0} минг ", Convert(thousand, true)); number %= 1000; } var hundred = number / 100; if (hundred > 0) { sb.AppendFormat("{0} юз ", Convert(hundred, false)); number %= 100; } if (number / 10 > 0) { sb.AppendFormat("{0} ", TensMap[number / 10]); number %= 10; } if (number > 0) { sb.AppendFormat("{0} ", UnitsMap[number]); } return sb .ToString() .Trim(); } public override string ConvertToOrdinal(int number) { var word = Convert(number); var i = 0; if (string.IsNullOrEmpty(word)) { return string.Empty; } var lastChar = word[^1]; if (lastChar is 'и' or 'а') { i = 1; } return $"{word}{OrdinalSuffixes[i]}"; } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/UzbekLatnNumberToWordConverter.cs ================================================ namespace Humanizer; class UzbekLatnNumberToWordConverter : GenderlessNumberToWordsConverter { static readonly string[] UnitsMap = ["nol", "bir", "ikki", "uch", "to`rt", "besh", "olti", "yetti", "sakkiz", "to`qqiz"]; static readonly string[] TensMap = ["nol", "o`n", "yigirma", "o`ttiz", "qirq", "ellik", "oltmish", "yetmish", "sakson", "to`qson"]; static readonly string[] OrdinalSuffixes = ["inchi", "nchi"]; public override string Convert(long input) { if (input is > int.MaxValue or < int.MinValue) { throw new NotImplementedException(); } var number = (int)input; if (number < 0) { return $"minus {Convert(-number, true)}"; } return Convert(number, true); } static string Convert(int number, bool checkForHundredRule) { if (number == 0) { return UnitsMap[0]; } if (checkForHundredRule && number == 100) { return "yuz"; } var sb = new StringBuilder(); if (number / 1000000000 > 0) { sb.AppendFormat("{0} milliard ", Convert(number / 1000000000, false)); number %= 1000000000; } if (number / 1000000 > 0) { sb.AppendFormat("{0} million ", Convert(number / 1000000, true)); number %= 1000000; } var thousand = number / 1000; if (thousand > 0) { sb.AppendFormat("{0} ming ", Convert(thousand, true)); number %= 1000; } var hundred = number / 100; if (hundred > 0) { sb.AppendFormat("{0} yuz ", Convert(hundred, false)); number %= 100; } if (number / 10 > 0) { sb.AppendFormat("{0} ", TensMap[number / 10]); number %= 10; } if (number > 0) { sb.AppendFormat("{0} ", UnitsMap[number]); } return sb .ToString() .Trim(); } public override string ConvertToOrdinal(int number) { var word = Convert(number); var i = 0; if (string.IsNullOrEmpty(word)) { return string.Empty; } var lastChar = word[^1]; if (lastChar is 'i' or 'a') { i = 1; } return $"{word}{OrdinalSuffixes[i]}"; } } ================================================ FILE: src/Humanizer/Localisation/NumberToWords/VietnameseNumberToWordsConverter.cs ================================================ namespace Humanizer; class VietnameseNumberToWordsConverter : GenderlessNumberToWordsConverter { const int OneBillion = 1000000000; const int OneMillion = 1000000; static readonly string[] NumberVerbalPairs = [ "", "một", "hai", "ba", "bốn", "năm", "sáu", "bảy", "tám", "chín" ]; public override string Convert(long number) => number == 0 ? "không" : ConvertImpl(number); public override string ConvertToOrdinal(int number) => $"thứ {ConvertToOrdinalImpl(number)}"; string ConvertToOrdinalImpl(int number) => number switch { 1 => "nhất", 2 => "nhì", 4 => "tư", _ => Convert(number) }; static string ConvertImpl(long number, bool hasTens = false, bool isGreaterThanOneHundred = false) { if (number < 0) { return $"trừ {ConvertImpl(-number, hasTens, isGreaterThanOneHundred)}"; } if (number >= OneBillion) { return string.Format( "{0} tỉ {1}", ConvertImpl(number / OneBillion), ConvertImpl(number % OneBillion, isGreaterThanOneHundred: true) ) .TrimEnd(); } if (number >= OneMillion) { return string.Format( "{0} triệu {1}", ConvertImpl(number / OneMillion), ConvertImpl(number % OneMillion, isGreaterThanOneHundred: true) ) .TrimEnd(); } if (number >= 1000) { return string.Format( "{0} nghìn {1}", ConvertImpl(number / 1000), ConvertImpl(number % 1000, isGreaterThanOneHundred: true) ) .TrimEnd(); } if (number >= 100) { return string.Format( "{0} trăm {1}", NumberVerbalPairs[number / 100], ConvertImpl(number % 100, isGreaterThanOneHundred: true) ) .TrimEnd(); } if (number >= 20) { return string.Format( "{0} mươi {1}", NumberVerbalPairs[number / 10], ConvertImpl(number % 10, hasTens: true) ) .TrimEnd(); } if (number == 14) { return "mười bốn"; } if (number == 11) { return "mười một"; } if (number >= 10) { return $"mười {ConvertImpl(number % 10, hasTens: true)}".TrimEnd(); } if (number == 5 && hasTens) { return "lăm"; } if (number == 4 && hasTens) { return "tư"; } if (number == 1 && hasTens) { return "mốt"; } if (number > 0 && isGreaterThanOneHundred && !hasTens) { return $"linh {NumberVerbalPairs[number]}"; } return NumberVerbalPairs[number]; } } ================================================ FILE: src/Humanizer/Localisation/Ordinalizers/ArmenianOrdinalizer.cs ================================================ namespace Humanizer; class ArmenianOrdinalizer : DefaultOrdinalizer { public override string Convert(int number, string numberString) { if (number is 1 or -1) { return numberString + "-ին"; } return numberString + "-րդ"; } } ================================================ FILE: src/Humanizer/Localisation/Ordinalizers/AzerbaijaniOrdinalizer.cs ================================================ namespace Humanizer; class AzerbaijaniOrdinalizer : DefaultOrdinalizer { public override string Convert(int number, string numberString) => numberString + "."; } ================================================ FILE: src/Humanizer/Localisation/Ordinalizers/CatalanOrdinalizer.cs ================================================ namespace Humanizer; class CatalanOrdinalizer() : DefaultOrdinalizer { public override string Convert(int number, string numberString) => Convert(number, numberString, GrammaticalGender.Masculine, WordForm.Normal); public override string Convert(int number, string numberString, GrammaticalGender gender) => Convert(number, numberString, gender, WordForm.Normal); public override string Convert(int number, string numberString, GrammaticalGender gender, WordForm wordForm) { if (number is 0 or int.MinValue) { return "0"; } if (number < 0) { return Convert(-number, (-number).ToString(), gender); } if (gender == GrammaticalGender.Feminine) { return $"{numberString}a"; } if (number % 10 == 1 || number % 10 == 3) { return $"{numberString}r"; } if (number % 10 == 2) { return $"{numberString}n"; } if (number % 10 == 4) { return $"{numberString}t"; } return $"{numberString}è"; } } ================================================ FILE: src/Humanizer/Localisation/Ordinalizers/DefaultOrdinalizer.cs ================================================ namespace Humanizer; class DefaultOrdinalizer : IOrdinalizer { public virtual string Convert(int number, string numberString, GrammaticalGender gender) => Convert(number, numberString); public virtual string Convert(int number, string numberString) => numberString; public virtual string Convert(int number, string numberString, WordForm wordForm) => Convert(number, numberString, default, wordForm); public virtual string Convert(int number, string numberString, GrammaticalGender gender, WordForm wordForm) => Convert(number, numberString, gender); } ================================================ FILE: src/Humanizer/Localisation/Ordinalizers/DutchOrdinalizer.cs ================================================ namespace Humanizer; class DutchOrdinalizer : DefaultOrdinalizer { public override string Convert(int number, string numberString) => Convert(number, numberString, GrammaticalGender.Masculine); public override string Convert(int number, string numberString, GrammaticalGender gender) { // N/A in Dutch if (number == 0) { return "0"; } return numberString + "e"; } } ================================================ FILE: src/Humanizer/Localisation/Ordinalizers/EnglishOrdinalizer.cs ================================================ namespace Humanizer; class EnglishOrdinalizer : DefaultOrdinalizer { public override string Convert(int number, string numberString) { var nMod100 = number % 100; if (nMod100 is >= 11 and <= 20) { return numberString + "th"; } return (number % 10) switch { 1 => numberString + "st", 2 => numberString + "nd", 3 => numberString + "rd", _ => numberString + "th" }; } } ================================================ FILE: src/Humanizer/Localisation/Ordinalizers/FrenchOrdinalizer.cs ================================================ namespace Humanizer; class FrenchOrdinalizer : DefaultOrdinalizer { public override string Convert(int number, string numberString) => Convert(number, numberString, GrammaticalGender.Masculine); public override string Convert(int number, string numberString, GrammaticalGender gender) { if (number == 1) { if (gender == GrammaticalGender.Feminine) { return numberString + "ère"; } return numberString + "er"; } return numberString + "ème"; } } ================================================ FILE: src/Humanizer/Localisation/Ordinalizers/GermanOrdinalizer.cs ================================================ namespace Humanizer; class GermanOrdinalizer : DefaultOrdinalizer { public override string Convert(int number, string numberString) => numberString + "."; } ================================================ FILE: src/Humanizer/Localisation/Ordinalizers/HungarianOrdinalizer.cs ================================================ namespace Humanizer; class HungarianOrdinalizer : DefaultOrdinalizer { // In hungarian language ordinal numbers are marked with a dot "." at the end public override string Convert(int number, string numberString) => numberString + "."; } ================================================ FILE: src/Humanizer/Localisation/Ordinalizers/IOrdinalizer.cs ================================================ namespace Humanizer; /// /// The interface used to localise the Ordinalize method /// public interface IOrdinalizer { /// /// Ordinalizes the number /// string Convert(int number, string numberString); /// /// Ordinalizes the number to a locale's specific form. /// string Convert(int number, string numberString, WordForm wordForm); /// /// Ordinalizes the number using the provided grammatical gender /// string Convert(int number, string numberString, GrammaticalGender gender); /// /// Ordinalizes the number to a locale's specific form using the provided grammatical gender. /// string Convert(int number, string numberString, GrammaticalGender gender, WordForm wordForm); } ================================================ FILE: src/Humanizer/Localisation/Ordinalizers/IcelandicOrdinalizer.cs ================================================ namespace Humanizer; class IcelandicOrdinalizer : DefaultOrdinalizer { public override string Convert(int number, string numberString) => numberString + "."; } ================================================ FILE: src/Humanizer/Localisation/Ordinalizers/ItalianOrdinalizer.cs ================================================ namespace Humanizer; class ItalianOrdinalizer : DefaultOrdinalizer { public override string Convert(int number, string numberString) => Convert(number, numberString, GrammaticalGender.Masculine); public override string Convert(int number, string numberString, GrammaticalGender gender) { // No ordinal for 0 in italian (neologism apart) if (number == 0) { return "0"; } if (gender == GrammaticalGender.Feminine) { return numberString + "ª"; } return numberString + "°"; } } ================================================ FILE: src/Humanizer/Localisation/Ordinalizers/LuxembourgishOrdinalizer.cs ================================================ namespace Humanizer; class LuxembourgishOrdinalizer : DefaultOrdinalizer { public override string Convert(int number, string numberString) => numberString + "."; } ================================================ FILE: src/Humanizer/Localisation/Ordinalizers/PortugueseOrdinalizer.cs ================================================ namespace Humanizer; class PortugueseOrdinalizer : DefaultOrdinalizer { public override string Convert(int number, string numberString) => Convert(number, numberString, GrammaticalGender.Masculine); public override string Convert(int number, string numberString, GrammaticalGender gender) { // N/A in Portuguese if (number == 0) { return "0"; } if (gender == GrammaticalGender.Feminine) { return numberString + "ª"; } return numberString + "º"; } } ================================================ FILE: src/Humanizer/Localisation/Ordinalizers/RomanianOrdinalizer.cs ================================================ namespace Humanizer; class RomanianOrdinalizer : DefaultOrdinalizer { public override string Convert(int number, string numberString) => Convert(number, numberString, GrammaticalGender.Masculine); public override string Convert(int number, string numberString, GrammaticalGender gender) { // No ordinal for 0 (zero) in Romanian. if (number == 0) { return "0"; } // Exception from the rule. if (number == 1) { if (gender == GrammaticalGender.Feminine) { return "prima"; // întâia } return "primul"; // întâiul } if (gender == GrammaticalGender.Feminine) { return $"a {numberString}-a"; } return $"al {numberString}-lea"; } } ================================================ FILE: src/Humanizer/Localisation/Ordinalizers/RussianOrdinalizer.cs ================================================ namespace Humanizer; class RussianOrdinalizer : DefaultOrdinalizer { public override string Convert(int number, string numberString) => Convert(number, numberString, GrammaticalGender.Masculine); public override string Convert(int number, string numberString, GrammaticalGender gender) { if (gender == GrammaticalGender.Masculine) { return numberString + "-й"; } if (gender == GrammaticalGender.Feminine) { return numberString + "-я"; } return numberString + "-е"; } } ================================================ FILE: src/Humanizer/Localisation/Ordinalizers/SpanishOrdinalizer.cs ================================================ namespace Humanizer; class SpanishOrdinalizer(CultureInfo culture) : DefaultOrdinalizer { public override string Convert(int number, string numberString) => Convert(number, numberString, GrammaticalGender.Masculine, WordForm.Normal); public override string Convert(int number, string numberString, GrammaticalGender gender) => Convert(number, numberString, gender, WordForm.Normal); public override string Convert(int number, string numberString, GrammaticalGender gender, WordForm wordForm) { // N/A in Spanish if (number is 0 or int.MinValue) { return "0"; } if (number < 0) { return Convert(-number, GetNumberString(-number), gender); } return gender switch { GrammaticalGender.Masculine or GrammaticalGender.Neuter => numberString + GetWordForm(number, wordForm), GrammaticalGender.Feminine => numberString + ".ª", _ => throw new ArgumentOutOfRangeException(nameof(gender), gender, null), }; } string GetNumberString(int number) => number.ToString(culture); static string GetWordForm(int number, WordForm wordForm) => (number % 10 == 1 || number % 10 == 3) && wordForm == WordForm.Abbreviation ? ".er" : ".º"; } ================================================ FILE: src/Humanizer/Localisation/Ordinalizers/TurkishOrdinalizer.cs ================================================ namespace Humanizer; class TurkishOrdinalizer : DefaultOrdinalizer { public override string Convert(int number, string numberString) => numberString + "."; } ================================================ FILE: src/Humanizer/Localisation/Ordinalizers/UkrainianOrdinalizer.cs ================================================ namespace Humanizer; class UkrainianOrdinalizer : DefaultOrdinalizer { public override string Convert(int number, string numberString) => Convert(number, numberString, GrammaticalGender.Masculine); public override string Convert(int number, string numberString, GrammaticalGender gender) { if (gender == GrammaticalGender.Masculine) { return numberString + "-й"; } if (gender == GrammaticalGender.Feminine) { if (number % 10 == 3) { return numberString + "-я"; } return numberString + "-а"; } if (gender == GrammaticalGender.Neuter) { if (number % 10 == 3) { return numberString + "-є"; } } return numberString + "-е"; } } ================================================ FILE: src/Humanizer/Localisation/ResourceKeys.Common.cs ================================================ namespace Humanizer; public partial class ResourceKeys { static void ValidateRange(int count) { ArgumentOutOfRangeException.ThrowIfNegative(count, nameof(count)); } } ================================================ FILE: src/Humanizer/Localisation/ResourceKeys.DateHumanize.cs ================================================ namespace Humanizer; public partial class ResourceKeys { /// /// Encapsulates the logic required to get the resource keys for DateTime.Humanize /// public static class DateHumanize { /// /// Resource key for Now. /// public const string Now = "DateHumanize_Now"; /// /// Resource key for Never. /// public const string Never = "DateHumanize_Never"; /// /// Generates Resource Keys according to convention. /// /// Time unit /// Is time unit in future or past /// Number of units, default is One. /// Resource key, like DateHumanize_SingleMinuteAgo public static string GetResourceKey(TimeUnit timeUnit, Tense timeUnitTense, int count = 1) { ValidateRange(count); if (count == 0) { return Now; } if (count == 1) { if (timeUnitTense == Tense.Future) { return timeUnit switch { TimeUnit.Millisecond => "DateHumanize_SingleMillisecondFromNow", TimeUnit.Second => "DateHumanize_SingleSecondFromNow", TimeUnit.Minute => "DateHumanize_SingleMinuteFromNow", TimeUnit.Hour => "DateHumanize_SingleHourFromNow", TimeUnit.Day => "DateHumanize_SingleDayFromNow", TimeUnit.Week => "DateHumanize_SingleWeekFromNow", TimeUnit.Month => "DateHumanize_SingleMonthFromNow", TimeUnit.Year => "DateHumanize_SingleYearFromNow", _ => throw new ArgumentOutOfRangeException(nameof(timeUnit), timeUnit, null) }; } return timeUnit switch { TimeUnit.Millisecond => "DateHumanize_SingleMillisecondAgo", TimeUnit.Second => "DateHumanize_SingleSecondAgo", TimeUnit.Minute => "DateHumanize_SingleMinuteAgo", TimeUnit.Hour => "DateHumanize_SingleHourAgo", TimeUnit.Day => "DateHumanize_SingleDayAgo", TimeUnit.Week => "DateHumanize_SingleWeekAgo", TimeUnit.Month => "DateHumanize_SingleMonthAgo", TimeUnit.Year => "DateHumanize_SingleYearAgo", _ => throw new ArgumentOutOfRangeException(nameof(timeUnit), timeUnit, null) }; } if (timeUnitTense == Tense.Future) { return timeUnit switch { TimeUnit.Millisecond => "DateHumanize_MultipleMillisecondsFromNow", TimeUnit.Second => "DateHumanize_MultipleSecondsFromNow", TimeUnit.Minute => "DateHumanize_MultipleMinutesFromNow", TimeUnit.Hour => "DateHumanize_MultipleHoursFromNow", TimeUnit.Day => "DateHumanize_MultipleDaysFromNow", TimeUnit.Week => "DateHumanize_MultipleWeeksFromNow", TimeUnit.Month => "DateHumanize_MultipleMonthsFromNow", TimeUnit.Year => "DateHumanize_MultipleYearsFromNow", _ => throw new ArgumentOutOfRangeException(nameof(timeUnit), timeUnit, null) }; } return timeUnit switch { TimeUnit.Millisecond => "DateHumanize_MultipleMillisecondsAgo", TimeUnit.Second => "DateHumanize_MultipleSecondsAgo", TimeUnit.Minute => "DateHumanize_MultipleMinutesAgo", TimeUnit.Hour => "DateHumanize_MultipleHoursAgo", TimeUnit.Day => "DateHumanize_MultipleDaysAgo", TimeUnit.Week => "DateHumanize_MultipleWeeksAgo", TimeUnit.Month => "DateHumanize_MultipleMonthsAgo", TimeUnit.Year => "DateHumanize_MultipleYearsAgo", _ => throw new ArgumentOutOfRangeException(nameof(timeUnit), timeUnit, null) }; } } } ================================================ FILE: src/Humanizer/Localisation/ResourceKeys.TimeSpanHumanize.cs ================================================ namespace Humanizer; public partial class ResourceKeys { /// /// Encapsulates the logic required to get the resource keys for TimeSpan.Humanize /// Examples: TimeSpanHumanize_SingleMinute, TimeSpanHumanize_MultipleHours. /// public static class TimeSpanHumanize { /// /// Generates Resource Keys according to convention. /// /// Time unit, . /// Number of units, default is One. /// Result to words, default is false. /// Resource key, like TimeSpanHumanize_SingleMinute public static string GetResourceKey(TimeUnit unit, int count = 1, bool toWords = false) { ValidateRange(count); if (count == 0 && toWords) { return "TimeSpanHumanize_Zero"; } if (count == 1) { return unit switch { TimeUnit.Millisecond => "TimeSpanHumanize_SingleMillisecond", TimeUnit.Second => "TimeSpanHumanize_SingleSecond", TimeUnit.Minute => "TimeSpanHumanize_SingleMinute", TimeUnit.Hour => "TimeSpanHumanize_SingleHour", TimeUnit.Day => "TimeSpanHumanize_SingleDay", TimeUnit.Week => "TimeSpanHumanize_SingleWeek", TimeUnit.Month => "TimeSpanHumanize_SingleMonth", TimeUnit.Year => "TimeSpanHumanize_SingleYear", _ => throw new ArgumentOutOfRangeException(nameof(unit), unit, null) }; } return unit switch { TimeUnit.Millisecond => "TimeSpanHumanize_MultipleMilliseconds", TimeUnit.Second => "TimeSpanHumanize_MultipleSeconds", TimeUnit.Minute => "TimeSpanHumanize_MultipleMinutes", TimeUnit.Hour => "TimeSpanHumanize_MultipleHours", TimeUnit.Day => "TimeSpanHumanize_MultipleDays", TimeUnit.Week => "TimeSpanHumanize_MultipleWeeks", TimeUnit.Month => "TimeSpanHumanize_MultipleMonths", TimeUnit.Year => "TimeSpanHumanize_MultipleYears", _ => throw new ArgumentOutOfRangeException(nameof(unit), unit, null) }; } } } ================================================ FILE: src/Humanizer/Localisation/ResourceKeys.TimeUnitSymbol.cs ================================================ namespace Humanizer; public partial class ResourceKeys { /// /// Encapsulates the logic required to get the resource keys for TimeUnit.ToSymbol /// public static class TimeUnitSymbol { /// /// Generates Resource Keys according to convention. /// Examples: TimeUnit_Minute, TimeUnit_Hour. /// /// Time unit, . /// Resource key, like TimeSpanHumanize_SingleMinute public static string GetResourceKey(TimeUnit unit) => unit switch { TimeUnit.Millisecond => "TimeUnit_Millisecond", TimeUnit.Second => "TimeUnit_Second", TimeUnit.Minute => "TimeUnit_Minute", TimeUnit.Hour => "TimeUnit_Hour", TimeUnit.Day => "TimeUnit_Day", TimeUnit.Week => "TimeUnit_Week", TimeUnit.Month => "TimeUnit_Month", TimeUnit.Year => "TimeUnit_Year", _ => throw new ArgumentOutOfRangeException(nameof(unit), unit, null) }; } } ================================================ FILE: src/Humanizer/Localisation/Resources.cs ================================================ using System.Resources; namespace Humanizer; /// /// Provides access to the resources of Humanizer /// public static class Resources { static readonly ResourceManager ResourceManager = new("Humanizer.Properties.Resources", typeof(Resources).GetTypeInfo() .Assembly); /// /// Returns the value of the specified string resource /// /// The name of the resource to retrieve. /// The culture of the resource to retrieve. If not specified, current thread's UI culture is used. /// The value of the resource localized for the specified culture. public static string GetResource(string resourceKey, CultureInfo? culture = null) { // When an explicit culture is provided, we must ensure the exact culture's resource set // is loaded before falling back. In Blazor WebAssembly, satellite assemblies are loaded // lazily, and ResourceManager.GetString's fallback logic may cache an incorrect neutral // culture result before the satellite assembly loads. To prevent this, we: // 1) Load the exact culture's ResourceSet (createIfNotExists: true, tryParents: false) // 2) Only fall back to GetString if the exact culture's resource set doesn't contain the key string? resource = null; // Only attempt to load the exact culture's resource set when an explicit culture is provided // This preserves the previous behavior for callers that pass null (they fall through to GetString). if (culture != null) { // Load the exact culture's resource set without trying parents. // This ensures the satellite assembly is loaded in Blazor WebAssembly scenarios. var exactResourceSet = ResourceManager.GetResourceSet(culture, createIfNotExists: true, tryParents: false); resource = exactResourceSet?.GetString(resourceKey); } // If not found in the exact culture (or culture was null), use the standard GetString // which performs the full fallback chain and accepts null culture. resource ??= ResourceManager.GetString(resourceKey, culture); if (resource == null || string.IsNullOrEmpty(resource)) { throw new ArgumentException($@"The resource object with key '{resourceKey}' was not found", nameof(resourceKey)); } return resource; } /// /// Tries to get the value of the specified string resource, without fallback /// /// The name of the resource to retrieve. /// The culture of the resource to retrieve. If not specified, current thread's UI culture is used. /// The value of the resource localized for the specified culture if found; null otherwise. /// true if the specified string resource was found for the given culture; otherwise, false. public static bool TryGetResource(string resourceKey, CultureInfo? culture, [NotNullWhen(true)] out string? result) { culture ??= CultureInfo.CurrentUICulture; var resourceSet = ResourceManager.GetResourceSet(culture, createIfNotExists: false, tryParents: false); result = resourceSet?.GetString(resourceKey); return result is not null; } } ================================================ FILE: src/Humanizer/Localisation/Tense.cs ================================================ namespace Humanizer; /// /// Enumerates the possible time references; past or future. /// public enum Tense { Future, Past } ================================================ FILE: src/Humanizer/Localisation/TimeToClockNotation/BrazilianPortugueseTimeOnlyToClockNotationConverter.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; class BrazilianPortugueseTimeOnlyToClockNotationConverter : ITimeOnlyToClockNotationConverter { public string Convert(TimeOnly time, ClockNotationRounding roundToNearestFive) { switch (time) { case { Hour: 0, Minute: 0 }: return "meia-noite"; case { Hour: 12, Minute: 0 }: return "meio-dia"; } var normalizedHour = time.Hour % 12; var normalizedMinutes = (int)(roundToNearestFive == ClockNotationRounding.NearestFiveMinutes ? 5 * Math.Round(time.Minute / 5.0) : time.Minute); return normalizedMinutes switch { 00 => $"{normalizedHour.ToWords(GrammaticalGender.Feminine)} em ponto", 30 => $"{normalizedHour.ToWords(GrammaticalGender.Feminine)} e meia", 40 => $"vinte para as {(normalizedHour + 1).ToWords(GrammaticalGender.Feminine)}", 45 => $"quinze para as {(normalizedHour + 1).ToWords(GrammaticalGender.Feminine)}", 50 => $"dez para as {(normalizedHour + 1).ToWords(GrammaticalGender.Feminine)}", 55 => $"cinco para as {(normalizedHour + 1).ToWords(GrammaticalGender.Feminine)}", 60 => $"{(normalizedHour + 1).ToWords(GrammaticalGender.Feminine)} em ponto", _ => $"{normalizedHour.ToWords(GrammaticalGender.Feminine)} e {normalizedMinutes.ToWords()}" }; } } #endif ================================================ FILE: src/Humanizer/Localisation/TimeToClockNotation/CaTimeOnlyToClockNotationConverter.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; class CaTimeOnlyToClockNotationConverter : ITimeOnlyToClockNotationConverter { const int MORNING = 6; const int NOON = 12; const int AFTERNOON = 21; public string Convert(TimeOnly time, ClockNotationRounding roundToNearestFive) { switch (time) { case { Hour: 0, Minute: 0 }: return "mitjanit"; case { Hour: 12, Minute: 0 }: return "migdia"; } var article = GetArticle(time); var articleNextHour = GetArticle(time.AddHours(1)); var hour = NormalizeHour(time).ToWords(GrammaticalGender.Feminine); var nextHour = NormalizeHour(time.AddHours(1)).ToWords(GrammaticalGender.Feminine); var dayPeriod = GetDayPeriod(time); var dayPeriodNextHour = GetDayPeriod(time.AddHours(1)); var normalizedMinutes = (int)(roundToNearestFive == ClockNotationRounding.NearestFiveMinutes ? 5 * Math.Round(time.Minute / 5.0) : time.Minute); return normalizedMinutes switch { 0 => $"{article} {hour} {dayPeriod}", 15 => $"{article} {hour} i quart {dayPeriod}", 30 => $"{article} {hour} i mitja {dayPeriod}", 35 => $"{articleNextHour} {nextHour} menys vint-i-cinc {dayPeriodNextHour}", 40 => $"{articleNextHour} {nextHour} menys vint {dayPeriodNextHour}", 45 => $"{articleNextHour} {nextHour} menys quart {dayPeriodNextHour}", 50 => $"{articleNextHour} {nextHour} menys deu {dayPeriodNextHour}", 55 => $"{articleNextHour} {nextHour} menys cinc {dayPeriodNextHour}", 60 => $"{articleNextHour} {nextHour} {dayPeriodNextHour}", _ => $"{article} {hour} i {normalizedMinutes.ToWords()} {dayPeriod}" }; } static int NormalizeHour(TimeOnly time) => time.Hour % 12 != 0 ? time.Hour % 12 : 12; static string GetArticle(TimeOnly time) => time.Hour is 1 or 13 ? "la" : "les"; static string GetDayPeriod(TimeOnly time) { if (IsEarlyMorning(time)) { return "de la matinada"; } if (IsMorning(time)) { return "del matí"; } if (IsAfternoon(time)) { return "de la tarda"; } return "de la nit"; } static bool IsEarlyMorning(TimeOnly time) => time.Hour is >= 1 and < MORNING; static bool IsMorning(TimeOnly time) => time.Hour is >= MORNING and < NOON; static bool IsAfternoon(TimeOnly time) => time.Hour is >= NOON and < AFTERNOON; } #endif ================================================ FILE: src/Humanizer/Localisation/TimeToClockNotation/DefaultTimeOnlyToClockNotationConverter.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; class DefaultTimeOnlyToClockNotationConverter : ITimeOnlyToClockNotationConverter { public string Convert(TimeOnly time, ClockNotationRounding roundToNearestFive) { switch (time) { case { Hour: 0, Minute: 0 }: return "midnight"; case { Hour: 12, Minute: 0 }: return "noon"; } var normalizedHour = time.Hour % 12; var normalizedMinutes = (int)(roundToNearestFive == ClockNotationRounding.NearestFiveMinutes ? 5 * Math.Round(time.Minute / 5.0) : time.Minute); return normalizedMinutes switch { 00 => $"{normalizedHour.ToWords()} o'clock", 05 => $"five past {normalizedHour.ToWords()}", 10 => $"ten past {normalizedHour.ToWords()}", 15 => $"a quarter past {normalizedHour.ToWords()}", 20 => $"twenty past {normalizedHour.ToWords()}", 25 => $"twenty-five past {normalizedHour.ToWords()}", 30 => $"half past {normalizedHour.ToWords()}", 40 => $"twenty to {(normalizedHour + 1).ToWords()}", 45 => $"a quarter to {(normalizedHour + 1).ToWords()}", 50 => $"ten to {(normalizedHour + 1).ToWords()}", 55 => $"five to {(normalizedHour + 1).ToWords()}", 60 => $"{(normalizedHour + 1).ToWords()} o'clock", _ => $"{normalizedHour.ToWords()} {normalizedMinutes.ToWords()}" }; } } #endif ================================================ FILE: src/Humanizer/Localisation/TimeToClockNotation/EsTimeOnlyToClockNotationConverter.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; class EsTimeOnlyToClockNotationConverter : ITimeOnlyToClockNotationConverter { const int MORNING = 6; const int NOON = 12; const int AFTERNOON = 21; public string Convert(TimeOnly time, ClockNotationRounding roundToNearestFive) { switch (time) { case { Hour: 0, Minute: 0 }: return "medianoche"; case { Hour: 12, Minute: 0 }: return "mediodía"; } var article = GetArticle(time); var articleNextHour = GetArticle(time.AddHours(1)); var hour = NormalizeHour(time).ToWords(GrammaticalGender.Feminine); var nextHour = NormalizeHour(time.AddHours(1)).ToWords(GrammaticalGender.Feminine); var dayPeriod = GetDayPeriod(time); var dayPeriodNextHour = GetDayPeriod(time.AddHours(1)); var normalizedMinutes = (int)(roundToNearestFive == ClockNotationRounding.NearestFiveMinutes ? 5 * Math.Round(time.Minute / 5.0) : time.Minute); return normalizedMinutes switch { 0 => $"{article} {hour} {dayPeriod}", 15 => $"{article} {hour} y cuarto {dayPeriod}", 30 => $"{article} {hour} y media {dayPeriod}", 35 => $"{articleNextHour} {nextHour} menos veinticinco {dayPeriodNextHour}", 40 => $"{articleNextHour} {nextHour} menos veinte {dayPeriodNextHour}", 45 => $"{articleNextHour} {nextHour} menos cuarto {dayPeriodNextHour}", 50 => $"{articleNextHour} {nextHour} menos diez {dayPeriodNextHour}", 55 => $"{articleNextHour} {nextHour} menos cinco {dayPeriodNextHour}", 60 => $"{articleNextHour} {nextHour} {dayPeriodNextHour}", _ => $"{article} {hour} y {normalizedMinutes.ToWords()} {dayPeriod}" }; } static int NormalizeHour(TimeOnly time) => time.Hour % 12 != 0 ? time.Hour % 12 : 12; static string GetArticle(TimeOnly time) => time.Hour is 1 or 13 ? "la" : "las"; static string GetDayPeriod(TimeOnly time) { if (IsEarlyMorning(time)) { return "de la madrugada"; } if (IsMorning(time)) { return "de la mañana"; } if (IsAfternoon(time)) { return "de la tarde"; } return "de la noche"; } static bool IsEarlyMorning(TimeOnly time) => time.Hour is >= 1 and < MORNING; static bool IsMorning(TimeOnly time) => time.Hour is >= MORNING and < NOON; static bool IsAfternoon(TimeOnly time) => time.Hour is >= NOON and < AFTERNOON; } #endif ================================================ FILE: src/Humanizer/Localisation/TimeToClockNotation/FrTimeOnlyToClockNotationConverter.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; class FrTimeOnlyToClockNotationConverter : ITimeOnlyToClockNotationConverter { public string Convert(TimeOnly time, ClockNotationRounding roundToNearestFive) { var normalizedMinutes = (int)(roundToNearestFive == ClockNotationRounding.NearestFiveMinutes ? 5 * Math.Round(time.Minute / 5.0) : time.Minute); return normalizedMinutes switch { 00 => GetHourExpression(time.Hour), 60 => GetHourExpression(time.Hour + 1), _ => $"{GetHourExpression(time.Hour)} {normalizedMinutes.ToWords(GrammaticalGender.Feminine)}" }; static string GetHourExpression(int hour) => hour switch { 0 => "minuit", 12 => "midi", _ => hour.ToWords(GrammaticalGender.Feminine) + (hour > 1 ? " heures" : " heure") }; } } #endif ================================================ FILE: src/Humanizer/Localisation/TimeToClockNotation/GermanTimeOnlyToClockNotationConverter.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; class GermanTimeOnlyToClockNotationConverter : ITimeOnlyToClockNotationConverter { public string Convert(TimeOnly time, ClockNotationRounding roundToNearestFive) { switch (time) { case { Hour: 0, Minute: 0 }: return "zwölf Uhr nachts"; case { Hour: 12, Minute: 0 }: return "zwölf Uhr mittags"; } var normalizedHour = time.Hour % 12; var normalizedMinutes = (int)(roundToNearestFive == ClockNotationRounding.NearestFiveMinutes ? 5 * Math.Round(time.Minute / 5.0) : time.Minute); return normalizedMinutes switch { 00 => $"{normalizedHour.ToWords()} Uhr", 05 => $"fünf nach {normalizedHour.ToWords()}", 10 => $"zehn nach {normalizedHour.ToWords()}", 15 => $"viertel nach {normalizedHour.ToWords()}", 20 => $"zwanzig nach {normalizedHour.ToWords()}", 25 => $"fünf vor halb {(normalizedHour + 1).ToWords()}", 30 => $"halb {(normalizedHour + 1).ToWords()}", 35 => $"fünf nach halb {(normalizedHour + 1).ToWords()}", 40 => $"zwanzig vor {(normalizedHour + 1).ToWords()}", 45 => $"viertel vor {(normalizedHour + 1).ToWords()}", 50 => $"zehn vor {(normalizedHour + 1).ToWords()}", 55 => $"fünf vor {(normalizedHour + 1).ToWords()}", 60 => $"{(normalizedHour + 1).ToWords()} Uhr", _ => $"{normalizedHour.ToWords()} Uhr {normalizedMinutes.ToWords()}" }; } } #endif ================================================ FILE: src/Humanizer/Localisation/TimeToClockNotation/ITimeOnlyToClockNotationConverter.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; /// /// The interface used to localise the ToClockNotation method. /// public interface ITimeOnlyToClockNotationConverter { /// /// Converts the time to Clock Notation /// string Convert(TimeOnly time, ClockNotationRounding roundToNearestFive); } #endif ================================================ FILE: src/Humanizer/Localisation/TimeToClockNotation/LbTimeOnlyToClockNotationConverter.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; class LbTimeOnlyToClockNotationConverter : ITimeOnlyToClockNotationConverter { public string Convert(TimeOnly time, ClockNotationRounding roundToNearestFive) { var roundedTime = roundToNearestFive is ClockNotationRounding.NearestFiveMinutes ? GetRoundedTime(time) : time; return roundedTime switch { { Hour: 0, Minute: 0 } => "Mëtternuecht", { Hour: 12, Minute: 0 } => "Mëtteg", _ => roundedTime.Minute switch { 00 => GetHourExpression(roundedTime.Hour, "Auer"), 15 => $"Véirel op {GetHourExpression(roundedTime.Hour)}", 25 => $"{GetMinuteExpression(30 - roundedTime.Minute, "vir")} hallwer {GetHourExpression(roundedTime.Hour + 1)}", 30 => $"hallwer {GetHourExpression(roundedTime.Hour + 1)}", 35 => $"{GetMinuteExpression(roundedTime.Minute - 30, "op")} hallwer {GetHourExpression(roundedTime.Hour + 1)}", 45 => $"Véirel vir {GetHourExpression(roundedTime.Hour + 1)}", 60 => GetHourExpression(roundedTime.Hour + 1, "Auer"), 01 => $"{GetMinuteExpression(roundedTime.Minute, "Minutt")} op {GetHourExpression(roundedTime.Hour)}", 59 => $"{GetMinuteExpression(60 - roundedTime.Minute, "Minutt")} vir {GetHourExpression(roundedTime.Hour + 1)}", 05 or 10 or 20 => $"{GetMinuteExpression(roundedTime.Minute, "op")} {GetHourExpression(roundedTime.Hour)}", 40 or 50 or 55 => $"{GetMinuteExpression(60 - roundedTime.Minute, "vir")} {GetHourExpression(roundedTime.Hour + 1)}", > 00 and < 25 => $"{GetMinuteExpression(roundedTime.Minute, "Minutten")} op {GetHourExpression(roundedTime.Hour)}", > 25 and < 30 => $"{GetMinuteExpression(30 - roundedTime.Minute, "Minutten")} vir hallwer {GetHourExpression(roundedTime.Hour + 1)}", > 30 and < 35 => $"{GetMinuteExpression(roundedTime.Minute - 30, "Minutten")} op hallwer {GetHourExpression(roundedTime.Hour + 1)}", > 35 and < 60 => $"{GetMinuteExpression(60 - roundedTime.Minute, "Minutten")} vir {GetHourExpression(roundedTime.Hour + 1)}", _ => $"{GetHourExpression(time.Hour, "Auer")} {GetMinuteExpression(time.Minute)}" } }; } private static TimeOnly GetRoundedTime(TimeOnly time) { var tempRoundedMinutes = (int)(5 * Math.Round(time.Minute / 5.0)); var roundedHours = tempRoundedMinutes == 60 ? time.Hour + 1 : time.Hour; var roundedMinutes = tempRoundedMinutes == 60 ? 0 : tempRoundedMinutes; return new(roundedHours, roundedMinutes); } private static string GetMinuteExpression(int minute, string nextWord = "") => GetFormattedExpression(minute, nextWord); private static string GetHourExpression(int hour, string nextWord = "") { var normalizedHour = hour % 12; var hourExpression = normalizedHour == 0 ? 12 : normalizedHour; return GetFormattedExpression(hourExpression, nextWord); } private static string GetFormattedExpression(int number, string nextWord) => (number switch { 1 or 2 => $"{number.ToWords(GrammaticalGender.Feminine)} {nextWord}", 7 => $"{number.ToWords(LuxembourgishFormatter.DoesEifelerRuleApply(nextWord) ? WordForm.Eifeler : WordForm.Normal)} {nextWord}", _ => $"{number.ToWords()} {nextWord}" }).TrimEnd(); } #endif ================================================ FILE: src/Humanizer/Localisation/TimeToClockNotation/PortugueseTimeOnlyToClockNotationConverter.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; class PortugueseTimeOnlyToClockNotationConverter : ITimeOnlyToClockNotationConverter { public string Convert(TimeOnly time, ClockNotationRounding roundToNearestFive) { switch (time) { case { Hour: 0, Minute: 0 }: return "meia-noite"; case { Hour: 12, Minute: 0 }: return "meio-dia"; } var normalizedHour = time.Hour % 12; var normalizedMinutes = (int)(roundToNearestFive == ClockNotationRounding.NearestFiveMinutes ? 5 * Math.Round(time.Minute / 5.0) : time.Minute); return normalizedMinutes switch { 00 => $"{normalizedHour.ToWords(GrammaticalGender.Feminine)} horas", 15 => $"{normalizedHour.ToWords(GrammaticalGender.Feminine)} e um quarto", 30 => $"{normalizedHour.ToWords(GrammaticalGender.Feminine)} e meia", 40 => $"{(normalizedHour + 1).ToWords(GrammaticalGender.Feminine)} menos vinte", 45 => $"{(normalizedHour + 1).ToWords(GrammaticalGender.Feminine)} menos um quarto", 50 => $"{(normalizedHour + 1).ToWords(GrammaticalGender.Feminine)} menos dez", 55 => $"{(normalizedHour + 1).ToWords(GrammaticalGender.Feminine)} menos cinco", 60 => $"{(normalizedHour + 1).ToWords(GrammaticalGender.Feminine)} horas", _ => $"{normalizedHour.ToWords(GrammaticalGender.Feminine)} e {normalizedMinutes.ToWords()}" }; } } #endif ================================================ FILE: src/Humanizer/Localisation/TimeUnit.cs ================================================ namespace Humanizer; public enum TimeUnit { Millisecond, Second, Minute, Hour, Day, Week, Month, Year } ================================================ FILE: src/Humanizer/Localisation/WordsToNumber/DefaultWordsToNumberConverter.cs ================================================ namespace Humanizer; internal class DefaultWordsToNumberConverter(CultureInfo culture) : GenderlessWordsToNumberConverter { private readonly CultureInfo cultureInfo = culture; public override int Convert(string words) { TryConvert(words, out var parsedValue); return parsedValue; } public override bool TryConvert(string words, out int parsedValue) => TryConvert(words, out parsedValue, out _); public override bool TryConvert(string words, out int parsedValue, out string? unrecognizedWord) { if (cultureInfo.TwoLetterISOLanguageName == "en") { return new EnglishWordsToNumberConverter().TryConvert(words, out parsedValue, out unrecognizedWord); } throw new NotSupportedException($"Words-to-number conversion is not supported for '{cultureInfo.TwoLetterISOLanguageName}'."); } } ================================================ FILE: src/Humanizer/Localisation/WordsToNumber/EnglishWordsToNumberConverter.cs ================================================ namespace Humanizer; internal partial class EnglishWordsToNumberConverter : GenderlessWordsToNumberConverter { private const string OrdinalSuffixPattern = @"\b(\d+)(st|nd|rd|th)\b"; #if NET7_0_OR_GREATER [GeneratedRegex(OrdinalSuffixPattern)] private static partial Regex OrdinalSuffixRegexGenerated(); private static Regex OrdinalSuffixRegex() => OrdinalSuffixRegexGenerated(); #else private static readonly Regex OrdinalSuffixRegexField = new(OrdinalSuffixPattern, RegexOptions.Compiled); private static Regex OrdinalSuffixRegex() => OrdinalSuffixRegexField; #endif private static readonly FrozenDictionary NumbersMap = new Dictionary { {"zero",0}, {"one",1}, {"two",2}, {"three",3}, {"four",4}, {"five",5}, {"six",6}, {"seven",7}, {"eight",8}, {"nine",9}, {"ten",10}, {"eleven",11}, {"twelve",12}, {"thirteen",13}, {"fourteen",14}, {"fifteen",15}, {"sixteen",16}, {"seventeen",17}, {"eighteen",18}, {"nineteen",19}, {"twenty", 20}, {"thirty", 30}, {"forty", 40}, {"fifty", 50}, {"sixty", 60}, {"seventy", 70}, {"eighty", 80}, {"ninety", 90}, {"hundred", 100}, {"thousand", 1000}, {"million", 1_000_000}, {"billion", 1_000_000_000} }.ToFrozenDictionary(); private static readonly FrozenDictionary OrdinalsMap = new Dictionary { {"first",1}, {"second",2}, {"third",3}, {"fourth",4}, {"fifth",5}, {"sixth",6}, {"seventh",7}, {"eighth",8}, {"ninth",9}, {"tenth",10}, {"eleventh",11}, {"twelfth",12}, {"thirteenth",13}, {"fourteenth",14}, {"fifteenth",15}, {"sixteenth",16}, {"seventeenth",17}, {"eighteenth",18}, {"nineteenth",19}, {"twentieth",20}, {"thirtieth",30}, {"fortieth",40}, {"fiftieth",50}, {"sixtieth",60}, {"seventieth",70}, {"eightieth",80}, {"ninetieth",90}, {"hundredth",100}, {"thousandth",1000} }.ToFrozenDictionary(); public override int Convert(string words) { if (!TryConvert(words, out var result, out var unrecognizedword)) { throw new ArgumentException($"Unrecognized number word: {unrecognizedword}"); } return result; } public override bool TryConvert(string words, out int result) => TryConvert(words, out result, out _); public override bool TryConvert(string words, out int parsedValue, out string? unrecognizedWord) { if (string.IsNullOrWhiteSpace(words)) { throw new ArgumentException("Input words cannot be empty."); } unrecognizedWord = null; words = words.Replace(",", "") .Replace(" and ", " ") .ToLowerInvariant() .Trim(); var isNegative = words.StartsWith("minus ") || words.StartsWith("negative "); if (isNegative) { words = words.Replace("minus ", "").Replace("negative ", "").Trim(); } // Remove ordinal suffixes (st, nd, rd, th) words = OrdinalSuffixRegex().Replace(words, "$1"); words = words.Replace("-", " "); if (int.TryParse(words, out var numericValue)) { parsedValue = isNegative ? -numericValue : numericValue; return true; } if (OrdinalsMap.TryGetValue(words, out var ordinalValue)) { parsedValue = isNegative ? -ordinalValue : ordinalValue; return true; } if (TryConvertWordsToNumber(words, out var numberValue, out var unrecognizedNumberWord)) { parsedValue = isNegative ? -numberValue : numberValue; return true; } unrecognizedWord = unrecognizedNumberWord; parsedValue = default; return false; } private static bool TryConvertWordsToNumber(string words, out int result, out string? unrecognizedWord) { var wordsArray = words.Split(' ', StringSplitOptions.RemoveEmptyEntries); result = 0; unrecognizedWord = null; var current = 0; var hasOrdinal = false; foreach (var word in wordsArray) { if (OrdinalsMap.TryGetValue(word, out var ordinalValue)) { result += current + ordinalValue; hasOrdinal = true; break; // Stop processing after an ordinal } if (!NumbersMap.TryGetValue(word, out var value)) { unrecognizedWord = word; return false; } if (value == 100) { current = (current == 0 ? 1 : current) * 100; } else if (value >= 1000) { result += (current == 0 ? 1 : current) * value; current = 0; } else { current += value; } } if (!hasOrdinal) { result += current; } return true; } } ================================================ FILE: src/Humanizer/Localisation/WordsToNumber/GenderlessWordsToNumberConverter.cs ================================================ namespace Humanizer; internal abstract class GenderlessWordsToNumberConverter : IWordsToNumberConverter { public abstract int Convert(string words); public abstract bool TryConvert(string words, out int parsedValue); public abstract bool TryConvert(string words, out int parsedValue, out string? unrecognizedNumber); } ================================================ FILE: src/Humanizer/Localisation/WordsToNumber/IWordsToNumberConverter.cs ================================================ namespace Humanizer; public interface IWordsToNumberConverter { bool TryConvert(string words, out int parsedValue); bool TryConvert(string words, out int parsedValue, out string? unrecognizedNumber); int Convert(string words); } ================================================ FILE: src/Humanizer/MetricNumeralExtensions.cs ================================================ // Wrote by Alois de Gouvello https://github.com/aloisdg // The MIT License (MIT) // Copyright (c) 2015 Alois de Gouvello // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in // the Software without restriction, including without limitation the rights to // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of // the Software, and to permit persons to whom the Software is furnished to do so, // subject to the following conditions: // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. namespace Humanizer; /// /// Contains extension methods for changing a number to Metric representation (ToMetric) /// and from Metric representation back to the number (FromMetric) /// public static class MetricNumeralExtensions { const int Limit = 27; static readonly double BigLimit = Math.Pow(10, Limit); static readonly double SmallLimit = Math.Pow(10, -Limit); /// /// Symbols is a list of every symbols for the Metric system. /// static readonly List[] Symbols = [ ['k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'], ['m', 'μ', 'n', 'p', 'f', 'a', 'z', 'y'] ]; /// /// UnitPrefixes link a Metric symbol (as key) to its prefix (as value). /// /// /// We dont support : /// {'h', "hecto"}, /// {'da', "deca" }, // !string /// {'d', "deci" }, /// {'c', "centi"}, /// static readonly FrozenDictionary UnitPrefixes = new Dictionary { { 'Y', new("yotta", "septillion", "quadrillion") }, { 'Z', new("zetta", "sextillion", "trilliard") }, { 'E', new("exa", "quintillion", "trillion") }, { 'P', new("peta", "quadrillion", "billiard") }, { 'T', new("tera", "trillion", "billion") }, { 'G', new("giga", "billion", "milliard") }, { 'M', new("mega", "million") }, { 'k', new("kilo", "thousand") }, { 'm', new("milli", "thousandth") }, { 'μ', new("micro", "millionth") }, { 'n', new("nano", "billionth", "milliardth") }, { 'p', new("pico", "trillionth", "billionth") }, { 'f', new("femto", "quadrillionth", "billiardth") }, { 'a', new("atto", "quintillionth", "trillionth") }, { 'z', new("zepto", "sextillionth", "trilliardth") }, { 'y', new("yocto", "septillionth", "quadrillionth") } }.ToFrozenDictionary(); /// /// Converts a Metric representation into a number. /// /// /// We don't support input in the format {number}{name} nor {number} {name}. /// We only provide a solution for {number}{symbol} and {number} {symbol}. /// /// Metric representation to convert to a number /// /// /// "1k".FromMetric() => 1000d /// "123".FromMetric() => 123d /// "100m".FromMetric() => 1E-1 /// /// /// A number after a conversion from a Metric representation. public static double FromMetric(this string input) { input = CleanRepresentation(input); return BuildNumber(input, input[^1]); } /// /// Converts a number into a valid and Human-readable Metric representation. /// /// /// Inspired by a snippet from Thom Smith. /// See this link for more. /// /// Number to convert to a Metric representation. /// A bitwise combination of enumeration values that format the metric representation. /// If not null it is the numbers of decimals to round the number to /// /// /// 1000.ToMetric() => "1k" /// 123.ToMetric() => "123" /// 1E-1.ToMetric() => "100m" /// /// /// A valid Metric representation public static string ToMetric(this int input, MetricNumeralFormats? formats = null, int? decimals = null) => ((double)input).ToMetric(formats, decimals); /// /// Converts a number into a valid and Human-readable Metric representation. /// /// /// Inspired by a snippet from Thom Smith. /// See this link for more. /// /// Number to convert to a Metric representation. /// A bitwise combination of enumeration values that format the metric representation. /// If not null it is the numbers of decimals to round the number to /// /// /// 1000.ToMetric() => "1k" /// 123.ToMetric() => "123" /// 1E-1.ToMetric() => "100m" /// /// /// A valid Metric representation public static string ToMetric(this long input, MetricNumeralFormats? formats = null, int? decimals = null) { if (input.Equals(0) && (!decimals.HasValue || (decimals == 0))) { return input.ToString(); } return BuildRepresentation(input, formats, decimals); } /// /// Converts a number into a valid and Human-readable Metric representation. /// /// /// Inspired by a snippet from Thom Smith. /// See this link for more. /// /// Number to convert to a Metric representation. /// A bitwise combination of enumeration values that format the metric representation. /// If not null it is the numbers of decimals to round the number to /// /// /// 1000d.ToMetric() => "1k" /// 123d.ToMetric() => "123" /// 1E-1.ToMetric() => "100m" /// /// /// A valid Metric representation public static string ToMetric(this double input, MetricNumeralFormats? formats = null, int? decimals = null) { if (input.Equals(0)) { return input.ToString(); } if (input.IsOutOfRange()) { throw new ArgumentOutOfRangeException(nameof(input)); } return BuildRepresentation(input, formats, decimals); } /// /// Clean or handle any wrong input /// /// Metric representation to clean /// A cleaned representation static string CleanRepresentation(string input) { ArgumentNullException.ThrowIfNull(input); input = input.Trim(); input = ReplaceNameBySymbol(input); if (input.Length == 0 || input.IsInvalidMetricNumeral()) { throw new ArgumentException("Empty or invalid Metric string.", nameof(input)); } return input.Replace(" ", string.Empty); } /// /// Build a number from a metric representation or from a number /// /// A Metric representation to parse to a number /// The last character of input /// A number build from a Metric representation static double BuildNumber(string input, char last) => char.IsLetter(last) ? BuildMetricNumber(input, last) : double.Parse(input); /// /// Build a number from a metric representation /// /// A Metric representation to parse to a number /// The last character of input /// A number build from a Metric representation static double BuildMetricNumber(string input, char last) { var number = double.Parse(input[..^1]); var indexInPositive = Symbols[0].IndexOf(last); if (indexInPositive >= 0) { var exponent = (indexInPositive + 1) * 3.0; return number * Math.Pow(10, exponent); } else { var indexInNegative = Symbols[1].IndexOf(last); var exponent = (indexInNegative + 1) * 3.0; return number * Math.Pow(10, -exponent); } } /// /// Replace every symbol's name by its symbol representation. /// /// Metric representation with a name or a symbol /// A metric representation with a symbol static string ReplaceNameBySymbol(string input) => UnitPrefixes.Aggregate(input, (current, unitPrefix) => current.Replace(unitPrefix.Value.Name, unitPrefix.Key.ToString())); /// /// Build a Metric representation of the number. /// /// Number to convert to a Metric representation. /// A bitwise combination of enumeration values that format the metric representation. /// If not null it is the numbers of decimals to round the number to /// A number in a Metric representation static string BuildRepresentation(long input, MetricNumeralFormats? formats, int? decimals) { var number = Math.Abs(input / 10); var exponent = 0; while (number > 0) { exponent++; number /= 10; } var scale = exponent / 3; if (!scale.Equals(0)) { return BuildMetricRepresentation(input, scale, formats, decimals); } var representation = decimals > 0 ? $"{input}.{new string('0', decimals.Value)}" : input.ToString(); var space = (formats & MetricNumeralFormats.WithSpace) == MetricNumeralFormats.WithSpace ? " " : string.Empty; return representation + space; } /// /// Build a Metric representation of the number. /// /// Number to convert to a Metric representation. /// Number of times number should be divided by 1000. /// A bitwise combination of enumeration values that format the metric representation. /// If not null it is the numbers of decimals to round the number to /// A number in a Metric representation static string BuildMetricRepresentation(long input, int scale, MetricNumeralFormats? formats, int? decimals) { // Convert back to actual exponent (number of 10s places) var exponent = scale * 3; var divisor = 1L; for (var i = 0; i < scale; i++) { divisor *= 1000; } var number = input / divisor; var fractionalPart = Math.Abs(input % divisor); // input could be negative if (Math.Abs(number) >= 1000 && exponent < Symbols[0].Count * 3) { exponent += 3; scale++; divisor *= 1000; number = input / divisor; fractionalPart = Math.Abs(input % divisor); } if (decimals.HasValue) { for (var i = decimals.Value; i < exponent; i++) { var roundUp = (i + 1 == exponent); fractionalPart = (fractionalPart + (roundUp ? 5 : 0)) / 10; } } else { decimals = exponent; } var symbol = Math.Sign(scale) == 1 ? Symbols[0][scale - 1] : Symbols[1][-scale - 1]; if (decimals == 0) { var space = formats.HasValue && formats.Value.HasFlag(MetricNumeralFormats.WithSpace) ? " " : string.Empty; return number + space + GetUnitText(symbol, formats); } else { var decimalPlaces = Math.Min(decimals.Value, exponent); var extraZeroes = (decimals.Value - decimalPlaces); var space = formats.HasValue && formats.Value.HasFlag(MetricNumeralFormats.WithSpace) ? " " : string.Empty; return number + CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator + fractionalPart.ToString("d" + decimalPlaces) + (extraZeroes <= 0 ? string.Empty : new string('0', extraZeroes)) + space + GetUnitText(symbol, formats); } } /// /// Build a Metric representation of the number. /// /// Number to convert to a Metric representation. /// A bitwise combination of enumeration values that format the metric representation. /// If not null it is the numbers of decimals to round the number to /// A number in a Metric representation static string BuildRepresentation(double input, MetricNumeralFormats? formats, int? decimals) { var exponent = (int)Math.Floor(Math.Log10(Math.Abs(input)) / 3); if (!exponent.Equals(0)) { return BuildMetricRepresentation(input, exponent, formats, decimals); } var representation = decimals.HasValue ? Math .Round(input, decimals.Value) .ToString() : input.ToString(); var space = (formats & MetricNumeralFormats.WithSpace) == MetricNumeralFormats.WithSpace ? " " : string.Empty; return representation + space; } /// /// Build a Metric representation of the number. /// /// Number to convert to a Metric representation. /// Exponent of the number in a scientific notation /// A bitwise combination of enumeration values that format the metric representation. /// If not null it is the numbers of decimals to round the number to /// A number in a Metric representation static string BuildMetricRepresentation(double input, int exponent, MetricNumeralFormats? formats, int? decimals) { var number = input * Math.Pow(1000, -exponent); if (decimals.HasValue) { number = Math.Round(number, decimals.Value); } if (Math.Abs(number) >= 1000 && exponent < Symbols[0].Count) { number /= 1000; exponent += 1; } var symbol = Math.Sign(exponent) == 1 ? Symbols[0][exponent - 1] : Symbols[1][-exponent - 1]; var space = formats.HasValue && formats.Value.HasFlag(MetricNumeralFormats.WithSpace) ? " " : string.Empty; return number.ToString("G15") + space + GetUnitText(symbol, formats); } /// /// Get the unit from a symbol of from the symbol's name. /// /// The symbol linked to the unit /// A bitwise combination of enumeration values that format the metric representation. /// A symbol, a symbol's name, a symbol's short scale word or a symbol's long scale word static string GetUnitText(char symbol, MetricNumeralFormats? formats) { if (formats.HasValue) { var formatValue = formats.Value; if (formatValue.HasFlag(MetricNumeralFormats.UseName)) { return UnitPrefixes[symbol].Name; } if (formatValue.HasFlag(MetricNumeralFormats.UseShortScaleWord)) { return UnitPrefixes[symbol].ShortScaleWord; } if (formatValue.HasFlag(MetricNumeralFormats.UseLongScaleWord)) { return UnitPrefixes[symbol].LongScaleWord; } } return symbol.ToString(); } /// /// Check if a Metric representation is out of the valid range. /// /// A Metric representation that may be out of the valid range. /// True if input is out of the valid range. static bool IsOutOfRange(this double input) { bool outside(double min, double max) => !(max > input && input > min); return (Math.Sign(input) == 1 && outside(SmallLimit, BigLimit)) || (Math.Sign(input) == -1 && outside(-BigLimit, -SmallLimit)); } /// /// Check if a string is not a valid Metric representation. /// A valid representation is in the format "{0}{1}" or "{0} {1}" /// where {0} is a number and {1} is an allowed symbol. /// /// /// ToDo: Performance: Use (string input, out number) to escape the double use of Parse() /// /// >A string that may contain an invalid Metric representation. /// True if input is not a valid Metric representation. static bool IsInvalidMetricNumeral(this string input) { var index = input.Length - 1; var last = input[index]; var isSymbol = UnitPrefixes.ContainsKey(last); return !double.TryParse(isSymbol ? input[..index] : input, out _); } struct UnitPrefix(string name, string shortScaleWord, string? longScaleWord = null) { public string Name { get; } = name; public string ShortScaleWord { get; } = shortScaleWord; public readonly string LongScaleWord => longScaleWord ?? ShortScaleWord; } } ================================================ FILE: src/Humanizer/MetricNumeralFormats.cs ================================================ namespace Humanizer; /// /// Flags for formatting the metric representation of numerals. /// [Flags] public enum MetricNumeralFormats { /// /// Use the metric prefix long scale word. /// UseLongScaleWord = 1, /// /// Use the metric prefix name instead of the symbol. /// UseName = 2, /// /// Use the metric prefix short scale word. /// UseShortScaleWord = 4, /// /// Include a space after the numeral. /// WithSpace = 8 } ================================================ FILE: src/Humanizer/NoMatchFoundException.cs ================================================ namespace Humanizer; /// /// This is thrown on String.DehumanizeTo enum when the provided string cannot be mapped to the target enum /// #pragma warning disable 1591 public class NoMatchFoundException : Exception { public NoMatchFoundException() { } public NoMatchFoundException(string message) : base(message) { } public NoMatchFoundException(string message, Exception inner) : base(message, inner) { } } #pragma warning restore 1591 ================================================ FILE: src/Humanizer/NumberToNumberExtensions.cs ================================================ using System.Runtime.CompilerServices; namespace Humanizer; /// /// Number to Number extensions /// public static class NumberToNumberExtensions { /// /// Multiplies an integer by 10, providing a more readable way to express multiples of ten in code. /// /// The integer value to multiply by 10. /// The input value multiplied by 10. /// /// /// 5.Tens() => 50 /// 3.Tens() => 30 /// 10.Tens() => 100 /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Tens(this int input) => input * 10; /// /// Multiplies an unsigned integer by 10, providing a more readable way to express multiples of ten in code. /// /// The unsigned integer value to multiply by 10. /// The input value multiplied by 10. /// /// /// 5U.Tens() => 50U /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Tens(this uint input) => input * 10; /// /// Multiplies a long integer by 10, providing a more readable way to express multiples of ten in code. /// /// The long integer value to multiply by 10. /// The input value multiplied by 10. /// /// /// 5L.Tens() => 50L /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Tens(this long input) => input * 10; /// /// Multiplies an unsigned long integer by 10, providing a more readable way to express multiples of ten in code. /// /// The unsigned long integer value to multiply by 10. /// The input value multiplied by 10. /// /// /// 5UL.Tens() => 50UL /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Tens(this ulong input) => input * 10; /// /// Multiplies a double by 10, providing a more readable way to express multiples of ten in code. /// /// The double value to multiply by 10. /// The input value multiplied by 10. /// /// /// 5.5.Tens() => 55.0 /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Tens(this double input) => input * 10; /// /// Multiplies an integer by 100, providing a more readable way to express hundreds in code. /// /// The integer value to multiply by 100. /// The input value multiplied by 100. /// /// /// 4.Hundreds() => 400 /// 2.Hundreds() => 200 /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Hundreds(this int input) => input * 100; /// /// Multiplies an unsigned integer by 100, providing a more readable way to express hundreds in code. /// /// The unsigned integer value to multiply by 100. /// The input value multiplied by 100. /// /// /// 4U.Hundreds() => 400U /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Hundreds(this uint input) => input * 100; /// /// Multiplies a long integer by 100, providing a more readable way to express hundreds in code. /// /// The long integer value to multiply by 100. /// The input value multiplied by 100. /// /// /// 4L.Hundreds() => 400L /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Hundreds(this long input) => input * 100; /// /// Multiplies an unsigned long integer by 100, providing a more readable way to express hundreds in code. /// /// The unsigned long integer value to multiply by 100. /// The input value multiplied by 100. /// /// /// 4UL.Hundreds() => 400UL /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Hundreds(this ulong input) => input * 100; /// /// Multiplies a double by 100, providing a more readable way to express hundreds in code. /// /// The double value to multiply by 100. /// The input value multiplied by 100. /// /// /// 4.0.Hundreds() => 400.0 /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Hundreds(this double input) => input * 100; /// /// Multiplies an integer by 1000, providing a more readable way to express thousands in code. /// /// The integer value to multiply by 1000. /// The input value multiplied by 1000. /// /// /// 3.Thousands() => 3000 /// 10.Thousands() => 10000 /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Thousands(this int input) => input * 1000; /// /// Multiplies an unsigned integer by 1000, providing a more readable way to express thousands in code. /// /// The unsigned integer value to multiply by 1000. /// The input value multiplied by 1000. /// /// /// 3U.Thousands() => 3000U /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Thousands(this uint input) => input * 1000; /// /// Multiplies a long integer by 1000, providing a more readable way to express thousands in code. /// /// The long integer value to multiply by 1000. /// The input value multiplied by 1000. /// /// /// 3L.Thousands() => 3000L /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Thousands(this long input) => input * 1000; /// /// Multiplies an unsigned long integer by 1000, providing a more readable way to express thousands in code. /// /// The unsigned long integer value to multiply by 1000. /// The input value multiplied by 1000. /// /// /// 3UL.Thousands() => 3000UL /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Thousands(this ulong input) => input * 1000; /// /// Multiplies a double by 1000, providing a more readable way to express thousands in code. /// /// The double value to multiply by 1000. /// The input value multiplied by 1000. /// /// /// 3.0.Thousands() => 3000.0 /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Thousands(this double input) => input * 1000; /// /// Multiplies an integer by 1,000,000, providing a more readable way to express millions in code. /// /// The integer value to multiply by 1,000,000. /// The input value multiplied by 1,000,000. /// /// /// 2.Millions() => 2000000 /// 5.Millions() => 5000000 /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Millions(this int input) => input * 1000000; /// /// Multiplies an unsigned integer by 1,000,000, providing a more readable way to express millions in code. /// /// The unsigned integer value to multiply by 1,000,000. /// The input value multiplied by 1,000,000. /// /// /// 2U.Millions() => 2000000U /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Millions(this uint input) => input * 1000000; /// /// Multiplies a long integer by 1,000,000, providing a more readable way to express millions in code. /// /// The long integer value to multiply by 1,000,000. /// The input value multiplied by 1,000,000. /// /// /// 2L.Millions() => 2000000L /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Millions(this long input) => input * 1000000; /// /// Multiplies an unsigned long integer by 1,000,000, providing a more readable way to express millions in code. /// /// The unsigned long integer value to multiply by 1,000,000. /// The input value multiplied by 1,000,000. /// /// /// 2UL.Millions() => 2000000UL /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Millions(this ulong input) => input * 1000000; /// /// Multiplies a double by 1,000,000, providing a more readable way to express millions in code. /// /// The double value to multiply by 1,000,000. /// The input value multiplied by 1,000,000. /// /// /// 2.0.Millions() => 2000000.0 /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Millions(this double input) => input * 1000000; /// /// Multiplies an integer by 1,000,000,000 (one billion in short scale), providing a more readable way to express billions in code. /// /// The integer value to multiply by 1,000,000,000. /// The input value multiplied by 1,000,000,000. /// /// /// 1.Billions() => 1000000000 /// 2.Billions() => 2000000000 /// /// /// /// Uses the short scale definition where 1 billion = 1,000,000,000 (10^9). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Billions(this int input) => input * 1000000000; /// /// Multiplies an unsigned integer by 1,000,000,000 (one billion in short scale), providing a more readable way to express billions in code. /// /// The unsigned integer value to multiply by 1,000,000,000. /// The input value multiplied by 1,000,000,000. /// /// Uses the short scale definition where 1 billion = 1,000,000,000 (10^9). /// /// /// /// 1U.Billions() => 1000000000U /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Billions(this uint input) => input * 1000000000; /// /// Multiplies a long integer by 1,000,000,000 (one billion in short scale), providing a more readable way to express billions in code. /// /// The long integer value to multiply by 1,000,000,000. /// The input value multiplied by 1,000,000,000. /// /// Uses the short scale definition where 1 billion = 1,000,000,000 (10^9). /// /// /// /// 1L.Billions() => 1000000000L /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Billions(this long input) => input * 1000000000; /// /// Multiplies an unsigned long integer by 1,000,000,000 (one billion in short scale), providing a more readable way to express billions in code. /// /// The unsigned long integer value to multiply by 1,000,000,000. /// The input value multiplied by 1,000,000,000. /// /// Uses the short scale definition where 1 billion = 1,000,000,000 (10^9). /// /// /// /// 1UL.Billions() => 1000000000UL /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Billions(this ulong input) => input * 1000000000; /// /// Multiplies a double by 1,000,000,000 (one billion in short scale), providing a more readable way to express billions in code. /// /// The double value to multiply by 1,000,000,000. /// The input value multiplied by 1,000,000,000. /// /// Uses the short scale definition where 1 billion = 1,000,000,000 (10^9). /// /// /// /// 1.0.Billions() => 1000000000.0 /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Billions(this double input) => input * 1000000000; } ================================================ FILE: src/Humanizer/NumberToTimeSpanExtensions.cs ================================================ namespace Humanizer; /// /// Provides extension methods for converting numeric values to instances, /// enabling fluent and readable time duration creation (e.g., 5.Seconds(), 3.Hours(), 2.Weeks()). /// /// /// These extensions make it easy to create TimeSpan values in a more natural, readable way: /// - Instead of TimeSpan.FromHours(3), you can write 3.Hours() /// - Instead of TimeSpan.FromMinutes(30), you can write 30.Minutes() /// - Supports all numeric types: byte, sbyte, short, ushort, int, uint, long, ulong, and double /// - Weeks are converted to days (1 week = 7 days) /// public static class NumberToTimeSpanExtensions { /// /// Creates a representing the specified number of milliseconds. /// /// The number of milliseconds. /// A representing milliseconds. /// /// /// 500.Milliseconds() => TimeSpan representing 500 milliseconds /// 1000.Milliseconds() => TimeSpan representing 1 second /// /// public static TimeSpan Milliseconds(this byte ms) => Milliseconds((double)ms); /// /// Creates a representing the specified number of milliseconds. /// /// The number of milliseconds. /// A representing milliseconds. /// /// /// ((sbyte)500).Milliseconds() => TimeSpan.FromMilliseconds(500) /// /// public static TimeSpan Milliseconds(this sbyte ms) => Milliseconds((double)ms); /// /// Creates a representing the specified number of milliseconds. /// /// The number of milliseconds. /// A representing milliseconds. /// /// /// ((short)500).Milliseconds() => TimeSpan.FromMilliseconds(500) /// /// public static TimeSpan Milliseconds(this short ms) => Milliseconds((double)ms); /// /// Creates a representing the specified number of milliseconds. /// /// The number of milliseconds. /// A representing milliseconds. /// /// /// ((ushort)500).Milliseconds() => TimeSpan.FromMilliseconds(500) /// /// public static TimeSpan Milliseconds(this ushort ms) => Milliseconds((double)ms); /// /// Creates a representing the specified number of milliseconds. /// /// The number of milliseconds. /// A representing milliseconds. /// /// /// 500.Milliseconds() => TimeSpan.FromMilliseconds(500) /// /// public static TimeSpan Milliseconds(this int ms) => Milliseconds((double)ms); /// /// Creates a representing the specified number of milliseconds. /// /// The number of milliseconds. /// A representing milliseconds. /// /// /// 500U.Milliseconds() => TimeSpan.FromMilliseconds(500) /// /// public static TimeSpan Milliseconds(this uint ms) => Milliseconds((double)ms); /// /// Creates a representing the specified number of milliseconds. /// /// The number of milliseconds. /// A representing milliseconds. /// /// /// 500L.Milliseconds() => TimeSpan.FromMilliseconds(500) /// /// public static TimeSpan Milliseconds(this long ms) => Milliseconds((double)ms); /// /// Creates a representing the specified number of milliseconds. /// /// The number of milliseconds. /// A representing milliseconds. /// /// /// 500UL.Milliseconds() => TimeSpan.FromMilliseconds(500) /// /// public static TimeSpan Milliseconds(this ulong ms) => Milliseconds((double)ms); /// /// Creates a representing the specified number of milliseconds. /// /// The number of milliseconds. /// A representing milliseconds. /// /// /// 500.0.Milliseconds() => TimeSpan.FromMilliseconds(500) /// /// public static TimeSpan Milliseconds(this double ms) => TimeSpan.FromMilliseconds(ms); /// /// Creates a representing the specified number of seconds. /// /// The number of seconds. /// A representing seconds. /// /// /// ((byte)30).Seconds() => TimeSpan.FromSeconds(30) /// /// public static TimeSpan Seconds(this byte seconds) => Seconds((double)seconds); /// /// Creates a representing the specified number of seconds. /// /// The number of seconds. /// A representing seconds. /// /// /// ((sbyte)30).Seconds() => TimeSpan.FromSeconds(30) /// /// public static TimeSpan Seconds(this sbyte seconds) => Seconds((double)seconds); /// /// Creates a representing the specified number of seconds. /// /// The number of seconds. /// A representing seconds. /// /// /// ((short)30).Seconds() => TimeSpan.FromSeconds(30) /// /// public static TimeSpan Seconds(this short seconds) => Seconds((double)seconds); /// /// Creates a representing the specified number of seconds. /// /// The number of seconds. /// A representing seconds. /// /// /// ((ushort)30).Seconds() => TimeSpan.FromSeconds(30) /// /// public static TimeSpan Seconds(this ushort seconds) => Seconds((double)seconds); /// /// Creates a representing the specified number of seconds. /// /// The number of seconds. /// A representing seconds. /// /// /// 30.Seconds() => TimeSpan.FromSeconds(30) /// /// public static TimeSpan Seconds(this int seconds) => Seconds((double)seconds); /// /// Creates a representing the specified number of seconds. /// /// The number of seconds. /// A representing seconds. /// /// /// 30U.Seconds() => TimeSpan.FromSeconds(30) /// /// public static TimeSpan Seconds(this uint seconds) => Seconds((double)seconds); /// /// Creates a representing the specified number of seconds. /// /// The number of seconds. /// A representing seconds. /// /// /// 30L.Seconds() => TimeSpan.FromSeconds(30) /// /// public static TimeSpan Seconds(this long seconds) => Seconds((double)seconds); /// /// Creates a representing the specified number of seconds. /// /// The number of seconds. /// A representing seconds. /// /// /// 30UL.Seconds() => TimeSpan.FromSeconds(30) /// /// public static TimeSpan Seconds(this ulong seconds) => Seconds((double)seconds); /// /// Creates a representing the specified number of seconds. /// /// The number of seconds. /// A representing seconds. /// /// /// 30.Seconds() => TimeSpan representing 30 seconds /// 90.Seconds() => TimeSpan representing 1 minute and 30 seconds /// /// public static TimeSpan Seconds(this double seconds) => TimeSpan.FromSeconds(seconds); /// /// Creates a representing the specified number of minutes. /// /// The number of minutes. /// A representing minutes. /// /// /// ((byte)30).Minutes() => TimeSpan.FromMinutes(30) /// /// public static TimeSpan Minutes(this byte minutes) => Minutes((double)minutes); /// /// Creates a representing the specified number of minutes. /// /// The number of minutes. /// A representing minutes. /// /// /// ((sbyte)30).Minutes() => TimeSpan.FromMinutes(30) /// /// public static TimeSpan Minutes(this sbyte minutes) => Minutes((double)minutes); /// /// Creates a representing the specified number of minutes. /// /// The number of minutes. /// A representing minutes. /// /// /// ((short)30).Minutes() => TimeSpan.FromMinutes(30) /// /// public static TimeSpan Minutes(this short minutes) => Minutes((double)minutes); /// /// Creates a representing the specified number of minutes. /// /// The number of minutes. /// A representing minutes. /// /// /// ((ushort)30).Minutes() => TimeSpan.FromMinutes(30) /// /// public static TimeSpan Minutes(this ushort minutes) => Minutes((double)minutes); /// /// Creates a representing the specified number of minutes. /// /// The number of minutes. /// A representing minutes. /// /// /// 30.Minutes() => TimeSpan.FromMinutes(30) /// /// public static TimeSpan Minutes(this int minutes) => Minutes((double)minutes); /// /// Creates a representing the specified number of minutes. /// /// The number of minutes. /// A representing minutes. /// /// /// 30U.Minutes() => TimeSpan.FromMinutes(30) /// /// public static TimeSpan Minutes(this uint minutes) => Minutes((double)minutes); /// /// Creates a representing the specified number of minutes. /// /// The number of minutes. /// A representing minutes. /// /// /// 30L.Minutes() => TimeSpan.FromMinutes(30) /// /// public static TimeSpan Minutes(this long minutes) => Minutes((double)minutes); /// /// Creates a representing the specified number of minutes. /// /// The number of minutes. /// A representing minutes. /// /// /// 30UL.Minutes() => TimeSpan.FromMinutes(30) /// /// public static TimeSpan Minutes(this ulong minutes) => Minutes((double)minutes); /// /// Creates a representing the specified number of minutes. /// /// The number of minutes. /// A representing minutes. /// /// /// 30.Minutes() => TimeSpan representing 30 minutes /// 90.Minutes() => TimeSpan representing 1 hour and 30 minutes /// /// public static TimeSpan Minutes(this double minutes) => TimeSpan.FromMinutes(minutes); /// /// Creates a representing the specified number of hours. /// /// The number of hours. /// A representing hours. /// /// /// ((byte)3).Hours() => TimeSpan.FromHours(3) /// /// public static TimeSpan Hours(this byte hours) => Hours((double)hours); /// /// Creates a representing the specified number of hours. /// /// The number of hours. /// A representing hours. /// /// /// ((sbyte)3).Hours() => TimeSpan.FromHours(3) /// /// public static TimeSpan Hours(this sbyte hours) => Hours((double)hours); /// /// Creates a representing the specified number of hours. /// /// The number of hours. /// A representing hours. /// /// /// ((short)3).Hours() => TimeSpan.FromHours(3) /// /// public static TimeSpan Hours(this short hours) => Hours((double)hours); /// /// Creates a representing the specified number of hours. /// /// The number of hours. /// A representing hours. /// /// /// ((ushort)3).Hours() => TimeSpan.FromHours(3) /// /// public static TimeSpan Hours(this ushort hours) => Hours((double)hours); /// /// Creates a representing the specified number of hours. /// /// The number of hours. /// A representing hours. /// /// /// 3.Hours() => TimeSpan.FromHours(3) /// /// public static TimeSpan Hours(this int hours) => Hours((double)hours); /// /// Creates a representing the specified number of hours. /// /// The number of hours. /// A representing hours. /// /// /// 3U.Hours() => TimeSpan.FromHours(3) /// /// public static TimeSpan Hours(this uint hours) => Hours((double)hours); /// /// Creates a representing the specified number of hours. /// /// The number of hours. /// A representing hours. /// /// /// 3L.Hours() => TimeSpan.FromHours(3) /// /// public static TimeSpan Hours(this long hours) => Hours((double)hours); /// /// Creates a representing the specified number of hours. /// /// The number of hours. /// A representing hours. /// /// /// 3UL.Hours() => TimeSpan.FromHours(3) /// /// public static TimeSpan Hours(this ulong hours) => Hours((double)hours); /// /// Creates a representing the specified number of hours. /// /// The number of hours. /// A representing hours. /// /// /// 3.Hours() => TimeSpan representing 3 hours /// 24.Hours() => TimeSpan representing 1 day /// 1.5.Hours() => TimeSpan representing 1 hour and 30 minutes /// /// public static TimeSpan Hours(this double hours) => TimeSpan.FromHours(hours); /// /// Creates a representing the specified number of days. /// /// The number of days. /// A representing days. /// /// /// ((byte)2).Days() => TimeSpan.FromDays(2) /// /// public static TimeSpan Days(this byte days) => Days((double)days); /// /// Creates a representing the specified number of days. /// /// The number of days. /// A representing days. /// /// /// ((sbyte)2).Days() => TimeSpan.FromDays(2) /// /// public static TimeSpan Days(this sbyte days) => Days((double)days); /// /// Creates a representing the specified number of days. /// /// The number of days. /// A representing days. /// /// /// ((short)2).Days() => TimeSpan.FromDays(2) /// /// public static TimeSpan Days(this short days) => Days((double)days); /// /// Creates a representing the specified number of days. /// /// The number of days. /// A representing days. /// /// /// ((ushort)2).Days() => TimeSpan.FromDays(2) /// /// public static TimeSpan Days(this ushort days) => Days((double)days); /// /// Creates a representing the specified number of days. /// /// The number of days. /// A representing days. /// /// /// 2.Days() => TimeSpan.FromDays(2) /// /// public static TimeSpan Days(this int days) => Days((double)days); /// /// Creates a representing the specified number of days. /// /// The number of days. /// A representing days. /// /// /// 2U.Days() => TimeSpan.FromDays(2) /// /// public static TimeSpan Days(this uint days) => Days((double)days); /// /// Creates a representing the specified number of days. /// /// The number of days. /// A representing days. /// /// /// 2L.Days() => TimeSpan.FromDays(2) /// /// public static TimeSpan Days(this long days) => Days((double)days); /// /// Creates a representing the specified number of days. /// /// The number of days. /// A representing days. /// /// /// 2UL.Days() => TimeSpan.FromDays(2) /// /// public static TimeSpan Days(this ulong days) => Days((double)days); /// /// Creates a representing the specified number of days. /// /// The number of days. /// A representing days. /// /// /// 2.Days() => TimeSpan representing 2 days /// 7.Days() => TimeSpan representing 1 week /// 1.5.Days() => TimeSpan representing 1 day and 12 hours /// /// public static TimeSpan Days(this double days) => TimeSpan.FromDays(days); /// /// Creates a representing the specified number of weeks. /// /// The number of weeks. /// A representing weeks (converted to days: 1 week = 7 days). /// /// /// ((byte)2).Weeks() => new TimeSpan(14, 0, 0, 0) /// /// public static TimeSpan Weeks(this byte input) => Weeks((double)input); /// /// Creates a representing the specified number of weeks. /// /// The number of weeks. /// A representing weeks (converted to days: 1 week = 7 days). /// /// /// ((sbyte)2).Weeks() => new TimeSpan(14, 0, 0, 0) /// /// public static TimeSpan Weeks(this sbyte input) => Weeks((double)input); /// /// Creates a representing the specified number of weeks. /// /// The number of weeks. /// A representing weeks (converted to days: 1 week = 7 days). /// /// /// ((short)2).Weeks() => new TimeSpan(14, 0, 0, 0) /// /// public static TimeSpan Weeks(this short input) => Weeks((double)input); /// /// Creates a representing the specified number of weeks. /// /// The number of weeks. /// A representing weeks (converted to days: 1 week = 7 days). /// /// /// ((ushort)2).Weeks() => new TimeSpan(14, 0, 0, 0) /// /// public static TimeSpan Weeks(this ushort input) => Weeks((double)input); /// /// Creates a representing the specified number of weeks. /// /// The number of weeks. /// A representing weeks (converted to days: 1 week = 7 days). /// /// /// 2.Weeks() => new TimeSpan(14, 0, 0, 0) /// /// public static TimeSpan Weeks(this int input) => Weeks((double)input); /// /// Creates a representing the specified number of weeks. /// /// The number of weeks. /// A representing weeks (converted to days: 1 week = 7 days). /// /// /// 2U.Weeks() => new TimeSpan(14, 0, 0, 0) /// /// public static TimeSpan Weeks(this uint input) => Weeks((double)input); /// /// Creates a representing the specified number of weeks. /// /// The number of weeks. /// A representing weeks (converted to days: 1 week = 7 days). /// /// /// 2L.Weeks() => new TimeSpan(14, 0, 0, 0) /// /// public static TimeSpan Weeks(this long input) => Weeks((double)input); /// /// Creates a representing the specified number of weeks. /// /// The number of weeks. /// A representing weeks (converted to days: 1 week = 7 days). /// /// /// 2UL.Weeks() => new TimeSpan(14, 0, 0, 0) /// /// public static TimeSpan Weeks(this ulong input) => Weeks((double)input); /// /// Creates a representing the specified number of weeks. /// /// The number of weeks. /// A representing weeks (converted to days: 1 week = 7 days). /// /// Since doesn't have a native concept of weeks, this method converts /// weeks to days (multiplying by 7). /// /// /// /// 2.Weeks() => TimeSpan representing 14 days /// 1.Weeks() => TimeSpan representing 7 days /// 0.5.Weeks() => TimeSpan representing 3.5 days /// /// public static TimeSpan Weeks(this double input) => Days(7 * input); } ================================================ FILE: src/Humanizer/NumberToWordsExtension.cs ================================================ namespace Humanizer; /// /// Transform a number into words; e.g. 1 => one /// public static class NumberToWordsExtension { /// /// 1.ToOrdinalWords() -> "first" /// /// Number to be turned to ordinal words /// Culture to use. If null, current thread's UI culture is used. public static string ToOrdinalWords(this int number, CultureInfo? culture = null) => Configurator.GetNumberToWordsConverter(culture).ConvertToOrdinal(number); /// /// Converts a number to ordinal words supporting locale's specific variations. /// /// /// In Spanish: /// /// 1.ToOrdinalWords(WordForm.Normal) -> "primero" // As in "He llegado el primero". /// 3.ToOrdinalWords(WordForm.Abbreviation) -> "tercer" // As in "Vivo en el tercer piso" /// /// /// Number to be turned to ordinal words /// Form of the word, i.e. abbreviation /// Culture to use. If null, current thread's UI culture is used. /// The number converted into ordinal words public static string ToOrdinalWords(this int number, WordForm wordForm, CultureInfo? culture = null) => Configurator.GetNumberToWordsConverter(culture).ConvertToOrdinal(number, wordForm); /// /// for Brazilian Portuguese locale /// 1.ToOrdinalWords(GrammaticalGender.Masculine) -> "primeiro" /// 1.ToOrdinalWords(GrammaticalGender.Feminine) -> "primeira" /// /// Number to be turned to words /// The grammatical gender to use for output words /// Culture to use. If null, current thread's UI culture is used. public static string ToOrdinalWords(this int number, GrammaticalGender gender, CultureInfo? culture = null) => Configurator.GetNumberToWordsConverter(culture).ConvertToOrdinal(number, gender); /// /// Converts a number to ordinal words supporting locale's specific variations. /// /// /// In Spanish: /// /// 3.ToOrdinalWords(GrammaticalGender.Masculine, WordForm.Normal) -> "tercero" /// 3.ToOrdinalWords(GrammaticalGender.Masculine, WordForm.Abbreviation) -> "tercer" /// 3.ToOrdinalWords(GrammaticalGender.Feminine, WordForm.Normal) -> "tercera" /// 3.ToOrdinalWords(GrammaticalGender.Feminine, WordForm.Abbreviation) -> "tercera" /// /// /// Number to be turned to ordinal words /// The grammatical gender to use for output words /// Form of the word, i.e. abbreviation /// Culture to use. If null, current thread's UI culture is used. /// The number converted into ordinal words public static string ToOrdinalWords(this int number, GrammaticalGender gender, WordForm wordForm, CultureInfo? culture = null) => Configurator.GetNumberToWordsConverter(culture).ConvertToOrdinal(number, gender, wordForm); /// /// 1.ToTuple() -> "single" /// /// Number to be turned to tuple /// Culture to use. If null, current thread's UI culture is used. public static string ToTuple(this int number, CultureInfo? culture = null) => Configurator.GetNumberToWordsConverter(culture).ConvertToTuple(number); /// /// 3501.ToWords() -> "three thousand five hundred and one" /// /// Number to be turned to words /// Culture to use. If null, current thread's UI culture is used. public static string ToWords(this int number, CultureInfo? culture = null) => ((long)number).ToWords(culture); /// /// Converts a number to words supporting specific word variations, including grammatical gender, of some locales. /// /// /// In Spanish, numbers ended in 1 change its form depending on their position in the sentence. /// /// 21.ToWords(WordForm.Normal) -> veintiuno // as in "Mi número favorito es el veintiuno". /// 21.ToWords(WordForm.Abbreviation) -> veintiún // as in "En total, conté veintiún coches" /// /// /// Number to be turned to words /// Form of the word, i.e. abbreviation /// Culture to use. If null, current thread's UI culture is used. /// The number converted to words public static string ToWords(this int number, WordForm wordForm, CultureInfo? culture = null) => ((long)number).ToWords(wordForm, culture); /// /// 3501.ToWords(false) -> "three thousand five hundred one" /// /// Number to be turned to words /// To add 'and' before the last number. /// Culture to use. If null, current thread's UI culture is used. public static string ToWords(this int number, bool addAnd, CultureInfo? culture = null) => ((long)number).ToWords(culture, addAnd); /// /// Converts a number to words supporting specific word variations of some locales. /// /// /// In Spanish, numbers ended in 1 changes its form depending on their position in the sentence. /// /// 21.ToWords(WordForm.Normal) -> veintiuno // as in "Mi número favorito es el veintiuno". /// 21.ToWords(WordForm.Abbreviation) -> veintiún // as in "En total, conté veintiún coches" /// /// /// Number to be turned to words /// To add 'and' before the last number /// Form of the word, i.e. abbreviation /// Culture to use. If null, current thread's UI culture is used. /// The number converted to words public static string ToWords(this int number, bool addAnd, WordForm wordForm, CultureInfo? culture = null) => ((long)number).ToWords(wordForm, culture, addAnd); /// /// For locales that support gender-specific forms /// /// /// Russian: /// /// 1.ToWords(GrammaticalGender.Masculine) -> "один" /// 1.ToWords(GrammaticalGender.Feminine) -> "одна" /// /// Hebrew: /// /// 1.ToWords(GrammaticalGender.Masculine) -> "אחד" /// 1.ToWords(GrammaticalGender.Feminine) -> "אחת" /// /// /// Number to be turned to words /// The grammatical gender to use for output words /// Culture to use. If null, current thread's UI culture is used. public static string ToWords(this int number, GrammaticalGender gender, CultureInfo? culture = null) => ((long)number).ToWords(gender, culture); /// /// Converts a number to words supporting specific word variations, including grammatical gender, of some locales. /// /// /// In Spanish, numbers ended in 1 change its form depending on their position in the sentence. /// /// 21.ToWords(WordForm.Normal, GrammaticalGender.Masculine) -> veintiuno // as in "Mi número favorito es el veintiuno". /// 21.ToWords(WordForm.Abbreviation, GrammaticalGender.Masculine) -> veintiún // as in "En total, conté veintiún coches" /// 21.ToWords(WordForm.Normal, GrammaticalGender.Feminine) -> veintiuna // as in "veintiuna personas" /// /// /// Number to be turned to words /// Form of the word, i.e. abbreviation /// The grammatical gender to use for output words /// Culture to use. If null, current thread's UI culture is used. /// The number converted to words public static string ToWords(this int number, WordForm wordForm, GrammaticalGender gender, CultureInfo? culture = null) => ((long)number).ToWords(wordForm, gender, culture); /// /// 3501.ToWords() -> "three thousand five hundred and one" /// /// Number to be turned to words /// Culture to use. If null, current thread's UI culture is used. /// Whether "and" should be included or not. public static string ToWords(this long number, CultureInfo? culture = null, bool addAnd = true) => Configurator.GetNumberToWordsConverter(culture).Convert(number, addAnd); /// /// Converts a number to words supporting specific word variations of some locales. /// /// /// In Spanish, numbers ended in 1 changes its form depending on their position in the sentence. /// /// 21.ToWords(WordForm.Normal) -> veintiuno // as in "Mi número favorito es el veintiuno". /// 21.ToWords(WordForm.Abbreviation) -> veintiún // as in "En total, conté veintiún coches" /// /// /// Number to be turned to words /// Form of the word, i.e. abbreviation /// Culture to use. If null, current thread's UI culture is used. /// To add 'and' before the last number /// The number converted to words public static string ToWords(this long number, WordForm wordForm, CultureInfo? culture = null, bool addAnd = false) => Configurator.GetNumberToWordsConverter(culture).Convert(number, addAnd, wordForm); /// /// For locales that support gender-specific forms /// /// /// Russian: /// /// 1.ToWords(GrammaticalGender.Masculine) -> "один" /// 1.ToWords(GrammaticalGender.Feminine) -> "одна" /// /// Hebrew: /// /// 1.ToWords(GrammaticalGender.Masculine) -> "אחד" /// 1.ToWords(GrammaticalGender.Feminine) -> "אחת" /// /// /// /// Number to be turned to words /// The grammatical gender to use for output words /// Culture to use. If null, current thread's UI culture is used. public static string ToWords(this long number, GrammaticalGender gender, CultureInfo? culture = null) => Configurator.GetNumberToWordsConverter(culture).Convert(number, gender); /// /// Converts a number to words supporting specific word variations, including grammatical gender, of some locales. /// /// /// In Spanish, numbers ended in 1 changes its form depending on their position in the sentence. /// /// 21.ToWords(WordForm.Normal, GrammaticalGender.Masculine) -> veintiuno // as in "Mi número favorito es el veintiuno". /// 21.ToWords(WordForm.Abbreviation, GrammaticalGender.Masculine) -> veintiún // as in "En total, conté veintiún coches" /// 21.ToWords(WordForm.Normal, GrammaticalGender.Feminine) -> veintiuna // as in "veintiuna personas" /// /// /// Number to be turned to words /// Form of the word, i.e. abbreviation /// The grammatical gender to use for output words /// Culture to use. If null, current thread's UI culture is used. /// The number converted to words public static string ToWords(this long number, WordForm wordForm, GrammaticalGender gender, CultureInfo? culture = null) => Configurator.GetNumberToWordsConverter(culture).Convert(number, wordForm, gender); } ================================================ FILE: src/Humanizer/OnNoMatch.cs ================================================ namespace Humanizer; /// /// Dictating what should be done when a match is not found - currently used only for DehumanizeTo /// public enum OnNoMatch { /// /// This is the default behavior which throws a NoMatchFoundException /// ThrowsException, /// /// If set to ReturnsNull the method returns null instead of throwing an exception /// ReturnsNull } ================================================ FILE: src/Humanizer/OrdinalizeExtensions.cs ================================================ namespace Humanizer; /// /// Ordinalize extensions /// public static class OrdinalizeExtensions { /// /// Turns a number into an ordinal string used to denote the position in an ordered sequence such as 1st, 2nd, 3rd, 4th. /// /// The number, in string, to be ordinalized public static string Ordinalize(this string numberString) => Configurator.Ordinalizer.Convert(int.Parse(numberString), numberString); /// /// Turns a number into an ordinal number used to denote the position in an ordered sequence supporting specific locale's variations. /// /// /// In Spanish: /// /// "1".Ordinalize(WordForm.Abbreviation) -> 1.er // As in "Vivo en el 1.er piso" /// "1".Ordinalize(WordForm.Normal) -> 1.º // As in "Fui el 1º de mi promoción" /// /// /// The number, in string, to be ordinalized /// Form of the word, i.e. abbreviation /// The number ordinalized public static string Ordinalize(this string numberString, WordForm wordForm) => Configurator.Ordinalizer.Convert(int.Parse(numberString), numberString, wordForm); /// /// Turns a number into an ordinal string used to denote the position in an ordered sequence such as 1st, 2nd, 3rd, 4th. /// /// The number, in string, to be ordinalized /// Culture to use. If null, current thread's UI culture is used. public static string Ordinalize(this string numberString, CultureInfo culture) => Configurator.Ordinalizers.ResolveForCulture(culture).Convert(int.Parse(numberString, culture), numberString); /// /// Turns a number into an ordinal number used to denote the position in an ordered sequence supporting specific locale's variations. /// /// /// In Spanish: /// /// "1".Ordinalize(new CultureInfo("es-ES"),WordForm.Abbreviation) -> 1.er // As in "Vivo en el 1.er piso" /// "1".Ordinalize(new CultureInfo("es-ES"), WordForm.Normal) -> 1.º // As in "Fui el 1º de mi promoción" /// /// /// The number to be ordinalized /// Culture to use. If null, current thread's UI culture is used. /// Form of the word, i.e. abbreviation /// The number ordinalized public static string Ordinalize(this string numberString, CultureInfo culture, WordForm wordForm) => Configurator.Ordinalizers.ResolveForCulture(culture).Convert(int.Parse(numberString, culture), numberString, wordForm); /// /// Turns a number into an ordinal string used to denote the position in an ordered sequence such as 1st, 2nd, 3rd, 4th. /// Gender for Brazilian Portuguese locale /// "1".Ordinalize(GrammaticalGender.Masculine) -> "1º" /// "1".Ordinalize(GrammaticalGender.Feminine) -> "1ª" /// /// The number, in string, to be ordinalized /// The grammatical gender to use for output words public static string Ordinalize(this string numberString, GrammaticalGender gender) => Configurator.Ordinalizer.Convert(int.Parse(numberString), numberString, gender); /// /// Turns a number into an ordinal number used to denote the position in an ordered sequence supporting specific /// locale's variations using the grammatical gender provided /// /// /// In Spanish: /// /// "1".Ordinalize(GrammaticalGender.Masculine, WordForm.Abbreviation) -> 1.er // As in "Vivo en el 1.er piso" /// "1".Ordinalize(GrammaticalGender.Masculine, WordForm.Normal) -> 1.º // As in "Fui el 1º de mi promoción" /// "1".Ordinalize(GrammaticalGender.Feminine, WordForm.Normal) -> 1.ª // As in "Es 1ª vez que hago esto" /// /// /// The number to be ordinalized /// The grammatical gender to use for output words /// Form of the word, i.e. abbreviation /// The number ordinalized public static string Ordinalize(this string numberString, GrammaticalGender gender, WordForm wordForm) => Configurator.Ordinalizer.Convert(int.Parse(numberString), numberString, gender, wordForm); /// /// Turns a number into an ordinal string used to denote the position in an ordered sequence such as 1st, 2nd, 3rd, 4th. /// Gender for Brazilian Portuguese locale /// "1".Ordinalize(GrammaticalGender.Masculine) -> "1º" /// "1".Ordinalize(GrammaticalGender.Feminine) -> "1ª" /// /// The number, in string, to be ordinalized /// The grammatical gender to use for output words /// Culture to use. If null, current thread's UI culture is used. public static string Ordinalize(this string numberString, GrammaticalGender gender, CultureInfo culture) => Configurator.Ordinalizers.ResolveForCulture(culture).Convert(int.Parse(numberString, culture), numberString, gender); /// /// Turns a number into an ordinal number used to denote the position in an ordered sequence supporting specific /// locale's variations using the grammatical gender provided /// /// /// In Spanish: /// /// "1".Ordinalize(GrammaticalGender.Masculine, new CultureInfo("es-ES"),WordForm.Abbreviation) -> 1.er // As in "Vivo en el 1.er piso" /// "1".Ordinalize(GrammaticalGender.Masculine, new CultureInfo("es-ES"), WordForm.Normal) -> 1.º // As in "Fui el 1º de mi promoción" /// "1".Ordinalize(GrammaticalGender.Feminine, new CultureInfo("es-ES"), WordForm.Normal) -> 1.º // As in "Fui el 1º de mi promoción" /// /// /// The number to be ordinalized /// The grammatical gender to use for output words /// Culture to use. If null, current thread's UI culture is used. /// Form of the word, i.e. abbreviation /// The number ordinalized public static string Ordinalize(this string numberString, GrammaticalGender gender, CultureInfo culture, WordForm wordForm) => Configurator.Ordinalizers.ResolveForCulture(culture).Convert(int.Parse(numberString, culture), numberString, gender, wordForm); /// /// Turns a number into an ordinal number used to denote the position in an ordered sequence such as 1st, 2nd, 3rd, 4th. /// /// The number to be ordinalized public static string Ordinalize(this int number) => Configurator.Ordinalizer.Convert(number, number.ToString(CultureInfo.InvariantCulture)); /// /// Turns a number into an ordinal number used to denote the position in an ordered sequence supporting specific locale's variations. /// /// /// In Spanish: /// /// 1.Ordinalize(WordForm.Abbreviation) -> 1.er // As in "Vivo en el 1.er piso" /// 1.Ordinalize(WordForm.Normal) -> 1.º // As in "Fui el 1º de mi promoción" /// /// /// The number to be ordinalized /// Form of the word, i.e. abbreviation /// The number ordinalized public static string Ordinalize(this int number, WordForm wordForm) => Configurator.Ordinalizer.Convert(number, number.ToString(CultureInfo.InvariantCulture), wordForm); /// /// Turns a number into an ordinal number used to denote the position in an ordered sequence such as 1st, 2nd, 3rd, 4th. /// /// The number to be ordinalized /// Culture to use. If null, current thread's UI culture is used. public static string Ordinalize(this int number, CultureInfo culture) => Configurator.Ordinalizers.ResolveForCulture(culture).Convert(number, number.ToString(culture)); /// /// Turns a number into an ordinal number used to denote the position in an ordered sequence supporting specific locale's variations. /// /// /// In Spanish: /// /// 1.Ordinalize(new CultureInfo("es-ES"),WordForm.Abbreviation) -> 1.er // As in "Vivo en el 1.er piso" /// 1.Ordinalize(new CultureInfo("es-ES"), WordForm.Normal) -> 1.º // As in "Fui el 1º de mi promoción" /// /// /// The number to be ordinalized /// Culture to use. If null, current thread's UI culture is used. /// Form of the word, i.e. abbreviation /// The number ordinalized public static string Ordinalize(this int number, CultureInfo culture, WordForm wordForm) => Configurator.Ordinalizers.ResolveForCulture(culture).Convert(number, number.ToString(culture), wordForm); /// /// Turns a number into an ordinal number used to denote the position in an ordered sequence such as 1st, 2nd, 3rd, 4th. /// Gender for Brazilian Portuguese locale /// 1.Ordinalize(GrammaticalGender.Masculine) -> "1º" /// 1.Ordinalize(GrammaticalGender.Feminine) -> "1ª" /// /// The number to be ordinalized /// The grammatical gender to use for output words public static string Ordinalize(this int number, GrammaticalGender gender) => Configurator.Ordinalizer.Convert(number, number.ToString(CultureInfo.InvariantCulture), gender); /// /// Turns a number into an ordinal number used to denote the position in an ordered sequence supporting specific /// locale's variations using the grammatical gender provided /// /// /// In Spanish: /// /// 1.Ordinalize(GrammaticalGender.Masculine, WordForm.Abbreviation) -> 1.er // As in "Vivo en el 1.er piso" /// 1.Ordinalize(GrammaticalGender.Masculine, WordForm.Normal) -> 1.º // As in "Fui el 1º de mi promoción" /// 1.Ordinalize(GrammaticalGender.Feminine, WordForm.Normal) -> 1.ª // As in "Es 1ª vez que hago esto" /// /// /// The number to be ordinalized /// The grammatical gender to use for output words /// Form of the word, i.e. abbreviation /// The number ordinalized public static string Ordinalize(this int number, GrammaticalGender gender, WordForm wordForm) => Configurator.Ordinalizer.Convert(number, number.ToString(CultureInfo.InvariantCulture), gender, wordForm); /// /// Turns a number into an ordinal number used to denote the position in an ordered sequence such as 1st, 2nd, 3rd, 4th. /// Gender for Brazilian Portuguese locale /// 1.Ordinalize(GrammaticalGender.Masculine) -> "1º" /// 1.Ordinalize(GrammaticalGender.Feminine) -> "1ª" /// /// The number to be ordinalized /// The grammatical gender to use for output words /// Culture to use. If null, current thread's UI culture is used. public static string Ordinalize(this int number, GrammaticalGender gender, CultureInfo culture) => Configurator.Ordinalizers.ResolveForCulture(culture).Convert(number, number.ToString(culture), gender); /// /// Turns a number into an ordinal number used to denote the position in an ordered sequence supporting specific /// locale's variations using the grammatical gender provided /// /// /// In Spanish: /// /// 1.Ordinalize(GrammaticalGender.Masculine, new CultureInfo("es-ES"),WordForm.Abbreviation) -> 1.er // As in "Vivo en el 1.er piso" /// 1.Ordinalize(GrammaticalGender.Masculine, new CultureInfo("es-ES"), WordForm.Normal) -> 1.º // As in "Fui el 1º de mi promoción" /// 1.Ordinalize(GrammaticalGender.Feminine, new CultureInfo("es-ES"), WordForm.Normal) -> 1.º // As in "Fui el 1º de mi promoción" /// /// /// The number to be ordinalized /// The grammatical gender to use for output words /// Culture to use. If null, current thread's UI culture is used. /// Form of the word, i.e. abbreviation /// The number ordinalized public static string Ordinalize(this int number, GrammaticalGender gender, CultureInfo culture, WordForm wordForm) => Configurator.Ordinalizers.ResolveForCulture(culture).Convert(number, number.ToString(culture), gender, wordForm); } ================================================ FILE: src/Humanizer/Plurality.cs ================================================ namespace Humanizer; /// /// Provides hint for Humanizer as to whether a word is singular, plural or with unknown plurality /// public enum Plurality { /// /// The word is singular /// Singular, /// /// The word is plural /// Plural, /// /// I am unsure of the plurality /// CouldBeEither } ================================================ FILE: src/Humanizer/PolyfillShims.cs ================================================ #if !(NET5_0_OR_GREATER) using System.Runtime.CompilerServices; namespace System; // C# 14 static extension members on the *type* itself. // Usage on old TFMs: Double.IsFinite(x), Double.IsIntegral(x), Single.IsFinite(x), ... static class PolyfillShims { // Extend the *type* ArgumentNullException with a static member extension(ArgumentNullException) { [Intrinsic] public static void ThrowIfNull( object? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) => _ = argument ?? throw new ArgumentNullException(paramName); } extension(ArgumentOutOfRangeException) { /// Throws an if is negative. /// The argument to validate as non-negative. /// The name of the parameter with which corresponds. public static void ThrowIfNegative(int value, [CallerArgumentExpression(nameof(value))] string? paramName = null) { if (value < 0) { throw new ArgumentOutOfRangeException(paramName, value, "Argument must be non-negative."); } } } // ---- Double ---- extension(double) { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(double x) { var bits = (ulong)BitConverter.DoubleToInt64Bits(x); return (bits & 0x7FF0_0000_0000_0000UL) != 0x7FF0_0000_0000_0000UL; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsIntegral(double x) { if (!IsFinite(x)) { return false; } return x == Math.Truncate(x); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinityFast(double x) { var bits = (ulong)BitConverter.DoubleToInt64Bits(x); return (bits & 0x7FFF_FFFF_FFFF_FFFFUL) == 0x7FF0_0000_0000_0000UL; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaNFast(double x) { var bits = (ulong)BitConverter.DoubleToInt64Bits(x); return (bits & 0x7FF0_0000_0000_0000UL) == 0x7FF0_0000_0000_0000UL && (bits & 0x000F_FFFF_FFFF_FFFFUL) != 0; } } // ---- float ---- extension(float) { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(float x) { // netstandard2.0 / net48: fastest is unsafe bit-cast unsafe { var bits = *(uint*)&x; return (bits & 0x7F80_0000u) != 0x7F80_0000u; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsIntegral(float x) { if (!IsFinite(x)) { return false; } return x == Math.Truncate(x); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinityFast(float x) { unsafe { var bits = *(uint*)&x; return (bits & 0x7FFF_FFFFu) == 0x7F80_0000u; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaNFast(float x) { unsafe { var bits = *(uint*)&x; var isExpAllOnes = (bits & 0x7F80_0000u) == 0x7F80_0000u; var hasMantissa = (bits & 0x007F_FFFFu) != 0; return isExpAllOnes && hasMantissa; } } } } #endif ================================================ FILE: src/Humanizer/PolyfillShims2.cs ================================================ #if !(NET5_0_OR_GREATER) namespace System.Runtime.CompilerServices; [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method)] internal sealed class IntrinsicAttribute : Attribute { } #endif ================================================ FILE: src/Humanizer/Properties/AssemblyInfo.cs ================================================ using System.Resources; [assembly: NeutralResourcesLanguage("en")] ================================================ FILE: src/Humanizer/Properties/Resources.af.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 {0} dae gelede oor {0} dae {0} ure gelede oor {0} ure {0} minute terug oor {0} minute {0} maande gelede oor {0} maande {0} sekondes terug oor {0} sekondes {0} jaar gelede oor {0} jaar nou gister môre 1 uur terug oor 1 uur 1 minuut terug oor 1 minuut 1 maand gelede oor 1 maand 1 sekonde terug oor 1 sekonde 1 jaar gelede oor 1 jaar {0} dae {0} ure {0} millisekondes {0} minute {0} maande {0} sekondes {0} weke {0} jaar 1 dag 1 uur 1 millisekond 1 minuut 1 maand 1 sekond 1 week 1 jaar geen tyd ================================================ FILE: src/Humanizer/Properties/Resources.ar.resx ================================================ text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 منذ {0} يوم {0} days ago منذ يومين two days ago منذ {0} أيام {0} days ago في غضون {0} يوم من الآن في غضون يومين من الآن in 2 days في غضون {0} أيام من الآن {0} days from now منذ {0} ساعة {0} hours ago منذ ساعتين two hours ago منذ {0} ساعات {0} hours ago في غضون {0} ساعة من الآن في غضون ساعتين من الآن in 2 hours في غضون {0} ساعات من الآن in {0} hours منذ {0} دقيقة {0} minutes ago منذ دقيقتين two minutes ago منذ {0} دقائق {0} minutes ago في غضون {0} دقيقة من الآن في غضون دقيقتين من الآن in 2 minutes في غضون {0} دقائق من الآن in {0} minutes منذ {0} شهر {0} months ago منذ شهرين two months ago منذ {0} أشهر {0} months ago في غضون {0} شهر من الآن في غضون شهرين من الآن in 2 months في غضون {0} أشهر من الآن in {0} months منذ {0} ثانية {0} seconds ago منذ ثانيتين two seconds ago منذ {0} ثوان {0} seconds ago في غضون {0} ثانية من الآن في غضون ثانيتين من الآن in 2 seconds في غضون {0} ثوان من الآن in {0} seconds منذ {0} عام {0} years ago منذ عامين two years ago منذ {0} أعوام {0} years ago في غضون {0} سنة من الآن في غضون سنتين من الآن in 2 years في غضون {0} سنوات من الآن in {0} years الآن now أمس yesterday في غضون يوم واحد من الآن منذ ساعة واحدة an hour ago في غضون ساعة واحدة من الآن منذ دقيقة واحدة a minute ago في غضون دقيقة واحدة من الآن منذ شهر واحد one month ago في غضون شهر واحد من الآن منذ ثانية واحدة one second ago في غضون ثانية واحدة من الآن العام السابق one year ago في غضون سنة واحدة من الآن {0} يوم {0} days يومين two days {0} أيام {0} days {0} ساعة {0} hours ساعتين two hours {0} ساعات {0} hours {0} جزء من الثانية {0} milliseconds جزئين من الثانية two milliseconds {0} أجزاء من الثانية {0} milliseconds {0} دقيقة {0} minutes دقيقتين two minutes {0} دقائق {0} minutes {0} أشهر شهرين {0} أشهر {0} ثانية {0} seconds ثانيتين two seconds {0} ثوان {0} seconds {0} أسبوع {0} weeks أسبوعين two weeks {0} أسابيع {0} weeks {0} سنة سنتين {0} سنة يوم واحد single day ساعة واحدة single hour جزء من الثانية single millisecond دقيقة واحدة single minute شهر 1 ثانية واحدة single second أسبوع واحد single week السنة 1 حالاً no time ================================================ FILE: src/Humanizer/Properties/Resources.az.resx ================================================ text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 {0} gün əvvəl {0} gün sonra {0} saat əvvəl {0} saat sonra {0} dəqiqə əvvəl {0} dəqiqə sonra {0} ay əvvəl {0} ay sonra {0} saniyə əvvəl {0} saniyə sonra {0} il əvvəl {0} il sonra indi dünən sabah bir saat əvvəl bir saat sonra bir dəqiqə əvvəl bir dəqiqə sonra bir ay əvvəl bir ay sonra bir saniyə əvvəl bir saniyə sonra bir il əvvəl bir il sonra {0} gün {0} saat {0} millisaniyə {0} dəqiqə {0} ay {0} saniyə {0} həftə {0} il 1 gün 1 saat 1 millisaniyə 1 dəqiqə 1 ay 1 saniyə 1 həftə 1 il zaman fərqi yoxdur ================================================ FILE: src/Humanizer/Properties/Resources.bg.resx ================================================ text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 преди {0} дена след {0} дена преди {0} часа след {0} часа преди {0} минути след {0} минути преди {0} месеца след {0} месеца преди {0} секунди след {0} секунди преди {0} години след {0} години сега вчера утре преди час след час преди минута след минута преди месец след месец преди секунда след секунда преди година след година {0} дена {0} часа {0} милисекунди {0} минути {0} месеца {0} секунди {0} седмици {0} години 1 ден един ден 1 час един час 1 милисекунда една милисекунда 1 минута една минута 1 месец един месец 1 секунда една секунда 1 седмица една седмица 1 година една година няма време ================================================ FILE: src/Humanizer/Properties/Resources.bn.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 {0} দিন আগে {0} দিন পর {0} ঘণ্টা আগে {0} ঘণ্টা পর {0} মিনিট আগে {0} মিনিট পর {0} মাস আগে {0} মাস পর {0} সেকেন্ড আগে {0} সেকেন্ড পর {0} বছর আগে {0} বছর পর এখন গতকাল আগামিকাল এক ঘণ্টা আগে এক ঘণ্টা পর এক মিনিট আগে এক মিনিট পর এক মাস আগে এক মাস পর এক সেকেন্ড আগে এক সেকেন্ড পর এক বছর আগে এক বছর পর {0} দিন {0} ঘণ্টা {0} মিলিসেকেন্ড {0} মিনিট {0} মাস {0} সেকেন্ড {0} সপ্তাহ {0} বছর এক দিন এক ঘণ্টা এক মিলিসেকেন্ড এক মিনিট এক মাসের এক সেকেন্ড এক সপ্তাহ এক বছর শূন্য সময় ================================================ FILE: src/Humanizer/Properties/Resources.ca.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 fa un segon fa {0} segons fa un minut fa {0} minuts fa una hora fa {0} hores ahir fa {0} dies fa un mes fa {0} mesos fa un any fa {0} anys {0} dies {0} hores {0} mil·lisegons {0} minuts {0} segons {0} setmanes 1 dia 1 hora 1 mil·lisegon 1 minut 1 segon 1 setmana res d'aquí {0} dies d'aquí {0} hores d'aquí {0} minuts d'aquí {0} mesos d'aquí {0} segons d'aquí {0} anys demà d'aquí una hora d'aquí un minut d'aquí un mes d'aquí un segon d'aquí un any ara {0} mesos {0} anys 1 mes 1 any {0} setmanes un dia una hora un mil·lisegon un minut un mes un segon una setmana un any nord nord-nord-est nord-est est-nord-est est est-sud-est sud-est sud-sud-est sud sud-sud-oest sud-oest oest-sud-oest oest oest-nord-oest {0} any {0} anys {0} anys {0} setmana fa {0} hores d'aquí {0} hores fa {0} minuts d'aquí {0} minuts fa {0} mesos d'aquí {0} mesos fa {0} segons d'aquí {0} segons fa {0} anys nord-oest d'aquí {0} anys {0} mil·lisegons {0} minuts {0} segons {0} setmanes mai {0} mesos {0} mesos {0} mesos {0} mes {0} anys {0} hores nord-nord-oest N N-NE min h dia setmana mes any s ms terabyte NE E-NE E E-SE SE S-SE S S-SO SO O-SO O TB O-NO N-NO bit b byte B kilobyte KB megabyte MB gigabyte GB NO {0} setmanes {0} segon {0} dia a partir d'ara fa {0} hores fa {0} hores fa {0} hora d'aquí {0} hores d'aquí {0} hora fa {0} minuts fa {0} minuts fa {0} minut {0} dies a partir d'ara fa {0} dia d'aquí {0} hores {0} minuts a partir d'ara fa {0} segons {0} segons a partir d'ara {0} anys a partir d'ara {0} dies {0} dies {0} minuts a partir d'ara {0} hores {0} minuts {0} minuts {0} segons {0} mil·lisegons fa {0} dies fa {0} dies {0} mil·lisegons {0} minut a partir d'ara {0} dies a partir d'ara fa {0} mesos {0} anys a partir d'ara {0} any a partir d'ara {0} dia fa {0} any {0} hores {0} minut {0} segons {0} hora fa {0} anys {0} mil·lisegon fa {0} anys fa {0} mes {0} mesos a partir d'ara {0} mesos a partir d'ara {0} mes a partir d'ara fa {0} mesos fa {0} segons {0} segons a partir d'ara {0} segon a partir d'ara fa {0} segon ================================================ FILE: src/Humanizer/Properties/Resources.cs.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 před {0} dny před {0} dny za {0} dnů za {0} dny před {0} hodinami před {0} hodinami za {0} hodin za {0} hodiny před {0} minutami před {0} minutami za {0} minut za {0} minuty před {0} měsíci před {0} měsíci za {0} měsíců za {0} měsíce před {0} sekundami před {0} sekundami za {0} sekund za {0} sekundy před {0} lety před {0} lety za {0} let za {0} roky teď včera zítra před hodinou za hodinu před minutou za minutu před měsícem za měsíc před sekundou za sekundu před rokem za rok {0} dnů {0} dny {0} hodin {0} hodiny {0} milisekund {0} milisekundy {0} minut {0} minuty {0} měsíců {0} měsíce {0} sekund {0} sekundy {0} týdnů {0} týdny {0} let {0} roky 1 den 1 hodina 1 milisekunda 1 minuta 1 měsíc 1 sekunda 1 týden 1 rok není čas ================================================ FILE: src/Humanizer/Properties/Resources.da.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 {0} dage siden {0} dage fra nu {0} timer siden {0} timer fra nu {0} minutter siden {0} minutter fra nu {0} måneder siden {0} måneder fra nu {0} sekunder siden {0} sekunder fra nu {0} år siden {0} år fra nu nu i går i morgen en time siden en time fra nu et minut siden et minut fra nu en måned siden en måned fra nu et sekund siden et sekund fra nu et år siden et år fra nu øst østnordøst ØNØ østsydøst ØSØ Ø nord nordøst nordnordøst NNØ nordnordvest NNV nordvest NV syd sydøst sydsydøst SSØ sydsydvest SSV sydvest SV {0} dage {0} timer {0} millisekunder {0} minutter {0} måneder {0} sekunder {0} uger {0} år en dag en time et millisekund et minut en måned et sekund en uge et år ingen tid vest vestnordvest VNV vestsydvest VSV V ================================================ FILE: src/Humanizer/Properties/Resources.de.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Bit bit Byte B Gigabyte GB Kilobyte kB Megabyte MB Terabyte TB vor {0} Tagen in {0} Tagen vor {0} Stunden in {0} Stunden vor {0} Minuten in {0} Minuten vor {0} Monaten in {0} Monaten vor {0} Sekunden in {0} Sekunden vor {0} Jahren in {0} Jahren nie jetzt gestern morgen vor einer Stunde in einer Stunde vor einer Minute in einer Minute vor einem Monat in einem Monat vor einer Sekunde in einer Sekunde vor einem Jahr in einem Jahr Ost Ostnordost ONO Ostsüdost OSO O Nord Nordost NO Nordnordost NNO Nordnordwest NNW Nordwest NW N Süd Südost SO Südsüdost SSO Südsüdwest SSW Südwest SW S {0} Tage {0} Stunden {0} Millisekunden {0} Minuten {0} Monate {0} Sekunden {0} Wochen {0} Jahre 1 Tag ein Tag 1 Stunde eine Stunde 1 Millisekunde eine Millisekunde 1 Minute eine Minute 1 Monat ein Monat 1 Sekunde eine Sekunde 1 Woche eine Woche 1 Jahr ein Jahr Keine Zeit d h ms min M s Woche a West Westnordwest WNW Westsüdwest WSW W ================================================ FILE: src/Humanizer/Properties/Resources.el.resx ================================================ text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 πριν από {0} ημέρες {0} ημέρες από τώρα πριν από {0} ώρες {0} ώρες από τώρα πριν από {0} λεπτά {0} λεπτά από τώρα πριν από {0} μήνες {0} μήνες από τώρα πριν από {0} δευτερόλεπτα {0} δευτερόλεπτα από τώρα πριν από {0} χρόνια {0} χρόνια από τώρα ποτέ τώρα χθες αύριο πριν από μία ώρα πρίν από μία ώρα από τώρα πριν από ένα λεπτό πρίν από ένα λεπτό από τώρα πριν από έναν μήνα πριν από έναν μήνα από τώρα πριν από ένα δευτερόλεπτο πριν από ένα δευτερόλεπτο από τώρα πριν από έναν χρόνο πριν από έναν χρόνο από τώρα {0} μέρες {0} ώρες {0} χιλιοστά του δευτερολέπτου {0} λεπτά {0} μήνες {0} δευτερόλεπτα {0} βδομάδες {0} χρόνια 1 μέρα 1 ώρα 1 χιλιοσtό του δευτερολέπτου 1 λεπτό 1 μήνα 1 δευτερόλεπτο 1 βδομάδα 1 χρόνο μηδέν χρόνος ================================================ FILE: src/Humanizer/Properties/Resources.es.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 bit b byte B gigabye GB kilobyte KB megabyte MB terabyte TB hace {0} días hace {0} días hace {0} días hace {0} día en {0} días hace {0} días desde ahora hace {0} días desde ahora {0} día desde ahora hace {0} horas hace {0} horas hace {0} horas hace {0} horas hace {0} hora en {0} horas hace {0} horas desde ahora hace {0} horas desde ahora hace {0} horas desde ahora hace {0} hora desde ahora hace {0} minutos hace {0} minutos hace {0} minutos hace {0} minutos hace {0} minuto en {0} minutos {0} minutos desde ahora hace {0} minutos desde ahora hace {0} minutos desde ahora hace {0} minuto desde ahora hace {0} meses hace {0} meses desde ahora hace {0} meses hace {0} meses hace {0} meses en {0} meses hace {0} meses desde ahora hace {0} meses desde ahora hace {0} meses desde ahora hace {0} mes desde ahora hace {0} segundos hace {0} segundos hace {0} segundos hace {0} segundos hace {0} segundo en {0} segundos hace {0} segundos desde ahora hace {0} segundos desde ahora hace {0} segundos desde ahora hace {0} segundo desde ahora hace {0} años hace {0} años hace {0} años hace {0} años hace {0} año en {0} años hace {0} años desde ahora hace {0} años desde ahora hace {0} años desde ahora hace {0} año desde ahora nunca ahora ayer mañana hace una hora en una hora hace un minuto en un minuto hace un mes en un mes hace un segundo en un segundo hace un año en un año este este-noreste E-NE este-sudeste E-SE E norte noreste NE norte-noreste N-NE norte-noroeste N-NO noroeste NO N sur sudeste SE sur-sudeste S-SE sur-sudoeste S-SO sudoeste SO S {0} días {0} días {0} días {0} día {0} horas {0} horas {0} horas {0} horas {0} hora {0} milisegundos {0} milisegundos {0} milisegundos {0} milisegundos {0} milisegundo {0} minutos {0} minutos {0} minutos {0} mintuos {0} minuto {0} meses {0} meses {0} meses {0} meses {0} mes {0} segundos {0} segundos {0} segundos {0} segundos {0} segundo {0} semanas {0} semanas {0} semanas {0} semanas {0} semana {0} años {0} años {0} años {0} años {0} año 1 día un día 1 hora una hora 1 milisegundo un milisegundo 1 minuto un minuto 1 mes un mes 1 segundo un segundo 1 semana una semana 1 año un año nada d h ms min mes s semana año oeste oeste-noroeste O-NO oeste-sudoeste O-SO O ================================================ FILE: src/Humanizer/Properties/Resources.fa.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 {0} روز پیش {0} روز بعد {0} ساعت پیش {0} ساعت بعد {0} دقیقه پیش {0} دقیقه بعد {0} ماه پیش {0} ماه بعد {0} ثانیه پیش {0} ثانیه بعد {0} سال پیش {0} سال بعد الآن دیروز فردا یک ساعت پیش یک ساعت بعد یک دقیقه پیش یک دقیقه بعد یک ماه پیش یک ماه بعد یک ثانیه پیش یک ثانیه بعد یک سال پیش یک سال بعد {0} روز {0} ساعت {0} میلی ثانیه {0} دقیقه {0} ماه {0} ثانیه {0} هفته {0} سال یک روز یک ساعت یک میلی ثانیه یک دقیقه یک ماه یک ثانیه یک هفته یک سال الآن ================================================ FILE: src/Humanizer/Properties/Resources.fi.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 {0} päivää sitten {0} päivän päästä {0} tuntia sitten {0} tunnin päästä {0} minuuttia sitten {0} minuutin päästä {0} kuukautta sitten {0} sekuntia sitten {0} vuotta sitten eilen huomenna tunti sitten tunnin päästä minuutti sitten minuutin päästä kuukausi sitten kuukauden päästä sekuntti sitten vuosi sitten vuoden päästä toissapäivänä ylihuomenna päivä tunti nyt ================================================ FILE: src/Humanizer/Properties/Resources.fil.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 {0} isang araw ang nakalipas {0} isang araw ang nakalipas {0} isang araw ang nakalipas {0} isang araw ang nakalipas {0} araw mula ngayon {0} araw mula ngayon {0} araw mula ngayon {0} araw mula ngayon {0} isang oras ang nakalipas {0} isang oras ang nakalipas {0} isang oras ang nakalipas {0} isang oras ang nakalipas {0} oras ang nakalipas {0} oras mula ngayon {0} oras mula ngayon {0} oras mula ngayon {0} oras mula ngayon {0} oras mula ngayon {0} minutong nakalipas {0} minutong nakalipas {0} minutong nakalipas {0} minutong nakalipas {0} minuto ang nakalipas {0} minuto mula ngayon {0} minuto mula ngayon {0} minuto mula ngayon {0} minuto mula ngayon {0} minuto mula ngayon {0} isang buwan ang nakalipas {0} isang buwan ang nakalipas {0} isang buwan ang nakalipas {0} isang buwan ang nakalipas {0} buwan ang nakalipas {0} buwan mula ngayon {0} buwan mula ngayon {0} buwan mula ngayon {0} buwan mula ngayon {0} buwan mula ngayon {0} segundong nakalipas {0} segundong nakalipas {0} segundong nakalipas {0} segundong nakalipas {0} segundo ang nakalipas {0} segundo mula ngayon {0} segundo mula ngayon {0} segundo mula ngayon {0} segundo mula ngayon {0} segundo mula ngayon {0} isang taong nakalipas {0} isang taong nakalipas {0} taon mula sa nakalipas {0} isang taong nakalipas {0} taon ang nakalipas {0} taon mula ngayon {0} taon mula ngayon {0} taon mula ngayon {0} taon mula ngayon {0} taon mula ngayon hindi kailanman ngayon kahapon bukas isang oras ang nakalipas isang oras mula ngayon isang minutong nakalipas isang minuto mula ngayon isang buwan ang nakalipas isang buwan mula ngayon isang segundo ang nakalipas isang segundo mula ngayon isang taong nakalipas isang taon mula ngayon {0} araw {0} araw {0} araw {0} araw {0} oras {0} oras {0} oras {0} oras {0} oras {0} milliseconds {0} milliseconds {0} milliseconds {0} milliseconds {0} millisecond {0} minuto {0} minuto {0} minuto {0} minuto {0} minuto {0} buwan {0} segundo {0} segundo {0} segundo {0} segundo {0} segundo {0} linggo {0} linggo {0} linggo {0} linggo {0} linggo {0} taon 1 araw 1 oras 1 millisecond 1 minuto 1 buwan 1 segundo 1 linggo 1 taon walang oras ================================================ FILE: src/Humanizer/Properties/Resources.fr.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 bit b octet o gigaoctet Go kilooctet Ko mégaoctet Mo téraoctet To il y a {0} jours avant-hier dans {0} jours après-demain il y a {0} heures dans {0} heures il y a {0} minutes dans {0} minutes il y a {0} mois dans {0} mois il y a {0} secondes dans {0} secondes il y a {0} ans dans {0} ans jamais maintenant hier demain il y a une heure dans une heure il y a une minute dans une minute il y a un mois dans un mois il y a une seconde dans une seconde il y a un an dans un an {0} jours {0} jour {0} heures {0} heure {0} millisecondes {0} milliseconde {0} minutes {0} minute {0} mois {0} mois {0} secondes {0} seconde {0} semaines {0} semaine {0} ans {0} an 1 jour un jour 1 heure une heure 1 milliseconde une milliseconde 1 minute une minute 1 mois un mois 1 seconde une seconde 1 semaine une semaine 1 an un an temps nul j h ms min mois s semaine a ================================================ FILE: src/Humanizer/Properties/Resources.he.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 לפני {0} יום {0} days ago לפני יומיים two days ago לפני {0} ימים {0} days ago בעוד {0} יום {0} days from now בעוד יומיים in 2 days בעוד {0} ימים {0} days from now לפני {0} שעות {0} hours ago לפני שעתיים two hours ago לפני {0} שעות {0} hours ago בעוד {0} שעות in {0} hours בעוד שעתיים in 2 hours בעוד {0} שעות in {0} hours לפני {0} דקות {0} minutes ago לפני {0} דקות two minutes ago לפני {0} דקות {0} minutes ago בעוד {0} דקות in {0} minutes בעוד 2 דקות in 2 minutes בעוד {0} דקות in {0} minutes לפני {0} חודשים {0} months ago לפני חודשיים two months ago לפני {0} חודשים {0} months ago בעוד {0} חודשים in {0} months בעוד חודשיים in 2 months בעוד {0} חודשים in {0} months לפני {0} שניות {0} seconds ago לפני {0} שניות two seconds ago לפני {0} שניות {0} seconds ago בעוד {0} שניות in {0} seconds בעוד 2 שניות in 2 seconds בעוד {0} שניות in {0} seconds לפני {0} שנה {0} years ago לפני שנתיים two years ago לפני {0} שנים {0} years ago בעוד {0} שנה in {0} years בעוד שנתיים in 2 years בעוד {0} שנים in {0} years כעת now אתמול yesterday מחר tomorrow לפני שעה an hour ago בעוד שעה in an hour לפני דקה a minute ago בעוד דקה in a minute לפני חודש one month ago בעוד חודש in a month לפני שנייה one second ago בעוד שנייה in a second לפני שנה one year ago בעוד שנה in a year {0} ימים {0} days יומיים two days {0} ימים {0} days {0} שעות {0} hours שעתיים two hours {0} שעות {0} hours {0} אלפיות שנייה {0} milliseconds שתי אלפיות שנייה two milliseconds {0} אלפיות שנייה {0} milliseconds {0} דקות {0} minutes שתי דקות two minutes {0} דקות {0} minutes {0} חודשים חודשיים {0} חודשים {0} שניות {0} seconds שתי שניות two seconds {0} שניות {0} seconds {0} שבועות {0} weeks שבועיים two weeks {0} שבועות {0} weeks {0} שנים שנתיים {0} שנים יום single day שעה single hour אלפית שנייה single millisecond דקה single minute חודש שנייה single second שבוע single week שנה אין זמן no time ================================================ FILE: src/Humanizer/Properties/Resources.hr.resx ================================================ text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 prije {0} dana prije {0} dana za {0} dana prije {0} sati prije {0} sata za {0} sati za {0} sata prije {0} minuta prije {0} minute za {0} minuta za {0} minute prije {0} mjeseci prije {0} mjeseca za {0} mjeseci za {0} mjeseca prije {0} sekundi prije {0} sekunde za {0} sekundi za {0} sekunde prije {0} godina prije {0} godine za {0} godina za {0} godine upravo sada jučer sutra prije sat vremena za sat vremena prije jedne minute za jednu minutu prije mjesec dana za mjesec dana prije jedne sekunde za jednu sekundu prije godinu dana za godinu dana {0} dana {0} dana {0} sati {0} sata {0} milisekundi {0} milisekunde {0} minuta {0} minute {0} mjeseci {0} mjeseca {0} sekundi {0} sekunde {0} tjedana {0} tjedna {0} godina {0} godine 1 dan 1 sat 1 milisekunda 1 minuta 1 mjesec 1 sekunda 1 tjedan 1 godina bez podatka o vremenu ================================================ FILE: src/Humanizer/Properties/Resources.hu.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 {0} napja {0} napja {0} napja {0} napja {0} napja {0} nap múlva {0} nap múlva {0} nap múlva {0} nap múlva {0} nap múlva {0} órája {0} órája {0} órája {0} órája {0} órája {0} óra múlva {0} óra múlva {0} óra múlva {0} óra múlva {0} óra múlva {0} perce {0} perce {0} perce {0} perce {0} perce {0} perc múlva {0} perc múlva {0} perc múlva {0} perc múlva {0} perc múlva {0} hónapja {0} hónapja {0} hónapja {0} hónapja {0} hónapja {0} hónap múlva {0} hónap múlva {0} hónap múlva {0} hónap múlva {0} hónap múlva {0} másodperce {0} másodperce {0} másodperce {0} másodperce {0} másodperce {0} másodperc múlva {0} másodperc múlva {0} másodperc múlva {0} másodperc múlva {0} másodperc múlva {0} éve {0} éve {0} éve {0} éve {0} éve {0} év múlva {0} év múlva {0} év múlva {0} év múlva {0} év múlva soha most tegnap holnap egy órája egy óra múlva egy perce egy perc múlva egy hónapja egy hónap múlva egy másodperce egy másodperc múlva egy éve egy év múlva két éve két év múlva kelet kelet-északkelet KÉK kelet-délkelet KDK K észak északkelet ÉK észak-északkelet ÉÉK észak-északnyugat ÉÉNy északnyugat ÉNy É dél délkelet DK dél-délkelet DDK dél-délnyugat DDNy délnyugat DNy D {0} nap {0} nap {0} nap {0} nap {0} nap {0} óra {0} óra {0} óra {0} óra {0} óra {0} ezredmásodperc {0} ezredmásodperc {0} ezredmásodperc {0} ezredmásodperc {0} ezredmásodperc {0} perc {0} perc {0} perc {0} perc {0} perc {0} hónap {0} hónap {0} hónap {0} hónap {0} hónap {0} másodperc {0} másodperc {0} másodperc {0} másodperc {0} másodperc {0} hét {0} hét {0} hét {0} hét {0} hét {0} év {0} év {0} év {0} év {0} év 1 nap egy nap 1 óra egy óra 1 ezredmásodperc egy ezredmásodperc 1 perc egy perc 1 hónap egy hónap 1 másodperc egy másodperc 1 hét egy hét 1 év egy év nincs idő n ó p h m hét é nyugat nyugat-északnyugat NyÉNy nyugat-délnyugat NyDNy Ny ================================================ FILE: src/Humanizer/Properties/Resources.hy.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 {0} օր առաջ {0} օրից {0} ժամ առաջ {0} ժամից {0} րոպե առաջ {0} րոպեից {0} ամիս առաջ {0} ամսից {0} վայրկյան առաջ {0} վայրկյանից {0} տարի առաջ {0} տարուց հիմա երեկ վաղը մեկ ժամ առաջ մեկ ժամից մեկ րոպե առաջ մեկ րոպեից մեկ ամիս առաջ մեկ ամսից մեկ վայրկյան առաջ մեկ վայրկյանից մեկ տարի առաջ մեկ տարուց {0} օր {0} ժամ {0} միլիվայրկյան {0} րոպե {0} ամիս {0} վայրկյան {0} շաբաթ {0} տարի մեկ օր մեկ ժամ մեկ միլիվայրկյան մեկ րոպե մեկ ամիս մեկ վայրկյան մեկ շաբաթ մեկ տարի ժամանակը բացակայում է ================================================ FILE: src/Humanizer/Properties/Resources.id.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 {0} hari yang lalu {0} days ago {0} hari dari sekarang {0} days from now {0} jam yang lalu {0} hours ago {0} jam dari sekarang {0} hours from now {0} menit yang lalu {0} minutes ago {0} menit dari sekarang {0} minutes from now {0} bulan yang lalu {0} months ago {0} bulan dari sekarang {0} months from now {0} detik yang lalu {0} seconds ago {0} detik dari sekarang {0} seconds from now {0} tahun yang lalu {0} years ago {0} tahun dari sekarang {0} years from now sekarang now kemarin yesterday besok tomorrow sejam yang lalu an hour ago sejam dari sekarang an hour from now semenit yang lalu a minute ago semenit dari sekarang a minute from now sebulan yang lalu one month ago sebulan dari sekarang one month from now sedetik yang lalu one second ago sedetik dari sekarang one second from now setahun yang lalu one year ago setahun dari sekarang one year from now {0} hari {0} days {0} jam {0} hours {0} milidetik {0} milliseconds {0} menit {0} minutes {0} bulan {0} detik {0} seconds {0} minggu {0} weeks {0} tahun 1 hari 1 day 1 jam 1 hour 1 milidetik 1 millisecond 1 menit 1 minute 1 bulan 1 detik 1 second 1 minggu 1 week 1 tahun waktu kosong no time ================================================ FILE: src/Humanizer/Properties/Resources.is.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 biti b bæti B gígabæti GB kílóbæti kB megabæti MB terabæti TB fyrir {0} dögum fyrir {0} dögum fyrir {0} degi eftir {0} daga eftir {0} daga eftir {0} dag fyrir {0} klukkustundum fyrir {0} klukkustundum fyrir {0} klukkustund eftir {0} klukkustundir eftir {0} klukkustundir eftir {0} klukkustund fyrir {0} mínútum fyrir {0} mínútum fyrir {0} mínútu eftir {0} mínútur eftir {0} mínútur eftir {0} mínútu fyrir {0} mánuðum fyrir {0} mánuðum fyrir {0} mánuði eftir {0} mánuði eftir {0} mánuði eftir {0} mánuð fyrir {0} sekúndum fyrir {0} sekúndu fyrir {0} sekúndu eftir {0} sekúndur eftir {0} sekúndur eftir {0} sekúndu fyrir {0} árum fyrir {0} árum fyrir {0} ári eftir {0} ár eftir {0} ár eftir {0} ár aldrei núna í gær á morgun fyrir einni klukkustund eftir eina klukkustund fyrir einni mínútu eftir eina mínútu fyrir einum mánuði eftir einn mánuð fyrir einni sekúndu eftir eina sekúndu fyrir einu ári eftir eitt ár austur austnorðaustur ANA austsuðaustur ASA A norður norðaustur NA norðnorðaustur NNA norðnorðvestur NNV norðvestur NV N suður suðaustur SA suðsuðaustur SSA suðsuðvestur SSV suðvestur SV S {0} dagar {0} dagar {0} dagur {0} klukkustundir {0} klukkustundir {0} klukkustund {0} millisekúndur {0} millisekúndur {0} millisekúnda {0} mínútur {0} mínútur {0} mínúta {0} mánuðir {0} mánuðir {0} mánuðir {0} sekúndur {0} sekúndur {0} sekúnda {0} vikur {0} vikur {0} vika {0} ár {0} ár {0} ár einn dagur einn dagur ein klukkustund ein klukkustund ein millisekúnda ein millisekúnda ein mínúta ein mínúta 1 mánuður einn mánuður ein sekúnda ein sekúnda ein vika ein vika 1 ár eitt ár engin stund vestur vestnorðvestur VNV vestsuðvestur VSV V ================================================ FILE: src/Humanizer/Properties/Resources.it.resx ================================================ text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 {0} giorni fa tra {0} giorni {0} ore fa tra {0} ore {0} minuti fa tra {0} minuti {0} mesi fa tra {0} mesi {0} secondi fa tra {0} secondi {0} anni fa tra {0} anni adesso ieri domani un'ora fa tra un'ora un minuto fa tra un minuto un mese fa tra un mese un secondo fa tra un secondo un anno fa tra un anno {0} giorni {0} ore {0} millisecondi {0} minuti {0} mesi {0} secondi {0} settimane {0} anni 1 giorno un giorno 1 ora una ora 1 millisecondo un millisecondo 1 minuto un minuto 1 mese un mese 1 secondo un secondo 1 settimana una settimana 1 anno un anno 0 secondi ================================================ FILE: src/Humanizer/Properties/Resources.ja.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 {0} 日前 {0} 日後 {0} 時間前 {0} 時間後 {0} 分前 {0} 分後 {0} か月前 {0} か月後 {0} 秒前 {0} 秒後 {0} 年前 {0} 年後 昨日 明日 1 時間前 1 時間後 1 分前 1 分後 先月 来月 1 秒前 1 秒後 去年 来年 {0} 日 {0} 時間 {0} ミリ秒 {0} 分 {0} ヶ月 {0} 秒 {0} 週間 {0} 年 1 日 1 時間 1 ミリ秒 1 分 1 ヶ月 1 秒 1 週間 1 年 0 秒 ================================================ FILE: src/Humanizer/Properties/Resources.ko.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 {0}일 전 {0}일 전 {0}일 전 {0}일 전 {0}일 후 {0}일 후 {0}일 후 {0}일 후 {0}시간 전 {0}시간 전 {0}시간 전 {0}시간 전 {0}시간 전 {0}시간 후 {0}시간 후 {0}시간 후 {0}시간 후 {0}시간 후 {0}분 전 {0}분 전 {0}분 전 {0}분 전 {0}분 전 {0}분 후 {0}분 후 {0}분 후 {0}분 후 {0}분 후 {0}개월 전 {0}개월 전 {0}개월 전 {0}개월 전 {0}개월 전 {0}개월 후 {0}개월 후 {0}개월 후 {0}개월 후 {0}개월 후 {0}초 전 {0}초 전 {0}초 전 {0}초 전 {0}초 전 {0}초 후 {0}초 후 {0}초 후 {0}초 후 {0}초 후 {0}년 전 {0}년 전 {0}년 전 {0}년 전 {0}년 전 {0}년 후 {0}년 후 {0}년 후 {0}년 후 {0}년 후 사용 안 함 지금 어제 내일 1시간 전 1시간 후 1분 전 1분 후 1개월 전 1개월 후 1초 전 1초 후 1년 전 1년 후 {0}일 {0}일 {0}일 {0}일 {0}시간 {0}시간 {0}시간 {0}시간 {0}시간 {0}밀리초 {0}밀리초 {0}밀리초 {0}밀리초 {0}밀리초 {0}분 {0}분 {0}분 {0}분 {0}분 {0}개월 {0}초 {0}초 {0}초 {0}초 {0}초 {0}주 {0}주 {0}주 {0}주 {0}주 {0}년 1일 1시간 1밀리초 1분 1개월 1초 1주 1년 방금 ================================================ FILE: src/Humanizer/Properties/Resources.ku.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 {0} ڕۆژ لەمەوبەر {0} ڕۆژ لەمەوبەر {0} ڕۆژ لەمەوبەر {0} ڕۆژ لەمەوبەر {0} ڕۆژی دیکە {0} ڕۆژی دیکە {0} ڕۆژی دیکە {0} ڕۆژی دیکە {0} کاتژمێر لەمەوبەر {0} کاتژمێر لەمەوبەر {0} کاتژمێر لەمەوبەر {0} کاتژمێر لەمەوبەر {0} کاتژمێر لەمەوبەر {0} کاتژمێری دیکە {0} کاتژمێری دیکە {0} کاتژمێری دیکە {0} کاتژمێری دیکە {0} کاتژمێری دیکە {0} خولەک لەمەوبەر {0} خولەک لەمەوبەر {0} خولەک لەمەوبەر {0} خولەک لەمەوبەر {0} خولەک لەمەوبەر {0} خولەکی دیکە {0} خولەکی دیکە {0} خولەکی دیکە {0} خولەکی دیکە {0} خولەکی دیکە {0} مانگ لەمەوبەر {0} مانگ لەمەوبەر {0} مانگ لەمەوبەر {0} مانگ لەمەوبەر {0} مانگ لەمەوبەر {0} مانگی دیکە {0} مانگی دیکە {0} مانگی دیکە {0} مانگی دیکە {0} مانگی دیکە {0} چرکە لەمەوبەر {0} چرکە لەمەوبەر {0} چرکە لەمەوبەر {0} چرکە لەمەوبەر {0} چرکە لەمەوبەر {0} چرکەی دیکە {0} چرکەی دیکە {0} چرکەی دیکە {0} چرکەی دیکە {0} چرکەی دیکە {0} ساڵ لەمەوبەر {0} ساڵ لەمەوبەر {0} ساڵ لەمەوبەر {0} ساڵ لەمەوبەر {0} ساڵ لەمەوبەر {0} ساڵی دیکە {0} ساڵی دیکە {0} ساڵی دیکە {0} ساڵی دیکە {0} ساڵی دیکە هەرگیز ئێستا دوێنێ بەیانی کاتژمێرێک لەمەوبەر کاتژمێرێکی دیکە خولەکێک لەمەوبەر خولەکێکی دیکە مانگێک لەمەوبەر مانگێکی دیکە چرکەیەک لەمەوبەر چرکەیەکی دیکە ساڵێک لەمەوبەر ساڵێکی دیکە {0} ڕۆژ {0} ڕۆژ {0} ڕۆژ {0} ڕۆژ {0} ڕۆژ {0} کاتژمێر {0} کاتژمێر {0} کاتژمێر {0} کاتژمێر {0} کاتژمێر {0} میلیچرکە {0} میلیچرکە {0} میلیچرکە {0} میلیچرکە {0} میلیچرکە {0} خولەک {0} خولەک {0} خولەک {0} خولەک {0} خولەک {0} مانگ {0} مانگ {0} مانگ {0} مانگ {0} مانگ {0} چرکە {0} چرکە {0} چرکە {0} چرکە {0} چرکە {0} هەفتە {0} هەفتە {0} هەفتە {0} هەفتە {0} هەفتە {0} ساڵ {0} ساڵ {0} ساڵ {0} ساڵ {0} ساڵ 1 ڕۆژ یەک ڕۆژ 1 کاتژمێر یەک کاتژمێر 1 میلیچرکە یەک میلیچرکە 1 خولەک یەک خولەک 1 مانگ یەک مانگ 1 چرکە یەک چرکە 1 هەفتە یەک هەفتە 1 ساڵ یەک ساڵ ئێستا ================================================ FILE: src/Humanizer/Properties/Resources.lb.resx ================================================  text/microsoft-resx 1.3 System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Bit bit Byte B Gigabyte GB Kilobyte KB Megabyte MB Terabyte TB viru{1} {0} Deeg virgëschter virun engem Dag a{1} {0} Deeg iwwermuer viru{1} {0} Stonnen a{1} {0} Stonnen viru{1} {0} Minutten a{1} {0} Minutten viru{1} {0} Méint a{1} {0} Méint viru{1} {0} Sekonnen a{1} {0} Sekonnen viru{1} {0} Joer a{1} {0} Joer ni elo gëschter muer virun enger Stonn an enger Stonn virun enger Minutt an enger Minutt virun engem Mount an engem Mount virun enger Sekonn an enger Sekonn virun engem Joer an engem Joer {0} Deeg {0} Stonnen {0} Millisekonnen {0} Minutten {0} Méint {0} Sekonnen {0} Wochen {0} Joer 1 Dag een Dag 1 Stonn eng Stonn 1 Millisekonn eng Millisekonn 1 Minutt eng Minutt 1 Mount ee Mount 1 Sekonn eng Sekonn 1 Woch eng Woch 1 Joer ee Joer Keng Zäit ================================================ FILE: src/Humanizer/Properties/Resources.lt.resx ================================================ text/microsoft-resx 1.3 System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 prieš {0} dienas prieš {0} dienų prieš {0} dieną po {0} dienų po {0} dienos prieš {0} valandas prieš {0} valandų prieš {0} valandą po {0} valandų po {0} valandos prieš {0} minutes prieš {0} minučių prieš {0} minutę po {0} minučių po {0} minutės prieš {0} mėnesius prieš {0} mėnesių prieš {0} mėnesį po {0} mėnesių po {0} mėnesio prieš {0} sekundes prieš {0} sekundžių prieš {0} sekundę po {0} sekundžių po {0} sekundės prieš {0} metus prieš {0} metų prieš {0} metus po {0} metų po {0} metų po {0} metų niekada dabar vakar rytoj prieš valandą po valandos prieš minutę po minutės prieš vieną mėnesį po vieno mėnesio prieš vieną sekundę po vienos sekundės prieš vienerius metus po vienerių metų {0} dienos {0} dienų {0} diena {0} valandos {0} valandų {0} valanda {0} milisekundės {0} milisekundžių {0} milisekundė {0} minutės {0} minučių {0} minutė {0} mėnesiai {0} mėnesių {0} mėnuo {0} sekundės {0} sekundžių {0} sekundė {0} savaitės {0} savaičių {0} savaitė {0} metai {0} metų {0} metai 1 diena viena diena 1 valanda viena valanda 1 milisekundė viena milisekundė 1 minutė viena minutė 1 mėnuo vienas mėnuo 1 sekundė viena sekundė 1 savaitė viena savaitė 1 metai vieni metai nėra laiko ================================================ FILE: src/Humanizer/Properties/Resources.lv.resx ================================================ text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 pirms {0} dienām pirms {0} dienām pirms {0} dienām pirms {0} dienas pēc {0} dienām pēc {0} dienām pēc {0} dienām pēc {0} dienas pirms {0} stundām pirms {0} stundām pirms {0} stundām pirms {0} stundām pirms {0} stundas pēc {0} stundām pēc {0} stundām pēc {0} stundām pēc {0} stundām pēc {0} stundas pirms {0} minūtēm pirms {0} minūtēm pirms {0} minūtēm pirms {0} minūtēm pirms {0} minūtes pēc {0} minūtēm pēc {0} minūtēm pēc {0} minūtēm pēc {0} minūtēm pēc {0} minūtes pirms {0} mēnešiem pirms {0} mēnešiem pirms {0} mēnešiem pirms {0} mēnešiem pirms {0} mēneša pēc {0} mēnešiem pēc {0} mēnešiem pēc {0} mēnešiem pēc {0} mēnešiem pēc {0} mēneša pirms {0} sekundēm pirms {0} sekundēm pirms {0} sekundēm pirms {0} sekundēm pirms {0} sekundes pēc {0} sekundēm pēc {0} sekundēm pēc {0} sekundēm pēc {0} sekundēm pēc {0} sekundes pirms {0} gadiem pirms {0} gadiem pirms {0} gadiem pirms {0} gadiem pirms {0} gada pēc {0} gadiem pēc {0} gadiem pēc {0} gadiem pēc {0} gadiem pēc {0} gada nekad tagad vakardien rītdien pirms stundas pēc stundas pirms minūtes pēc minūtēs pirms mēneša pēc mēneša pirms sekundes pēc sekundes pirms gada pēc gada {0} dienas {0} dienas {0} dienas {0} diena {0} stundas {0} stundas {0} stundas {0} stundas {0} stunda {0} milisekundes {0} milisekundes {0} milisekundes {0} milisekundes {0} milisekunde {0} minūtes {0} minūtes {0} minūtes {0} minūtes {0} minūte {0} mēneši {0} sekundes {0} sekundes {0} sekundes {0} sekundes {0} sekunde {0} nedēļas {0} nedēļas {0} nedēļas {0} nedēļas {0} nedēļa {0} gadi 1 diena 1 stunda 1 milisekunde 1 minūte 1 mēnesis 1 sekunde 1 nedēļa 1 gads bez laika ================================================ FILE: src/Humanizer/Properties/Resources.ms.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 {0} hari yang lalu {0} hari yang lalu {0} hari yang lalu {0} hari yang lalu {0} hari dari sekarang {0} hari dari sekarang {0} hari dari sekarang {0} hari dari sekarang {0} jam yang lalu {0} jam yang lalu {0} jam yang lalu {0} jam yang lalu {0} jam yang lalu {0} jam dari sekarang {0} jam dari sekarang {0} jam dari sekarang {0} jam dari sekarang {0} jam dari sekarang {0} minit yang lalu {0} minit yang lalu {0} minit yang lalu {0} minit yang lalu {0} minit yang lalu {0} minit dari sekarang {0} minit dari sekarang {0} minit dari sekarang {0} minit dari sekarang {0} minit dari sekarang {0} bulan yang lalu {0} bulan yang lalu {0} bulan yang lalu {0} bulan yang lalu {0} bulan yang lalu {0} bulan dari sekarang {0} bulan dari sekarang {0} bulan dari sekarang {0} bulan dari sekarang {0} bulan dari sekarang {0} saat yang lalu {0} saat yang lalu {0} saat yang lalu {0} saat yang lalu {0} saat yang lalu {0} saat dari sekarang {0} saat dari sekarang {0} saat dari sekarang {0} saat dari sekarang {0} saat dari sekarang {0} tahun yang lalu {0} tahun yang lalu {0} tahun dari yang lalu {0} tahun yang lalu {0} tahun yang lalu {0} tahun dari sekarang {0} tahun dari sekarang {0} tahun dari sekarang {0} tahun dari sekarang {0} tahun dari sekarang tidak pernah sekarang semalam esok sejam yang lalu sejam dari sekarang seminit yang lalu seminit dari sekarang sebulan yang lalu sebulan dari sekarang sesaat yang lalu sesaat dari sekarang setahun yang lalu setahun dari sekarang {0} hari {0} hari {0} hari {0} hari {0} jam {0} jam {0} jam {0} jam {0} jam {0} milisaat {0} milisaat {0} milisaat {0} milisaat {0} milisaat {0} minit {0} minit {0} minit {0} minit {0} minit {0} bulan {0} saat {0} saat {0} saat {0} saat {0} saat {0} minggu {0} minggu {0} minggu {0} minggu {0} minggu {0} tahun 1 hari 1 jam 1 milisaat 1 minit 1 bulan 1 saat 1 minggu 1 tahun tiada masa ================================================ FILE: src/Humanizer/Properties/Resources.mt.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 {0} jiem ilu jumejn ilu {0} jiem ilu il-bieraħ {0} jiem oħra pitgħada {0} jiem oħra għada {0} siegħat ilu sagħtejn ilu {0} siegħat ilu {0} siegħat ilu siegħa ilu {0} siegħat oħra sagħtejn oħra {0} siegħat oħra {0} siegħat oħra siegħa oħra {0} minuti ilu {0} minuti ilu {0} minuti ilu {0} minuti ilu minuta ilu {0} minuti oħra {0} minuti oħra {0} minuti oħra {0} minuti oħra minuta oħra {0} xhur ilu xahrejn ilu {0} xhur ilu {0} xhur ilu xahar ilu {0} xhur oħra xahrejn oħra {0} xhur oħra {0} xhur oħra xahar ieħor {0} sekondi ilu {0} sekondi ilu {0} sekondi ilu {0} sekondi ilu sekonda ilu {0} sekondi oħra {0} sekondi oħra {0} sekondi oħra {0} sekondi oħra sekonda oħra {0} snin ilu sentejn ilu {0} snin ilu {0} snin ilu sena ilu {0} snin oħra sentejn oħra {0} snin oħra {0} snin oħra sena oħra qatt issa il-bieraħ għada siegħa ilu siegħa oħra minuta ilu minuta oħra xahar ilu xahar ieħor sekonda ilu sekonda oħra sena ilu sena oħra lvant grieg il-lvant GL east-southeast xlokk il-lvant L XL grigal G grieg it-tramuntana GT majjistral it-tramuntana MT majjistral M T nofsinhar xlokk X nofsinhar ix-xlokk NX nofsinhar il-lbiċ NL lbiċ L N {0} jiem jumejn {0} jiem {0} jiem jum {0} siegħat sagħtejn {0} siegħat {0} siegħat siegħa {0} millisekondi {0} millisekondi {0} millisekondi {0} millisekondi millisekonda {0} minuti {0} minuti {0} minuti {0} minuti {0} minuta {0} xhur xahrejn {0} xhur {0} xhur xahar {0} sekondi {0} sekondi {0} sekondi {0} sekondi sekonda {0} ġimgħat ġimgħatejn {0} ġimgħat {0} ġimgħat ġimgħa {0} snin sentejn {0} snin {0} snin {0} snin ġurnata ġurnata siegħa siegħa millisekonda millisekonda minuta minuta xahar xahar sekonda sekonda ġimgħa ġimgħa sena sena xejn punent punent majjistru PM punent il-lbiċ PL P ================================================ FILE: src/Humanizer/Properties/Resources.nb.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 {0} dager siden {0} dager fra nå {0} timer siden {0} timer fra nå {0} minutter siden {0} minutter fra nå {0} måneder siden {0} måneder fra nå {0} sekunder siden {0} sekunder fra nå {0} år siden {0} år fra nå i går i morgen en time siden en time fra nå ett minutt siden ett minutt fra nå en måned siden en måned fra nå ett sekund siden ett sekund fra nå ett år siden ett år fra nå {0} dager {0} timer {0} millisekunder {0} minutter {0} måneder {0} sekunder {0} uker {0} år 1 dag en dag 1 time en time 1 millisekund ett millisekund 1 minutt ett minutt 1 måned en måned 1 sekund ett sekund 1 uke en uke 1 år ett år ingen tid ================================================ FILE: src/Humanizer/Properties/Resources.nl.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 {0} dagen geleden over {0} dagen {0} uur geleden over {0} uur {0} minuten geleden over {0} minuten {0} maanden geleden over {0} maanden {0} seconden geleden over {0} seconden {0} jaar geleden over {0} jaar nu gisteren morgen 1 uur geleden over 1 uur 1 minuut geleden over 1 minuut 1 maand geleden over 1 maand 1 seconde geleden over 1 seconde 1 jaar geleden over 1 jaar {0} dagen {0} uur {0} milliseconden {0} minuten {0} maanden {0} seconden {0} weken {0} jaar 1 dag 1 uur 1 milliseconde 1 minuut 1 maand 1 seconde 1 week 1 jaar geen tijd ================================================ FILE: src/Humanizer/Properties/Resources.pl.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 przed {0} dniami przed {0} dniami za {0} dni za {0} dni przed {0} godzinami przed {0} godzinami za {0} godzin za {0} godziny przed {0} minutami przed {0} minutami za {0} minut za {0} minuty przed {0} miesiącami przed {0} miesiącami za {0} miesięcy za {0} miesiące przed {0} sekundami przed {0} sekundami za {0} sekund za {0} sekundy przed {0} laty przed {0} laty za {0} lat za {0} lata teraz wczoraj jutro przed godziną za godzinę przed minutą za minutę przed miesiącem za miesiąc przed sekundą za sekundę przed rokiem za rok {0} dni {0} dni {0} godzin {0} godziny {0} milisekund {0} milisekundy {0} minut {0} minuty {0} miesięcy {0} miesiące {0} sekund {0} sekundy {0} tygodni {0} tygodnie {0} lat {0} lata 1 dzień 1 godzina 1 milisekunda 1 minuta 1 miesiąc 1 sekunda 1 tydzień 1 rok brak czasu ================================================ FILE: src/Humanizer/Properties/Resources.pt-BR.resx ================================================ text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 bit Unidade de dados: bit bit Símbolo da unidade de dados: bit byte Unidade de dados: byte B Símbolo da unidade de dados: byte gigabyte Unidade de dados: gigabyte GB Símbolo da unidade de dados: gigabyte kilobyte Unidade de dados: kilobyte KB Símbolo da unidade de dados: kilobyte megabyte Unidade de dados: megabyte MB Símbolo da unidade de dados: megabyte terabyte Unidade de dados: terabyte TB Símbolo da unidade de dados: terabyte {0} dias atrás {0} dias atrás {0} dias atrás {0} dia atrás em {0} dias em {0} dias em {0} dias em {0} dia {0} horas atrás {0} horas atrás {0} horas atrás {0} horas atrás {0} hora atrás em {0} horas em {0} horas em {0} horas em {0} horas em {0} hora {0} minutos atrás {0} minutos atrás {0} minutos atrás {0} minutos atrás {0} minuto atrás em {0} minutos em {0} minutos em {0} minutos em {0} minutos em {0} minuto {0} meses atrás {0} meses atrás {0} meses atrás {0} meses atrás {0} mês atrás em {0} meses em {0} meses em {0} meses em {0} meses em {0} mês {0} segundos atrás {0} segundos atrás {0} segundos atrás {0} segundos atrás {0} segundo atrás em {0} segundos em {0} segundos em {0} segundos em {0} segundos em {0} segundo {0} anos atrás {0} anos atrás {0} anos atrás {0} anos atrás {0} ano atrás em {0} anos em {0} anos em {0} anos em {0} anos em {0} ano nunca agora ontem amanhã uma hora atrás em uma hora um minuto atrás em um minuto um mês atrás em um mês um segundo atrás em um segundo um ano atrás em um ano leste leste-nordeste LNE leste-sudeste LSE L norte nordeste NE norte-nordeste NNE norte-noroeste NNO noroeste NO N sul sudeste SE sul-sudeste SSE sul-sudoeste SSO sudoeste SO S {0} dias {0} dias {0} dias {0} dias {0} dia {0} horas {0} horas {0} horas {0} horas {0} hora {0} milisegundos {0} milisegundos {0} milisegundos {0} milisegundos {0} milisegundo {0} minutos {0} minutos {0} minutos {0} minutos {0} minuto {0} meses {0} meses {0} meses {0} meses {0} mês {0} segundos {0} segundos {0} segundos {0} segundos {0} segundo {0} semanas {0} semanas {0} semanas {0} semanas {0} semana {0} anos {0} anos {0} anos {0} anos {0} ano 1 dia um dia 1 hora uma hora 1 milisegundo um milisegundo 1 minuto um minuto 1 mês um mês 1 segundo um segundo 1 semana uma semana 1 ano um ano sem horário d Unidade de tempo: dia h Unidade de tempo: hora ms Unidade de tempo: milisegundo min Unidade de tempo: minuto m Unidade de tempo: mês s Unidade de tempo: segundo semana Unidade de tempo: semana a Unidade de tempo: ano oeste oeste-noroeste ONO oeste-sudoeste OSO O ================================================ FILE: src/Humanizer/Properties/Resources.pt.resx ================================================ text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 bit Unidade de dados: bit bit Símbolo da unidade de dados: bit byte Unidade de dados: byte B Símbolo da unidade de dados: byte gigabyte Unidade de dados: gigabyte GB Símbolo da unidade de dados: gigabyte kilobyte Unidade de dados: kilobyte KB Símbolo da unidade de dados: kilobyte megabyte Unidade de dados: megabyte MB Símbolo da unidade de dados: megabyte terabyte Unidade de dados: terabyte TB Símbolo da unidade de dados: terabyte há {0} dias há {0} dias há {0} dias há {0} dia daqui a {0} dias daqui a {0} dias daqui a {0} dias daqui a {0} dia há {0} horas há {0} horas há {0} horas há {0} horas há {0} hora daqui a {0} horas daqui a {0} horas daqui a {0} horas daqui a {0} horas daqui a {0} hora há {0} minutos há {0} minutos há {0} minutos há {0} minutos há {0} minuto daqui a {0} minutos daqui a {0} minutos daqui a {0} minutos daqui a {0} minutos daqui a {0} minuto há {0} meses há {0} meses há {0} meses há {0} meses há {0} mês daqui a {0} meses daqui a {0} meses daqui a {0} meses daqui a {0} meses daqui a {0} mês há {0} segundos há {0} segundos há {0} segundos há {0} segundos há {0} segundo daqui a {0} segundos daqui a {0} segundos daqui a {0} segundos daqui a {0} segundos daqui a {0} segundo há {0} anos há {0} anos há {0} anos há {0} anos há {0} ano daqui a {0} anos daqui a {0} anos daqui a {0} anos daqui a {0} anos daqui a {0} ano nunca agora ontem amanhã há uma hora daqui a uma hora há um minuto daqui a um minuto há um mês daqui a um mês há um segundo daqui a um segundo há um ano daqui a um ano leste leste-nordeste LNE leste-sudeste LSE L norte nordeste NE norte-nordeste NNE norte-noroeste NNO noroeste NO N sul sudeste SE sul-sudeste SSE sul-sudoeste SSO sudoeste SO S {0} dias {0} dias {0} dias {0} dias {0} dia {0} horas {0} horas {0} horas {0} horas {0} hora {0} milisegundos {0} milisegundos {0} milisegundos {0} milisegundos {0} milisegundo {0} minutos {0} minutos {0} minutos {0} minutos {0} minuto {0} meses {0} meses {0} meses {0} meses {0} mês {0} segundos {0} segundos {0} segundos {0} segundos {0} segundo {0} semanas {0} semanas {0} semanas {0} semanas {0} semana {0} anos {0} anos {0} anos {0} anos {0} ano 1 dia um dia 1 hora uma hora 1 milisegundo um milisegundo 1 minuto um minuto 1 mês um mês 1 segundo um segundo 1 semana uma semana 1 ano um ano sem horário d Unidade de tempo: dia h Unidade de tempo: hora ms Unidade de tempo: milisegundo min Unidade de tempo: minuto m Unidade de tempo: mês s Unidade de tempo: segundo semana Unidade de tempo: semana a Unidade de tempo: ano oeste oeste-noroeste ONO oeste-sudoeste OSO O ================================================ FILE: src/Humanizer/Properties/Resources.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 bit Data unit: bit b Symbol for data unit: bit byte Data unit: byte B Symbol for data unit: byte gigabyte Data unit: gigabyte GB Symbol for data unit: gigabyte kilobyte Data unit: kilobyte KB Symbol for data unit: kilobyte megabyte Data unit: megabyte MB Symbol for data unit: megabyte terabyte Data unit: terabyte TB Symbol for data unit: terabyte {0} days ago Date, number in word form, ambiguous {0} days ago Date, number in word form, dual {0} days ago Date, number in word form, paucal {0} days ago Date, number in word form, plural {0} day ago Date, number in word form, singular {0} days from now Date, number in word form, ambiguous {0} days from now Date, number in word form, dual {0} days from now Date, number in word form, paucal {0} days from now Date, number in word form, plural {0} day from now Date, number in word form, singular {0} hours ago Time, number in word form, ambiguous {0} hours ago Time, number in word form, dual {0} hours ago Time, number in word form, paucal {0} hours ago Time, number in word form, plural {0} hour ago Time, number in word form, singular {0} hours from now Time, number in word form, ambiguous {0} hours from now Time, number in word form, dual {0} hours from now Time, number in word form, paucal {0} hours from now Time, number in word form, plural {0} hour from now Time, number in word form, singular {0} minutes ago Time, number in word form, ambiguous {0} minutes ago Time, number in word form, dual {0} minutes ago Time, number in word form, paucal {0} minutes ago Time, number in word form, plural {0} minute ago Time, number in word form, singular {0} minutes from now Time, number in word form, ambiguous {0} minutes from now Time, number in word form, dual {0} minutes from now Time, number in word form, paucal {0} minutes from now Time, number in word form, plural {0} minute from now Time, number in word form, singular {0} months ago Date, number in word form, ambiguous {0} months ago Date, number in word form, dual {0} months ago Date, number in word form, paucal {0} months ago Date, number in word form, plural {0} month ago Date, number in word form, singular {0} months from now Date, number in word form, ambiguous {0} months from now Date, number in word form, dual {0} months from now Date, number in word form, paucal {0} months from now Date, number in word form, plural {0} month from now Date, number in word form, singular {0} seconds ago Time, number in word form, ambiguous {0} seconds ago Time, number in word form, dual {0} seconds ago Time, number in word form, paucal {0} seconds ago Time, number in word form, plural {0} second ago Time, number in word form, singular {0} seconds from now Time, number in word form, ambiguous {0} seconds from now Time, number in word form, dual {0} seconds from now Time, number in word form, paucal {0} seconds from now Time, number in word form, plural {0} second from now Time, number in word form, singular {0} years ago Date, number in word form, ambiguous {0} years ago Date, number in word form, dual {0} years ago Date, number in word form, paucal {0} years ago Date, number in word form, plural {0} year ago Date, number in word form, singular {0} years from now Date, number in word form, ambiguous {0} years from now Date, number in word form, dual {0} years from now Date, number in word form, paucal {0} years from now Date, number in word form, plural {0} year from now Date, number in word form, singular never Date/Time now Date/Time yesterday Date tomorrow Date an hour ago Time an hour from now Time a minute ago Time a minute from now Time one month ago Date one month from now Date one second ago Time one second from now Time one year ago Date one year from now Date two days ago Date two days from now Date east Cardinal Direction east-northeast Cardinal Direction ENE Cardinal Direction Abbreviation east-southeast Cardinal Direction ESE Cardinal Direction Abbreviation E Cardinal Direction Abbreviation north Cardinal Direction northeast Cardinal Direction NE Cardinal Direction Abbreviation north-northeast Cardinal Direction NNE Cardinal Direction Abbreviation north-northwest Cardinal Direction NNW Cardinal Direction Abbreviation northwest Cardinal Direction NW Cardinal Direction Abbreviation N Cardinal Direction Abbreviation south Cardinal Direction southeast Cardinal Direction SE Cardinal Direction Abbreviation south-southeast Cardinal Direction SSE Cardinal Direction Abbreviation south-southwest Cardinal Direction SSW Cardinal Direction Abbreviation southwest Cardinal Direction SW Cardinal Direction Abbreviation S Cardinal Direction Abbreviation {0} old Age as in 'three years old' {0} days Date, number as words, ambiguous {0} days Date, number as words, dual {0} days Date, number as words, paucal {0} days Date, number as words, plural {0} day Date, number as words, singular {0} hours Time, number as words, ambiguous {0} hours Time, number as words, dual {0} hours Time, number as words, paucal {0} hours Time, number as words, plural {0} hour Time, number as words, singular {0} milliseconds Time, number as words, ambiguous {0} milliseconds Time, number as words, dual {0} milliseconds Time, number as words, paucal {0} milliseconds Time, number as words, plural {0} millisecond Time, number as words, singular {0} minutes Date, number as words, ambiguous {0} minutes Date, number as words, dual {0} minutes Date, number as words, paucal {0} minutes Date, number as words, plural {0} minute Date, number as words, singular {0} months Date, number as words, ambiguous {0} months Date, number as words, dual {0} months Date, number as words, paucal {0} months Date, number as words, plural {0} months Date, number as words, singular {0} seconds Time, number as words, ambiguous {0} seconds Time, number as words, dual {0} seconds Time, number as words, paucal {0} seconds Time, number as words, plural {0} second Time, number as words, singular {0} weeks Date, number as words, ambiguous {0} weeks Date, number as words, dual {0} weeks Date, number as words, paucal {0} weeks Date, number as words, plural {0} week Date, number as words, singular {0} years Date, number as words, ambiguous {0} years Date, number as words, dual {0} years Date, number as words, paucal {0} years Date, number as words, plural {0} years Date, number as words, singular 1 day Date single as number one day Date words 1 hour Time single as number one hour Time words 1 millisecond Time single as number one millisecond Time words 1 minute Time single as number one minute Time words 1 month Date single as number one month Date words 1 second Time single as number one second Time words 1 week Date single as number one week Date words 1 year Date single as number one year Date words no time Time d Time unit: day h Time unit: hour ms Time unit: millisecond min Time unit: minute mo Time unit: month s Time unit: second week Time unit: week y Time unit: year west Cardinal Direction west-northwest Cardinal Direction WNW Cardinal Direction Abbreviation west-southwest Cardinal Direction WSW Cardinal Direction Abbreviation W Cardinal Direction Abbreviation ================================================ FILE: src/Humanizer/Properties/Resources.ro.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 acum {0}{1} zile peste {0}{1} zile acum {0}{1} ore peste {0}{1} ore acum {0}{1} minute peste {0}{1} minute acum {0}{1} luni peste {0}{1} luni acum {0}{1} secunde peste {0}{1} secunde acum {0}{1} ani peste {0}{1} ani acum ieri mâine acum o oră peste o oră acum un minut peste un minut acum o lună peste o lună acum o secundă peste o secundă acum un an peste un an {0}{1} zile {0}{1} ore {0}{1} milisecunde {0}{1} minute {0}{1} luni {0}{1} secunde {0}{1} săptămâni {0}{1} ani 1 zi 1 oră 1 milisecundă 1 minut 1 lună 1 secundă 1 săptămână 1 an 0 secunde ================================================ FILE: src/Humanizer/Properties/Resources.ru.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 бит бит байт Б гигабайт ГБ килобайт КБ мегабайт МБ терабайт ТБ {0} дней назад {0} дня назад {0} дня назад {0} дней назад {0} день назад через {0} дней через {0} дня через {0} дня через {0} дней через {0} день {0} часов назад {0} часа назад {0} часа назад {0} часов назад {0} час назад через {0} часов через {0} часа через {0} часа через {0} часов через {0} час {0} минут назад {0} минуты назад {0} минуты назад {0} минут назад {0} минуту назад через {0} минут через {0} минуты через {0} минуты через {0} минут через {0} минуту {0} месяцев назад {0} месяца назад {0} месяца назад {0} месяцев назад {0} месяц назад через {0} месяцев через {0} месяца через {0} месяца через {0} месяцев через {0} месяц {0} секунд назад {0} секунды назад {0} секунды назад {0} секунд назад {0} секунду назад через {0} секунд через {0} секунды через {0} секунды через {0} секунд через {0} секунду {0} лет назад {0} года назад {0} года назад {0} лет назад {0} год назад через {0} лет через {0} года через {0} года через {0} лет через {0} год никогда сейчас вчера завтра час назад через час минуту назад через минуту месяц назад через месяц секунду назад через секунду год назад через год два дня назад через два дня восток востоко-северо-восток ВСВ востоко-юго-восток ВЮВ В север северо-восток СВ северо-северо-восток ССВ северо-северо-запад ССЗ северо-запад СЗ С юг юго-восток ЮВ юго-юго-восток ЮЮВ юго-юго-запад ЮЮЗ юго-запад ЮЗ Ю {0} дней {0} дня {0} дня {0} дней {0} день {0} часов {0} часа {0} часа {0} часов {0} час {0} миллисекунд {0} миллисекунды {0} миллисекунды {0} миллисекунд {0} миллисекунда {0} минут {0} минуты {0} минуты {0} минут {0} минута {0} месяцев {0} месяца {0} месяца {0} месяцев {0} месяц {0} секунд {0} секунды {0} секунды {0} секунд {0} секунда {0} недель {0} недели {0} недели {0} недель {0} неделя {0} лет {0} года {0} года {0} лет {0} год 1 день один день 1 час один час 1 миллисекунда одна миллисекунда 1 минута одна минута 1 месяц один месяц 1 секунда одна секунда 1 неделя одна неделя 1 год один год нет времени д. ч. мс. мин. мес. сек. нед. г. запад западо-северо-запад ЗСЗ западо-юго-запад ЗЮЗ З ================================================ FILE: src/Humanizer/Properties/Resources.sk.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 pred {0} dňami pred {0} dňami o {0} dní o {0} dni pred {0} hodinami pred {0} hodinami o {0} hodín o {0} hodiny pred {0} minútami pred {0} minútami o {0} minút o {0} minúty pred {0} mesiacmi pred {0} mesiacmi o {0} mesiacov o {0} mesiace pred {0} sekundami pred {0} sekundami o {0} sekúnd o {0} sekundy pred {0} rokmi pred {0} rokmi o {0} rokov o {0} roky teraz včera zajtra pred hodinou o hodinu pred minútou o minútu pred mesiacom o mesiac pred sekundou o sekundu pred rokom o rok {0} dní {0} dni {0} hodín {0} hodiny {0} milisekúnd {0} milisekundy {0} minút {0} minúty {0} mesiacov {0} mesiace {0} sekúnd {0} sekundy {0} týždňov {0} týždne {0} rokov {0} roky 1 deň 1 hodina 1 milisekunda 1 minúta 1 mesiac 1 sekunda 1 týždeň 1 rok žiadny čas ================================================ FILE: src/Humanizer/Properties/Resources.sl.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 pred {0} dnevi pred {0} dnevoma pred {0} dnevi čez {0} dni čez {0} dni čez {0} dni pred {0} urami pred {0} urama pred {0} urami čez {0} ur čez {0} uri čez {0} ure pred {0} minutami pred {0} minutama pred {0} minutami čez {0} minut čez {0} minuti čez {0} minute pred {0} meseci pred {0} mesecema pred {0} meseci čez {0} mesecev čez {0} meseca čez {0} mesece pred {0} sekundami pred {0} sekundama pred {0} sekundami čez {0} sekund čez {0} sekundi čez {0} sekunde pred {0} leti pred {0} letoma pred {0} leti čez {0} let čez {0} leti čez {0} leta nikoli sedaj včeraj jutri pred eno uro čez eno uro pred eno minuto čez eno minuto pred enim mesecem čez en mesec pred eno sekundo čez eno sekundo pred enim letom čez eno leto {0} dni {0} dneva {0} dni {0} ur {0} uri {0} ure {0} milisekund {0} milisekundi {0} milisekunde {0} minut {0} minuti {0} minute {0} mesecev {0} meseca {0} mesece {0} sekund {0} sekundi {0} sekunde {0} tednov {0} tedna {0} tedne {0} let {0} leti {0} leta 1 dan 1 ura 1 milisekunda 1 minuta 1 mesec 1 sekunda 1 teden 1 leto nič časa ================================================ FILE: src/Humanizer/Properties/Resources.sr-Latn.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 pre {0} dana pre {0} dana za {0} dana za {0} dana pre {0} sati pre {0} sata za {0} sati za {0} sata pre {0} minuta pre {0} minuta za {0} minuta za {0} minuta pre {0} meseci pre {0} meseca za {0} meseci za {0} meseca pre {0} sekundi pre {0} sekunde za {0} sekundi za {0} sekunde pre {0} godina pre {0} godine za {0} godina za {0} godine sada juče sutra pre sat vremena za sat vremena pre minut za minut pre mesec dana za mesec dana pre sekund za sekund pre godinu dana za godinu dana {0} dana {0} dana {0} sati {0} sata {0} milisekundi {0} milisekunde {0} minuta {0} minuta {0} meseci {0} meseca {0} sekundi {0} sekunde {0} nedelja {0} nedelje {0} godina {0} godine 1 dan 1 sat 1 milisekunda 1 minut 1 mesec 1 sekunda 1 nedelja 1 godina bez proteklog vremena ================================================ FILE: src/Humanizer/Properties/Resources.sr.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 пре {0} дана пре {0} дана за {0} дана за {0} дана пре {0} сати пре {0} сата за {0} сати за {0} сата пре {0} минута пре {0} минута за {0} минута за {0} минута пре {0} месеци пре {0} месеца за {0} месеци за {0} месеца пре {0} секунди пре {0} секунде за {0} секунди за {0} секунде пре {0} година пре {0} године за {0} година за {0} године сада јуче сутра пре сат времена за сат времена пре минут за минут пре месец дана за месец дана пре секунд за секунд пре годину дана за годину дана {0} дана {0} дана {0} сати {0} сата {0} милисекунди {0} милисекунде {0} минута {0} минута {0} месеци {0} месеца {0} секунди {0} секунде {0} недеља {0} недеље {0} година {0} године 1 дан 1 сат 1 милисекунда 1 минут 1 месец 1 секунда 1 недеља 1 година без протеклог времена ================================================ FILE: src/Humanizer/Properties/Resources.sv.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 för {0} dagar sedan om {0} dagar för {0} timmar sedan om {0} timmar för {0} minuter sedan om {0} minuter för {0} månader sedan om {0} månader för {0} sekunder sedan om {0} sekunder för {0} år sedan om {0} år nu igår i morgon en timme sedan om en timme en minut sedan om en minut en månad sedan om en månad en sekund sedan om en sekund ett år sedan om ett år {0} dagar {0} timmar {0} millisekunder {0} minuter {0} månader {0} sekunder {0} veckor {0} år 1 dag 1 timma 1 millisekund 1 minut en månad 1 sekund 1 vecka ett år ingen tid ================================================ FILE: src/Humanizer/Properties/Resources.th.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 {0} วันที่แล้ว {0} วันที่แล้ว {0} วันที่แล้ว {0} วันที่แล้ว {0} วันจากนี้ {0} วันจากนี้ {0} วันจากนี้ {0} วันจากนี้ {0} ชั่วโมงที่แล้ว {0} ชั่วโมงที่แล้ว {0} ชั่วโมงที่แล้ว {0} ชั่วโมงที่แล้ว {0} ชั่วโมงที่แล้ว {0} ชั่วโมงจากนี้ {0} ชั่วโมงจากนี้ {0} ชั่วโมงจากนี้ {0} ชั่วโมงจากนี้ {0} ชั่วโมงจากนี้ {0} นาทีที่แล้ว {0} นาทีที่แล้ว {0} นาทีที่แล้ว {0} นาทีที่แล้ว {0} นาทีที่แล้ว {0} นาทีจากนี้ {0} นาทีจากนี้ {0} นาทีจากนี้ {0} นาทีจากนี้ {0} นาทีจากนี้ {0} เดือนที่แล้ว {0} เดือนที่แล้ว {0} เดือนที่แล้ว {0} เดือนที่แล้ว {0} เดือนที่แล้ว {0} เดือนจากนี้ {0} เดือนจากนี้ {0} เดือนจากนี้ {0} เดือนจากนี้ {0} เดือนจากนี้ {0} วินาทีที่แล้ว {0} วินาทีที่แล้ว {0} วินาทีที่แล้ว {0} วินาทีที่แล้ว {0} วินาทีที่แล้ว {0} วินาทีจากนี้ {0} วินาทีจากนี้ {0} วินาทีจากนี้ {0} วินาทีจากนี้ {0} วินาทีจากนี้ {0} ปีที่แล้ว {0} ปีที่แล้ว {0} ปีที่แล้ว {0} ปีที่แล้ว {0} ปีที่แล้ว {0} ปีจากนี้ {0} ปีจากนี้ {0} ปีจากนี้ {0} ปีจากนี้ {0} ปีจากนี้ ไม่เคย ขณะนี้ เมื่อวานนี้ พรุ่งนี้ หนึ่งชั่วโมงที่แล้ว หนึ่งชั่วโมงจากนี้ หนึ่งนาทีที่แล้ว หนึ่งนาทีจากนี้ หนึ่งเดือนที่แล้ว หนึ่งเดือนจากนี้ หนึ่งวินาทีที่แล้ว หนึ่งวินาทีจากนี้ หนึ่งปีที่แล้ว หนึ่งปีจากนี้ {0} วัน {0} วัน {0} วัน {0} วัน {0} ชั่วโมง {0} ชั่วโมง {0} ชั่วโมง {0} ชั่วโมง {0} ชั่วโมง {0} มิลลิวินาที {0} มิลลิวินาที {0} มิลลิวินาที {0} มิลลิวินาที {0} มิลลิวินาที {0} นาที {0} นาที {0} นาที {0} นาที {0} นาที {0} เดือน {0} วินาที {0} วินาที {0} วินาที {0} วินาที {0} วินาที {0} สัปดาห์ {0} สัปดาห์ {0} สัปดาห์ {0} สัปดาห์ {0} สัปดาห์ {0} ปี 1 วัน 1 ชั่วโมง 1 มิลลิวินาที 1 นาที 1 เดือน 1 วินาที 1 สัปดาห์ 1 ปี ไม่มีเวลา ================================================ FILE: src/Humanizer/Properties/Resources.tr.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 {0} gün önce {0} gün sonra {0} saat önce {0} saat sonra {0} dakika önce {0} dakika sonra {0} ay önce {0} ay sonra {0} saniye önce {0} saniye sonra {0} yıl önce {0} yıl sonra şimdi dün yarın bir saat önce bir saat sonra bir dakika önce bir dakika sonra bir ay önce bir ay sonra bir saniye önce bir saniye sonra bir yıl önce bir yıl sonra {0} gün {0} saat {0} milisaniye {0} dakika {0} ay {0} saniye {0} hafta {0} yıl 1 gün 1 saat 1 milisaniye 1 dakika 1 ay 1 saniye 1 hafta 1 yıl zaman farkı yok ================================================ FILE: src/Humanizer/Properties/Resources.uk.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 {0} днів тому {0} дні тому {0} день тому через {0} днів через {0} дні через {0} день {0} годин тому {0} години тому {0} годину тому через {0} годин через {0} години через {0} годину {0} хвилин тому {0} хвилини тому {0} хвилину тому через {0} хвилин через {0} хвилини через {0} хвилину {0} місяців тому {0} місяці тому {0} місяць тому через {0} місяців через {0} місяці через {0} місяць {0} секунд тому {0} секунди тому {0} секунду тому через {0} секунд через {0} секунди через {0} секунду {0} років тому {0} роки тому {0} рік тому через {0} років через {0} роки через {0} рік зараз вчора завтра годину тому через годину хвилину тому через хвилину місяць тому через місяць секунду тому через секунду рік тому через рік {0} днів {0} дні {0} день {0} годин {0} години {0} година {0} мілісекунд {0} мілісекунди {0} мілісекунда {0} хвилин {0} хвилини {0} хвилина {0} місяців {0} місяці {0} місяць {0} секунд {0} секунди {0} секунда {0} тижнів {0} тижні {0} тиждень {0} років {0} роки {0} рік 1 день один день 1 година одна година 1 мілісекунда одна мілісекунда 1 хвилина одна хвилина 1 місяць один місяць 1 секунда одна секунда 1 тиждень один тиждень 1 рік один рік без часу ================================================ FILE: src/Humanizer/Properties/Resources.uz-Cyrl-UZ.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 {0} кун аввал {0} кундан сўнг {0} соат аввал {0} соатдан сўнг {0} минут аввал {0} минутдан сўнг {0} ой аввал {0} ойдан сўнг {0} секунд аввал {0} секунддан сўнг {0} йил аввал {0} йилдан сўнг ҳозир кеча эртага бир соат аввал бир соатдан сўнг бир дақиқа аввал бир дақиқадан сўнг бир ой аввал бир ойдан сўнг бир сония аввал бир сониядан сўнг бир йил аввал бир йилдан сўнг {0} кун {0} соат {0} миллисекунд {0} минут {0} ой {0} секунд {0} ҳафта {0} йил 1 кун 1 соат 1 миллисекунд 1 минут 1 ой 1 секунд 1 ҳафта 1 йил вақт йўқ ================================================ FILE: src/Humanizer/Properties/Resources.uz-Latn-UZ.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 {0} kun avval {0} kundan so`ng {0} soat avval {0} soatdan so`ng {0} minut avval {0} minutdan so`ng {0} oy avval {0} oydan so`ng {0} sekund avval {0} sekunddan so`ng {0} yil avval {0} yildan so`ng hozir kecha ertaga bir soat avval bir soatdan so`ng bir daqiqa avval bir daqiqadan so`ng bir oy avval bir oydan so`ng bir soniya avval bir soniyadan so`ng bir yil avval bir yildan so`ng {0} kun {0} soat {0} millisekund {0} minut {0} oy {0} sekund {0} hafta {0} yil 1 kun 1 soat 1 millisekund 1 minut 1 oy 1 sekund 1 hafta 1 yil vaqt yo`q ================================================ FILE: src/Humanizer/Properties/Resources.vi.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 cách đây {0} ngày {0} ngày nữa cách đây {0} tiếng {0} tiếng nữa cách đây {0} phút {0} phút nữa cách đây {0} tháng {0} tháng nữa cách đây {0} giây {0} giây nữa cách đây {0} năm {0} năm nữa bây giờ hôm qua ngày mai cách đây một tiếng một tiếng nữa cách đây một phút một phút nữa cách đây một tháng một tháng nữa cách đây một giây một giây nữa cách đây một năm một năm nữa {0} ngày {0} giờ {0} phần ngàn giây {0} phút {0} tháng {0} giây {0} tuần {0} năm 1 ngày 1 giờ 1 phần ngàn giây 1 phút 1 tháng 1 giây 1 tuần 1 năm không giờ ================================================ FILE: src/Humanizer/Properties/Resources.zh-CN.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 {0} 天前 {0} 天后 {0} 小时前 {0} 小时后 {0} 分钟前 {0} 分钟后 {0} 个月前 {0} 个月后 {0} 秒钟前 {0} 秒钟后 {0} 年前 {0} 年后 现在 昨天 明天 1 小时前 1 小时后 1 分钟前 1 分钟后 1 个月前 1 个月后 1 秒钟前 1 秒钟后 去年 明年 {0} 天 {0} 小时 {0} 毫秒 {0} 分 {0} 个月 {0} 秒 {0} 周 {0} 年 1 天 1 小时 1 毫秒 1 分 1 个月 1 秒 1 周 1 年 没有时间 ================================================ FILE: src/Humanizer/Properties/Resources.zh-Hans.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 {0} 天前 {0} 天后 {0} 小时前 {0} 小时后 {0} 分钟前 {0} 分钟后 {0} 个月前 {0} 个月后 {0} 秒钟前 {0} 秒钟后 {0} 年前 {0} 年后 现在 昨天 明天 1 小时前 1 小时后 1 分钟前 1 分钟后 1 个月前 1 个月后 1 秒钟前 1 秒钟后 去年 明年 {0} 天 {0} 小时 {0} 毫秒 {0} 分 {0} 个月 {0} 秒 {0} 周 {0} 年 1 天 1 小时 1 毫秒 1 分 1 个月 1 秒 1 周 1 年 没有时间 ================================================ FILE: src/Humanizer/Properties/Resources.zh-Hant.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 {0} 天前 {0} 天後 {0} 小時前 {0} 小時後 {0} 分鐘前 {0} 分鐘後 {0} 個月前 {0} 個月後 {0} 秒鐘前 {0} 秒鐘後 {0} 年前 {0} 年後 現在 昨天 明天 1 小時前 1 小時後 1 分鐘前 1 分鐘後 1 個月前 1 個月後 1 秒鐘前 1 秒鐘後 去年 明年 {0} 天 {0} 小時 {0} 毫秒 {0} 分 {0} 個月 {0} 秒 {0} 周 {0} 年 1 天 1 小時 1 毫秒 1 分 1 個月 1 秒 1 周 1 年 沒有時間 ================================================ FILE: src/Humanizer/RomanNumeralExtensions.cs ================================================ // Done by Jesse Slicer https://github.com/jslicer using System.Diagnostics; namespace Humanizer; /// /// Contains extension methods for changing a number to Roman representation (ToRoman) and from Roman representation back to the number (FromRoman) /// public static partial class RomanNumeralExtensions { static readonly KeyValuePair[] RomanNumeralsSequence = [ new("M", 1000), new("CM", 900), new("D", 500 ), new("CD", 400), new("C", 100 ), new("XC", 90 ), new("L", 50 ), new("XL", 40 ), new("X", 10 ), new("IX", 9 ), new("V", 5 ), new("IV", 4 ), new("I", 1 ), ]; static int GetRomanNumeralCharValue(char c) { Debug.Assert(char.ToUpperInvariant(c) is 'M' or 'D' or 'C' or 'L' or 'X' or 'V' or 'I', "Invalid Roman numeral character"); return (c & ~0x20) switch { 'M' => 1000, 'D' => 500, 'C' => 100, 'L' => 50, 'X' => 10, 'V' => 5, _ => 1, }; } private const string ValidRomanNumeralPattern = @"^(?i:(?=[MDCLXVI])((M{0,3})((C[DM])|(D?C{0,3}))?((X[LC])|(L?XX{0,2})|L)?((I[VX])|(V?(II{0,2}))|V)?))$"; #if NET7_0_OR_GREATER [GeneratedRegex(ValidRomanNumeralPattern, RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)] private static partial Regex ValidRomanNumeralGenerated(); private static Regex ValidRomanNumeral() => ValidRomanNumeralGenerated(); #else private static readonly Regex ValidRomanNumeralRegex = new( ValidRomanNumeralPattern, RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); private static Regex ValidRomanNumeral() => ValidRomanNumeralRegex; #endif /// /// Converts a Roman numeral string to its integer representation. /// /// The Roman numeral string to convert (e.g., "XIV", "MCMXC"). Must not be null. /// /// The integer value represented by the Roman numeral. /// /// Thrown when is null. /// /// Thrown when is empty or contains an invalid Roman numeral format. /// /// /// Valid Roman numerals use the characters M, D, C, L, X, V, and I (case-insensitive). /// Supports subtractive notation (e.g., IV = 4, IX = 9, XL = 40, XC = 90, CD = 400, CM = 900). /// Valid range is 1 to 3999. /// /// /// /// "XIV".FromRoman() => 14 /// "MCMXC".FromRoman() => 1990 /// "IV".FromRoman() => 4 /// "MMXXIII".FromRoman() => 2023 /// /// public static int FromRoman(this string input) { ArgumentNullException.ThrowIfNull(input); return FromRoman(input.AsSpan()); } /// /// Converts a Roman numeral character span to its integer representation. /// /// The Roman numeral character span to convert. Must not be empty. /// /// The integer value represented by the Roman numeral. /// /// /// Thrown when is empty (after trimming) or contains an invalid Roman numeral format. /// /// /// This is a memory-efficient overload that works with character spans to avoid string allocations. /// Valid Roman numerals use the characters M, D, C, L, X, V, and I (case-insensitive). /// Supports subtractive notation (e.g., IV = 4, IX = 9). /// /// /// /// "XIV".AsSpan().FromRoman() => 14 /// "MCMXC".AsSpan().FromRoman() => 1990 /// /// public static int FromRoman(CharSpan input) { input = input.Trim(); var length = input.Length; if (length == 0 || IsInvalidRomanNumeral(input)) { throw new ArgumentException("Empty or invalid Roman numeral string.", nameof(input)); } var total = 0; var i = length; while (i > 0) { var digit = GetRomanNumeralCharValue(input[--i]); if (i > 0) { var previousDigit = GetRomanNumeralCharValue(input[i - 1]); if (previousDigit < digit) { digit -= previousDigit; i--; } } total += digit; } return total; } /// /// Converts an integer to its Roman numeral representation. /// /// The integer value to convert. Must be between 1 and 3999 inclusive. /// /// A string containing the Roman numeral representation of the input value. /// /// /// Thrown when is less than 1 or greater than 3999. /// Roman numerals are traditionally limited to this range. /// /// /// Uses standard Roman numeral notation including subtractive notation for 4, 9, 40, 90, 400, and 900. /// The implementation is optimized for performance and avoids string allocations where possible. /// /// /// /// 14.ToRoman() => "XIV" /// 1990.ToRoman() => "MCMXC" /// 4.ToRoman() => "IV" /// 2023.ToRoman() => "MMXXIII" /// 3999.ToRoman() => "MMMCMXCIX" /// /// public static string ToRoman(this int input) { const int minValue = 1; const int maxValue = 3999; const int maxRomanNumeralLength = 15; if (input is < minValue or > maxValue) { throw new ArgumentOutOfRangeException(nameof(input)); } Span builder = stackalloc char[maxRomanNumeralLength]; var pos = 0; foreach (var pair in RomanNumeralsSequence) { while (input >= pair.Value) { pair.Key.AsSpan().CopyTo(builder[pos..]); pos += pair.Key.Length; input -= pair.Value; } } return builder[..pos].ToString(); } static bool IsInvalidRomanNumeral(CharSpan input) => !ValidRomanNumeral().IsMatch(input); } ================================================ FILE: src/Humanizer/StringDehumanizeExtensions.cs ================================================ namespace Humanizer; /// /// Contains extension methods for dehumanizing strings. /// public static class StringDehumanizeExtensions { /// /// Converts a humanized string back to PascalCase format by removing spaces and capitalizing each word. /// /// The string to be dehumanized. Must not be null. /// /// A PascalCase string with all spaces removed and each word capitalized. /// If the input is already in PascalCase (contains no spaces), it is returned unchanged. /// /// /// This method reverses the humanization process by: /// 1. Splitting the input on spaces /// 2. Humanizing each word (to handle any edge cases) /// 3. Pascalizing each word (capitalizing first letter) /// 4. Removing all spaces /// This is the inverse operation of . /// /// /// /// "some string".Dehumanize() => "SomeString" /// "Some String".Dehumanize() => "SomeString" /// "Some string".Dehumanize() => "SomeString" /// "SomeStringAndAnotherString".Dehumanize() => "SomeStringAndAnotherString" // Already dehumanized, returned unchanged /// /// public static string Dehumanize(this string input) { var words = input.Split(' ', StringSplitOptions.RemoveEmptyEntries); if (words.Length == 0) { return input; } if (words.Length == 1) { return words[0].Humanize().Pascalize(); } return string.Concat(words.Select(word => word.Humanize().Pascalize())); } } ================================================ FILE: src/Humanizer/StringHumanizeExtensions.cs ================================================ using System.Runtime.InteropServices; namespace Humanizer; /// /// Contains extension methods for humanizing string values. /// public static partial class StringHumanizeExtensions { const string PascalCaseWordPartsPattern = @"(\p{Lu}?\p{Ll}+|[0-9]+\p{Ll}*|\p{Lu}+(?=\p{Lu}|[0-9]|\b)|\p{Lo}+)[,;]?"; const string FreestandingSpacingCharPattern = @"\s[-_]|[-_]\s"; #if NET7_0_OR_GREATER [GeneratedRegex(PascalCaseWordPartsPattern, RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture)] private static partial Regex PascalCaseWordPartsRegexGenerated(); private static Regex PascalCaseWordPartsRegex() => PascalCaseWordPartsRegexGenerated(); [GeneratedRegex(FreestandingSpacingCharPattern)] private static partial Regex FreestandingSpacingCharRegexGenerated(); private static Regex FreestandingSpacingCharRegex() => FreestandingSpacingCharRegexGenerated(); #else private static readonly Regex PascalCaseWordPartsRegexField = new( PascalCaseWordPartsPattern, RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture | RegexOptions.Compiled); private static Regex PascalCaseWordPartsRegex() => PascalCaseWordPartsRegexField; private static readonly Regex FreestandingSpacingCharRegexField = new(FreestandingSpacingCharPattern, RegexOptions.Compiled); private static Regex FreestandingSpacingCharRegex() => FreestandingSpacingCharRegexField; #endif static string FromUnderscoreDashSeparatedWords(string input) { #if NET7_0_OR_GREATER return string.Create(input.Length, input, (span, state) => { state.AsSpan().CopyTo(span); span.Replace('_', ' '); span.Replace('-', ' '); }); #else return input.Replace('_', ' ').Replace('-', ' '); #endif } static string FromPascalCase(string input) { var result = string.Join(" ", PascalCaseWordPartsRegex() .Matches(input) // ReSharper disable once RedundantEnumerableCastCall .Cast() .Select(match => { var value = match.Value; return value.All(char.IsUpper) && (value.Length > 1 || (match.Index > 0 && input[match.Index - 1] == ' ') || value == "I") ? value : value.ToLower(); })); if (result.All(c => c == ' ' || char.IsUpper(c)) && result.Contains(' ')) { result = result.ToLower(); } return result.Length > 0 ? Concat(char.ToUpper(result[0]), result.AsSpan(1, result.Length - 1)) : result; } /// /// Transforms a string into a human-readable format by intelligently handling PascalCase, camelCase, /// underscored_strings, and dash-separated-strings, converting them into space-separated text with /// appropriate capitalization. /// /// The string to be humanized. Must not be null. /// /// A humanized version of the input string with spaces inserted between words and appropriate /// capitalization. Preserves all-uppercase acronyms unchanged. /// /// /// The method applies several rules in order: /// - If the entire input is uppercase (an acronym), it returns unchanged /// - Handles freestanding underscores/dashes (e.g., "some _ string") /// - Splits on underscores and dashes /// - Breaks up PascalCase and camelCase text /// The first letter of the result is always capitalized. /// /// /// /// "PascalCaseInputString".Humanize() => "Pascal case input string" /// "Underscored_input_String_is_turned_INTO_sentence".Humanize() => "Underscored input String is turned INTO sentence" /// "dash-separated-string".Humanize() => "Dash separated string" /// "HTML".Humanize() => "HTML" /// "camelCaseText".Humanize() => "Camel case text" /// /// public static string Humanize(this string input) { // if input is all capitals (e.g. an acronym) then return it without change if (input.All(char.IsUpper)) { return input; } // if input contains a dash or underscore which precedes or follows a space (or both, e.g. freestanding) // remove the dash/underscore and run it through FromPascalCase if (FreestandingSpacingCharRegex().IsMatch(input)) { return FromPascalCase(FromUnderscoreDashSeparatedWords(input)); } if (input.IndexOfAny(['_', '-']) >= 0) { return FromUnderscoreDashSeparatedWords(input); } return FromPascalCase(input); } /// /// Transforms a string into a human-readable format and applies the specified letter casing. /// /// The string to be humanized. Must not be null. /// The desired letter casing to apply to the humanized result. /// /// A humanized version of the input string with the specified casing applied. /// /// /// This is a convenience method that combines with . /// /// /// /// "PascalCaseInputString".Humanize(LetterCasing.AllCaps) => "PASCAL CASE INPUT STRING" /// "PascalCaseInputString".Humanize(LetterCasing.LowerCase) => "pascal case input string" /// "PascalCaseInputString".Humanize(LetterCasing.Title) => "Pascal Case Input String" /// /// public static string Humanize(this string input, LetterCasing casing) => input .Humanize() .ApplyCase(casing); #if NET internal static string Concat(CharSpan left, CharSpan right) => string.Concat(left, right); internal static string Concat(char left, CharSpan right) => string.Concat(MemoryMarshal.CreateReadOnlySpan(ref left, 1), right); internal static string Concat(CharSpan left, char right) => string.Concat(left, MemoryMarshal.CreateReadOnlySpan(ref right, 1)); #else internal static unsafe string Concat(CharSpan left, CharSpan right) { var result = new string('\0', left.Length + right.Length); fixed (char* pResult = result) { left.CopyTo(new(pResult, left.Length)); right.CopyTo(new(pResult + left.Length, right.Length)); } return result; } internal static unsafe string Concat(char left, CharSpan right) => Concat(new CharSpan(&left, 1), right); internal static unsafe string Concat(CharSpan left, char right) => Concat(left, new CharSpan(&right, 1)); #endif } ================================================ FILE: src/Humanizer/TimeOnlyToClockNotationExtensions.cs ================================================ #if NET6_0_OR_GREATER namespace Humanizer; /// /// Humanizes TimeOnly into human readable sentence /// public static class TimeOnlyToClockNotationExtensions { /// /// Converts a value to its clock notation string representation /// (e.g., "three o'clock", "half past four", "quarter to six"). /// /// The time to be converted to clock notation. /// /// Specifies whether and how to round the minutes. Default is . /// - : Use exact minutes /// - : Round to nearest 5 minutes /// /// /// A culture-specific string representation of the time in clock notation. /// For English: "three o'clock", "ten past four", "quarter to six", etc. /// /// /// The output format varies by culture. Some cultures express time differently than others. /// This method is only available on .NET 6.0 and later. /// /// /// /// // English (en-US) examples: /// new TimeOnly(15, 0).ToClockNotation() => "three o'clock" /// new TimeOnly(15, 15).ToClockNotation() => "quarter past three" /// new TimeOnly(15, 30).ToClockNotation() => "half past three" /// new TimeOnly(15, 45).ToClockNotation() => "quarter to four" /// new TimeOnly(15, 7).ToClockNotation(ClockNotationRounding.NearestFiveMinutes) => "five past three" /// /// public static string ToClockNotation(this TimeOnly input, ClockNotationRounding roundToNearestFive = ClockNotationRounding.None) => Configurator.TimeOnlyToClockNotationConverter.Convert(input, roundToNearestFive); } #endif ================================================ FILE: src/Humanizer/TimeSpanHumanizeExtensions.cs ================================================ namespace Humanizer; /// /// Humanizes TimeSpan into human readable form /// public static class TimeSpanHumanizeExtensions { const int DaysInAWeek = 7; const double DaysInAYear = 365.2425; // see https://en.wikipedia.org/wiki/Gregorian_calendar const double DaysInAMonth = DaysInAYear / 12; static readonly TimeUnit[] TimeUnits = [.. Enumerable.Reverse(Enum.GetValues())]; /// /// Turns a TimeSpan into a human readable form. E.g. 1 day. /// /// The maximum number of time units to return. Defaulted is 1 which means the largest unit is returned /// Culture to use. If null, current thread's UI culture is used. /// The maximum unit of time to output. The default value is . The time units and will give approximations for time spans bigger 30 days by calculating with 365.2425 days a year and 30.4369 days a month. /// The minimum unit of time to output. /// The separator to use when combining humanized time parts. If null, the default collection formatter for the current culture is used. /// Uses words instead of numbers if true. E.g. one day. public static string Humanize(this TimeSpan timeSpan, int precision = 1, CultureInfo? culture = null, TimeUnit maxUnit = TimeUnit.Week, TimeUnit minUnit = TimeUnit.Millisecond, string? collectionSeparator = ", ", bool toWords = false) => Humanize(timeSpan, precision, false, culture, maxUnit, minUnit, collectionSeparator, toWords); /// /// Turns a TimeSpan into a human readable form. E.g. 1 day. /// /// The maximum number of time units to return. /// Controls whether empty time units should be counted towards maximum number of time units. Leading empty time units never count. /// Culture to use. If null, current thread's UI culture is used. /// The maximum unit of time to output. The default value is . The time units and will give approximations for time spans bigger than 30 days by calculating with 365.2425 days a year and 30.4369 days a month. /// The minimum unit of time to output. /// The separator to use when combining humanized time parts. If null, the default collection formatter for the current culture is used. /// Uses words instead of numbers if true. E.g. one day. public static string Humanize(this TimeSpan timeSpan, int precision, bool countEmptyUnits, CultureInfo? culture = null, TimeUnit maxUnit = TimeUnit.Week, TimeUnit minUnit = TimeUnit.Millisecond, string? collectionSeparator = ", ", bool toWords = false) { var timeParts = CreateTheTimePartsWithUpperAndLowerLimits(timeSpan, culture, maxUnit, minUnit, toWords); timeParts = SetPrecisionOfTimeSpan(timeParts, precision, countEmptyUnits); return ConcatenateTimeSpanParts(timeParts, culture, collectionSeparator); } /// /// Turns a TimeSpan into an age expression, e.g. "40 years old" /// /// Elapsed time /// Culture to use. If null, current thread's UI culture is used. /// The maximum unit of time to output. The default value is . /// Uses words instead of numbers if true. E.g. "forty years old". /// Age expression in the given culture/language public static string ToAge(this TimeSpan timeSpan, CultureInfo? culture = null, TimeUnit maxUnit = TimeUnit.Year, bool toWords = false) { var timeSpanExpression = timeSpan.Humanize(culture: culture, maxUnit: maxUnit, toWords: toWords); var cultureFormatter = Configurator.GetFormatter(culture); var ageFormat = cultureFormatter.TimeSpanHumanize_Age(); // Fast path: avoid string.Format for common "{0} old" pattern if (ageFormat == "{0} old") { return string.Concat(timeSpanExpression, " old"); } return string.Format(ageFormat, timeSpanExpression); } static List CreateTheTimePartsWithUpperAndLowerLimits(TimeSpan timespan, CultureInfo? culture, TimeUnit maxUnit, TimeUnit minUnit, bool toWords = false) { var cultureFormatter = Configurator.GetFormatter(culture); var firstValueFound = false; var timeParts = new List(); foreach (var timeUnit in TimeUnits) { var timePart = GetTimeUnitPart(timeUnit, timespan, maxUnit, minUnit, cultureFormatter, toWords); if (timePart != null || firstValueFound) { firstValueFound = true; timeParts.Add(timePart); } } if (IsContainingOnlyNullValue(timeParts)) { var noTimeValueCultureFormatted = toWords ? cultureFormatter.TimeSpanHumanize_Zero() : cultureFormatter.TimeSpanHumanize(minUnit, 0); timeParts = CreateTimePartsWithNoTimeValue(noTimeValueCultureFormatted); } return timeParts; } static string? GetTimeUnitPart(TimeUnit timeUnitToGet, TimeSpan timespan, TimeUnit maximumTimeUnit, TimeUnit minimumTimeUnit, IFormatter cultureFormatter, bool toWords = false) { if (timeUnitToGet <= maximumTimeUnit && timeUnitToGet >= minimumTimeUnit) { var numberOfTimeUnits = GetTimeUnitNumericalValue(timeUnitToGet, timespan, maximumTimeUnit); return BuildFormatTimePart(cultureFormatter, timeUnitToGet, numberOfTimeUnits, toWords); } return null; } static int GetTimeUnitNumericalValue(TimeUnit timeUnitToGet, TimeSpan timespan, TimeUnit maximumTimeUnit) { var isTimeUnitToGetTheMaximumTimeUnit = timeUnitToGet == maximumTimeUnit; return timeUnitToGet switch { TimeUnit.Millisecond => GetNormalCaseTimeAsInteger(timespan.Milliseconds, timespan.TotalMilliseconds, isTimeUnitToGetTheMaximumTimeUnit), TimeUnit.Second => GetNormalCaseTimeAsInteger(timespan.Seconds, timespan.TotalSeconds, isTimeUnitToGetTheMaximumTimeUnit), TimeUnit.Minute => GetNormalCaseTimeAsInteger(timespan.Minutes, timespan.TotalMinutes, isTimeUnitToGetTheMaximumTimeUnit), TimeUnit.Hour => GetNormalCaseTimeAsInteger(timespan.Hours, timespan.TotalHours, isTimeUnitToGetTheMaximumTimeUnit), TimeUnit.Day => GetSpecialCaseDaysAsInteger(timespan, maximumTimeUnit), TimeUnit.Week => GetSpecialCaseWeeksAsInteger(timespan, isTimeUnitToGetTheMaximumTimeUnit), TimeUnit.Month => GetSpecialCaseMonthAsInteger(timespan, isTimeUnitToGetTheMaximumTimeUnit), TimeUnit.Year => GetSpecialCaseYearAsInteger(timespan), _ => 0 }; } static int GetSpecialCaseMonthAsInteger(TimeSpan timespan, bool isTimeUnitToGetTheMaximumTimeUnit) { if (isTimeUnitToGetTheMaximumTimeUnit) { return (int)(timespan.Days / DaysInAMonth); } var remainingDays = timespan.Days % DaysInAYear; return (int)(remainingDays / DaysInAMonth); } static int GetSpecialCaseYearAsInteger(TimeSpan timespan) => (int)(timespan.Days / DaysInAYear); static int GetSpecialCaseWeeksAsInteger(TimeSpan timespan, bool isTimeUnitToGetTheMaximumTimeUnit) { if (isTimeUnitToGetTheMaximumTimeUnit || timespan.Days < DaysInAMonth) { return timespan.Days / DaysInAWeek; } return 0; } static int GetSpecialCaseDaysAsInteger(TimeSpan timespan, TimeUnit maximumTimeUnit) { if (maximumTimeUnit == TimeUnit.Day) { return timespan.Days; } if (timespan.Days < DaysInAMonth || maximumTimeUnit == TimeUnit.Week) { var remainingDays = timespan.Days % DaysInAWeek; return remainingDays; } return (int)(timespan.Days % DaysInAMonth); } static int GetNormalCaseTimeAsInteger(int timeNumberOfUnits, double totalTimeNumberOfUnits, bool isTimeUnitToGetTheMaximumTimeUnit) { if (isTimeUnitToGetTheMaximumTimeUnit) { try { return (int)totalTimeNumberOfUnits; } catch { //To be implemented so that TimeSpanHumanize method accepts double type as unit return 0; } } return timeNumberOfUnits; } static string? BuildFormatTimePart(IFormatter cultureFormatter, TimeUnit timeUnitType, int amountOfTimeUnits, bool toWords = false) => // Always use positive units to account for negative timespans amountOfTimeUnits != 0 ? cultureFormatter.TimeSpanHumanize(timeUnitType, Math.Abs(amountOfTimeUnits), toWords) : null; static List CreateTimePartsWithNoTimeValue(string noTimeValue) => [noTimeValue]; static bool IsContainingOnlyNullValue(IEnumerable timeParts) => !timeParts.Any(x => x != null); static List SetPrecisionOfTimeSpan(IEnumerable timeParts, int precision, bool countEmptyUnits) { if (!countEmptyUnits) { timeParts = timeParts.Where(x => x != null); } timeParts = timeParts.Take(precision); if (countEmptyUnits) { timeParts = timeParts.Where(x => x != null); } return [.. timeParts]; } static string ConcatenateTimeSpanParts(IEnumerable timeSpanParts, CultureInfo? culture, string? collectionSeparator) { if (collectionSeparator == null) { return Configurator .CollectionFormatters.ResolveForCulture(culture) .Humanize(timeSpanParts); } return string.Join(collectionSeparator, timeSpanParts); } } ================================================ FILE: src/Humanizer/TimeUnitToSymbolExtensions.cs ================================================ namespace Humanizer; /// /// Transform a time unit into a symbol; e.g. => "a" /// public static class TimeUnitToSymbolExtensions { /// /// TimeUnit.Day.ToSymbol() -> "d" /// /// Unit of time to be turned to a symbol /// Culture to use. If null, current thread's UI culture is used. public static string ToSymbol(this TimeUnit unit, CultureInfo? culture = null) => Configurator.GetFormatter(culture).TimeUnitHumanize(unit); } ================================================ FILE: src/Humanizer/ToQuantityExtensions.cs ================================================ namespace Humanizer; /// /// Enumerates the ways of displaying a quantity value when converting /// a word to a quantity string. /// public enum ShowQuantityAs { /// /// Indicates that no quantity will be included in the formatted string. /// None = 0, /// /// Indicates that the quantity will be included in the output, formatted /// as its numeric value (e.g. "1"). /// Numeric, /// /// Incidates that the quantity will be included in the output, formatted as /// words (e.g. 123 => "one hundred and twenty three"). /// Words } /// /// Provides extensions for formatting a word as a quantity. /// public static class ToQuantityExtensions { /// /// Prefixes the provided word with the number and accordingly pluralizes or singularizes the word /// /// The word to be prefixed /// The quantity of the word /// How to show the quantity. Numeric by default /// /// "request".ToQuantity(0) => "0 requests" /// "request".ToQuantity(1) => "1 request" /// "request".ToQuantity(2) => "2 requests" /// "men".ToQuantity(2) => "2 men" /// "process".ToQuantity(1200, ShowQuantityAs.Words) => "one thousand two hundred processes" /// public static string ToQuantity(this string input, int quantity, ShowQuantityAs showQuantityAs = ShowQuantityAs.Numeric) => input.ToQuantity((long)quantity, showQuantityAs, format: null, formatProvider: null); /// /// Prefixes the provided word with the number and accordingly pluralizes or singularizes the word /// /// The word to be prefixed /// The quantity of the word /// A standard or custom numeric format string. /// An object that supplies culture-specific formatting information. /// /// "request".ToQuantity(0) => "0 requests" /// "request".ToQuantity(10000, format: "N0") => "10,000 requests" /// "request".ToQuantity(1, format: "N0") => "1 request" /// public static string ToQuantity(this string input, int quantity, string? format, IFormatProvider? formatProvider = null) => input.ToQuantity((long)quantity, showQuantityAs: ShowQuantityAs.Numeric, format: format, formatProvider: formatProvider); /// /// Prefixes the provided word with the number and accordingly pluralizes or singularizes the word /// /// The word to be prefixed /// The quantity of the word /// How to show the quantity. Numeric by default /// /// "request".ToQuantity(0) => "0 requests" /// "request".ToQuantity(1) => "1 request" /// "request".ToQuantity(2) => "2 requests" /// "men".ToQuantity(2) => "2 men" /// "process".ToQuantity(1200, ShowQuantityAs.Words) => "one thousand two hundred processes" /// public static string ToQuantity(this string input, long quantity, ShowQuantityAs showQuantityAs = ShowQuantityAs.Numeric) => input.ToQuantity(quantity, showQuantityAs, format: null, formatProvider: null); /// /// Prefixes the provided word with the number and accordingly pluralizes or singularizes the word /// /// The word to be prefixed /// The quantity of the word /// A standard or custom numeric format string. /// An object that supplies culture-specific formatting information. /// /// "request".ToQuantity(0) => "0 requests" /// "request".ToQuantity(10000, format: "N0") => "10,000 requests" /// "request".ToQuantity(1, format: "N0") => "1 request" /// public static string ToQuantity(this string input, long quantity, string? format, IFormatProvider? formatProvider = null) => input.ToQuantity(quantity, showQuantityAs: ShowQuantityAs.Numeric, format: format, formatProvider: formatProvider); static string ToQuantity(this string input, long quantity, ShowQuantityAs showQuantityAs = ShowQuantityAs.Numeric, string? format = null, IFormatProvider? formatProvider = null) { var transformedInput = quantity is 1 or -1 ? input.Singularize(inputIsKnownToBePlural: false) : input.Pluralize(inputIsKnownToBeSingular: false); if (showQuantityAs == ShowQuantityAs.None) { return transformedInput; } if (showQuantityAs == ShowQuantityAs.Numeric) { var quantityStr = quantity.ToString(format, formatProvider); return formatProvider != null ? string.Format(formatProvider, "{0} {1}", quantityStr, transformedInput) : ConcatWithSpace(quantityStr, transformedInput); } return ConcatWithSpace(quantity.ToWords(), transformedInput); } /// /// Prefixes the provided word with the number and accordingly pluralizes or singularizes the word /// /// The word to be prefixed /// The quantity of the word /// A standard or custom numeric format string. /// An object that supplies culture-specific formatting information. /// /// "request".ToQuantity(0.2) => "0.2 requests" /// "request".ToQuantity(10.6, format: "N0") => "10.6 requests" /// "request".ToQuantity(1.0, format: "N0") => "1 request" /// public static string ToQuantity(this string input, double quantity, string? format = null, IFormatProvider? formatProvider = null) { var isFinite = !(double.IsNaN(quantity) || double.IsInfinity(quantity)); var isSingular = isFinite && quantity == Math.Truncate(quantity) && Math.Abs(quantity) == 1d; var transformedInput = isSingular ? input.Singularize(inputIsKnownToBePlural: false) : input.Pluralize(inputIsKnownToBeSingular: false); var quantityStr = quantity.ToString(format, formatProvider); return formatProvider != null ? string.Format(formatProvider, "{0} {1}", quantityStr, transformedInput) : ConcatWithSpace(quantityStr, transformedInput); } /// /// Prefixes the provided word with the number and accordingly pluralizes or singularizes the word /// /// The word to be prefixed /// The quantity of the word /// /// "request".ToQuantity(0.2) => "0.2 requests" /// public static string ToQuantity(this string input, double quantity) => ToQuantity(input, quantity, null, null); static string ConcatWithSpace(string left, string right) { #if NET6_0_OR_GREATER return string.Create(left.Length + 1 + right.Length, (left, right), (span, state) => { state.left.CopyTo(span); span[state.left.Length] = ' '; state.right.CopyTo(span[(state.left.Length + 1)..]); }); #else return string.Concat(left, " ", right); #endif } } ================================================ FILE: src/Humanizer/Transformer/ICulturedStringTransformer.cs ================================================ namespace Humanizer; /// /// Can transform a string with the given culture /// public interface ICulturedStringTransformer : IStringTransformer { /// /// Transform the input /// /// String to be transformed string Transform(string input, CultureInfo culture); } ================================================ FILE: src/Humanizer/Transformer/IStringTransformer.cs ================================================ namespace Humanizer; /// /// Can transform a string /// public interface IStringTransformer { /// /// Transform the input /// /// String to be transformed string Transform(string input); } ================================================ FILE: src/Humanizer/Transformer/To.cs ================================================ namespace Humanizer; /// /// A portal to string transformation using IStringTransformer /// public static class To { /// /// Transforms a string using the provided transformers. Transformations are applied in the provided order. /// public static string Transform(this string input, params IStringTransformer[] transformers) => transformers.Aggregate(input, (current, stringTransformer) => stringTransformer.Transform(current)); /// /// Transforms a string using the provided transformers. Transformations are applied in the provided order. /// public static string Transform(this string input, CultureInfo culture, params ICulturedStringTransformer[] transformers) => transformers.Aggregate(input, (current, stringTransformer) => stringTransformer.Transform(current, culture)); /// /// Changes string to title case /// /// /// "INvalid caSEs arE corrected" -> "Invalid Cases Are Corrected" /// public static ICulturedStringTransformer TitleCase { get; } = new ToTitleCase(); /// /// Changes the string to lower case /// /// /// "Sentence casing" -> "sentence casing" /// public static ICulturedStringTransformer LowerCase { get; } = new ToLowerCase(); /// /// Changes the string to upper case /// /// /// "lower case statement" -> "LOWER CASE STATEMENT" /// public static ICulturedStringTransformer UpperCase { get; } = new ToUpperCase(); /// /// Changes the string to sentence case /// /// /// "lower case statement" -> "Lower case statement" /// public static ICulturedStringTransformer SentenceCase { get; } = new ToSentenceCase(); } ================================================ FILE: src/Humanizer/Transformer/ToLowerCase.cs ================================================ namespace Humanizer; class ToLowerCase : ICulturedStringTransformer { public string Transform(string input) => Transform(input, CultureInfo.CurrentCulture); public string Transform(string input, CultureInfo culture) { return culture.TextInfo.ToLower(input); } } ================================================ FILE: src/Humanizer/Transformer/ToSentenceCase.cs ================================================ namespace Humanizer; class ToSentenceCase : ICulturedStringTransformer { public string Transform(string input) => Transform(input, CultureInfo.CurrentCulture); public string Transform(string input, CultureInfo culture) { if (input.Length >= 1) { if (char.IsUpper(input[0])) { return input; } return StringHumanizeExtensions.Concat(culture.TextInfo.ToUpper(input[0]), input.AsSpan(1)); } return culture.TextInfo.ToUpper(input); } } ================================================ FILE: src/Humanizer/Transformer/ToTitleCase.cs ================================================ namespace Humanizer; partial class ToTitleCase : ICulturedStringTransformer { public string Transform(string input) => Transform(input, CultureInfo.CurrentCulture); private const string WordPattern = @"(\w|[^\u0000-\u007F])+'?\w*"; #if NET7_0_OR_GREATER [GeneratedRegex(WordPattern)] private static partial Regex WordRegexGenerated(); private static Regex WordRegex() => WordRegexGenerated(); #else private static readonly Regex WordRegexDefinition = new(WordPattern, RegexOptions.Compiled); private static Regex WordRegex() => WordRegexDefinition; #endif public string Transform(string input, CultureInfo culture) { var matches = WordRegex().Matches(input); var builder = new StringBuilder(input); var textInfo = culture.TextInfo; for (var i = 0; i < matches.Count; i++) { var word = matches[i]; var value = word.Value; if (AllCapitals(value) || (i > 0 && IsArticleOrConjunctionOrPreposition(value))) { continue; } builder[word.Index] = textInfo.ToUpper(value[0]); Overwrite(builder, word.Index + 1, textInfo.ToLower(value[1..])); } return builder.ToString(); } static void Overwrite(StringBuilder builder, int index, string replacement) { // Directly overwrite characters instead of Remove + Insert for (var i = 0; i < replacement.Length; i++) { builder[index + i] = replacement[i]; } } static bool AllCapitals(string input) { foreach (var ch in input) { if (!char.IsUpper(ch)) { return false; } } return true; } private static bool IsArticleOrConjunctionOrPreposition(string word) => word is // articles "a" or "an" or "the" or // conjunctions "and" or "as" or "but" or "if" or "nor" or "or" or "so" or "yet" or // prepositions "as" or "at" or "by" or "for" or "in" or "of" or "off" or "on" or "to" or "up" or "via"; } ================================================ FILE: src/Humanizer/Transformer/ToUpperCase.cs ================================================ namespace Humanizer; class ToUpperCase : ICulturedStringTransformer { public string Transform(string input) => Transform(input, CultureInfo.CurrentCulture); public string Transform(string input, CultureInfo culture) { return culture.TextInfo.ToUpper(input); } } ================================================ FILE: src/Humanizer/TruncateExtensions.cs ================================================ namespace Humanizer; /// /// Allow strings to be truncated /// public static class TruncateExtensions { /// /// Truncates a string to a specified maximum length using the default truncation string ("…") and /// fixed-length truncator. /// /// The string to be truncated. Can be null. /// The maximum length of the result string, including the truncation indicator. /// /// The truncated string if its length exceeds , otherwise the original string. /// Returns null if is null. /// /// /// The default truncation indicator is "…" (ellipsis), and truncation occurs from the right side of the string. /// /// /// /// "This is a long string".Truncate(10) => "This is a…" /// "Short".Truncate(10) => "Short" /// null.Truncate(10) => null /// /// [return: NotNullIfNotNull(nameof(input))] public static string? Truncate(this string? input, int length) => input.Truncate(length, "…", Truncator.FixedLength); /// /// Truncates a string to a specified maximum length using a custom truncator and truncation direction. /// /// The string to be truncated. Can be null. /// The maximum length of the result string, including the truncation indicator. /// /// The implementation to use for truncation logic. /// Must not be null. /// /// /// Specifies from which side of the string to truncate. Default is . /// /// /// The truncated string if its length exceeds , otherwise the original string. /// Returns null if is null. /// /// Thrown when is null. /// /// /// "This is a long string".Truncate(10, Truncator.FixedLength, TruncateFrom.Left) => "…ng string" /// "This is a long string".Truncate(10, Truncator.FixedNumberOfWords) => "This is…" /// /// [return: NotNullIfNotNull(nameof(input))] public static string? Truncate(this string? input, int length, ITruncator truncator, TruncateFrom from = TruncateFrom.Right) => input.Truncate(length, "…", truncator, from); /// /// Truncates a string to a specified maximum length using a custom truncation string and fixed-length truncator. /// /// The string to be truncated. Can be null. /// The maximum length of the result string, including the truncation indicator. /// /// The string to use as the truncation indicator (e.g., "...", "…", or any custom string). /// Can be null or empty. /// /// /// Specifies from which side of the string to truncate. Default is . /// /// /// The truncated string if its length exceeds , otherwise the original string. /// Returns null if is null. /// /// /// /// "This is a long string".Truncate(10, "...") => "This is..." /// "This is a long string".Truncate(15, "--") => "This is a lo--" /// "This is a long string".Truncate(10, "...", TruncateFrom.Left) => "...string" /// /// [return: NotNullIfNotNull(nameof(input))] public static string? Truncate(this string? input, int length, string? truncationString, TruncateFrom from = TruncateFrom.Right) => input.Truncate(length, truncationString, Truncator.FixedLength, from); /// /// Truncates a string to a specified maximum length using a custom truncation string, truncator, and direction. /// /// The string to be truncated. Can be null. /// The maximum length of the result string, including the truncation indicator. /// /// The string to use as the truncation indicator (e.g., "...", "…", or any custom string). /// Can be null or empty. /// /// /// The implementation to use for truncation logic. /// Must not be null. /// /// /// Specifies from which side of the string to truncate. Default is . /// /// /// The truncated string if its length exceeds , otherwise the original string. /// Returns null if is null. /// /// Thrown when is null. /// /// This is the most flexible truncation method, allowing full customization of the truncation behavior. /// /// /// /// "This is a long string".Truncate(10, "...", Truncator.FixedLength, TruncateFrom.Right) => "This is..." /// "This is a long string".Truncate(10, "…", Truncator.FixedNumberOfWords, TruncateFrom.Left) => "… string" /// /// [return: NotNullIfNotNull(nameof(input))] public static string? Truncate(this string? input, int length, string? truncationString, ITruncator truncator, TruncateFrom from = TruncateFrom.Right) { ArgumentNullException.ThrowIfNull(truncator); if (input == null) { return null; } return truncator.Truncate(input, length, truncationString, from); } } ================================================ FILE: src/Humanizer/TruncateFrom.cs ================================================ namespace Humanizer; /// /// Truncation location for humanizer /// public enum TruncateFrom { /// /// Truncate letters from the left (start) of the string /// Left, /// /// Truncate letters from the right (end) of the string /// Right } ================================================ FILE: src/Humanizer/Truncation/DynamicLengthAndPreserveWordsTruncator.cs ================================================ namespace Humanizer; /// /// Truncate a string to a fixed length while preserving whole words. /// If the truncation point falls in the middle of a word, /// that word is dropped entirely and the delimiter is attached. /// For left-truncation, if no complete word fits in the allowed space, /// only the delimiter is returned. /// class DynamicLengthAndPreserveWordsTruncator : ITruncator { [return: NotNullIfNotNull(nameof(value))] public string? Truncate(string? value, int length, string? truncationString, TruncateFrom truncateFrom = TruncateFrom.Right) { if (value == null) { return null; } if (value.Length == 0) { return value; } // For this scenario we expect a single-character delimiter. // If truncation string is null, treat it as empty. truncationString ??= string.Empty; // If the delimiter itself is longer than the allowed length, fall back to a basic substring. if (truncationString.Length > length) { return truncateFrom == TruncateFrom.Right ? value[..length] : value[^length..]; } // If the whole string fits, return it. if (value.Length <= length) { return value; } return truncateFrom == TruncateFrom.Right ? TruncateFromRight(value, length, truncationString) : TruncateFromLeft(value, length, truncationString); } static string TruncateFromLeft(string value, int length, string truncationString) { // For left truncation, the final output is: delimiter + substring. // Determine how many characters (after the delimiter) are allowed. var allowedContentLength = length - truncationString.Length; if (allowedContentLength <= 0) { return truncationString; } // We'll scan backward from the end of the string for a whitespace boundary // such that the substring (after trimming) is no longer than allowedContentLength. var candidateStart = value.Length; for (var i = value.Length - 1; i >= 0; i--) { if (char.IsWhiteSpace(value[i])) { candidateStart = i + 1; var candidateLength = value.Length - candidateStart; if (candidateLength <= allowedContentLength) { break; } } } var candidate = value[candidateStart..].TrimStart(); // If the candidate word is too long (i.e. would be partial) or empty, return just the delimiter. if (candidate.Length > allowedContentLength || candidate.Length == 0) { return truncationString; } return truncationString + candidate; } static string TruncateFromRight(string value, int length, string truncationString) { var effectiveLength = length - truncationString.Length; if (effectiveLength <= 0) { return truncationString; } // If the cutoff falls in the middle of a word, backtrack to the last space. if (effectiveLength < value.Length && !char.IsWhiteSpace(value[effectiveLength])) { var lastSpace = value.LastIndexOf(' ', effectiveLength); if (lastSpace > 0) { effectiveLength = lastSpace; } else { return truncationString; } } var prefix = value[..effectiveLength].TrimEnd(); if (prefix.Length == 0) { return truncationString; } return prefix + truncationString; } } ================================================ FILE: src/Humanizer/Truncation/DynamicNumberOfCharactersAndPreserveWordTruncator.cs ================================================ namespace Humanizer; /// /// Truncate a string to a fixed number of letters or digits, /// preserving whole words by never cutting a word in half. /// If a complete word (plus the delimiter, if any) cannot fit, then only the delimiter is returned. /// When truncating from the left, the delimiter is prepended if a complete word can be preserved; /// otherwise, only the delimiter is returned. /// The allowed count is computed by counting only letters/digits. /// public class DynamicNumberOfCharactersAndPreserveWordsTruncator : ITruncator { [return: NotNullIfNotNull(nameof(value))] public string? Truncate(string? value, int totalLength, string? delimiter, TruncateFrom truncateFrom = TruncateFrom.Right) { if (value == null) { return null; } if (value.Length == 0) { return value; } // Treat a null delimiter as an empty string. delimiter ??= string.Empty; // If the delimiter itself is longer than totalLength, fallback to a plain substring. if (delimiter.Length > totalLength && totalLength >= value.Length) { return value; } // Count all alphanumeric characters. If they already fit, return full string. var totalAlpha = value.Count(char.IsLetterOrDigit); if (totalAlpha <= totalLength) { return value; } // Delegate to the appropriate helper. return truncateFrom == TruncateFrom.Right ? TruncateRight(value, totalLength, delimiter) : TruncateLeft(value, totalLength, delimiter); } static string TruncateRight(string value, int totalLength, string delimiter) { var dLen = delimiter.Length; var alphaCount = 0; var candidateIndex = -1; var lastSpace = -1; for (var i = 0; i < value.Length; i++) { if (char.IsWhiteSpace(value[i])) { lastSpace = i; } if (char.IsLetterOrDigit(value[i])) { alphaCount++; } if (alphaCount + dLen == totalLength) { candidateIndex = i + 1; break; } if (alphaCount == totalLength) // if alpha count without delimiter reached total length { candidateIndex = i; break; } } if (candidateIndex == -1) { candidateIndex = value.Length; } // If the candidate index is in the middle of a word, backtrack to last whitespace. if (candidateIndex < value.Length && !char.IsWhiteSpace(value[candidateIndex])) { if (lastSpace > 0) { candidateIndex = lastSpace; } else if (delimiter.Length > totalLength) { return string.Empty; } else { return delimiter; // no complete word fits } } // Get the substring and trim trailing spaces. var prefix = value[..candidateIndex].TrimEnd(); var prefixLength = 0; for (var i = prefix.Length - 1; i >= 0; i--) { if (char.IsLetterOrDigit(prefix[i])) { prefixLength++; } } if (prefixLength == 0) { return delimiter; } if (delimiter.Length > totalLength && prefixLength > totalLength) { return string.Empty; } if (delimiter.Length > prefixLength && delimiter.Length > totalLength) { return prefix; } if (delimiter.Length <= totalLength && delimiter.Length + prefixLength > totalLength) { return delimiter; } return prefix + delimiter; } static string TruncateLeft(string value, int totalLength, string delimiter) { var dLen = delimiter.Length; var alphaCount = 0; var candidateIndex = -1; var nextSpace = -1; // Iterate backwards. for (var i = value.Length - 1; i >= 0; i--) { if (char.IsLetterOrDigit(value[i])) { alphaCount++; } if (char.IsWhiteSpace(value[i])) { nextSpace = i; } if (alphaCount + dLen == totalLength) { candidateIndex = i; break; } if (alphaCount == totalLength) // if alpha count without delimiter reached total length { candidateIndex = i; break; } } if (candidateIndex == -1) { candidateIndex = 0; } // If candidateIndex is in the middle of a word, move forward to the next whitespace. if (candidateIndex < value.Length && candidateIndex > 0 && !char.IsWhiteSpace(value[candidateIndex - 1])) { if (nextSpace >= candidateIndex) { candidateIndex = nextSpace + 1; } else if (delimiter.Length > totalLength) { return string.Empty; } else { return delimiter; // no complete word fits } } var suffix = value[candidateIndex..].TrimStart(); var suffixLength = 0; for (var i = suffix.Length - 1; i >= 0; i--) { if (char.IsLetterOrDigit(suffix[i])) { suffixLength++; } } if (suffixLength == 0) { return delimiter; } if (delimiter.Length > totalLength && suffixLength > totalLength) { return string.Empty; } if (delimiter.Length > suffixLength && delimiter.Length > totalLength) { return suffix; } if (delimiter.Length <= totalLength && delimiter.Length + suffixLength > totalLength) { return delimiter; } return delimiter + suffix; } } ================================================ FILE: src/Humanizer/Truncation/FixedLengthTruncator.cs ================================================ namespace Humanizer; /// /// Truncate a string to a fixed length /// class FixedLengthTruncator : ITruncator { [return: NotNullIfNotNull(nameof(value))] public string? Truncate(string? value, int length, string? truncationString, TruncateFrom truncateFrom = TruncateFrom.Right) { if (value == null) { return null; } if (value.Length == 0 || value.Length <= length) { return value; } if (truncationString == null || truncationString.Length > length) { return truncateFrom == TruncateFrom.Right ? value[..length] : value[^length..]; } return truncateFrom == TruncateFrom.Left ? StringHumanizeExtensions.Concat(truncationString.AsSpan(), value.AsSpan(value.Length - length + truncationString.Length)) : StringHumanizeExtensions.Concat(value.AsSpan(0, length - truncationString.Length), truncationString.AsSpan()); } } ================================================ FILE: src/Humanizer/Truncation/FixedNumberOfCharactersTruncator.cs ================================================ namespace Humanizer; /// /// Truncate a string to a fixed number of letters or digits /// class FixedNumberOfCharactersTruncator : ITruncator { [return: NotNullIfNotNull(nameof(value))] public string? Truncate(string? value, int length, string? truncationString, TruncateFrom truncateFrom = TruncateFrom.Right) { if (value == null) { return null; } if (value.Length == 0) { return value; } truncationString ??= string.Empty; if (truncationString.Length > length) { return truncateFrom == TruncateFrom.Right ? value[..length] : value[^length..]; } // Count letter or digit characters up to length + 1 to determine if truncation is needed var alphaNumericalCount = 0; foreach (var c in value) { if (char.IsLetterOrDigit(c)) { alphaNumericalCount++; if (alphaNumericalCount > length) { break; } } } if (alphaNumericalCount <= length) { return value; } var alphaNumericalCharactersProcessed = 0; if (truncateFrom == TruncateFrom.Left) { for (var i = value.Length - 1; i > 0; i--) { if (char.IsLetterOrDigit(value[i])) { alphaNumericalCharactersProcessed++; } if (alphaNumericalCharactersProcessed + truncationString.Length == length) { return StringHumanizeExtensions.Concat(truncationString.AsSpan(), value.AsSpan(i)); } } } for (var i = 0; i < value.Length - truncationString.Length; i++) { if (char.IsLetterOrDigit(value[i])) { alphaNumericalCharactersProcessed++; } if (alphaNumericalCharactersProcessed + truncationString.Length == length) { return StringHumanizeExtensions.Concat(value.AsSpan(0, i + 1), truncationString.AsSpan()); } } return value; } } ================================================ FILE: src/Humanizer/Truncation/FixedNumberOfWordsTruncator.cs ================================================ namespace Humanizer; /// /// Truncate a string to a fixed number of words /// class FixedNumberOfWordsTruncator : ITruncator { [return: NotNullIfNotNull(nameof(value))] public string? Truncate(string? value, int length, string? truncationString, TruncateFrom truncateFrom = TruncateFrom.Right) { if (value == null) { return null; } if (value.Length == 0) { return value; } // Count words without allocating array var numberOfWords = 0; var wasWhiteSpace = true; foreach (var c in value) { if (char.IsWhiteSpace(c)) { wasWhiteSpace = true; } else if (wasWhiteSpace) { numberOfWords++; wasWhiteSpace = false; } } if (numberOfWords <= length) { return value; } return truncateFrom == TruncateFrom.Left ? TruncateFromLeft(value, length, truncationString) : TruncateFromRight(value, length, truncationString); } static string TruncateFromRight(string value, int length, string? truncationString) { var lastCharactersWasWhiteSpace = true; var numberOfWordsProcessed = 0; for (var i = 0; i < value.Length; i++) { if (char.IsWhiteSpace(value[i])) { if (!lastCharactersWasWhiteSpace) { numberOfWordsProcessed++; } lastCharactersWasWhiteSpace = true; if (numberOfWordsProcessed == length) { return StringHumanizeExtensions.Concat(value.AsSpan(0, i), truncationString.AsSpan()); } } else { lastCharactersWasWhiteSpace = false; } } return value + truncationString; } static string TruncateFromLeft(string value, int length, string? truncationString) { var lastCharactersWasWhiteSpace = true; var numberOfWordsProcessed = 0; for (var i = value.Length - 1; i > 0; i--) { if (char.IsWhiteSpace(value[i])) { if (!lastCharactersWasWhiteSpace) { numberOfWordsProcessed++; } lastCharactersWasWhiteSpace = true; if (numberOfWordsProcessed == length) { return StringHumanizeExtensions.Concat(truncationString.AsSpan(), value.AsSpan(i + 1).TrimEnd()); } } else { lastCharactersWasWhiteSpace = false; } } return truncationString + value; } } ================================================ FILE: src/Humanizer/Truncation/ITruncator.cs ================================================ namespace Humanizer; /// /// Can truncate a string. /// public interface ITruncator { /// /// Truncate a string /// /// The string to truncate /// The length to truncate to /// The string used to truncate with /// The enum value used to determine from where to truncate the string /// The truncated string [return: NotNullIfNotNull(nameof(value))] string? Truncate(string? value, int length, string? truncationString, TruncateFrom truncateFrom = TruncateFrom.Right); } ================================================ FILE: src/Humanizer/Truncation/Truncator.cs ================================================ namespace Humanizer; /// /// Gets a ITruncator /// public static class Truncator { /// /// Fixed length truncator /// public static ITruncator FixedLength { get; } = new FixedLengthTruncator(); /// /// Fixed number of characters truncator /// public static ITruncator FixedNumberOfCharacters { get; } = new FixedNumberOfCharactersTruncator(); /// /// Fixed number of words truncator /// public static ITruncator FixedNumberOfWords { get; } = new FixedNumberOfWordsTruncator(); /// /// Dynamic length And Preserve Words truncator /// public static ITruncator DynamicLengthAndPreserveWords { get; } = new DynamicLengthAndPreserveWordsTruncator(); /// /// Dynamic number of characters And Preserve Words truncator /// public static ITruncator DynamicNumberOfCharactersAndPreserveWords { get; } = new DynamicNumberOfCharactersAndPreserveWordsTruncator(); } ================================================ FILE: src/Humanizer/TupleizeExtensions.cs ================================================ // ReSharper disable IdentifierTypo // ReSharper disable StringLiteralTypo namespace Humanizer; /// /// Convert int to named tuple strings (1 -> 'single', 2-> 'double' etc.). /// Only values 1-10, 100, and 1000 have specific names. All others will return 'n-tuple'. /// public static class TupleizeExtensions { /// /// Converts an integer to its corresponding tuple name (e.g., 'single', 'double', 'triple'). /// /// The integer value to convert to a tuple name. /// /// A string representing the tuple name: /// - 1 returns "single" /// - 2 returns "double" /// - 3 returns "triple" /// - 4 returns "quadruple" /// - 5 returns "quintuple" /// - 6 returns "sextuple" /// - 7 returns "septuple" /// - 8 returns "octuple" /// - 9 returns "nonuple" /// - 10 returns "decuple" /// - 100 returns "centuple" /// - 1000 returns "milluple" /// - Any other value returns "{value}-tuple" (e.g., "42-tuple") /// /// /// Only values 1-10, 100, and 1000 have specific named tuples. All other values return /// a generic n-tuple format. Negative values and zero will return in the format "{value}-tuple". /// /// /// /// 1.Tupleize() => "single" /// 2.Tupleize() => "double" /// 3.Tupleize() => "triple" /// 10.Tupleize() => "decuple" /// 100.Tupleize() => "centuple" /// 42.Tupleize() => "42-tuple" /// (-5).Tupleize() => "-5-tuple" /// /// public static string Tupleize(this int input) => input switch { 1 => "single", 2 => "double", 3 => "triple", 4 => "quadruple", 5 => "quintuple", 6 => "sextuple", 7 => "septuple", 8 => "octuple", 9 => "nonuple", 10 => "decuple", 100 => "centuple", 1000 => "milluple", _ => $"{input}-tuple" }; } ================================================ FILE: src/Humanizer/WordForm.cs ================================================ namespace Humanizer; /// /// Options for specifying the form of the word when different variations of the same word exists. /// public enum WordForm { /// /// Indicates the normal form of a written word. /// Normal, /// /// Indicates the shortened form of a written word. /// Abbreviation, /// /// Indicates the Eifeler Rule form of a word. /// https://lb.wikipedia.org/wiki/Eifeler_Reegel /// Eifeler, } ================================================ FILE: src/Humanizer/WordsToNumberExtension.cs ================================================ namespace Humanizer; /// /// Transform humanized string to number; e.g. one => 1 /// public static class WordsToNumberExtension { /// /// Converts a spelled-out number string to its integer representation. /// /// /// The spelled-out number (e.g., "three hundred twenty-one", "forty-two"). /// Must not be null. /// /// /// The culture to use for parsing. Different cultures may have different word representations /// for numbers (e.g., "twenty" in English vs. "vingt" in French). /// /// /// The integer value represented by the words. /// /// /// Thrown when the input contains unrecognized words or cannot be parsed as a number. /// /// Thrown when is null. /// /// This method strictly parses the input and throws an exception if any word is not recognized. /// For a non-throwing version, use . /// /// /// /// // English (en-US) /// "three hundred twenty-one".ToNumber(new CultureInfo("en-US")) => 321 /// "forty-two".ToNumber(new CultureInfo("en-US")) => 42 /// "one thousand".ToNumber(new CultureInfo("en-US")) => 1000 /// /// // Invalid input throws exception /// "xyz".ToNumber(new CultureInfo("en-US")) => throws FormatException /// /// public static int ToNumber(this string words, CultureInfo culture) => Configurator.GetWordsToNumberConverter(culture).Convert(words); /// /// Attempts to convert a spelled-out number string to its integer representation without throwing exceptions. /// /// /// The spelled-out number (e.g., "forty-two", "one hundred"). /// Must not be null. /// /// /// When this method returns, contains the integer value represented by the words if the conversion succeeded, /// or 0 if the conversion failed. /// /// /// The culture to use for parsing. /// /// /// true if the conversion was successful; otherwise, false. /// /// /// This is the recommended method for parsing when you're not sure if the input is valid. /// It does not throw exceptions on invalid input. /// /// /// /// // Successful conversion /// "forty-two".TryToNumber(out int result, new CultureInfo("en-US")) => returns true, result = 42 /// /// // Failed conversion /// "xyz".TryToNumber(out int result, new CultureInfo("en-US")) => returns false, result = 0 /// /// public static bool TryToNumber(this string words, out int parsedNumber, CultureInfo culture) => Configurator.GetWordsToNumberConverter(culture).TryConvert(words, out parsedNumber); /// /// Attempts to convert a spelled-out number string to its integer representation and provides /// the first unrecognized word if the conversion fails. /// /// /// The spelled-out number (e.g., "one thousand one"). /// Must not be null. /// /// /// When this method returns, contains the integer value represented by the words if the conversion succeeded, /// or 0 if the conversion failed. /// /// /// The culture to use for parsing. /// /// /// When this method returns false, contains the first unrecognized word found in the input. /// When this method returns true, this parameter is set to null. /// /// /// true if the conversion was successful; otherwise, false. /// /// /// This overload is useful for debugging or providing detailed error messages to users, /// as it identifies which specific word caused the parsing failure. /// /// /// /// // Successful conversion /// "one thousand".TryToNumber(out int result, new CultureInfo("en-US"), out string? badWord) /// => returns true, result = 1000, badWord = null /// /// // Failed conversion with unrecognized word /// "one xyz three".TryToNumber(out int result, new CultureInfo("en-US"), out string? badWord) /// => returns false, result = 0, badWord = "xyz" /// /// public static bool TryToNumber(this string words, out int parsedNumber, CultureInfo culture, out string? unrecognizedWord) => Configurator.GetWordsToNumberConverter(culture).TryConvert(words, out parsedNumber, out unrecognizedWord); } ================================================ FILE: src/Humanizer.Analyzers/AnalyzerReleases.Shipped.md ================================================ ## Release 1.0.0 ### New Rules Rule ID | Category | Severity | Notes --------|----------|----------|------- HUMANIZER001 | Usage | Warning | Old Humanizer namespace usage ================================================ FILE: src/Humanizer.Analyzers/AnalyzerReleases.Unshipped.md ================================================ ; Unshipped analyzer release ; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md ================================================ FILE: src/Humanizer.Analyzers/Humanizer.Analyzers.csproj ================================================ netstandard2.0 latest enable true true $(NoWarn);RS2001;RS1038;RS1041;RS2003 cs false false 3.8 roslyn$(RoslynVersion) $(MSBuildProjectDirectory)\bin\$(Configuration)\$(AnalyzerVariant)\ 3.8.0 3.0.0 4.8.0 3.3.4 4.14.0 3.11.0 3.8.0 3.0.0 $(DefineConstants);ROSLYN_4_14_OR_GREATER ================================================ FILE: src/Humanizer.Analyzers/NamespaceMigrationAnalyzer.cs ================================================ using System.Collections.Generic; using System.Collections.Immutable; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; namespace Humanizer.Analyzers; [DiagnosticAnalyzer(LanguageNames.CSharp)] public class NamespaceMigrationAnalyzer : DiagnosticAnalyzer { public const string DiagnosticId = "HUMANIZER001"; private const string Category = "Usage"; private static readonly LocalizableString Title = "Old Humanizer namespace usage"; private static readonly LocalizableString MessageFormat = "The namespace '{0}' has been consolidated into 'Humanizer' in v3. Update your using directive."; private static readonly LocalizableString Description = "Humanizer v3 consolidates sub-namespaces into the root Humanizer namespace. This using directive should be updated to 'using Humanizer;'."; private static readonly DiagnosticDescriptor Rule = new( DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Error, isEnabledByDefault: true, description: Description); private static readonly string[] PrefixMatchingNamespaces = [ "Humanizer.Localisation.CollectionFormatters", "Humanizer.Localisation.TimeToClockNotation", "Humanizer.Localisation.DateToOrdinalWords", "Humanizer.Localisation.NumberToWords", "Humanizer.Localisation.Formatters", "Humanizer.Localisation.Ordinalizers", "Humanizer.DateTimeHumanizeStrategy", "Humanizer.Configuration", "Humanizer.Localisation", "Humanizer.Inflections", "Humanizer.Bytes" ]; private static readonly HashSet OldNamespaces = new(PrefixMatchingNamespaces, StringComparer.Ordinal); public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); public override void Initialize(AnalysisContext context) { context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.EnableConcurrentExecution(); context.RegisterSyntaxNodeAction(AnalyzeUsingDirective, SyntaxKind.UsingDirective); context.RegisterSyntaxNodeAction(AnalyzeQualifiedName, SyntaxKind.QualifiedName); } private static void AnalyzeUsingDirective(SyntaxNodeAnalysisContext context) { if (context.Node is not UsingDirectiveSyntax usingDirective) return; if (usingDirective.Name is null) return; var namespaceName = usingDirective.Name.ToString(); if (OldNamespaces.Contains(namespaceName)) { var diagnostic = Diagnostic.Create(Rule, usingDirective.Name.GetLocation(), namespaceName); context.ReportDiagnostic(diagnostic); } } private static void AnalyzeQualifiedName(SyntaxNodeAnalysisContext context) { if (context.Node is not QualifiedNameSyntax qualifiedName) return; // Skip if this is part of a using directive (already handled above) // Check all ancestors, not just immediate parent, because nested qualified names // will have another qualified name as parent if (qualifiedName.Ancestors().OfType().Any()) return; // Skip if this qualified name has a parent qualified name that also matches // We only want to report the outermost qualified name to avoid duplicate diagnostics if (qualifiedName.Parent is QualifiedNameSyntax parentQualified) { var parentName = parentQualified.ToString(); if (HasMatchingNamespace(parentName)) return; } var fullName = qualifiedName.ToString(); if (!TryGetMatchingNamespace(fullName, out var matchingNamespace)) return; var diagnostic = Diagnostic.Create(Rule, qualifiedName.GetLocation(), matchingNamespace); context.ReportDiagnostic(diagnostic); } #if ROSLYN_4_14_OR_GREATER private static bool IsNamespaceMatch(ReadOnlySpan fullName, ReadOnlySpan oldNamespace) { // Exact match if (fullName.Length == oldNamespace.Length) return fullName.Equals(oldNamespace, StringComparison.Ordinal); // Prefix match with dot separator return fullName.Length > oldNamespace.Length && fullName[oldNamespace.Length] == '.' && fullName.StartsWith(oldNamespace, StringComparison.Ordinal); } #else private static bool IsNamespaceMatch(string fullName, string oldNamespace) { if (fullName.Length == oldNamespace.Length) return string.Equals(fullName, oldNamespace, StringComparison.Ordinal); return fullName.Length > oldNamespace.Length && fullName[oldNamespace.Length] == '.' && fullName.StartsWith(oldNamespace, StringComparison.Ordinal); } #endif private static bool HasMatchingNamespace(string namespaceName) { #if ROSLYN_4_14_OR_GREATER var nameSpan = namespaceName.AsSpan(); foreach (var ns in PrefixMatchingNamespaces) { if (IsNamespaceMatch(nameSpan, ns)) return true; } #else foreach (var ns in PrefixMatchingNamespaces) { if (IsNamespaceMatch(namespaceName, ns)) return true; } #endif return false; } private static bool TryGetMatchingNamespace(string fullName, out string? matchingNamespace) { #if ROSLYN_4_14_OR_GREATER var fullNameSpan = fullName.AsSpan(); foreach (var ns in PrefixMatchingNamespaces) { if (!IsNamespaceMatch(fullNameSpan, ns)) continue; matchingNamespace = ns; return true; } #else foreach (var ns in PrefixMatchingNamespaces) { if (!IsNamespaceMatch(fullName, ns)) continue; matchingNamespace = ns; return true; } #endif matchingNamespace = null; return false; } } ================================================ FILE: src/Humanizer.Analyzers/NamespaceMigrationCodeFixProvider.cs ================================================ using System.Collections.Immutable; using System.Composition; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; namespace Humanizer.Analyzers; [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(NamespaceMigrationCodeFixProvider)), Shared] public class NamespaceMigrationCodeFixProvider : CodeFixProvider { private const string Title = "Update to Humanizer namespace"; // Ordered by length (longest first) for optimal matching private static readonly string[] OldNamespaces = [ "Humanizer.Localisation.CollectionFormatters", "Humanizer.Localisation.TimeToClockNotation", "Humanizer.Localisation.DateToOrdinalWords", "Humanizer.Localisation.NumberToWords", "Humanizer.Localisation.Formatters", "Humanizer.Localisation.Ordinalizers", "Humanizer.DateTimeHumanizeStrategy", "Humanizer.Configuration", "Humanizer.Localisation", "Humanizer.Inflections", "Humanizer.Bytes" ]; public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(NamespaceMigrationAnalyzer.DiagnosticId); public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); if (root is null) return; var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; var node = root.FindNode(diagnosticSpan); // The diagnostic is reported on the namespace name, so navigate up to the using directive var usingDirective = node.FirstAncestorOrSelf(); if (usingDirective is not null) { context.RegisterCodeFix( CodeAction.Create( title: Title, createChangedDocument: c => ReplaceUsingDirectiveAsync(context.Document, usingDirective, c), equivalenceKey: Title), diagnostic); return; } // Handle qualified names (e.g., Humanizer.Bytes.ByteSize) if (node is QualifiedNameSyntax qualifiedName) { context.RegisterCodeFix( CodeAction.Create( title: Title, createChangedDocument: c => ReplaceQualifiedNameAsync(context.Document, qualifiedName, c), equivalenceKey: Title), diagnostic); } } private static async Task ReplaceUsingDirectiveAsync( Document document, UsingDirectiveSyntax usingDirective, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); if (root is null) return document; // Replace the namespace with "Humanizer" var newName = SyntaxFactory.IdentifierName("Humanizer"); var newUsingDirective = usingDirective.WithName(newName); var updatedRoot = root.ReplaceNode(usingDirective, newUsingDirective); return document.WithSyntaxRoot(updatedRoot); } private static async Task ReplaceQualifiedNameAsync(Document document, QualifiedNameSyntax qualifiedName, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); if (root is null) return document; // Find which old namespace this qualified name starts with var fullName = qualifiedName.ToString(); if (!TryGetMatchingNamespace(fullName, out var matchedNamespace)) return document; // Replace the old namespace prefix with "Humanizer" var newNameText = GetReplacementName(fullName, matchedNamespace!); var newQualifiedName = SyntaxFactory.ParseName(newNameText) .WithLeadingTrivia(qualifiedName.GetLeadingTrivia()) .WithTrailingTrivia(qualifiedName.GetTrailingTrivia()); var updatedRoot = root.ReplaceNode(qualifiedName, newQualifiedName); return document.WithSyntaxRoot(updatedRoot); } #if ROSLYN_4_14_OR_GREATER private static bool IsNamespaceMatch(ReadOnlySpan fullName, ReadOnlySpan oldNamespace) { // Exact match if (fullName.Length == oldNamespace.Length) return fullName.Equals(oldNamespace, StringComparison.Ordinal); // Prefix match with dot separator return fullName.Length > oldNamespace.Length && fullName[oldNamespace.Length] == '.' && fullName.StartsWith(oldNamespace, StringComparison.Ordinal); } #else private static bool IsNamespaceMatch(string fullName, string oldNamespace) { if (fullName.Length == oldNamespace.Length) return string.Equals(fullName, oldNamespace, StringComparison.Ordinal); return fullName.Length > oldNamespace.Length && fullName[oldNamespace.Length] == '.' && fullName.StartsWith(oldNamespace, StringComparison.Ordinal); } #endif private static string GetReplacementName(string fullName, string matchedNamespace) { if (fullName.Length == matchedNamespace.Length) return "Humanizer"; // Skip the matched namespace and the dot var startIndex = matchedNamespace.Length + 1; if (startIndex >= fullName.Length) return "Humanizer"; #if NET10_0_OR_GREATER return string.Concat("Humanizer.", fullName.AsSpan(startIndex)); #else return string.Concat("Humanizer.", fullName.Substring(startIndex)); #endif } private static bool TryGetMatchingNamespace(string fullName, out string? matchedNamespace) { #if ROSLYN_4_14_OR_GREATER var fullNameSpan = fullName.AsSpan(); foreach (var ns in OldNamespaces) { if (!IsNamespaceMatch(fullNameSpan, ns)) continue; matchedNamespace = ns; return true; } #else foreach (var ns in OldNamespaces) { if (!IsNamespaceMatch(fullName, ns)) continue; matchedNamespace = ns; return true; } #endif matchedNamespace = null; return false; } } ================================================ FILE: src/Humanizer.Analyzers/README.md ================================================ # Humanizer.Analyzers A Roslyn analyzer and code fix provider to help migrate code from Humanizer v2 to v3. `Humanizer.Core` ships analyzer assets per Roslyn version so compatible analyzers are selected automatically by modern SDK/IDE hosts. ## What it does Humanizer v3 consolidates all sub-namespaces into the root `Humanizer` namespace. This analyzer: 1. **Detects** old namespace usages (e.g., `Humanizer.Bytes`, `Humanizer.Localisation`) 2. **Provides** automatic code fixes to update to `Humanizer` 3. **Supports** batch fixing (Fix All) for entire projects or solutions ## Deprecated Namespaces The following namespaces have been consolidated into `Humanizer`: - `Humanizer.Bytes` - `Humanizer.Localisation` - `Humanizer.Localisation.Formatters` - `Humanizer.Localisation.NumberToWords` - `Humanizer.DateTimeHumanizeStrategy` - `Humanizer.Configuration` - `Humanizer.Localisation.DateToOrdinalWords` - `Humanizer.Localisation.Ordinalizers` - `Humanizer.Inflections` - `Humanizer.Localisation.CollectionFormatters` - `Humanizer.Localisation.TimeToClockNotation` ## Usage ### Automatic Fixes The analyzer will highlight old namespace usages with warnings. You can: 1. **Single fix**: Click the lightbulb 💡 icon and select "Update to Humanizer namespace" 2. **Fix All in Document**: Right-click → Quick Actions → Fix All Occurrences in Document 3. **Fix All in Project**: Right-click → Quick Actions → Fix All Occurrences in Project 4. **Fix All in Solution**: Right-click → Quick Actions → Fix All Occurrences in Solution ### Examples **Before:** ```csharp using Humanizer.Bytes; using Humanizer.Localisation; public class Example { public void Method() { var size = ByteSize.FromKilobytes(10); var formatter = new DefaultFormatter(); } } ``` **After (automatic fix):** ```csharp using Humanizer; public class Example { public void Method() { var size = ByteSize.FromKilobytes(10); var formatter = new DefaultFormatter(); } } ``` ## Command Line Usage You can also use the .NET CLI to apply fixes: ```bash # Analyze and show diagnostics dotnet build /p:TreatWarningsAsErrors=false # Apply code fixes (requires dotnet format or IDE) dotnet format analyzers --diagnostics HUMANIZER001 ``` ## Development ### Building ```bash cd src/Humanizer.Analyzers dotnet build ``` ### Testing ```bash # from the repository root cd tests/Humanizer.Analyzers.Tests dotnet test ``` ## Diagnostic ID - **HUMANIZER001**: Old Humanizer namespace usage ================================================ FILE: src/Humanizer.Analyzers/build/Humanizer.Core.targets ================================================ ================================================ FILE: src/scripts/split-benchmark-results.ps1 ================================================ param( [Parameter(Mandatory)] [string]$InputDir, [string]$OutputRoot = "." ) # ---- Editable short TFM map ---- # Keys are substrings or regexes you expect in the runtime name. # Left to right match wins. Add or reorder as needed. $TfmMap = @( @{ Pattern = '^\.NET\s+10(\.0)?$'; Tfm = 'net10.0' } @{ Pattern = '^\.NET\s+8(\.0)?$'; Tfm = 'net8.0' } @{ Pattern = '^\.NET\s+Framework\s*4\.8$'; Tfm = 'net48' } ) $DefaultTfm = 'unknown' # ---- Helpers ---- function Get-Runtime([object]$b) { # 1) Old path if ($b.PSObject.Properties.Name -contains 'Properties' -and $b.Properties.Runtime) { return [string]$b.Properties.Runtime } # 2) New nested path $rt = $b.BenchmarkCase.Job.Environment.Runtime.Name if ($rt) { return [string]$rt } # 3) Fallback from DisplayInfo, e.g. "...(Runtime=.NET 10.0)" $di = [string]$b.DisplayInfo if ($di -match 'Runtime=([^)]+)\)') { return $Matches[1].Trim() } return $null } function To-ShortTfm([string]$runtimeName) { foreach ($m in $TfmMap) { if ($runtimeName -match $m.Pattern) { return $m.Tfm } } return $DefaultTfm } # ---- Process all JSONs in directory ---- $files = Get-ChildItem -LiteralPath $InputDir -File -Filter *.json if (-not $files) { throw "No .json files found in '$InputDir'." } foreach ($f in $files) { try { $root = Get-Content -Raw -LiteralPath $f.FullName | ConvertFrom-Json -AsHashtable if (-not $root.ContainsKey('Benchmarks')) { Write-Warning "Skip '$($f.Name)': no 'Benchmarks'."; continue } $byRuntime = @{} foreach ($b in $root.Benchmarks) { $rt = Get-Runtime $b if (-not $rt) { Write-Warning "Skip one entry in '$($f.Name)': runtime not detected."; continue } if (-not $byRuntime.ContainsKey($rt)) { $byRuntime[$rt] = [System.Collections.ArrayList]::new() } [void]$byRuntime[$rt].Add($b) } if ($byRuntime.Count -eq 0) { Write-Warning "Skip '$($f.Name)': no entries with detectable runtime."; continue } foreach ($rt in $byRuntime.Keys) { $short = To-ShortTfm $rt $outDir = Join-Path $OutputRoot $short New-Item -ItemType Directory -Force -Path $outDir | Out-Null # Build per-runtime JSON preserving top-level fields except Benchmarks $out = [ordered]@{} foreach ($k in $root.Keys) { if ($k -ne 'Benchmarks') { $out[$k] = $root[$k] } } $out['Title'] = "{0} ({1})" -f $root['Title'], $rt $out['Benchmarks'] = $byRuntime[$rt] $json = $out | ConvertTo-Json -Depth 100 $dest = Join-Path $outDir $f.Name Set-Content -LiteralPath $dest -Value $json -NoNewline Write-Host "Wrote $dest" } } catch { Write-Warning "Error processing '$($f.FullName)': $($_.Exception.Message)" } } ================================================ FILE: tests/Humanizer.Analyzers.Tests/AnalyzerAssemblyCompatibilityTests.cs ================================================ using System.Reflection; using System.Linq; using Humanizer.Analyzers; using Xunit; namespace Humanizer.Analyzers.Tests; public class AnalyzerAssemblyCompatibilityTests { [Fact] public void ShouldReferenceCompatibleSystemMemoryVersion() { var systemMemoryReference = GetAssemblyReferences().SingleOrDefault(reference => reference.Name == "System.Memory"); if (systemMemoryReference is null) return; var isCompatible = systemMemoryReference.Version is not null && systemMemoryReference.Version <= new Version(4, 0, 1, 2); if (!isCompatible) throw new InvalidOperationException($"Expected System.Memory version <= 4.0.1.2 but found {systemMemoryReference.Version}."); } [Fact] public void ShouldReferenceCompatibleSystemCollectionsImmutableVersion() { var immutableReference = GetAssemblyReferences().SingleOrDefault(reference => reference.Name == "System.Collections.Immutable"); if (immutableReference is null) throw new InvalidOperationException("Expected System.Collections.Immutable reference but none was found."); var isCompatible = immutableReference.Version is not null && immutableReference.Version.Major <= 7; if (!isCompatible) throw new InvalidOperationException($"Expected System.Collections.Immutable major version <= 7 but found {immutableReference.Version}."); } private static AssemblyName[] GetAssemblyReferences() => typeof(NamespaceMigrationAnalyzer).Assembly.GetReferencedAssemblies(); } ================================================ FILE: tests/Humanizer.Analyzers.Tests/Humanizer.Analyzers.Tests.csproj ================================================ net10.0 Exe true true ================================================ FILE: tests/Humanizer.Analyzers.Tests/NamespaceMigrationAnalyzerTests.cs ================================================ using Xunit; using VerifyCS = Humanizer.Analyzers.Tests.CSharpCodeFixVerifier< Humanizer.Analyzers.NamespaceMigrationAnalyzer, Humanizer.Analyzers.NamespaceMigrationCodeFixProvider>; namespace Humanizer.Analyzers.Tests; public class NamespaceMigrationAnalyzerTests { [Fact] public async Task EmptyCode_NoDiagnostic() { var test = ""; await VerifyCS.VerifyAnalyzerAsync(test); } [Fact] public async Task UsingHumanizer_NoDiagnostic() { var test = @" using Humanizer; class TestClass { } "; await VerifyCS.VerifyAnalyzerAsync(test); } [Fact] public async Task UsingHumanizerBytes_Diagnostic() { var test = @" using {|#0:Humanizer.Bytes|}; class TestClass { } "; await VerifyCS.VerifyAnalyzerAsync(test, VerifyCS.Diagnostic(NamespaceMigrationAnalyzer.DiagnosticId) .WithLocation(0) .WithArguments("Humanizer.Bytes")); } [Fact] public async Task UsingHumanizerLocalisation_Diagnostic() { var test = @" using {|#0:Humanizer.Localisation|}; class TestClass { } "; await VerifyCS.VerifyAnalyzerAsync(test, VerifyCS.Diagnostic(NamespaceMigrationAnalyzer.DiagnosticId) .WithLocation(0) .WithArguments("Humanizer.Localisation")); } [Fact] public async Task UsingHumanizerLocalisationFormatters_Diagnostic() { var test = @" using {|#0:Humanizer.Localisation.Formatters|}; class TestClass { } "; await VerifyCS.VerifyAnalyzerAsync(test, VerifyCS.Diagnostic(NamespaceMigrationAnalyzer.DiagnosticId) .WithLocation(0) .WithArguments("Humanizer.Localisation.Formatters")); } [Fact] public async Task UsingHumanizerConfiguration_Diagnostic() { var test = @" using {|#0:Humanizer.Configuration|}; class TestClass { } "; await VerifyCS.VerifyAnalyzerAsync(test, VerifyCS.Diagnostic(NamespaceMigrationAnalyzer.DiagnosticId) .WithLocation(0) .WithArguments("Humanizer.Configuration")); } [Fact] public async Task UsingHumanizerInflections_Diagnostic() { var test = @" using {|#0:Humanizer.Inflections|}; class TestClass { } "; await VerifyCS.VerifyAnalyzerAsync(test, VerifyCS.Diagnostic(NamespaceMigrationAnalyzer.DiagnosticId) .WithLocation(0) .WithArguments("Humanizer.Inflections")); } [Fact] public async Task MultipleOldUsings_MultipleDiagnostics() { var test = @" using {|#0:Humanizer.Bytes|}; using {|#1:Humanizer.Localisation|}; using {|#2:Humanizer.Configuration|}; class TestClass { } "; await VerifyCS.VerifyAnalyzerAsync(test, VerifyCS.Diagnostic(NamespaceMigrationAnalyzer.DiagnosticId) .WithLocation(0) .WithArguments("Humanizer.Bytes"), VerifyCS.Diagnostic(NamespaceMigrationAnalyzer.DiagnosticId) .WithLocation(1) .WithArguments("Humanizer.Localisation"), VerifyCS.Diagnostic(NamespaceMigrationAnalyzer.DiagnosticId) .WithLocation(2) .WithArguments("Humanizer.Configuration")); } [Fact] public async Task QualifiedNameUsage_Diagnostic() { var test = @" namespace TestNamespace { class TestClass { void Method() { var typeName = typeof({|#0:Humanizer.Bytes.IFormatter|}).Name; } } } "; await VerifyCS.VerifyAnalyzerAsync(test, VerifyCS.Diagnostic(NamespaceMigrationAnalyzer.DiagnosticId) .WithLocation(0) .WithArguments("Humanizer.Bytes")); } } ================================================ FILE: tests/Humanizer.Analyzers.Tests/NamespaceMigrationCodeFixTests.cs ================================================ using Xunit; using VerifyCS = Humanizer.Analyzers.Tests.CSharpCodeFixVerifier< Humanizer.Analyzers.NamespaceMigrationAnalyzer, Humanizer.Analyzers.NamespaceMigrationCodeFixProvider>; namespace Humanizer.Analyzers.Tests; public class NamespaceMigrationCodeFixTests { [Fact] public async Task FixUsingHumanizerBytes() { var test = @" using Humanizer.Bytes; class TestClass { } "; var fixedCode = @" using Humanizer; class TestClass { } "; var expected = VerifyCS.Diagnostic(NamespaceMigrationAnalyzer.DiagnosticId) .WithSpan(2, 7, 2, 22) .WithArguments("Humanizer.Bytes"); await VerifyCS.VerifyCodeFixAsync(test, expected, fixedCode); } [Fact] public async Task FixUsingHumanizerLocalisation() { var test = @" using Humanizer.Localisation; class TestClass { } "; var fixedCode = @" using Humanizer; class TestClass { } "; var expected = VerifyCS.Diagnostic(NamespaceMigrationAnalyzer.DiagnosticId) .WithSpan(2, 7, 2, 29) .WithArguments("Humanizer.Localisation"); await VerifyCS.VerifyCodeFixAsync(test, expected, fixedCode); } [Fact] public async Task FixUsingHumanizerConfiguration() { var test = @" using Humanizer.Configuration; class TestClass { } "; var fixedCode = @" using Humanizer; class TestClass { } "; var expected = VerifyCS.Diagnostic(NamespaceMigrationAnalyzer.DiagnosticId) .WithSpan(2, 7, 2, 30) .WithArguments("Humanizer.Configuration"); await VerifyCS.VerifyCodeFixAsync(test, expected, fixedCode); } [Fact] public async Task FixUsingHumanizerLocalisationFormatters() { var test = @" using Humanizer.Localisation.Formatters; class TestClass { } "; var fixedCode = @" using Humanizer; class TestClass { } "; var expected = VerifyCS.Diagnostic(NamespaceMigrationAnalyzer.DiagnosticId) .WithSpan(2, 7, 2, 40) .WithArguments("Humanizer.Localisation.Formatters"); await VerifyCS.VerifyCodeFixAsync(test, expected, fixedCode); } [Fact] public async Task FixUsingHumanizerInflections() { var test = @" using Humanizer.Inflections; class TestClass { } "; var fixedCode = @" using Humanizer; class TestClass { } "; var expected = VerifyCS.Diagnostic(NamespaceMigrationAnalyzer.DiagnosticId) .WithSpan(2, 7, 2, 28) .WithArguments("Humanizer.Inflections"); await VerifyCS.VerifyCodeFixAsync(test, expected, fixedCode); } [Fact] public async Task FixQualifiedNameUsage() { var test = @" namespace TestNamespace { class TestClass { void Method() { var typeName = typeof(Humanizer.Bytes.IFormatter).Name; } } } "; var fixedCode = @" namespace TestNamespace { class TestClass { void Method() { var typeName = typeof(Humanizer.IFormatter).Name; } } } "; var expected = VerifyCS.Diagnostic(NamespaceMigrationAnalyzer.DiagnosticId) .WithSpan(8, 35, 8, 61) .WithArguments("Humanizer.Bytes"); await VerifyCS.VerifyCodeFixAsync(test, expected, fixedCode); } } ================================================ FILE: tests/Humanizer.Analyzers.Tests/Verifiers.cs ================================================ using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.CSharp.Testing; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.CodeFixes; namespace Humanizer.Analyzers.Tests; public static class CSharpCodeFixVerifier where TAnalyzer : DiagnosticAnalyzer, new() where TCodeFix : CodeFixProvider, new() { public static DiagnosticResult Diagnostic(string diagnosticId) => CSharpCodeFixVerifier.Diagnostic(diagnosticId); public static async Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected) { var test = new CSharpAnalyzerTest { TestCode = source, CompilerDiagnostics = CompilerDiagnostics.None, }; test.TestState.AdditionalReferences.Add(typeof(Humanizer.ByteSize).Assembly); test.ExpectedDiagnostics.AddRange(expected); await test.RunAsync(); } public static async Task VerifyCodeFixAsync(string source, string fixedSource) { await VerifyCodeFixAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource); } public static async Task VerifyCodeFixAsync(string source, DiagnosticResult expected, string fixedSource) { await VerifyCodeFixAsync(source, new[] { expected }, fixedSource); } public static async Task VerifyCodeFixAsync(string source, DiagnosticResult[] expected, string fixedSource) { var test = new CSharpCodeFixTest { TestCode = source, FixedCode = fixedSource, CompilerDiagnostics = CompilerDiagnostics.None, }; test.TestState.AdditionalReferences.Add(typeof(Humanizer.ByteSize).Assembly); test.FixedState.AdditionalReferences.Add(typeof(Humanizer.ByteSize).Assembly); test.ExpectedDiagnostics.AddRange(expected); await test.RunAsync(); } } ================================================ FILE: tests/Humanizer.Tests/.editorconfig ================================================ [*.cs] dotnet_diagnostic.CA1050.severity = none # CA1050: Declare types in namespaces # CA1861: Avoid constant arrays as arguments dotnet_diagnostic.CA1861.severity = silent # IDE0060: Remove unused parameter dotnet_diagnostic.IDE0060.severity = none # IDE0022: Use expression body for method dotnet_diagnostic.IDE0130.severity = none ================================================ FILE: tests/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.Approve_Public_Api.DotNet10_0.verified.txt ================================================ [assembly: System.Reflection.AssemblyMetadata("IsAotCompatible", "True")] [assembly: System.Reflection.AssemblyMetadata("IsTrimmable", "True")] [assembly: System.Resources.NeutralResourcesLanguage("en")] [assembly: System.Runtime.Versioning.TargetFramework(".NETCoreApp,Version=v10.0", FrameworkDisplayName=".NET 10.0")] namespace Humanizer { public class ByteRate { public ByteRate(Humanizer.ByteSize size, System.TimeSpan interval) { } public System.TimeSpan Interval { get; } public Humanizer.ByteSize Size { get; } public string Humanize(Humanizer.TimeUnit timeUnit = 1) { } public string Humanize(string? format, Humanizer.TimeUnit timeUnit = 1, System.Globalization.CultureInfo? culture = null) { } } public struct ByteSize : System.IComparable, System.IComparable, System.IEquatable, System.IFormattable { public const string Bit = "bit"; public const string BitSymbol = "b"; public const long BitsInByte = 8; public const string Byte = "byte"; public const string ByteSymbol = "B"; public const long BytesInGigabyte = 1073741824; public const long BytesInKilobyte = 1024; public const long BytesInMegabyte = 1048576; public const long BytesInTerabyte = 1099511627776; public const string Gigabyte = "gigabyte"; public const string GigabyteSymbol = "GB"; public const string Kilobyte = "kilobyte"; public const string KilobyteSymbol = "KB"; public const string Megabyte = "megabyte"; public const string MegabyteSymbol = "MB"; public const string Terabyte = "terabyte"; public const string TerabyteSymbol = "TB"; public static readonly Humanizer.ByteSize MaxValue; public static readonly Humanizer.ByteSize MinValue; public ByteSize(double byteSize) { } public long Bits { get; } public double Bytes { get; } public double Gigabytes { get; } public double Kilobytes { get; } public string LargestWholeNumberFullWord { get; } public string LargestWholeNumberSymbol { get; } public double LargestWholeNumberValue { get; } public double Megabytes { get; } public double Terabytes { get; } public Humanizer.ByteSize Add(Humanizer.ByteSize bs) { } public Humanizer.ByteSize AddBits(long value) { } public Humanizer.ByteSize AddBytes(double value) { } public Humanizer.ByteSize AddGigabytes(double value) { } public Humanizer.ByteSize AddKilobytes(double value) { } public Humanizer.ByteSize AddMegabytes(double value) { } public Humanizer.ByteSize AddTerabytes(double value) { } public int CompareTo(Humanizer.ByteSize other) { } public int CompareTo(object? obj) { } public bool Equals(Humanizer.ByteSize value) { } public override bool Equals(object? value) { } public override int GetHashCode() { } public string GetLargestWholeNumberFullWord(System.IFormatProvider? provider = null) { } public string GetLargestWholeNumberSymbol(System.IFormatProvider? provider = null) { } public Humanizer.ByteSize Subtract(Humanizer.ByteSize bs) { } public string ToFullWords(string? format = null, System.IFormatProvider? provider = null) { } public override string ToString() { } public string ToString(System.IFormatProvider? provider) { } public string ToString(string? format) { } public string ToString(string? format, System.IFormatProvider? provider) { } public static Humanizer.ByteSize FromBits(long value) { } public static Humanizer.ByteSize FromBytes(double value) { } public static Humanizer.ByteSize FromGigabytes(double value) { } public static Humanizer.ByteSize FromKilobytes(double value) { } public static Humanizer.ByteSize FromMegabytes(double value) { } public static Humanizer.ByteSize FromTerabytes(double value) { } public static Humanizer.ByteSize Parse(string s) { } public static Humanizer.ByteSize Parse(string s, System.IFormatProvider? formatProvider) { } public static bool TryParse(System.ReadOnlySpan s, out Humanizer.ByteSize result) { } public static bool TryParse(string? s, out Humanizer.ByteSize result) { } public static bool TryParse(System.ReadOnlySpan s, System.IFormatProvider? formatProvider, out Humanizer.ByteSize result) { } public static bool TryParse(string? s, System.IFormatProvider? formatProvider, out Humanizer.ByteSize result) { } public static bool operator !=(Humanizer.ByteSize b1, Humanizer.ByteSize b2) { } public static Humanizer.ByteSize operator +(Humanizer.ByteSize b1, Humanizer.ByteSize b2) { } public static Humanizer.ByteSize operator ++(Humanizer.ByteSize b) { } public static Humanizer.ByteSize operator -(Humanizer.ByteSize b) { } public static Humanizer.ByteSize operator -(Humanizer.ByteSize b1, Humanizer.ByteSize b2) { } public static Humanizer.ByteSize operator --(Humanizer.ByteSize b) { } public static bool operator <(Humanizer.ByteSize b1, Humanizer.ByteSize b2) { } public static bool operator <=(Humanizer.ByteSize b1, Humanizer.ByteSize b2) { } public static bool operator ==(Humanizer.ByteSize b1, Humanizer.ByteSize b2) { } public static bool operator >(Humanizer.ByteSize b1, Humanizer.ByteSize b2) { } public static bool operator >=(Humanizer.ByteSize b1, Humanizer.ByteSize b2) { } } public static class ByteSizeExtensions { public static Humanizer.ByteSize Bits(this byte input) { } public static Humanizer.ByteSize Bits(this int input) { } public static Humanizer.ByteSize Bits(this long input) { } public static Humanizer.ByteSize Bits(this sbyte input) { } public static Humanizer.ByteSize Bits(this short input) { } public static Humanizer.ByteSize Bits(this uint input) { } public static Humanizer.ByteSize Bits(this ushort input) { } public static Humanizer.ByteSize Bytes(this byte input) { } public static Humanizer.ByteSize Bytes(this double input) { } public static Humanizer.ByteSize Bytes(this int input) { } public static Humanizer.ByteSize Bytes(this long input) { } public static Humanizer.ByteSize Bytes(this sbyte input) { } public static Humanizer.ByteSize Bytes(this short input) { } public static Humanizer.ByteSize Bytes(this uint input) { } public static Humanizer.ByteSize Bytes(this ushort input) { } public static Humanizer.ByteSize Gigabytes(this byte input) { } public static Humanizer.ByteSize Gigabytes(this double input) { } public static Humanizer.ByteSize Gigabytes(this int input) { } public static Humanizer.ByteSize Gigabytes(this long input) { } public static Humanizer.ByteSize Gigabytes(this sbyte input) { } public static Humanizer.ByteSize Gigabytes(this short input) { } public static Humanizer.ByteSize Gigabytes(this uint input) { } public static Humanizer.ByteSize Gigabytes(this ushort input) { } public static string Humanize(this Humanizer.ByteSize input, System.IFormatProvider formatProvider) { } public static string Humanize(this Humanizer.ByteSize input, string? format = null) { } public static string Humanize(this Humanizer.ByteSize input, string? format, System.IFormatProvider? formatProvider) { } public static Humanizer.ByteSize Kilobytes(this byte input) { } public static Humanizer.ByteSize Kilobytes(this double input) { } public static Humanizer.ByteSize Kilobytes(this int input) { } public static Humanizer.ByteSize Kilobytes(this long input) { } public static Humanizer.ByteSize Kilobytes(this sbyte input) { } public static Humanizer.ByteSize Kilobytes(this short input) { } public static Humanizer.ByteSize Kilobytes(this uint input) { } public static Humanizer.ByteSize Kilobytes(this ushort input) { } public static Humanizer.ByteSize Megabytes(this byte input) { } public static Humanizer.ByteSize Megabytes(this double input) { } public static Humanizer.ByteSize Megabytes(this int input) { } public static Humanizer.ByteSize Megabytes(this long input) { } public static Humanizer.ByteSize Megabytes(this sbyte input) { } public static Humanizer.ByteSize Megabytes(this short input) { } public static Humanizer.ByteSize Megabytes(this uint input) { } public static Humanizer.ByteSize Megabytes(this ushort input) { } public static Humanizer.ByteRate Per(this Humanizer.ByteSize size, System.TimeSpan interval) { } public static Humanizer.ByteSize Terabytes(this byte input) { } public static Humanizer.ByteSize Terabytes(this double input) { } public static Humanizer.ByteSize Terabytes(this int input) { } public static Humanizer.ByteSize Terabytes(this long input) { } public static Humanizer.ByteSize Terabytes(this sbyte input) { } public static Humanizer.ByteSize Terabytes(this short input) { } public static Humanizer.ByteSize Terabytes(this uint input) { } public static Humanizer.ByteSize Terabytes(this ushort input) { } } public static class CasingExtensions { public static string ApplyCase(this string input, Humanizer.LetterCasing casing) { } } public enum ClockNotationRounding { None = 0, NearestFiveMinutes = 1, } public static class CollectionHumanizeExtensions { public static string Humanize(this System.Collections.Generic.IEnumerable collection) { } public static string Humanize(this System.Collections.Generic.IEnumerable collection, System.Func displayFormatter) { } public static string Humanize(this System.Collections.Generic.IEnumerable collection, System.Func displayFormatter) { } public static string Humanize(this System.Collections.Generic.IEnumerable collection, string separator) { } public static string Humanize(this System.Collections.Generic.IEnumerable collection, System.Func displayFormatter, string separator) { } public static string Humanize(this System.Collections.Generic.IEnumerable collection, System.Func displayFormatter, string separator) { } } public static class Configurator { public static Humanizer.LocaliserRegistry CollectionFormatters { get; } public static Humanizer.IDateOnlyHumanizeStrategy DateOnlyHumanizeStrategy { get; set; } public static Humanizer.LocaliserRegistry DateOnlyToOrdinalWordsConverters { get; } public static Humanizer.IDateTimeHumanizeStrategy DateTimeHumanizeStrategy { get; set; } public static Humanizer.IDateTimeOffsetHumanizeStrategy DateTimeOffsetHumanizeStrategy { get; set; } public static Humanizer.LocaliserRegistry DateToOrdinalWordsConverters { get; } public static Humanizer.LocaliserRegistry Formatters { get; } public static Humanizer.LocaliserRegistry NumberToWordsConverters { get; } public static Humanizer.LocaliserRegistry Ordinalizers { get; } public static Humanizer.ITimeOnlyHumanizeStrategy TimeOnlyHumanizeStrategy { get; set; } public static Humanizer.LocaliserRegistry TimeOnlyToClockNotationConverters { get; } public static void UseEnumDescriptionPropertyLocator(System.Func func) { } } public enum DataUnit { Bit = 0, Byte = 1, Kilobyte = 2, Megabyte = 3, Gigabyte = 4, Terabyte = 5, } public static class DateHumanizeExtensions { public static string Humanize(this System.DateOnly input, System.DateOnly? dateToCompareAgainst = default, System.Globalization.CultureInfo? culture = null) { } public static string Humanize(this System.DateOnly? input, System.DateOnly? dateToCompareAgainst = default, System.Globalization.CultureInfo? culture = null) { } public static string Humanize(this System.DateTimeOffset input, System.DateTimeOffset? dateToCompareAgainst = default, System.Globalization.CultureInfo? culture = null) { } public static string Humanize(this System.DateTimeOffset? input, System.DateTimeOffset? dateToCompareAgainst = default, System.Globalization.CultureInfo? culture = null) { } public static string Humanize(this System.DateTime input, bool? utcDate = default, System.DateTime? dateToCompareAgainst = default, System.Globalization.CultureInfo? culture = null) { } public static string Humanize(this System.DateTime? input, bool? utcDate = default, System.DateTime? dateToCompareAgainst = default, System.Globalization.CultureInfo? culture = null) { } public static string Humanize(this System.TimeOnly input, System.TimeOnly? timeToCompareAgainst = default, bool useUtc = true, System.Globalization.CultureInfo? culture = null) { } public static string Humanize(this System.TimeOnly? input, System.TimeOnly? timeToCompareAgainst = default, bool useUtc = true, System.Globalization.CultureInfo? culture = null) { } } public static class DateToOrdinalWordsExtensions { public static string ToOrdinalWords(this System.DateOnly input) { } public static string ToOrdinalWords(this System.DateTime input) { } public static string ToOrdinalWords(this System.DateOnly input, Humanizer.GrammaticalCase grammaticalCase) { } public static string ToOrdinalWords(this System.DateTime input, Humanizer.GrammaticalCase grammaticalCase) { } } public class DefaultDateOnlyHumanizeStrategy : Humanizer.IDateOnlyHumanizeStrategy { public DefaultDateOnlyHumanizeStrategy() { } public string Humanize(System.DateOnly input, System.DateOnly comparisonBase, System.Globalization.CultureInfo? culture) { } } public class DefaultDateTimeHumanizeStrategy : Humanizer.IDateTimeHumanizeStrategy { public DefaultDateTimeHumanizeStrategy() { } public string Humanize(System.DateTime input, System.DateTime comparisonBase, System.Globalization.CultureInfo? culture) { } } public class DefaultDateTimeOffsetHumanizeStrategy : Humanizer.IDateTimeOffsetHumanizeStrategy { public DefaultDateTimeOffsetHumanizeStrategy() { } public string Humanize(System.DateTimeOffset input, System.DateTimeOffset comparisonBase, System.Globalization.CultureInfo? culture) { } } public class DefaultFormatter : Humanizer.IFormatter { public DefaultFormatter(System.Globalization.CultureInfo culture) { } public DefaultFormatter(string localeCode) { } protected System.Globalization.CultureInfo Culture { get; } public virtual string DataUnitHumanize(Humanizer.DataUnit dataUnit, double count, bool toSymbol = true) { } public virtual string DateHumanize(Humanizer.TimeUnit timeUnit, Humanizer.Tense timeUnitTense, int unit) { } public virtual string DateHumanize_Never() { } public virtual string DateHumanize_Now() { } protected virtual string Format(string resourceKey) { } protected virtual string Format(Humanizer.TimeUnit unit, string resourceKey, int number, bool toWords = false) { } protected virtual string GetResourceKey(string resourceKey) { } protected virtual string GetResourceKey(string resourceKey, int number) { } protected virtual string NumberToWords(Humanizer.TimeUnit unit, int number, System.Globalization.CultureInfo culture) { } public virtual string TimeSpanHumanize(Humanizer.TimeUnit timeUnit, int unit, bool toWords = false) { } public virtual string TimeSpanHumanize_Age() { } public virtual string TimeSpanHumanize_Zero() { } public virtual string TimeUnitHumanize(Humanizer.TimeUnit timeUnit) { } } public class DefaultTimeOnlyHumanizeStrategy : Humanizer.ITimeOnlyHumanizeStrategy { public DefaultTimeOnlyHumanizeStrategy() { } public string Humanize(System.TimeOnly input, System.TimeOnly comparisonBase, System.Globalization.CultureInfo? culture) { } } public class DynamicNumberOfCharactersAndPreserveWordsTruncator : Humanizer.ITruncator { public DynamicNumberOfCharactersAndPreserveWordsTruncator() { } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("value")] public string? Truncate(string? value, int totalLength, string? delimiter, Humanizer.TruncateFrom truncateFrom = 1) { } } public static class EnglishArticle { public static string[] AppendArticlePrefix(string[] items) { } public static string[] PrependArticleSuffix(string[] appended) { } } public static class EnumDehumanizeExtensions { [System.Diagnostics.CodeAnalysis.DynamicDependency(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods, typeof(Humanizer.EnumDehumanizeExtensions))] [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("The native code for the target enumeration might not be available at runtime.")] [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("The native code for the target enumeration might not be available at runtime.")] public static System.Enum DehumanizeTo(this string input, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields)] System.Type targetEnum, Humanizer.OnNoMatch onNoMatch = 0) { } public static TTargetEnum DehumanizeTo<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields)] TTargetEnum>(this string input) where TTargetEnum : struct, System.Enum { } public static TTargetEnum? DehumanizeTo<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields)] TTargetEnum>(this string input, Humanizer.OnNoMatch onNoMatch = 0) where TTargetEnum : struct, System.Enum { } } public static class EnumHumanizeExtensions { public static string Humanize<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields)] T>(this T input) where T : struct, System.Enum { } public static string Humanize<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields)] T>(this T input, Humanizer.LetterCasing casing) where T : struct, System.Enum { } } public enum GrammaticalCase { Nominative = 0, Genitive = 1, Dative = 2, Accusative = 3, Instrumental = 4, Prepositional = 5, } public enum GrammaticalGender { Masculine = 0, Feminine = 1, Neuter = 2, } public static class HeadingExtensions { public static double FromAbbreviatedHeading(this string heading) { } public static double FromAbbreviatedHeading(this string heading, System.Globalization.CultureInfo? culture = null) { } public static double FromHeadingArrow(this char heading) { } public static double FromHeadingArrow(this string heading) { } public static string ToHeading(this double heading, Humanizer.HeadingStyle style = 0, System.Globalization.CultureInfo? culture = null) { } public static char ToHeadingArrow(this double heading) { } } public enum HeadingStyle { Abbreviated = 0, Full = 1, } public interface ICollectionFormatter { string Humanize(System.Collections.Generic.IEnumerable collection); string Humanize(System.Collections.Generic.IEnumerable collection, System.Func objectFormatter); string Humanize(System.Collections.Generic.IEnumerable collection, System.Func objectFormatter); string Humanize(System.Collections.Generic.IEnumerable collection, string separator); string Humanize(System.Collections.Generic.IEnumerable collection, System.Func objectFormatter, string separator); string Humanize(System.Collections.Generic.IEnumerable collection, System.Func objectFormatter, string separator); } public interface ICulturedStringTransformer : Humanizer.IStringTransformer { string Transform(string input, System.Globalization.CultureInfo culture); } public interface IDateOnlyHumanizeStrategy { string Humanize(System.DateOnly input, System.DateOnly comparisonBase, System.Globalization.CultureInfo? culture); } public interface IDateOnlyToOrdinalWordConverter { string Convert(System.DateOnly date); string Convert(System.DateOnly date, Humanizer.GrammaticalCase grammaticalCase); } public interface IDateTimeHumanizeStrategy { string Humanize(System.DateTime input, System.DateTime comparisonBase, System.Globalization.CultureInfo? culture); } public interface IDateTimeOffsetHumanizeStrategy { string Humanize(System.DateTimeOffset input, System.DateTimeOffset comparisonBase, System.Globalization.CultureInfo? culture); } public interface IDateToOrdinalWordConverter { string Convert(System.DateTime date); string Convert(System.DateTime date, Humanizer.GrammaticalCase grammaticalCase); } public interface IFormatter { string DataUnitHumanize(Humanizer.DataUnit dataUnit, double count, bool toSymbol = true); string DateHumanize(Humanizer.TimeUnit timeUnit, Humanizer.Tense timeUnitTense, int unit); string DateHumanize_Never(); string DateHumanize_Now(); string TimeSpanHumanize(Humanizer.TimeUnit timeUnit, int unit, bool toWords = false); string TimeSpanHumanize_Age(); string TimeSpanHumanize_Zero(); string TimeUnitHumanize(Humanizer.TimeUnit timeUnit); } public interface INumberToWordsConverter { string Convert(long number); string Convert(long number, Humanizer.WordForm wordForm); string Convert(long number, bool addAnd); string Convert(long number, Humanizer.GrammaticalGender gender, bool addAnd = true); string Convert(long number, bool addAnd, Humanizer.WordForm wordForm); string Convert(long number, Humanizer.WordForm wordForm, Humanizer.GrammaticalGender gender, bool addAnd = true); string ConvertToOrdinal(int number); string ConvertToOrdinal(int number, Humanizer.GrammaticalGender gender); string ConvertToOrdinal(int number, Humanizer.WordForm wordForm); string ConvertToOrdinal(int number, Humanizer.GrammaticalGender gender, Humanizer.WordForm wordForm); string ConvertToTuple(int number); } public interface IOrdinalizer { string Convert(int number, string numberString); string Convert(int number, string numberString, Humanizer.GrammaticalGender gender); string Convert(int number, string numberString, Humanizer.WordForm wordForm); string Convert(int number, string numberString, Humanizer.GrammaticalGender gender, Humanizer.WordForm wordForm); } public interface IStringTransformer { string Transform(string input); } public interface ITimeOnlyHumanizeStrategy { string Humanize(System.TimeOnly input, System.TimeOnly comparisonBase, System.Globalization.CultureInfo? culture); } public interface ITimeOnlyToClockNotationConverter { string Convert(System.TimeOnly time, Humanizer.ClockNotationRounding roundToNearestFive); } public interface ITruncator { [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("value")] string? Truncate(string? value, int length, string? truncationString, Humanizer.TruncateFrom truncateFrom = 1); } public interface IWordsToNumberConverter { int Convert(string words); bool TryConvert(string words, out int parsedValue); bool TryConvert(string words, out int parsedValue, out string? unrecognizedNumber); } public class In { public In() { } public static System.DateTime April { get; } public static System.DateTime August { get; } public static System.DateTime December { get; } public static System.DateTime February { get; } public static System.DateTime January { get; } public static System.DateTime July { get; } public static System.DateTime June { get; } public static System.DateTime March { get; } public static System.DateTime May { get; } public static System.DateTime November { get; } public static System.DateTime October { get; } public static System.DateTime September { get; } public static System.DateTime AprilOf(int year) { } public static System.DateTime AugustOf(int year) { } public static System.DateTime DecemberOf(int year) { } public static System.DateTime FebruaryOf(int year) { } public static System.DateTime JanuaryOf(int year) { } public static System.DateTime JulyOf(int year) { } public static System.DateTime JuneOf(int year) { } public static System.DateTime MarchOf(int year) { } public static System.DateTime MayOf(int year) { } public static System.DateTime NovemberOf(int year) { } public static System.DateTime OctoberOf(int year) { } public static System.DateTime SeptemberOf(int year) { } public static System.DateTime TheYear(int year) { } public static class Eight { public static System.DateTime Days { get; } public static System.DateTime Hours { get; } public static System.DateTime Minutes { get; } public static System.DateTime Months { get; } public static System.DateTime Seconds { get; } public static System.DateTime Weeks { get; } public static System.DateTime Years { get; } public static System.DateTime DaysFrom(System.DateTime date) { } public static System.DateTime HoursFrom(System.DateTime date) { } public static System.DateTime MinutesFrom(System.DateTime date) { } public static System.DateTime MonthsFrom(System.DateTime date) { } public static System.DateTime SecondsFrom(System.DateTime date) { } public static System.DateTime WeeksFrom(System.DateTime date) { } public static System.DateTime YearsFrom(System.DateTime date) { } } public static class Five { public static System.DateTime Days { get; } public static System.DateTime Hours { get; } public static System.DateTime Minutes { get; } public static System.DateTime Months { get; } public static System.DateTime Seconds { get; } public static System.DateTime Weeks { get; } public static System.DateTime Years { get; } public static System.DateTime DaysFrom(System.DateTime date) { } public static System.DateTime HoursFrom(System.DateTime date) { } public static System.DateTime MinutesFrom(System.DateTime date) { } public static System.DateTime MonthsFrom(System.DateTime date) { } public static System.DateTime SecondsFrom(System.DateTime date) { } public static System.DateTime WeeksFrom(System.DateTime date) { } public static System.DateTime YearsFrom(System.DateTime date) { } } public static class Four { public static System.DateTime Days { get; } public static System.DateTime Hours { get; } public static System.DateTime Minutes { get; } public static System.DateTime Months { get; } public static System.DateTime Seconds { get; } public static System.DateTime Weeks { get; } public static System.DateTime Years { get; } public static System.DateTime DaysFrom(System.DateTime date) { } public static System.DateTime HoursFrom(System.DateTime date) { } public static System.DateTime MinutesFrom(System.DateTime date) { } public static System.DateTime MonthsFrom(System.DateTime date) { } public static System.DateTime SecondsFrom(System.DateTime date) { } public static System.DateTime WeeksFrom(System.DateTime date) { } public static System.DateTime YearsFrom(System.DateTime date) { } } public static class Nine { public static System.DateTime Days { get; } public static System.DateTime Hours { get; } public static System.DateTime Minutes { get; } public static System.DateTime Months { get; } public static System.DateTime Seconds { get; } public static System.DateTime Weeks { get; } public static System.DateTime Years { get; } public static System.DateTime DaysFrom(System.DateTime date) { } public static System.DateTime HoursFrom(System.DateTime date) { } public static System.DateTime MinutesFrom(System.DateTime date) { } public static System.DateTime MonthsFrom(System.DateTime date) { } public static System.DateTime SecondsFrom(System.DateTime date) { } public static System.DateTime WeeksFrom(System.DateTime date) { } public static System.DateTime YearsFrom(System.DateTime date) { } } public static class One { public static System.DateTime Day { get; } public static System.DateTime Hour { get; } public static System.DateTime Minute { get; } public static System.DateTime Month { get; } public static System.DateTime Second { get; } public static System.DateTime Week { get; } public static System.DateTime Year { get; } public static System.DateTime DayFrom(System.DateTime date) { } public static System.DateTime HourFrom(System.DateTime date) { } public static System.DateTime MinuteFrom(System.DateTime date) { } public static System.DateTime MonthFrom(System.DateTime date) { } public static System.DateTime SecondFrom(System.DateTime date) { } public static System.DateTime WeekFrom(System.DateTime date) { } public static System.DateTime YearFrom(System.DateTime date) { } } public static class Seven { public static System.DateTime Days { get; } public static System.DateTime Hours { get; } public static System.DateTime Minutes { get; } public static System.DateTime Months { get; } public static System.DateTime Seconds { get; } public static System.DateTime Weeks { get; } public static System.DateTime Years { get; } public static System.DateTime DaysFrom(System.DateTime date) { } public static System.DateTime HoursFrom(System.DateTime date) { } public static System.DateTime MinutesFrom(System.DateTime date) { } public static System.DateTime MonthsFrom(System.DateTime date) { } public static System.DateTime SecondsFrom(System.DateTime date) { } public static System.DateTime WeeksFrom(System.DateTime date) { } public static System.DateTime YearsFrom(System.DateTime date) { } } public static class Six { public static System.DateTime Days { get; } public static System.DateTime Hours { get; } public static System.DateTime Minutes { get; } public static System.DateTime Months { get; } public static System.DateTime Seconds { get; } public static System.DateTime Weeks { get; } public static System.DateTime Years { get; } public static System.DateTime DaysFrom(System.DateTime date) { } public static System.DateTime HoursFrom(System.DateTime date) { } public static System.DateTime MinutesFrom(System.DateTime date) { } public static System.DateTime MonthsFrom(System.DateTime date) { } public static System.DateTime SecondsFrom(System.DateTime date) { } public static System.DateTime WeeksFrom(System.DateTime date) { } public static System.DateTime YearsFrom(System.DateTime date) { } } public static class Ten { public static System.DateTime Days { get; } public static System.DateTime Hours { get; } public static System.DateTime Minutes { get; } public static System.DateTime Months { get; } public static System.DateTime Seconds { get; } public static System.DateTime Weeks { get; } public static System.DateTime Years { get; } public static System.DateTime DaysFrom(System.DateTime date) { } public static System.DateTime HoursFrom(System.DateTime date) { } public static System.DateTime MinutesFrom(System.DateTime date) { } public static System.DateTime MonthsFrom(System.DateTime date) { } public static System.DateTime SecondsFrom(System.DateTime date) { } public static System.DateTime WeeksFrom(System.DateTime date) { } public static System.DateTime YearsFrom(System.DateTime date) { } } public static class Three { public static System.DateTime Days { get; } public static System.DateTime Hours { get; } public static System.DateTime Minutes { get; } public static System.DateTime Months { get; } public static System.DateTime Seconds { get; } public static System.DateTime Weeks { get; } public static System.DateTime Years { get; } public static System.DateTime DaysFrom(System.DateTime date) { } public static System.DateTime HoursFrom(System.DateTime date) { } public static System.DateTime MinutesFrom(System.DateTime date) { } public static System.DateTime MonthsFrom(System.DateTime date) { } public static System.DateTime SecondsFrom(System.DateTime date) { } public static System.DateTime WeeksFrom(System.DateTime date) { } public static System.DateTime YearsFrom(System.DateTime date) { } } public static class Two { public static System.DateTime Days { get; } public static System.DateTime Hours { get; } public static System.DateTime Minutes { get; } public static System.DateTime Months { get; } public static System.DateTime Seconds { get; } public static System.DateTime Weeks { get; } public static System.DateTime Years { get; } public static System.DateTime DaysFrom(System.DateTime date) { } public static System.DateTime HoursFrom(System.DateTime date) { } public static System.DateTime MinutesFrom(System.DateTime date) { } public static System.DateTime MonthsFrom(System.DateTime date) { } public static System.DateTime SecondsFrom(System.DateTime date) { } public static System.DateTime WeeksFrom(System.DateTime date) { } public static System.DateTime YearsFrom(System.DateTime date) { } } } public class InDate { public InDate() { } public static System.DateOnly April { get; } public static System.DateOnly August { get; } public static System.DateOnly December { get; } public static System.DateOnly February { get; } public static System.DateOnly January { get; } public static System.DateOnly July { get; } public static System.DateOnly June { get; } public static System.DateOnly March { get; } public static System.DateOnly May { get; } public static System.DateOnly November { get; } public static System.DateOnly October { get; } public static System.DateOnly September { get; } public static System.DateOnly AprilOf(int year) { } public static System.DateOnly AugustOf(int year) { } public static System.DateOnly DecemberOf(int year) { } public static System.DateOnly FebruaryOf(int year) { } public static System.DateOnly JanuaryOf(int year) { } public static System.DateOnly JulyOf(int year) { } public static System.DateOnly JuneOf(int year) { } public static System.DateOnly MarchOf(int year) { } public static System.DateOnly MayOf(int year) { } public static System.DateOnly NovemberOf(int year) { } public static System.DateOnly OctoberOf(int year) { } public static System.DateOnly SeptemberOf(int year) { } public static System.DateOnly TheYear(int year) { } public static class Eight { public static System.DateOnly Days { get; } public static System.DateOnly Months { get; } public static System.DateOnly Weeks { get; } public static System.DateOnly Years { get; } public static System.DateOnly DaysFrom(System.DateOnly date) { } public static System.DateOnly DaysFrom(System.DateTime date) { } public static System.DateOnly MonthsFrom(System.DateOnly date) { } public static System.DateOnly MonthsFrom(System.DateTime date) { } public static System.DateOnly WeeksFrom(System.DateOnly date) { } public static System.DateOnly WeeksFrom(System.DateTime date) { } public static System.DateOnly YearsFrom(System.DateOnly date) { } public static System.DateOnly YearsFrom(System.DateTime date) { } } public static class Five { public static System.DateOnly Days { get; } public static System.DateOnly Months { get; } public static System.DateOnly Weeks { get; } public static System.DateOnly Years { get; } public static System.DateOnly DaysFrom(System.DateOnly date) { } public static System.DateOnly DaysFrom(System.DateTime date) { } public static System.DateOnly MonthsFrom(System.DateOnly date) { } public static System.DateOnly MonthsFrom(System.DateTime date) { } public static System.DateOnly WeeksFrom(System.DateOnly date) { } public static System.DateOnly WeeksFrom(System.DateTime date) { } public static System.DateOnly YearsFrom(System.DateOnly date) { } public static System.DateOnly YearsFrom(System.DateTime date) { } } public static class Four { public static System.DateOnly Days { get; } public static System.DateOnly Months { get; } public static System.DateOnly Weeks { get; } public static System.DateOnly Years { get; } public static System.DateOnly DaysFrom(System.DateOnly date) { } public static System.DateOnly DaysFrom(System.DateTime date) { } public static System.DateOnly MonthsFrom(System.DateOnly date) { } public static System.DateOnly MonthsFrom(System.DateTime date) { } public static System.DateOnly WeeksFrom(System.DateOnly date) { } public static System.DateOnly WeeksFrom(System.DateTime date) { } public static System.DateOnly YearsFrom(System.DateOnly date) { } public static System.DateOnly YearsFrom(System.DateTime date) { } } public static class Nine { public static System.DateOnly Days { get; } public static System.DateOnly Months { get; } public static System.DateOnly Weeks { get; } public static System.DateOnly Years { get; } public static System.DateOnly DaysFrom(System.DateOnly date) { } public static System.DateOnly DaysFrom(System.DateTime date) { } public static System.DateOnly MonthsFrom(System.DateOnly date) { } public static System.DateOnly MonthsFrom(System.DateTime date) { } public static System.DateOnly WeeksFrom(System.DateOnly date) { } public static System.DateOnly WeeksFrom(System.DateTime date) { } public static System.DateOnly YearsFrom(System.DateOnly date) { } public static System.DateOnly YearsFrom(System.DateTime date) { } } public static class One { public static System.DateOnly Day { get; } public static System.DateOnly Month { get; } public static System.DateOnly Week { get; } public static System.DateOnly Year { get; } public static System.DateOnly DayFrom(System.DateOnly date) { } public static System.DateOnly DayFrom(System.DateTime date) { } public static System.DateOnly MonthFrom(System.DateOnly date) { } public static System.DateOnly MonthFrom(System.DateTime date) { } public static System.DateOnly WeekFrom(System.DateOnly date) { } public static System.DateOnly WeekFrom(System.DateTime date) { } public static System.DateOnly YearFrom(System.DateOnly date) { } public static System.DateOnly YearFrom(System.DateTime date) { } } public static class Seven { public static System.DateOnly Days { get; } public static System.DateOnly Months { get; } public static System.DateOnly Weeks { get; } public static System.DateOnly Years { get; } public static System.DateOnly DaysFrom(System.DateOnly date) { } public static System.DateOnly DaysFrom(System.DateTime date) { } public static System.DateOnly MonthsFrom(System.DateOnly date) { } public static System.DateOnly MonthsFrom(System.DateTime date) { } public static System.DateOnly WeeksFrom(System.DateOnly date) { } public static System.DateOnly WeeksFrom(System.DateTime date) { } public static System.DateOnly YearsFrom(System.DateOnly date) { } public static System.DateOnly YearsFrom(System.DateTime date) { } } public static class Six { public static System.DateOnly Days { get; } public static System.DateOnly Months { get; } public static System.DateOnly Weeks { get; } public static System.DateOnly Years { get; } public static System.DateOnly DaysFrom(System.DateOnly date) { } public static System.DateOnly DaysFrom(System.DateTime date) { } public static System.DateOnly MonthsFrom(System.DateOnly date) { } public static System.DateOnly MonthsFrom(System.DateTime date) { } public static System.DateOnly WeeksFrom(System.DateOnly date) { } public static System.DateOnly WeeksFrom(System.DateTime date) { } public static System.DateOnly YearsFrom(System.DateOnly date) { } public static System.DateOnly YearsFrom(System.DateTime date) { } } public static class Ten { public static System.DateOnly Days { get; } public static System.DateOnly Months { get; } public static System.DateOnly Weeks { get; } public static System.DateOnly Years { get; } public static System.DateOnly DaysFrom(System.DateOnly date) { } public static System.DateOnly DaysFrom(System.DateTime date) { } public static System.DateOnly MonthsFrom(System.DateOnly date) { } public static System.DateOnly MonthsFrom(System.DateTime date) { } public static System.DateOnly WeeksFrom(System.DateOnly date) { } public static System.DateOnly WeeksFrom(System.DateTime date) { } public static System.DateOnly YearsFrom(System.DateOnly date) { } public static System.DateOnly YearsFrom(System.DateTime date) { } } public static class Three { public static System.DateOnly Days { get; } public static System.DateOnly Months { get; } public static System.DateOnly Weeks { get; } public static System.DateOnly Years { get; } public static System.DateOnly DaysFrom(System.DateOnly date) { } public static System.DateOnly DaysFrom(System.DateTime date) { } public static System.DateOnly MonthsFrom(System.DateOnly date) { } public static System.DateOnly MonthsFrom(System.DateTime date) { } public static System.DateOnly WeeksFrom(System.DateOnly date) { } public static System.DateOnly WeeksFrom(System.DateTime date) { } public static System.DateOnly YearsFrom(System.DateOnly date) { } public static System.DateOnly YearsFrom(System.DateTime date) { } } public static class Two { public static System.DateOnly Days { get; } public static System.DateOnly Months { get; } public static System.DateOnly Weeks { get; } public static System.DateOnly Years { get; } public static System.DateOnly DaysFrom(System.DateOnly date) { } public static System.DateOnly DaysFrom(System.DateTime date) { } public static System.DateOnly MonthsFrom(System.DateOnly date) { } public static System.DateOnly MonthsFrom(System.DateTime date) { } public static System.DateOnly WeeksFrom(System.DateOnly date) { } public static System.DateOnly WeeksFrom(System.DateTime date) { } public static System.DateOnly YearsFrom(System.DateOnly date) { } public static System.DateOnly YearsFrom(System.DateTime date) { } } } public static class InflectorExtensions { public static string Camelize(this string input) { } public static string Dasherize(this string underscoredWord) { } public static string Hyphenate(this string underscoredWord) { } public static string Kebaberize(this string input) { } public static string Pascalize(this string input) { } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("word")] public static string? Pluralize(this string? word, bool inputIsKnownToBeSingular = true) { } public static string Singularize(this string word, bool inputIsKnownToBePlural = true, bool skipSimpleWords = false) { } public static string Titleize(this string input) { } public static string Underscore(this string input) { } } public enum LetterCasing { Title = 0, AllCaps = 1, LowerCase = 2, Sentence = 3, } public class LocaliserRegistry where TLocaliser : class { public LocaliserRegistry(System.Func defaultLocaliser) { } public LocaliserRegistry(TLocaliser defaultLocaliser) { } public void Register(string localeCode, System.Func localiser) { } public void Register(string localeCode, TLocaliser localiser) { } public TLocaliser ResolveForCulture(System.Globalization.CultureInfo? culture) { } public TLocaliser ResolveForUiCulture() { } } public static class MetricNumeralExtensions { public static double FromMetric(this string input) { } public static string ToMetric(this double input, Humanizer.MetricNumeralFormats? formats = default, int? decimals = default) { } public static string ToMetric(this int input, Humanizer.MetricNumeralFormats? formats = default, int? decimals = default) { } public static string ToMetric(this long input, Humanizer.MetricNumeralFormats? formats = default, int? decimals = default) { } } [System.Flags] public enum MetricNumeralFormats { UseLongScaleWord = 1, UseName = 2, UseShortScaleWord = 4, WithSpace = 8, } public class NoMatchFoundException : System.Exception { public NoMatchFoundException() { } public NoMatchFoundException(string message) { } public NoMatchFoundException(string message, System.Exception inner) { } } public static class NumberToNumberExtensions { public static double Billions(this double input) { } public static int Billions(this int input) { } public static long Billions(this long input) { } public static uint Billions(this uint input) { } public static ulong Billions(this ulong input) { } public static double Hundreds(this double input) { } public static int Hundreds(this int input) { } public static long Hundreds(this long input) { } public static uint Hundreds(this uint input) { } public static ulong Hundreds(this ulong input) { } public static double Millions(this double input) { } public static int Millions(this int input) { } public static long Millions(this long input) { } public static uint Millions(this uint input) { } public static ulong Millions(this ulong input) { } public static double Tens(this double input) { } public static int Tens(this int input) { } public static long Tens(this long input) { } public static uint Tens(this uint input) { } public static ulong Tens(this ulong input) { } public static double Thousands(this double input) { } public static int Thousands(this int input) { } public static long Thousands(this long input) { } public static uint Thousands(this uint input) { } public static ulong Thousands(this ulong input) { } } public static class NumberToTimeSpanExtensions { public static System.TimeSpan Days(this byte days) { } public static System.TimeSpan Days(this double days) { } public static System.TimeSpan Days(this int days) { } public static System.TimeSpan Days(this long days) { } public static System.TimeSpan Days(this sbyte days) { } public static System.TimeSpan Days(this short days) { } public static System.TimeSpan Days(this uint days) { } public static System.TimeSpan Days(this ulong days) { } public static System.TimeSpan Days(this ushort days) { } public static System.TimeSpan Hours(this byte hours) { } public static System.TimeSpan Hours(this double hours) { } public static System.TimeSpan Hours(this int hours) { } public static System.TimeSpan Hours(this long hours) { } public static System.TimeSpan Hours(this sbyte hours) { } public static System.TimeSpan Hours(this short hours) { } public static System.TimeSpan Hours(this uint hours) { } public static System.TimeSpan Hours(this ulong hours) { } public static System.TimeSpan Hours(this ushort hours) { } public static System.TimeSpan Milliseconds(this byte ms) { } public static System.TimeSpan Milliseconds(this double ms) { } public static System.TimeSpan Milliseconds(this int ms) { } public static System.TimeSpan Milliseconds(this long ms) { } public static System.TimeSpan Milliseconds(this sbyte ms) { } public static System.TimeSpan Milliseconds(this short ms) { } public static System.TimeSpan Milliseconds(this uint ms) { } public static System.TimeSpan Milliseconds(this ulong ms) { } public static System.TimeSpan Milliseconds(this ushort ms) { } public static System.TimeSpan Minutes(this byte minutes) { } public static System.TimeSpan Minutes(this double minutes) { } public static System.TimeSpan Minutes(this int minutes) { } public static System.TimeSpan Minutes(this long minutes) { } public static System.TimeSpan Minutes(this sbyte minutes) { } public static System.TimeSpan Minutes(this short minutes) { } public static System.TimeSpan Minutes(this uint minutes) { } public static System.TimeSpan Minutes(this ulong minutes) { } public static System.TimeSpan Minutes(this ushort minutes) { } public static System.TimeSpan Seconds(this byte seconds) { } public static System.TimeSpan Seconds(this double seconds) { } public static System.TimeSpan Seconds(this int seconds) { } public static System.TimeSpan Seconds(this long seconds) { } public static System.TimeSpan Seconds(this sbyte seconds) { } public static System.TimeSpan Seconds(this short seconds) { } public static System.TimeSpan Seconds(this uint seconds) { } public static System.TimeSpan Seconds(this ulong seconds) { } public static System.TimeSpan Seconds(this ushort seconds) { } public static System.TimeSpan Weeks(this byte input) { } public static System.TimeSpan Weeks(this double input) { } public static System.TimeSpan Weeks(this int input) { } public static System.TimeSpan Weeks(this long input) { } public static System.TimeSpan Weeks(this sbyte input) { } public static System.TimeSpan Weeks(this short input) { } public static System.TimeSpan Weeks(this uint input) { } public static System.TimeSpan Weeks(this ulong input) { } public static System.TimeSpan Weeks(this ushort input) { } } public static class NumberToWordsExtension { public static string ToOrdinalWords(this int number, System.Globalization.CultureInfo? culture = null) { } public static string ToOrdinalWords(this int number, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo? culture = null) { } public static string ToOrdinalWords(this int number, Humanizer.WordForm wordForm, System.Globalization.CultureInfo? culture = null) { } public static string ToOrdinalWords(this int number, Humanizer.GrammaticalGender gender, Humanizer.WordForm wordForm, System.Globalization.CultureInfo? culture = null) { } public static string ToTuple(this int number, System.Globalization.CultureInfo? culture = null) { } public static string ToWords(this int number, System.Globalization.CultureInfo? culture = null) { } public static string ToWords(this int number, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo? culture = null) { } public static string ToWords(this int number, Humanizer.WordForm wordForm, System.Globalization.CultureInfo? culture = null) { } public static string ToWords(this int number, bool addAnd, System.Globalization.CultureInfo? culture = null) { } public static string ToWords(this long number, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo? culture = null) { } public static string ToWords(this long number, System.Globalization.CultureInfo? culture = null, bool addAnd = true) { } public static string ToWords(this int number, Humanizer.WordForm wordForm, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo? culture = null) { } public static string ToWords(this int number, bool addAnd, Humanizer.WordForm wordForm, System.Globalization.CultureInfo? culture = null) { } public static string ToWords(this long number, Humanizer.WordForm wordForm, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo? culture = null) { } public static string ToWords(this long number, Humanizer.WordForm wordForm, System.Globalization.CultureInfo? culture = null, bool addAnd = false) { } } public class On { public On() { } public class April { public April() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class August { public August() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The31st { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class December { public December() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The31st { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class February { public February() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class January { public January() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The31st { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class July { public July() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The31st { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class June { public June() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class March { public March() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The31st { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class May { public May() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The31st { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class November { public November() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class October { public October() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The31st { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class September { public September() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } } public class OnDate { public OnDate() { } public class April { public April() { } public static System.DateOnly The10th { get; } public static System.DateOnly The11th { get; } public static System.DateOnly The12th { get; } public static System.DateOnly The13th { get; } public static System.DateOnly The14th { get; } public static System.DateOnly The15th { get; } public static System.DateOnly The16th { get; } public static System.DateOnly The17th { get; } public static System.DateOnly The18th { get; } public static System.DateOnly The19th { get; } public static System.DateOnly The1st { get; } public static System.DateOnly The20th { get; } public static System.DateOnly The21st { get; } public static System.DateOnly The22nd { get; } public static System.DateOnly The23rd { get; } public static System.DateOnly The24th { get; } public static System.DateOnly The25th { get; } public static System.DateOnly The26th { get; } public static System.DateOnly The27th { get; } public static System.DateOnly The28th { get; } public static System.DateOnly The29th { get; } public static System.DateOnly The2nd { get; } public static System.DateOnly The30th { get; } public static System.DateOnly The3rd { get; } public static System.DateOnly The4th { get; } public static System.DateOnly The5th { get; } public static System.DateOnly The6th { get; } public static System.DateOnly The7th { get; } public static System.DateOnly The8th { get; } public static System.DateOnly The9th { get; } public static System.DateOnly The(int dayNumber) { } } public class August { public August() { } public static System.DateOnly The10th { get; } public static System.DateOnly The11th { get; } public static System.DateOnly The12th { get; } public static System.DateOnly The13th { get; } public static System.DateOnly The14th { get; } public static System.DateOnly The15th { get; } public static System.DateOnly The16th { get; } public static System.DateOnly The17th { get; } public static System.DateOnly The18th { get; } public static System.DateOnly The19th { get; } public static System.DateOnly The1st { get; } public static System.DateOnly The20th { get; } public static System.DateOnly The21st { get; } public static System.DateOnly The22nd { get; } public static System.DateOnly The23rd { get; } public static System.DateOnly The24th { get; } public static System.DateOnly The25th { get; } public static System.DateOnly The26th { get; } public static System.DateOnly The27th { get; } public static System.DateOnly The28th { get; } public static System.DateOnly The29th { get; } public static System.DateOnly The2nd { get; } public static System.DateOnly The30th { get; } public static System.DateOnly The31st { get; } public static System.DateOnly The3rd { get; } public static System.DateOnly The4th { get; } public static System.DateOnly The5th { get; } public static System.DateOnly The6th { get; } public static System.DateOnly The7th { get; } public static System.DateOnly The8th { get; } public static System.DateOnly The9th { get; } public static System.DateOnly The(int dayNumber) { } } public class December { public December() { } public static System.DateOnly The10th { get; } public static System.DateOnly The11th { get; } public static System.DateOnly The12th { get; } public static System.DateOnly The13th { get; } public static System.DateOnly The14th { get; } public static System.DateOnly The15th { get; } public static System.DateOnly The16th { get; } public static System.DateOnly The17th { get; } public static System.DateOnly The18th { get; } public static System.DateOnly The19th { get; } public static System.DateOnly The1st { get; } public static System.DateOnly The20th { get; } public static System.DateOnly The21st { get; } public static System.DateOnly The22nd { get; } public static System.DateOnly The23rd { get; } public static System.DateOnly The24th { get; } public static System.DateOnly The25th { get; } public static System.DateOnly The26th { get; } public static System.DateOnly The27th { get; } public static System.DateOnly The28th { get; } public static System.DateOnly The29th { get; } public static System.DateOnly The2nd { get; } public static System.DateOnly The30th { get; } public static System.DateOnly The31st { get; } public static System.DateOnly The3rd { get; } public static System.DateOnly The4th { get; } public static System.DateOnly The5th { get; } public static System.DateOnly The6th { get; } public static System.DateOnly The7th { get; } public static System.DateOnly The8th { get; } public static System.DateOnly The9th { get; } public static System.DateOnly The(int dayNumber) { } } public class February { public February() { } public static System.DateOnly The10th { get; } public static System.DateOnly The11th { get; } public static System.DateOnly The12th { get; } public static System.DateOnly The13th { get; } public static System.DateOnly The14th { get; } public static System.DateOnly The15th { get; } public static System.DateOnly The16th { get; } public static System.DateOnly The17th { get; } public static System.DateOnly The18th { get; } public static System.DateOnly The19th { get; } public static System.DateOnly The1st { get; } public static System.DateOnly The20th { get; } public static System.DateOnly The21st { get; } public static System.DateOnly The22nd { get; } public static System.DateOnly The23rd { get; } public static System.DateOnly The24th { get; } public static System.DateOnly The25th { get; } public static System.DateOnly The26th { get; } public static System.DateOnly The27th { get; } public static System.DateOnly The28th { get; } public static System.DateOnly The29th { get; } public static System.DateOnly The2nd { get; } public static System.DateOnly The3rd { get; } public static System.DateOnly The4th { get; } public static System.DateOnly The5th { get; } public static System.DateOnly The6th { get; } public static System.DateOnly The7th { get; } public static System.DateOnly The8th { get; } public static System.DateOnly The9th { get; } public static System.DateOnly The(int dayNumber) { } } public class January { public January() { } public static System.DateOnly The10th { get; } public static System.DateOnly The11th { get; } public static System.DateOnly The12th { get; } public static System.DateOnly The13th { get; } public static System.DateOnly The14th { get; } public static System.DateOnly The15th { get; } public static System.DateOnly The16th { get; } public static System.DateOnly The17th { get; } public static System.DateOnly The18th { get; } public static System.DateOnly The19th { get; } public static System.DateOnly The1st { get; } public static System.DateOnly The20th { get; } public static System.DateOnly The21st { get; } public static System.DateOnly The22nd { get; } public static System.DateOnly The23rd { get; } public static System.DateOnly The24th { get; } public static System.DateOnly The25th { get; } public static System.DateOnly The26th { get; } public static System.DateOnly The27th { get; } public static System.DateOnly The28th { get; } public static System.DateOnly The29th { get; } public static System.DateOnly The2nd { get; } public static System.DateOnly The30th { get; } public static System.DateOnly The31st { get; } public static System.DateOnly The3rd { get; } public static System.DateOnly The4th { get; } public static System.DateOnly The5th { get; } public static System.DateOnly The6th { get; } public static System.DateOnly The7th { get; } public static System.DateOnly The8th { get; } public static System.DateOnly The9th { get; } public static System.DateOnly The(int dayNumber) { } } public class July { public July() { } public static System.DateOnly The10th { get; } public static System.DateOnly The11th { get; } public static System.DateOnly The12th { get; } public static System.DateOnly The13th { get; } public static System.DateOnly The14th { get; } public static System.DateOnly The15th { get; } public static System.DateOnly The16th { get; } public static System.DateOnly The17th { get; } public static System.DateOnly The18th { get; } public static System.DateOnly The19th { get; } public static System.DateOnly The1st { get; } public static System.DateOnly The20th { get; } public static System.DateOnly The21st { get; } public static System.DateOnly The22nd { get; } public static System.DateOnly The23rd { get; } public static System.DateOnly The24th { get; } public static System.DateOnly The25th { get; } public static System.DateOnly The26th { get; } public static System.DateOnly The27th { get; } public static System.DateOnly The28th { get; } public static System.DateOnly The29th { get; } public static System.DateOnly The2nd { get; } public static System.DateOnly The30th { get; } public static System.DateOnly The31st { get; } public static System.DateOnly The3rd { get; } public static System.DateOnly The4th { get; } public static System.DateOnly The5th { get; } public static System.DateOnly The6th { get; } public static System.DateOnly The7th { get; } public static System.DateOnly The8th { get; } public static System.DateOnly The9th { get; } public static System.DateOnly The(int dayNumber) { } } public class June { public June() { } public static System.DateOnly The10th { get; } public static System.DateOnly The11th { get; } public static System.DateOnly The12th { get; } public static System.DateOnly The13th { get; } public static System.DateOnly The14th { get; } public static System.DateOnly The15th { get; } public static System.DateOnly The16th { get; } public static System.DateOnly The17th { get; } public static System.DateOnly The18th { get; } public static System.DateOnly The19th { get; } public static System.DateOnly The1st { get; } public static System.DateOnly The20th { get; } public static System.DateOnly The21st { get; } public static System.DateOnly The22nd { get; } public static System.DateOnly The23rd { get; } public static System.DateOnly The24th { get; } public static System.DateOnly The25th { get; } public static System.DateOnly The26th { get; } public static System.DateOnly The27th { get; } public static System.DateOnly The28th { get; } public static System.DateOnly The29th { get; } public static System.DateOnly The2nd { get; } public static System.DateOnly The30th { get; } public static System.DateOnly The3rd { get; } public static System.DateOnly The4th { get; } public static System.DateOnly The5th { get; } public static System.DateOnly The6th { get; } public static System.DateOnly The7th { get; } public static System.DateOnly The8th { get; } public static System.DateOnly The9th { get; } public static System.DateOnly The(int dayNumber) { } } public class March { public March() { } public static System.DateOnly The10th { get; } public static System.DateOnly The11th { get; } public static System.DateOnly The12th { get; } public static System.DateOnly The13th { get; } public static System.DateOnly The14th { get; } public static System.DateOnly The15th { get; } public static System.DateOnly The16th { get; } public static System.DateOnly The17th { get; } public static System.DateOnly The18th { get; } public static System.DateOnly The19th { get; } public static System.DateOnly The1st { get; } public static System.DateOnly The20th { get; } public static System.DateOnly The21st { get; } public static System.DateOnly The22nd { get; } public static System.DateOnly The23rd { get; } public static System.DateOnly The24th { get; } public static System.DateOnly The25th { get; } public static System.DateOnly The26th { get; } public static System.DateOnly The27th { get; } public static System.DateOnly The28th { get; } public static System.DateOnly The29th { get; } public static System.DateOnly The2nd { get; } public static System.DateOnly The30th { get; } public static System.DateOnly The31st { get; } public static System.DateOnly The3rd { get; } public static System.DateOnly The4th { get; } public static System.DateOnly The5th { get; } public static System.DateOnly The6th { get; } public static System.DateOnly The7th { get; } public static System.DateOnly The8th { get; } public static System.DateOnly The9th { get; } public static System.DateOnly The(int dayNumber) { } } public class May { public May() { } public static System.DateOnly The10th { get; } public static System.DateOnly The11th { get; } public static System.DateOnly The12th { get; } public static System.DateOnly The13th { get; } public static System.DateOnly The14th { get; } public static System.DateOnly The15th { get; } public static System.DateOnly The16th { get; } public static System.DateOnly The17th { get; } public static System.DateOnly The18th { get; } public static System.DateOnly The19th { get; } public static System.DateOnly The1st { get; } public static System.DateOnly The20th { get; } public static System.DateOnly The21st { get; } public static System.DateOnly The22nd { get; } public static System.DateOnly The23rd { get; } public static System.DateOnly The24th { get; } public static System.DateOnly The25th { get; } public static System.DateOnly The26th { get; } public static System.DateOnly The27th { get; } public static System.DateOnly The28th { get; } public static System.DateOnly The29th { get; } public static System.DateOnly The2nd { get; } public static System.DateOnly The30th { get; } public static System.DateOnly The31st { get; } public static System.DateOnly The3rd { get; } public static System.DateOnly The4th { get; } public static System.DateOnly The5th { get; } public static System.DateOnly The6th { get; } public static System.DateOnly The7th { get; } public static System.DateOnly The8th { get; } public static System.DateOnly The9th { get; } public static System.DateOnly The(int dayNumber) { } } public class November { public November() { } public static System.DateOnly The10th { get; } public static System.DateOnly The11th { get; } public static System.DateOnly The12th { get; } public static System.DateOnly The13th { get; } public static System.DateOnly The14th { get; } public static System.DateOnly The15th { get; } public static System.DateOnly The16th { get; } public static System.DateOnly The17th { get; } public static System.DateOnly The18th { get; } public static System.DateOnly The19th { get; } public static System.DateOnly The1st { get; } public static System.DateOnly The20th { get; } public static System.DateOnly The21st { get; } public static System.DateOnly The22nd { get; } public static System.DateOnly The23rd { get; } public static System.DateOnly The24th { get; } public static System.DateOnly The25th { get; } public static System.DateOnly The26th { get; } public static System.DateOnly The27th { get; } public static System.DateOnly The28th { get; } public static System.DateOnly The29th { get; } public static System.DateOnly The2nd { get; } public static System.DateOnly The30th { get; } public static System.DateOnly The3rd { get; } public static System.DateOnly The4th { get; } public static System.DateOnly The5th { get; } public static System.DateOnly The6th { get; } public static System.DateOnly The7th { get; } public static System.DateOnly The8th { get; } public static System.DateOnly The9th { get; } public static System.DateOnly The(int dayNumber) { } } public class October { public October() { } public static System.DateOnly The10th { get; } public static System.DateOnly The11th { get; } public static System.DateOnly The12th { get; } public static System.DateOnly The13th { get; } public static System.DateOnly The14th { get; } public static System.DateOnly The15th { get; } public static System.DateOnly The16th { get; } public static System.DateOnly The17th { get; } public static System.DateOnly The18th { get; } public static System.DateOnly The19th { get; } public static System.DateOnly The1st { get; } public static System.DateOnly The20th { get; } public static System.DateOnly The21st { get; } public static System.DateOnly The22nd { get; } public static System.DateOnly The23rd { get; } public static System.DateOnly The24th { get; } public static System.DateOnly The25th { get; } public static System.DateOnly The26th { get; } public static System.DateOnly The27th { get; } public static System.DateOnly The28th { get; } public static System.DateOnly The29th { get; } public static System.DateOnly The2nd { get; } public static System.DateOnly The30th { get; } public static System.DateOnly The31st { get; } public static System.DateOnly The3rd { get; } public static System.DateOnly The4th { get; } public static System.DateOnly The5th { get; } public static System.DateOnly The6th { get; } public static System.DateOnly The7th { get; } public static System.DateOnly The8th { get; } public static System.DateOnly The9th { get; } public static System.DateOnly The(int dayNumber) { } } public class September { public September() { } public static System.DateOnly The10th { get; } public static System.DateOnly The11th { get; } public static System.DateOnly The12th { get; } public static System.DateOnly The13th { get; } public static System.DateOnly The14th { get; } public static System.DateOnly The15th { get; } public static System.DateOnly The16th { get; } public static System.DateOnly The17th { get; } public static System.DateOnly The18th { get; } public static System.DateOnly The19th { get; } public static System.DateOnly The1st { get; } public static System.DateOnly The20th { get; } public static System.DateOnly The21st { get; } public static System.DateOnly The22nd { get; } public static System.DateOnly The23rd { get; } public static System.DateOnly The24th { get; } public static System.DateOnly The25th { get; } public static System.DateOnly The26th { get; } public static System.DateOnly The27th { get; } public static System.DateOnly The28th { get; } public static System.DateOnly The29th { get; } public static System.DateOnly The2nd { get; } public static System.DateOnly The30th { get; } public static System.DateOnly The3rd { get; } public static System.DateOnly The4th { get; } public static System.DateOnly The5th { get; } public static System.DateOnly The6th { get; } public static System.DateOnly The7th { get; } public static System.DateOnly The8th { get; } public static System.DateOnly The9th { get; } public static System.DateOnly The(int dayNumber) { } } } public enum OnNoMatch { ThrowsException = 0, ReturnsNull = 1, } public static class OrdinalizeExtensions { public static string Ordinalize(this int number) { } public static string Ordinalize(this string numberString) { } public static string Ordinalize(this int number, Humanizer.GrammaticalGender gender) { } public static string Ordinalize(this int number, Humanizer.WordForm wordForm) { } public static string Ordinalize(this int number, System.Globalization.CultureInfo culture) { } public static string Ordinalize(this string numberString, Humanizer.GrammaticalGender gender) { } public static string Ordinalize(this string numberString, Humanizer.WordForm wordForm) { } public static string Ordinalize(this string numberString, System.Globalization.CultureInfo culture) { } public static string Ordinalize(this int number, Humanizer.GrammaticalGender gender, Humanizer.WordForm wordForm) { } public static string Ordinalize(this int number, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo culture) { } public static string Ordinalize(this int number, System.Globalization.CultureInfo culture, Humanizer.WordForm wordForm) { } public static string Ordinalize(this string numberString, Humanizer.GrammaticalGender gender, Humanizer.WordForm wordForm) { } public static string Ordinalize(this string numberString, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo culture) { } public static string Ordinalize(this string numberString, System.Globalization.CultureInfo culture, Humanizer.WordForm wordForm) { } public static string Ordinalize(this int number, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo culture, Humanizer.WordForm wordForm) { } public static string Ordinalize(this string numberString, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo culture, Humanizer.WordForm wordForm) { } } public enum Plurality { Singular = 0, Plural = 1, CouldBeEither = 2, } public class PrecisionDateOnlyHumanizeStrategy : Humanizer.IDateOnlyHumanizeStrategy { public PrecisionDateOnlyHumanizeStrategy(double precision = 0.75) { } public string Humanize(System.DateOnly input, System.DateOnly comparisonBase, System.Globalization.CultureInfo? culture) { } } public class PrecisionDateTimeHumanizeStrategy : Humanizer.IDateTimeHumanizeStrategy { public PrecisionDateTimeHumanizeStrategy(double precision = 0.75) { } public string Humanize(System.DateTime input, System.DateTime comparisonBase, System.Globalization.CultureInfo? culture) { } } public class PrecisionDateTimeOffsetHumanizeStrategy : Humanizer.IDateTimeOffsetHumanizeStrategy { public PrecisionDateTimeOffsetHumanizeStrategy(double precision = 0.75) { } public string Humanize(System.DateTimeOffset input, System.DateTimeOffset comparisonBase, System.Globalization.CultureInfo? culture) { } } public class PrecisionTimeOnlyHumanizeStrategy : Humanizer.ITimeOnlyHumanizeStrategy { public PrecisionTimeOnlyHumanizeStrategy(double precision = 0.75) { } public string Humanize(System.TimeOnly input, System.TimeOnly comparisonBase, System.Globalization.CultureInfo? culture) { } } public static class PrepositionsExtensions { public static System.DateTime At(this System.DateTime date, int hour, int min = 0, int second = 0, int millisecond = 0) { } public static System.DateTime AtMidnight(this System.DateTime date) { } public static System.DateTime AtNoon(this System.DateTime date) { } public static System.DateTime In(this System.DateTime date, int year) { } } public class ResourceKeys { public ResourceKeys() { } public static class DateHumanize { public const string Never = "DateHumanize_Never"; public const string Now = "DateHumanize_Now"; public static string GetResourceKey(Humanizer.TimeUnit timeUnit, Humanizer.Tense timeUnitTense, int count = 1) { } } public static class TimeSpanHumanize { public static string GetResourceKey(Humanizer.TimeUnit unit, int count = 1, bool toWords = false) { } } public static class TimeUnitSymbol { public static string GetResourceKey(Humanizer.TimeUnit unit) { } } } public static class Resources { public static string GetResource(string resourceKey, System.Globalization.CultureInfo? culture = null) { } public static bool TryGetResource(string resourceKey, System.Globalization.CultureInfo? culture, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out string? result) { } } public static class RomanNumeralExtensions { public static int FromRoman(System.ReadOnlySpan input) { } public static int FromRoman(this string input) { } public static string ToRoman(this int input) { } } public enum ShowQuantityAs { None = 0, Numeric = 1, Words = 2, } public static class StringDehumanizeExtensions { public static string Dehumanize(this string input) { } } public static class StringHumanizeExtensions { public static string Humanize(this string input) { } public static string Humanize(this string input, Humanizer.LetterCasing casing) { } } public enum Tense { Future = 0, Past = 1, } public static class TimeOnlyToClockNotationExtensions { public static string ToClockNotation(this System.TimeOnly input, Humanizer.ClockNotationRounding roundToNearestFive = 0) { } } public static class TimeSpanHumanizeExtensions { public static string Humanize(this System.TimeSpan timeSpan, int precision = 1, System.Globalization.CultureInfo? culture = null, Humanizer.TimeUnit maxUnit = 5, Humanizer.TimeUnit minUnit = 0, string? collectionSeparator = ", ", bool toWords = false) { } public static string Humanize(this System.TimeSpan timeSpan, int precision, bool countEmptyUnits, System.Globalization.CultureInfo? culture = null, Humanizer.TimeUnit maxUnit = 5, Humanizer.TimeUnit minUnit = 0, string? collectionSeparator = ", ", bool toWords = false) { } public static string ToAge(this System.TimeSpan timeSpan, System.Globalization.CultureInfo? culture = null, Humanizer.TimeUnit maxUnit = 7, bool toWords = false) { } } public enum TimeUnit { Millisecond = 0, Second = 1, Minute = 2, Hour = 3, Day = 4, Week = 5, Month = 6, Year = 7, } public static class TimeUnitToSymbolExtensions { public static string ToSymbol(this Humanizer.TimeUnit unit, System.Globalization.CultureInfo? culture = null) { } } public static class To { public static Humanizer.ICulturedStringTransformer LowerCase { get; } public static Humanizer.ICulturedStringTransformer SentenceCase { get; } public static Humanizer.ICulturedStringTransformer TitleCase { get; } public static Humanizer.ICulturedStringTransformer UpperCase { get; } public static string Transform(this string input, params Humanizer.IStringTransformer[] transformers) { } public static string Transform(this string input, System.Globalization.CultureInfo culture, params Humanizer.ICulturedStringTransformer[] transformers) { } } public static class ToQuantityExtensions { public static string ToQuantity(this string input, double quantity) { } public static string ToQuantity(this string input, int quantity, Humanizer.ShowQuantityAs showQuantityAs = 1) { } public static string ToQuantity(this string input, long quantity, Humanizer.ShowQuantityAs showQuantityAs = 1) { } public static string ToQuantity(this string input, double quantity, string? format = null, System.IFormatProvider? formatProvider = null) { } public static string ToQuantity(this string input, int quantity, string? format, System.IFormatProvider? formatProvider = null) { } public static string ToQuantity(this string input, long quantity, string? format, System.IFormatProvider? formatProvider = null) { } } public static class TruncateExtensions { [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("input")] public static string? Truncate(this string? input, int length) { } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("input")] public static string? Truncate(this string? input, int length, Humanizer.ITruncator truncator, Humanizer.TruncateFrom from = 1) { } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("input")] public static string? Truncate(this string? input, int length, string? truncationString, Humanizer.TruncateFrom from = 1) { } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("input")] public static string? Truncate(this string? input, int length, string? truncationString, Humanizer.ITruncator truncator, Humanizer.TruncateFrom from = 1) { } } public enum TruncateFrom { Left = 0, Right = 1, } public static class Truncator { public static Humanizer.ITruncator DynamicLengthAndPreserveWords { get; } public static Humanizer.ITruncator DynamicNumberOfCharactersAndPreserveWords { get; } public static Humanizer.ITruncator FixedLength { get; } public static Humanizer.ITruncator FixedNumberOfCharacters { get; } public static Humanizer.ITruncator FixedNumberOfWords { get; } } public static class TupleizeExtensions { public static string Tupleize(this int input) { } } public static class Vocabularies { public static Humanizer.Vocabulary Default { get; } } public class Vocabulary { public void AddIrregular(string singular, string plural, bool matchEnding = true) { } public void AddPlural(string rule, string replacement) { } public void AddSingular(string rule, string replacement) { } public void AddUncountable(string word) { } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("word")] public string? Pluralize(string? word, bool inputIsKnownToBeSingular = true) { } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("word")] public string? Singularize(string? word, bool inputIsKnownToBePlural = true, bool skipSimpleWords = false) { } } public enum WordForm { Normal = 0, Abbreviation = 1, Eifeler = 2, } public static class WordsToNumberExtension { public static int ToNumber(this string words, System.Globalization.CultureInfo culture) { } public static bool TryToNumber(this string words, out int parsedNumber, System.Globalization.CultureInfo culture) { } public static bool TryToNumber(this string words, out int parsedNumber, System.Globalization.CultureInfo culture, out string? unrecognizedWord) { } } } ================================================ FILE: tests/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.Approve_Public_Api.DotNet8_0.verified.txt ================================================ [assembly: System.Reflection.AssemblyMetadata("IsTrimmable", "True")] [assembly: System.Resources.NeutralResourcesLanguage("en")] [assembly: System.Runtime.Versioning.TargetFramework(".NETCoreApp,Version=v8.0", FrameworkDisplayName=".NET 8.0")] namespace Humanizer { public class ByteRate { public ByteRate(Humanizer.ByteSize size, System.TimeSpan interval) { } public System.TimeSpan Interval { get; } public Humanizer.ByteSize Size { get; } public string Humanize(Humanizer.TimeUnit timeUnit = 1) { } public string Humanize(string? format, Humanizer.TimeUnit timeUnit = 1, System.Globalization.CultureInfo? culture = null) { } } public struct ByteSize : System.IComparable, System.IComparable, System.IEquatable, System.IFormattable { public const string Bit = "bit"; public const string BitSymbol = "b"; public const long BitsInByte = 8; public const string Byte = "byte"; public const string ByteSymbol = "B"; public const long BytesInGigabyte = 1073741824; public const long BytesInKilobyte = 1024; public const long BytesInMegabyte = 1048576; public const long BytesInTerabyte = 1099511627776; public const string Gigabyte = "gigabyte"; public const string GigabyteSymbol = "GB"; public const string Kilobyte = "kilobyte"; public const string KilobyteSymbol = "KB"; public const string Megabyte = "megabyte"; public const string MegabyteSymbol = "MB"; public const string Terabyte = "terabyte"; public const string TerabyteSymbol = "TB"; public static readonly Humanizer.ByteSize MaxValue; public static readonly Humanizer.ByteSize MinValue; public ByteSize(double byteSize) { } public long Bits { get; } public double Bytes { get; } public double Gigabytes { get; } public double Kilobytes { get; } public string LargestWholeNumberFullWord { get; } public string LargestWholeNumberSymbol { get; } public double LargestWholeNumberValue { get; } public double Megabytes { get; } public double Terabytes { get; } public Humanizer.ByteSize Add(Humanizer.ByteSize bs) { } public Humanizer.ByteSize AddBits(long value) { } public Humanizer.ByteSize AddBytes(double value) { } public Humanizer.ByteSize AddGigabytes(double value) { } public Humanizer.ByteSize AddKilobytes(double value) { } public Humanizer.ByteSize AddMegabytes(double value) { } public Humanizer.ByteSize AddTerabytes(double value) { } public int CompareTo(Humanizer.ByteSize other) { } public int CompareTo(object? obj) { } public bool Equals(Humanizer.ByteSize value) { } public override bool Equals(object? value) { } public override int GetHashCode() { } public string GetLargestWholeNumberFullWord(System.IFormatProvider? provider = null) { } public string GetLargestWholeNumberSymbol(System.IFormatProvider? provider = null) { } public Humanizer.ByteSize Subtract(Humanizer.ByteSize bs) { } public string ToFullWords(string? format = null, System.IFormatProvider? provider = null) { } public override string ToString() { } public string ToString(System.IFormatProvider? provider) { } public string ToString(string? format) { } public string ToString(string? format, System.IFormatProvider? provider) { } public static Humanizer.ByteSize FromBits(long value) { } public static Humanizer.ByteSize FromBytes(double value) { } public static Humanizer.ByteSize FromGigabytes(double value) { } public static Humanizer.ByteSize FromKilobytes(double value) { } public static Humanizer.ByteSize FromMegabytes(double value) { } public static Humanizer.ByteSize FromTerabytes(double value) { } public static Humanizer.ByteSize Parse(string s) { } public static Humanizer.ByteSize Parse(string s, System.IFormatProvider? formatProvider) { } public static bool TryParse(System.ReadOnlySpan s, out Humanizer.ByteSize result) { } public static bool TryParse(string? s, out Humanizer.ByteSize result) { } public static bool TryParse(System.ReadOnlySpan s, System.IFormatProvider? formatProvider, out Humanizer.ByteSize result) { } public static bool TryParse(string? s, System.IFormatProvider? formatProvider, out Humanizer.ByteSize result) { } public static bool operator !=(Humanizer.ByteSize b1, Humanizer.ByteSize b2) { } public static Humanizer.ByteSize operator +(Humanizer.ByteSize b1, Humanizer.ByteSize b2) { } public static Humanizer.ByteSize operator ++(Humanizer.ByteSize b) { } public static Humanizer.ByteSize operator -(Humanizer.ByteSize b) { } public static Humanizer.ByteSize operator -(Humanizer.ByteSize b1, Humanizer.ByteSize b2) { } public static Humanizer.ByteSize operator --(Humanizer.ByteSize b) { } public static bool operator <(Humanizer.ByteSize b1, Humanizer.ByteSize b2) { } public static bool operator <=(Humanizer.ByteSize b1, Humanizer.ByteSize b2) { } public static bool operator ==(Humanizer.ByteSize b1, Humanizer.ByteSize b2) { } public static bool operator >(Humanizer.ByteSize b1, Humanizer.ByteSize b2) { } public static bool operator >=(Humanizer.ByteSize b1, Humanizer.ByteSize b2) { } } public static class ByteSizeExtensions { public static Humanizer.ByteSize Bits(this byte input) { } public static Humanizer.ByteSize Bits(this int input) { } public static Humanizer.ByteSize Bits(this long input) { } public static Humanizer.ByteSize Bits(this sbyte input) { } public static Humanizer.ByteSize Bits(this short input) { } public static Humanizer.ByteSize Bits(this uint input) { } public static Humanizer.ByteSize Bits(this ushort input) { } public static Humanizer.ByteSize Bytes(this byte input) { } public static Humanizer.ByteSize Bytes(this double input) { } public static Humanizer.ByteSize Bytes(this int input) { } public static Humanizer.ByteSize Bytes(this long input) { } public static Humanizer.ByteSize Bytes(this sbyte input) { } public static Humanizer.ByteSize Bytes(this short input) { } public static Humanizer.ByteSize Bytes(this uint input) { } public static Humanizer.ByteSize Bytes(this ushort input) { } public static Humanizer.ByteSize Gigabytes(this byte input) { } public static Humanizer.ByteSize Gigabytes(this double input) { } public static Humanizer.ByteSize Gigabytes(this int input) { } public static Humanizer.ByteSize Gigabytes(this long input) { } public static Humanizer.ByteSize Gigabytes(this sbyte input) { } public static Humanizer.ByteSize Gigabytes(this short input) { } public static Humanizer.ByteSize Gigabytes(this uint input) { } public static Humanizer.ByteSize Gigabytes(this ushort input) { } public static string Humanize(this Humanizer.ByteSize input, System.IFormatProvider formatProvider) { } public static string Humanize(this Humanizer.ByteSize input, string? format = null) { } public static string Humanize(this Humanizer.ByteSize input, string? format, System.IFormatProvider? formatProvider) { } public static Humanizer.ByteSize Kilobytes(this byte input) { } public static Humanizer.ByteSize Kilobytes(this double input) { } public static Humanizer.ByteSize Kilobytes(this int input) { } public static Humanizer.ByteSize Kilobytes(this long input) { } public static Humanizer.ByteSize Kilobytes(this sbyte input) { } public static Humanizer.ByteSize Kilobytes(this short input) { } public static Humanizer.ByteSize Kilobytes(this uint input) { } public static Humanizer.ByteSize Kilobytes(this ushort input) { } public static Humanizer.ByteSize Megabytes(this byte input) { } public static Humanizer.ByteSize Megabytes(this double input) { } public static Humanizer.ByteSize Megabytes(this int input) { } public static Humanizer.ByteSize Megabytes(this long input) { } public static Humanizer.ByteSize Megabytes(this sbyte input) { } public static Humanizer.ByteSize Megabytes(this short input) { } public static Humanizer.ByteSize Megabytes(this uint input) { } public static Humanizer.ByteSize Megabytes(this ushort input) { } public static Humanizer.ByteRate Per(this Humanizer.ByteSize size, System.TimeSpan interval) { } public static Humanizer.ByteSize Terabytes(this byte input) { } public static Humanizer.ByteSize Terabytes(this double input) { } public static Humanizer.ByteSize Terabytes(this int input) { } public static Humanizer.ByteSize Terabytes(this long input) { } public static Humanizer.ByteSize Terabytes(this sbyte input) { } public static Humanizer.ByteSize Terabytes(this short input) { } public static Humanizer.ByteSize Terabytes(this uint input) { } public static Humanizer.ByteSize Terabytes(this ushort input) { } } public static class CasingExtensions { public static string ApplyCase(this string input, Humanizer.LetterCasing casing) { } } public enum ClockNotationRounding { None = 0, NearestFiveMinutes = 1, } public static class CollectionHumanizeExtensions { public static string Humanize(this System.Collections.Generic.IEnumerable collection) { } public static string Humanize(this System.Collections.Generic.IEnumerable collection, System.Func displayFormatter) { } public static string Humanize(this System.Collections.Generic.IEnumerable collection, System.Func displayFormatter) { } public static string Humanize(this System.Collections.Generic.IEnumerable collection, string separator) { } public static string Humanize(this System.Collections.Generic.IEnumerable collection, System.Func displayFormatter, string separator) { } public static string Humanize(this System.Collections.Generic.IEnumerable collection, System.Func displayFormatter, string separator) { } } public static class Configurator { public static Humanizer.LocaliserRegistry CollectionFormatters { get; } public static Humanizer.IDateOnlyHumanizeStrategy DateOnlyHumanizeStrategy { get; set; } public static Humanizer.LocaliserRegistry DateOnlyToOrdinalWordsConverters { get; } public static Humanizer.IDateTimeHumanizeStrategy DateTimeHumanizeStrategy { get; set; } public static Humanizer.IDateTimeOffsetHumanizeStrategy DateTimeOffsetHumanizeStrategy { get; set; } public static Humanizer.LocaliserRegistry DateToOrdinalWordsConverters { get; } public static Humanizer.LocaliserRegistry Formatters { get; } public static Humanizer.LocaliserRegistry NumberToWordsConverters { get; } public static Humanizer.LocaliserRegistry Ordinalizers { get; } public static Humanizer.ITimeOnlyHumanizeStrategy TimeOnlyHumanizeStrategy { get; set; } public static Humanizer.LocaliserRegistry TimeOnlyToClockNotationConverters { get; } public static void UseEnumDescriptionPropertyLocator(System.Func func) { } } public enum DataUnit { Bit = 0, Byte = 1, Kilobyte = 2, Megabyte = 3, Gigabyte = 4, Terabyte = 5, } public static class DateHumanizeExtensions { public static string Humanize(this System.DateOnly input, System.DateOnly? dateToCompareAgainst = default, System.Globalization.CultureInfo? culture = null) { } public static string Humanize(this System.DateOnly? input, System.DateOnly? dateToCompareAgainst = default, System.Globalization.CultureInfo? culture = null) { } public static string Humanize(this System.DateTimeOffset input, System.DateTimeOffset? dateToCompareAgainst = default, System.Globalization.CultureInfo? culture = null) { } public static string Humanize(this System.DateTimeOffset? input, System.DateTimeOffset? dateToCompareAgainst = default, System.Globalization.CultureInfo? culture = null) { } public static string Humanize(this System.DateTime input, bool? utcDate = default, System.DateTime? dateToCompareAgainst = default, System.Globalization.CultureInfo? culture = null) { } public static string Humanize(this System.DateTime? input, bool? utcDate = default, System.DateTime? dateToCompareAgainst = default, System.Globalization.CultureInfo? culture = null) { } public static string Humanize(this System.TimeOnly input, System.TimeOnly? timeToCompareAgainst = default, bool useUtc = true, System.Globalization.CultureInfo? culture = null) { } public static string Humanize(this System.TimeOnly? input, System.TimeOnly? timeToCompareAgainst = default, bool useUtc = true, System.Globalization.CultureInfo? culture = null) { } } public static class DateToOrdinalWordsExtensions { public static string ToOrdinalWords(this System.DateOnly input) { } public static string ToOrdinalWords(this System.DateTime input) { } public static string ToOrdinalWords(this System.DateOnly input, Humanizer.GrammaticalCase grammaticalCase) { } public static string ToOrdinalWords(this System.DateTime input, Humanizer.GrammaticalCase grammaticalCase) { } } public class DefaultDateOnlyHumanizeStrategy : Humanizer.IDateOnlyHumanizeStrategy { public DefaultDateOnlyHumanizeStrategy() { } public string Humanize(System.DateOnly input, System.DateOnly comparisonBase, System.Globalization.CultureInfo? culture) { } } public class DefaultDateTimeHumanizeStrategy : Humanizer.IDateTimeHumanizeStrategy { public DefaultDateTimeHumanizeStrategy() { } public string Humanize(System.DateTime input, System.DateTime comparisonBase, System.Globalization.CultureInfo? culture) { } } public class DefaultDateTimeOffsetHumanizeStrategy : Humanizer.IDateTimeOffsetHumanizeStrategy { public DefaultDateTimeOffsetHumanizeStrategy() { } public string Humanize(System.DateTimeOffset input, System.DateTimeOffset comparisonBase, System.Globalization.CultureInfo? culture) { } } public class DefaultFormatter : Humanizer.IFormatter { public DefaultFormatter(System.Globalization.CultureInfo culture) { } public DefaultFormatter(string localeCode) { } protected System.Globalization.CultureInfo Culture { get; } public virtual string DataUnitHumanize(Humanizer.DataUnit dataUnit, double count, bool toSymbol = true) { } public virtual string DateHumanize(Humanizer.TimeUnit timeUnit, Humanizer.Tense timeUnitTense, int unit) { } public virtual string DateHumanize_Never() { } public virtual string DateHumanize_Now() { } protected virtual string Format(string resourceKey) { } protected virtual string Format(Humanizer.TimeUnit unit, string resourceKey, int number, bool toWords = false) { } protected virtual string GetResourceKey(string resourceKey) { } protected virtual string GetResourceKey(string resourceKey, int number) { } protected virtual string NumberToWords(Humanizer.TimeUnit unit, int number, System.Globalization.CultureInfo culture) { } public virtual string TimeSpanHumanize(Humanizer.TimeUnit timeUnit, int unit, bool toWords = false) { } public virtual string TimeSpanHumanize_Age() { } public virtual string TimeSpanHumanize_Zero() { } public virtual string TimeUnitHumanize(Humanizer.TimeUnit timeUnit) { } } public class DefaultTimeOnlyHumanizeStrategy : Humanizer.ITimeOnlyHumanizeStrategy { public DefaultTimeOnlyHumanizeStrategy() { } public string Humanize(System.TimeOnly input, System.TimeOnly comparisonBase, System.Globalization.CultureInfo? culture) { } } public class DynamicNumberOfCharactersAndPreserveWordsTruncator : Humanizer.ITruncator { public DynamicNumberOfCharactersAndPreserveWordsTruncator() { } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("value")] public string? Truncate(string? value, int totalLength, string? delimiter, Humanizer.TruncateFrom truncateFrom = 1) { } } public static class EnglishArticle { public static string[] AppendArticlePrefix(string[] items) { } public static string[] PrependArticleSuffix(string[] appended) { } } public static class EnumDehumanizeExtensions { [System.Diagnostics.CodeAnalysis.DynamicDependency(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods, typeof(Humanizer.EnumDehumanizeExtensions))] [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("The native code for the target enumeration might not be available at runtime.")] [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("The native code for the target enumeration might not be available at runtime.")] public static System.Enum DehumanizeTo(this string input, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields)] System.Type targetEnum, Humanizer.OnNoMatch onNoMatch = 0) { } public static TTargetEnum DehumanizeTo<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields)] TTargetEnum>(this string input) where TTargetEnum : struct, System.Enum { } public static TTargetEnum? DehumanizeTo<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields)] TTargetEnum>(this string input, Humanizer.OnNoMatch onNoMatch = 0) where TTargetEnum : struct, System.Enum { } } public static class EnumHumanizeExtensions { public static string Humanize<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields)] T>(this T input) where T : struct, System.Enum { } public static string Humanize<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields)] T>(this T input, Humanizer.LetterCasing casing) where T : struct, System.Enum { } } public enum GrammaticalCase { Nominative = 0, Genitive = 1, Dative = 2, Accusative = 3, Instrumental = 4, Prepositional = 5, } public enum GrammaticalGender { Masculine = 0, Feminine = 1, Neuter = 2, } public static class HeadingExtensions { public static double FromAbbreviatedHeading(this string heading) { } public static double FromAbbreviatedHeading(this string heading, System.Globalization.CultureInfo? culture = null) { } public static double FromHeadingArrow(this char heading) { } public static double FromHeadingArrow(this string heading) { } public static string ToHeading(this double heading, Humanizer.HeadingStyle style = 0, System.Globalization.CultureInfo? culture = null) { } public static char ToHeadingArrow(this double heading) { } } public enum HeadingStyle { Abbreviated = 0, Full = 1, } public interface ICollectionFormatter { string Humanize(System.Collections.Generic.IEnumerable collection); string Humanize(System.Collections.Generic.IEnumerable collection, System.Func objectFormatter); string Humanize(System.Collections.Generic.IEnumerable collection, System.Func objectFormatter); string Humanize(System.Collections.Generic.IEnumerable collection, string separator); string Humanize(System.Collections.Generic.IEnumerable collection, System.Func objectFormatter, string separator); string Humanize(System.Collections.Generic.IEnumerable collection, System.Func objectFormatter, string separator); } public interface ICulturedStringTransformer : Humanizer.IStringTransformer { string Transform(string input, System.Globalization.CultureInfo culture); } public interface IDateOnlyHumanizeStrategy { string Humanize(System.DateOnly input, System.DateOnly comparisonBase, System.Globalization.CultureInfo? culture); } public interface IDateOnlyToOrdinalWordConverter { string Convert(System.DateOnly date); string Convert(System.DateOnly date, Humanizer.GrammaticalCase grammaticalCase); } public interface IDateTimeHumanizeStrategy { string Humanize(System.DateTime input, System.DateTime comparisonBase, System.Globalization.CultureInfo? culture); } public interface IDateTimeOffsetHumanizeStrategy { string Humanize(System.DateTimeOffset input, System.DateTimeOffset comparisonBase, System.Globalization.CultureInfo? culture); } public interface IDateToOrdinalWordConverter { string Convert(System.DateTime date); string Convert(System.DateTime date, Humanizer.GrammaticalCase grammaticalCase); } public interface IFormatter { string DataUnitHumanize(Humanizer.DataUnit dataUnit, double count, bool toSymbol = true); string DateHumanize(Humanizer.TimeUnit timeUnit, Humanizer.Tense timeUnitTense, int unit); string DateHumanize_Never(); string DateHumanize_Now(); string TimeSpanHumanize(Humanizer.TimeUnit timeUnit, int unit, bool toWords = false); string TimeSpanHumanize_Age(); string TimeSpanHumanize_Zero(); string TimeUnitHumanize(Humanizer.TimeUnit timeUnit); } public interface INumberToWordsConverter { string Convert(long number); string Convert(long number, Humanizer.WordForm wordForm); string Convert(long number, bool addAnd); string Convert(long number, Humanizer.GrammaticalGender gender, bool addAnd = true); string Convert(long number, bool addAnd, Humanizer.WordForm wordForm); string Convert(long number, Humanizer.WordForm wordForm, Humanizer.GrammaticalGender gender, bool addAnd = true); string ConvertToOrdinal(int number); string ConvertToOrdinal(int number, Humanizer.GrammaticalGender gender); string ConvertToOrdinal(int number, Humanizer.WordForm wordForm); string ConvertToOrdinal(int number, Humanizer.GrammaticalGender gender, Humanizer.WordForm wordForm); string ConvertToTuple(int number); } public interface IOrdinalizer { string Convert(int number, string numberString); string Convert(int number, string numberString, Humanizer.GrammaticalGender gender); string Convert(int number, string numberString, Humanizer.WordForm wordForm); string Convert(int number, string numberString, Humanizer.GrammaticalGender gender, Humanizer.WordForm wordForm); } public interface IStringTransformer { string Transform(string input); } public interface ITimeOnlyHumanizeStrategy { string Humanize(System.TimeOnly input, System.TimeOnly comparisonBase, System.Globalization.CultureInfo? culture); } public interface ITimeOnlyToClockNotationConverter { string Convert(System.TimeOnly time, Humanizer.ClockNotationRounding roundToNearestFive); } public interface ITruncator { [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("value")] string? Truncate(string? value, int length, string? truncationString, Humanizer.TruncateFrom truncateFrom = 1); } public interface IWordsToNumberConverter { int Convert(string words); bool TryConvert(string words, out int parsedValue); bool TryConvert(string words, out int parsedValue, out string? unrecognizedNumber); } public class In { public In() { } public static System.DateTime April { get; } public static System.DateTime August { get; } public static System.DateTime December { get; } public static System.DateTime February { get; } public static System.DateTime January { get; } public static System.DateTime July { get; } public static System.DateTime June { get; } public static System.DateTime March { get; } public static System.DateTime May { get; } public static System.DateTime November { get; } public static System.DateTime October { get; } public static System.DateTime September { get; } public static System.DateTime AprilOf(int year) { } public static System.DateTime AugustOf(int year) { } public static System.DateTime DecemberOf(int year) { } public static System.DateTime FebruaryOf(int year) { } public static System.DateTime JanuaryOf(int year) { } public static System.DateTime JulyOf(int year) { } public static System.DateTime JuneOf(int year) { } public static System.DateTime MarchOf(int year) { } public static System.DateTime MayOf(int year) { } public static System.DateTime NovemberOf(int year) { } public static System.DateTime OctoberOf(int year) { } public static System.DateTime SeptemberOf(int year) { } public static System.DateTime TheYear(int year) { } public static class Eight { public static System.DateTime Days { get; } public static System.DateTime Hours { get; } public static System.DateTime Minutes { get; } public static System.DateTime Months { get; } public static System.DateTime Seconds { get; } public static System.DateTime Weeks { get; } public static System.DateTime Years { get; } public static System.DateTime DaysFrom(System.DateTime date) { } public static System.DateTime HoursFrom(System.DateTime date) { } public static System.DateTime MinutesFrom(System.DateTime date) { } public static System.DateTime MonthsFrom(System.DateTime date) { } public static System.DateTime SecondsFrom(System.DateTime date) { } public static System.DateTime WeeksFrom(System.DateTime date) { } public static System.DateTime YearsFrom(System.DateTime date) { } } public static class Five { public static System.DateTime Days { get; } public static System.DateTime Hours { get; } public static System.DateTime Minutes { get; } public static System.DateTime Months { get; } public static System.DateTime Seconds { get; } public static System.DateTime Weeks { get; } public static System.DateTime Years { get; } public static System.DateTime DaysFrom(System.DateTime date) { } public static System.DateTime HoursFrom(System.DateTime date) { } public static System.DateTime MinutesFrom(System.DateTime date) { } public static System.DateTime MonthsFrom(System.DateTime date) { } public static System.DateTime SecondsFrom(System.DateTime date) { } public static System.DateTime WeeksFrom(System.DateTime date) { } public static System.DateTime YearsFrom(System.DateTime date) { } } public static class Four { public static System.DateTime Days { get; } public static System.DateTime Hours { get; } public static System.DateTime Minutes { get; } public static System.DateTime Months { get; } public static System.DateTime Seconds { get; } public static System.DateTime Weeks { get; } public static System.DateTime Years { get; } public static System.DateTime DaysFrom(System.DateTime date) { } public static System.DateTime HoursFrom(System.DateTime date) { } public static System.DateTime MinutesFrom(System.DateTime date) { } public static System.DateTime MonthsFrom(System.DateTime date) { } public static System.DateTime SecondsFrom(System.DateTime date) { } public static System.DateTime WeeksFrom(System.DateTime date) { } public static System.DateTime YearsFrom(System.DateTime date) { } } public static class Nine { public static System.DateTime Days { get; } public static System.DateTime Hours { get; } public static System.DateTime Minutes { get; } public static System.DateTime Months { get; } public static System.DateTime Seconds { get; } public static System.DateTime Weeks { get; } public static System.DateTime Years { get; } public static System.DateTime DaysFrom(System.DateTime date) { } public static System.DateTime HoursFrom(System.DateTime date) { } public static System.DateTime MinutesFrom(System.DateTime date) { } public static System.DateTime MonthsFrom(System.DateTime date) { } public static System.DateTime SecondsFrom(System.DateTime date) { } public static System.DateTime WeeksFrom(System.DateTime date) { } public static System.DateTime YearsFrom(System.DateTime date) { } } public static class One { public static System.DateTime Day { get; } public static System.DateTime Hour { get; } public static System.DateTime Minute { get; } public static System.DateTime Month { get; } public static System.DateTime Second { get; } public static System.DateTime Week { get; } public static System.DateTime Year { get; } public static System.DateTime DayFrom(System.DateTime date) { } public static System.DateTime HourFrom(System.DateTime date) { } public static System.DateTime MinuteFrom(System.DateTime date) { } public static System.DateTime MonthFrom(System.DateTime date) { } public static System.DateTime SecondFrom(System.DateTime date) { } public static System.DateTime WeekFrom(System.DateTime date) { } public static System.DateTime YearFrom(System.DateTime date) { } } public static class Seven { public static System.DateTime Days { get; } public static System.DateTime Hours { get; } public static System.DateTime Minutes { get; } public static System.DateTime Months { get; } public static System.DateTime Seconds { get; } public static System.DateTime Weeks { get; } public static System.DateTime Years { get; } public static System.DateTime DaysFrom(System.DateTime date) { } public static System.DateTime HoursFrom(System.DateTime date) { } public static System.DateTime MinutesFrom(System.DateTime date) { } public static System.DateTime MonthsFrom(System.DateTime date) { } public static System.DateTime SecondsFrom(System.DateTime date) { } public static System.DateTime WeeksFrom(System.DateTime date) { } public static System.DateTime YearsFrom(System.DateTime date) { } } public static class Six { public static System.DateTime Days { get; } public static System.DateTime Hours { get; } public static System.DateTime Minutes { get; } public static System.DateTime Months { get; } public static System.DateTime Seconds { get; } public static System.DateTime Weeks { get; } public static System.DateTime Years { get; } public static System.DateTime DaysFrom(System.DateTime date) { } public static System.DateTime HoursFrom(System.DateTime date) { } public static System.DateTime MinutesFrom(System.DateTime date) { } public static System.DateTime MonthsFrom(System.DateTime date) { } public static System.DateTime SecondsFrom(System.DateTime date) { } public static System.DateTime WeeksFrom(System.DateTime date) { } public static System.DateTime YearsFrom(System.DateTime date) { } } public static class Ten { public static System.DateTime Days { get; } public static System.DateTime Hours { get; } public static System.DateTime Minutes { get; } public static System.DateTime Months { get; } public static System.DateTime Seconds { get; } public static System.DateTime Weeks { get; } public static System.DateTime Years { get; } public static System.DateTime DaysFrom(System.DateTime date) { } public static System.DateTime HoursFrom(System.DateTime date) { } public static System.DateTime MinutesFrom(System.DateTime date) { } public static System.DateTime MonthsFrom(System.DateTime date) { } public static System.DateTime SecondsFrom(System.DateTime date) { } public static System.DateTime WeeksFrom(System.DateTime date) { } public static System.DateTime YearsFrom(System.DateTime date) { } } public static class Three { public static System.DateTime Days { get; } public static System.DateTime Hours { get; } public static System.DateTime Minutes { get; } public static System.DateTime Months { get; } public static System.DateTime Seconds { get; } public static System.DateTime Weeks { get; } public static System.DateTime Years { get; } public static System.DateTime DaysFrom(System.DateTime date) { } public static System.DateTime HoursFrom(System.DateTime date) { } public static System.DateTime MinutesFrom(System.DateTime date) { } public static System.DateTime MonthsFrom(System.DateTime date) { } public static System.DateTime SecondsFrom(System.DateTime date) { } public static System.DateTime WeeksFrom(System.DateTime date) { } public static System.DateTime YearsFrom(System.DateTime date) { } } public static class Two { public static System.DateTime Days { get; } public static System.DateTime Hours { get; } public static System.DateTime Minutes { get; } public static System.DateTime Months { get; } public static System.DateTime Seconds { get; } public static System.DateTime Weeks { get; } public static System.DateTime Years { get; } public static System.DateTime DaysFrom(System.DateTime date) { } public static System.DateTime HoursFrom(System.DateTime date) { } public static System.DateTime MinutesFrom(System.DateTime date) { } public static System.DateTime MonthsFrom(System.DateTime date) { } public static System.DateTime SecondsFrom(System.DateTime date) { } public static System.DateTime WeeksFrom(System.DateTime date) { } public static System.DateTime YearsFrom(System.DateTime date) { } } } public class InDate { public InDate() { } public static System.DateOnly April { get; } public static System.DateOnly August { get; } public static System.DateOnly December { get; } public static System.DateOnly February { get; } public static System.DateOnly January { get; } public static System.DateOnly July { get; } public static System.DateOnly June { get; } public static System.DateOnly March { get; } public static System.DateOnly May { get; } public static System.DateOnly November { get; } public static System.DateOnly October { get; } public static System.DateOnly September { get; } public static System.DateOnly AprilOf(int year) { } public static System.DateOnly AugustOf(int year) { } public static System.DateOnly DecemberOf(int year) { } public static System.DateOnly FebruaryOf(int year) { } public static System.DateOnly JanuaryOf(int year) { } public static System.DateOnly JulyOf(int year) { } public static System.DateOnly JuneOf(int year) { } public static System.DateOnly MarchOf(int year) { } public static System.DateOnly MayOf(int year) { } public static System.DateOnly NovemberOf(int year) { } public static System.DateOnly OctoberOf(int year) { } public static System.DateOnly SeptemberOf(int year) { } public static System.DateOnly TheYear(int year) { } public static class Eight { public static System.DateOnly Days { get; } public static System.DateOnly Months { get; } public static System.DateOnly Weeks { get; } public static System.DateOnly Years { get; } public static System.DateOnly DaysFrom(System.DateOnly date) { } public static System.DateOnly DaysFrom(System.DateTime date) { } public static System.DateOnly MonthsFrom(System.DateOnly date) { } public static System.DateOnly MonthsFrom(System.DateTime date) { } public static System.DateOnly WeeksFrom(System.DateOnly date) { } public static System.DateOnly WeeksFrom(System.DateTime date) { } public static System.DateOnly YearsFrom(System.DateOnly date) { } public static System.DateOnly YearsFrom(System.DateTime date) { } } public static class Five { public static System.DateOnly Days { get; } public static System.DateOnly Months { get; } public static System.DateOnly Weeks { get; } public static System.DateOnly Years { get; } public static System.DateOnly DaysFrom(System.DateOnly date) { } public static System.DateOnly DaysFrom(System.DateTime date) { } public static System.DateOnly MonthsFrom(System.DateOnly date) { } public static System.DateOnly MonthsFrom(System.DateTime date) { } public static System.DateOnly WeeksFrom(System.DateOnly date) { } public static System.DateOnly WeeksFrom(System.DateTime date) { } public static System.DateOnly YearsFrom(System.DateOnly date) { } public static System.DateOnly YearsFrom(System.DateTime date) { } } public static class Four { public static System.DateOnly Days { get; } public static System.DateOnly Months { get; } public static System.DateOnly Weeks { get; } public static System.DateOnly Years { get; } public static System.DateOnly DaysFrom(System.DateOnly date) { } public static System.DateOnly DaysFrom(System.DateTime date) { } public static System.DateOnly MonthsFrom(System.DateOnly date) { } public static System.DateOnly MonthsFrom(System.DateTime date) { } public static System.DateOnly WeeksFrom(System.DateOnly date) { } public static System.DateOnly WeeksFrom(System.DateTime date) { } public static System.DateOnly YearsFrom(System.DateOnly date) { } public static System.DateOnly YearsFrom(System.DateTime date) { } } public static class Nine { public static System.DateOnly Days { get; } public static System.DateOnly Months { get; } public static System.DateOnly Weeks { get; } public static System.DateOnly Years { get; } public static System.DateOnly DaysFrom(System.DateOnly date) { } public static System.DateOnly DaysFrom(System.DateTime date) { } public static System.DateOnly MonthsFrom(System.DateOnly date) { } public static System.DateOnly MonthsFrom(System.DateTime date) { } public static System.DateOnly WeeksFrom(System.DateOnly date) { } public static System.DateOnly WeeksFrom(System.DateTime date) { } public static System.DateOnly YearsFrom(System.DateOnly date) { } public static System.DateOnly YearsFrom(System.DateTime date) { } } public static class One { public static System.DateOnly Day { get; } public static System.DateOnly Month { get; } public static System.DateOnly Week { get; } public static System.DateOnly Year { get; } public static System.DateOnly DayFrom(System.DateOnly date) { } public static System.DateOnly DayFrom(System.DateTime date) { } public static System.DateOnly MonthFrom(System.DateOnly date) { } public static System.DateOnly MonthFrom(System.DateTime date) { } public static System.DateOnly WeekFrom(System.DateOnly date) { } public static System.DateOnly WeekFrom(System.DateTime date) { } public static System.DateOnly YearFrom(System.DateOnly date) { } public static System.DateOnly YearFrom(System.DateTime date) { } } public static class Seven { public static System.DateOnly Days { get; } public static System.DateOnly Months { get; } public static System.DateOnly Weeks { get; } public static System.DateOnly Years { get; } public static System.DateOnly DaysFrom(System.DateOnly date) { } public static System.DateOnly DaysFrom(System.DateTime date) { } public static System.DateOnly MonthsFrom(System.DateOnly date) { } public static System.DateOnly MonthsFrom(System.DateTime date) { } public static System.DateOnly WeeksFrom(System.DateOnly date) { } public static System.DateOnly WeeksFrom(System.DateTime date) { } public static System.DateOnly YearsFrom(System.DateOnly date) { } public static System.DateOnly YearsFrom(System.DateTime date) { } } public static class Six { public static System.DateOnly Days { get; } public static System.DateOnly Months { get; } public static System.DateOnly Weeks { get; } public static System.DateOnly Years { get; } public static System.DateOnly DaysFrom(System.DateOnly date) { } public static System.DateOnly DaysFrom(System.DateTime date) { } public static System.DateOnly MonthsFrom(System.DateOnly date) { } public static System.DateOnly MonthsFrom(System.DateTime date) { } public static System.DateOnly WeeksFrom(System.DateOnly date) { } public static System.DateOnly WeeksFrom(System.DateTime date) { } public static System.DateOnly YearsFrom(System.DateOnly date) { } public static System.DateOnly YearsFrom(System.DateTime date) { } } public static class Ten { public static System.DateOnly Days { get; } public static System.DateOnly Months { get; } public static System.DateOnly Weeks { get; } public static System.DateOnly Years { get; } public static System.DateOnly DaysFrom(System.DateOnly date) { } public static System.DateOnly DaysFrom(System.DateTime date) { } public static System.DateOnly MonthsFrom(System.DateOnly date) { } public static System.DateOnly MonthsFrom(System.DateTime date) { } public static System.DateOnly WeeksFrom(System.DateOnly date) { } public static System.DateOnly WeeksFrom(System.DateTime date) { } public static System.DateOnly YearsFrom(System.DateOnly date) { } public static System.DateOnly YearsFrom(System.DateTime date) { } } public static class Three { public static System.DateOnly Days { get; } public static System.DateOnly Months { get; } public static System.DateOnly Weeks { get; } public static System.DateOnly Years { get; } public static System.DateOnly DaysFrom(System.DateOnly date) { } public static System.DateOnly DaysFrom(System.DateTime date) { } public static System.DateOnly MonthsFrom(System.DateOnly date) { } public static System.DateOnly MonthsFrom(System.DateTime date) { } public static System.DateOnly WeeksFrom(System.DateOnly date) { } public static System.DateOnly WeeksFrom(System.DateTime date) { } public static System.DateOnly YearsFrom(System.DateOnly date) { } public static System.DateOnly YearsFrom(System.DateTime date) { } } public static class Two { public static System.DateOnly Days { get; } public static System.DateOnly Months { get; } public static System.DateOnly Weeks { get; } public static System.DateOnly Years { get; } public static System.DateOnly DaysFrom(System.DateOnly date) { } public static System.DateOnly DaysFrom(System.DateTime date) { } public static System.DateOnly MonthsFrom(System.DateOnly date) { } public static System.DateOnly MonthsFrom(System.DateTime date) { } public static System.DateOnly WeeksFrom(System.DateOnly date) { } public static System.DateOnly WeeksFrom(System.DateTime date) { } public static System.DateOnly YearsFrom(System.DateOnly date) { } public static System.DateOnly YearsFrom(System.DateTime date) { } } } public static class InflectorExtensions { public static string Camelize(this string input) { } public static string Dasherize(this string underscoredWord) { } public static string Hyphenate(this string underscoredWord) { } public static string Kebaberize(this string input) { } public static string Pascalize(this string input) { } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("word")] public static string? Pluralize(this string? word, bool inputIsKnownToBeSingular = true) { } public static string Singularize(this string word, bool inputIsKnownToBePlural = true, bool skipSimpleWords = false) { } public static string Titleize(this string input) { } public static string Underscore(this string input) { } } public enum LetterCasing { Title = 0, AllCaps = 1, LowerCase = 2, Sentence = 3, } public class LocaliserRegistry where TLocaliser : class { public LocaliserRegistry(System.Func defaultLocaliser) { } public LocaliserRegistry(TLocaliser defaultLocaliser) { } public void Register(string localeCode, System.Func localiser) { } public void Register(string localeCode, TLocaliser localiser) { } public TLocaliser ResolveForCulture(System.Globalization.CultureInfo? culture) { } public TLocaliser ResolveForUiCulture() { } } public static class MetricNumeralExtensions { public static double FromMetric(this string input) { } public static string ToMetric(this double input, Humanizer.MetricNumeralFormats? formats = default, int? decimals = default) { } public static string ToMetric(this int input, Humanizer.MetricNumeralFormats? formats = default, int? decimals = default) { } public static string ToMetric(this long input, Humanizer.MetricNumeralFormats? formats = default, int? decimals = default) { } } [System.Flags] public enum MetricNumeralFormats { UseLongScaleWord = 1, UseName = 2, UseShortScaleWord = 4, WithSpace = 8, } public class NoMatchFoundException : System.Exception { public NoMatchFoundException() { } public NoMatchFoundException(string message) { } public NoMatchFoundException(string message, System.Exception inner) { } } public static class NumberToNumberExtensions { public static double Billions(this double input) { } public static int Billions(this int input) { } public static long Billions(this long input) { } public static uint Billions(this uint input) { } public static ulong Billions(this ulong input) { } public static double Hundreds(this double input) { } public static int Hundreds(this int input) { } public static long Hundreds(this long input) { } public static uint Hundreds(this uint input) { } public static ulong Hundreds(this ulong input) { } public static double Millions(this double input) { } public static int Millions(this int input) { } public static long Millions(this long input) { } public static uint Millions(this uint input) { } public static ulong Millions(this ulong input) { } public static double Tens(this double input) { } public static int Tens(this int input) { } public static long Tens(this long input) { } public static uint Tens(this uint input) { } public static ulong Tens(this ulong input) { } public static double Thousands(this double input) { } public static int Thousands(this int input) { } public static long Thousands(this long input) { } public static uint Thousands(this uint input) { } public static ulong Thousands(this ulong input) { } } public static class NumberToTimeSpanExtensions { public static System.TimeSpan Days(this byte days) { } public static System.TimeSpan Days(this double days) { } public static System.TimeSpan Days(this int days) { } public static System.TimeSpan Days(this long days) { } public static System.TimeSpan Days(this sbyte days) { } public static System.TimeSpan Days(this short days) { } public static System.TimeSpan Days(this uint days) { } public static System.TimeSpan Days(this ulong days) { } public static System.TimeSpan Days(this ushort days) { } public static System.TimeSpan Hours(this byte hours) { } public static System.TimeSpan Hours(this double hours) { } public static System.TimeSpan Hours(this int hours) { } public static System.TimeSpan Hours(this long hours) { } public static System.TimeSpan Hours(this sbyte hours) { } public static System.TimeSpan Hours(this short hours) { } public static System.TimeSpan Hours(this uint hours) { } public static System.TimeSpan Hours(this ulong hours) { } public static System.TimeSpan Hours(this ushort hours) { } public static System.TimeSpan Milliseconds(this byte ms) { } public static System.TimeSpan Milliseconds(this double ms) { } public static System.TimeSpan Milliseconds(this int ms) { } public static System.TimeSpan Milliseconds(this long ms) { } public static System.TimeSpan Milliseconds(this sbyte ms) { } public static System.TimeSpan Milliseconds(this short ms) { } public static System.TimeSpan Milliseconds(this uint ms) { } public static System.TimeSpan Milliseconds(this ulong ms) { } public static System.TimeSpan Milliseconds(this ushort ms) { } public static System.TimeSpan Minutes(this byte minutes) { } public static System.TimeSpan Minutes(this double minutes) { } public static System.TimeSpan Minutes(this int minutes) { } public static System.TimeSpan Minutes(this long minutes) { } public static System.TimeSpan Minutes(this sbyte minutes) { } public static System.TimeSpan Minutes(this short minutes) { } public static System.TimeSpan Minutes(this uint minutes) { } public static System.TimeSpan Minutes(this ulong minutes) { } public static System.TimeSpan Minutes(this ushort minutes) { } public static System.TimeSpan Seconds(this byte seconds) { } public static System.TimeSpan Seconds(this double seconds) { } public static System.TimeSpan Seconds(this int seconds) { } public static System.TimeSpan Seconds(this long seconds) { } public static System.TimeSpan Seconds(this sbyte seconds) { } public static System.TimeSpan Seconds(this short seconds) { } public static System.TimeSpan Seconds(this uint seconds) { } public static System.TimeSpan Seconds(this ulong seconds) { } public static System.TimeSpan Seconds(this ushort seconds) { } public static System.TimeSpan Weeks(this byte input) { } public static System.TimeSpan Weeks(this double input) { } public static System.TimeSpan Weeks(this int input) { } public static System.TimeSpan Weeks(this long input) { } public static System.TimeSpan Weeks(this sbyte input) { } public static System.TimeSpan Weeks(this short input) { } public static System.TimeSpan Weeks(this uint input) { } public static System.TimeSpan Weeks(this ulong input) { } public static System.TimeSpan Weeks(this ushort input) { } } public static class NumberToWordsExtension { public static string ToOrdinalWords(this int number, System.Globalization.CultureInfo? culture = null) { } public static string ToOrdinalWords(this int number, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo? culture = null) { } public static string ToOrdinalWords(this int number, Humanizer.WordForm wordForm, System.Globalization.CultureInfo? culture = null) { } public static string ToOrdinalWords(this int number, Humanizer.GrammaticalGender gender, Humanizer.WordForm wordForm, System.Globalization.CultureInfo? culture = null) { } public static string ToTuple(this int number, System.Globalization.CultureInfo? culture = null) { } public static string ToWords(this int number, System.Globalization.CultureInfo? culture = null) { } public static string ToWords(this int number, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo? culture = null) { } public static string ToWords(this int number, Humanizer.WordForm wordForm, System.Globalization.CultureInfo? culture = null) { } public static string ToWords(this int number, bool addAnd, System.Globalization.CultureInfo? culture = null) { } public static string ToWords(this long number, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo? culture = null) { } public static string ToWords(this long number, System.Globalization.CultureInfo? culture = null, bool addAnd = true) { } public static string ToWords(this int number, Humanizer.WordForm wordForm, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo? culture = null) { } public static string ToWords(this int number, bool addAnd, Humanizer.WordForm wordForm, System.Globalization.CultureInfo? culture = null) { } public static string ToWords(this long number, Humanizer.WordForm wordForm, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo? culture = null) { } public static string ToWords(this long number, Humanizer.WordForm wordForm, System.Globalization.CultureInfo? culture = null, bool addAnd = false) { } } public class On { public On() { } public class April { public April() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class August { public August() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The31st { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class December { public December() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The31st { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class February { public February() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class January { public January() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The31st { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class July { public July() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The31st { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class June { public June() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class March { public March() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The31st { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class May { public May() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The31st { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class November { public November() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class October { public October() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The31st { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class September { public September() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } } public class OnDate { public OnDate() { } public class April { public April() { } public static System.DateOnly The10th { get; } public static System.DateOnly The11th { get; } public static System.DateOnly The12th { get; } public static System.DateOnly The13th { get; } public static System.DateOnly The14th { get; } public static System.DateOnly The15th { get; } public static System.DateOnly The16th { get; } public static System.DateOnly The17th { get; } public static System.DateOnly The18th { get; } public static System.DateOnly The19th { get; } public static System.DateOnly The1st { get; } public static System.DateOnly The20th { get; } public static System.DateOnly The21st { get; } public static System.DateOnly The22nd { get; } public static System.DateOnly The23rd { get; } public static System.DateOnly The24th { get; } public static System.DateOnly The25th { get; } public static System.DateOnly The26th { get; } public static System.DateOnly The27th { get; } public static System.DateOnly The28th { get; } public static System.DateOnly The29th { get; } public static System.DateOnly The2nd { get; } public static System.DateOnly The30th { get; } public static System.DateOnly The3rd { get; } public static System.DateOnly The4th { get; } public static System.DateOnly The5th { get; } public static System.DateOnly The6th { get; } public static System.DateOnly The7th { get; } public static System.DateOnly The8th { get; } public static System.DateOnly The9th { get; } public static System.DateOnly The(int dayNumber) { } } public class August { public August() { } public static System.DateOnly The10th { get; } public static System.DateOnly The11th { get; } public static System.DateOnly The12th { get; } public static System.DateOnly The13th { get; } public static System.DateOnly The14th { get; } public static System.DateOnly The15th { get; } public static System.DateOnly The16th { get; } public static System.DateOnly The17th { get; } public static System.DateOnly The18th { get; } public static System.DateOnly The19th { get; } public static System.DateOnly The1st { get; } public static System.DateOnly The20th { get; } public static System.DateOnly The21st { get; } public static System.DateOnly The22nd { get; } public static System.DateOnly The23rd { get; } public static System.DateOnly The24th { get; } public static System.DateOnly The25th { get; } public static System.DateOnly The26th { get; } public static System.DateOnly The27th { get; } public static System.DateOnly The28th { get; } public static System.DateOnly The29th { get; } public static System.DateOnly The2nd { get; } public static System.DateOnly The30th { get; } public static System.DateOnly The31st { get; } public static System.DateOnly The3rd { get; } public static System.DateOnly The4th { get; } public static System.DateOnly The5th { get; } public static System.DateOnly The6th { get; } public static System.DateOnly The7th { get; } public static System.DateOnly The8th { get; } public static System.DateOnly The9th { get; } public static System.DateOnly The(int dayNumber) { } } public class December { public December() { } public static System.DateOnly The10th { get; } public static System.DateOnly The11th { get; } public static System.DateOnly The12th { get; } public static System.DateOnly The13th { get; } public static System.DateOnly The14th { get; } public static System.DateOnly The15th { get; } public static System.DateOnly The16th { get; } public static System.DateOnly The17th { get; } public static System.DateOnly The18th { get; } public static System.DateOnly The19th { get; } public static System.DateOnly The1st { get; } public static System.DateOnly The20th { get; } public static System.DateOnly The21st { get; } public static System.DateOnly The22nd { get; } public static System.DateOnly The23rd { get; } public static System.DateOnly The24th { get; } public static System.DateOnly The25th { get; } public static System.DateOnly The26th { get; } public static System.DateOnly The27th { get; } public static System.DateOnly The28th { get; } public static System.DateOnly The29th { get; } public static System.DateOnly The2nd { get; } public static System.DateOnly The30th { get; } public static System.DateOnly The31st { get; } public static System.DateOnly The3rd { get; } public static System.DateOnly The4th { get; } public static System.DateOnly The5th { get; } public static System.DateOnly The6th { get; } public static System.DateOnly The7th { get; } public static System.DateOnly The8th { get; } public static System.DateOnly The9th { get; } public static System.DateOnly The(int dayNumber) { } } public class February { public February() { } public static System.DateOnly The10th { get; } public static System.DateOnly The11th { get; } public static System.DateOnly The12th { get; } public static System.DateOnly The13th { get; } public static System.DateOnly The14th { get; } public static System.DateOnly The15th { get; } public static System.DateOnly The16th { get; } public static System.DateOnly The17th { get; } public static System.DateOnly The18th { get; } public static System.DateOnly The19th { get; } public static System.DateOnly The1st { get; } public static System.DateOnly The20th { get; } public static System.DateOnly The21st { get; } public static System.DateOnly The22nd { get; } public static System.DateOnly The23rd { get; } public static System.DateOnly The24th { get; } public static System.DateOnly The25th { get; } public static System.DateOnly The26th { get; } public static System.DateOnly The27th { get; } public static System.DateOnly The28th { get; } public static System.DateOnly The29th { get; } public static System.DateOnly The2nd { get; } public static System.DateOnly The3rd { get; } public static System.DateOnly The4th { get; } public static System.DateOnly The5th { get; } public static System.DateOnly The6th { get; } public static System.DateOnly The7th { get; } public static System.DateOnly The8th { get; } public static System.DateOnly The9th { get; } public static System.DateOnly The(int dayNumber) { } } public class January { public January() { } public static System.DateOnly The10th { get; } public static System.DateOnly The11th { get; } public static System.DateOnly The12th { get; } public static System.DateOnly The13th { get; } public static System.DateOnly The14th { get; } public static System.DateOnly The15th { get; } public static System.DateOnly The16th { get; } public static System.DateOnly The17th { get; } public static System.DateOnly The18th { get; } public static System.DateOnly The19th { get; } public static System.DateOnly The1st { get; } public static System.DateOnly The20th { get; } public static System.DateOnly The21st { get; } public static System.DateOnly The22nd { get; } public static System.DateOnly The23rd { get; } public static System.DateOnly The24th { get; } public static System.DateOnly The25th { get; } public static System.DateOnly The26th { get; } public static System.DateOnly The27th { get; } public static System.DateOnly The28th { get; } public static System.DateOnly The29th { get; } public static System.DateOnly The2nd { get; } public static System.DateOnly The30th { get; } public static System.DateOnly The31st { get; } public static System.DateOnly The3rd { get; } public static System.DateOnly The4th { get; } public static System.DateOnly The5th { get; } public static System.DateOnly The6th { get; } public static System.DateOnly The7th { get; } public static System.DateOnly The8th { get; } public static System.DateOnly The9th { get; } public static System.DateOnly The(int dayNumber) { } } public class July { public July() { } public static System.DateOnly The10th { get; } public static System.DateOnly The11th { get; } public static System.DateOnly The12th { get; } public static System.DateOnly The13th { get; } public static System.DateOnly The14th { get; } public static System.DateOnly The15th { get; } public static System.DateOnly The16th { get; } public static System.DateOnly The17th { get; } public static System.DateOnly The18th { get; } public static System.DateOnly The19th { get; } public static System.DateOnly The1st { get; } public static System.DateOnly The20th { get; } public static System.DateOnly The21st { get; } public static System.DateOnly The22nd { get; } public static System.DateOnly The23rd { get; } public static System.DateOnly The24th { get; } public static System.DateOnly The25th { get; } public static System.DateOnly The26th { get; } public static System.DateOnly The27th { get; } public static System.DateOnly The28th { get; } public static System.DateOnly The29th { get; } public static System.DateOnly The2nd { get; } public static System.DateOnly The30th { get; } public static System.DateOnly The31st { get; } public static System.DateOnly The3rd { get; } public static System.DateOnly The4th { get; } public static System.DateOnly The5th { get; } public static System.DateOnly The6th { get; } public static System.DateOnly The7th { get; } public static System.DateOnly The8th { get; } public static System.DateOnly The9th { get; } public static System.DateOnly The(int dayNumber) { } } public class June { public June() { } public static System.DateOnly The10th { get; } public static System.DateOnly The11th { get; } public static System.DateOnly The12th { get; } public static System.DateOnly The13th { get; } public static System.DateOnly The14th { get; } public static System.DateOnly The15th { get; } public static System.DateOnly The16th { get; } public static System.DateOnly The17th { get; } public static System.DateOnly The18th { get; } public static System.DateOnly The19th { get; } public static System.DateOnly The1st { get; } public static System.DateOnly The20th { get; } public static System.DateOnly The21st { get; } public static System.DateOnly The22nd { get; } public static System.DateOnly The23rd { get; } public static System.DateOnly The24th { get; } public static System.DateOnly The25th { get; } public static System.DateOnly The26th { get; } public static System.DateOnly The27th { get; } public static System.DateOnly The28th { get; } public static System.DateOnly The29th { get; } public static System.DateOnly The2nd { get; } public static System.DateOnly The30th { get; } public static System.DateOnly The3rd { get; } public static System.DateOnly The4th { get; } public static System.DateOnly The5th { get; } public static System.DateOnly The6th { get; } public static System.DateOnly The7th { get; } public static System.DateOnly The8th { get; } public static System.DateOnly The9th { get; } public static System.DateOnly The(int dayNumber) { } } public class March { public March() { } public static System.DateOnly The10th { get; } public static System.DateOnly The11th { get; } public static System.DateOnly The12th { get; } public static System.DateOnly The13th { get; } public static System.DateOnly The14th { get; } public static System.DateOnly The15th { get; } public static System.DateOnly The16th { get; } public static System.DateOnly The17th { get; } public static System.DateOnly The18th { get; } public static System.DateOnly The19th { get; } public static System.DateOnly The1st { get; } public static System.DateOnly The20th { get; } public static System.DateOnly The21st { get; } public static System.DateOnly The22nd { get; } public static System.DateOnly The23rd { get; } public static System.DateOnly The24th { get; } public static System.DateOnly The25th { get; } public static System.DateOnly The26th { get; } public static System.DateOnly The27th { get; } public static System.DateOnly The28th { get; } public static System.DateOnly The29th { get; } public static System.DateOnly The2nd { get; } public static System.DateOnly The30th { get; } public static System.DateOnly The31st { get; } public static System.DateOnly The3rd { get; } public static System.DateOnly The4th { get; } public static System.DateOnly The5th { get; } public static System.DateOnly The6th { get; } public static System.DateOnly The7th { get; } public static System.DateOnly The8th { get; } public static System.DateOnly The9th { get; } public static System.DateOnly The(int dayNumber) { } } public class May { public May() { } public static System.DateOnly The10th { get; } public static System.DateOnly The11th { get; } public static System.DateOnly The12th { get; } public static System.DateOnly The13th { get; } public static System.DateOnly The14th { get; } public static System.DateOnly The15th { get; } public static System.DateOnly The16th { get; } public static System.DateOnly The17th { get; } public static System.DateOnly The18th { get; } public static System.DateOnly The19th { get; } public static System.DateOnly The1st { get; } public static System.DateOnly The20th { get; } public static System.DateOnly The21st { get; } public static System.DateOnly The22nd { get; } public static System.DateOnly The23rd { get; } public static System.DateOnly The24th { get; } public static System.DateOnly The25th { get; } public static System.DateOnly The26th { get; } public static System.DateOnly The27th { get; } public static System.DateOnly The28th { get; } public static System.DateOnly The29th { get; } public static System.DateOnly The2nd { get; } public static System.DateOnly The30th { get; } public static System.DateOnly The31st { get; } public static System.DateOnly The3rd { get; } public static System.DateOnly The4th { get; } public static System.DateOnly The5th { get; } public static System.DateOnly The6th { get; } public static System.DateOnly The7th { get; } public static System.DateOnly The8th { get; } public static System.DateOnly The9th { get; } public static System.DateOnly The(int dayNumber) { } } public class November { public November() { } public static System.DateOnly The10th { get; } public static System.DateOnly The11th { get; } public static System.DateOnly The12th { get; } public static System.DateOnly The13th { get; } public static System.DateOnly The14th { get; } public static System.DateOnly The15th { get; } public static System.DateOnly The16th { get; } public static System.DateOnly The17th { get; } public static System.DateOnly The18th { get; } public static System.DateOnly The19th { get; } public static System.DateOnly The1st { get; } public static System.DateOnly The20th { get; } public static System.DateOnly The21st { get; } public static System.DateOnly The22nd { get; } public static System.DateOnly The23rd { get; } public static System.DateOnly The24th { get; } public static System.DateOnly The25th { get; } public static System.DateOnly The26th { get; } public static System.DateOnly The27th { get; } public static System.DateOnly The28th { get; } public static System.DateOnly The29th { get; } public static System.DateOnly The2nd { get; } public static System.DateOnly The30th { get; } public static System.DateOnly The3rd { get; } public static System.DateOnly The4th { get; } public static System.DateOnly The5th { get; } public static System.DateOnly The6th { get; } public static System.DateOnly The7th { get; } public static System.DateOnly The8th { get; } public static System.DateOnly The9th { get; } public static System.DateOnly The(int dayNumber) { } } public class October { public October() { } public static System.DateOnly The10th { get; } public static System.DateOnly The11th { get; } public static System.DateOnly The12th { get; } public static System.DateOnly The13th { get; } public static System.DateOnly The14th { get; } public static System.DateOnly The15th { get; } public static System.DateOnly The16th { get; } public static System.DateOnly The17th { get; } public static System.DateOnly The18th { get; } public static System.DateOnly The19th { get; } public static System.DateOnly The1st { get; } public static System.DateOnly The20th { get; } public static System.DateOnly The21st { get; } public static System.DateOnly The22nd { get; } public static System.DateOnly The23rd { get; } public static System.DateOnly The24th { get; } public static System.DateOnly The25th { get; } public static System.DateOnly The26th { get; } public static System.DateOnly The27th { get; } public static System.DateOnly The28th { get; } public static System.DateOnly The29th { get; } public static System.DateOnly The2nd { get; } public static System.DateOnly The30th { get; } public static System.DateOnly The31st { get; } public static System.DateOnly The3rd { get; } public static System.DateOnly The4th { get; } public static System.DateOnly The5th { get; } public static System.DateOnly The6th { get; } public static System.DateOnly The7th { get; } public static System.DateOnly The8th { get; } public static System.DateOnly The9th { get; } public static System.DateOnly The(int dayNumber) { } } public class September { public September() { } public static System.DateOnly The10th { get; } public static System.DateOnly The11th { get; } public static System.DateOnly The12th { get; } public static System.DateOnly The13th { get; } public static System.DateOnly The14th { get; } public static System.DateOnly The15th { get; } public static System.DateOnly The16th { get; } public static System.DateOnly The17th { get; } public static System.DateOnly The18th { get; } public static System.DateOnly The19th { get; } public static System.DateOnly The1st { get; } public static System.DateOnly The20th { get; } public static System.DateOnly The21st { get; } public static System.DateOnly The22nd { get; } public static System.DateOnly The23rd { get; } public static System.DateOnly The24th { get; } public static System.DateOnly The25th { get; } public static System.DateOnly The26th { get; } public static System.DateOnly The27th { get; } public static System.DateOnly The28th { get; } public static System.DateOnly The29th { get; } public static System.DateOnly The2nd { get; } public static System.DateOnly The30th { get; } public static System.DateOnly The3rd { get; } public static System.DateOnly The4th { get; } public static System.DateOnly The5th { get; } public static System.DateOnly The6th { get; } public static System.DateOnly The7th { get; } public static System.DateOnly The8th { get; } public static System.DateOnly The9th { get; } public static System.DateOnly The(int dayNumber) { } } } public enum OnNoMatch { ThrowsException = 0, ReturnsNull = 1, } public static class OrdinalizeExtensions { public static string Ordinalize(this int number) { } public static string Ordinalize(this string numberString) { } public static string Ordinalize(this int number, Humanizer.GrammaticalGender gender) { } public static string Ordinalize(this int number, Humanizer.WordForm wordForm) { } public static string Ordinalize(this int number, System.Globalization.CultureInfo culture) { } public static string Ordinalize(this string numberString, Humanizer.GrammaticalGender gender) { } public static string Ordinalize(this string numberString, Humanizer.WordForm wordForm) { } public static string Ordinalize(this string numberString, System.Globalization.CultureInfo culture) { } public static string Ordinalize(this int number, Humanizer.GrammaticalGender gender, Humanizer.WordForm wordForm) { } public static string Ordinalize(this int number, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo culture) { } public static string Ordinalize(this int number, System.Globalization.CultureInfo culture, Humanizer.WordForm wordForm) { } public static string Ordinalize(this string numberString, Humanizer.GrammaticalGender gender, Humanizer.WordForm wordForm) { } public static string Ordinalize(this string numberString, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo culture) { } public static string Ordinalize(this string numberString, System.Globalization.CultureInfo culture, Humanizer.WordForm wordForm) { } public static string Ordinalize(this int number, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo culture, Humanizer.WordForm wordForm) { } public static string Ordinalize(this string numberString, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo culture, Humanizer.WordForm wordForm) { } } public enum Plurality { Singular = 0, Plural = 1, CouldBeEither = 2, } public class PrecisionDateOnlyHumanizeStrategy : Humanizer.IDateOnlyHumanizeStrategy { public PrecisionDateOnlyHumanizeStrategy(double precision = 0.75) { } public string Humanize(System.DateOnly input, System.DateOnly comparisonBase, System.Globalization.CultureInfo? culture) { } } public class PrecisionDateTimeHumanizeStrategy : Humanizer.IDateTimeHumanizeStrategy { public PrecisionDateTimeHumanizeStrategy(double precision = 0.75) { } public string Humanize(System.DateTime input, System.DateTime comparisonBase, System.Globalization.CultureInfo? culture) { } } public class PrecisionDateTimeOffsetHumanizeStrategy : Humanizer.IDateTimeOffsetHumanizeStrategy { public PrecisionDateTimeOffsetHumanizeStrategy(double precision = 0.75) { } public string Humanize(System.DateTimeOffset input, System.DateTimeOffset comparisonBase, System.Globalization.CultureInfo? culture) { } } public class PrecisionTimeOnlyHumanizeStrategy : Humanizer.ITimeOnlyHumanizeStrategy { public PrecisionTimeOnlyHumanizeStrategy(double precision = 0.75) { } public string Humanize(System.TimeOnly input, System.TimeOnly comparisonBase, System.Globalization.CultureInfo? culture) { } } public static class PrepositionsExtensions { public static System.DateTime At(this System.DateTime date, int hour, int min = 0, int second = 0, int millisecond = 0) { } public static System.DateTime AtMidnight(this System.DateTime date) { } public static System.DateTime AtNoon(this System.DateTime date) { } public static System.DateTime In(this System.DateTime date, int year) { } } public class ResourceKeys { public ResourceKeys() { } public static class DateHumanize { public const string Never = "DateHumanize_Never"; public const string Now = "DateHumanize_Now"; public static string GetResourceKey(Humanizer.TimeUnit timeUnit, Humanizer.Tense timeUnitTense, int count = 1) { } } public static class TimeSpanHumanize { public static string GetResourceKey(Humanizer.TimeUnit unit, int count = 1, bool toWords = false) { } } public static class TimeUnitSymbol { public static string GetResourceKey(Humanizer.TimeUnit unit) { } } } public static class Resources { public static string GetResource(string resourceKey, System.Globalization.CultureInfo? culture = null) { } public static bool TryGetResource(string resourceKey, System.Globalization.CultureInfo? culture, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out string? result) { } } public static class RomanNumeralExtensions { public static int FromRoman(System.ReadOnlySpan input) { } public static int FromRoman(this string input) { } public static string ToRoman(this int input) { } } public enum ShowQuantityAs { None = 0, Numeric = 1, Words = 2, } public static class StringDehumanizeExtensions { public static string Dehumanize(this string input) { } } public static class StringHumanizeExtensions { public static string Humanize(this string input) { } public static string Humanize(this string input, Humanizer.LetterCasing casing) { } } public enum Tense { Future = 0, Past = 1, } public static class TimeOnlyToClockNotationExtensions { public static string ToClockNotation(this System.TimeOnly input, Humanizer.ClockNotationRounding roundToNearestFive = 0) { } } public static class TimeSpanHumanizeExtensions { public static string Humanize(this System.TimeSpan timeSpan, int precision = 1, System.Globalization.CultureInfo? culture = null, Humanizer.TimeUnit maxUnit = 5, Humanizer.TimeUnit minUnit = 0, string? collectionSeparator = ", ", bool toWords = false) { } public static string Humanize(this System.TimeSpan timeSpan, int precision, bool countEmptyUnits, System.Globalization.CultureInfo? culture = null, Humanizer.TimeUnit maxUnit = 5, Humanizer.TimeUnit minUnit = 0, string? collectionSeparator = ", ", bool toWords = false) { } public static string ToAge(this System.TimeSpan timeSpan, System.Globalization.CultureInfo? culture = null, Humanizer.TimeUnit maxUnit = 7, bool toWords = false) { } } public enum TimeUnit { Millisecond = 0, Second = 1, Minute = 2, Hour = 3, Day = 4, Week = 5, Month = 6, Year = 7, } public static class TimeUnitToSymbolExtensions { public static string ToSymbol(this Humanizer.TimeUnit unit, System.Globalization.CultureInfo? culture = null) { } } public static class To { public static Humanizer.ICulturedStringTransformer LowerCase { get; } public static Humanizer.ICulturedStringTransformer SentenceCase { get; } public static Humanizer.ICulturedStringTransformer TitleCase { get; } public static Humanizer.ICulturedStringTransformer UpperCase { get; } public static string Transform(this string input, params Humanizer.IStringTransformer[] transformers) { } public static string Transform(this string input, System.Globalization.CultureInfo culture, params Humanizer.ICulturedStringTransformer[] transformers) { } } public static class ToQuantityExtensions { public static string ToQuantity(this string input, double quantity) { } public static string ToQuantity(this string input, int quantity, Humanizer.ShowQuantityAs showQuantityAs = 1) { } public static string ToQuantity(this string input, long quantity, Humanizer.ShowQuantityAs showQuantityAs = 1) { } public static string ToQuantity(this string input, double quantity, string? format = null, System.IFormatProvider? formatProvider = null) { } public static string ToQuantity(this string input, int quantity, string? format, System.IFormatProvider? formatProvider = null) { } public static string ToQuantity(this string input, long quantity, string? format, System.IFormatProvider? formatProvider = null) { } } public static class TruncateExtensions { [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("input")] public static string? Truncate(this string? input, int length) { } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("input")] public static string? Truncate(this string? input, int length, Humanizer.ITruncator truncator, Humanizer.TruncateFrom from = 1) { } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("input")] public static string? Truncate(this string? input, int length, string? truncationString, Humanizer.TruncateFrom from = 1) { } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("input")] public static string? Truncate(this string? input, int length, string? truncationString, Humanizer.ITruncator truncator, Humanizer.TruncateFrom from = 1) { } } public enum TruncateFrom { Left = 0, Right = 1, } public static class Truncator { public static Humanizer.ITruncator DynamicLengthAndPreserveWords { get; } public static Humanizer.ITruncator DynamicNumberOfCharactersAndPreserveWords { get; } public static Humanizer.ITruncator FixedLength { get; } public static Humanizer.ITruncator FixedNumberOfCharacters { get; } public static Humanizer.ITruncator FixedNumberOfWords { get; } } public static class TupleizeExtensions { public static string Tupleize(this int input) { } } public static class Vocabularies { public static Humanizer.Vocabulary Default { get; } } public class Vocabulary { public void AddIrregular(string singular, string plural, bool matchEnding = true) { } public void AddPlural(string rule, string replacement) { } public void AddSingular(string rule, string replacement) { } public void AddUncountable(string word) { } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("word")] public string? Pluralize(string? word, bool inputIsKnownToBeSingular = true) { } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("word")] public string? Singularize(string? word, bool inputIsKnownToBePlural = true, bool skipSimpleWords = false) { } } public enum WordForm { Normal = 0, Abbreviation = 1, Eifeler = 2, } public static class WordsToNumberExtension { public static int ToNumber(this string words, System.Globalization.CultureInfo culture) { } public static bool TryToNumber(this string words, out int parsedNumber, System.Globalization.CultureInfo culture) { } public static bool TryToNumber(this string words, out int parsedNumber, System.Globalization.CultureInfo culture, out string? unrecognizedWord) { } } } ================================================ FILE: tests/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.Approve_Public_Api.Net4_8.verified.txt ================================================ [assembly: System.Resources.NeutralResourcesLanguage("en")] [assembly: System.Runtime.Versioning.TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName=".NET Framework 4.8")] namespace Humanizer { public class ByteRate { public ByteRate(Humanizer.ByteSize size, System.TimeSpan interval) { } public System.TimeSpan Interval { get; } public Humanizer.ByteSize Size { get; } public string Humanize(Humanizer.TimeUnit timeUnit = 1) { } public string Humanize(string? format, Humanizer.TimeUnit timeUnit = 1, System.Globalization.CultureInfo? culture = null) { } } public struct ByteSize : System.IComparable, System.IComparable, System.IEquatable, System.IFormattable { public const string Bit = "bit"; public const string BitSymbol = "b"; public const long BitsInByte = 8; public const string Byte = "byte"; public const string ByteSymbol = "B"; public const long BytesInGigabyte = 1073741824; public const long BytesInKilobyte = 1024; public const long BytesInMegabyte = 1048576; public const long BytesInTerabyte = 1099511627776; public const string Gigabyte = "gigabyte"; public const string GigabyteSymbol = "GB"; public const string Kilobyte = "kilobyte"; public const string KilobyteSymbol = "KB"; public const string Megabyte = "megabyte"; public const string MegabyteSymbol = "MB"; public const string Terabyte = "terabyte"; public const string TerabyteSymbol = "TB"; public static readonly Humanizer.ByteSize MaxValue; public static readonly Humanizer.ByteSize MinValue; public ByteSize(double byteSize) { } public long Bits { get; } public double Bytes { get; } public double Gigabytes { get; } public double Kilobytes { get; } public string LargestWholeNumberFullWord { get; } public string LargestWholeNumberSymbol { get; } public double LargestWholeNumberValue { get; } public double Megabytes { get; } public double Terabytes { get; } public Humanizer.ByteSize Add(Humanizer.ByteSize bs) { } public Humanizer.ByteSize AddBits(long value) { } public Humanizer.ByteSize AddBytes(double value) { } public Humanizer.ByteSize AddGigabytes(double value) { } public Humanizer.ByteSize AddKilobytes(double value) { } public Humanizer.ByteSize AddMegabytes(double value) { } public Humanizer.ByteSize AddTerabytes(double value) { } public int CompareTo(Humanizer.ByteSize other) { } public int CompareTo(object? obj) { } public bool Equals(Humanizer.ByteSize value) { } public override bool Equals(object? value) { } public override int GetHashCode() { } public string GetLargestWholeNumberFullWord(System.IFormatProvider? provider = null) { } public string GetLargestWholeNumberSymbol(System.IFormatProvider? provider = null) { } public Humanizer.ByteSize Subtract(Humanizer.ByteSize bs) { } public string ToFullWords(string? format = null, System.IFormatProvider? provider = null) { } public override string ToString() { } public string ToString(System.IFormatProvider? provider) { } public string ToString(string? format) { } public string ToString(string? format, System.IFormatProvider? provider) { } public static Humanizer.ByteSize FromBits(long value) { } public static Humanizer.ByteSize FromBytes(double value) { } public static Humanizer.ByteSize FromGigabytes(double value) { } public static Humanizer.ByteSize FromKilobytes(double value) { } public static Humanizer.ByteSize FromMegabytes(double value) { } public static Humanizer.ByteSize FromTerabytes(double value) { } public static Humanizer.ByteSize Parse(string s) { } public static Humanizer.ByteSize Parse(string s, System.IFormatProvider? formatProvider) { } public static bool TryParse(System.ReadOnlySpan s, out Humanizer.ByteSize result) { } public static bool TryParse(string? s, out Humanizer.ByteSize result) { } public static bool TryParse(System.ReadOnlySpan s, System.IFormatProvider? formatProvider, out Humanizer.ByteSize result) { } public static bool TryParse(string? s, System.IFormatProvider? formatProvider, out Humanizer.ByteSize result) { } public static bool operator !=(Humanizer.ByteSize b1, Humanizer.ByteSize b2) { } public static Humanizer.ByteSize operator +(Humanizer.ByteSize b1, Humanizer.ByteSize b2) { } public static Humanizer.ByteSize operator ++(Humanizer.ByteSize b) { } public static Humanizer.ByteSize operator -(Humanizer.ByteSize b) { } public static Humanizer.ByteSize operator -(Humanizer.ByteSize b1, Humanizer.ByteSize b2) { } public static Humanizer.ByteSize operator --(Humanizer.ByteSize b) { } public static bool operator <(Humanizer.ByteSize b1, Humanizer.ByteSize b2) { } public static bool operator <=(Humanizer.ByteSize b1, Humanizer.ByteSize b2) { } public static bool operator ==(Humanizer.ByteSize b1, Humanizer.ByteSize b2) { } public static bool operator >(Humanizer.ByteSize b1, Humanizer.ByteSize b2) { } public static bool operator >=(Humanizer.ByteSize b1, Humanizer.ByteSize b2) { } } public static class ByteSizeExtensions { public static Humanizer.ByteSize Bits(this byte input) { } public static Humanizer.ByteSize Bits(this int input) { } public static Humanizer.ByteSize Bits(this long input) { } public static Humanizer.ByteSize Bits(this sbyte input) { } public static Humanizer.ByteSize Bits(this short input) { } public static Humanizer.ByteSize Bits(this uint input) { } public static Humanizer.ByteSize Bits(this ushort input) { } public static Humanizer.ByteSize Bytes(this byte input) { } public static Humanizer.ByteSize Bytes(this double input) { } public static Humanizer.ByteSize Bytes(this int input) { } public static Humanizer.ByteSize Bytes(this long input) { } public static Humanizer.ByteSize Bytes(this sbyte input) { } public static Humanizer.ByteSize Bytes(this short input) { } public static Humanizer.ByteSize Bytes(this uint input) { } public static Humanizer.ByteSize Bytes(this ushort input) { } public static Humanizer.ByteSize Gigabytes(this byte input) { } public static Humanizer.ByteSize Gigabytes(this double input) { } public static Humanizer.ByteSize Gigabytes(this int input) { } public static Humanizer.ByteSize Gigabytes(this long input) { } public static Humanizer.ByteSize Gigabytes(this sbyte input) { } public static Humanizer.ByteSize Gigabytes(this short input) { } public static Humanizer.ByteSize Gigabytes(this uint input) { } public static Humanizer.ByteSize Gigabytes(this ushort input) { } public static string Humanize(this Humanizer.ByteSize input, System.IFormatProvider formatProvider) { } public static string Humanize(this Humanizer.ByteSize input, string? format = null) { } public static string Humanize(this Humanizer.ByteSize input, string? format, System.IFormatProvider? formatProvider) { } public static Humanizer.ByteSize Kilobytes(this byte input) { } public static Humanizer.ByteSize Kilobytes(this double input) { } public static Humanizer.ByteSize Kilobytes(this int input) { } public static Humanizer.ByteSize Kilobytes(this long input) { } public static Humanizer.ByteSize Kilobytes(this sbyte input) { } public static Humanizer.ByteSize Kilobytes(this short input) { } public static Humanizer.ByteSize Kilobytes(this uint input) { } public static Humanizer.ByteSize Kilobytes(this ushort input) { } public static Humanizer.ByteSize Megabytes(this byte input) { } public static Humanizer.ByteSize Megabytes(this double input) { } public static Humanizer.ByteSize Megabytes(this int input) { } public static Humanizer.ByteSize Megabytes(this long input) { } public static Humanizer.ByteSize Megabytes(this sbyte input) { } public static Humanizer.ByteSize Megabytes(this short input) { } public static Humanizer.ByteSize Megabytes(this uint input) { } public static Humanizer.ByteSize Megabytes(this ushort input) { } public static Humanizer.ByteRate Per(this Humanizer.ByteSize size, System.TimeSpan interval) { } public static Humanizer.ByteSize Terabytes(this byte input) { } public static Humanizer.ByteSize Terabytes(this double input) { } public static Humanizer.ByteSize Terabytes(this int input) { } public static Humanizer.ByteSize Terabytes(this long input) { } public static Humanizer.ByteSize Terabytes(this sbyte input) { } public static Humanizer.ByteSize Terabytes(this short input) { } public static Humanizer.ByteSize Terabytes(this uint input) { } public static Humanizer.ByteSize Terabytes(this ushort input) { } } public static class CasingExtensions { public static string ApplyCase(this string input, Humanizer.LetterCasing casing) { } } public enum ClockNotationRounding { None = 0, NearestFiveMinutes = 1, } public static class CollectionHumanizeExtensions { public static string Humanize(this System.Collections.Generic.IEnumerable collection) { } public static string Humanize(this System.Collections.Generic.IEnumerable collection, System.Func displayFormatter) { } public static string Humanize(this System.Collections.Generic.IEnumerable collection, System.Func displayFormatter) { } public static string Humanize(this System.Collections.Generic.IEnumerable collection, string separator) { } public static string Humanize(this System.Collections.Generic.IEnumerable collection, System.Func displayFormatter, string separator) { } public static string Humanize(this System.Collections.Generic.IEnumerable collection, System.Func displayFormatter, string separator) { } } public static class Configurator { public static Humanizer.LocaliserRegistry CollectionFormatters { get; } public static Humanizer.IDateTimeHumanizeStrategy DateTimeHumanizeStrategy { get; set; } public static Humanizer.IDateTimeOffsetHumanizeStrategy DateTimeOffsetHumanizeStrategy { get; set; } public static Humanizer.LocaliserRegistry DateToOrdinalWordsConverters { get; } public static Humanizer.LocaliserRegistry Formatters { get; } public static Humanizer.LocaliserRegistry NumberToWordsConverters { get; } public static Humanizer.LocaliserRegistry Ordinalizers { get; } public static void UseEnumDescriptionPropertyLocator(System.Func func) { } } public enum DataUnit { Bit = 0, Byte = 1, Kilobyte = 2, Megabyte = 3, Gigabyte = 4, Terabyte = 5, } public static class DateHumanizeExtensions { public static string Humanize(this System.DateTimeOffset input, System.DateTimeOffset? dateToCompareAgainst = default, System.Globalization.CultureInfo? culture = null) { } public static string Humanize(this System.DateTimeOffset? input, System.DateTimeOffset? dateToCompareAgainst = default, System.Globalization.CultureInfo? culture = null) { } public static string Humanize(this System.DateTime input, bool? utcDate = default, System.DateTime? dateToCompareAgainst = default, System.Globalization.CultureInfo? culture = null) { } public static string Humanize(this System.DateTime? input, bool? utcDate = default, System.DateTime? dateToCompareAgainst = default, System.Globalization.CultureInfo? culture = null) { } } public static class DateToOrdinalWordsExtensions { public static string ToOrdinalWords(this System.DateTime input) { } public static string ToOrdinalWords(this System.DateTime input, Humanizer.GrammaticalCase grammaticalCase) { } } public class DefaultDateTimeHumanizeStrategy : Humanizer.IDateTimeHumanizeStrategy { public DefaultDateTimeHumanizeStrategy() { } public string Humanize(System.DateTime input, System.DateTime comparisonBase, System.Globalization.CultureInfo? culture) { } } public class DefaultDateTimeOffsetHumanizeStrategy : Humanizer.IDateTimeOffsetHumanizeStrategy { public DefaultDateTimeOffsetHumanizeStrategy() { } public string Humanize(System.DateTimeOffset input, System.DateTimeOffset comparisonBase, System.Globalization.CultureInfo? culture) { } } public class DefaultFormatter : Humanizer.IFormatter { public DefaultFormatter(System.Globalization.CultureInfo culture) { } public DefaultFormatter(string localeCode) { } protected System.Globalization.CultureInfo Culture { get; } public virtual string DataUnitHumanize(Humanizer.DataUnit dataUnit, double count, bool toSymbol = true) { } public virtual string DateHumanize(Humanizer.TimeUnit timeUnit, Humanizer.Tense timeUnitTense, int unit) { } public virtual string DateHumanize_Never() { } public virtual string DateHumanize_Now() { } protected virtual string Format(string resourceKey) { } protected virtual string Format(Humanizer.TimeUnit unit, string resourceKey, int number, bool toWords = false) { } protected virtual string GetResourceKey(string resourceKey) { } protected virtual string GetResourceKey(string resourceKey, int number) { } protected virtual string NumberToWords(Humanizer.TimeUnit unit, int number, System.Globalization.CultureInfo culture) { } public virtual string TimeSpanHumanize(Humanizer.TimeUnit timeUnit, int unit, bool toWords = false) { } public virtual string TimeSpanHumanize_Age() { } public virtual string TimeSpanHumanize_Zero() { } public virtual string TimeUnitHumanize(Humanizer.TimeUnit timeUnit) { } } public class DynamicNumberOfCharactersAndPreserveWordsTruncator : Humanizer.ITruncator { public DynamicNumberOfCharactersAndPreserveWordsTruncator() { } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("value")] public string? Truncate(string? value, int totalLength, string? delimiter, Humanizer.TruncateFrom truncateFrom = 1) { } } public static class EnglishArticle { public static string[] AppendArticlePrefix(string[] items) { } public static string[] PrependArticleSuffix(string[] appended) { } } public static class EnumDehumanizeExtensions { public static System.Enum DehumanizeTo(this string input, System.Type targetEnum, Humanizer.OnNoMatch onNoMatch = 0) { } public static TTargetEnum DehumanizeTo(this string input) where TTargetEnum : struct, System.Enum { } public static TTargetEnum? DehumanizeTo(this string input, Humanizer.OnNoMatch onNoMatch = 0) where TTargetEnum : struct, System.Enum { } } public static class EnumHumanizeExtensions { public static string Humanize(this T input) where T : struct, System.Enum { } public static string Humanize(this T input, Humanizer.LetterCasing casing) where T : struct, System.Enum { } } public enum GrammaticalCase { Nominative = 0, Genitive = 1, Dative = 2, Accusative = 3, Instrumental = 4, Prepositional = 5, } public enum GrammaticalGender { Masculine = 0, Feminine = 1, Neuter = 2, } public static class HeadingExtensions { public static double FromAbbreviatedHeading(this string heading) { } public static double FromAbbreviatedHeading(this string heading, System.Globalization.CultureInfo? culture = null) { } public static double FromHeadingArrow(this char heading) { } public static double FromHeadingArrow(this string heading) { } public static string ToHeading(this double heading, Humanizer.HeadingStyle style = 0, System.Globalization.CultureInfo? culture = null) { } public static char ToHeadingArrow(this double heading) { } } public enum HeadingStyle { Abbreviated = 0, Full = 1, } public interface ICollectionFormatter { string Humanize(System.Collections.Generic.IEnumerable collection); string Humanize(System.Collections.Generic.IEnumerable collection, System.Func objectFormatter); string Humanize(System.Collections.Generic.IEnumerable collection, System.Func objectFormatter); string Humanize(System.Collections.Generic.IEnumerable collection, string separator); string Humanize(System.Collections.Generic.IEnumerable collection, System.Func objectFormatter, string separator); string Humanize(System.Collections.Generic.IEnumerable collection, System.Func objectFormatter, string separator); } public interface ICulturedStringTransformer : Humanizer.IStringTransformer { string Transform(string input, System.Globalization.CultureInfo culture); } public interface IDateTimeHumanizeStrategy { string Humanize(System.DateTime input, System.DateTime comparisonBase, System.Globalization.CultureInfo? culture); } public interface IDateTimeOffsetHumanizeStrategy { string Humanize(System.DateTimeOffset input, System.DateTimeOffset comparisonBase, System.Globalization.CultureInfo? culture); } public interface IDateToOrdinalWordConverter { string Convert(System.DateTime date); string Convert(System.DateTime date, Humanizer.GrammaticalCase grammaticalCase); } public interface IFormatter { string DataUnitHumanize(Humanizer.DataUnit dataUnit, double count, bool toSymbol = true); string DateHumanize(Humanizer.TimeUnit timeUnit, Humanizer.Tense timeUnitTense, int unit); string DateHumanize_Never(); string DateHumanize_Now(); string TimeSpanHumanize(Humanizer.TimeUnit timeUnit, int unit, bool toWords = false); string TimeSpanHumanize_Age(); string TimeSpanHumanize_Zero(); string TimeUnitHumanize(Humanizer.TimeUnit timeUnit); } public interface INumberToWordsConverter { string Convert(long number); string Convert(long number, Humanizer.WordForm wordForm); string Convert(long number, bool addAnd); string Convert(long number, Humanizer.GrammaticalGender gender, bool addAnd = true); string Convert(long number, bool addAnd, Humanizer.WordForm wordForm); string Convert(long number, Humanizer.WordForm wordForm, Humanizer.GrammaticalGender gender, bool addAnd = true); string ConvertToOrdinal(int number); string ConvertToOrdinal(int number, Humanizer.GrammaticalGender gender); string ConvertToOrdinal(int number, Humanizer.WordForm wordForm); string ConvertToOrdinal(int number, Humanizer.GrammaticalGender gender, Humanizer.WordForm wordForm); string ConvertToTuple(int number); } public interface IOrdinalizer { string Convert(int number, string numberString); string Convert(int number, string numberString, Humanizer.GrammaticalGender gender); string Convert(int number, string numberString, Humanizer.WordForm wordForm); string Convert(int number, string numberString, Humanizer.GrammaticalGender gender, Humanizer.WordForm wordForm); } public interface IStringTransformer { string Transform(string input); } public interface ITruncator { [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("value")] string? Truncate(string? value, int length, string? truncationString, Humanizer.TruncateFrom truncateFrom = 1); } public interface IWordsToNumberConverter { int Convert(string words); bool TryConvert(string words, out int parsedValue); bool TryConvert(string words, out int parsedValue, out string? unrecognizedNumber); } public class In { public In() { } public static System.DateTime April { get; } public static System.DateTime August { get; } public static System.DateTime December { get; } public static System.DateTime February { get; } public static System.DateTime January { get; } public static System.DateTime July { get; } public static System.DateTime June { get; } public static System.DateTime March { get; } public static System.DateTime May { get; } public static System.DateTime November { get; } public static System.DateTime October { get; } public static System.DateTime September { get; } public static System.DateTime AprilOf(int year) { } public static System.DateTime AugustOf(int year) { } public static System.DateTime DecemberOf(int year) { } public static System.DateTime FebruaryOf(int year) { } public static System.DateTime JanuaryOf(int year) { } public static System.DateTime JulyOf(int year) { } public static System.DateTime JuneOf(int year) { } public static System.DateTime MarchOf(int year) { } public static System.DateTime MayOf(int year) { } public static System.DateTime NovemberOf(int year) { } public static System.DateTime OctoberOf(int year) { } public static System.DateTime SeptemberOf(int year) { } public static System.DateTime TheYear(int year) { } public static class Eight { public static System.DateTime Days { get; } public static System.DateTime Hours { get; } public static System.DateTime Minutes { get; } public static System.DateTime Months { get; } public static System.DateTime Seconds { get; } public static System.DateTime Weeks { get; } public static System.DateTime Years { get; } public static System.DateTime DaysFrom(System.DateTime date) { } public static System.DateTime HoursFrom(System.DateTime date) { } public static System.DateTime MinutesFrom(System.DateTime date) { } public static System.DateTime MonthsFrom(System.DateTime date) { } public static System.DateTime SecondsFrom(System.DateTime date) { } public static System.DateTime WeeksFrom(System.DateTime date) { } public static System.DateTime YearsFrom(System.DateTime date) { } } public static class Five { public static System.DateTime Days { get; } public static System.DateTime Hours { get; } public static System.DateTime Minutes { get; } public static System.DateTime Months { get; } public static System.DateTime Seconds { get; } public static System.DateTime Weeks { get; } public static System.DateTime Years { get; } public static System.DateTime DaysFrom(System.DateTime date) { } public static System.DateTime HoursFrom(System.DateTime date) { } public static System.DateTime MinutesFrom(System.DateTime date) { } public static System.DateTime MonthsFrom(System.DateTime date) { } public static System.DateTime SecondsFrom(System.DateTime date) { } public static System.DateTime WeeksFrom(System.DateTime date) { } public static System.DateTime YearsFrom(System.DateTime date) { } } public static class Four { public static System.DateTime Days { get; } public static System.DateTime Hours { get; } public static System.DateTime Minutes { get; } public static System.DateTime Months { get; } public static System.DateTime Seconds { get; } public static System.DateTime Weeks { get; } public static System.DateTime Years { get; } public static System.DateTime DaysFrom(System.DateTime date) { } public static System.DateTime HoursFrom(System.DateTime date) { } public static System.DateTime MinutesFrom(System.DateTime date) { } public static System.DateTime MonthsFrom(System.DateTime date) { } public static System.DateTime SecondsFrom(System.DateTime date) { } public static System.DateTime WeeksFrom(System.DateTime date) { } public static System.DateTime YearsFrom(System.DateTime date) { } } public static class Nine { public static System.DateTime Days { get; } public static System.DateTime Hours { get; } public static System.DateTime Minutes { get; } public static System.DateTime Months { get; } public static System.DateTime Seconds { get; } public static System.DateTime Weeks { get; } public static System.DateTime Years { get; } public static System.DateTime DaysFrom(System.DateTime date) { } public static System.DateTime HoursFrom(System.DateTime date) { } public static System.DateTime MinutesFrom(System.DateTime date) { } public static System.DateTime MonthsFrom(System.DateTime date) { } public static System.DateTime SecondsFrom(System.DateTime date) { } public static System.DateTime WeeksFrom(System.DateTime date) { } public static System.DateTime YearsFrom(System.DateTime date) { } } public static class One { public static System.DateTime Day { get; } public static System.DateTime Hour { get; } public static System.DateTime Minute { get; } public static System.DateTime Month { get; } public static System.DateTime Second { get; } public static System.DateTime Week { get; } public static System.DateTime Year { get; } public static System.DateTime DayFrom(System.DateTime date) { } public static System.DateTime HourFrom(System.DateTime date) { } public static System.DateTime MinuteFrom(System.DateTime date) { } public static System.DateTime MonthFrom(System.DateTime date) { } public static System.DateTime SecondFrom(System.DateTime date) { } public static System.DateTime WeekFrom(System.DateTime date) { } public static System.DateTime YearFrom(System.DateTime date) { } } public static class Seven { public static System.DateTime Days { get; } public static System.DateTime Hours { get; } public static System.DateTime Minutes { get; } public static System.DateTime Months { get; } public static System.DateTime Seconds { get; } public static System.DateTime Weeks { get; } public static System.DateTime Years { get; } public static System.DateTime DaysFrom(System.DateTime date) { } public static System.DateTime HoursFrom(System.DateTime date) { } public static System.DateTime MinutesFrom(System.DateTime date) { } public static System.DateTime MonthsFrom(System.DateTime date) { } public static System.DateTime SecondsFrom(System.DateTime date) { } public static System.DateTime WeeksFrom(System.DateTime date) { } public static System.DateTime YearsFrom(System.DateTime date) { } } public static class Six { public static System.DateTime Days { get; } public static System.DateTime Hours { get; } public static System.DateTime Minutes { get; } public static System.DateTime Months { get; } public static System.DateTime Seconds { get; } public static System.DateTime Weeks { get; } public static System.DateTime Years { get; } public static System.DateTime DaysFrom(System.DateTime date) { } public static System.DateTime HoursFrom(System.DateTime date) { } public static System.DateTime MinutesFrom(System.DateTime date) { } public static System.DateTime MonthsFrom(System.DateTime date) { } public static System.DateTime SecondsFrom(System.DateTime date) { } public static System.DateTime WeeksFrom(System.DateTime date) { } public static System.DateTime YearsFrom(System.DateTime date) { } } public static class Ten { public static System.DateTime Days { get; } public static System.DateTime Hours { get; } public static System.DateTime Minutes { get; } public static System.DateTime Months { get; } public static System.DateTime Seconds { get; } public static System.DateTime Weeks { get; } public static System.DateTime Years { get; } public static System.DateTime DaysFrom(System.DateTime date) { } public static System.DateTime HoursFrom(System.DateTime date) { } public static System.DateTime MinutesFrom(System.DateTime date) { } public static System.DateTime MonthsFrom(System.DateTime date) { } public static System.DateTime SecondsFrom(System.DateTime date) { } public static System.DateTime WeeksFrom(System.DateTime date) { } public static System.DateTime YearsFrom(System.DateTime date) { } } public static class Three { public static System.DateTime Days { get; } public static System.DateTime Hours { get; } public static System.DateTime Minutes { get; } public static System.DateTime Months { get; } public static System.DateTime Seconds { get; } public static System.DateTime Weeks { get; } public static System.DateTime Years { get; } public static System.DateTime DaysFrom(System.DateTime date) { } public static System.DateTime HoursFrom(System.DateTime date) { } public static System.DateTime MinutesFrom(System.DateTime date) { } public static System.DateTime MonthsFrom(System.DateTime date) { } public static System.DateTime SecondsFrom(System.DateTime date) { } public static System.DateTime WeeksFrom(System.DateTime date) { } public static System.DateTime YearsFrom(System.DateTime date) { } } public static class Two { public static System.DateTime Days { get; } public static System.DateTime Hours { get; } public static System.DateTime Minutes { get; } public static System.DateTime Months { get; } public static System.DateTime Seconds { get; } public static System.DateTime Weeks { get; } public static System.DateTime Years { get; } public static System.DateTime DaysFrom(System.DateTime date) { } public static System.DateTime HoursFrom(System.DateTime date) { } public static System.DateTime MinutesFrom(System.DateTime date) { } public static System.DateTime MonthsFrom(System.DateTime date) { } public static System.DateTime SecondsFrom(System.DateTime date) { } public static System.DateTime WeeksFrom(System.DateTime date) { } public static System.DateTime YearsFrom(System.DateTime date) { } } } public static class InflectorExtensions { public static string Camelize(this string input) { } public static string Dasherize(this string underscoredWord) { } public static string Hyphenate(this string underscoredWord) { } public static string Kebaberize(this string input) { } public static string Pascalize(this string input) { } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("word")] public static string? Pluralize(this string? word, bool inputIsKnownToBeSingular = true) { } public static string Singularize(this string word, bool inputIsKnownToBePlural = true, bool skipSimpleWords = false) { } public static string Titleize(this string input) { } public static string Underscore(this string input) { } } public enum LetterCasing { Title = 0, AllCaps = 1, LowerCase = 2, Sentence = 3, } public class LocaliserRegistry where TLocaliser : class { public LocaliserRegistry(System.Func defaultLocaliser) { } public LocaliserRegistry(TLocaliser defaultLocaliser) { } public void Register(string localeCode, System.Func localiser) { } public void Register(string localeCode, TLocaliser localiser) { } public TLocaliser ResolveForCulture(System.Globalization.CultureInfo? culture) { } public TLocaliser ResolveForUiCulture() { } } public static class MetricNumeralExtensions { public static double FromMetric(this string input) { } public static string ToMetric(this double input, Humanizer.MetricNumeralFormats? formats = default, int? decimals = default) { } public static string ToMetric(this int input, Humanizer.MetricNumeralFormats? formats = default, int? decimals = default) { } public static string ToMetric(this long input, Humanizer.MetricNumeralFormats? formats = default, int? decimals = default) { } } [System.Flags] public enum MetricNumeralFormats { UseLongScaleWord = 1, UseName = 2, UseShortScaleWord = 4, WithSpace = 8, } public class NoMatchFoundException : System.Exception { public NoMatchFoundException() { } public NoMatchFoundException(string message) { } public NoMatchFoundException(string message, System.Exception inner) { } } public static class NumberToNumberExtensions { public static double Billions(this double input) { } public static int Billions(this int input) { } public static long Billions(this long input) { } public static uint Billions(this uint input) { } public static ulong Billions(this ulong input) { } public static double Hundreds(this double input) { } public static int Hundreds(this int input) { } public static long Hundreds(this long input) { } public static uint Hundreds(this uint input) { } public static ulong Hundreds(this ulong input) { } public static double Millions(this double input) { } public static int Millions(this int input) { } public static long Millions(this long input) { } public static uint Millions(this uint input) { } public static ulong Millions(this ulong input) { } public static double Tens(this double input) { } public static int Tens(this int input) { } public static long Tens(this long input) { } public static uint Tens(this uint input) { } public static ulong Tens(this ulong input) { } public static double Thousands(this double input) { } public static int Thousands(this int input) { } public static long Thousands(this long input) { } public static uint Thousands(this uint input) { } public static ulong Thousands(this ulong input) { } } public static class NumberToTimeSpanExtensions { public static System.TimeSpan Days(this byte days) { } public static System.TimeSpan Days(this double days) { } public static System.TimeSpan Days(this int days) { } public static System.TimeSpan Days(this long days) { } public static System.TimeSpan Days(this sbyte days) { } public static System.TimeSpan Days(this short days) { } public static System.TimeSpan Days(this uint days) { } public static System.TimeSpan Days(this ulong days) { } public static System.TimeSpan Days(this ushort days) { } public static System.TimeSpan Hours(this byte hours) { } public static System.TimeSpan Hours(this double hours) { } public static System.TimeSpan Hours(this int hours) { } public static System.TimeSpan Hours(this long hours) { } public static System.TimeSpan Hours(this sbyte hours) { } public static System.TimeSpan Hours(this short hours) { } public static System.TimeSpan Hours(this uint hours) { } public static System.TimeSpan Hours(this ulong hours) { } public static System.TimeSpan Hours(this ushort hours) { } public static System.TimeSpan Milliseconds(this byte ms) { } public static System.TimeSpan Milliseconds(this double ms) { } public static System.TimeSpan Milliseconds(this int ms) { } public static System.TimeSpan Milliseconds(this long ms) { } public static System.TimeSpan Milliseconds(this sbyte ms) { } public static System.TimeSpan Milliseconds(this short ms) { } public static System.TimeSpan Milliseconds(this uint ms) { } public static System.TimeSpan Milliseconds(this ulong ms) { } public static System.TimeSpan Milliseconds(this ushort ms) { } public static System.TimeSpan Minutes(this byte minutes) { } public static System.TimeSpan Minutes(this double minutes) { } public static System.TimeSpan Minutes(this int minutes) { } public static System.TimeSpan Minutes(this long minutes) { } public static System.TimeSpan Minutes(this sbyte minutes) { } public static System.TimeSpan Minutes(this short minutes) { } public static System.TimeSpan Minutes(this uint minutes) { } public static System.TimeSpan Minutes(this ulong minutes) { } public static System.TimeSpan Minutes(this ushort minutes) { } public static System.TimeSpan Seconds(this byte seconds) { } public static System.TimeSpan Seconds(this double seconds) { } public static System.TimeSpan Seconds(this int seconds) { } public static System.TimeSpan Seconds(this long seconds) { } public static System.TimeSpan Seconds(this sbyte seconds) { } public static System.TimeSpan Seconds(this short seconds) { } public static System.TimeSpan Seconds(this uint seconds) { } public static System.TimeSpan Seconds(this ulong seconds) { } public static System.TimeSpan Seconds(this ushort seconds) { } public static System.TimeSpan Weeks(this byte input) { } public static System.TimeSpan Weeks(this double input) { } public static System.TimeSpan Weeks(this int input) { } public static System.TimeSpan Weeks(this long input) { } public static System.TimeSpan Weeks(this sbyte input) { } public static System.TimeSpan Weeks(this short input) { } public static System.TimeSpan Weeks(this uint input) { } public static System.TimeSpan Weeks(this ulong input) { } public static System.TimeSpan Weeks(this ushort input) { } } public static class NumberToWordsExtension { public static string ToOrdinalWords(this int number, System.Globalization.CultureInfo? culture = null) { } public static string ToOrdinalWords(this int number, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo? culture = null) { } public static string ToOrdinalWords(this int number, Humanizer.WordForm wordForm, System.Globalization.CultureInfo? culture = null) { } public static string ToOrdinalWords(this int number, Humanizer.GrammaticalGender gender, Humanizer.WordForm wordForm, System.Globalization.CultureInfo? culture = null) { } public static string ToTuple(this int number, System.Globalization.CultureInfo? culture = null) { } public static string ToWords(this int number, System.Globalization.CultureInfo? culture = null) { } public static string ToWords(this int number, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo? culture = null) { } public static string ToWords(this int number, Humanizer.WordForm wordForm, System.Globalization.CultureInfo? culture = null) { } public static string ToWords(this int number, bool addAnd, System.Globalization.CultureInfo? culture = null) { } public static string ToWords(this long number, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo? culture = null) { } public static string ToWords(this long number, System.Globalization.CultureInfo? culture = null, bool addAnd = true) { } public static string ToWords(this int number, Humanizer.WordForm wordForm, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo? culture = null) { } public static string ToWords(this int number, bool addAnd, Humanizer.WordForm wordForm, System.Globalization.CultureInfo? culture = null) { } public static string ToWords(this long number, Humanizer.WordForm wordForm, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo? culture = null) { } public static string ToWords(this long number, Humanizer.WordForm wordForm, System.Globalization.CultureInfo? culture = null, bool addAnd = false) { } } public class On { public On() { } public class April { public April() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class August { public August() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The31st { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class December { public December() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The31st { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class February { public February() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class January { public January() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The31st { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class July { public July() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The31st { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class June { public June() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class March { public March() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The31st { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class May { public May() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The31st { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class November { public November() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class October { public October() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The31st { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } public class September { public September() { } public static System.DateTime The10th { get; } public static System.DateTime The11th { get; } public static System.DateTime The12th { get; } public static System.DateTime The13th { get; } public static System.DateTime The14th { get; } public static System.DateTime The15th { get; } public static System.DateTime The16th { get; } public static System.DateTime The17th { get; } public static System.DateTime The18th { get; } public static System.DateTime The19th { get; } public static System.DateTime The1st { get; } public static System.DateTime The20th { get; } public static System.DateTime The21st { get; } public static System.DateTime The22nd { get; } public static System.DateTime The23rd { get; } public static System.DateTime The24th { get; } public static System.DateTime The25th { get; } public static System.DateTime The26th { get; } public static System.DateTime The27th { get; } public static System.DateTime The28th { get; } public static System.DateTime The29th { get; } public static System.DateTime The2nd { get; } public static System.DateTime The30th { get; } public static System.DateTime The3rd { get; } public static System.DateTime The4th { get; } public static System.DateTime The5th { get; } public static System.DateTime The6th { get; } public static System.DateTime The7th { get; } public static System.DateTime The8th { get; } public static System.DateTime The9th { get; } public static System.DateTime The(int dayNumber) { } } } public enum OnNoMatch { ThrowsException = 0, ReturnsNull = 1, } public static class OrdinalizeExtensions { public static string Ordinalize(this int number) { } public static string Ordinalize(this string numberString) { } public static string Ordinalize(this int number, Humanizer.GrammaticalGender gender) { } public static string Ordinalize(this int number, Humanizer.WordForm wordForm) { } public static string Ordinalize(this int number, System.Globalization.CultureInfo culture) { } public static string Ordinalize(this string numberString, Humanizer.GrammaticalGender gender) { } public static string Ordinalize(this string numberString, Humanizer.WordForm wordForm) { } public static string Ordinalize(this string numberString, System.Globalization.CultureInfo culture) { } public static string Ordinalize(this int number, Humanizer.GrammaticalGender gender, Humanizer.WordForm wordForm) { } public static string Ordinalize(this int number, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo culture) { } public static string Ordinalize(this int number, System.Globalization.CultureInfo culture, Humanizer.WordForm wordForm) { } public static string Ordinalize(this string numberString, Humanizer.GrammaticalGender gender, Humanizer.WordForm wordForm) { } public static string Ordinalize(this string numberString, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo culture) { } public static string Ordinalize(this string numberString, System.Globalization.CultureInfo culture, Humanizer.WordForm wordForm) { } public static string Ordinalize(this int number, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo culture, Humanizer.WordForm wordForm) { } public static string Ordinalize(this string numberString, Humanizer.GrammaticalGender gender, System.Globalization.CultureInfo culture, Humanizer.WordForm wordForm) { } } public enum Plurality { Singular = 0, Plural = 1, CouldBeEither = 2, } public class PrecisionDateTimeHumanizeStrategy : Humanizer.IDateTimeHumanizeStrategy { public PrecisionDateTimeHumanizeStrategy(double precision = 0.75) { } public string Humanize(System.DateTime input, System.DateTime comparisonBase, System.Globalization.CultureInfo? culture) { } } public class PrecisionDateTimeOffsetHumanizeStrategy : Humanizer.IDateTimeOffsetHumanizeStrategy { public PrecisionDateTimeOffsetHumanizeStrategy(double precision = 0.75) { } public string Humanize(System.DateTimeOffset input, System.DateTimeOffset comparisonBase, System.Globalization.CultureInfo? culture) { } } public static class PrepositionsExtensions { public static System.DateTime At(this System.DateTime date, int hour, int min = 0, int second = 0, int millisecond = 0) { } public static System.DateTime AtMidnight(this System.DateTime date) { } public static System.DateTime AtNoon(this System.DateTime date) { } public static System.DateTime In(this System.DateTime date, int year) { } } public class ResourceKeys { public ResourceKeys() { } public static class DateHumanize { public const string Never = "DateHumanize_Never"; public const string Now = "DateHumanize_Now"; public static string GetResourceKey(Humanizer.TimeUnit timeUnit, Humanizer.Tense timeUnitTense, int count = 1) { } } public static class TimeSpanHumanize { public static string GetResourceKey(Humanizer.TimeUnit unit, int count = 1, bool toWords = false) { } } public static class TimeUnitSymbol { public static string GetResourceKey(Humanizer.TimeUnit unit) { } } } public static class Resources { public static string GetResource(string resourceKey, System.Globalization.CultureInfo? culture = null) { } public static bool TryGetResource(string resourceKey, System.Globalization.CultureInfo? culture, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out string? result) { } } public static class RomanNumeralExtensions { public static int FromRoman(System.ReadOnlySpan input) { } public static int FromRoman(this string input) { } public static string ToRoman(this int input) { } } public enum ShowQuantityAs { None = 0, Numeric = 1, Words = 2, } public static class StringDehumanizeExtensions { public static string Dehumanize(this string input) { } } public static class StringHumanizeExtensions { public static string Humanize(this string input) { } public static string Humanize(this string input, Humanizer.LetterCasing casing) { } } public enum Tense { Future = 0, Past = 1, } public static class TimeSpanHumanizeExtensions { public static string Humanize(this System.TimeSpan timeSpan, int precision = 1, System.Globalization.CultureInfo? culture = null, Humanizer.TimeUnit maxUnit = 5, Humanizer.TimeUnit minUnit = 0, string? collectionSeparator = ", ", bool toWords = false) { } public static string Humanize(this System.TimeSpan timeSpan, int precision, bool countEmptyUnits, System.Globalization.CultureInfo? culture = null, Humanizer.TimeUnit maxUnit = 5, Humanizer.TimeUnit minUnit = 0, string? collectionSeparator = ", ", bool toWords = false) { } public static string ToAge(this System.TimeSpan timeSpan, System.Globalization.CultureInfo? culture = null, Humanizer.TimeUnit maxUnit = 7, bool toWords = false) { } } public enum TimeUnit { Millisecond = 0, Second = 1, Minute = 2, Hour = 3, Day = 4, Week = 5, Month = 6, Year = 7, } public static class TimeUnitToSymbolExtensions { public static string ToSymbol(this Humanizer.TimeUnit unit, System.Globalization.CultureInfo? culture = null) { } } public static class To { public static Humanizer.ICulturedStringTransformer LowerCase { get; } public static Humanizer.ICulturedStringTransformer SentenceCase { get; } public static Humanizer.ICulturedStringTransformer TitleCase { get; } public static Humanizer.ICulturedStringTransformer UpperCase { get; } public static string Transform(this string input, params Humanizer.IStringTransformer[] transformers) { } public static string Transform(this string input, System.Globalization.CultureInfo culture, params Humanizer.ICulturedStringTransformer[] transformers) { } } public static class ToQuantityExtensions { public static string ToQuantity(this string input, double quantity) { } public static string ToQuantity(this string input, int quantity, Humanizer.ShowQuantityAs showQuantityAs = 1) { } public static string ToQuantity(this string input, long quantity, Humanizer.ShowQuantityAs showQuantityAs = 1) { } public static string ToQuantity(this string input, double quantity, string? format = null, System.IFormatProvider? formatProvider = null) { } public static string ToQuantity(this string input, int quantity, string? format, System.IFormatProvider? formatProvider = null) { } public static string ToQuantity(this string input, long quantity, string? format, System.IFormatProvider? formatProvider = null) { } } public static class TruncateExtensions { [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("input")] public static string? Truncate(this string? input, int length) { } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("input")] public static string? Truncate(this string? input, int length, Humanizer.ITruncator truncator, Humanizer.TruncateFrom from = 1) { } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("input")] public static string? Truncate(this string? input, int length, string? truncationString, Humanizer.TruncateFrom from = 1) { } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("input")] public static string? Truncate(this string? input, int length, string? truncationString, Humanizer.ITruncator truncator, Humanizer.TruncateFrom from = 1) { } } public enum TruncateFrom { Left = 0, Right = 1, } public static class Truncator { public static Humanizer.ITruncator DynamicLengthAndPreserveWords { get; } public static Humanizer.ITruncator DynamicNumberOfCharactersAndPreserveWords { get; } public static Humanizer.ITruncator FixedLength { get; } public static Humanizer.ITruncator FixedNumberOfCharacters { get; } public static Humanizer.ITruncator FixedNumberOfWords { get; } } public static class TupleizeExtensions { public static string Tupleize(this int input) { } } public static class Vocabularies { public static Humanizer.Vocabulary Default { get; } } public class Vocabulary { public void AddIrregular(string singular, string plural, bool matchEnding = true) { } public void AddPlural(string rule, string replacement) { } public void AddSingular(string rule, string replacement) { } public void AddUncountable(string word) { } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("word")] public string? Pluralize(string? word, bool inputIsKnownToBeSingular = true) { } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("word")] public string? Singularize(string? word, bool inputIsKnownToBePlural = true, bool skipSimpleWords = false) { } } public enum WordForm { Normal = 0, Abbreviation = 1, Eifeler = 2, } public static class WordsToNumberExtension { public static int ToNumber(this string words, System.Globalization.CultureInfo culture) { } public static bool TryToNumber(this string words, out int parsedNumber, System.Globalization.CultureInfo culture) { } public static bool TryToNumber(this string words, out int parsedNumber, System.Globalization.CultureInfo culture, out string? unrecognizedWord) { } } } ================================================ FILE: tests/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.cs ================================================ using PublicApiGenerator; public class PublicApiApprovalTest { [Fact] public Task Approve_Public_Api() { var publicApi = typeof(StringHumanizeExtensions).Assembly.GeneratePublicApi(); return Verify(publicApi) .ScrubLinesContaining("CommitHash", "RepositoryUrl", "InternalsVisibleTo", "CloudBuildNumber") .UniqueForTargetFrameworkAndVersion(); } } ================================================ FILE: tests/Humanizer.Tests/ArticlePrefixSortTests.cs ================================================ public class ArticlePrefixSortTests { [Theory] [InlineData(new[] { "Ant", "The Theater", "The apple", "Fox", "Bear" }, new[] { "Ant", "The apple", "Bear", "Fox", "The Theater" })] [InlineData(new[] { "An Ant", "The Theater", "the apple", "a Fox", "Bear" }, new[] { "An Ant", "the apple", "Bear", "a Fox", "The Theater" })] [InlineData(new[] { "Ant", "A Theater", "an apple", "Fox", "Bear" }, new[] { "Ant", "an apple", "Bear", "Fox", "A Theater" })] [InlineData(new[] { " Ant ", " A Theater ", " an apple ", " Fox", "Bear " }, new[] { "A Theater", "an apple", "Ant", "Bear", "Fox" })] [InlineData(new[] { "The General Theory of Relativity" }, new[] { "The General Theory of Relativity" })] public void SortStringArrayIgnoringArticlePrefixes(string[] input, string[] expectedOutput) => Assert.Equal(expectedOutput, EnglishArticle.PrependArticleSuffix(EnglishArticle.AppendArticlePrefix(input))); [Fact] public void An_Empty_String_Array_Throws_ArgumentOutOfRangeException() { string[] items = []; void action() => EnglishArticle.AppendArticlePrefix(items); Assert.Throws(action); } } ================================================ FILE: tests/Humanizer.Tests/BitFieldEnumHumanizeTests.cs ================================================ [UseCulture("en")] public class BitFieldEnumHumanizeTests { [Fact] public void CanHumanizeSingleWordDescriptionAttribute() => Assert.Equal(BitFlagEnumTestsResources.MemberWithSingleWordDisplayAttribute, BitFieldEnumUnderTest.RED.Humanize()); [Fact] public void CanHumanizeMultipleWordDescriptionAttribute() => Assert.Equal(BitFlagEnumTestsResources.MemberWithMultipleWordDisplayAttribute, BitFieldEnumUnderTest.DARK_GRAY.Humanize()); [Fact] public void CanHumanizeMultipleValueBitFieldEnum() { var xoredBitFlag = BitFieldEnumUnderTest.RED | BitFieldEnumUnderTest.DARK_GRAY; Assert.Equal(BitFlagEnumTestsResources.ExpectedResultWhenBothValuesXored, xoredBitFlag.Humanize()); } [Fact] public void CanHumanizeShortSingleWordDescriptionAttribute() => Assert.Equal(BitFlagEnumTestsResources.MemberWithSingleWordDisplayAttribute, ShortBitFieldEnumUnderTest.RED.Humanize()); [Fact] public void CanHumanizeShortMultipleWordDescriptionAttribute() => Assert.Equal(BitFlagEnumTestsResources.MemberWithMultipleWordDisplayAttribute, ShortBitFieldEnumUnderTest.DARK_GRAY.Humanize()); [Fact] public void CanHumanizeShortMultipleValueBitFieldEnum() { var xoredBitFlag = ShortBitFieldEnumUnderTest.RED | ShortBitFieldEnumUnderTest.DARK_GRAY; Assert.Equal(BitFlagEnumTestsResources.ExpectedResultWhenBothValuesXored, xoredBitFlag.Humanize()); } [Fact] public void CanHumanizeBitFieldEnumWithZeroValue() => Assert.Equal(BitFlagEnumTestsResources.None, BitFieldEnumUnderTest.NONE.Humanize()); } ================================================ FILE: tests/Humanizer.Tests/BitFieldEnumUnderTest.cs ================================================ using System.ComponentModel.DataAnnotations; [Flags] public enum BitFieldEnumUnderTest : int { [Display(Description = BitFlagEnumTestsResources.None)] NONE = 0, [Display(Description = BitFlagEnumTestsResources.MemberWithSingleWordDisplayAttribute)] RED = 1, [Display(Description = BitFlagEnumTestsResources.MemberWithMultipleWordDisplayAttribute)] DARK_GRAY = 2 } [Flags] public enum ShortBitFieldEnumUnderTest : short { [Display(Description = BitFlagEnumTestsResources.MemberWithSingleWordDisplayAttribute)] RED = 1, [Display(Description = BitFlagEnumTestsResources.MemberWithMultipleWordDisplayAttribute)] DARK_GRAY = 2 } public class BitFlagEnumTestsResources { public const string None = "None"; public const string MemberWithSingleWordDisplayAttribute = "Red"; public const string MemberWithMultipleWordDisplayAttribute = "Dark Gray"; public const string ExpectedResultWhenBothValuesXored = "Red and Dark Gray"; } ================================================ FILE: tests/Humanizer.Tests/Bytes/ArithmeticTests.cs ================================================ public class ArithmeticTests { [Fact] public void Add() { var size1 = ByteSize.FromBytes(1); var result = size1.Add(size1); Assert.Equal(2, result.Bytes); Assert.Equal(16, result.Bits); } [Fact] public void AddBits() { var size = ByteSize .FromBytes(1) .AddBits(8); Assert.Equal(2, size.Bytes); Assert.Equal(16, size.Bits); } [Fact] public void AddBytes() { var size = ByteSize .FromBytes(1) .AddBytes(1); Assert.Equal(2, size.Bytes); Assert.Equal(16, size.Bits); } [Fact] public void AddKilobytes() { var size = ByteSize .FromKilobytes(2) .AddKilobytes(2); Assert.Equal(4 * 1024 * 8, size.Bits); Assert.Equal(4 * 1024, size.Bytes); Assert.Equal(4, size.Kilobytes); } [Fact] public void AddMegabytes() { var size = ByteSize .FromMegabytes(2) .AddMegabytes(2); Assert.Equal(4 * 1024 * 1024 * 8, size.Bits); Assert.Equal(4 * 1024 * 1024, size.Bytes); Assert.Equal(4 * 1024, size.Kilobytes); Assert.Equal(4, size.Megabytes); } [Fact] public void AddGigabytes() { var size = ByteSize .FromGigabytes(2) .AddGigabytes(2); Assert.Equal(4d * 1024 * 1024 * 1024 * 8, size.Bits); Assert.Equal(4d * 1024 * 1024 * 1024, size.Bytes); Assert.Equal(4d * 1024 * 1024, size.Kilobytes); Assert.Equal(4d * 1024, size.Megabytes); Assert.Equal(4d, size.Gigabytes); } [Fact] public void AddTerabytes() { var size = ByteSize .FromTerabytes(2) .AddTerabytes(2); Assert.Equal(4d * 1024 * 1024 * 1024 * 1024 * 8, size.Bits); Assert.Equal(4d * 1024 * 1024 * 1024 * 1024, size.Bytes); Assert.Equal(4d * 1024 * 1024 * 1024, size.Kilobytes); Assert.Equal(4d * 1024 * 1024, size.Megabytes); Assert.Equal(4d * 1024, size.Gigabytes); Assert.Equal(4d, size.Terabytes); } [Fact] public void Subtract() { var size = ByteSize .FromBytes(4) .Subtract(ByteSize.FromBytes(2)); Assert.Equal(16, size.Bits); Assert.Equal(2, size.Bytes); } [Fact] public void IncrementOperator() { var size = ByteSize.FromBytes(2); size++; Assert.Equal(24, size.Bits); Assert.Equal(3, size.Bytes); } [Fact] public void NegativeOperator() { var size = ByteSize.FromBytes(2); size = -size; Assert.Equal(-16, size.Bits); Assert.Equal(-2, size.Bytes); } [Fact] public void DecrementOperator() { var size = ByteSize.FromBytes(2); size--; Assert.Equal(8, size.Bits); Assert.Equal(1, size.Bytes); } [Fact] public void PlusOperator() { var size1 = ByteSize.FromBytes(1); var size2 = ByteSize.FromBytes(1); var result = size1 + size2; Assert.Equal(2, result.Bytes); } [Fact] public void MinusOperator() { var size1 = ByteSize.FromBytes(2); var size2 = ByteSize.FromBytes(1); var result = size1 - size2; Assert.Equal(1, result.Bytes); } } ================================================ FILE: tests/Humanizer.Tests/Bytes/ByteRateTests.cs ================================================ [UseCulture("en")] public class ByteRateTests { [Theory] [InlineData(400, 1, "400 B/s")] [InlineData(4 * 1024, 1, "4 KB/s")] [InlineData(4 * 1024 * 1024, 1, "4 MB/s")] [InlineData(4 * 2 * 1024 * 1024, 2, "4 MB/s")] [InlineData(4 * 1024, 0.1, "40 KB/s")] [InlineData(15 * 60 * 1024 * 1024, 60, "15 MB/s")] public void HumanizesRates(long inputBytes, double perSeconds, string expectedValue) { var size = new ByteSize(inputBytes); var interval = TimeSpan.FromSeconds(perSeconds); var rate = size .Per(interval) .Humanize(); Assert.Equal(expectedValue, rate); } [Theory] [InlineData(1, 1, TimeUnit.Second, "1 MB/s")] [InlineData(1, 60, TimeUnit.Minute, "1 MB/min")] [InlineData(1, 60 * 60, TimeUnit.Hour, "1 MB/h")] [InlineData(10, 1, TimeUnit.Second, "10 MB/s")] [InlineData(10, 60, TimeUnit.Minute, "10 MB/min")] [InlineData(10, 60 * 60, TimeUnit.Hour, "10 MB/h")] [InlineData(1, 10 * 1, TimeUnit.Second, "102.4 KB/s")] [InlineData(1, 10 * 60, TimeUnit.Minute, "102.4 KB/min")] [InlineData(1, 10 * 60 * 60, TimeUnit.Hour, "102.4 KB/h")] public void TimeUnitTests(long megabytes, double measurementIntervalSeconds, TimeUnit displayInterval, string expectedValue) { var size = ByteSize.FromMegabytes(megabytes); var measurementInterval = TimeSpan.FromSeconds(measurementIntervalSeconds); var rate = size.Per(measurementInterval); var text = rate.Humanize(displayInterval); Assert.Equal(expectedValue, text); } [Theory] [InlineData(19854651984, 1, TimeUnit.Second, null, "18.49 GB/s")] [InlineData(19854651984, 1, TimeUnit.Second, "#.##", "18.49 GB/s")] public void FormattedTimeUnitTests(long bytes, int measurementIntervalSeconds, TimeUnit displayInterval, string? format, string expectedValue) { var size = ByteSize.FromBytes(bytes); var measurementInterval = TimeSpan.FromSeconds(measurementIntervalSeconds); var rate = size.Per(measurementInterval); var text = rate.Humanize(format, displayInterval); Assert.Equal(expectedValue, text); } [Theory] [InlineData(TimeUnit.Millisecond)] [InlineData(TimeUnit.Day)] [InlineData(TimeUnit.Month)] [InlineData(TimeUnit.Week)] [InlineData(TimeUnit.Year)] public void ThrowsOnUnsupportedData(TimeUnit units) { var dummyRate = ByteSize .FromBits(1) .Per(TimeSpan.FromSeconds(1)); Assert.Throws(() => dummyRate.Humanize(units)); } } ================================================ FILE: tests/Humanizer.Tests/Bytes/ByteSizeExtensionsTests.cs ================================================ [UseCulture("en")] public class ByteSizeExtensionsTests { [Fact] public void ByteTerabytes() { const byte size = 2; Assert.Equal(ByteSize.FromTerabytes(size), size.Terabytes()); } [Fact] public void SbyteTerabytes() { const sbyte size = 2; Assert.Equal(ByteSize.FromTerabytes(size), size.Terabytes()); } [Fact] public void ShortTerabytes() { const short size = 2; Assert.Equal(ByteSize.FromTerabytes(size), size.Terabytes()); } [Fact] public void UshortTerabytes() { const ushort size = 2; Assert.Equal(ByteSize.FromTerabytes(size), size.Terabytes()); } [Fact] public void IntTerabytes() { const int size = 2; Assert.Equal(ByteSize.FromTerabytes(size), size.Terabytes()); } [Fact] public void UintTerabytes() { const uint size = 2; Assert.Equal(ByteSize.FromTerabytes(size), size.Terabytes()); } [Fact] public void DoubleTerabytes() { const double size = 2; Assert.Equal(ByteSize.FromTerabytes(size), size.Terabytes()); } [Fact] public void LongTerabytes() { const long size = 2; Assert.Equal(ByteSize.FromTerabytes(size), size.Terabytes()); } [Theory] [InlineData(2, null, "en", "2 TB")] [InlineData(2, null, "fr", "2 To")] [InlineData(2, "GB", "en", "2048 GB")] [InlineData(2.1, null, "en", "2.1 TB")] [InlineData(2.123, "#.#", "en", "2.1 TB")] public void HumanizesTerabytes(double input, string? format, string cultureName, string expectedValue) { var culture = new CultureInfo(cultureName); Assert.Equal(expectedValue, input .Terabytes() .Humanize(format, culture)); } [Fact] public void ByteGigabytes() { const byte size = 2; Assert.Equal(ByteSize.FromGigabytes(size), size.Gigabytes()); } [Fact] public void SbyteGigabytes() { const sbyte size = 2; Assert.Equal(ByteSize.FromGigabytes(size), size.Gigabytes()); } [Fact] public void ShortGigabytes() { const short size = 2; Assert.Equal(ByteSize.FromGigabytes(size), size.Gigabytes()); } [Fact] public void UshortGigabytes() { const ushort size = 2; Assert.Equal(ByteSize.FromGigabytes(size), size.Gigabytes()); } [Fact] public void IntGigabytes() { const int size = 2; Assert.Equal(ByteSize.FromGigabytes(size), size.Gigabytes()); } [Fact] public void UintGigabytes() { const uint size = 2; Assert.Equal(ByteSize.FromGigabytes(size), size.Gigabytes()); } [Fact] public void DoubleGigabytes() { const double size = 2; Assert.Equal(ByteSize.FromGigabytes(size), size.Gigabytes()); } [Fact] public void LongGigabytes() { const long size = 2; Assert.Equal(ByteSize.FromGigabytes(size), size.Gigabytes()); } [Theory] [InlineData(0, null, "en", "0 b")] [InlineData(0, "GB", "en", "0 GB")] [InlineData(2, null, "en", "2 GB")] [InlineData(2, null, "fr", "2 Go")] [InlineData(2, "MB", "en", "2048 MB")] [InlineData(2.123, "#.##", "en", "2.12 GB")] public void HumanizesGigabytes(double input, string? format, string cultureName, string expectedValue) { var cultureInfo = new CultureInfo(cultureName); Assert.Equal(expectedValue, input .Gigabytes() .Humanize(format, cultureInfo)); } [Fact] public void ByteMegabytes() { const byte size = 2; Assert.Equal(ByteSize.FromMegabytes(size), size.Megabytes()); } [Fact] public void SbyteMegabytes() { const sbyte size = 2; Assert.Equal(ByteSize.FromMegabytes(size), size.Megabytes()); } [Fact] public void ShortMegabytes() { const short size = 2; Assert.Equal(ByteSize.FromMegabytes(size), size.Megabytes()); } [Fact] public void UshortMegabytes() { const ushort size = 2; Assert.Equal(ByteSize.FromMegabytes(size), size.Megabytes()); } [Fact] public void IntMegabytes() { const int size = 2; Assert.Equal(ByteSize.FromMegabytes(size), size.Megabytes()); } [Fact] public void UintMegabytes() { const uint size = 2; Assert.Equal(ByteSize.FromMegabytes(size), size.Megabytes()); } [Fact] public void DoubleMegabytes() { const double size = 2; Assert.Equal(ByteSize.FromMegabytes(size), size.Megabytes()); } [Fact] public void LongMegabytes() { const long size = 2; Assert.Equal(ByteSize.FromMegabytes(size), size.Megabytes()); } [Theory] [InlineData(0, null, "en", "0 b")] [InlineData(0, "MB", "en", "0 MB")] [InlineData(2, null, "en", "2 MB")] [InlineData(2, null, "fr", "2 Mo")] [InlineData(2, "KB", "en", "2048 KB")] [InlineData(2.123, "#", "en", "2 MB")] public void HumanizesMegabytes(double input, string? format, string cultureName, string expectedValue) { var cultureInfo = new CultureInfo(cultureName); Assert.Equal(expectedValue, input .Megabytes() .Humanize(format, cultureInfo)); } [Fact] public void ByteKilobytes() { const byte size = 2; Assert.Equal(ByteSize.FromKilobytes(size), size.Kilobytes()); } [Fact] public void SbyteKilobytes() { const sbyte size = 2; Assert.Equal(ByteSize.FromKilobytes(size), size.Kilobytes()); } [Fact] public void ShortKilobytes() { const short size = 2; Assert.Equal(ByteSize.FromKilobytes(size), size.Kilobytes()); } [Fact] public void UshortKilobytes() { const ushort size = 2; Assert.Equal(ByteSize.FromKilobytes(size), size.Kilobytes()); } [Fact] public void IntKilobytes() { const int size = 2; Assert.Equal(ByteSize.FromKilobytes(size), size.Kilobytes()); } [Fact] public void UintKilobytes() { const uint size = 2; Assert.Equal(ByteSize.FromKilobytes(size), size.Kilobytes()); } [Fact] public void DoubleKilobytes() { const double size = 2; Assert.Equal(ByteSize.FromKilobytes(size), size.Kilobytes()); } [Fact] public void LongKilobytes() { const long size = 2; Assert.Equal(ByteSize.FromKilobytes(size), size.Kilobytes()); } [Theory] [InlineData(0, null, "en", "0 b")] [InlineData(0, "KB", "en", "0 KB")] [InlineData(2, null, "en", "2 KB")] [InlineData(2, null, "fr", "2 Ko")] [InlineData(2, "B", "en", "2048 B")] [InlineData(2.123, "#.####", "en", "2.123 KB")] public void HumanizesKilobytes(double input, string? format, string cultureName, string expectedValue) { var cultureInfo = new CultureInfo(cultureName); Assert.Equal(expectedValue, input .Kilobytes() .Humanize(format, cultureInfo)); } [Fact] public void ByteBytes() { const byte size = 2; Assert.Equal(ByteSize.FromBytes(size), size.Bytes()); } [Fact] public void SbyteBytes() { const sbyte size = 2; Assert.Equal(ByteSize.FromBytes(size), size.Bytes()); } [Fact] public void ShortBytes() { const short size = 2; Assert.Equal(ByteSize.FromBytes(size), size.Bytes()); } [Fact] public void UshortBytes() { const ushort size = 2; Assert.Equal(ByteSize.FromBytes(size), size.Bytes()); } [Fact] public void IntBytes() { const int size = 2; Assert.Equal(ByteSize.FromBytes(size), size.Bytes()); } [Fact] public void UintBytes() { const uint size = 2; Assert.Equal(ByteSize.FromBytes(size), size.Bytes()); } [Fact] public void DoubleBytes() { const double size = 2; Assert.Equal(ByteSize.FromBytes(size), size.Bytes()); } [Fact] public void LongBytes() { const long size = 2; Assert.Equal(ByteSize.FromBytes(size), size.Bytes()); } [Theory] [InlineData(0, null, "en", "0 b")] [InlineData(0, "#.##", "en", "0 b")] [InlineData(0, "#.## B", "en", "0 B")] [InlineData(0, "B", "en", "0 B")] [InlineData(2, null, "en", "2 B")] [InlineData(2, null, "fr", "2 o")] [InlineData(2000, "KB", "en", "1.95 KB")] [InlineData(2123, "#.##", "en", "2.07 KB")] [InlineData(10000000, "KB", "en", "9765.63 KB")] [InlineData(10000000, "#,##0 KB", "en", "9,766 KB")] [InlineData(10000000, "#,##0.# KB", "en", "9,765.6 KB")] public void HumanizesBytes(double input, string? format, string cultureName, string expectedValue) { var cultureInfo = new CultureInfo(cultureName); Assert.Equal(expectedValue, input .Bytes() .Humanize(format, cultureInfo)); } [Fact] public void ByteBits() { const byte size = 2; Assert.Equal(ByteSize.FromBits(size), size.Bits()); } [Fact] public void SbyteBits() { const sbyte size = 2; Assert.Equal(ByteSize.FromBits(size), size.Bits()); } [Fact] public void ShortBits() { const short size = 2; Assert.Equal(ByteSize.FromBits(size), size.Bits()); } [Fact] public void UshortBits() { const ushort size = 2; Assert.Equal(ByteSize.FromBits(size), size.Bits()); } [Fact] public void IntBits() { const int size = 2; Assert.Equal(ByteSize.FromBits(size), size.Bits()); } [Fact] public void UintBits() { const uint size = 2; Assert.Equal(ByteSize.FromBits(size), size.Bits()); } [Fact] public void LongBits() { const long size = 2; Assert.Equal(ByteSize.FromBits(size), size.Bits()); } [Theory] [InlineData(0, null, "en", "0 b")] [InlineData(0, "b", "en", "0 b")] [InlineData(2, null, "en", "2 b")] [InlineData(2, null, "fr", "2 b")] [InlineData(12, "B", "en", "1.5 B")] [InlineData(10000, "#.# KB", "en", "1.2 KB")] public void HumanizesBits(long input, string? format, string cultureName, string expectedValue) { var cultureInfo = new CultureInfo(cultureName); Assert.Equal(expectedValue, input .Bits() .Humanize(format, cultureInfo)); } } ================================================ FILE: tests/Humanizer.Tests/Bytes/ComparingTests.cs ================================================ public class ComparingTests { [Theory] [InlineData(13, 23, -1)] [InlineData(23, 23, 0)] [InlineData(45, 23, 1)] public void CompareStrongTyped(double value, double valueToCompareWith, int expectedResult) { var valueSize = new ByteSize(value); var otherSize = new ByteSize(valueToCompareWith); var result = valueSize.CompareTo(otherSize); Assert.Equal(expectedResult, result); } [Theory] [InlineData(13, 23, -1)] [InlineData(23, 23, 0)] [InlineData(45, 23, 1)] public void CompareUntyped(double value, double valueToCompareWith, int expectedResult) { var valueSize = new ByteSize(value); object otherSize = new ByteSize(valueToCompareWith); var result = valueSize.CompareTo(otherSize); Assert.Equal(expectedResult, result); } [Theory] [InlineData(new[] { "1GB", "3KB", "5MB" }, new[] { "3KB", "5MB", "1GB" })] [InlineData(new[] { "1MB", "3KB", "5MB" }, new[] { "3KB", "1MB", "5MB" })] public void SortList(IEnumerable values, IEnumerable expected) { var list = values.Select(ByteSize.Parse).ToList(); list.Sort(); Assert.Equal(expected.Select(ByteSize.Parse), list); } } ================================================ FILE: tests/Humanizer.Tests/Bytes/CreatingTests.cs ================================================ //The MIT License (MIT) //Copyright (c) 2013-2014 Omar Khudeira (http://omar.io) //Permission is hereby granted, free of charge, to any person obtaining a copy //of this software and associated documentation files (the "Software"), to deal //in the Software without restriction, including without limitation the rights //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell //copies of the Software, and to permit persons to whom the Software is //furnished to do so, subject to the following conditions: //The above copyright notice and this permission notice shall be included in //all copies or substantial portions of the Software. //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN //THE SOFTWARE. public class CreatingTests { [Fact] public void Constructor() { var result = new ByteSize(1099511627776); Assert.Equal(8.796093022208e12, result.Bits); Assert.Equal(1099511627776, result.Bytes); Assert.Equal(1073741824, result.Kilobytes); Assert.Equal(1048576, result.Megabytes); Assert.Equal(1024, result.Gigabytes); Assert.Equal(1, result.Terabytes); } [Fact] public void FromBits() { var result = ByteSize.FromBits(8); Assert.Equal(8, result.Bits); Assert.Equal(1, result.Bytes); } [Fact] public void FromBytes() { var result = ByteSize.FromBytes(1.5); Assert.Equal(12, result.Bits); Assert.Equal(1.5, result.Bytes); } [Fact] public void FromKilobytes() { var result = ByteSize.FromKilobytes(1.5); Assert.Equal(1536, result.Bytes); Assert.Equal(1.5, result.Kilobytes); } [Fact] public void FromMegabytes() { var result = ByteSize.FromMegabytes(1.5); Assert.Equal(1572864, result.Bytes); Assert.Equal(1.5, result.Megabytes); } [Fact] public void FromGigabytes() { var result = ByteSize.FromGigabytes(1.5); Assert.Equal(1610612736, result.Bytes); Assert.Equal(1.5, result.Gigabytes); } [Fact] public void FromTerabytes() { var result = ByteSize.FromTerabytes(1.5); Assert.Equal(1649267441664, result.Bytes); Assert.Equal(1.5, result.Terabytes); } } ================================================ FILE: tests/Humanizer.Tests/Bytes/ParsingTests.cs ================================================ //The MIT License (MIT) //Copyright (c) 2013-2014 Omar Khudeira (http://omar.io) //Permission is hereby granted, free of charge, to any person obtaining a copy //of this software and associated documentation files (the "Software"), to deal //in the Software without restriction, including without limitation the rights //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell //copies of the Software, and to permit persons to whom the Software is //furnished to do so, subject to the following conditions: //The above copyright notice and this permission notice shall be included in //all copies or substantial portions of the Software. //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN //THE SOFTWARE. [UseCulture("en")] public class ParsingTests { [Fact] public void Parse() => Assert.Equal(ByteSize.FromKilobytes(1020), ByteSize.Parse("1020KB")); [Fact] public void TryParseReturnsFalseOnNullOrEmpty() { string? stringNull = null; // Get rid of redundant cast error Assert.False(ByteSize.TryParse(stringNull, out var result)); Assert.Equal(default, result); Assert.False(ByteSize.TryParse(string.Empty, out result)); Assert.Equal(default, result); Assert.False(ByteSize.TryParse(" \r\n\t", out result)); Assert.Equal(default, result); Assert.False(ByteSize.TryParse(" \r\n\t".AsSpan(), out result)); Assert.Equal(default, result); } [Fact] public void TryParse() { var resultBool = ByteSize.TryParse("1020KB", out var resultByteSize); Assert.True(resultBool); Assert.Equal(ByteSize.FromKilobytes(1020), resultByteSize); resultBool = ByteSize.TryParse("1020KB".AsSpan(), out resultByteSize); Assert.True(resultBool); Assert.Equal(ByteSize.FromKilobytes(1020), resultByteSize); } [Theory] [InlineData("2000.01KB", "")] // Invariant [InlineData("2,000.01KB", "")] [InlineData("+2000.01KB", "")] [InlineData("2000.01KB", "en")] [InlineData("2,000.01KB", "en")] [InlineData("+2000.01KB", "en")] [InlineData("2000,01KB", "de")] [InlineData("2.000,01KB", "de")] [InlineData("+2000,01KB", "de")] public void TryParseWithCultureInfo(string value, string cultureName) { var culture = new CultureInfo(cultureName); Assert.True(ByteSize.TryParse(value, culture, out var resultByteSize)); Assert.Equal(ByteSize.FromKilobytes(2000.01), resultByteSize); Assert.Equal(resultByteSize, ByteSize.Parse(value, culture)); Assert.True(ByteSize.TryParse(value.AsSpan(), culture, out resultByteSize)); Assert.Equal(ByteSize.FromKilobytes(2000.01), resultByteSize); Assert.Equal(resultByteSize, ByteSize.Parse(value, culture)); } [Fact] public void TryParseWithNumberFormatInfo() { var numberFormat = new NumberFormatInfo { NumberDecimalSeparator = "_", NumberGroupSeparator = ";", NegativeSign = "−", // proper minus, not hyphen-minus }; var value = "−2;000_01KB"; Assert.True(ByteSize.TryParse(value, numberFormat, out var resultByteSize)); Assert.Equal(ByteSize.FromKilobytes(-2000.01), resultByteSize); Assert.Equal(resultByteSize, ByteSize.Parse(value, numberFormat)); Assert.True(ByteSize.TryParse(value.AsSpan(), numberFormat, out resultByteSize)); Assert.Equal(ByteSize.FromKilobytes(-2000.01), resultByteSize); Assert.Equal(resultByteSize, ByteSize.Parse(value, numberFormat)); } [Fact] public void TryParseWithArabicCulture() { var arabic = new CultureInfo("ar"); Assert.True(ByteSize.TryParse("0 b", arabic, out var resultByteSize)); Assert.Equal(ByteSize.FromBits(0), resultByteSize); Assert.True(ByteSize.TryParse("100KB", arabic, out resultByteSize)); Assert.Equal(ByteSize.FromKilobytes(100), resultByteSize); Assert.True(ByteSize.TryParse("0 b".AsSpan(), arabic, out resultByteSize)); Assert.Equal(ByteSize.FromBits(0), resultByteSize); } [Fact] public void ParseDecimalMegabytes() => Assert.Equal(ByteSize.FromMegabytes(100.5), ByteSize.Parse("100.5MB")); [Theory] [InlineData("")] [InlineData(" ")] [InlineData("\t")] [InlineData("Unexpected Value")] [InlineData("1000")] [InlineData(" 1000 ")] [InlineData("KB")] [InlineData("1000.5b")] // Partial bits [InlineData("1000KBB")] // Bad suffix public void TryParseReturnsFalseOnBadValue(string input) { var resultBool = ByteSize.TryParse(input, out var resultByteSize); Assert.False(resultBool); Assert.Equal(new(), resultByteSize); resultBool = ByteSize.TryParse(input.AsSpan(), out resultByteSize); Assert.False(resultBool); Assert.Equal(new(), resultByteSize); Assert.Throws(() => ByteSize.Parse(input)); } [Fact] public void TryParseWorksWithLotsOfSpaces() => Assert.Equal(ByteSize.FromKilobytes(100), ByteSize.Parse(" 100 KB ")); [Fact] public void ParseThrowsOnNull() => Assert.Throws(() => ByteSize.Parse(null!)); [Fact] public void ParseBits() => Assert.Equal(ByteSize.FromBits(1), ByteSize.Parse("1b")); [Fact] public void ParseBytes() => Assert.Equal(ByteSize.FromBytes(1), ByteSize.Parse("1B")); [Fact] public void ParseKilobytes() => Assert.Equal(ByteSize.FromKilobytes(1020), ByteSize.Parse("1020KB")); [Fact] public void ParseMegabytes() => Assert.Equal(ByteSize.FromMegabytes(1000), ByteSize.Parse("1000MB")); [Fact] public void ParseGigabytes() => Assert.Equal(ByteSize.FromGigabytes(805), ByteSize.Parse("805GB")); [Fact] public void ParseTerabytes() => Assert.Equal(ByteSize.FromTerabytes(100), ByteSize.Parse("100TB")); } ================================================ FILE: tests/Humanizer.Tests/Bytes/ToFullWordsTests.cs ================================================ //The MIT License (MIT) //Copyright (c) 2013-2014 Omar Khudeira (http://omar.io) //Permission is hereby granted, free of charge, to any person obtaining a copy //of this software and associated documentation files (the "Software"), to deal //in the Software without restriction, including without limitation the rights //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell //copies of the Software, and to permit persons to whom the Software is //furnished to do so, subject to the following conditions: //The above copyright notice and this permission notice shall be included in //all copies or substantial portions of the Software. //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN //THE SOFTWARE. [UseCulture("en")] public class ToFullWordsTests { [Fact] public void ReturnsSingularBit() => Assert.Equal("1 bit", ByteSize.FromBits(1).ToFullWords()); [Fact] public void ReturnsPluralBits() => Assert.Equal("2 bits", ByteSize.FromBits(2).ToFullWords()); [Fact] public void ReturnsSingularByte() => Assert.Equal("1 byte", ByteSize.FromBytes(1).ToFullWords()); [Fact] public void ReturnsPluralBytes() => Assert.Equal("10 bytes", ByteSize.FromBytes(10).ToFullWords()); [Fact] public void ReturnsSingularKiloByte() => Assert.Equal("1 kilobyte", ByteSize.FromKilobytes(1).ToFullWords()); [Fact] public void ReturnsPluralKilobytes() => Assert.Equal("10 kilobytes", ByteSize.FromKilobytes(10).ToFullWords()); [Fact] public void ReturnsSingularMegabyte() => Assert.Equal("1 megabyte", ByteSize.FromMegabytes(1).ToFullWords()); [Fact] public void ReturnsPluralMegabytes() => Assert.Equal("10 megabytes", ByteSize.FromMegabytes(10).ToFullWords()); [Fact] public void ReturnsSingularGigabyte() => Assert.Equal("1 gigabyte", ByteSize.FromGigabytes(1).ToFullWords()); [Fact] public void ReturnsPluralGigabytes() => Assert.Equal("10 gigabytes", ByteSize.FromGigabytes(10).ToFullWords()); [Fact] public void ReturnsSingularTerabyte() => Assert.Equal("1 terabyte", ByteSize.FromTerabytes(1).ToFullWords()); [Fact] public void ReturnsPluralTerabytes() => Assert.Equal("10 terabytes", ByteSize.FromTerabytes(10).ToFullWords()); [Theory] [InlineData(229376, "B", "229376 bytes")] [InlineData(229376, "# KB", "224 kilobytes")] public void ToFullWordsFormatted(double input, string format, string expectedValue) => Assert.Equal(expectedValue, ByteSize.FromBytes(input).ToFullWords(format)); } ================================================ FILE: tests/Humanizer.Tests/Bytes/ToStringTests.cs ================================================ //The MIT License (MIT) //Copyright (c) 2013-2014 Omar Khudeira (http://omar.io) //Permission is hereby granted, free of charge, to any person obtaining a copy //of this software and associated documentation files (the "Software"), to deal //in the Software without restriction, including without limitation the rights //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell //copies of the Software, and to permit persons to whom the Software is //furnished to do so, subject to the following conditions: //The above copyright notice and this permission notice shall be included in //all copies or substantial portions of the Software. //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN //THE SOFTWARE. [UseCulture("en")] public class ToStringTests { [Fact] public void ReturnsLargestMetricSuffix() => Assert.Equal("10.5 KB", ByteSize.FromKilobytes(10.5).ToString()); [Fact] public void ReturnsDefaultNumberFormat() { Assert.Equal("10.5 KB", ByteSize.FromKilobytes(10.501).ToString()); Assert.Equal("10.5 KB", ByteSize.FromKilobytes(10.5).ToString("KB")); } [Fact] public void ReturnsProvidedNumberFormat() => Assert.Equal("10.1234 KB", ByteSize.FromKilobytes(10.1234).ToString("#.#### KB")); [Fact] public void ReturnsBits() => Assert.Equal("10 b", ByteSize.FromBits(10).ToString("##.#### b")); [Fact] public void ReturnsBytes() => Assert.Equal("10 B", ByteSize.FromBytes(10).ToString("##.#### B")); [Fact] public void ReturnsKilobytes() => Assert.Equal("10 KB", ByteSize.FromKilobytes(10).ToString("##.#### KB")); [Fact] public void ReturnsMegabytes() => Assert.Equal("10 MB", ByteSize.FromMegabytes(10).ToString("##.#### MB")); [Fact] public void ReturnsGigabytes() => Assert.Equal("10 GB", ByteSize.FromGigabytes(10).ToString("##.#### GB")); [Fact] public void ReturnsTerabytes() => Assert.Equal("10 TB", ByteSize.FromTerabytes(10).ToString("##.#### TB")); [Fact] public void ReturnsSelectedFormat() => Assert.Equal("10.0 TB", ByteSize.FromTerabytes(10).ToString("0.0 TB")); [Fact] public void ReturnsLargestMetricPrefixLargerThanZero() => Assert.Equal("512 KB", ByteSize.FromMegabytes(.5).ToString("#.#")); [Fact] public void ReturnsLargestMetricPrefixLargerThanZeroForNegativeValues() => Assert.Equal("-512 KB", ByteSize.FromMegabytes(-.5).ToString("#.#")); [Fact] public void ReturnsBytesViaGeneralFormat() => Assert.Equal("10 B", $"{ByteSize.FromBytes(10)}"); } ================================================ FILE: tests/Humanizer.Tests/CasingTests.cs ================================================ public class CasingTests { [Theory] [InlineData("lower case statement", "Lower Case Statement")] [InlineData("Sentence casing", "Sentence Casing")] [InlineData("honors UPPER case", "Honors UPPER Case")] [InlineData("Title Case", "Title Case")] [InlineData("title case (with parenthesis)", "Title Case (With Parenthesis)")] public void ApplyCaseTitle(string input, string expectedOutput) => Assert.Equal(expectedOutput, input.ApplyCase(LetterCasing.Title)); [Theory] [InlineData("lower case statement", "lower case statement")] [InlineData("Sentence casing", "sentence casing")] [InlineData("No honor for UPPER case", "no honor for upper case")] [InlineData("Title Case", "title case")] public void ApplyCaseLower(string input, string expectedOutput) => Assert.Equal(expectedOutput, input.ApplyCase(LetterCasing.LowerCase)); [Theory] [InlineData("lower case statement", "Lower case statement")] [InlineData("Sentence casing", "Sentence casing")] [InlineData("honors UPPER case", "Honors UPPER case")] public void ApplyCaseSentence(string input, string expectedOutput) => Assert.Equal(expectedOutput, input.ApplyCase(LetterCasing.Sentence)); [Theory] [InlineData("lower case statement", "LOWER CASE STATEMENT")] [InlineData("Sentence casing", "SENTENCE CASING")] [InlineData("Title Case", "TITLE CASE")] public void ApplyCaseAllCaps(string input, string expectedOutput) => Assert.Equal(expectedOutput, input.ApplyCase(LetterCasing.AllCaps)); } ================================================ FILE: tests/Humanizer.Tests/CollectionHumanizeTests.cs ================================================ public class SomeClass { public string? SomeString; public int SomeInt; public override string ToString() => "ToString"; } [UseCulture("en")] public class CollectionHumanizeTests { [Fact] public void HumanizeReturnsOnlyNameWhenCollectionContainsOneItem() { var collection = new List { "A String" }; Assert.Equal("A String", collection.Humanize()); } [Fact] public void HumanizeUsesSeparatorWhenMoreThanOneItemIsInCollection() { var collection = new List { "A String", "Another String", }; Assert.Equal("A String or Another String", collection.Humanize("or")); } [Fact] public void HumanizeDefaultsSeparatorToAnd() { var collection = new List { "A String", "Another String", }; Assert.Equal("A String and Another String", collection.Humanize()); } [Fact] public void HumanizeUsesOxfordComma() { var collection = new List { "A String", "Another String", "A Third String", }; Assert.Equal("A String, Another String, or A Third String", collection.Humanize("or")); } readonly List testCollection = [ new() { SomeInt = 1, SomeString = "One" }, new() { SomeInt = 2, SomeString = "Two" }, new() { SomeInt = 3, SomeString = "Three" } ]; [Fact] public void HumanizeDefaultsToToString() => Assert.Equal("ToString, ToString, or ToString", testCollection.Humanize("or")); [Fact] public void HumanizeUsesStringDisplayFormatter() { var humanized = testCollection.Humanize(sc => $"SomeObject #{sc.SomeInt} - {sc.SomeString}"); Assert.Equal("SomeObject #1 - One, SomeObject #2 - Two, and SomeObject #3 - Three", humanized); } [Fact] public void HumanizeUsesObjectDisplayFormatter() { var humanized = testCollection.Humanize(sc => sc.SomeInt); Assert.Equal("1, 2, and 3", humanized); } [Fact] public void HumanizeUsesStringDisplayFormatterWhenSeparatorIsProvided() { var humanized = testCollection.Humanize(sc => $"SomeObject #{sc.SomeInt} - {sc.SomeString}", "or"); Assert.Equal("SomeObject #1 - One, SomeObject #2 - Two, or SomeObject #3 - Three", humanized); } [Fact] public void HumanizeUsesObjectDisplayFormatterWhenSeparatorIsProvided() { var humanized = testCollection.Humanize(sc => sc.SomeInt, "or"); Assert.Equal("1, 2, or 3", humanized); } [Fact] public void HumanizeHandlesNullItemsWithoutAnException() => Assert.Null(Record.Exception(() => new object?[] { null, null }.Humanize())); [Fact] public void HumanizeHandlesNullStringDisplayFormatterReturnsWithoutAnException() => Assert.Null(Record.Exception(() => new[] { "A", "B", "C" }.Humanize(_ => null!))); [Fact] public void HumanizeHandlesNullObjectDisplayFormatterReturnsWithoutAnException() => Assert.Null(Record.Exception(() => new[] { "A", "B", "C" }.Humanize(_ => (object)null!))); [Fact] public void HumanizeRunsStringDisplayFormatterOnNulls() => Assert.Equal("1, (null), and 3", new int?[] { 1, null, 3 }.Humanize(_ => _?.ToString() ?? "(null)")); [Fact] public void HumanizeRunsObjectDisplayFormatterOnNulls() => Assert.Equal("1, 2, and 3", new int?[] { 1, null, 3 }.Humanize(_ => _ ?? 2)); [Fact] public void HumanizeRemovesEmptyItemsByDefault() => Assert.Equal("A and C", new[] { "A", " ", "C" }.Humanize(DummyFormatter)); [Fact] public void HumanizeTrimsItemsByDefault() => Assert.Equal("A, B, and C", new[] { "A", " B ", "C" }.Humanize(DummyFormatter)); /// /// Use the dummy formatter to ensure tests are testing formatter output rather than input /// static readonly Func DummyFormatter = input => input; } ================================================ FILE: tests/Humanizer.Tests/DateHumanize.cs ================================================ public class DateHumanize { static readonly Lock LockObject = new(); static void VerifyWithCurrentDate(string expectedString, TimeSpan deltaFromNow, CultureInfo? culture) { var utcNow = DateTime.UtcNow; var localNow = DateTime.Now; // feels like the only way to avoid breaking tests because CPU ticks over is to inject the base date VerifyWithDate(expectedString, deltaFromNow, culture, localNow, utcNow); } static void VerifyWithDateInjection(string expectedString, TimeSpan deltaFromNow, CultureInfo? culture) { var utcNow = new DateTime(2013, 6, 20, 9, 58, 22, DateTimeKind.Utc); var now = new DateTime(2013, 6, 20, 11, 58, 22, DateTimeKind.Local); VerifyWithDate(expectedString, deltaFromNow, culture, now, utcNow); } static void VerifyWithDate(string expectedString, TimeSpan deltaFromBase, CultureInfo? culture, DateTime baseDate, DateTime baseDateUtc) { Assert.Equal(expectedString, baseDateUtc .Add(deltaFromBase) .Humanize(utcDate: true, dateToCompareAgainst: baseDateUtc, culture: culture)); Assert.Equal(expectedString, baseDate .Add(deltaFromBase) .Humanize(false, baseDate, culture: culture)); // Compared with default utcDate Assert.Equal(expectedString, baseDateUtc .Add(deltaFromBase) .Humanize(utcDate: null, dateToCompareAgainst: baseDateUtc, culture: culture)); Assert.Equal(expectedString, baseDate .Add(deltaFromBase) .Humanize(null, baseDate, culture: culture)); } public static void Verify(string expectedString, int unit, TimeUnit timeUnit, Tense tense, double? precision = null, CultureInfo? culture = null, DateTime? baseDate = null, DateTime? baseDateUtc = null) { // We lock this as these tests can be multi-threaded and we're setting a static lock (LockObject) { if (precision.HasValue) { Configurator.DateTimeHumanizeStrategy = new PrecisionDateTimeHumanizeStrategy(precision.Value); } else { Configurator.DateTimeHumanizeStrategy = new DefaultDateTimeHumanizeStrategy(); } unit = Math.Abs(unit); if (tense == Tense.Past) { unit = -unit; } var deltaFromNow = timeUnit switch { TimeUnit.Millisecond => TimeSpan.FromMilliseconds(unit), TimeUnit.Second => TimeSpan.FromSeconds(unit), TimeUnit.Minute => TimeSpan.FromMinutes(unit), TimeUnit.Hour => TimeSpan.FromHours(unit), TimeUnit.Day => TimeSpan.FromDays(unit), TimeUnit.Month => TimeSpan.FromDays(unit * 31), TimeUnit.Year => TimeSpan.FromDays(unit * 366), _ => new() }; if (baseDate == null) { VerifyWithCurrentDate(expectedString, deltaFromNow, culture); VerifyWithDateInjection(expectedString, deltaFromNow, culture); } else { VerifyWithDate(expectedString, deltaFromNow, culture, baseDate.Value, baseDateUtc!.Value); } } } } ================================================ FILE: tests/Humanizer.Tests/DateHumanizeDefaultStrategyTests.cs ================================================ [UseCulture("en-US")] public class DateHumanizeDefaultStrategyTests { [Theory] [InlineData(1, "one second ago")] [InlineData(10, "10 seconds ago")] [InlineData(59, "59 seconds ago")] [InlineData(60, "a minute ago")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "one second from now")] [InlineData(10, "10 seconds from now")] [InlineData(59, "59 seconds from now")] [InlineData(60, "a minute from now")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(1, "a minute ago")] [InlineData(10, "10 minutes ago")] [InlineData(44, "44 minutes ago")] [InlineData(45, "45 minutes ago")] [InlineData(59, "59 minutes ago")] [InlineData(60, "an hour ago")] [InlineData(119, "an hour ago")] [InlineData(120, "2 hours ago")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "a minute from now")] [InlineData(10, "10 minutes from now")] [InlineData(44, "44 minutes from now")] [InlineData(45, "45 minutes from now")] [InlineData(119, "an hour from now")] [InlineData(120, "2 hours from now")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(1, "an hour ago")] [InlineData(10, "10 hours ago")] [InlineData(23, "23 hours ago")] [InlineData(24, "yesterday")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "an hour from now")] [InlineData(10, "10 hours from now")] [InlineData(23, "23 hours from now")] [InlineData(24, "tomorrow")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(38, "tomorrow")] [InlineData(40, "2 days from now")] public void HoursFromNowNotTomorrow(int hours, string expected) { //Only test with injected date, as results are dependent on time of day var utcNow = new DateTime(2014, 6, 28, 9, 58, 22, DateTimeKind.Utc); var now = new DateTime(2014, 6, 28, 9, 58, 22, DateTimeKind.Local); DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future, null, null, now, utcNow); } [Theory] [InlineData(1, "yesterday")] [InlineData(10, "10 days ago")] [InlineData(27, "27 days ago")] [InlineData(32, "one month ago")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "tomorrow")] [InlineData(10, "10 days from now")] [InlineData(27, "27 days from now")] [InlineData(32, "one month from now")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(1, "one month ago")] [InlineData(10, "10 months ago")] [InlineData(11, "11 months ago")] [InlineData(12, "one year ago")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "one month from now")] [InlineData(10, "10 months from now")] [InlineData(11, "11 months from now")] [InlineData(12, "one year from now")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(1, "one year ago")] [InlineData(2, "2 years ago")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "one year from now")] [InlineData(2, "2 years from now")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Fact] public void Now() => DateHumanize.Verify("now", 0, TimeUnit.Year, Tense.Future); [Fact] public void Never() { DateTime? never = null; Assert.Equal("never", never.Humanize()); } [Fact] public void Nullable_ExpectSame() { DateTime? never = new DateTime(2015, 12, 7, 9, 0, 0); Assert.Equal(never.Value.Humanize(), never.Humanize()); } [Theory] [InlineData(1, TimeUnit.Year, Tense.Future, "en-US", "one year from now")] [InlineData(40, TimeUnit.Second, Tense.Past, "ru-RU", "40 секунд назад")] [InlineData(2, TimeUnit.Day, Tense.Past, "sv-SE", "för 2 dagar sedan")] public void CanSpecifyCultureExplicitly(int unit, TimeUnit timeUnit, Tense tense, string culture, string expected) => DateHumanize.Verify(expected, unit, timeUnit, tense, culture: new(culture)); } ================================================ FILE: tests/Humanizer.Tests/DateOnlyHumanizeTests.cs ================================================ #if NET6_0_OR_GREATER [UseCulture("en-US")] public class DateOnlyHumanizeTests { [Fact] public void DefaultStrategy_SameDate() { Configurator.DateOnlyHumanizeStrategy = new DefaultDateOnlyHumanizeStrategy(); var inputTime = new DateOnly(2015, 07, 05); var baseTime = new DateOnly(2015, 07, 05); const string expectedResult = "now"; var actualResult = inputTime.Humanize(baseTime); Assert.Equal(expectedResult, actualResult); } [Fact] public void DefaultStrategy_MonthApart() { Configurator.DateOnlyHumanizeStrategy = new DefaultDateOnlyHumanizeStrategy(); var inputTime = new DateOnly(2015, 08, 05); var baseTime = new DateOnly(2015, 07, 05); const string expectedResult = "one month from now"; var actualResult = inputTime.Humanize(baseTime); Assert.Equal(expectedResult, actualResult); } [Fact] public void DefaultStrategy_DaysAgo() { Configurator.DateOnlyHumanizeStrategy = new DefaultDateOnlyHumanizeStrategy(); var inputTime = new DateOnly(2015, 07, 02); var baseTime = new DateOnly(2015, 07, 05); const string expectedResult = "3 days ago"; var actualResult = inputTime.Humanize(baseTime); Assert.Equal(expectedResult, actualResult); } [Fact] public void DefaultStrategy_YearsAgo() { Configurator.DateOnlyHumanizeStrategy = new DefaultDateOnlyHumanizeStrategy(); var baseDate = DateTime.Now; var inputTime = DateOnly.FromDateTime(baseDate.AddMonths(-24)); var baseTime = DateOnly.FromDateTime(baseDate); const string expectedResult = "2 years ago"; var actualResult = inputTime.Humanize(baseTime); Assert.Equal(expectedResult, actualResult); } [Fact] public void PrecisionStrategy_NextDay() { Configurator.DateOnlyHumanizeStrategy = new PrecisionDateOnlyHumanizeStrategy(0.75); var inputTime = new DateOnly(2015, 07, 05); var baseTime = new DateOnly(2015, 07, 04); const string expectedResult = "tomorrow"; var actualResult = inputTime.Humanize(baseTime); Assert.Equal(expectedResult, actualResult); } [Fact] public void Never() { DateOnly? never = null; Assert.Equal("never", never.Humanize()); } [Fact] public void Nullable_ExpectSame() { DateOnly? never = new DateOnly(2015, 12, 7); Assert.Equal(never.Value.Humanize(), never.Humanize()); } } #endif ================================================ FILE: tests/Humanizer.Tests/DateTimeHumanizePrecisionStrategyTests.cs ================================================ [UseCulture("en-US")] public class DateTimeHumanizePrecisionStrategyTests { const double DefaultPrecision = .75; [Theory] [InlineData(1, "now")] [InlineData(749, "now")] [InlineData(750, "one second ago")] [InlineData(1000, "one second ago")] [InlineData(1749, "one second ago")] [InlineData(1750, "2 seconds ago")] public void MillisecondsAgo(int milliseconds, string expected) => DateHumanize.Verify(expected, milliseconds, TimeUnit.Millisecond, Tense.Past, DefaultPrecision); [Theory] [InlineData(1, "now")] [InlineData(749, "now")] [InlineData(750, "one second from now")] [InlineData(1000, "one second from now")] [InlineData(1749, "one second from now")] [InlineData(1750, "2 seconds from now")] public void MillisecondsFromNow(int milliseconds, string expected) => DateHumanize.Verify(expected, milliseconds, TimeUnit.Millisecond, Tense.Future, DefaultPrecision); [Theory] [InlineData(1, "one second ago")] [InlineData(10, "10 seconds ago")] [InlineData(44, "44 seconds ago")] [InlineData(45, "a minute ago")] [InlineData(60, "a minute ago")] [InlineData(104, "a minute ago")] [InlineData(105, "2 minutes ago")] [InlineData(120, "2 minutes ago")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past, DefaultPrecision); [Theory] [InlineData(1, "one second from now")] [InlineData(10, "10 seconds from now")] [InlineData(44, "44 seconds from now")] [InlineData(45, "a minute from now")] [InlineData(60, "a minute from now")] [InlineData(104, "a minute from now")] [InlineData(105, "2 minutes from now")] [InlineData(120, "2 minutes from now")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future, DefaultPrecision); [Theory] [InlineData(1, "a minute ago")] [InlineData(10, "10 minutes ago")] [InlineData(44, "44 minutes ago")] [InlineData(45, "an hour ago")] [InlineData(60, "an hour ago")] [InlineData(104, "an hour ago")] [InlineData(105, "2 hours ago")] [InlineData(120, "2 hours ago")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past, DefaultPrecision); [Theory] [InlineData(1, "a minute from now")] [InlineData(10, "10 minutes from now")] [InlineData(44, "44 minutes from now")] [InlineData(45, "an hour from now")] [InlineData(60, "an hour from now")] [InlineData(104, "an hour from now")] [InlineData(105, "2 hours from now")] [InlineData(120, "2 hours from now")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future, DefaultPrecision); [Theory] [InlineData(1, "an hour ago")] [InlineData(10, "10 hours ago")] [InlineData(17, "17 hours ago")] [InlineData(18, "yesterday")] [InlineData(24, "yesterday")] [InlineData(41, "yesterday")] [InlineData(42, "2 days ago")] [InlineData(48, "2 days ago")] [InlineData(60, "2 days ago")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past, DefaultPrecision); [Theory] [InlineData(1, "an hour from now")] [InlineData(10, "10 hours from now")] [InlineData(18, "tomorrow")] [InlineData(24, "tomorrow")] [InlineData(41, "tomorrow")] [InlineData(42, "2 days from now")] [InlineData(48, "2 days from now")] [InlineData(60, "2 days from now")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future, DefaultPrecision); [Theory] [InlineData(1, "yesterday")] [InlineData(10, "10 days ago")] [InlineData(20, "20 days ago")] [InlineData(22, "22 days ago")] [InlineData(23, "one month ago")] [InlineData(31, "one month ago")] [InlineData(43, "one month ago")] [InlineData(53, "2 months ago")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past, DefaultPrecision); [Theory] [InlineData(1, "tomorrow")] [InlineData(10, "10 days from now")] [InlineData(20, "20 days from now")] [InlineData(22, "22 days from now")] [InlineData(23, "one month from now")] [InlineData(31, "one month from now")] [InlineData(43, "one month from now")] [InlineData(53, "2 months from now")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future, DefaultPrecision); [Theory] [InlineData(1, "one month ago")] [InlineData(8, "8 months ago")] [InlineData(9, "one year ago")] [InlineData(12, "one year ago")] [InlineData(19, "one year ago")] [InlineData(21, "2 years ago")] [InlineData(24, "2 years ago")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past, DefaultPrecision); [Theory] [InlineData(1, "one month from now")] [InlineData(8, "8 months from now")] [InlineData(9, "one year from now")] [InlineData(12, "one year from now")] [InlineData(19, "one year from now")] [InlineData(21, "2 years from now")] [InlineData(24, "2 years from now")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future, DefaultPrecision); [Theory] [InlineData(1, "one year ago")] [InlineData(2, "2 years ago")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past, DefaultPrecision); [Theory] [InlineData(1, "one year from now")] [InlineData(2, "2 years from now")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future, DefaultPrecision); } ================================================ FILE: tests/Humanizer.Tests/DateTimeOffsetHumanizeTests.cs ================================================ [UseCulture("en-US")] public class DateTimeOffsetHumanizeTests { [Fact] public void DefaultStrategy_SameOffset() { Configurator.DateTimeOffsetHumanizeStrategy = new DefaultDateTimeOffsetHumanizeStrategy(); var inputTime = new DateTimeOffset(2015, 07, 05, 04, 0, 0, TimeSpan.Zero); var baseTime = new DateTimeOffset(2015, 07, 05, 03, 0, 0, TimeSpan.Zero); const string expectedResult = "an hour from now"; var actualResult = inputTime.Humanize(baseTime); Assert.Equal(expectedResult, actualResult); } [Fact] public void DefaultStrategy_DifferentOffsets() { Configurator.DateTimeOffsetHumanizeStrategy = new DefaultDateTimeOffsetHumanizeStrategy(); var inputTime = new DateTimeOffset(2015, 07, 05, 03, 0, 0, new(2, 0, 0)); var baseTime = new DateTimeOffset(2015, 07, 05, 02, 30, 0, new(1, 0, 0)); const string expectedResult = "30 minutes ago"; var actualResult = inputTime.Humanize(baseTime); Assert.Equal(expectedResult, actualResult); } [Fact] public void PrecisionStrategy_SameOffset() { Configurator.DateTimeOffsetHumanizeStrategy = new PrecisionDateTimeOffsetHumanizeStrategy(0.75); var inputTime = new DateTimeOffset(2015, 07, 05, 04, 0, 0, TimeSpan.Zero); var baseTime = new DateTimeOffset(2015, 07, 04, 05, 0, 0, TimeSpan.Zero); const string expectedResult = "tomorrow"; var actualResult = inputTime.Humanize(baseTime); Assert.Equal(expectedResult, actualResult); } [Fact] public void PrecisionStrategy_DifferentOffsets() { Configurator.DateTimeOffsetHumanizeStrategy = new PrecisionDateTimeOffsetHumanizeStrategy(0.75); var inputTime = new DateTimeOffset(2015, 07, 05, 03, 45, 0, new(2, 0, 0)); var baseTime = new DateTimeOffset(2015, 07, 05, 02, 30, 0, new(-5, 0, 0)); const string expectedResult = "6 hours ago"; var actualResult = inputTime.Humanize(baseTime); Assert.Equal(expectedResult, actualResult); } [Fact] public void Never() { DateTimeOffset? never = null; Assert.Equal("never", never.Humanize()); } [Fact] public void Nullable_ExpectSame() { DateTimeOffset? never = new DateTimeOffset(2015, 12, 7, 9, 0, 0, TimeSpan.FromHours(1)); Assert.Equal(never.Value.Humanize(), never.Humanize()); } } ================================================ FILE: tests/Humanizer.Tests/EnumHumanizeTests.cs ================================================ using System.Diagnostics.CodeAnalysis; public class EnumHumanizeTests { [Fact] public void HonorsDescriptionAttribute() => Assert.Equal(EnumTestsResources.MemberWithDescriptionAttribute, EnumUnderTest.MemberWithDescriptionAttribute.Humanize()); [Fact] public void HonorsDescriptionAttributeSubclasses() => Assert.Equal("Overridden " + EnumTestsResources.MemberWithDescriptionAttributeSubclass, EnumUnderTest.MemberWithDescriptionAttributeSubclass.Humanize()); [Fact] public void HonorsAnyAttributeWithDescriptionStringProperty() => Assert.Equal(EnumTestsResources.MemberWithCustomDescriptionAttribute, EnumUnderTest.MemberWithCustomDescriptionAttribute.Humanize()); [Fact] public void OnlyStringDescriptionsApply() => Assert.Equal(EnumTestsResources.MemberWithImposterDescriptionAttribute, EnumUnderTest.MemberWithImposterDescriptionAttribute.Humanize()); [Fact] public void CanHumanizeMembersWithoutDescriptionAttribute() => Assert.Equal(EnumTestsResources.MemberWithoutDescriptionAttributeSentence, EnumUnderTest.MemberWithoutDescriptionAttribute.Humanize()); [Fact] public void CanApplyTitleCasingOnEnumHumanization() => Assert.Equal( EnumTestsResources.MemberWithoutDescriptionAttributeTitle, EnumUnderTest.MemberWithoutDescriptionAttribute.Humanize(LetterCasing.Title)); [Fact] public void CanApplyLowerCaseCasingOnEnumHumanization() => Assert.Equal( EnumTestsResources.MemberWithoutDescriptionAttributeLowerCase, EnumUnderTest.MemberWithoutDescriptionAttribute.Humanize(LetterCasing.LowerCase)); [Fact] public void AllCapitalMembersAreReturnedAsIs() => Assert.Equal(EnumUnderTest.ALLCAPITALS.ToString(), EnumUnderTest.ALLCAPITALS.Humanize()); [Fact] public void HonorsDisplayAttribute() => Assert.Equal(EnumTestsResources.MemberWithDisplayAttribute, EnumUnderTest.MemberWithDisplayAttribute.Humanize()); [Fact] public void HandlesDisplayAttributeWithNoDescription() => Assert.Equal(EnumTestsResources.MemberWithDisplayAttributeWithoutDescription, EnumUnderTest.MemberWithDisplayAttributeWithoutDescription.Humanize()); [Fact] public void HonorsLocalizedDisplayAttribute() => Assert.Equal(EnumTestsResources.MemberWithLocalizedDisplayAttribute, EnumUnderTest.MemberWithLocalizedDisplayAttribute.Humanize()); [Fact] public void HumanizeCustomPropertyAttributeWithLocator() { Configurator.ResetUseEnumDescriptionPropertyLocator(); Configurator.UseEnumDescriptionPropertyLocator(p => p.Name == "Info"); try { Assert.Equal(EnumTestsResources.MemberWithCustomPropertyAttribute, EnumForCustomLocator.MemberWithCustomPropertyAttribute.Humanize()); } finally { Configurator.ResetUseEnumDescriptionPropertyLocator(); } } [Fact] public void HumanizeMembersWithoutDescriptionAttributeWithLocator() { Configurator.ResetUseEnumDescriptionPropertyLocator(); Configurator.UseEnumDescriptionPropertyLocator(p => p.Name == "Info"); try { Assert.Equal(EnumTestsResources.MemberWithoutDescriptionAttributeSentence, EnumForCustomLocator.MemberWithoutDescriptionAttribute.Humanize()); } finally { Configurator.ResetUseEnumDescriptionPropertyLocator(); } } [Fact] [RequiresDynamicCode("The native code for the target enumeration might not be available at runtime.")] [RequiresUnreferencedCode("The native code for the target enumeration might not be available at runtime.")] public void DehumanizeThrowsForEnumNoMatch() { Assert.Throws(() => EnumTestsResources.MemberWithDescriptionAttribute.DehumanizeTo()); Assert.Throws(() => EnumTestsResources.MemberWithDescriptionAttribute.DehumanizeTo(typeof(DummyEnum))); } [Fact] [RequiresDynamicCode("The native code for the target enumeration might not be available at runtime.")] [RequiresUnreferencedCode("The native code for the target enumeration might not be available at runtime.")] public void DehumanizeCanReturnNullForEnumNoMatch() => Assert.Null(EnumTestsResources.MemberWithDescriptionAttribute.DehumanizeTo(OnNoMatch.ReturnsNull)); [Fact] [RequiresDynamicCode("The native code for the target enumeration might not be available at runtime.")] [RequiresUnreferencedCode("The native code for the target enumeration might not be available at runtime.")] public void DehumanizeDescriptionAttribute() { Assert.Equal(EnumUnderTest.MemberWithDescriptionAttribute, EnumTestsResources.MemberWithDescriptionAttribute.DehumanizeTo()); Assert.Equal(EnumUnderTest.MemberWithDescriptionAttribute, EnumTestsResources.MemberWithDescriptionAttribute.DehumanizeTo(typeof(EnumUnderTest))); } [Fact] [RequiresDynamicCode("The native code for the target enumeration might not be available at runtime.")] [RequiresUnreferencedCode("The native code for the target enumeration might not be available at runtime.")] public void DehumanizeDescriptionAttributeSubclasses() { const string calculatedDescription = "Overridden " + EnumTestsResources.MemberWithDescriptionAttributeSubclass; Assert.Equal(EnumUnderTest.MemberWithDescriptionAttributeSubclass, calculatedDescription.DehumanizeTo()); Assert.Equal(EnumUnderTest.MemberWithDescriptionAttributeSubclass, calculatedDescription.DehumanizeTo(typeof(EnumUnderTest))); } [Fact] [RequiresDynamicCode("The native code for the target enumeration might not be available at runtime.")] [RequiresUnreferencedCode("The native code for the target enumeration might not be available at runtime.")] public void DehumanizeAnyAttributeWithDescriptionStringProperty() { Assert.Equal(EnumUnderTest.MemberWithCustomDescriptionAttribute, EnumTestsResources.MemberWithCustomDescriptionAttribute.DehumanizeTo()); Assert.Equal(EnumUnderTest.MemberWithCustomDescriptionAttribute, EnumTestsResources.MemberWithCustomDescriptionAttribute.DehumanizeTo(typeof(EnumUnderTest))); } [Fact] [RequiresDynamicCode("The native code for the target enumeration might not be available at runtime.")] [RequiresUnreferencedCode("The native code for the target enumeration might not be available at runtime.")] public void DehumanizeMembersWithoutDescriptionAttribute() { Assert.Equal(EnumUnderTest.MemberWithoutDescriptionAttribute, EnumTestsResources.MemberWithoutDescriptionAttributeSentence.DehumanizeTo()); Assert.Equal(EnumUnderTest.MemberWithoutDescriptionAttribute, EnumTestsResources.MemberWithoutDescriptionAttributeSentence.DehumanizeTo(typeof(EnumUnderTest))); } [Theory] [InlineData(EnumTestsResources.MemberWithoutDescriptionAttributeTitle, EnumUnderTest.MemberWithoutDescriptionAttribute)] [InlineData(EnumTestsResources.MemberWithoutDescriptionAttributeLowerCase, EnumUnderTest.MemberWithoutDescriptionAttribute)] [InlineData(EnumTestsResources.MemberWithoutDescriptionAttributeSentence, EnumUnderTest.MemberWithoutDescriptionAttribute)] [RequiresDynamicCode("The native code for the target enumeration might not be available at runtime.")] [RequiresUnreferencedCode("The native code for the target enumeration might not be available at runtime.")] public void DehumanizeIsCaseInsensitive(string input, EnumUnderTest expectedEnum) { Assert.Equal(expectedEnum, input.DehumanizeTo()); Assert.Equal(expectedEnum, input.DehumanizeTo(typeof(EnumUnderTest))); } [Fact] [RequiresDynamicCode("The native code for the target enumeration might not be available at runtime.")] [RequiresUnreferencedCode("The native code for the target enumeration might not be available at runtime.")] public void DehumanizeAllCapitalMembersAreReturnedAsIs() { Assert.Equal(EnumUnderTest.ALLCAPITALS, EnumUnderTest.ALLCAPITALS.ToString().DehumanizeTo()); Assert.Equal(EnumUnderTest.ALLCAPITALS, EnumUnderTest.ALLCAPITALS.ToString().DehumanizeTo(typeof(EnumUnderTest))); } [Fact] [RequiresDynamicCode("The native code for the target enumeration might not be available at runtime.")] [RequiresUnreferencedCode("The native code for the target enumeration might not be available at runtime.")] public void DehumanizeDisplayAttribute() { Assert.Equal(EnumUnderTest.MemberWithDisplayAttribute, EnumTestsResources.MemberWithDisplayAttribute.DehumanizeTo()); Assert.Equal(EnumUnderTest.MemberWithDisplayAttribute, EnumTestsResources.MemberWithDisplayAttribute.DehumanizeTo(typeof(EnumUnderTest))); } [Fact] [RequiresDynamicCode("The native code for the target enumeration might not be available at runtime.")] [RequiresUnreferencedCode("The native code for the target enumeration might not be available at runtime.")] public void DehumanizeLocalizedDisplayAttribute() { Assert.Equal(EnumUnderTest.MemberWithLocalizedDisplayAttribute, EnumTestsResources.MemberWithLocalizedDisplayAttribute.DehumanizeTo()); Assert.Equal(EnumUnderTest.MemberWithLocalizedDisplayAttribute, EnumTestsResources.MemberWithLocalizedDisplayAttribute.DehumanizeTo(typeof(EnumUnderTest))); } enum DummyEnum { First, Second } } ================================================ FILE: tests/Humanizer.Tests/EnumUnderTest.cs ================================================ using System.ComponentModel; using System.ComponentModel.DataAnnotations; public enum EnumUnderTest { [Description(EnumTestsResources.MemberWithDescriptionAttribute)] MemberWithDescriptionAttribute, [DescriptionSubclass(EnumTestsResources.MemberWithDescriptionAttributeSubclass)] MemberWithDescriptionAttributeSubclass, [CustomDescription(EnumTestsResources.MemberWithCustomDescriptionAttribute)] MemberWithCustomDescriptionAttribute, [ImposterDescription(42)] MemberWithImposterDescriptionAttribute, [CustomProperty(EnumTestsResources.MemberWithCustomPropertyAttribute)] MemberWithCustomPropertyAttribute, MemberWithoutDescriptionAttribute, ALLCAPITALS, [Display(Description = EnumTestsResources.MemberWithDisplayAttribute)] MemberWithDisplayAttribute, [Display(Description = "MemberWithLocalizedDisplayAttribute", ResourceType = typeof(EnumTestsResources))] MemberWithLocalizedDisplayAttribute, [Display(Name = EnumTestsResources.MemberWithDisplayAttributeWithoutDescription)] MemberWithDisplayAttributeWithoutDescription } public enum EnumForCustomLocator { [CustomProperty(EnumTestsResources.MemberWithCustomPropertyAttribute)] MemberWithCustomPropertyAttribute, MemberWithoutDescriptionAttribute, } public class EnumTestsResources { public const string MemberWithDescriptionAttribute = "Some Description"; public const string MemberWithDescriptionAttributeSubclass = "Description in Description subclass"; public const string MemberWithCustomDescriptionAttribute = "Description in custom Description attribute"; public const string MemberWithImposterDescriptionAttribute = "Member with imposter description attribute"; public const string MemberWithCustomPropertyAttribute = "Description in custom property attribute"; public const string MemberWithoutDescriptionAttributeSentence = "Member without description attribute"; public const string MemberWithoutDescriptionAttributeTitle = "Member Without Description Attribute"; public const string MemberWithoutDescriptionAttributeLowerCase = "member without description attribute"; public const string MemberWithDisplayAttribute = "Description from Display attribute"; public const string MemberWithDisplayAttributeWithoutDescription = "Displayattribute without description"; public static string MemberWithLocalizedDisplayAttribute => "Localized description from Display attribute"; } [AttributeUsage(AttributeTargets.Field)] public class ImposterDescriptionAttribute(int description) : Attribute { public int Description { get; set; } = description; } [AttributeUsage(AttributeTargets.Field | AttributeTargets.Method)] public class CustomDescriptionAttribute(string description) : Attribute { public string Description { get; set; } = description; } [AttributeUsage(AttributeTargets.Field)] public class DescriptionSubclassAttribute(string description) : DescriptionAttribute(description) { public override string Description => "Overridden " + base.Description; } [AttributeUsage(AttributeTargets.Field)] public class CustomPropertyAttribute(string info) : Attribute { public string Info { get; set; } = info; } ================================================ FILE: tests/Humanizer.Tests/FluentDate/InDateTests.cs ================================================ #if NET6_0_OR_GREATER public class InDateTests { [Fact] public void InJanuary() => Assert.Equal(new(DateTime.Now.Year, 1, 1), InDate.January); [Fact] public void InJanuaryOf2009() => Assert.Equal(new(2009, 1, 1), InDate.JanuaryOf(2009)); [Fact] public void InFebruary() => Assert.Equal(new(DateTime.Now.Year, 2, 1), InDate.February); [Fact] public void InTheYear() => Assert.Equal(new(2009, 1, 1), InDate.TheYear(2009)); [Fact] public void InFiveDays() { var baseDate = OnDate.January.The21st; var date = InDate.Five.DaysFrom(baseDate); Assert.Equal(baseDate.AddDays(5), date); } } #endif ================================================ FILE: tests/Humanizer.Tests/FluentDate/InTests.cs ================================================ public class InTests { [Fact] public void InJanuary() => Assert.Equal(new(DateTime.Now.Year, 1, 1), In.January); [Fact] public void InJanuaryOf2009() => Assert.Equal(new(2009, 1, 1), In.JanuaryOf(2009)); [Fact] public void InFebruary() => Assert.Equal(new(DateTime.Now.Year, 2, 1), In.February); [Fact] public void InFebruaryOf2009() => Assert.Equal(new(2009, 2, 1), In.FebruaryOf(2009)); [Fact] public void InMarch() => Assert.Equal(new(DateTime.Now.Year, 3, 1), In.March); [Fact] public void InMarchOf2009() => Assert.Equal(new(2009, 3, 1), In.MarchOf(2009)); [Fact] public void InApril() => Assert.Equal(new(DateTime.Now.Year, 4, 1), In.April); [Fact] public void InAprilOf2009() => Assert.Equal(new(2009, 4, 1), In.AprilOf(2009)); [Fact] public void InMay() => Assert.Equal(new(DateTime.Now.Year, 5, 1), In.May); [Fact] public void InMayOf2009() => Assert.Equal(new(2009, 5, 1), In.MayOf(2009)); [Fact] public void InJune() => Assert.Equal(new(DateTime.Now.Year, 6, 1), In.June); [Fact] public void InJuneOf2009() => Assert.Equal(new(2009, 6, 1), In.JuneOf(2009)); [Fact] public void InJuly() => Assert.Equal(new(DateTime.Now.Year, 7, 1), In.July); [Fact] public void InJulyOf2009() => Assert.Equal(new(2009, 7, 1), In.JulyOf(2009)); [Fact] public void InAugust() => Assert.Equal(new(DateTime.Now.Year, 8, 1), In.August); [Fact] public void InAugustOf2009() => Assert.Equal(new(2009, 8, 1), In.AugustOf(2009)); [Fact] public void InSeptember() => Assert.Equal(new(DateTime.Now.Year, 9, 1), In.September); [Fact] public void InSeptemberOf2009() => Assert.Equal(new(2009, 9, 1), In.SeptemberOf(2009)); [Fact] public void InOctober() => Assert.Equal(new(DateTime.Now.Year, 10, 1), In.October); [Fact] public void InOctoberOfIn2009() => Assert.Equal(new(2009, 10, 1), In.OctoberOf(2009)); [Fact] public void InNovember() => Assert.Equal(new(DateTime.Now.Year, 11, 1), In.November); [Fact] public void InNovemberOf2009() => Assert.Equal(new(2009, 11, 1), In.NovemberOf(2009)); [Fact] public void InDecember() => Assert.Equal(new(DateTime.Now.Year, 12, 1), In.December); [Fact] public void InDecemberOf2009() => Assert.Equal(new(2009, 12, 1), In.DecemberOf(2009)); [Fact] public void InTheYear() => Assert.Equal(new(2009, 1, 1), In.TheYear(2009)); [Fact] public void InFiveDays() { var baseDate = On.January.The21st; var date = In.Five.DaysFrom(baseDate); Assert.Equal(baseDate.AddDays(5), date); } } ================================================ FILE: tests/Humanizer.Tests/FluentDate/OnDateTests.cs ================================================ #if NET6_0_OR_GREATER public class OnDateTests { [Fact] public void OnJanuaryThe23rd() => Assert.Equal(new(DateTime.Now.Year, 1, 23), OnDate.January.The23rd); [Fact] public void OnDecemberThe4th() => Assert.Equal(new(DateTime.Now.Year, 12, 4), OnDate.December.The4th); [Fact] public void OnFebruaryThe() => Assert.Equal(new(DateTime.Now.Year, 2, 11), OnDate.February.The(11)); } #endif ================================================ FILE: tests/Humanizer.Tests/FluentDate/OnTests.cs ================================================ public class OnTests { [Fact] public void OnJanuaryThe23rd() => Assert.Equal(new(DateTime.Now.Year, 1, 23), On.January.The23rd); [Fact] public void OnDecemberThe4th() => Assert.Equal(new(DateTime.Now.Year, 12, 4), On.December.The4th); [Fact] public void OnFebruaryThe() => Assert.Equal(new(DateTime.Now.Year, 2, 11), On.February.The(11)); } ================================================ FILE: tests/Humanizer.Tests/FluentDate/PrepositionTests.cs ================================================ public class PrepositionTests { [Fact] public void AtMidnight() { var now = DateTime.Now; var midnight = now.AtMidnight(); Assert.Equal(new(now.Year, now.Month, now.Day), midnight); } [Fact] public void AtNoon() { var now = DateTime.Now; var noon = now.AtNoon(); Assert.Equal(new(now.Year, now.Month, now.Day, 12, 0, 0), noon); } [Fact] public void InYear() { var now = DateTime.Now; var in2012 = now.In(2012); Assert.Equal(new(2012, now.Month, now.Day, now.Hour, now.Minute, now.Second, now.Millisecond), in2012); } } ================================================ FILE: tests/Humanizer.Tests/GlobalUsings.cs ================================================ global using System.Globalization; global using System.Runtime.CompilerServices; global using Humanizer; ================================================ FILE: tests/Humanizer.Tests/HeadingTests.cs ================================================ [UseCulture("en-US")] public class HeadingTests { [InlineData(0, "N")] [InlineData(11.2, "N")] [InlineData(11.3, "NNE")] [InlineData(22.5, "NNE")] [InlineData(33.7, "NNE")] [InlineData(33.8, "NE")] [InlineData(45, "NE")] [InlineData(56.2, "NE")] [InlineData(56.3, "ENE")] [InlineData(67.5, "ENE")] [InlineData(78.7, "ENE")] [InlineData(78.8, "E")] [InlineData(90, "E")] [InlineData(101.2, "E")] [InlineData(101.3, "ESE")] [InlineData(112.5, "ESE")] [InlineData(123.7, "ESE")] [InlineData(123.8, "SE")] [InlineData(135, "SE")] [InlineData(146.2, "SE")] [InlineData(146.3, "SSE")] [InlineData(157.5, "SSE")] [InlineData(168.7, "SSE")] [InlineData(168.8, "S")] [InlineData(180, "S")] [InlineData(191.2, "S")] [InlineData(191.3, "SSW")] [InlineData(202.5, "SSW")] [InlineData(213.7, "SSW")] [InlineData(213.8, "SW")] [InlineData(225, "SW")] [InlineData(236.2, "SW")] [InlineData(236.3, "WSW")] [InlineData(247.5, "WSW")] [InlineData(258.7, "WSW")] [InlineData(258.8, "W")] [InlineData(270, "W")] [InlineData(281.2, "W")] [InlineData(281.3, "WNW")] [InlineData(292.5, "WNW")] [InlineData(303.7, "WNW")] [InlineData(303.8, "NW")] [InlineData(315, "NW")] [InlineData(326.2, "NW")] [InlineData(326.3, "NNW")] [InlineData(337.5, "NNW")] [InlineData(348.7, "NNW")] [InlineData(348.8, "N")] [InlineData(360, "N")] [InlineData(720, "N")] [Theory] public void ToHeadingAbbreviated(double heading, string expected) => Assert.Equal(expected, heading.ToHeading()); [InlineData(0, "north")] [InlineData(22.5, "north-northeast")] [InlineData(45, "northeast")] [InlineData(67.5, "east-northeast")] [InlineData(90, "east")] [InlineData(112.5, "east-southeast")] [InlineData(135, "southeast")] [InlineData(157.5, "south-southeast")] [InlineData(180, "south")] [InlineData(202.5, "south-southwest")] [InlineData(225, "southwest")] [InlineData(247.5, "west-southwest")] [InlineData(270, "west")] [InlineData(292.5, "west-northwest")] [InlineData(315, "northwest")] [InlineData(337.5, "north-northwest")] [InlineData(360, "north")] [InlineData(720, "north")] [Theory] public void ToHeading(double heading, string expected) => Assert.Equal(expected, heading.ToHeading(HeadingStyle.Full)); [InlineData("N", 0)] [InlineData("NNE", 22.5)] [InlineData("NE", 45)] [InlineData("ENE", 67.5)] [InlineData("E", 90)] [InlineData("ESE", 112.5)] [InlineData("SE", 135)] [InlineData("SSE", 157.5)] [InlineData("S", 180)] [InlineData("SSW", 202.5)] [InlineData("SW", 225)] [InlineData("WSW", 247.5)] [InlineData("W", 270)] [InlineData("WNW", 292.5)] [InlineData("NW", 315)] [InlineData("NNW", 337.5)] [Theory] public void FromShortHeading(string heading, double expected) => Assert.Equal(expected, heading.FromAbbreviatedHeading()); [InlineData(0, '↑')] [InlineData(11.2, '↑')] [InlineData(11.3, '↑')] [InlineData(22.5, '↗')] [InlineData(33.7, '↗')] [InlineData(33.8, '↗')] [InlineData(45, '↗')] [InlineData(56.2, '↗')] [InlineData(56.3, '↗')] [InlineData(67.5, '→')] [InlineData(78.7, '→')] [InlineData(78.8, '→')] [InlineData(90, '→')] [InlineData(101.2, '→')] [InlineData(101.3, '→')] [InlineData(112.5, '↘')] [InlineData(123.7, '↘')] [InlineData(123.8, '↘')] [InlineData(135, '↘')] [InlineData(146.2, '↘')] [InlineData(146.3, '↘')] [InlineData(157.5, '↓')] [InlineData(168.7, '↓')] [InlineData(168.8, '↓')] [InlineData(180, '↓')] [InlineData(191.2, '↓')] [InlineData(191.3, '↓')] [InlineData(202.5, '↙')] [InlineData(213.7, '↙')] [InlineData(213.8, '↙')] [InlineData(225, '↙')] [InlineData(236.2, '↙')] [InlineData(236.3, '↙')] [InlineData(247.5, '←')] [InlineData(258.7, '←')] [InlineData(258.8, '←')] [InlineData(270, '←')] [InlineData(281.2, '←')] [InlineData(281.3, '←')] [InlineData(292.5, '↖')] [InlineData(303.7, '↖')] [InlineData(303.8, '↖')] [InlineData(315, '↖')] [InlineData(326.2, '↖')] [InlineData(326.3, '↖')] [InlineData(337.5, '↑')] [InlineData(348.7, '↑')] [InlineData(348.8, '↑')] [InlineData(360, '↑')] [InlineData(720, '↑')] [Theory] public void ToHeadingArrow(double heading, char expected) => Assert.Equal(expected, heading.ToHeadingArrow()); [InlineData('↑', 0)] [InlineData('↗', 45)] [InlineData('→', 90)] [InlineData('↘', 135)] [InlineData('↓', 180)] [InlineData('↙', 225)] [InlineData('←', 270)] [InlineData('↖', 315)] [InlineData('\n', -1)] [Theory] public void FromHeadingArrow(char heading, double expected) => Assert.Equal(expected, heading.FromHeadingArrow()); [InlineData("↑", 0)] [InlineData("↗", 45)] [InlineData("→", 90)] [InlineData("↘", 135)] [InlineData("↓", 180)] [InlineData("↙", 225)] [InlineData("←", 270)] [InlineData("↖", 315)] [InlineData("", -1)] [InlineData("xyz", -1)] [Theory] public void FromHeadingArrow_Also_Works_With_Strings(string heading, double expected) => Assert.Equal(expected, heading.FromHeadingArrow()); [InlineData("NNW", "en-US", 337.5)] [InlineData("ØNØ", "da", 67.5)] [InlineData("O", "de-DE", 90.0)] [Theory] public void FromShortHeading_CanSpecifyCultureExplicitly(string heading, string culture, double expected) => Assert.Equal(expected, heading.FromAbbreviatedHeading(new(culture))); } ================================================ FILE: tests/Humanizer.Tests/Humanizer.Tests.csproj ================================================  net10.0;net8.0;net48 Exe true true ================================================ FILE: tests/Humanizer.Tests/InflectorTests.cs ================================================ //The Inflector class was cloned from Inflector (https://github.com/srkirkland/Inflector) //The MIT License (MIT) //Copyright (c) 2013 Scott Kirkland //Permission is hereby granted, free of charge, to any person obtaining a copy of //this software and associated documentation files (the "Software"), to deal in //the Software without restriction, including without limitation the rights to //use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of //the Software, and to permit persons to whom the Software is furnished to do so, //subject to the following conditions: //The above copyright notice and this permission notice shall be included in all //copies or substantial portions of the Software. //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS //FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR //COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER //IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN //CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using System.Collections; public class InflectorTests { public readonly IList PluralTestData = []; [Theory] [ClassData(typeof(PluralTestSource))] public void Pluralize(string singular, string plural) => Assert.Equal(plural, singular.Pluralize()); [Theory] [ClassData(typeof(PluralTestSource))] public void PluralizeWordsWithUnknownPlurality(string singular, string plural) { Assert.Equal(plural, plural.Pluralize(false)); Assert.Equal(plural, singular.Pluralize(false)); } [Theory] [ClassData(typeof(PluralTestSource))] public void Singularize(string singular, string plural) => Assert.Equal(singular, plural.Singularize()); [Theory] [ClassData(typeof(PluralTestSource))] public void SingularizeWordsWithUnknownSingularity(string singular, string plural) { Assert.Equal(singular, singular.Singularize(false)); Assert.Equal(singular, plural.Singularize(false)); } [Theory] [InlineData("tires", "tires")] [InlineData("body", "bodies")] [InlineData("traxxas", "traxxas")] public void SingularizeSkipSimpleWords(string singular, string plural) => Assert.Equal(singular, plural.Singularize(skipSimpleWords: true)); [Theory] [InlineData("a")] [InlineData("A")] [InlineData("s")] [InlineData("S")] [InlineData("z")] [InlineData("Z")] [InlineData("1")] public void SingularizeSingleLetter(string input) => Assert.Equal(input, input.Singularize()); //Uppercases individual words and removes some characters [Theory] [InlineData("some title", "Some Title")] [InlineData("some-title", "Some Title")] [InlineData("sometitle", "Sometitle")] [InlineData("some-title: The beginning", "Some Title: The Beginning")] [InlineData("some_title:_the_beginning", "Some Title: the Beginning")] [InlineData("some title: The_beginning", "Some Title: The Beginning")] public void Titleize(string input, string expectedOutput) => Assert.Equal(expectedOutput, input.Titleize()); // Issue #385: Titleize should preserve input with no recognized letters [Theory] [InlineData("Майк", "Майк")] [InlineData("@@", "@@")] [InlineData("?", "?")] [InlineData("123", "123")] public void TitleizeShouldPreserveUnrecognizedCharacters(string input, string expected) => Assert.Equal(expected, input.Titleize()); [InlineData("some_title", "some-title")] [InlineData("some-title", "some-title")] [InlineData("some_title_goes_here", "some-title-goes-here")] [InlineData("some_title and_another", "some-title and-another")] [Theory] public void Dasherize(string input, string expectedOutput) => Assert.Equal(input.Dasherize(), expectedOutput); [InlineData("some_title", "some-title")] [InlineData("some-title", "some-title")] [InlineData("some_title_goes_here", "some-title-goes-here")] [InlineData("some_title and_another", "some-title and-another")] [Theory] public void Hyphenate(string input, string expectedOutput) => Assert.Equal(input.Hyphenate(), expectedOutput); [Theory] [InlineData("customer", "Customer")] [InlineData("CUSTOMER", "CUSTOMER")] [InlineData("CUStomer", "CUStomer")] [InlineData("customer_name", "CustomerName")] [InlineData("customer_first_name", "CustomerFirstName")] [InlineData("customer_first_name goes here", "CustomerFirstNameGoesHere")] [InlineData("customer name", "CustomerName")] [InlineData("customer name 1", "CustomerName1")] [InlineData("customer name $", "CustomerName$")] [InlineData("customer name", "CustomerName")] [InlineData("customer-first-name", "CustomerFirstName")] [InlineData("_customer-first-name", "CustomerFirstName")] [InlineData(" customer__first--name", "CustomerFirstName")] public void Pascalize(string input, string expectedOutput) => Assert.Equal(expectedOutput, input.Pascalize()); // Same as pascalize, except first char is lowercase [Theory] [InlineData("customer", "customer")] [InlineData("CUSTOMER", "cUSTOMER")] [InlineData("CUStomer", "cUStomer")] [InlineData("customer_name", "customerName")] [InlineData("customer_first_name", "customerFirstName")] [InlineData("customer_first_name goes here", "customerFirstNameGoesHere")] [InlineData("customer name", "customerName")] [InlineData("customer name 1", "customerName1")] [InlineData("customer name $", "customerName$")] [InlineData("customer name", "customerName")] [InlineData("", "")] public void Camelize(string input, string expectedOutput) => Assert.Equal(expectedOutput, input.Camelize()); //Makes an underscored lowercase string [Theory] [InlineData("SomeTitle", "some_title")] [InlineData("someTitle", "some_title")] [InlineData("some title", "some_title")] [InlineData("some title that will be underscored", "some_title_that_will_be_underscored")] [InlineData("SomeTitleThatWillBeUnderscored", "some_title_that_will_be_underscored")] [InlineData("SomeForeignWordsLikeÄgyptenÑu", "some_foreign_words_like_ägypten_ñu")] [InlineData("Some wordsTo be Underscored", "some_words_to_be_underscored")] public void Underscore(string input, string expectedOutput) => Assert.Equal(expectedOutput, input.Underscore()); // transform words into lowercase and separate with a - [Theory] [InlineData("SomeWords", "some-words")] [InlineData("SOME words TOGETHER", "some-words-together")] [InlineData("A spanish word EL niño", "a-spanish-word-el-niño")] [InlineData("SomeForeignWords ÆgÑuÄgypten", "some-foreign-words-æg-ñu-ägypten")] [InlineData("A VeryShortSENTENCE", "a-very-short-sentence")] public void Kebaberize(string input, string expectedOutput) => Assert.Equal(expectedOutput, input.Kebaberize()); } class PluralTestSource : IEnumerable { public IEnumerator GetEnumerator() { yield return ["search", "searches"]; yield return ["switch", "switches"]; yield return ["fix", "fixes"]; yield return ["box", "boxes"]; yield return ["process", "processes"]; yield return ["address", "addresses"]; yield return ["case", "cases"]; yield return ["stack", "stacks"]; yield return ["wish", "wishes"]; yield return ["fish", "fish"]; yield return ["category", "categories"]; yield return ["query", "queries"]; yield return ["ability", "abilities"]; yield return ["agency", "agencies"]; yield return ["movie", "movies"]; yield return ["archive", "archives"]; yield return ["index", "indices"]; yield return ["wife", "wives"]; yield return ["safe", "saves"]; yield return ["half", "halves"]; yield return ["glove", "gloves"]; yield return ["move", "moves"]; yield return ["salesperson", "salespeople"]; yield return ["person", "people"]; yield return ["spokesman", "spokesmen"]; yield return ["man", "men"]; yield return ["woman", "women"]; yield return ["freshman", "freshmen"]; yield return ["chairman", "chairmen"]; yield return ["human", "humans"]; yield return ["personnel", "personnel"]; yield return ["staff", "staff"]; yield return ["training", "training"]; yield return ["basis", "bases"]; yield return ["diagnosis", "diagnoses"]; yield return ["datum", "data"]; yield return ["medium", "media"]; yield return ["analysis", "analyses"]; yield return ["node_child", "node_children"]; yield return ["child", "children"]; yield return ["experience", "experiences"]; yield return ["day", "days"]; yield return ["comment", "comments"]; yield return ["foobar", "foobars"]; yield return ["newsletter", "newsletters"]; yield return ["old_news", "old_news"]; yield return ["news", "news"]; yield return ["series", "series"]; yield return ["species", "species"]; yield return ["quiz", "quizzes"]; yield return ["perspective", "perspectives"]; yield return ["ox", "oxen"]; yield return ["photo", "photos"]; yield return ["buffalo", "buffaloes"]; yield return ["tomato", "tomatoes"]; yield return ["dwarf", "dwarves"]; yield return ["elf", "elves"]; yield return ["information", "information"]; yield return ["equipment", "equipment"]; yield return ["bus", "buses"]; yield return ["status", "statuses"]; yield return ["status_code", "status_codes"]; yield return ["mouse", "mice"]; yield return ["louse", "lice"]; yield return ["house", "houses"]; yield return ["octopus", "octopi"]; yield return ["alias", "aliases"]; yield return ["portfolio", "portfolios"]; yield return ["criterion", "criteria"]; yield return ["vertex", "vertices"]; yield return ["matrix", "matrices"]; yield return ["axis", "axes"]; yield return ["testis", "testes"]; yield return ["crisis", "crises"]; yield return ["corn", "corn"]; yield return ["milk", "milk"]; yield return ["rice", "rice"]; yield return ["shoe", "shoes"]; yield return ["horse", "horses"]; yield return ["prize", "prizes"]; yield return ["edge", "edges"]; /* Tests added by Bas Jansen */ yield return ["goose", "geese"]; yield return ["deer", "deer"]; yield return ["sheep", "sheep"]; yield return ["wolf", "wolves"]; yield return ["volcano", "volcanoes"]; yield return ["aircraft", "aircraft"]; yield return ["alumna", "alumnae"]; yield return ["alumnus", "alumni"]; yield return ["fungus", "fungi"]; yield return ["water", "water"]; yield return ["waters", "waters"]; yield return ["semen", "semen"]; yield return ["sperm", "sperm"]; yield return ["wave", "waves"]; yield return ["campus", "campuses"]; yield return ["is", "are"]; yield return ["addendum", "addenda"]; yield return ["alga", "algae"]; yield return ["appendix", "appendices"]; yield return ["bias", "biases"]; yield return ["bison", "bison"]; yield return ["blitz", "blitzes"]; yield return ["buzz", "buzzes"]; yield return ["cactus", "cacti"]; yield return ["corps", "corps"]; yield return ["curriculum", "curricula"]; yield return ["die", "dice"]; yield return ["echo", "echoes"]; yield return ["ellipsis", "ellipses"]; yield return ["elk", "elk"]; yield return ["emphasis", "emphases"]; yield return ["embargo", "embargoes"]; yield return ["focus", "foci"]; yield return ["foot", "feet"]; yield return ["fuse", "fuses"]; yield return ["grass", "grass"]; yield return ["hair", "hair"]; yield return ["hero", "heroes"]; yield return ["hippopotamus", "hippopotami"]; yield return ["hoof", "hooves"]; yield return ["iris", "irises"]; yield return ["larva", "larvae"]; yield return ["leaf", "leaves"]; yield return ["loaf", "loaves"]; yield return ["luggage", "luggage"]; yield return ["means", "means"]; yield return ["mail", "mail"]; yield return ["millennium", "millennia"]; yield return ["moose", "moose"]; yield return ["mosquito", "mosquitoes"]; yield return ["mud", "mud"]; yield return ["nucleus", "nuclei"]; yield return ["neurosis", "neuroses"]; yield return ["oasis", "oases"]; yield return ["offspring", "offspring"]; yield return ["paralysis", "paralyses"]; yield return ["phenomenon", "phenomena"]; yield return ["potato", "potatoes"]; yield return ["radius", "radii"]; yield return ["salmon", "salmon"]; yield return ["scissors", "scissors"]; yield return ["shrimp", "shrimp"]; yield return ["someone", "someone"]; yield return ["stimulus", "stimuli"]; yield return ["swine", "swine"]; yield return ["syllabus", "syllabi"]; yield return ["that", "those"]; yield return ["thief", "thieves"]; yield return ["this", "these"]; yield return ["tie", "ties"]; yield return ["tooth", "teeth"]; yield return ["torpedo", "torpedoes"]; yield return ["trellis", "trellises"]; yield return ["trout", "trout"]; yield return ["tuna", "tuna"]; yield return ["vertebra", "vertebrae"]; yield return ["veto", "vetoes"]; yield return ["virus", "viruses"]; yield return ["walrus", "walruses"]; yield return ["waltz", "waltzes"]; yield return ["zombie", "zombies"]; yield return ["cookie", "cookies"]; yield return ["bookie", "bookies"]; yield return ["rookie", "rookies"]; yield return ["roomie", "roomies"]; yield return ["smoothie", "smoothies"]; //Issue #789 yield return ["cache", "caches"]; //Issue #975, added by Alex Boutin yield return ["ex", "exes"]; yield return ["", ""]; //Issue #1100 yield return ["doe", "does"]; yield return ["hoe", "hoes"]; yield return ["toe", "toes"]; yield return ["woe", "woes"]; //Issue #1132 yield return ["metadata", "metadata"]; //Issue #1154 yield return ["a", "as"]; yield return ["A", "As"]; yield return ["s", "ss"]; yield return ["S", "Ss"]; yield return ["z", "zs"]; yield return ["Z", "Zs"]; yield return ["1", "1s"]; //Issue #1252 yield return ["pliers", "pliers"]; yield return ["sheers", "sheers"]; yield return ["valve", "valves"]; yield return ["clothes", "clothes"]; yield return ["lens", "lenses"]; yield return ["apparatus", "apparatus"]; yield return ["clove", "cloves"]; yield return ["chassis", "chassis"]; yield return ["explosive", "explosives"]; yield return ["debris", "debris"]; //Issue #1042 yield return ["database", "databases"]; } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } ================================================ FILE: tests/Humanizer.Tests/Localisation/DefaultFormatterTests.cs ================================================ namespace Humanizer.Tests.Localisation; public class DefaultFormatterTests { [Fact] [UseCulture("iv")] public void HandlesNotImplementedCollectionFormattersGracefully() { var a = new[] { DateTime.UtcNow, DateTime.UtcNow.AddDays(10) }; var b = a.Humanize(); Assert.Equal(a[0] + " & " + a[1], b); } } ================================================ FILE: tests/Humanizer.Tests/Localisation/ResourcesTests.cs ================================================ namespace Humanizer.Tests.Localisation; public class ResourcesTests { [Fact] [UseCulture("ro")] public void CanGetCultureSpecificTranslationsWithImplicitCulture() { var format = Resources.GetResource("DateHumanize_MultipleYearsAgo"); Assert.Equal("acum {0}{1} ani", format); } [Fact] public void CanGetCultureSpecificTranslationsWithExplicitCulture() { var format = Resources.GetResource("DateHumanize_MultipleYearsAgo", new("ro")); Assert.Equal("acum {0}{1} ani", format); } } ================================================ FILE: tests/Humanizer.Tests/Localisation/af/DateHumanizeTests.cs ================================================ namespace af; [UseCulture("af")] public class DateHumanizeTests { [Theory] [InlineData(2, "2 dae gelede")] [InlineData(1, "gister")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(2, "2 ure gelede")] [InlineData(1, "1 uur terug")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(2, "2 minute terug")] [InlineData(1, "1 minuut terug")] [InlineData(60, "1 uur terug")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(2, "2 maande gelede")] [InlineData(1, "1 maand gelede")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(2, "2 sekondes terug")] [InlineData(1, "1 sekonde terug")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(2, "2 jaar gelede")] [InlineData(1, "1 jaar gelede")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(2, "oor 2 dae")] [InlineData(1, "môre")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(2, "oor 2 ure")] [InlineData(1, "oor 1 uur")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(2, "oor 2 minute")] [InlineData(1, "oor 1 minuut")] [InlineData(60, "oor 1 uur")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(2, "oor 2 maande")] [InlineData(1, "oor 1 maand")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(2, "oor 2 sekondes")] [InlineData(1, "oor 1 sekonde")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(2, "oor 2 jaar")] [InlineData(1, "oor 1 jaar")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Theory] [InlineData(0, "nou")] public void RightNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/af/NumberToWordsTests.cs ================================================ namespace af; [UseCulture("af")] public class AfrikaansNumberToWordsTests { [InlineData(1, "een")] [InlineData(10, "tien")] [InlineData(11, "elf")] [InlineData(20, "twintig")] [InlineData(122, "een honderd twee en twintig")] [InlineData(3501, "drie duisend vyf honderd en een")] [InlineData(100, "een honderd")] [InlineData(1000, "een duisend")] [InlineData(100000, "een honderd duisend")] [InlineData(1000000, "een miljoen")] [InlineData(10000000, "tien miljoen")] [InlineData(100000000, "een honderd miljoen")] [InlineData(1000000000, "een miljard")] [InlineData(111, "een honderd en elf")] [InlineData(1111, "een duisend een honderd en elf")] [InlineData(111111, "een honderd en elf duisend een honderd en elf")] [InlineData(1111111, "een miljoen een honderd en elf duisend een honderd en elf")] [InlineData(11111111, "elf miljoen een honderd en elf duisend een honderd en elf")] [InlineData(111111111, "een honderd en elf miljoen een honderd en elf duisend een honderd en elf")] [InlineData(1111111111, "een miljard een honderd en elf miljoen een honderd en elf duisend een honderd en elf")] [InlineData(123, "een honderd drie en twintig")] [InlineData(1234, "een duisend twee honderd vier en dertig")] [InlineData(12345, "twaalf duisend drie honderd vyf en veertig")] [InlineData(123456, "een honderd drie en twintig duisend vier honderd ses en vyftig")] [InlineData(1234567, "een miljoen twee honderd vier en dertig duisend vyf honderd sewe en sestig")] [InlineData(12345678, "twaalf miljoen drie honderd vyf en veertig duisend ses honderd agt en sewentig")] [InlineData(123456789, "een honderd drie en twintig miljoen vier honderd ses en vyftig duisend sewe honderd nege en tagtig")] [InlineData(1234567890, "een miljard twee honderd vier en dertig miljoen vyf honderd sewe en sestig duisend agt honderd en negentig")] [Theory] public void ToWords(int number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(0, "nulste")] [InlineData(1, "eerste")] [InlineData(2, "tweede")] [InlineData(3, "derde")] [InlineData(4, "vierde")] [InlineData(5, "vyfde")] [InlineData(6, "sesde")] [InlineData(7, "sewende")] [InlineData(8, "agste")] [InlineData(9, "negende")] [InlineData(10, "tiende")] [InlineData(11, "elfde")] [InlineData(12, "twaalfde")] [InlineData(13, "dertiende")] [InlineData(14, "veertiende")] [InlineData(15, "vyftiende")] [InlineData(16, "sestiende")] [InlineData(17, "sewentiende")] [InlineData(18, "agtiende")] [InlineData(19, "negentiende")] [InlineData(20, "twintigste")] [InlineData(21, "een en twintigste")] [InlineData(22, "twee en twintigste")] [InlineData(30, "dertigste")] [InlineData(40, "veertigste")] [InlineData(50, "vyftigste")] [InlineData(60, "sestigste")] [InlineData(70, "sewentigste")] [InlineData(80, "tagtigste")] [InlineData(90, "negentigste")] [InlineData(95, "vyf en negentigste")] [InlineData(96, "ses en negentigste")] [InlineData(100, "honderdste")] [InlineData(112, "honderd en twaalfde")] [InlineData(120, "honderd en twintigste")] [InlineData(121, "honderd een en twintigste")] [InlineData(1000, "duisendste")] [InlineData(1001, "duisend en eerste")] [InlineData(1021, "duisend een en twintigste")] [InlineData(10000, "tien duisendste")] [InlineData(10121, "tien duisend een honderd een en twintigste")] [InlineData(100000, "honderd duisendste")] [InlineData(1000000, "miljoenste")] public void ToOrdinalWords(int number, string words) => Assert.Equal(words, number.ToOrdinalWords()); [Theory] [InlineData(11, "en-US", "eleven")] [InlineData(22, "ar", "اثنان و عشرون")] [InlineData(40, "ru", "сорок")] public void ToWords_CanSpecifyCultureExplicitly(int number, string culture, string expected) => Assert.Equal(expected, number.ToWords(new(culture))); [Theory] [InlineData(1021, "en-US", "thousand and twenty-first")] [InlineData(21, "ar", "الحادي و العشرون")] [InlineData(1112, "ru", "одна тысяча сто двенадцатый")] public void ToOrdinalWords_CanSpecifyCultureExplicitly(int number, string culture, string expected) => Assert.Equal(expected, number.ToOrdinalWords(new(culture))); } ================================================ FILE: tests/Humanizer.Tests/Localisation/af/TimeSpanHumanizeTests.cs ================================================ namespace af; [UseCulture("af")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "1 jaar")] [InlineData(731, "2 jaar")] [InlineData(1096, "3 jaar")] [InlineData(4018, "11 jaar")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "1 maand")] [InlineData(61, "2 maande")] [InlineData(92, "3 maande")] [InlineData(335, "11 maande")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Fact] public void TwoWeeks() => Assert.Equal("2 weke", TimeSpan.FromDays(14).Humanize()); [Fact] public void OneWeek() => Assert.Equal("1 week", TimeSpan.FromDays(7).Humanize()); [Fact] public void SixDays() => Assert.Equal("6 dae", TimeSpan.FromDays(6).Humanize()); [Fact] public void TwoDays() => Assert.Equal("2 dae", TimeSpan.FromDays(2).Humanize()); [Fact] public void OneDay() => Assert.Equal("1 dag", TimeSpan.FromDays(1).Humanize()); [Fact] public void TwoHours() => Assert.Equal("2 ure", TimeSpan.FromHours(2).Humanize()); [Fact] public void OneHour() => Assert.Equal("1 uur", TimeSpan.FromHours(1).Humanize()); [Fact] public void TwoMinutes() => Assert.Equal("2 minute", TimeSpan.FromMinutes(2).Humanize()); [Fact] public void OneMinute() => Assert.Equal("1 minuut", TimeSpan.FromMinutes(1).Humanize()); [Fact] public void TwoSeconds() => Assert.Equal("2 sekondes", TimeSpan.FromSeconds(2).Humanize()); [Fact] public void OneSecond() => Assert.Equal("1 sekond", TimeSpan.FromSeconds(1).Humanize()); [Fact] public void TwoMilliseconds() => Assert.Equal("2 millisekondes", TimeSpan.FromMilliseconds(2).Humanize()); [Fact] public void OneMillisecond() => Assert.Equal("1 millisekond", TimeSpan.FromMilliseconds(1).Humanize()); [Fact] public void NoTime() => Assert.Equal("0 millisekondes", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => Assert.Equal("geen tyd", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ar/DateHumanizeTests.cs ================================================ namespace ar; [UseCulture("ar")] public class DateHumanizeTests { [Theory] [InlineData(-1, "أمس")] [InlineData(-2, "منذ يومين")] [InlineData(-3, "منذ 3 أيام")] [InlineData(-11, "منذ 11 يوم")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "في غضون يوم واحد من الآن")] [InlineData(2, "في غضون يومين من الآن")] [InlineData(10, "في غضون 10 أيام من الآن")] [InlineData(17, "في غضون 17 يوم من الآن")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(-2, "منذ ساعتين")] [InlineData(-1, "منذ ساعة واحدة")] [InlineData(-3, "منذ 3 ساعات")] [InlineData(-11, "منذ 11 ساعة")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "في غضون ساعة واحدة من الآن")] [InlineData(2, "في غضون ساعتين من الآن")] [InlineData(10, "في غضون 10 ساعات من الآن")] [InlineData(23, "في غضون 23 ساعة من الآن")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(-2, "منذ دقيقتين")] [InlineData(-1, "منذ دقيقة واحدة")] [InlineData(-3, "منذ 3 دقائق")] [InlineData(-11, "منذ 11 دقيقة")] [InlineData(60, "منذ ساعة واحدة")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "في غضون دقيقة واحدة من الآن")] [InlineData(2, "في غضون دقيقتين من الآن")] [InlineData(10, "في غضون 10 دقائق من الآن")] [InlineData(23, "في غضون 23 دقيقة من الآن")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(-2, "منذ شهرين")] [InlineData(-1, "منذ شهر واحد")] [InlineData(-3, "منذ 3 أشهر")] [InlineData(-11, "منذ 11 شهر")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "في غضون شهر واحد من الآن")] [InlineData(2, "في غضون شهرين من الآن")] [InlineData(10, "في غضون 10 أشهر من الآن")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(-2, "منذ ثانيتين")] [InlineData(-1, "منذ ثانية واحدة")] [InlineData(-3, "منذ 3 ثوان")] [InlineData(-11, "منذ 11 ثانية")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(0, "الآن")] [InlineData(1, "في غضون ثانية واحدة من الآن")] [InlineData(2, "في غضون ثانيتين من الآن")] [InlineData(10, "في غضون 10 ثوان من الآن")] [InlineData(24, "في غضون 24 ثانية من الآن")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(-2, "منذ عامين")] [InlineData(-1, "العام السابق")] [InlineData(-3, "منذ 3 أعوام")] [InlineData(-11, "منذ 11 عام")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "في غضون سنة واحدة من الآن")] [InlineData(2, "في غضون سنتين من الآن")] [InlineData(7, "في غضون 7 سنوات من الآن")] [InlineData(55, "في غضون 55 سنة من الآن")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ar/NumberToWordsTests.cs ================================================ namespace ar; [UseCulture("ar")] public class NumberToWordsTests { [Theory] [InlineData("صفر", 0)] [InlineData("واحد", 1)] [InlineData("اثنان", 2)] [InlineData("اثنان و عشرون", 22)] [InlineData("أحد عشر", 11)] [InlineData("ثلاثة آلاف و خمس مئة و واحد", 3501)] [InlineData("مليون و واحد", 1000001)] 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)] [InlineData("اثنتان", 2)] [InlineData("اثنتان و عشرون", 22)] [InlineData("إحدى عشرة", 11)] [InlineData("ثلاثة آلاف و خمس مئة و واحدة", 3501)] [InlineData("مليون و واحدة", 1000001)] 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)); [Theory] [InlineData(122, "مئة و اثنتان و عشرون", GrammaticalGender.Feminine)] [InlineData(3501, "ثلاثة آلاف و خمس مئة و واحدة", GrammaticalGender.Feminine)] [InlineData(3501, "ثلاثة آلاف و خمس مئة و واحد", GrammaticalGender.Neuter)] public void ToWordsWithGender(long number, string expected, GrammaticalGender gender) => Assert.Equal(expected, number.ToWords(gender)); [Theory] [InlineData(0, "الصفر")] [InlineData(1, "الأول")] [InlineData(2, "الثاني")] [InlineData(3, "الثالث")] [InlineData(4, "الرابع")] [InlineData(5, "الخامس")] [InlineData(6, "السادس")] [InlineData(7, "السابع")] [InlineData(8, "الثامن")] [InlineData(9, "التاسع")] [InlineData(10, "العاشر")] [InlineData(11, "الحادي عشر")] [InlineData(12, "الثاني عشر")] [InlineData(13, "الثالث عشر")] [InlineData(14, "الرابع عشر")] [InlineData(15, "الخامس عشر")] [InlineData(16, "السادس عشر")] [InlineData(17, "السابع عشر")] [InlineData(18, "الثامن عشر")] [InlineData(19, "التاسع عشر")] [InlineData(20, "العشرون")] [InlineData(21, "الحادي و العشرون")] [InlineData(22, "الثاني و العشرون")] [InlineData(30, "الثلاثون")] [InlineData(40, "الأربعون")] [InlineData(50, "الخمسون")] [InlineData(60, "الستون")] [InlineData(70, "السبعون")] [InlineData(80, "الثمانون")] [InlineData(90, "التسعون")] [InlineData(95, "الخامس و التسعون")] [InlineData(96, "السادس و التسعون")] [InlineData(100, "المئة")] [InlineData(120, "العشرون بعد المئة")] [InlineData(121, "الحادي و العشرون بعد المئة")] [InlineData(200, "المئتان")] [InlineData(221, "الحادي و العشرون بعد المئتان")] [InlineData(300, "الثلاث مئة")] [InlineData(321, "الحادي و العشرون بعد الثلاث مئة")] [InlineData(327, "السابع و العشرون بعد الثلاث مئة")] [InlineData(1000, "الألف")] [InlineData(1001, "الأول بعد الألف")] [InlineData(1021, "الحادي و العشرون بعد الألف")] [InlineData(10000, "العشرة آلاف")] [InlineData(10121, "الحادي و العشرون بعد العشرة آلاف و مئة")] [InlineData(100000, "المئة ألف")] [InlineData(1000000, "المليون")] [InlineData(1020135, "الخامس و الثلاثون بعد المليون و عشرون ألفاً و مئة")] public void ToOrdinalWords(int number, string words) => Assert.Equal(words, number.ToOrdinalWords()); [Theory] [InlineData(0, "الصفر")] [InlineData(1, "الأولى")] [InlineData(2, "الثانية")] [InlineData(3, "الثالثة")] [InlineData(4, "الرابعة")] [InlineData(5, "الخامسة")] [InlineData(6, "السادسة")] [InlineData(7, "السابعة")] [InlineData(8, "الثامنة")] [InlineData(9, "التاسعة")] [InlineData(10, "العاشرة")] [InlineData(11, "الحادية عشرة")] [InlineData(12, "الثانية عشرة")] [InlineData(13, "الثالثة عشرة")] [InlineData(14, "الرابعة عشرة")] [InlineData(15, "الخامسة عشرة")] [InlineData(16, "السادسة عشرة")] [InlineData(17, "السابعة عشرة")] [InlineData(18, "الثامنة عشرة")] [InlineData(19, "التاسعة عشرة")] [InlineData(20, "العشرون")] [InlineData(21, "الحادية و العشرون")] [InlineData(22, "الثانية و العشرون")] [InlineData(30, "الثلاثون")] [InlineData(40, "الأربعون")] [InlineData(50, "الخمسون")] [InlineData(60, "الستون")] [InlineData(70, "السبعون")] [InlineData(80, "الثمانون")] [InlineData(90, "التسعون")] [InlineData(95, "الخامسة و التسعون")] [InlineData(96, "السادسة و التسعون")] [InlineData(100, "المئة")] [InlineData(120, "العشرون بعد المئة")] [InlineData(121, "الحادية و العشرون بعد المئة")] [InlineData(200, "المئتان")] [InlineData(221, "الحادية و العشرون بعد المئتان")] [InlineData(300, "الثلاث مئة")] [InlineData(321, "الحادية و العشرون بعد الثلاث مئة")] [InlineData(327, "السابعة و العشرون بعد الثلاث مئة")] [InlineData(1000, "الألف")] [InlineData(1001, "الأولى بعد الألف")] [InlineData(1021, "الحادية و العشرون بعد الألف")] [InlineData(10000, "العشرة آلاف")] [InlineData(10121, "الحادية و العشرون بعد العشرة آلاف و مئة")] [InlineData(100000, "المئة ألف")] [InlineData(1000000, "المليون")] [InlineData(1020135, "الخامسة و الثلاثون بعد المليون و عشرون ألفاً و مئة")] public void ToOrdinalWordsWithFeminineGender(int number, string words) => Assert.Equal(words, number.ToOrdinalWords(GrammaticalGender.Feminine)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ar/TimeSpanHumanizeTests.cs ================================================ namespace ar; [UseCulture("ar")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "السنة 1")] [InlineData(731, "سنتين")] [InlineData(1096, "3 سنة")] [InlineData(4018, "11 سنة")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "شهر 1")] [InlineData(61, "شهرين")] [InlineData(92, "3 أشهر")] [InlineData(335, "11 أشهر")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(7, "أسبوع واحد")] [InlineData(14, "أسبوعين")] [InlineData(21, "3 أسابيع")] [InlineData(77, "11 أسبوع")] public void Weeks(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "يوم واحد")] [InlineData(2, "يومين")] [InlineData(3, "3 أيام")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "ساعة واحدة")] [InlineData(2, "ساعتين")] [InlineData(3, "3 ساعات")] [InlineData(11, "11 ساعة")] public void Hours(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); [Theory] [InlineData(1, "دقيقة واحدة")] [InlineData(2, "دقيقتين")] [InlineData(3, "3 دقائق")] [InlineData(11, "11 دقيقة")] public void Minutes(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); [Theory] [InlineData(1, "ثانية واحدة")] [InlineData(2, "ثانيتين")] [InlineData(3, "3 ثوان")] [InlineData(11, "11 ثانية")] public void Seconds(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); [Theory] [InlineData(1, "جزء من الثانية")] [InlineData(2, "جزئين من الثانية")] [InlineData(3, "3 أجزاء من الثانية")] [InlineData(11, "11 جزء من الثانية")] public void Milliseconds(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); [Fact] public void NoTime() => Assert.Equal("0 جزء من الثانية", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => Assert.Equal("حالاً", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/az/DateHumanizeTests.cs ================================================ namespace az; [UseCulture("az")] public class DateHumanizeTests { [Theory] [InlineData(1, "bir saniyə əvvəl")] [InlineData(10, "10 saniyə əvvəl")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "bir saniyə sonra")] [InlineData(10, "10 saniyə sonra")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(1, "bir dəqiqə əvvəl")] [InlineData(10, "10 dəqiqə əvvəl")] [InlineData(60, "bir saat əvvəl")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "bir dəqiqə sonra")] [InlineData(10, "10 dəqiqə sonra")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(1, "bir saat əvvəl")] [InlineData(10, "10 saat əvvəl")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "bir saat sonra")] [InlineData(10, "10 saat sonra")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(1, "dünən")] [InlineData(10, "10 gün əvvəl")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "sabah")] [InlineData(10, "10 gün sonra")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(1, "bir ay əvvəl")] [InlineData(10, "10 ay əvvəl")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "bir ay sonra")] [InlineData(10, "10 ay sonra")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(1, "bir il əvvəl")] [InlineData(2, "2 il əvvəl")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "bir il sonra")] [InlineData(2, "2 il sonra")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Fact] public void Now() => DateHumanize.Verify("indi", 0, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/az/NumberToWordsTests.cs ================================================ namespace az; [UseCulture("az")] public class NumberToWordsTests { [Theory] [InlineData("sıfır", 0)] [InlineData("bir", 1)] [InlineData("iki", 2)] [InlineData("on", 10)] [InlineData("yüz on iki", 112)] [InlineData("min dörd yüz qırx", 1440)] [InlineData("iyirmi iki", 22)] [InlineData("on bir", 11)] [InlineData("üç min beş yüz bir", 3501)] [InlineData("bir milyon bir", 1000001)] [InlineData("mənfi bir milyon üç yüz qırx altı min yeddi yüz on bir", -1346711)] public void ToWords(string expected, int number) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(0, "sıfırıncı")] [InlineData(1, "birinci")] [InlineData(2, "ikinci")] [InlineData(3, "üçüncü")] [InlineData(4, "dördüncü")] [InlineData(5, "beşinci")] [InlineData(6, "altıncı")] [InlineData(7, "yeddinci")] [InlineData(8, "səkkizinci")] [InlineData(9, "doqquzuncu")] [InlineData(10, "onuncu")] [InlineData(11, "on birinci")] [InlineData(12, "on ikinci")] [InlineData(13, "on üçüncü")] [InlineData(14, "on dördüncü")] [InlineData(15, "on beşinci")] [InlineData(16, "on altıncı")] [InlineData(17, "on yeddinci")] [InlineData(18, "on səkkizinci")] [InlineData(19, "on doqquzuncu")] [InlineData(20, "iyirminci")] [InlineData(21, "iyirmi birinci")] [InlineData(30, "otuzuncu")] [InlineData(40, "qırxıncı")] [InlineData(50, "əllinci")] [InlineData(60, "altmışıncı")] [InlineData(70, "yetmişinci")] [InlineData(80, "səksəninci")] [InlineData(90, "doxsanıncı")] [InlineData(100, "yüzüncü")] [InlineData(120, "yüz iyirminci")] [InlineData(121, "yüz iyirmi birinci")] [InlineData(200, "iki yüzüncü")] [InlineData(221, "iki yüz iyirmi birinci")] [InlineData(300, "üç yüzüncü")] [InlineData(321, "üç yüz iyirmi birinci")] [InlineData(1000, "mininci")] [InlineData(1001, "min birinci")] [InlineData(10000, "on mininci")] [InlineData(100000, "yüz mininci")] [InlineData(1000000, "bir milyonuncu")] [InlineData(1022135, "bir milyon iyirmi iki min yüz otuz beşinci")] public void ToOrdinalWords(int number, string words) => Assert.Equal(words, number.ToOrdinalWords()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/az/TimeSpanHumanizeTests.cs ================================================ namespace az; [UseCulture("az")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "1 il")] [InlineData(731, "2 il")] [InlineData(1096, "3 il")] [InlineData(4018, "11 il")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan .FromDays(days) .Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "1 ay")] [InlineData(61, "2 ay")] [InlineData(92, "3 ay")] [InlineData(335, "11 ay")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan .FromDays(days) .Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(14, "2 həftə")] [InlineData(7, "1 həftə")] public void Weeks(int days, string expected) { var actual = TimeSpan .FromDays(days) .Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(6, "6 gün")] [InlineData(2, "2 gün")] public void Days(int days, string expected) { var actual = TimeSpan .FromDays(days) .Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 saat")] [InlineData(1, "1 saat")] public void Hours(int hours, string expected) { var actual = TimeSpan .FromHours(hours) .Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 dəqiqə")] [InlineData(1, "1 dəqiqə")] public void Minutes(int minutes, string expected) { var actual = TimeSpan .FromMinutes(minutes) .Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 saniyə")] [InlineData(1, "1 saniyə")] public void Seconds(int seconds, string expected) { var actual = TimeSpan .FromSeconds(seconds) .Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 millisaniyə")] [InlineData(1, "1 millisaniyə")] public void Milliseconds(int ms, string expected) { var actual = TimeSpan .FromMilliseconds(ms) .Humanize(); Assert.Equal(expected, actual); } [Fact] public void NoTime() { var noTime = TimeSpan.Zero; var actual = noTime.Humanize(); Assert.Equal("0 millisaniyə", actual); } [Fact] public void NoTimeToWords() { var noTime = TimeSpan.Zero; var actual = noTime.Humanize(toWords: true); Assert.Equal("zaman fərqi yoxdur", actual); } } ================================================ FILE: tests/Humanizer.Tests/Localisation/bg/DateHumanizeTests.cs ================================================ namespace bg; [UseCulture("bg-BG")] public class DateHumanizeTests { [Theory] [InlineData(1, "преди секунда")] [InlineData(2, "преди 2 секунди")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "след секунда")] [InlineData(2, "след 2 секунди")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(1, "преди минута")] [InlineData(2, "преди 2 минути")] [InlineData(60, "преди час")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "след минута")] [InlineData(2, "след 2 минути")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(1, "преди час")] [InlineData(2, "преди 2 часа")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "след час")] [InlineData(2, "след 2 часа")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(1, "вчера")] [InlineData(2, "преди 2 дена")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "утре")] [InlineData(2, "след 2 дена")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(1, "преди месец")] [InlineData(2, "преди 2 месеца")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "след месец")] [InlineData(2, "след 2 месеца")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(1, "преди година")] [InlineData(2, "преди 2 години")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "след година")] [InlineData(2, "след 2 години")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Fact] public void Now() => DateHumanize.Verify("сега", 0, TimeUnit.Day, Tense.Past); } ================================================ FILE: tests/Humanizer.Tests/Localisation/bg/NumberToWordsTests.cs ================================================ namespace bg; [UseCulture("bg")] public class NumberToWordsTests { [Theory] [InlineData(0, "нула")] [InlineData(1, "едно")] [InlineData(10, "десет")] [InlineData(11, "единадесет")] [InlineData(12, "дванадесет")] [InlineData(13, "тринадесет")] [InlineData(14, "четиринадесет")] [InlineData(15, "петнадесет")] [InlineData(16, "шестнадесет")] [InlineData(17, "седемнадесет")] [InlineData(18, "осемнадесет")] [InlineData(19, "деветнадесет")] [InlineData(20, "двадесет")] [InlineData(30, "тридесет")] [InlineData(40, "четиридесет")] [InlineData(50, "петдесет")] [InlineData(60, "шестдесет")] [InlineData(70, "седемдесет")] [InlineData(80, "осемдесет")] [InlineData(90, "деветдесет")] [InlineData(100, "сто")] [InlineData(200, "двеста")] [InlineData(300, "триста")] [InlineData(400, "четиристотин")] [InlineData(500, "петстотин")] [InlineData(600, "шестстотин")] [InlineData(700, "седемстотин")] [InlineData(800, "осемстотин")] [InlineData(900, "деветстотин")] [InlineData(122, "сто двадесет и две")] [InlineData(111, "сто и единадесет")] [InlineData(55, "петдесет и пет")] [InlineData(555, "петстотин петдесет и пет")] [InlineData(1000, "една хиляда")] [InlineData(2000, "две хиляди")] [InlineData(4213, "четири хиляди двеста и тринадесет")] [InlineData(5000, "пет хиляди")] [InlineData(28205, "двадесет и осем хиляди двеста и пет")] [InlineData(35000, "тридесет и пет хиляди")] [InlineData(352192, "триста петдесет и две хиляди сто деветдесет и две")] [InlineData(1000000, "един милион")] [InlineData(2000000, "два милиона")] [InlineData(4000210, "четири милиона двеста и десет")] [InlineData(5200, "пет хиляди и двеста")] [InlineData(1125000, "един милион и сто двадесет и пет хиляди")] [InlineData(1000000000, "един милиард")] [InlineData(2000000000, "два милиарда")] [InlineData(3000000000, "три милиарда")] public void ToWordsBg(long number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(0, "нулев")] [InlineData(1, "първи")] [InlineData(2, "втори")] [InlineData(3, "трети")] [InlineData(4, "четвърти")] [InlineData(5, "пети")] [InlineData(6, "шести")] [InlineData(7, "седми")] [InlineData(8, "осми")] [InlineData(11, "единадесети")] [InlineData(12, "дванадесети")] [InlineData(13, "тринадесети")] [InlineData(14, "четиринадесети")] [InlineData(15, "петнадесети")] [InlineData(16, "шестнадесети")] [InlineData(17, "седемнадесети")] [InlineData(18, "осемнадесети")] [InlineData(19, "деветнадесети")] [InlineData(20, "двадесети")] [InlineData(30, "тридесети")] [InlineData(40, "четиридесети")] [InlineData(50, "петдесети")] [InlineData(60, "шестдесети")] [InlineData(70, "седемдесети")] [InlineData(80, "осемдесети")] [InlineData(90, "деветдесети")] [InlineData(21, "двадесет и първи")] [InlineData(22, "двадесет и втори")] [InlineData(35, "тридесет и пети")] [InlineData(100, "стотен")] [InlineData(111, "сто и единадесети")] [InlineData(200, "двестотен")] [InlineData(300, "тристотен")] [InlineData(1000, "една хиляден")] [InlineData(1111, "една хиляда сто и единадесети")] [InlineData(10000, "десет хиляден")] [InlineData(12345, "дванадесет хиляди триста четиридесет и пети")] [InlineData(12000, "дванадесет хиляден")] [InlineData(100000, "сто хиляден")] [InlineData(101111, "сто и една хиляда сто и единадесети")] [InlineData(1000000, "един милионен")] [InlineData(2000000, "два милионен")] public void ToOrdinalWordsMasculine(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Masculine)); [Theory] [InlineData(0, "нулева")] [InlineData(1, "първа")] [InlineData(2, "втора")] [InlineData(3, "трета")] [InlineData(4, "четвърта")] [InlineData(5, "пета")] [InlineData(6, "шеста")] [InlineData(7, "седма")] [InlineData(8, "осма")] [InlineData(11, "единадесета")] [InlineData(12, "дванадесета")] [InlineData(13, "тринадесета")] [InlineData(14, "четиринадесета")] [InlineData(15, "петнадесета")] [InlineData(16, "шестнадесета")] [InlineData(17, "седемнадесета")] [InlineData(18, "осемнадесета")] [InlineData(19, "деветнадесета")] [InlineData(20, "двадесета")] [InlineData(30, "тридесета")] [InlineData(40, "четиридесета")] [InlineData(50, "петдесета")] [InlineData(60, "шестдесета")] [InlineData(70, "седемдесета")] [InlineData(80, "осемдесета")] [InlineData(90, "деветдесета")] [InlineData(21, "двадесет и първа")] [InlineData(22, "двадесет и втора")] [InlineData(35, "тридесет и пета")] [InlineData(100, "стотна")] [InlineData(111, "сто и единадесета")] [InlineData(200, "двестотна")] [InlineData(300, "тристотна")] [InlineData(1000, "една хилядна")] [InlineData(1111, "една хиляда сто и единадесета")] [InlineData(10000, "десет хилядна")] [InlineData(12345, "дванадесет хиляди триста четиридесет и пета")] [InlineData(12000, "дванадесет хилядна")] [InlineData(100000, "сто хилядна")] [InlineData(101111, "сто и една хиляда сто и единадесета")] [InlineData(1000000, "един милионна")] [InlineData(2000000, "два милионна")] public void ToOrdinalWordsFeminine(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Feminine)); [Theory] [InlineData(0, "нулево")] [InlineData(1, "първо")] [InlineData(2, "второ")] [InlineData(3, "трето")] [InlineData(4, "четвърто")] [InlineData(5, "пето")] [InlineData(6, "шесто")] [InlineData(7, "седмо")] [InlineData(8, "осмо")] [InlineData(11, "единадесето")] [InlineData(12, "дванадесето")] [InlineData(13, "тринадесето")] [InlineData(14, "четиринадесето")] [InlineData(15, "петнадесето")] [InlineData(16, "шестнадесето")] [InlineData(17, "седемнадесето")] [InlineData(18, "осемнадесето")] [InlineData(19, "деветнадесето")] [InlineData(20, "двадесето")] [InlineData(30, "тридесето")] [InlineData(40, "четиридесето")] [InlineData(50, "петдесето")] [InlineData(60, "шестдесето")] [InlineData(70, "седемдесето")] [InlineData(80, "осемдесето")] [InlineData(90, "деветдесето")] [InlineData(21, "двадесет и първо")] [InlineData(22, "двадесет и второ")] [InlineData(35, "тридесет и пето")] [InlineData(100, "стотно")] [InlineData(111, "сто и единадесето")] [InlineData(200, "двестотно")] [InlineData(300, "тристотно")] [InlineData(1000, "една хилядно")] [InlineData(1111, "една хиляда сто и единадесето")] [InlineData(10000, "десет хилядно")] [InlineData(12345, "дванадесет хиляди триста четиридесет и пето")] [InlineData(12000, "дванадесет хилядно")] [InlineData(100000, "сто хилядно")] [InlineData(101111, "сто и една хиляда сто и единадесето")] [InlineData(1000000, "един милионно")] [InlineData(2000000, "два милионно")] public void ToOrdinalWordsNeuter(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Neuter)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/bg/TimeSpanHumanizeTests.cs ================================================ namespace bg; [UseCulture("bg-BG")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "1 година")] [InlineData(731, "2 години")] [InlineData(1096, "3 години")] [InlineData(4018, "11 години")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(366, "една година")] [InlineData(731, "две години")] [InlineData(1096, "три години")] [InlineData(4018, "единадесет години")] // [InlineData(7671, "двадесет и една година")] public void YearsToWords(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year, toWords: true)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "1 месец")] [InlineData(61, "2 месеца")] [InlineData(92, "3 месеца")] [InlineData(335, "11 месеца")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "един месец")] [InlineData(61, "два месеца")] [InlineData(92, "три месеца")] [InlineData(335, "единадесет месеца")] public void MonthsToWords(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Month, toWords: true)); [Theory] [InlineData(7, "1 седмица")] [InlineData(14, "2 седмици")] public void Weeks(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(7, "една седмица")] [InlineData(14, "две седмици")] public void WeeksToWords(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(toWords: true)); [Theory] [InlineData(1, "1 ден")] [InlineData(2, "2 дена")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "един ден")] [InlineData(2, "два дена")] public void DaysToWords(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(toWords: true)); [Theory] [InlineData(1, "1 час")] [InlineData(2, "2 часа")] public void Hours(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); [Theory] [InlineData(1, "един час")] [InlineData(2, "два часа")] public void HoursToWords(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize(toWords: true)); [Theory] [InlineData(1, "1 минута")] [InlineData(2, "2 минути")] public void Minutes(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); [Theory] [InlineData(1, "една минута")] [InlineData(2, "две минути")] public void MinutesToWords(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize(toWords: true)); [Theory] [InlineData(1, "1 секунда")] [InlineData(2, "2 секунди")] public void Seconds(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); [Theory] [InlineData(1, "една секунда")] [InlineData(2, "две секунди")] public void SecondsToWords(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize(toWords: true)); [Theory] [InlineData(1, "1 милисекунда")] [InlineData(2, "2 милисекунди")] public void Milliseconds(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); [Theory] [InlineData(1, "една милисекунда")] [InlineData(2, "две милисекунди")] public void MillisecondsToWords(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize(toWords: true)); [Fact] public void NoTime() => // This one doesn't make a lot of sense but ... w/e Assert.Equal("0 милисекунди", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => Assert.Equal("няма време", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/bn-BD/DateHumanizeTests.cs ================================================ namespace bnBD; [UseCulture("bn-BD")] public class DateHumanizeTests { [Theory] [InlineData(1, "আগামিকাল")] [InlineData(13, "13 দিন পর")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(-1, "গতকাল")] [InlineData(-11, "11 দিন আগে")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "এক ঘণ্টা পর")] [InlineData(11, "11 ঘণ্টা পর")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(-1, "এক ঘণ্টা আগে")] [InlineData(-11, "11 ঘণ্টা আগে")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "এক মিনিট পর")] [InlineData(13, "13 মিনিট পর")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(-1, "এক মিনিট আগে")] [InlineData(-13, "13 মিনিট আগে")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "এক মাস পর")] [InlineData(10, "10 মাস পর")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(-1, "এক মাস আগে")] [InlineData(-10, "10 মাস আগে")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "এক সেকেন্ড পর")] [InlineData(11, "11 সেকেন্ড পর")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(-1, "এক সেকেন্ড আগে")] [InlineData(-11, "11 সেকেন্ড আগে")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "এক বছর পর")] [InlineData(21, "21 বছর পর")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Theory] [InlineData(-1, "এক বছর আগে")] [InlineData(-21, "21 বছর আগে")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); } ================================================ FILE: tests/Humanizer.Tests/Localisation/bn-BD/NumberToWordsTests.cs ================================================ namespace bnBD; [UseCulture("bn-BD")] public class NumberToWordsTests { [InlineData(0, "শূন্য")] [InlineData(1, "এক")] [InlineData(10, "দশ")] [InlineData(11, "এগারো")] [InlineData(20, "বিশ")] [InlineData(122, "একশ বাইশ")] [InlineData(3501, "তিন হাজার পাঁচশ এক")] [InlineData(100, "একশ")] [InlineData(1000, "এক হাজার")] [InlineData(100000, "এক লক্ষ")] [InlineData(1000000, "দশ লক্ষ")] [InlineData(10000000, "এক কোটি")] [InlineData(100000000, "দশ কোটি")] [InlineData(1000000000, "একশ কোটি")] [InlineData(111, "একশ এগারো")] [InlineData(1111, "এক হাজার একশ এগারো")] [InlineData(111111, "এক লক্ষ এগারো হাজার একশ এগারো")] [InlineData(1111111, "এগারো লক্ষ এগারো হাজার একশ এগারো")] [InlineData(11111111, "এক কোটি এগারো লক্ষ এগারো হাজার একশ এগারো")] [InlineData(111111111, "এগারো কোটি এগারো লক্ষ এগারো হাজার একশ এগারো")] [InlineData(1111111111, "একশ এগারো কোটি এগারো লক্ষ এগারো হাজার একশ এগারো")] [InlineData(123, "একশ তেইশ")] [InlineData(1234, "এক হাজার দুইশ চৌঁতিরিশ")] [InlineData(12345, "বারো হাজার তিনশ পঁয়তাল্লিশ")] [InlineData(123456, "এক লক্ষ তেইশ হাজার চারশ ছাপ্পান্ন")] [InlineData(1234567, "বারো লক্ষ চৌঁতিরিশ হাজার পাঁচশ সাতষট্টি")] [InlineData(12345678, "এক কোটি তেইশ লক্ষ পঁয়তাল্লিশ হাজার ছয়শ আটাত্তর")] [InlineData(123456789, "বারো কোটি চৌঁতিরিশ লক্ষ ছাপ্পান্ন হাজার সাতশ উননব্বই")] [InlineData(1234567890, "একশ তেইশ কোটি পঁয়তাল্লিশ লক্ষ সাতষট্টি হাজার আটশ নব্বই")] [InlineData(-1234567890, "ঋণাত্মক একশ তেইশ কোটি পঁয়তাল্লিশ লক্ষ সাতষট্টি হাজার আটশ নব্বই")] [Theory] public void ToWords(int number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(0, "শূন্য তম")] [InlineData(1, "প্রথম")] [InlineData(2, "দ্বিতীয়")] [InlineData(3, "তৃতীয়")] [InlineData(4, "চতুর্থ")] [InlineData(5, "পঞ্চম")] [InlineData(6, "ষষ্ট")] [InlineData(7, "সপ্তম")] [InlineData(8, "অষ্টম")] [InlineData(9, "নবম")] [InlineData(10, "দশম")] [InlineData(11, "একাদশ")] [InlineData(12, "দ্বাদশ")] [InlineData(13, "ত্রয়োদশ")] [InlineData(14, "চতুর্দশ")] [InlineData(15, "পঞ্চদশ")] [InlineData(16, "ষোড়শ")] [InlineData(17, "সপ্তদশ")] [InlineData(18, "অষ্টাদশ")] [InlineData(19, "উনিশ তম")] [InlineData(20, "বিশ তম")] [InlineData(21, "একুশ তম")] [InlineData(100, "শত তম")] [InlineData(112, "একশ বারো তম")] [InlineData(118, "একশ আঠারো তম")] [InlineData(1000, "হাজার তম")] [InlineData(1001, "এক হাজার এক তম")] [InlineData(1021, "এক হাজার একুশ তম")] [InlineData(10000, "দশ হাজার তম")] [InlineData(10121, "দশ হাজার একশ একুশ তম")] [InlineData(100000, "লক্ষ তম")] [InlineData(1000000, "দশ লক্ষ তম")] [InlineData(10000000, "কোটি তম")] public void ToOrdinalWords(int number, string words) => Assert.Equal(words, number.ToOrdinalWords()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/bn-BD/TimeSpanHumanizeTests.cs ================================================ namespace bnBD; [UseCulture("bn-BD")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "এক বছর")] [InlineData(731, "2 বছর")] [InlineData(1096, "3 বছর")] [InlineData(4018, "11 বছর")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "এক মাসের")] [InlineData(61, "2 মাস")] [InlineData(92, "3 মাস")] [InlineData(335, "11 মাস")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(7, "এক সপ্তাহ")] [InlineData(14, "2 সপ্তাহ")] public void Weeks(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "এক দিন")] [InlineData(2, "2 দিন")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "এক ঘণ্টা")] [InlineData(2, "2 ঘণ্টা")] public void Hours(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); [Theory] [InlineData(1, "এক মিনিট")] [InlineData(2, "2 মিনিট")] public void Minutes(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); [Theory] [InlineData(1, "এক সেকেন্ড")] [InlineData(2, "2 সেকেন্ড")] public void Seconds(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); [Theory] [InlineData(1, "এক মিলিসেকেন্ড")] [InlineData(2, "2 মিলিসেকেন্ড")] public void Milliseconds(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); [Fact] public void NoTime() => Assert.Equal("0 মিলিসেকেন্ড", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => // This one really doesn't make a lot of sense but again... w/e Assert.Equal("শূন্য সময়", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ca/DateHumanizeTests.cs ================================================ namespace ca; [UseCulture("ca")] public class DateHumanizeTests { [Theory] [InlineData(1, "fa un segon")] [InlineData(2, "fa 2 segons")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "d'aquí un segon")] [InlineData(2, "d'aquí 2 segons")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(1, "fa un minut")] [InlineData(2, "fa 2 minuts")] [InlineData(60, "fa una hora")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "d'aquí un minut")] [InlineData(2, "d'aquí 2 minuts")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(1, "fa una hora")] [InlineData(2, "fa 2 hores")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "d'aquí una hora")] [InlineData(2, "d'aquí 2 hores")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(1, "ahir")] [InlineData(2, "fa 2 dies")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "demà")] [InlineData(2, "d'aquí 2 dies")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(1, "fa un mes")] [InlineData(2, "fa 2 mesos")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "d'aquí un mes")] [InlineData(2, "d'aquí 2 mesos")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(1, "fa un any")] [InlineData(2, "fa 2 anys")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "d'aquí un any")] [InlineData(2, "d'aquí 2 anys")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ca/DateToOrdinalWordsTests.cs ================================================ namespace ca; [UseCulture("ca")] public class DateToOrdinalWordsTests { [Fact] public void OrdinalizeString() { Assert.Equal("25 de gener de 2022", new DateTime(2022, 1, 25).ToOrdinalWords()); Assert.Equal("29 de febrer de 2020", new DateTime(2020, 2, 29).ToOrdinalWords()); Assert.Equal("4 de setembre de 2015", new DateTime(2015, 9, 4).ToOrdinalWords()); Assert.Equal("7 de novembre de 1979", new DateTime(1979, 11, 7).ToOrdinalWords()); } #if NET6_0_OR_GREATER [Fact] public void OrdinalizeDateOnlyString() { Assert.Equal("25 de gener de 2022", new DateOnly(2022, 1, 25).ToOrdinalWords()); Assert.Equal("29 de febrer de 2020", new DateOnly(2020, 2, 29).ToOrdinalWords()); Assert.Equal("4 de setembre de 2015", new DateOnly(2015, 9, 4).ToOrdinalWords()); Assert.Equal("7 de novembre de 1979", new DateOnly(1979, 11, 7).ToOrdinalWords()); } #endif } ================================================ FILE: tests/Humanizer.Tests/Localisation/ca/NumberToWordsFeminineTest.cs ================================================ namespace ca; [UseCulture("ca")] public class NumberToWordsFeminineTests { [Theory] [InlineData(1, "una")] [InlineData(21, "vint-i-una")] [InlineData(31, "trenta-una")] [InlineData(81, "vuitanta-una")] [InlineData(500, "cinc-centes")] [InlineData(701, "set-centes una")] [InlineData(3500, "tres mil cinc-centes")] [InlineData(200121, "dues-centes mil cent vint-i-una")] [InlineData(200000121, "dos-cents milions cent vint-i-una")] [InlineData(1000001, "un milió una")] public void ToWords(int number, string expected) => Assert.Equal(expected, number.ToWords(GrammaticalGender.Feminine)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ca/NumberToWordsTests.cs ================================================ namespace ca; [UseCulture("ca")] public class NumberToWordsTests { [Theory] [InlineData(-1, "menys primer", GrammaticalGender.Neuter)] [InlineData(0, "zero", GrammaticalGender.Neuter)] [InlineData(1, "primer", GrammaticalGender.Neuter)] [InlineData(1, "primer", GrammaticalGender.Masculine)] [InlineData(1, "primera", GrammaticalGender.Feminine)] [InlineData(2, "segon", GrammaticalGender.Masculine)] [InlineData(2, "segona", GrammaticalGender.Feminine)] [InlineData(3, "tercer", GrammaticalGender.Neuter)] [InlineData(3, "tercer", GrammaticalGender.Masculine)] [InlineData(3, "tercera", GrammaticalGender.Feminine)] [InlineData(4, "quart", GrammaticalGender.Masculine)] [InlineData(4, "quarta", GrammaticalGender.Feminine)] [InlineData(5, "cinquè", GrammaticalGender.Masculine)] [InlineData(5, "cinquena", GrammaticalGender.Feminine)] [InlineData(6, "sisè", GrammaticalGender.Masculine)] [InlineData(6, "sisena", GrammaticalGender.Feminine)] [InlineData(7, "setè", GrammaticalGender.Masculine)] [InlineData(7, "setena", GrammaticalGender.Feminine)] [InlineData(8, "vuitè", GrammaticalGender.Masculine)] [InlineData(8, "vuitena", GrammaticalGender.Feminine)] [InlineData(9, "novè", GrammaticalGender.Masculine)] [InlineData(9, "novena", GrammaticalGender.Feminine)] [InlineData(10, "desè", GrammaticalGender.Masculine)] [InlineData(10, "desena", GrammaticalGender.Feminine)] [InlineData(11, "onzè", GrammaticalGender.Masculine)] [InlineData(11, "onzena", GrammaticalGender.Feminine)] [InlineData(20, "vintè", GrammaticalGender.Masculine)] [InlineData(20, "vintena", GrammaticalGender.Feminine)] [InlineData(22, "vint-i-dosè", GrammaticalGender.Masculine)] [InlineData(22, "vint-i-dosena", GrammaticalGender.Feminine)] [InlineData(30, "trentè", GrammaticalGender.Masculine)] [InlineData(30, "trentena", GrammaticalGender.Feminine)] [InlineData(34, "trenta-quatrè", GrammaticalGender.Masculine)] [InlineData(34, "trenta-quatrena", GrammaticalGender.Feminine)] [InlineData(40, "quarantaè", GrammaticalGender.Masculine)] [InlineData(40, "quarantaena", GrammaticalGender.Feminine)] [InlineData(46, "quaranta-sisè", GrammaticalGender.Masculine)] [InlineData(46, "quaranta-sisena", GrammaticalGender.Feminine)] [InlineData(50, "cinquantaè", GrammaticalGender.Masculine)] [InlineData(50, "cinquantaena", GrammaticalGender.Feminine)] [InlineData(57, "cinquanta-setè", GrammaticalGender.Masculine)] [InlineData(57, "cinquanta-setena", GrammaticalGender.Feminine)] [InlineData(60, "seixantè", GrammaticalGender.Masculine)] [InlineData(60, "seixantena", GrammaticalGender.Feminine)] [InlineData(69, "seixanta-novè", GrammaticalGender.Masculine)] [InlineData(69, "seixanta-novena", GrammaticalGender.Feminine)] [InlineData(70, "setantè", GrammaticalGender.Masculine)] [InlineData(70, "setantena", GrammaticalGender.Feminine)] [InlineData(74, "setanta-quatrè", GrammaticalGender.Masculine)] [InlineData(74, "setanta-quatrena", GrammaticalGender.Feminine)] [InlineData(80, "vuitantè", GrammaticalGender.Masculine)] [InlineData(80, "vuitantena", GrammaticalGender.Feminine)] [InlineData(85, "vuitanta-cinquè", GrammaticalGender.Masculine)] [InlineData(85, "vuitanta-cinquena", GrammaticalGender.Feminine)] [InlineData(90, "norantè", GrammaticalGender.Masculine)] [InlineData(90, "norantena", GrammaticalGender.Feminine)] [InlineData(99, "noranta-novè", GrammaticalGender.Masculine)] [InlineData(99, "noranta-novena", GrammaticalGender.Feminine)] [InlineData(100, "centè", GrammaticalGender.Masculine)] [InlineData(100, "centena", GrammaticalGender.Feminine)] [InlineData(101, "cent primer", GrammaticalGender.Masculine)] [InlineData(101, "cent primera", GrammaticalGender.Feminine)] [InlineData(110, "cent deu", GrammaticalGender.Masculine)] [InlineData(111, "cent onzè", GrammaticalGender.Masculine)] [InlineData(120, "cent vint", GrammaticalGender.Masculine)] [InlineData(121, "cent vint-i-un", GrammaticalGender.Masculine)] [InlineData(121, "cent vint-i-una", GrammaticalGender.Feminine)] [InlineData(200, "dos-cents", GrammaticalGender.Masculine)] [InlineData(200, "dues-centes", GrammaticalGender.Feminine)] [InlineData(201, "dos-cents un", GrammaticalGender.Masculine)] [InlineData(201, "dues-centes una", GrammaticalGender.Feminine)] [InlineData(221, "dos-cents vint-i-un", GrammaticalGender.Masculine)] [InlineData(221, "dues-centes vint-i-una", GrammaticalGender.Feminine)] [InlineData(500, "cinc-cents", GrammaticalGender.Masculine)] [InlineData(500, "cinc-centes", GrammaticalGender.Feminine)] [InlineData(701, "set-cents un", GrammaticalGender.Masculine)] [InlineData(701, "set-centes una", GrammaticalGender.Feminine)] [InlineData(900, "nou-cents", GrammaticalGender.Masculine)] [InlineData(900, "nou-centes", GrammaticalGender.Feminine)] [InlineData(999, "nou-cents noranta-nou", GrammaticalGender.Masculine)] [InlineData(999, "nou-centes noranta-nou", GrammaticalGender.Feminine)] [InlineData(1000, "mil", GrammaticalGender.Masculine)] [InlineData(1001, "mil un", GrammaticalGender.Masculine)] [InlineData(1001, "mil una", GrammaticalGender.Feminine)] [InlineData(1021, "mil vint-i-un", GrammaticalGender.Masculine)] [InlineData(1021, "mil vint-i-una", GrammaticalGender.Feminine)] [InlineData(1100, "mil cent", GrammaticalGender.Masculine)] [InlineData(1100, "mil cent", GrammaticalGender.Feminine)] [InlineData(2000, "dos mil", GrammaticalGender.Masculine)] [InlineData(2100, "dos mil cent", GrammaticalGender.Masculine)] [InlineData(3500, "tres mil cinc-cents", GrammaticalGender.Masculine)] [InlineData(3500, "tres mil cinc-centes", GrammaticalGender.Feminine)] [InlineData(100000, "cent mil", GrammaticalGender.Masculine)] [InlineData(100001, "cent mil un", GrammaticalGender.Masculine)] [InlineData(100001, "cent mil una", GrammaticalGender.Feminine)] [InlineData(100002, "cent mil dos", GrammaticalGender.Masculine)] [InlineData(100002, "cent mil dues", GrammaticalGender.Feminine)] [InlineData(100021, "cent mil vint-i-un", GrammaticalGender.Masculine)] [InlineData(100021, "cent mil vint-i-una", GrammaticalGender.Feminine)] [InlineData(200000, "dos-cents mil", GrammaticalGender.Masculine)] [InlineData(200000, "dues-centes mil", GrammaticalGender.Feminine)] [InlineData(200121, "dos-cents mil cent vint-i-un", GrammaticalGender.Masculine)] [InlineData(200121, "dues-centes mil cent vint-i-una", GrammaticalGender.Feminine)] [InlineData(1000000, "un milió", GrammaticalGender.Masculine)] [InlineData(1000001, "un milió un", GrammaticalGender.Masculine)] [InlineData(1000001, "un milió una", GrammaticalGender.Feminine)] [InlineData(2000000, "dos milions", GrammaticalGender.Masculine)] [InlineData(2000001, "dos milions un", GrammaticalGender.Masculine)] [InlineData(2000001, "dos milions una", GrammaticalGender.Feminine)] [InlineData(200000121, "dos-cents milions cent vint-i-un", GrammaticalGender.Masculine)] [InlineData(200000121, "dos-cents milions cent vint-i-una", GrammaticalGender.Feminine)] public void ToOrdinalWords(int number, string words, GrammaticalGender gender) => Assert.Equal(words, number.ToOrdinalWords(gender)); [Theory] [InlineData(1, WordForm.Abbreviation, GrammaticalGender.Masculine, "1r")] [InlineData(1, WordForm.Abbreviation, GrammaticalGender.Feminine, "1a")] [InlineData(2, WordForm.Abbreviation, GrammaticalGender.Masculine, "2n")] [InlineData(2, WordForm.Abbreviation, GrammaticalGender.Feminine, "2a")] [InlineData(3, WordForm.Abbreviation, GrammaticalGender.Masculine, "3r")] [InlineData(3, WordForm.Abbreviation, GrammaticalGender.Feminine, "3a")] [InlineData(11, WordForm.Abbreviation, GrammaticalGender.Masculine, "11è")] [InlineData(11, WordForm.Abbreviation, GrammaticalGender.Feminine, "11a")] [InlineData(22, WordForm.Abbreviation, GrammaticalGender.Masculine, "22n")] [InlineData(22, WordForm.Abbreviation, GrammaticalGender.Feminine, "22a")] [InlineData(31, WordForm.Abbreviation, GrammaticalGender.Masculine, "31r")] [InlineData(31, WordForm.Abbreviation, GrammaticalGender.Feminine, "31a")] [InlineData(100, WordForm.Abbreviation, GrammaticalGender.Masculine, "100è")] [InlineData(100, WordForm.Abbreviation, GrammaticalGender.Feminine, "100a")] [InlineData(101, WordForm.Abbreviation, GrammaticalGender.Masculine, "101r")] [InlineData(101, WordForm.Abbreviation, GrammaticalGender.Feminine, "101a")] [InlineData(999, WordForm.Abbreviation, GrammaticalGender.Masculine, "999è")] [InlineData(999, WordForm.Abbreviation, GrammaticalGender.Feminine, "999a")] public void ToOrdinalWordsWithWordForm(int number, WordForm wordForm, GrammaticalGender gender, string expected) => Assert.Equal(expected, number.ToOrdinalWords(gender, wordForm)); [Theory] [InlineData(1, WordForm.Abbreviation, GrammaticalGender.Masculine, "1r")] [InlineData(1, WordForm.Abbreviation, GrammaticalGender.Feminine, "1a")] [InlineData(2, WordForm.Abbreviation, GrammaticalGender.Masculine, "2n")] [InlineData(2, WordForm.Abbreviation, GrammaticalGender.Feminine, "2a")] [InlineData(3, WordForm.Abbreviation, GrammaticalGender.Masculine, "3r")] [InlineData(3, WordForm.Abbreviation, GrammaticalGender.Feminine, "3a")] [InlineData(11, WordForm.Abbreviation, GrammaticalGender.Masculine, "11è")] [InlineData(11, WordForm.Abbreviation, GrammaticalGender.Feminine, "11a")] [InlineData(22, WordForm.Abbreviation, GrammaticalGender.Masculine, "22n")] [InlineData(22, WordForm.Abbreviation, GrammaticalGender.Feminine, "22a")] [InlineData(31, WordForm.Abbreviation, GrammaticalGender.Masculine, "31r")] [InlineData(31, WordForm.Abbreviation, GrammaticalGender.Feminine, "31a")] [InlineData(100, WordForm.Abbreviation, GrammaticalGender.Masculine, "100è")] [InlineData(100, WordForm.Abbreviation, GrammaticalGender.Feminine, "100a")] [InlineData(101, WordForm.Abbreviation, GrammaticalGender.Masculine, "101r")] [InlineData(101, WordForm.Abbreviation, GrammaticalGender.Feminine, "101a")] [InlineData(999, WordForm.Abbreviation, GrammaticalGender.Masculine, "999è")] [InlineData(999, WordForm.Abbreviation, GrammaticalGender.Feminine, "999a")] public void ToOrdinalWordsWithWordFormAndGender(int number, WordForm wordForm, GrammaticalGender gender, string expected) => Assert.Equal(expected, number.ToOrdinalWords(gender, wordForm)); [Theory] [InlineData(0, "zero vegades")] [InlineData(2, "doble")] [InlineData(100, "cent vegades")] public void ToTuple(int number, string expected) => Assert.Equal(expected, number.ToTuple()); [Theory] [InlineData(0, "zero", GrammaticalGender.Masculine)] [InlineData(1, "un", GrammaticalGender.Masculine)] [InlineData(1, "una", GrammaticalGender.Feminine)] [InlineData(2, "dos", GrammaticalGender.Masculine)] [InlineData(2, "dues", GrammaticalGender.Feminine)] [InlineData(3, "tres", GrammaticalGender.Masculine)] [InlineData(3, "tres", GrammaticalGender.Feminine)] [InlineData(11, "onze", GrammaticalGender.Masculine)] [InlineData(21, "vint-i-u", GrammaticalGender.Masculine)] [InlineData(21, "vint-i-una", GrammaticalGender.Feminine)] [InlineData(31, "trenta-u", GrammaticalGender.Masculine)] [InlineData(31, "trenta-una", GrammaticalGender.Feminine)] [InlineData(81, "vuitanta-u", GrammaticalGender.Masculine)] [InlineData(81, "vuitanta-una", GrammaticalGender.Feminine)] [InlineData(101, "cent u", GrammaticalGender.Masculine)] [InlineData(101, "cent una", GrammaticalGender.Feminine)] [InlineData(500, "cinc-cents", GrammaticalGender.Masculine)] [InlineData(500, "cinc-centes", GrammaticalGender.Feminine)] [InlineData(701, "set-cents u", GrammaticalGender.Masculine)] [InlineData(701, "set-centes una", GrammaticalGender.Feminine)] [InlineData(3500, "tres mil cinc-cents", GrammaticalGender.Masculine)] [InlineData(3500, "tres mil cinc-centes", GrammaticalGender.Feminine)] [InlineData(200121, "dos-cents mil cent vint-i-u", GrammaticalGender.Masculine)] [InlineData(200121, "dues-centes mil cent vint-i-una", GrammaticalGender.Feminine)] [InlineData(200000121, "dos-cents milions cent vint-i-u", GrammaticalGender.Masculine)] [InlineData(200000121, "dos-cents milions cent vint-i-una", GrammaticalGender.Feminine)] [InlineData(1000001, "un milió u", GrammaticalGender.Masculine)] [InlineData(1000001, "un milió una", GrammaticalGender.Feminine)] [InlineData(-15, "menys quinze", GrammaticalGender.Masculine)] [InlineData(-123, "menys cent vint-i-tres", GrammaticalGender.Masculine)] public void ToWords(long number, string expected, GrammaticalGender gender = GrammaticalGender.Masculine) => Assert.Equal(expected, number.ToWords(gender)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ca/OrdinalizeTests.cs ================================================ namespace ca; [UseCulture("ca")] public class OrdinalizeTests { [Theory] [InlineData(1, "1r")] [InlineData(3, "3r")] public void OrdinalizeDefaultGender(int number, string ordinalized) => Assert.Equal(number.Ordinalize(), ordinalized); [Theory] [InlineData(-1, "1r")] [InlineData(int.MinValue, "0")] public void OrdinalizeZeroOrNegativeNumber(int number, string ordinalized) => Assert.Equal(number.Ordinalize(), ordinalized); [Theory] [InlineData(1, WordForm.Abbreviation, "1r")] [InlineData(1, WordForm.Normal, "1r")] [InlineData(2, WordForm.Abbreviation, "2n")] [InlineData(2, WordForm.Normal, "2n")] [InlineData(3, WordForm.Abbreviation, "3r")] [InlineData(3, WordForm.Normal, "3r")] [InlineData(21, WordForm.Abbreviation, "21r")] [InlineData(21, WordForm.Normal, "21r")] public void OrdinalizeWithWordForm(int number, WordForm wordForm, string expected) { Assert.Equal(expected, number.Ordinalize(wordForm)); Assert.Equal(expected, number.ToString(CultureInfo.CurrentUICulture).Ordinalize(wordForm)); } [Theory] [InlineData(1, GrammaticalGender.Masculine, WordForm.Abbreviation, "1r")] [InlineData(1, GrammaticalGender.Masculine, WordForm.Normal, "1r")] [InlineData(1, GrammaticalGender.Feminine, WordForm.Abbreviation, "1a")] [InlineData(1, GrammaticalGender.Feminine, WordForm.Normal, "1a")] [InlineData(1, GrammaticalGender.Neuter, WordForm.Abbreviation, "1r")] [InlineData(1, GrammaticalGender.Neuter, WordForm.Normal, "1r")] public void OrdinalizeWithWordFormAndGender(int number, GrammaticalGender gender, WordForm wordForm, string expected) { Assert.Equal(expected, number.Ordinalize(gender, wordForm)); Assert.Equal(expected, number.ToString(CultureInfo.CurrentUICulture).Ordinalize(gender, wordForm)); } [Theory] [InlineData("1", "1r")] [InlineData("2", "2n")] [InlineData("3", "3r")] [InlineData("4", "4t")] [InlineData("5", "5è")] [InlineData("6", "6è")] [InlineData("23", "23r")] [InlineData("100", "100è")] [InlineData("101", "101r")] [InlineData("102", "102n")] [InlineData("103", "103r")] [InlineData("1001", "1001r")] public void OrdinalizeString(string number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Masculine), ordinalized); [Theory] [InlineData("0", "0")] [InlineData("1", "1a")] [InlineData("2", "2a")] [InlineData("3", "3a")] [InlineData("4", "4a")] [InlineData("5", "5a")] [InlineData("6", "6a")] [InlineData("23", "23a")] [InlineData("100", "100a")] [InlineData("101", "101a")] [InlineData("102", "102a")] [InlineData("103", "103a")] [InlineData("1001", "1001a")] public void OrdinalizeStringFeminine(string number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Feminine), ordinalized); [Theory] [InlineData(0, "0")] [InlineData(1, "1r")] [InlineData(2, "2n")] [InlineData(3, "3r")] [InlineData(4, "4t")] [InlineData(5, "5è")] [InlineData(6, "6è")] [InlineData(10, "10è")] [InlineData(23, "23r")] [InlineData(100, "100è")] [InlineData(101, "101r")] [InlineData(102, "102n")] [InlineData(103, "103r")] [InlineData(1001, "1001r")] public void OrdinalizeNumber(int number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Masculine), ordinalized); [Theory] [InlineData(0, "0")] [InlineData(1, "1a")] [InlineData(2, "2a")] [InlineData(3, "3a")] [InlineData(4, "4a")] [InlineData(5, "5a")] [InlineData(6, "6a")] [InlineData(10, "10a")] [InlineData(23, "23a")] [InlineData(100, "100a")] [InlineData(101, "101a")] [InlineData(102, "102a")] [InlineData(103, "103a")] [InlineData(1001, "1001a")] public void OrdinalizeNumberFeminine(int number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Feminine), ordinalized); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ca/TimeSpanHumanizeTests.cs ================================================ namespace ca; [UseCulture("ca")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "1 any")] [InlineData(731, "2 anys")] [InlineData(1096, "3 anys")] [InlineData(4018, "11 anys")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "1 mes")] [InlineData(61, "2 mesos")] [InlineData(92, "3 mesos")] [InlineData(335, "11 mesos")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Fact] public void TwoWeeks() => Assert.Equal("2 setmanes", TimeSpan.FromDays(14).Humanize()); [Fact] public void OneWeek() => Assert.Equal("1 setmana", TimeSpan.FromDays(7).Humanize()); [Fact] public void SixDays() => Assert.Equal("6 dies", TimeSpan.FromDays(6).Humanize()); [Fact] public void TwoDays() => Assert.Equal("2 dies", TimeSpan.FromDays(2).Humanize()); [Fact] public void OneDay() => Assert.Equal("1 dia", TimeSpan.FromDays(1).Humanize()); [Fact] public void TwoHours() => Assert.Equal("2 hores", TimeSpan.FromHours(2).Humanize()); [Fact] public void OneHour() => Assert.Equal("1 hora", TimeSpan.FromHours(1).Humanize()); [Fact] public void TwoMinutes() => Assert.Equal("2 minuts", TimeSpan.FromMinutes(2).Humanize()); [Fact] public void OneMinute() => Assert.Equal("1 minut", TimeSpan.FromMinutes(1).Humanize()); [Fact] public void TwoSeconds() => Assert.Equal("2 segons", TimeSpan.FromSeconds(2).Humanize()); [Fact] public void OneSecond() => Assert.Equal("1 segon", TimeSpan.FromSeconds(1).Humanize()); [Fact] public void TwoMilliseconds() => Assert.Equal("2 mil·lisegons", TimeSpan.FromMilliseconds(2).Humanize()); [Fact] public void OneMillisecond() => Assert.Equal("1 mil·lisegon", TimeSpan.FromMilliseconds(1).Humanize()); [Theory] [InlineData(0, 0, 1, 1, 2, "un minut, un segon")] [InlineData(0, 0, 2, 2, 2, "dos minuts, dos segons")] [InlineData(1, 2, 3, 4, 4, "un dia, dues hores, tres minuts, quatre segons")] public void ComplexTimeSpan(int days, int hours, int minutes, int seconds, int precision, string expected) { var timeSpan = new TimeSpan(days, hours, minutes, seconds); Assert.Equal(expected, timeSpan.Humanize(precision, toWords: true)); } [Fact] public void NoTime() => // This one doesn't make a lot of sense but ... w/e Assert.Equal("0 mil·lisegons", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => // This one doesn't make a lot of sense but ... w/e Assert.Equal("res", TimeSpan.Zero.Humanize(toWords: true)); [Fact] public void AllTimeSpansMustBeUniqueForASequenceOfDays() { var culture = new CultureInfo("ca"); var qry = from i in Enumerable.Range(0, 100000) let ts = TimeSpan.FromDays(i) let text = ts.Humanize(precision: 3, culture: culture, maxUnit: TimeUnit.Year) select text; var grouping = from t in qry group t by t into g select new { g.Key, Count = g.Count() }; var allUnique = grouping.All(g => g.Count == 1); Assert.True(allUnique); } [Theory] [InlineData(365, "11 mesos, 30 dies")] [InlineData(365 + 1, "1 any")] [InlineData(365 + 365, "1 any, 11 mesos, 29 dies")] [InlineData(365 + 365 + 1, "2 anys")] [InlineData(365 + 365 + 365, "2 anys, 11 mesos, 29 dies")] [InlineData(365 + 365 + 365 + 1, "3 anys")] [InlineData(365 + 365 + 365 + 365, "3 anys, 11 mesos, 29 dies")] [InlineData(365 + 365 + 365 + 365 + 1, "4 anys")] [InlineData(365 + 365 + 365 + 365 + 366, "4 anys, 11 mesos, 30 dies")] [InlineData(365 + 365 + 365 + 365 + 366 + 1, "5 anys")] public void Year(int days, string expected) { var actual = TimeSpan.FromDays(days).Humanize(precision: 7, maxUnit: TimeUnit.Year); Assert.Equal(expected, actual); } [Theory] [InlineData(30, "4 setmanes, 2 dies")] [InlineData(30 + 1, "1 mes")] [InlineData(30 + 30, "1 mes, 29 dies")] [InlineData(30 + 30 + 1, "2 mesos")] [InlineData(30 + 30 + 31, "2 mesos, 30 dies")] [InlineData(30 + 30 + 31 + 1, "3 mesos")] [InlineData(30 + 30 + 31 + 30, "3 mesos, 29 dies")] [InlineData(30 + 30 + 31 + 30 + 1, "4 mesos")] [InlineData(30 + 30 + 31 + 30 + 31, "4 mesos, 30 dies")] [InlineData(30 + 30 + 31 + 30 + 31 + 1, "5 mesos")] [InlineData(365, "11 mesos, 30 dies")] [InlineData(366, "1 any")] public void Month(int days, string expected) { var actual = TimeSpan.FromDays(days).Humanize(precision: 7, maxUnit: TimeUnit.Year); Assert.Equal(expected, actual); } [Theory] [InlineData(14, "2 setmanes")] [InlineData(7, "1 setmana")] [InlineData(-14, "2 setmanes")] [InlineData(-7, "1 setmana")] [InlineData(730, "104 setmanes")] public void Weeks(int days, string expected) { var actual = TimeSpan.FromDays(days).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(6, "6 dies")] [InlineData(2, "2 dies")] [InlineData(1, "1 dia")] [InlineData(-6, "6 dies")] [InlineData(-2, "2 dies")] [InlineData(-1, "1 dia")] public void Days(int days, string expected) { var actual = TimeSpan.FromDays(days).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 hores")] [InlineData(1, "1 hora")] [InlineData(-2, "2 hores")] [InlineData(-1, "1 hora")] public void Hours(int hours, string expected) { var actual = TimeSpan.FromHours(hours).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 minuts")] [InlineData(1, "1 minut")] [InlineData(-2, "2 minuts")] [InlineData(-1, "1 minut")] public void Minutes(int minutes, string expected) { var actual = TimeSpan.FromMinutes(minutes).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(135, "2 minuts")] [InlineData(60, "1 minut")] [InlineData(2, "2 segons")] [InlineData(1, "1 segon")] [InlineData(-135, "2 minuts")] [InlineData(-60, "1 minut")] [InlineData(-2, "2 segons")] [InlineData(-1, "1 segon")] public void Seconds(int seconds, string expected) { var actual = TimeSpan.FromSeconds(seconds).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2500, "2 segons")] [InlineData(1400, "1 segon")] [InlineData(2, "2 mil·lisegons")] [InlineData(1, "1 mil·lisegon")] [InlineData(-2500, "2 segons")] [InlineData(-1400, "1 segon")] [InlineData(-2, "2 mil·lisegons")] [InlineData(-1, "1 mil·lisegon")] public void Milliseconds(int ms, string expected) { var actual = TimeSpan.FromMilliseconds(ms).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData((long)366 * 24 * 60 * 60 * 1000, "12 mesos", TimeUnit.Month)] [InlineData((long)6 * 7 * 24 * 60 * 60 * 1000, "6 setmanes", TimeUnit.Week)] [InlineData(7 * 24 * 60 * 60 * 1000, "7 dies", TimeUnit.Day)] [InlineData(24 * 60 * 60 * 1000, "24 hores", TimeUnit.Hour)] [InlineData(60 * 60 * 1000, "60 minuts", TimeUnit.Minute)] [InlineData(60 * 1000, "60 segons", TimeUnit.Second)] [InlineData(1000, "1000 mil·lisegons", TimeUnit.Millisecond)] public void TimeSpanWithMaxTimeUnit(long ms, string expected, TimeUnit maxUnit) { var actual = TimeSpan.FromMilliseconds(ms).Humanize(maxUnit: maxUnit); Assert.Equal(expected, actual); } [Theory] [InlineData(10, "10 mil·lisegons", TimeUnit.Millisecond)] [InlineData(10, "res", TimeUnit.Second, true)] [InlineData(10, "res", TimeUnit.Minute, true)] [InlineData(10, "res", TimeUnit.Hour, true)] [InlineData(10, "res", TimeUnit.Day, true)] [InlineData(10, "res", TimeUnit.Week, true)] [InlineData(10, "0 segons", TimeUnit.Second)] [InlineData(10, "0 minuts", TimeUnit.Minute)] [InlineData(10, "0 hores", TimeUnit.Hour)] [InlineData(10, "0 dies", TimeUnit.Day)] [InlineData(10, "0 setmanes", TimeUnit.Week)] [InlineData(2500, "2 segons, 500 mil·lisegons", TimeUnit.Millisecond)] [InlineData(2500, "2 segons", TimeUnit.Second)] [InlineData(2500, "res", TimeUnit.Minute, true)] [InlineData(2500, "res", TimeUnit.Hour, true)] [InlineData(2500, "res", TimeUnit.Day, true)] [InlineData(2500, "res", TimeUnit.Week, true)] [InlineData(2500, "0 minuts", TimeUnit.Minute)] [InlineData(2500, "0 hores", TimeUnit.Hour)] [InlineData(2500, "0 dies", TimeUnit.Day)] [InlineData(2500, "0 setmanes", TimeUnit.Week)] [InlineData(122500, "2 minuts, 2 segons, 500 mil·lisegons", TimeUnit.Millisecond)] [InlineData(122500, "2 minuts, 2 segons", TimeUnit.Second)] [InlineData(122500, "2 minuts", TimeUnit.Minute)] [InlineData(122500, "res", TimeUnit.Hour, true)] [InlineData(122500, "res", TimeUnit.Day, true)] [InlineData(122500, "res", TimeUnit.Week, true)] [InlineData(122500, "0 hores", TimeUnit.Hour)] [InlineData(122500, "0 dies", TimeUnit.Day)] [InlineData(122500, "0 setmanes", TimeUnit.Week)] [InlineData(3722500, "1 hora, 2 minuts, 2 segons, 500 mil·lisegons", TimeUnit.Millisecond)] [InlineData(3722500, "1 hora, 2 minuts, 2 segons", TimeUnit.Second)] [InlineData(3722500, "1 hora, 2 minuts", TimeUnit.Minute)] [InlineData(3722500, "1 hora", TimeUnit.Hour)] [InlineData(3722500, "res", TimeUnit.Day, true)] [InlineData(3722500, "res", TimeUnit.Week, true)] [InlineData(3722500, "0 dies", TimeUnit.Day)] [InlineData(3722500, "0 setmanes", TimeUnit.Week)] [InlineData(90122500, "1 dia, 1 hora, 2 minuts, 2 segons, 500 mil·lisegons", TimeUnit.Millisecond)] [InlineData(90122500, "1 dia, 1 hora, 2 minuts, 2 segons", TimeUnit.Second)] [InlineData(90122500, "1 dia, 1 hora, 2 minuts", TimeUnit.Minute)] [InlineData(90122500, "1 dia, 1 hora", TimeUnit.Hour)] [InlineData(90122500, "1 dia", TimeUnit.Day)] [InlineData(90122500, "res", TimeUnit.Week, true)] [InlineData(90122500, "0 setmanes", TimeUnit.Week)] [InlineData(694922500, "1 setmana, 1 dia, 1 hora, 2 minuts, 2 segons, 500 mil·lisegons", TimeUnit.Millisecond)] [InlineData(694922500, "1 setmana, 1 dia, 1 hora, 2 minuts, 2 segons", TimeUnit.Second)] [InlineData(694922500, "1 setmana, 1 dia, 1 hora, 2 minuts", TimeUnit.Minute)] [InlineData(694922500, "1 setmana, 1 dia, 1 hora", TimeUnit.Hour)] [InlineData(694922500, "1 setmana, 1 dia", TimeUnit.Day)] [InlineData(694922500, "1 setmana", TimeUnit.Week)] [InlineData(2768462500, "1 mes, 1 dia, 1 hora, 1 minut, 2 segons, 500 mil·lisegons", TimeUnit.Millisecond)] [InlineData(2768462500, "1 mes, 1 dia, 1 hora, 1 minut, 2 segons", TimeUnit.Second)] [InlineData(2768462500, "1 mes, 1 dia, 1 hora, 1 minut", TimeUnit.Minute)] [InlineData(2768462500, "1 mes, 1 dia, 1 hora", TimeUnit.Hour)] [InlineData(2768462500, "1 mes, 1 dia", TimeUnit.Day)] [InlineData(2768462500, "1 mes", TimeUnit.Week)] [InlineData(2768462500, "1 mes", TimeUnit.Month)] [InlineData(2768462500, "res", TimeUnit.Year, true)] [InlineData(2768462500, "0 anys", TimeUnit.Year)] [InlineData(34390862500, "1 any, 1 mes, 2 dies, 1 hora, 1 minut, 2 segons, 500 mil·lisegons", TimeUnit.Millisecond)] [InlineData(34390862500, "1 any, 1 mes, 2 dies, 1 hora, 1 minut, 2 segons", TimeUnit.Second)] [InlineData(34390862500, "1 any, 1 mes, 2 dies, 1 hora, 1 minut", TimeUnit.Minute)] [InlineData(34390862500, "1 any, 1 mes, 2 dies, 1 hora", TimeUnit.Hour)] [InlineData(34390862500, "1 any, 1 mes, 2 dies", TimeUnit.Day)] [InlineData(34390862500, "1 any, 1 mes", TimeUnit.Week)] [InlineData(34390862500, "1 any, 1 mes", TimeUnit.Month)] [InlineData(34390862500, "1 any", TimeUnit.Year)] public void TimeSpanWithMinTimeUnit(long ms, string expected, TimeUnit minUnit, bool toWords = false) { var actual = TimeSpan.FromMilliseconds(ms).Humanize(minUnit: minUnit, precision: 7, maxUnit: TimeUnit.Year, toWords: toWords); Assert.Equal(expected, actual); } [Theory] [InlineData(0, 3, "res", true)] [InlineData(0, 2, "res", true)] [InlineData(0, 3, "0 mil·lisegons")] [InlineData(0, 2, "0 mil·lisegons")] [InlineData(10, 2, "10 mil·lisegons")] [InlineData(1400, 2, "1 segon, 400 mil·lisegons")] [InlineData(2500, 2, "2 segons, 500 mil·lisegons")] [InlineData(120000, 2, "2 minuts")] [InlineData(62000, 2, "1 minut, 2 segons")] [InlineData(62020, 2, "1 minut, 2 segons")] [InlineData(62020, 3, "1 minut, 2 segons, 20 mil·lisegons")] [InlineData(3600020, 4, "1 hora, 20 mil·lisegons")] [InlineData(3600020, 3, "1 hora, 20 mil·lisegons")] [InlineData(3600020, 2, "1 hora, 20 mil·lisegons")] [InlineData(3600020, 1, "1 hora")] [InlineData(3603001, 2, "1 hora, 3 segons")] [InlineData(3603001, 3, "1 hora, 3 segons, 1 mil·lisegon")] [InlineData(86400000, 3, "1 dia")] [InlineData(86400000, 2, "1 dia")] [InlineData(86400000, 1, "1 dia")] [InlineData(86401000, 1, "1 dia")] [InlineData(86401000, 2, "1 dia, 1 segon")] [InlineData(86401200, 2, "1 dia, 1 segon")] [InlineData(86401200, 3, "1 dia, 1 segon, 200 mil·lisegons")] [InlineData(1296000000, 1, "2 setmanes")] [InlineData(1296000000, 2, "2 setmanes, 1 dia")] [InlineData(1299600000, 2, "2 setmanes, 1 dia")] [InlineData(1299600000, 3, "2 setmanes, 1 dia, 1 hora")] [InlineData(1299630020, 3, "2 setmanes, 1 dia, 1 hora")] [InlineData(1299630020, 4, "2 setmanes, 1 dia, 1 hora, 30 segons")] [InlineData(1299630020, 5, "2 setmanes, 1 dia, 1 hora, 30 segons, 20 mil·lisegons")] [InlineData(2768462500, 6, "1 mes, 1 dia, 1 hora, 1 minut, 2 segons, 500 mil·lisegons")] [InlineData(2768462500, 5, "1 mes, 1 dia, 1 hora, 1 minut, 2 segons")] [InlineData(2768462500, 4, "1 mes, 1 dia, 1 hora, 1 minut")] [InlineData(2768462500, 3, "1 mes, 1 dia, 1 hora")] [InlineData(2768462500, 2, "1 mes, 1 dia")] [InlineData(2768462500, 1, "1 mes")] [InlineData(34390862500, 7, "1 any, 1 mes, 2 dies, 1 hora, 1 minut, 2 segons, 500 mil·lisegons")] [InlineData(34390862500, 6, "1 any, 1 mes, 2 dies, 1 hora, 1 minut, 2 segons")] [InlineData(34390862500, 5, "1 any, 1 mes, 2 dies, 1 hora, 1 minut")] [InlineData(34390862500, 4, "1 any, 1 mes, 2 dies, 1 hora")] [InlineData(34390862500, 3, "1 any, 1 mes, 2 dies")] [InlineData(34390862500, 2, "1 any, 1 mes")] [InlineData(34390862500, 1, "1 any")] public void TimeSpanWithPrecision(long milliseconds, int precision, string expected, bool toWords = false) { var actual = TimeSpan.FromMilliseconds(milliseconds).Humanize(precision, maxUnit: TimeUnit.Year, toWords: toWords); Assert.Equal(expected, actual); } [Theory] [InlineData(3 * 7 + 4, 2, "3 setmanes, 4 dies")] [InlineData(6 * 7 + 3, 2, "6 setmanes, 3 dies")] [InlineData(72 * 7 + 6, 2, "72 setmanes, 6 dies")] public void DaysWithPrecision(int days, int precision, string expected) { var actual = TimeSpan.FromDays(days).Humanize(precision: precision); Assert.Equal(expected, actual); } [Theory] [InlineData(50)] [InlineData(52)] public void TimeSpanWithMinAndMaxUnits_DoesNotReportExcessiveTime(int minutes) { var actual = TimeSpan.FromMinutes(minutes).Humanize(2, null, TimeUnit.Hour, TimeUnit.Minute); var expected = TimeSpan.FromMinutes(minutes).Humanize(2); Assert.Equal(expected, actual); } [Theory] [InlineData(0, 3, "res", true)] [InlineData(0, 2, "res", true)] [InlineData(0, 3, "0 mil·lisegons")] [InlineData(0, 2, "0 mil·lisegons")] [InlineData(10, 2, "10 mil·lisegons")] [InlineData(1400, 2, "1 segon, 400 mil·lisegons")] [InlineData(2500, 2, "2 segons, 500 mil·lisegons")] [InlineData(60001, 1, "1 minut")] [InlineData(60001, 2, "1 minut")] [InlineData(60001, 3, "1 minut, 1 mil·lisegon")] [InlineData(120000, 2, "2 minuts")] [InlineData(62000, 2, "1 minut, 2 segons")] [InlineData(62020, 2, "1 minut, 2 segons")] [InlineData(62020, 3, "1 minut, 2 segons, 20 mil·lisegons")] [InlineData(3600020, 4, "1 hora, 20 mil·lisegons")] [InlineData(3600020, 3, "1 hora")] [InlineData(3600020, 2, "1 hora")] [InlineData(3600020, 1, "1 hora")] [InlineData(3603001, 2, "1 hora")] [InlineData(3603001, 3, "1 hora, 3 segons")] [InlineData(86400000, 3, "1 dia")] [InlineData(86400000, 2, "1 dia")] [InlineData(86400000, 1, "1 dia")] [InlineData(86401000, 1, "1 dia")] [InlineData(86401000, 2, "1 dia")] [InlineData(86401000, 3, "1 dia")] [InlineData(86401000, 4, "1 dia, 1 segon")] [InlineData(86401200, 4, "1 dia, 1 segon")] [InlineData(86401200, 5, "1 dia, 1 segon, 200 mil·lisegons")] [InlineData(1296000000, 1, "2 setmanes")] [InlineData(1296000000, 2, "2 setmanes, 1 dia")] [InlineData(1299600000, 2, "2 setmanes, 1 dia")] [InlineData(1299600000, 3, "2 setmanes, 1 dia, 1 hora")] [InlineData(1299630020, 3, "2 setmanes, 1 dia, 1 hora")] [InlineData(1299630020, 4, "2 setmanes, 1 dia, 1 hora")] [InlineData(1299630020, 5, "2 setmanes, 1 dia, 1 hora, 30 segons")] [InlineData(1299630020, 6, "2 setmanes, 1 dia, 1 hora, 30 segons, 20 mil·lisegons")] public void TimeSpanWithPrecisionAndCountingEmptyUnits(int milliseconds, int precision, string expected, bool toWords = false) { var actual = TimeSpan.FromMilliseconds(milliseconds).Humanize(precision: precision, countEmptyUnits: true, toWords: toWords); Assert.Equal(expected, actual); } [Theory] [InlineData(0, 3, "res", true)] [InlineData(0, 2, "res", true)] [InlineData(0, 3, "0 mil·lisegons")] [InlineData(0, 2, "0 mil·lisegons")] [InlineData(10, 2, "10 mil·lisegons")] [InlineData(1400, 2, "1 segon i 400 mil·lisegons")] [InlineData(2500, 2, "2 segons i 500 mil·lisegons")] [InlineData(120000, 2, "2 minuts")] [InlineData(62000, 2, "1 minut i 2 segons")] [InlineData(62020, 2, "1 minut i 2 segons")] [InlineData(62020, 3, "1 minut, 2 segons i 20 mil·lisegons")] [InlineData(3600020, 4, "1 hora i 20 mil·lisegons")] [InlineData(3600020, 3, "1 hora i 20 mil·lisegons")] [InlineData(3600020, 2, "1 hora i 20 mil·lisegons")] [InlineData(3600020, 1, "1 hora")] [InlineData(3603001, 2, "1 hora i 3 segons")] [InlineData(3603001, 3, "1 hora, 3 segons i 1 mil·lisegon")] [InlineData(86400000, 3, "1 dia")] [InlineData(86400000, 2, "1 dia")] [InlineData(86400000, 1, "1 dia")] [InlineData(86401000, 1, "1 dia")] [InlineData(86401000, 2, "1 dia i 1 segon")] [InlineData(86401200, 2, "1 dia i 1 segon")] [InlineData(86401200, 3, "1 dia, 1 segon i 200 mil·lisegons")] [InlineData(1296000000, 1, "2 setmanes")] [InlineData(1296000000, 2, "2 setmanes i 1 dia")] [InlineData(1299600000, 2, "2 setmanes i 1 dia")] [InlineData(1299600000, 3, "2 setmanes, 1 dia i 1 hora")] [InlineData(1299630020, 3, "2 setmanes, 1 dia i 1 hora")] [InlineData(1299630020, 4, "2 setmanes, 1 dia, 1 hora i 30 segons")] [InlineData(1299630020, 5, "2 setmanes, 1 dia, 1 hora, 30 segons i 20 mil·lisegons")] public void TimeSpanWithPrecisionAndAlternativeCollectionFormatter(int milliseconds, int precision, string expected, bool toWords = false) { var actual = TimeSpan.FromMilliseconds(milliseconds).Humanize(precision, collectionSeparator: null, toWords: toWords); Assert.Equal(expected, actual); } [Theory] [InlineData(0, 3, "res")] [InlineData(0, 2, "res")] [InlineData(10, 2, "deu mil·lisegons")] [InlineData(1400, 2, "un segon, quatre-cents mil·lisegons")] [InlineData(2500, 2, "dos segons, cinc-cents mil·lisegons")] [InlineData(120000, 2, "dos minuts")] [InlineData(62000, 2, "un minut, dos segons")] [InlineData(62020, 2, "un minut, dos segons")] [InlineData(62020, 3, "un minut, dos segons, vint mil·lisegons")] [InlineData(3600020, 4, "una hora, vint mil·lisegons")] [InlineData(3600020, 3, "una hora, vint mil·lisegons")] [InlineData(3600020, 2, "una hora, vint mil·lisegons")] [InlineData(3600020, 1, "una hora")] [InlineData(3603001, 2, "una hora, tres segons")] [InlineData(3603001, 3, "una hora, tres segons, un mil·lisegon")] [InlineData(86400000, 3, "un dia")] [InlineData(86400000, 2, "un dia")] [InlineData(86400000, 1, "un dia")] [InlineData(86401000, 1, "un dia")] [InlineData(86401000, 2, "un dia, un segon")] [InlineData(86401200, 2, "un dia, un segon")] [InlineData(86401200, 3, "un dia, un segon, dos-cents mil·lisegons")] [InlineData(1296000000, 1, "dues setmanes")] [InlineData(1296000000, 2, "dues setmanes, un dia")] [InlineData(1299600000, 2, "dues setmanes, un dia")] [InlineData(1299600000, 3, "dues setmanes, un dia, una hora")] [InlineData(1299630020, 3, "dues setmanes, un dia, una hora")] [InlineData(1299630020, 4, "dues setmanes, un dia, una hora, trenta segons")] [InlineData(1299630020, 5, "dues setmanes, un dia, una hora, trenta segons, vint mil·lisegons")] public void TimeSpanWithNumbersConvertedToWords(int milliseconds, int precision, string expected) { var actual = TimeSpan.FromMilliseconds(milliseconds).Humanize(precision, toWords: true); Assert.Equal(expected, actual); } } ================================================ FILE: tests/Humanizer.Tests/Localisation/ca/TimeToClockNotationTests.cs ================================================ #if NET6_0_OR_GREATER namespace ca; [UseCulture("ca")] public class TimeToClockNotationTests { [Theory] [InlineData(0, 0, "mitjanit")] [InlineData(0, 7, "les dotze i set de la nit")] [InlineData(1, 11, "la una i onze de la matinada")] [InlineData(4, 0, "les quatre de la matinada")] [InlineData(5, 1, "les cinc i un de la matinada")] [InlineData(6, 0, "les sis del matí")] [InlineData(6, 5, "les sis i cinc del matí")] [InlineData(7, 10, "les set i deu del matí")] [InlineData(8, 15, "les vuit i quart del matí")] [InlineData(9, 20, "les nou i vint del matí")] [InlineData(10, 25, "les deu i vint-i-cinc del matí")] [InlineData(11, 30, "les onze i mitja del matí")] [InlineData(12, 00, "migdia")] [InlineData(12, 38, "les dotze i trenta-vuit de la tarda")] [InlineData(12, 35, "la una menys vint-i-cinc de la tarda")] [InlineData(15, 40, "les quatre menys vint de la tarda")] [InlineData(17, 45, "les sis menys quart de la tarda")] [InlineData(19, 50, "les vuit menys deu de la tarda")] [InlineData(21, 0, "les nou de la nit")] [InlineData(21, 55, "les deu menys cinc de la nit")] [InlineData(22, 59, "les deu i cinquanta-nou de la nit")] [InlineData(23, 43, "les onze i quaranta-tres de la nit")] public void ConvertToClockNotationTimeOnlyString(int hours, int minutes, string expectedResult) { var actualResult = new TimeOnly(hours, minutes).ToClockNotation(); Assert.Equal(expectedResult, actualResult); } [Theory] [InlineData(0, 0, "mitjanit")] [InlineData(0, 7, "les dotze i cinc de la nit")] [InlineData(1, 11, "la una i deu de la matinada")] [InlineData(4, 0, "les quatre de la matinada")] [InlineData(5, 1, "les cinc de la matinada")] [InlineData(6, 0, "les sis del matí")] [InlineData(6, 5, "les sis i cinc del matí")] [InlineData(7, 10, "les set i deu del matí")] [InlineData(8, 15, "les vuit i quart del matí")] [InlineData(9, 20, "les nou i vint del matí")] [InlineData(10, 25, "les deu i vint-i-cinc del matí")] [InlineData(11, 30, "les onze i mitja del matí")] [InlineData(12, 00, "migdia")] [InlineData(12, 38, "la una menys vint de la tarda")] [InlineData(12, 35, "la una menys vint-i-cinc de la tarda")] [InlineData(15, 40, "les quatre menys vint de la tarda")] [InlineData(17, 45, "les sis menys quart de la tarda")] [InlineData(19, 50, "les vuit menys deu de la tarda")] [InlineData(21, 0, "les nou de la nit")] [InlineData(21, 55, "les deu menys cinc de la nit")] [InlineData(22, 59, "les onze de la nit")] [InlineData(23, 43, "les dotze menys quart de la nit")] public void ConvertToRoundedClockNotationTimeOnlyString(int hours, int minutes, string expectedResult) { var actualResult = new TimeOnly(hours, minutes).ToClockNotation(ClockNotationRounding.NearestFiveMinutes); Assert.Equal(expectedResult, actualResult); } } #endif ================================================ FILE: tests/Humanizer.Tests/Localisation/cs/DateHumanizeTests.cs ================================================ namespace cs; [UseCulture("cs-CZ")] public class DateHumanizeTests { [Theory] [InlineData(1, "za sekundu")] [InlineData(2, "za 2 sekundy")] [InlineData(3, "za 3 sekundy")] [InlineData(4, "za 4 sekundy")] [InlineData(5, "za 5 sekund")] [InlineData(6, "za 6 sekund")] [InlineData(10, "za 10 sekund")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(1, "za minutu")] [InlineData(2, "za 2 minuty")] [InlineData(3, "za 3 minuty")] [InlineData(4, "za 4 minuty")] [InlineData(5, "za 5 minut")] [InlineData(6, "za 6 minut")] [InlineData(10, "za 10 minut")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(1, "za hodinu")] [InlineData(2, "za 2 hodiny")] [InlineData(3, "za 3 hodiny")] [InlineData(4, "za 4 hodiny")] [InlineData(5, "za 5 hodin")] [InlineData(6, "za 6 hodin")] [InlineData(10, "za 10 hodin")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(1, "zítra")] [InlineData(2, "za 2 dny")] [InlineData(3, "za 3 dny")] [InlineData(4, "za 4 dny")] [InlineData(9, "za 9 dnů")] [InlineData(10, "za 10 dnů")] public void DayFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(1, "za měsíc")] [InlineData(2, "za 2 měsíce")] [InlineData(3, "za 3 měsíce")] [InlineData(4, "za 4 měsíce")] [InlineData(5, "za 5 měsíců")] [InlineData(6, "za 6 měsíců")] [InlineData(10, "za 10 měsíců")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(1, "za rok")] [InlineData(2, "za 2 roky")] [InlineData(3, "za 3 roky")] [InlineData(4, "za 4 roky")] [InlineData(5, "za 5 let")] [InlineData(6, "za 6 let")] [InlineData(10, "za 10 let")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Theory] [InlineData(1, "před sekundou")] [InlineData(2, "před 2 sekundami")] [InlineData(3, "před 3 sekundami")] [InlineData(4, "před 4 sekundami")] [InlineData(5, "před 5 sekundami")] [InlineData(6, "před 6 sekundami")] [InlineData(10, "před 10 sekundami")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "před minutou")] [InlineData(2, "před 2 minutami")] [InlineData(3, "před 3 minutami")] [InlineData(4, "před 4 minutami")] [InlineData(5, "před 5 minutami")] [InlineData(6, "před 6 minutami")] [InlineData(10, "před 10 minutami")] [InlineData(60, "před hodinou")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "před hodinou")] [InlineData(2, "před 2 hodinami")] [InlineData(3, "před 3 hodinami")] [InlineData(4, "před 4 hodinami")] [InlineData(5, "před 5 hodinami")] [InlineData(6, "před 6 hodinami")] [InlineData(10, "před 10 hodinami")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "včera")] [InlineData(2, "před 2 dny")] [InlineData(3, "před 3 dny")] [InlineData(4, "před 4 dny")] [InlineData(9, "před 9 dny")] [InlineData(10, "před 10 dny")] public void DayAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "před měsícem")] [InlineData(2, "před 2 měsíci")] [InlineData(3, "před 3 měsíci")] [InlineData(4, "před 4 měsíci")] [InlineData(5, "před 5 měsíci")] [InlineData(6, "před 6 měsíci")] [InlineData(10, "před 10 měsíci")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "před rokem")] [InlineData(2, "před 2 lety")] [InlineData(3, "před 3 lety")] [InlineData(4, "před 4 lety")] [InlineData(5, "před 5 lety")] [InlineData(6, "před 6 lety")] [InlineData(10, "před 10 lety")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); } ================================================ FILE: tests/Humanizer.Tests/Localisation/cs/NumberToWordsTests.cs ================================================ namespace cs; [UseCulture("cs-CZ")] public class NumberToWordsTests { [Theory] [InlineData(0, "nula")] [InlineData(1, "jeden")] [InlineData(2, "dva")] [InlineData(3, "tři")] [InlineData(4, "čtyři")] [InlineData(5, "pět")] [InlineData(6, "šest")] [InlineData(7, "sedm")] [InlineData(8, "osm")] [InlineData(9, "devět")] [InlineData(10, "deset")] [InlineData(11, "jedenáct")] [InlineData(12, "dvanáct")] [InlineData(13, "třináct")] [InlineData(14, "čtrnáct")] [InlineData(15, "patnáct")] [InlineData(16, "šestnáct")] [InlineData(17, "sedmnáct")] [InlineData(18, "osmnáct")] [InlineData(19, "devatenáct")] [InlineData(20, "dvacet")] [InlineData(22, "dvacet dva")] [InlineData(30, "třicet")] [InlineData(40, "čtyřicet")] [InlineData(50, "padesát")] [InlineData(60, "šedesát")] [InlineData(70, "sedmdesát")] [InlineData(80, "osmdesát")] [InlineData(90, "devadesát")] [InlineData(100, "sto")] [InlineData(112, "sto dvanáct")] [InlineData(128, "sto dvacet osm")] [InlineData(1000, "jeden tisíc")] [InlineData(2000, "dva tisíce")] [InlineData(5000, "pět tisíc")] [InlineData(10000, "deset tisíc")] [InlineData(20000, "dvacet tisíc")] [InlineData(21000, "dvacet jedna tisíc")] [InlineData(22000, "dvacet dva tisíc")] [InlineData(25000, "dvacet pět tisíc")] [InlineData(100000, "sto tisíc")] [InlineData(500000, "pět set tisíc")] [InlineData(1000000, "jeden milion")] [InlineData(2000000, "dva miliony")] [InlineData(5000000, "pět milionů")] [InlineData(1000000000, "jedna miliarda")] [InlineData(1001001001, "jedna miliarda jeden milion jeden tisíc jeden")] [InlineData(2000000000, "dvě miliardy")] [InlineData(1501001892, "jedna miliarda pět set jedna milionů jeden tisíc osm set devadesát dva")] [InlineData(2147483647, "dvě miliardy sto čtyřicet sedm milionů čtyři sta osmdesát tři tisíc šest set čtyřicet sedm")] [InlineData(-1501001892, "mínus jedna miliarda pět set jedna milionů jeden tisíc osm set devadesát dva")] public void ToWordsCzech(int number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(0, "nula")] [InlineData(1, "jedna")] [InlineData(2, "dvě")] [InlineData(3, "tři")] [InlineData(4, "čtyři")] [InlineData(5, "pět")] [InlineData(6, "šest")] [InlineData(7, "sedm")] [InlineData(8, "osm")] [InlineData(9, "devět")] [InlineData(10, "deset")] [InlineData(11, "jedenáct")] [InlineData(12, "dvanáct")] [InlineData(13, "třináct")] [InlineData(14, "čtrnáct")] [InlineData(15, "patnáct")] [InlineData(16, "šestnáct")] [InlineData(17, "sedmnáct")] [InlineData(18, "osmnáct")] [InlineData(19, "devatenáct")] [InlineData(20, "dvacet")] [InlineData(22, "dvacet dvě")] [InlineData(30, "třicet")] [InlineData(40, "čtyřicet")] [InlineData(50, "padesát")] [InlineData(60, "šedesát")] [InlineData(70, "sedmdesát")] [InlineData(80, "osmdesát")] [InlineData(90, "devadesát")] [InlineData(100, "sto")] [InlineData(112, "sto dvanáct")] [InlineData(128, "sto dvacet osm")] [InlineData(1000, "jeden tisíc")] [InlineData(2000, "dva tisíce")] [InlineData(5000, "pět tisíc")] [InlineData(10000, "deset tisíc")] [InlineData(20000, "dvacet tisíc")] [InlineData(21000, "dvacet jedna tisíc")] [InlineData(22000, "dvacet dva tisíc")] [InlineData(25000, "dvacet pět tisíc")] [InlineData(100000, "sto tisíc")] [InlineData(500000, "pět set tisíc")] [InlineData(1000000, "jeden milion")] [InlineData(2000000, "dva miliony")] [InlineData(5000000, "pět milionů")] [InlineData(1000000000, "jedna miliarda")] [InlineData(1001001001, "jedna miliarda jeden milion jeden tisíc jedna")] [InlineData(2000000000, "dvě miliardy")] [InlineData(1501001892, "jedna miliarda pět set jedna milionů jeden tisíc osm set devadesát dvě")] [InlineData(2147483647, "dvě miliardy sto čtyřicet sedm milionů čtyři sta osmdesát tři tisíc šest set čtyřicet sedm")] [InlineData(-1501001892, "mínus jedna miliarda pět set jedna milionů jeden tisíc osm set devadesát dvě")] public void ToWordsCzechFeminine(int number, string expected) => Assert.Equal(expected, number.ToWords(GrammaticalGender.Feminine)); [Theory] [InlineData(0, "nula")] [InlineData(1, "jedno")] [InlineData(2, "dvě")] [InlineData(3, "tři")] [InlineData(4, "čtyři")] [InlineData(5, "pět")] [InlineData(6, "šest")] [InlineData(7, "sedm")] [InlineData(8, "osm")] [InlineData(9, "devět")] [InlineData(10, "deset")] [InlineData(11, "jedenáct")] [InlineData(12, "dvanáct")] [InlineData(13, "třináct")] [InlineData(14, "čtrnáct")] [InlineData(15, "patnáct")] [InlineData(16, "šestnáct")] [InlineData(17, "sedmnáct")] [InlineData(18, "osmnáct")] [InlineData(19, "devatenáct")] [InlineData(20, "dvacet")] [InlineData(22, "dvacet dvě")] [InlineData(30, "třicet")] [InlineData(40, "čtyřicet")] [InlineData(50, "padesát")] [InlineData(60, "šedesát")] [InlineData(70, "sedmdesát")] [InlineData(80, "osmdesát")] [InlineData(90, "devadesát")] [InlineData(100, "sto")] [InlineData(112, "sto dvanáct")] [InlineData(128, "sto dvacet osm")] [InlineData(1000, "jeden tisíc")] [InlineData(2000, "dva tisíce")] [InlineData(5000, "pět tisíc")] [InlineData(10000, "deset tisíc")] [InlineData(20000, "dvacet tisíc")] [InlineData(21000, "dvacet jedna tisíc")] [InlineData(22000, "dvacet dva tisíc")] [InlineData(25000, "dvacet pět tisíc")] [InlineData(100000, "sto tisíc")] [InlineData(500000, "pět set tisíc")] [InlineData(1000000, "jeden milion")] [InlineData(2000000, "dva miliony")] [InlineData(5000000, "pět milionů")] [InlineData(1000000000, "jedna miliarda")] [InlineData(1001001001, "jedna miliarda jeden milion jeden tisíc jedno")] [InlineData(2000000000, "dvě miliardy")] [InlineData(1501001892, "jedna miliarda pět set jedna milionů jeden tisíc osm set devadesát dvě")] [InlineData(2147483647, "dvě miliardy sto čtyřicet sedm milionů čtyři sta osmdesát tři tisíc šest set čtyřicet sedm")] [InlineData(-1501001892, "mínus jedna miliarda pět set jedna milionů jeden tisíc osm set devadesát dvě")] public void ToWordsCzechNeuter(int number, string expected) => Assert.Equal(expected, number.ToWords(GrammaticalGender.Neuter)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/cs/TimeSpanHumanizeTests.cs ================================================ namespace cs; [UseCulture("cs-CZ")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "1 rok")] [InlineData(731, "2 roky")] [InlineData(1096, "3 roky")] [InlineData(4018, "11 let")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "1 měsíc")] [InlineData(61, "2 měsíce")] [InlineData(92, "3 měsíce")] [InlineData(335, "11 měsíců")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(1, "1 milisekunda")] [InlineData(2, "2 milisekundy")] [InlineData(3, "3 milisekundy")] [InlineData(4, "4 milisekundy")] [InlineData(5, "5 milisekund")] [InlineData(6, "6 milisekund")] [InlineData(10, "10 milisekund")] public void Milliseconds(int number, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(number).Humanize()); [Theory] [InlineData(1, "1 sekunda")] [InlineData(2, "2 sekundy")] [InlineData(3, "3 sekundy")] [InlineData(4, "4 sekundy")] [InlineData(5, "5 sekund")] [InlineData(6, "6 sekund")] [InlineData(10, "10 sekund")] public void Seconds(int number, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(number).Humanize()); [Theory] [InlineData(1, "1 minuta")] [InlineData(2, "2 minuty")] [InlineData(3, "3 minuty")] [InlineData(4, "4 minuty")] [InlineData(5, "5 minut")] [InlineData(6, "6 minut")] [InlineData(10, "10 minut")] public void Minutes(int number, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(number).Humanize()); [Theory] [InlineData(1, "1 hodina")] [InlineData(2, "2 hodiny")] [InlineData(3, "3 hodiny")] [InlineData(4, "4 hodiny")] [InlineData(5, "5 hodin")] [InlineData(6, "6 hodin")] [InlineData(10, "10 hodin")] public void Hours(int number, string expected) => Assert.Equal(expected, TimeSpan.FromHours(number).Humanize()); [Theory] [InlineData(1, "1 den")] [InlineData(2, "2 dny")] [InlineData(3, "3 dny")] [InlineData(4, "4 dny")] [InlineData(5, "5 dnů")] [InlineData(6, "6 dnů")] public void Days(int number, string expected) => Assert.Equal(expected, TimeSpan.FromDays(number).Humanize()); [Theory] [InlineData(1, "1 týden")] [InlineData(2, "2 týdny")] [InlineData(3, "3 týdny")] [InlineData(4, "4 týdny")] [InlineData(5, "5 týdnů")] [InlineData(6, "6 týdnů")] public void Weeks(int number, string expected) => Assert.Equal(expected, TimeSpan.FromDays(number * 7).Humanize()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/da/DateHumanizeTests.cs ================================================ namespace da; [UseCulture("da-DK")] public class DateHumanizeTests { [Theory] [InlineData(-2, "2 dage siden")] [InlineData(-1, "i går")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "i morgen")] [InlineData(10, "10 dage fra nu")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(1, "et sekund fra nu")] [InlineData(10, "10 sekunder fra nu")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(-2, "2 timer siden")] [InlineData(-1, "en time siden")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "en time fra nu")] [InlineData(10, "10 timer fra nu")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(-2, "2 minutter siden")] [InlineData(-1, "et minut siden")] [InlineData(60, "en time siden")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "et minut fra nu")] [InlineData(10, "10 minutter fra nu")] [InlineData(59, "59 minutter fra nu")] [InlineData(60, "en time fra nu")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(-2, "2 måneder siden")] [InlineData(-1, "en måned siden")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "en måned fra nu")] [InlineData(10, "10 måneder fra nu")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(-2, "2 sekunder siden")] [InlineData(-1, "et sekund siden")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(-2, "2 år siden")] [InlineData(-1, "et år siden")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "et år fra nu")] [InlineData(2, "2 år fra nu")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Theory] [InlineData(0, "nu")] public void Now(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/da/TimeSpanHumanizeTests.cs ================================================ namespace da; [UseCulture("da-DK")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Native speaker")] [InlineData(366, "et år")] [InlineData(731, "2 år")] [InlineData(1096, "3 år")] [InlineData(4018, "11 år")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Native speaker")] [InlineData(31, "en måned")] [InlineData(61, "2 måneder")] [InlineData(92, "3 måneder")] [InlineData(335, "11 måneder")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(7, "en uge")] [InlineData(14, "2 uger")] public void Weeks(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "en dag")] [InlineData(2, "2 dage")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "en time")] [InlineData(2, "2 timer")] public void Hours(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); [Theory] [InlineData(1, "et minut")] [InlineData(2, "2 minutter")] public void Minutes(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); [Theory] [InlineData(1, "et sekund")] [InlineData(2, "2 sekunder")] public void Seconds(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); [Theory] [InlineData(1, "et millisekund")] [InlineData(2, "2 millisekunder")] public void Milliseconds(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); [Fact] public void NoTime() => Assert.Equal("0 millisekunder", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => Assert.Equal("ingen tid", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/de/Bytes/ByteRateTests.cs ================================================ namespace de.Bytes; [UseCulture("de-DE")] public class ByteRateTests { [Theory] [InlineData(400, 1, "400 B/s")] [InlineData(4 * 1024, 1, "4 kB/s")] [InlineData(4 * 1024 * 1024, 1, "4 MB/s")] [InlineData(4 * 2 * 1024 * 1024, 2, "4 MB/s")] [InlineData(4 * 1024, 0.1, "40 kB/s")] [InlineData(15 * 60 * 1024 * 1024, 60, "15 MB/s")] public void HumanizesRates(long inputBytes, double perSeconds, string expectedValue) { var size = new ByteSize(inputBytes); var interval = TimeSpan.FromSeconds(perSeconds); var rate = size.Per(interval).Humanize(); Assert.Equal(expectedValue, rate); } [Theory] [InlineData(1, 1, TimeUnit.Second, "1 MB/s")] [InlineData(1, 60, TimeUnit.Minute, "1 MB/min")] [InlineData(1, 60 * 60, TimeUnit.Hour, "1 MB/h")] [InlineData(10, 1, TimeUnit.Second, "10 MB/s")] [InlineData(10, 60, TimeUnit.Minute, "10 MB/min")] [InlineData(10, 60 * 60, TimeUnit.Hour, "10 MB/h")] [InlineData(1, 10 * 1, TimeUnit.Second, "102,4 kB/s")] [InlineData(1, 10 * 60, TimeUnit.Minute, "102,4 kB/min")] [InlineData(1, 10 * 60 * 60, TimeUnit.Hour, "102,4 kB/h")] public void TimeUnitTests(long megabytes, double measurementIntervalSeconds, TimeUnit displayInterval, string expectedValue) { var size = ByteSize.FromMegabytes(megabytes); var measurementInterval = TimeSpan.FromSeconds(measurementIntervalSeconds); var rate = size.Per(measurementInterval); var text = rate.Humanize(displayInterval); Assert.Equal(expectedValue, text); } [Theory] [InlineData(19854651984, 1, TimeUnit.Second, null, "18,49 GB/s")] [InlineData(19854651984, 1, TimeUnit.Second, "#.##", "18,49 GB/s")] public void FormattedTimeUnitTests(long bytes, int measurementIntervalSeconds, TimeUnit displayInterval, string? format, string expectedValue) { var size = ByteSize.FromBytes(bytes); var measurementInterval = TimeSpan.FromSeconds(measurementIntervalSeconds); var rate = size.Per(measurementInterval); var text = rate.Humanize(format, displayInterval); Assert.Equal(expectedValue, text); } [Theory] [InlineData(TimeUnit.Millisecond)] [InlineData(TimeUnit.Day)] [InlineData(TimeUnit.Month)] [InlineData(TimeUnit.Week)] [InlineData(TimeUnit.Year)] public void ThrowsOnUnsupportedData(TimeUnit units) { var dummyRate = ByteSize.FromBits(1).Per(TimeSpan.FromSeconds(1)); Assert.Throws(() => dummyRate.Humanize(units)); } } ================================================ FILE: tests/Humanizer.Tests/Localisation/de/Bytes/ByteSizeExtensionsTests.cs ================================================ namespace de.Bytes; [UseCulture("de-DE")] public class ByteSizeExtensionsTests { [Theory] [InlineData(2, null, "2 TB")] [InlineData(2, "GB", "2048 GB")] [InlineData(2.123, "#.#", "2,1 TB")] public void HumanizesTerabytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Terabytes().Humanize(format)); [Theory] [InlineData(0, null, "0 bit")] [InlineData(0, "GB", "0 GB")] [InlineData(2, null, "2 GB")] [InlineData(2, "MB", "2048 MB")] [InlineData(2.123, "#.##", "2,12 GB")] public void HumanizesGigabytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Gigabytes().Humanize(format)); [Theory] [InlineData(0, null, "0 bit")] [InlineData(0, "MB", "0 MB")] [InlineData(2, null, "2 MB")] [InlineData(2, "KB", "2048 kB")] [InlineData(2.123, "#", "2 MB")] public void HumanizesMegabytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Megabytes().Humanize(format)); [Theory] [InlineData(0, null, "0 bit")] [InlineData(0, "KB", "0 kB")] [InlineData(2, null, "2 kB")] [InlineData(2, "B", "2048 B")] [InlineData(2.123, "#.####", "2,123 kB")] public void HumanizesKilobytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Kilobytes().Humanize(format)); [Theory] [InlineData(0, null, "0 bit")] [InlineData(0, "#.##", "0 bit")] [InlineData(0, "#.## B", "0 B")] [InlineData(0, "B", "0 B")] [InlineData(2, null, "2 B")] [InlineData(2000, "KB", "1,95 kB")] [InlineData(2123, "#.##", "2,07 kB")] [InlineData(10000000, "KB", "9765,63 kB")] [InlineData(10000000, "#,##0 KB", "9.766 kB")] [InlineData(10000000, "#,##0.# KB", "9.765,6 kB")] public void HumanizesBytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Bytes().Humanize(format)); [Theory] [InlineData(0, null, "0 bit")] [InlineData(0, "b", "0 bit")] [InlineData(2, null, "2 bit")] [InlineData(12, "B", "1,5 B")] [InlineData(10000, "#.# KB", "1,2 kB")] public void HumanizesBits(long input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Bits().Humanize(format)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/de/Bytes/ToFullWordsTests.cs ================================================ namespace de.Bytes; [UseCulture("de-DE")] public class ToFullWordsTests { [Fact] public void ReturnsSingularBit() => Assert.Equal("1 Bit", ByteSize.FromBits(1).ToFullWords()); [Fact] public void ReturnsPluralBits() => Assert.Equal("2 Bit", ByteSize.FromBits(2).ToFullWords()); [Fact] public void ReturnsSingularByte() => Assert.Equal("1 Byte", ByteSize.FromBytes(1).ToFullWords()); [Fact] public void ReturnsPluralBytes() => Assert.Equal("10 Byte", ByteSize.FromBytes(10).ToFullWords()); [Fact] public void ReturnsSingularKiloByte() => Assert.Equal("1 Kilobyte", ByteSize.FromKilobytes(1).ToFullWords()); [Fact] public void ReturnsPluralKilobytes() => Assert.Equal("10 Kilobyte", ByteSize.FromKilobytes(10).ToFullWords()); [Fact] public void ReturnsSingularMegabyte() => Assert.Equal("1 Megabyte", ByteSize.FromMegabytes(1).ToFullWords()); [Fact] public void ReturnsPluralMegabytes() => Assert.Equal("10 Megabyte", ByteSize.FromMegabytes(10).ToFullWords()); [Fact] public void ReturnsSingularGigabyte() => Assert.Equal("1 Gigabyte", ByteSize.FromGigabytes(1).ToFullWords()); [Fact] public void ReturnsPluralGigabytes() => Assert.Equal("10 Gigabyte", ByteSize.FromGigabytes(10).ToFullWords()); [Fact] public void ReturnsSingularTerabyte() => Assert.Equal("1 Terabyte", ByteSize.FromTerabytes(1).ToFullWords()); [Fact] public void ReturnsPluralTerabytes() => Assert.Equal("10 Terabyte", ByteSize.FromTerabytes(10).ToFullWords()); [Theory] [InlineData(229376, "B", "229376 Byte")] [InlineData(229376, "# KB", "224 Kilobyte")] public void ToFullWordsFormatted(double input, string format, string expectedValue) => Assert.Equal(expectedValue, ByteSize.FromBytes(input).ToFullWords(format)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/de/Bytes/ToStringTests.cs ================================================ namespace de.Bytes; [UseCulture("de-DE")] public class ToStringTests { [Fact] public void ReturnsLargestMetricSuffix() => Assert.Equal("10,5 kB", ByteSize.FromKilobytes(10.5).ToString()); [Fact] public void ReturnsDefaultNumberFormat() => Assert.Equal("10,5 kB", ByteSize.FromKilobytes(10.5).ToString("KB")); [Fact] public void ReturnsProvidedNumberFormat() => Assert.Equal("10,1234 kB", ByteSize.FromKilobytes(10.1234).ToString("#.#### KB")); [Fact] public void ReturnsBits() => Assert.Equal("10 bit", ByteSize.FromBits(10).ToString("##.#### b")); [Fact] public void ReturnsBytes() => Assert.Equal("10 B", ByteSize.FromBytes(10).ToString("##.#### B")); [Fact] public void ReturnsKilobytes() => Assert.Equal("10 kB", ByteSize.FromKilobytes(10).ToString("##.#### KB")); [Fact] public void ReturnsMegabytes() => Assert.Equal("10 MB", ByteSize.FromMegabytes(10).ToString("##.#### MB")); [Fact] public void ReturnsGigabytes() => Assert.Equal("10 GB", ByteSize.FromGigabytes(10).ToString("##.#### GB")); [Fact] public void ReturnsTerabytes() => Assert.Equal("10 TB", ByteSize.FromTerabytes(10).ToString("##.#### TB")); [Fact] public void ReturnsSelectedFormat() => Assert.Equal("10,0 TB", ByteSize.FromTerabytes(10).ToString("0.0 TB")); [Fact] public void ReturnsLargestMetricPrefixLargerThanZero() => Assert.Equal("512 kB", ByteSize.FromMegabytes(.5).ToString("#.#")); [Fact] public void ReturnsLargestMetricPrefixLargerThanZeroForNegativeValues() => Assert.Equal("-512 kB", ByteSize.FromMegabytes(-.5).ToString("#.#")); [Fact] public void ReturnsBytesViaGeneralFormat() => Assert.Equal("10 B", $"{ByteSize.FromBytes(10)}"); } ================================================ FILE: tests/Humanizer.Tests/Localisation/de/CollectionFormatterTests.cs ================================================ namespace de; [UseCulture("de")] public class CollectionFormatterTests { [Fact] public void OneItem() { var collection = new List([1]); var humanized = "1"; Assert.Equal(humanized, collection.Humanize()); } [Fact] public void TwoItems() { var collection = new List([1, 2]); var humanized = "1 und 2"; Assert.Equal(humanized, collection.Humanize()); } [Fact] public void MoreThanTwoItems() { var collection = new List([1, 2, 3]); var humanized = "1, 2 und 3"; Assert.Equal(humanized, collection.Humanize()); } } ================================================ FILE: tests/Humanizer.Tests/Localisation/de/DateHumanizeTests.cs ================================================ namespace de; [UseCulture("de-DE")] public class DateHumanizeTests { [Theory] [InlineData(-2, "vor 2 Tagen")] [InlineData(-1, "gestern")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(2, "in 2 Tagen")] [InlineData(1, "morgen")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(-2, "vor 2 Stunden")] [InlineData(-1, "vor einer Stunde")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(2, "in 2 Stunden")] [InlineData(1, "in einer Stunde")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(-2, "vor 2 Minuten")] [InlineData(-1, "vor einer Minute")] [InlineData(60, "vor einer Stunde")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(2, "in 2 Minuten")] [InlineData(1, "in einer Minute")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(-2, "vor 2 Monaten")] [InlineData(-1, "vor einem Monat")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(2, "in 2 Monaten")] [InlineData(1, "in einem Monat")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(-2, "vor 2 Sekunden")] [InlineData(-1, "vor einer Sekunde")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(2, "in 2 Sekunden")] [InlineData(1, "in einer Sekunde")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(-2, "vor 2 Jahren")] [InlineData(-1, "vor einem Jahr")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(2, "in 2 Jahren")] [InlineData(1, "in einem Jahr")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/de/DateToOrdinalWordsTests.cs ================================================ namespace de; [UseCulture("de")] public class DateToOrdinalWordsTests { [Fact] public void OrdinalizeString() => Assert.Equal("1. Januar 2015", new DateTime(2015, 1, 1).ToOrdinalWords()); #if NET6_0_OR_GREATER [Fact] public void OrdinalizeDateOnlyString() => Assert.Equal("1. Januar 2015", new DateOnly(2015, 1, 1).ToOrdinalWords()); #endif } ================================================ FILE: tests/Humanizer.Tests/Localisation/de/HeadingTests.cs ================================================ namespace de; [UseCulture("de-DE")] public class HeadingTests { [InlineData(0, "N")] [InlineData(11.2, "N")] [InlineData(11.3, "NNO")] [InlineData(22.5, "NNO")] [InlineData(33.7, "NNO")] [InlineData(33.8, "NO")] [InlineData(45, "NO")] [InlineData(56.2, "NO")] [InlineData(56.3, "ONO")] [InlineData(67.5, "ONO")] [InlineData(78.7, "ONO")] [InlineData(78.8, "O")] [InlineData(90, "O")] [InlineData(101.2, "O")] [InlineData(101.3, "OSO")] [InlineData(112.5, "OSO")] [InlineData(123.7, "OSO")] [InlineData(123.8, "SO")] [InlineData(135, "SO")] [InlineData(146.2, "SO")] [InlineData(146.3, "SSO")] [InlineData(157.5, "SSO")] [InlineData(168.7, "SSO")] [InlineData(168.8, "S")] [InlineData(180, "S")] [InlineData(191.2, "S")] [InlineData(191.3, "SSW")] [InlineData(202.5, "SSW")] [InlineData(213.7, "SSW")] [InlineData(213.8, "SW")] [InlineData(225, "SW")] [InlineData(236.2, "SW")] [InlineData(236.3, "WSW")] [InlineData(247.5, "WSW")] [InlineData(258.7, "WSW")] [InlineData(258.8, "W")] [InlineData(270, "W")] [InlineData(281.2, "W")] [InlineData(281.3, "WNW")] [InlineData(292.5, "WNW")] [InlineData(303.7, "WNW")] [InlineData(303.8, "NW")] [InlineData(315, "NW")] [InlineData(326.2, "NW")] [InlineData(326.3, "NNW")] [InlineData(337.5, "NNW")] [InlineData(348.7, "NNW")] [InlineData(348.8, "N")] [InlineData(720, "N")] [Theory] public void ToHeadingAbbreviated(double heading, string expected) => Assert.Equal(expected, heading.ToHeading()); [InlineData(0, "Nord")] [InlineData(22.5, "Nordnordost")] [InlineData(45, "Nordost")] [InlineData(67.5, "Ostnordost")] [InlineData(90, "Ost")] [InlineData(112.5, "Ostsüdost")] [InlineData(135, "Südost")] [InlineData(157.5, "Südsüdost")] [InlineData(180, "Süd")] [InlineData(202.5, "Südsüdwest")] [InlineData(225, "Südwest")] [InlineData(247.5, "Westsüdwest")] [InlineData(270, "West")] [InlineData(292.5, "Westnordwest")] [InlineData(315, "Nordwest")] [InlineData(337.5, "Nordnordwest")] [InlineData(720, "Nord")] [Theory] public void ToHeading(double heading, string expected) => Assert.Equal(expected, heading.ToHeading(HeadingStyle.Full)); [InlineData("N", 0)] [InlineData("NNO", 22.5)] [InlineData("NO", 45)] [InlineData("ONO", 67.5)] [InlineData("O", 90)] [InlineData("OSO", 112.5)] [InlineData("SO", 135)] [InlineData("SSO", 157.5)] [InlineData("S", 180)] [InlineData("SSW", 202.5)] [InlineData("SW", 225)] [InlineData("WSW", 247.5)] [InlineData("W", 270)] [InlineData("WNW", 292.5)] [InlineData("NW", 315)] [InlineData("NNW", 337.5)] [Theory] public void FromShortHeading(string heading, double expected) => Assert.Equal(expected, heading.FromAbbreviatedHeading()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/de/NumberToWordsTests.cs ================================================ namespace de; [UseCulture("de-DE")] public class NumberToWordsTests { [Theory] [InlineData(0, "null")] [InlineData(1, "eins")] [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, "dreißig")] [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ünfhunderteins")] [InlineData(111, "einhundertelf")] [InlineData(1112, "eintausendeinhundertzwölf")] [InlineData(11213, "elftausendzweihundertdreizehn")] [InlineData(121314, "einhunderteinundzwanzigtausenddreihundertvierzehn")] [InlineData(2132415, "zwei Millionen einhundertzweiunddreißigtausendvierhundertfünfzehn")] [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(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, "dreißigster")] [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, "zweimillioneneinhundertzweiunddreißigtausendvierhundertfünfzehnter")] [InlineData(12345516, "zwölfmillionendreihundertfünfundvierzigtausendfünfhundertsechzehnter")] [InlineData(751633617, "siebenhunderteinundfünfzigmillionensechshundertdreiunddreißigtausendsechshundertsiebzehnter")] [InlineData(1111111118, "einemilliardeeinhundertelfmillioneneinhundertelftausendeinhundertachtzehnter")] [InlineData(-751633619, "minus siebenhunderteinundfünfzigmillionensechshundertdreiunddreißigtausendsechshundertneunzehnter")] 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, "zweimillioneneinhundertzweiunddreißigtausendvierhundertfünfzehnte")] [InlineData(12345516, "zwölfmillionendreihundertfünfundvierzigtausendfünfhundertsechzehnte")] [InlineData(751633617, "siebenhunderteinundfünfzigmillionensechshundertdreiunddreißigtausendsechshundertsiebzehnte")] [InlineData(1111111118, "einemilliardeeinhundertelfmillioneneinhundertelftausendeinhundertachtzehnte")] [InlineData(-751633619, "minus siebenhunderteinundfünfzigmillionensechshundertdreiunddreißigtausendsechshundertneunzehnte")] 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, "zweimillioneneinhundertzweiunddreißigtausendvierhundertfünfzehntes")] [InlineData(12345516, "zwölfmillionendreihundertfünfundvierzigtausendfünfhundertsechzehntes")] [InlineData(751633617, "siebenhunderteinundfünfzigmillionensechshundertdreiunddreißigtausendsechshundertsiebzehntes")] [InlineData(1111111118, "einemilliardeeinhundertelfmillioneneinhundertelftausendeinhundertachtzehntes")] [InlineData(-751633619, "minus siebenhunderteinundfünfzigmillionensechshundertdreiunddreißigtausendsechshundertneunzehntes")] public void ToOrdinalWordsNeuter(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Neuter)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/de/OrdinalizeTests.cs ================================================ namespace de; [UseCulture("de-DE")] public class OrdinalizeTests { [Theory] [InlineData("0", "0.")] [InlineData("1", "1.")] [InlineData("2", "2.")] [InlineData("3", "3.")] [InlineData("4", "4.")] [InlineData("5", "5.")] [InlineData("6", "6.")] [InlineData("23", "23.")] [InlineData("100", "100.")] [InlineData("101", "101.")] [InlineData("102", "102.")] [InlineData("103", "103.")] [InlineData("1001", "1001.")] public void OrdinalizeString(string number, string ordinalized) => Assert.Equal(ordinalized, number.Ordinalize()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/de/TimeSpanHumanizeTests.cs ================================================ namespace de; [UseCulture("de-DE")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Native speaker")] [InlineData(366, "1 Jahr")] [InlineData(731, "2 Jahre")] [InlineData(1096, "3 Jahre")] [InlineData(4018, "11 Jahre")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Native speaker")] [InlineData(366, "ein Jahr")] [InlineData(731, "zwei Jahre")] [InlineData(1096, "drei Jahre")] [InlineData(4018, "elf Jahre")] public void YearsToWords(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year, toWords: true)); [Theory] [Trait("Translation", "Native speaker")] [InlineData(31, "1 Monat")] [InlineData(61, "2 Monate")] [InlineData(92, "3 Monate")] [InlineData(335, "11 Monate")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Native speaker")] [InlineData(31, "ein Monat")] [InlineData(61, "zwei Monate")] [InlineData(92, "drei Monate")] [InlineData(335, "elf Monate")] public void MonthsToWords(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year, toWords: true)); [Theory] [InlineData(7, "1 Woche")] [InlineData(14, "2 Wochen")] [InlineData(21, "3 Wochen")] [InlineData(77, "11 Wochen")] public void Weeks(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(7, "eine Woche")] [InlineData(14, "zwei Wochen")] [InlineData(21, "drei Wochen")] [InlineData(77, "elf Wochen")] public void WeeksToWords(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(toWords: true)); [Theory] [InlineData(1, "1 Tag")] [InlineData(2, "2 Tage")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "ein Tag")] [InlineData(2, "zwei Tage")] public void DaysToWords(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(toWords: true)); [Theory] [InlineData(1, "1 Stunde")] [InlineData(2, "2 Stunden")] public void Hours(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); [Theory] [InlineData(1, "eine Stunde")] [InlineData(2, "zwei Stunden")] public void HoursToWords(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize(toWords: true)); [Theory] [InlineData(1, "1 Minute")] [InlineData(2, "2 Minuten")] public void Minutes(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); [Theory] [InlineData(1, "eine Minute")] [InlineData(2, "zwei Minuten")] public void MinutesToWords(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize(toWords: true)); [Theory] [InlineData(1, "1 Sekunde")] [InlineData(2, "2 Sekunden")] public void Seconds(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); [Theory] [InlineData(1, "eine Sekunde")] [InlineData(2, "zwei Sekunden")] public void SecondsToWords(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize(toWords: true)); [Theory] [InlineData(1, "1 Millisekunde")] [InlineData(2, "2 Millisekunden")] public void Milliseconds(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); [Theory] [InlineData(1, "eine Millisekunde")] [InlineData(2, "zwei Millisekunden")] public void MillisecondsToWords(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize(toWords: true)); [Fact] public void NoTime() => Assert.Equal("0 Millisekunden", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => // This one doesn't make a lot of sense but ... w/e Assert.Equal("Keine Zeit", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/de/TimeToClockNotationTests.cs ================================================ #if NET6_0_OR_GREATER namespace de; [UseCulture("de")] public class TimeToClockNotationTests { [Theory] [InlineData(00, 00, "zwölf Uhr nachts")] [InlineData(04, 00, "vier Uhr")] [InlineData(05, 01, "fünf Uhr eins")] [InlineData(06, 05, "fünf nach sechs")] [InlineData(07, 10, "zehn nach sieben")] [InlineData(08, 15, "viertel nach acht")] [InlineData(09, 20, "zwanzig nach neun")] [InlineData(10, 25, "fünf vor halb elf")] [InlineData(11, 30, "halb zwölf")] [InlineData(12, 00, "zwölf Uhr mittags")] [InlineData(15, 35, "fünf nach halb vier")] [InlineData(16, 40, "zwanzig vor fünf")] [InlineData(17, 45, "viertel vor sechs")] [InlineData(18, 50, "zehn vor sieben")] [InlineData(19, 55, "fünf vor acht")] [InlineData(20, 59, "acht Uhr neunundfünfzig")] public void ConvertToClockNotationTimeOnlyStringDe(int hours, int minutes, string expectedResult) { var actualResult = new TimeOnly(hours, minutes).ToClockNotation(); Assert.Equal(expectedResult, actualResult); } [Theory] [InlineData(00, 00, "zwölf Uhr nachts")] [InlineData(04, 00, "vier Uhr")] [InlineData(05, 01, "fünf Uhr")] [InlineData(06, 05, "fünf nach sechs")] [InlineData(07, 10, "zehn nach sieben")] [InlineData(08, 15, "viertel nach acht")] [InlineData(09, 20, "zwanzig nach neun")] [InlineData(10, 25, "fünf vor halb elf")] [InlineData(11, 30, "halb zwölf")] [InlineData(12, 00, "zwölf Uhr mittags")] [InlineData(13, 23, "fünf vor halb zwei")] [InlineData(14, 32, "halb drei")] [InlineData(15, 35, "fünf nach halb vier")] [InlineData(16, 40, "zwanzig vor fünf")] [InlineData(17, 45, "viertel vor sechs")] [InlineData(18, 50, "zehn vor sieben")] [InlineData(19, 55, "fünf vor acht")] [InlineData(20, 59, "neun Uhr")] public void ConvertToRoundedClockNotationTimeOnlyStringDe(int hours, int minutes, string expectedResult) { var actualResult = new TimeOnly(hours, minutes).ToClockNotation(ClockNotationRounding.NearestFiveMinutes); Assert.Equal(expectedResult, actualResult); } } #endif ================================================ FILE: tests/Humanizer.Tests/Localisation/de/TimeUnitToSymbolTests.cs ================================================ namespace de; [UseCulture("de-DE")] public class TimeUnitToSymbolTests { [Theory] [Trait("Translation", "Native speaker")] [InlineData(TimeUnit.Millisecond, "ms")] [InlineData(TimeUnit.Second, "s")] [InlineData(TimeUnit.Minute, "min")] [InlineData(TimeUnit.Hour, "h")] [InlineData(TimeUnit.Day, "d")] [InlineData(TimeUnit.Week, "Woche")] [InlineData(TimeUnit.Month, "M")] [InlineData(TimeUnit.Year, "a")] public void ToSymbol(TimeUnit unit, string expected) => Assert.Equal(expected, unit.ToSymbol()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/de-CH/NumberToWordsTests.cs ================================================ namespace deCH; [UseCulture("de-CH")] public class NumberToWordsTests { [Theory] [InlineData(0, "null")] [InlineData(1, "eins")] [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ünfhunderteins")] [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)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/de-LI/NumberToWordsTests.cs ================================================ namespace deLI; [UseCulture("de-LI")] public class NumberToWordsTests { [Theory] [InlineData(0, "null")] [InlineData(1, "eins")] [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ünfhunderteins")] [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)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/el/DateHumanizeTests.cs ================================================ namespace el; [UseCulture("el")] public class DateHumanizeTests { [Theory] [InlineData(-2, "πριν από 2 ημέρες")] [InlineData(-1, "χθες")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(2, "2 ημέρες από τώρα")] [InlineData(1, "αύριο")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(-2, "πριν από 2 ώρες")] [InlineData(-1, "πριν από μία ώρα")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(2, "2 ώρες από τώρα")] [InlineData(1, "πρίν από μία ώρα από τώρα")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(-2, "πριν από 2 λεπτά")] [InlineData(-1, "πριν από ένα λεπτό")] [InlineData(60, "πριν από μία ώρα")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(2, "2 λεπτά από τώρα")] [InlineData(1, "πρίν από ένα λεπτό από τώρα")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(-2, "πριν από 2 μήνες")] [InlineData(-1, "πριν από έναν μήνα")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(2, "2 μήνες από τώρα")] [InlineData(1, "πριν από έναν μήνα από τώρα")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(-2, "πριν από 2 δευτερόλεπτα")] [InlineData(-1, "πριν από ένα δευτερόλεπτο")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(2, "2 δευτερόλεπτα από τώρα")] [InlineData(1, "πριν από ένα δευτερόλεπτο από τώρα")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(-2, "πριν από 2 χρόνια")] [InlineData(-1, "πριν από έναν χρόνο")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(2, "2 χρόνια από τώρα")] [InlineData(1, "πριν από έναν χρόνο από τώρα")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/el/NumberToOrdinalWordsTests.cs ================================================ namespace el; [UseCulture("el")] public class NumberToOrdinalWordsTests { [InlineData(-1, "")] [InlineData(0, "")] [InlineData(1, "πρώτος")] [InlineData(10, "δέκατος")] [InlineData(11, "ενδέκατος")] [InlineData(12, "δωδέκατος")] [InlineData(20, "εικοστός")] [InlineData(31, "τριακοστός πρώτος")] [InlineData(100, "εκατοστός")] [InlineData(105, "εκατοστός πέμπτος")] [InlineData(286, "διακοσιοστός ογδοηκοστός έκτος")] [InlineData(530, "πεντακοσιοστός τριακοστός")] [InlineData(912, "εννιακοσιοστός δωδέκατος")] [InlineData(1203, "χιλιοστός διακοσιοστός τρίτος")] [InlineData(1596, "χιλιοστός πεντακοσιοστός ενενηκοστός έκτος")] [InlineData(1061, "χιλιοστός εξηκοστός πρώτος")] [InlineData(1008, "χιλιοστός όγδοος")] [InlineData(1211, "χιλιοστός διακοσιοστός ενδέκατος")] [InlineData(1999, "χιλιοστός εννιακοσιοστός ενενηκοστός ένατος")] [InlineData(2000, "")] [Theory] public void ToOrdinalWordsInt(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/el/NumberToWordsTests.cs ================================================ namespace el; [UseCulture("el")] public class NumberToWordsTests { [InlineData(1, "ένα")] [InlineData(10, "δέκα")] [InlineData(11, "έντεκα")] [InlineData(14, "δεκατέσσερα")] [InlineData(20, "είκοσι")] [InlineData(122, "εκατόν είκοσι δύο")] [InlineData(3501, "τρείς χιλιάδες πεντακόσια ένα")] [InlineData(100, "εκατό")] [InlineData(1000, "χίλια")] [InlineData(100000, "εκατό χιλιάδες")] [InlineData(13448, "δεκατρείς χιλιάδες τετρακόσια σαράντα οκτώ")] [InlineData(53, "πενήντα τρία")] [InlineData(123647, "εκατόν είκοσι τρείς χιλιάδες εξακόσια σαράντα επτά")] [InlineData(14000000, "δεκατέσσερα εκατομμύρια")] [InlineData(578412, "πεντακόσιες εβδομήντα οκτώ χιλιάδες τετρακόσια δώδεκα")] [InlineData(1000000000, "ένα δισεκατομμύριο")] [InlineData(1000000001, "ένα δισεκατομμύριο ένα")] [InlineData(1469, "χίλια τετρακόσια εξήντα εννέα")] [InlineData(69, "εξήντα εννέα")] [InlineData(619, "εξακόσια δεκαεννέα")] [InlineData(1190, "χίλια εκατόν ενενήντα")] [Theory] public void ToWordsInt(int number, string expected) => Assert.Equal(expected, number.ToWords()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/el/TimeSpanHumanizeTests.cs ================================================ namespace el; [UseCulture("el")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Native speaker")] [InlineData(366, "1 χρόνο")] [InlineData(731, "2 χρόνια")] [InlineData(1096, "3 χρόνια")] [InlineData(4018, "11 χρόνια")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Native speaker")] [InlineData(31, "1 μήνα")] [InlineData(61, "2 μήνες")] [InlineData(92, "3 μήνες")] [InlineData(335, "11 μήνες")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(7, "1 βδομάδα")] [InlineData(14, "2 βδομάδες")] [InlineData(21, "3 βδομάδες")] [InlineData(77, "11 βδομάδες")] public void Weeks(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "1 μέρα")] [InlineData(2, "2 μέρες")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "1 ώρα")] [InlineData(2, "2 ώρες")] public void Hours(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); [Theory] [InlineData(1, "1 λεπτό")] [InlineData(2, "2 λεπτά")] public void Minutes(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); [Theory] [InlineData(1, "1 δευτερόλεπτο")] [InlineData(2, "2 δευτερόλεπτα")] public void Seconds(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); [Theory] [InlineData(1, "1 χιλιοσtό του δευτερολέπτου")] [InlineData(2, "2 χιλιοστά του δευτερολέπτου")] public void Milliseconds(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); [Fact] public void NoTime() => Assert.Equal("0 χιλιοστά του δευτερολέπτου", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => Assert.Equal("μηδέν χρόνος", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/en/DateToOrdinalWordsTests.cs ================================================ namespace en; public class DateToOrdinalWordsTests { [UseCulture("en-GB")] [Fact] public void OrdinalizeStringGb() => Assert.Equal("1st January 2015", new DateTime(2015, 1, 1).ToOrdinalWords()); [UseCulture("en-US")] [Fact] public void OrdinalizeStringUs() => Assert.Equal("January 1st, 2015", new DateTime(2015, 1, 1).ToOrdinalWords()); #if NET6_0_OR_GREATER [UseCulture("en-GB")] [Fact] public void OrdinalizeDateOnlyStringGb() => Assert.Equal("1st January 2015", new DateOnly(2015, 1, 1).ToOrdinalWords()); [UseCulture("en-US")] [Fact] public void OrdinalizeDateOnlyStringUs() => Assert.Equal("January 1st, 2015", new DateOnly(2015, 1, 1).ToOrdinalWords()); #endif } ================================================ FILE: tests/Humanizer.Tests/Localisation/en/TimeToClockNotationTests.cs ================================================ #if NET6_0_OR_GREATER namespace en; [UseCulture("en")] public class TimeToClockNotationTests { [Theory] [InlineData(00, 00, "midnight")] [InlineData(04, 00, "four o'clock")] [InlineData(05, 01, "five one")] [InlineData(06, 05, "five past six")] [InlineData(07, 10, "ten past seven")] [InlineData(08, 15, "a quarter past eight")] [InlineData(09, 20, "twenty past nine")] [InlineData(10, 25, "twenty-five past ten")] [InlineData(11, 30, "half past eleven")] [InlineData(12, 00, "noon")] [InlineData(15, 35, "three thirty-five")] [InlineData(16, 40, "twenty to five")] [InlineData(17, 45, "a quarter to six")] [InlineData(18, 50, "ten to seven")] [InlineData(19, 55, "five to eight")] [InlineData(20, 59, "eight fifty-nine")] public void ConvertToClockNotationTimeOnlyStringEnUs(int hours, int minutes, string expectedResult) { var actualResult = new TimeOnly(hours, minutes).ToClockNotation(); Assert.Equal(expectedResult, actualResult); } [Theory] [InlineData(00, 00, "midnight")] [InlineData(04, 00, "four o'clock")] [InlineData(05, 01, "five o'clock")] [InlineData(06, 05, "five past six")] [InlineData(07, 10, "ten past seven")] [InlineData(08, 15, "a quarter past eight")] [InlineData(09, 20, "twenty past nine")] [InlineData(10, 25, "twenty-five past ten")] [InlineData(11, 30, "half past eleven")] [InlineData(12, 00, "noon")] [InlineData(13, 23, "twenty-five past one")] [InlineData(14, 32, "half past two")] [InlineData(15, 35, "three thirty-five")] [InlineData(16, 40, "twenty to five")] [InlineData(17, 45, "a quarter to six")] [InlineData(18, 50, "ten to seven")] [InlineData(19, 55, "five to eight")] [InlineData(20, 59, "nine o'clock")] public void ConvertToRoundedClockNotationTimeOnlyStringEnUs(int hours, int minutes, string expectedResult) { var actualResult = new TimeOnly(hours, minutes).ToClockNotation(ClockNotationRounding.NearestFiveMinutes); Assert.Equal(expectedResult, actualResult); } } #endif ================================================ FILE: tests/Humanizer.Tests/Localisation/en-IN/NumberToWordsTests.cs ================================================ namespace enIN; [UseCulture("en-IN")] public class NumberToWordsTests { [Theory] [InlineData(0, "")] [InlineData(1, "one")] [InlineData(10, "ten")] [InlineData(11, "eleven")] [InlineData(20, "twenty")] [InlineData(122, "one hundred and twenty two")] [InlineData(3501, "three thousand five hundred and one")] [InlineData(100, "one hundred")] [InlineData(1000, "one thousand")] [InlineData(1001, "one thousand one")] [InlineData(100000, "one lakh")] [InlineData(1000000, "ten lakh")] [InlineData(10000000, "one crore")] [InlineData(100000000, "ten crore")] [InlineData(1000000000, "one hundred crore")] [InlineData(111, "one hundred and eleven")] [InlineData(1111, "one thousand one hundred and eleven")] [InlineData(111111, "one lakh eleven thousand one hundred and eleven")] [InlineData(1111111, "eleven lakh eleven thousand one hundred and eleven")] [InlineData(11111111, "one crore eleven lakh eleven thousand one hundred and eleven")] [InlineData(111111111, "eleven crore eleven lakh eleven thousand one hundred and eleven")] [InlineData(1111111111, "one hundred and eleven crore eleven lakh eleven thousand one hundred and eleven")] [InlineData(101, "one hundred and one")] [InlineData(1011, "one thousand eleven")] [InlineData(100011, "one lakh eleven")] [InlineData(1100001, "eleven lakh one")] [InlineData(11000011, "one crore ten lakh eleven")] [InlineData(110000011, "eleven crore eleven")] [InlineData(1100000111, "one hundred and ten crore one hundred and eleven")] [InlineData(123, "one hundred and twenty three")] [InlineData(1234, "one thousand two hundred and thirty four")] [InlineData(12345, "twelve thousand three hundred and forty five")] [InlineData(123456, "one lakh twenty three thousand four hundred and fifty six")] [InlineData(1234567, "twelve lakh thirty four thousand five hundred and sixty seven")] [InlineData(12345678, "one crore twenty three lakh forty five thousand six hundred and seventy eight")] [InlineData(123456789, "twelve crore thirty four lakh fifty six thousand seven hundred and eighty nine")] [InlineData(1234567890, "one hundred and twenty three crore forty five lakh sixty seven thousand eight hundred and ninety")] [InlineData(1000000000000, "one lakh crore")] [InlineData(45678912345678, "forty five lakh sixty seven thousand eight hundred and ninety one crore twenty three lakh forty five thousand six hundred and seventy eight")] [InlineData(-7516, "(Negative) seven thousand five hundred and sixteen")] public void ToWords(long number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(1, "one")] [InlineData(3501, "three thousand five hundred and one")] public void ToWordsFeminine(long number, string expected) => Assert.Equal(expected, number.ToWords(GrammaticalGender.Feminine)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/es/DateHumanizeTests.cs ================================================ namespace es; [UseCulture("es-ES")] public class DateHumanizeTests { [Theory] [InlineData(1, "hace un segundo")] [InlineData(2, "hace 2 segundos")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "en un segundo")] [InlineData(2, "en 2 segundos")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(1, "hace un minuto")] [InlineData(2, "hace 2 minutos")] [InlineData(60, "hace una hora")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "en un minuto")] [InlineData(2, "en 2 minutos")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(1, "hace una hora")] [InlineData(2, "hace 2 horas")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "en una hora")] [InlineData(2, "en 2 horas")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(1, "ayer")] [InlineData(2, "hace 2 días")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "mañana")] [InlineData(2, "en 2 días")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(1, "hace un mes")] [InlineData(2, "hace 2 meses")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "en un mes")] [InlineData(2, "en 2 meses")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(1, "hace un año")] [InlineData(2, "hace 2 años")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "en un año")] [InlineData(2, "en 2 años")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/es/DateToOrdinalWordsTests.cs ================================================ namespace es; [UseCulture("es-ES")] public class DateToOrdinalWordsTests { [Fact] public void OrdinalizeString() { Assert.Equal("25 de enero de 2022", new DateTime(2022, 1, 25).ToOrdinalWords()); Assert.Equal("29 de febrero de 2020", new DateTime(2020, 2, 29).ToOrdinalWords()); Assert.Equal("4 de septiembre de 2015", new DateTime(2015, 9, 4).ToOrdinalWords()); Assert.Equal("7 de noviembre de 1979", new DateTime(1979, 11, 7).ToOrdinalWords()); } #if NET6_0_OR_GREATER [Fact] public void OrdinalizeDateOnlyString() { Assert.Equal("25 de enero de 2022", new DateOnly(2022, 1, 25).ToOrdinalWords()); Assert.Equal("29 de febrero de 2020", new DateOnly(2020, 2, 29).ToOrdinalWords()); Assert.Equal("4 de septiembre de 2015", new DateOnly(2015, 9, 4).ToOrdinalWords()); Assert.Equal("7 de noviembre de 1979", new DateOnly(1979, 11, 7).ToOrdinalWords()); } #endif } ================================================ FILE: tests/Humanizer.Tests/Localisation/es/NumberToWordsFeminineTest.cs ================================================ namespace es; [UseCulture("es-ES")] public class NumberToWordsFeminineTests { [Theory] [InlineData(1, "una")] [InlineData(21, "veintiuna")] [InlineData(31, "treinta y una")] [InlineData(81, "ochenta y una")] [InlineData(500, "quinientas")] [InlineData(701, "setecientas una")] [InlineData(3500, "tres mil quinientas")] [InlineData(200121, "doscientas mil ciento veintiuna")] [InlineData(200000121, "doscientos millones ciento veintiuna")] [InlineData(1000001, "un millón una")] public void ToWords(int number, string expected) => Assert.Equal(expected, number.ToWords(GrammaticalGender.Feminine)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/es/NumberToWordsTests.cs ================================================ namespace es; [UseCulture("es-ES")] public class NumberToWordsTests { [Theory] [InlineData(-1, "primero", GrammaticalGender.Neuter)] [InlineData(0, "cero", GrammaticalGender.Neuter)] [InlineData(1, "primero", GrammaticalGender.Neuter)] [InlineData(1, "primero", GrammaticalGender.Masculine)] [InlineData(1, "primera", GrammaticalGender.Feminine)] [InlineData(2, "segundo", GrammaticalGender.Masculine)] [InlineData(2, "segunda", GrammaticalGender.Feminine)] [InlineData(3, "tercero", GrammaticalGender.Neuter)] [InlineData(3, "tercero", GrammaticalGender.Masculine)] [InlineData(3, "tercera", GrammaticalGender.Feminine)] [InlineData(4, "cuarto", GrammaticalGender.Masculine)] [InlineData(4, "cuarta", GrammaticalGender.Feminine)] [InlineData(5, "quinto", GrammaticalGender.Masculine)] [InlineData(5, "quinta", GrammaticalGender.Feminine)] [InlineData(6, "sexto", GrammaticalGender.Masculine)] [InlineData(6, "sexta", GrammaticalGender.Feminine)] [InlineData(7, "séptimo", GrammaticalGender.Masculine)] [InlineData(7, "séptima", GrammaticalGender.Feminine)] [InlineData(8, "octavo", GrammaticalGender.Masculine)] [InlineData(8, "octava", GrammaticalGender.Feminine)] [InlineData(9, "noveno", GrammaticalGender.Masculine)] [InlineData(9, "novena", GrammaticalGender.Feminine)] [InlineData(10, "décimo", GrammaticalGender.Masculine)] [InlineData(10, "décima", GrammaticalGender.Feminine)] [InlineData(11, "décimo primero", GrammaticalGender.Masculine)] [InlineData(11, "décima primera", GrammaticalGender.Feminine)] [InlineData(20, "vigésimo", GrammaticalGender.Masculine)] [InlineData(20, "vigésima", GrammaticalGender.Feminine)] [InlineData(22, "vigésimo segundo", GrammaticalGender.Masculine)] [InlineData(22, "vigésima segunda", GrammaticalGender.Feminine)] [InlineData(30, "trigésimo", GrammaticalGender.Masculine)] [InlineData(30, "trigésima", GrammaticalGender.Feminine)] [InlineData(34, "trigésimo cuarto", GrammaticalGender.Masculine)] [InlineData(34, "trigésima cuarta", GrammaticalGender.Feminine)] [InlineData(40, "cuadragésimo", GrammaticalGender.Masculine)] [InlineData(40, "cuadragésima", GrammaticalGender.Feminine)] [InlineData(46, "cuadragésimo sexto", GrammaticalGender.Masculine)] [InlineData(46, "cuadragésima sexta", GrammaticalGender.Feminine)] [InlineData(50, "quincuagésimo", GrammaticalGender.Masculine)] [InlineData(50, "quincuagésima", GrammaticalGender.Feminine)] [InlineData(57, "quincuagésimo séptimo", GrammaticalGender.Masculine)] [InlineData(57, "quincuagésima séptima", GrammaticalGender.Feminine)] [InlineData(60, "sexagésimo", GrammaticalGender.Masculine)] [InlineData(60, "sexagésima", GrammaticalGender.Feminine)] [InlineData(69, "sexagésimo noveno", GrammaticalGender.Masculine)] [InlineData(69, "sexagésima novena", GrammaticalGender.Feminine)] [InlineData(70, "septuagésimo", GrammaticalGender.Masculine)] [InlineData(70, "septuagésima", GrammaticalGender.Feminine)] [InlineData(74, "septuagésimo cuarto", GrammaticalGender.Masculine)] [InlineData(74, "septuagésima cuarta", GrammaticalGender.Feminine)] [InlineData(80, "octogésimo", GrammaticalGender.Masculine)] [InlineData(80, "octogésima", GrammaticalGender.Feminine)] [InlineData(85, "octogésimo quinto", GrammaticalGender.Masculine)] [InlineData(85, "octogésima quinta", GrammaticalGender.Feminine)] [InlineData(90, "nonagésimo", GrammaticalGender.Masculine)] [InlineData(90, "nonagésima", GrammaticalGender.Feminine)] [InlineData(99, "nonagésimo noveno", GrammaticalGender.Masculine)] [InlineData(99, "nonagésima novena", GrammaticalGender.Feminine)] [InlineData(100, "centésimo", GrammaticalGender.Masculine)] [InlineData(100, "centésima", GrammaticalGender.Feminine)] [InlineData(101, "centésimo primero", GrammaticalGender.Masculine)] [InlineData(101, "centésima primera", GrammaticalGender.Feminine)] [InlineData(131, "centésimo trigésimo primero", GrammaticalGender.Masculine)] [InlineData(131, "centésima trigésima primera", GrammaticalGender.Feminine)] [InlineData(156, "centésimo quincuagésimo sexto", GrammaticalGender.Masculine)] [InlineData(156, "centésima quincuagésima sexta", GrammaticalGender.Feminine)] [InlineData(214, "ducentésimo décimo cuarto", GrammaticalGender.Masculine)] [InlineData(214, "ducentésima décima cuarta", GrammaticalGender.Feminine)] [InlineData(330, "tricentésimo trigésimo", GrammaticalGender.Masculine)] [InlineData(330, "tricentésima trigésima", GrammaticalGender.Feminine)] [InlineData(334, "tricentésimo trigésimo cuarto", GrammaticalGender.Masculine)] [InlineData(334, "tricentésima trigésima cuarta", GrammaticalGender.Feminine)] [InlineData(400, "cuadringentésimo", GrammaticalGender.Masculine)] [InlineData(400, "cuadringentésima", GrammaticalGender.Feminine)] [InlineData(407, "cuadringentésimo séptimo", GrammaticalGender.Masculine)] [InlineData(407, "cuadringentésima séptima", GrammaticalGender.Feminine)] [InlineData(476, "cuadringentésimo septuagésimo sexto", GrammaticalGender.Masculine)] [InlineData(476, "cuadringentésima septuagésima sexta", GrammaticalGender.Feminine)] [InlineData(500, "quingentésimo", GrammaticalGender.Masculine)] [InlineData(500, "quingentésima", GrammaticalGender.Feminine)] [InlineData(509, "quingentésimo noveno", GrammaticalGender.Masculine)] [InlineData(509, "quingentésima novena", GrammaticalGender.Feminine)] [InlineData(549, "quingentésimo cuadragésimo noveno", GrammaticalGender.Masculine)] [InlineData(549, "quingentésima cuadragésima novena", GrammaticalGender.Feminine)] [InlineData(600, "sexcentésimo", GrammaticalGender.Masculine)] [InlineData(600, "sexcentésima", GrammaticalGender.Feminine)] [InlineData(605, "sexcentésimo quinto", GrammaticalGender.Masculine)] [InlineData(605, "sexcentésima quinta", GrammaticalGender.Feminine)] [InlineData(670, "sexcentésimo septuagésimo", GrammaticalGender.Masculine)] [InlineData(670, "sexcentésima septuagésima", GrammaticalGender.Feminine)] [InlineData(692, "sexcentésimo nonagésimo segundo", GrammaticalGender.Masculine)] [InlineData(692, "sexcentésima nonagésima segunda", GrammaticalGender.Feminine)] [InlineData(700, "septingentésimo", GrammaticalGender.Masculine)] [InlineData(700, "septingentésima", GrammaticalGender.Feminine)] [InlineData(771, "septingentésimo septuagésimo primero", GrammaticalGender.Masculine)] [InlineData(771, "septingentésima septuagésima primera", GrammaticalGender.Feminine)] [InlineData(800, "octingentésimo", GrammaticalGender.Masculine)] [InlineData(800, "octingentésima", GrammaticalGender.Feminine)] [InlineData(849, "octingentésimo cuadragésimo noveno", GrammaticalGender.Masculine)] [InlineData(849, "octingentésima cuadragésima novena", GrammaticalGender.Feminine)] [InlineData(900, "noningentésimo", GrammaticalGender.Masculine)] [InlineData(900, "noningentésima", GrammaticalGender.Feminine)] [InlineData(921, "noningentésimo vigésimo primero", GrammaticalGender.Masculine)] [InlineData(921, "noningentésima vigésima primera", GrammaticalGender.Feminine)] [InlineData(1000, "milésimo", GrammaticalGender.Masculine)] [InlineData(1000, "milésima", GrammaticalGender.Feminine)] [InlineData(1006, "milésimo sexto", GrammaticalGender.Masculine)] [InlineData(1006, "milésima sexta", GrammaticalGender.Feminine)] [InlineData(1108, "milésimo centésimo octavo", GrammaticalGender.Masculine)] [InlineData(1108, "milésima centésima octava", GrammaticalGender.Feminine)] [InlineData(1323, "milésimo tricentésimo vigésimo tercero", GrammaticalGender.Masculine)] [InlineData(1323, "milésima tricentésima vigésima tercera", GrammaticalGender.Feminine)] [InlineData(2000, "dosmilésimo", GrammaticalGender.Masculine)] [InlineData(2000, "dosmilésima", GrammaticalGender.Feminine)] [InlineData(2164, "dosmilésimo centésimo sexagésimo cuarto", GrammaticalGender.Masculine)] [InlineData(2164, "dosmilésima centésima sexagésima cuarta", GrammaticalGender.Feminine)] [InlineData(2915, "dosmilésimo noningentésimo décimo quinto", GrammaticalGender.Masculine)] [InlineData(2915, "dosmilésima noningentésima décima quinta", GrammaticalGender.Feminine)] [InlineData(3000, "tresmilésimo", GrammaticalGender.Masculine)] [InlineData(3000, "tresmilésima", GrammaticalGender.Feminine)] [InlineData(3456, "tresmilésimo cuadringentésimo quincuagésimo sexto", GrammaticalGender.Masculine)] [InlineData(3456, "tresmilésima cuadringentésima quincuagésima sexta", GrammaticalGender.Feminine)] [InlineData(4000, "cuatromilésimo", GrammaticalGender.Masculine)] [InlineData(4000, "cuatromilésima", GrammaticalGender.Feminine)] [InlineData(4354, "cuatromilésimo tricentésimo quincuagésimo cuarto", GrammaticalGender.Masculine)] [InlineData(4354, "cuatromilésima tricentésima quincuagésima cuarta", GrammaticalGender.Feminine)] [InlineData(5000, "cincomilésimo", GrammaticalGender.Masculine)] [InlineData(5000, "cincomilésima", GrammaticalGender.Feminine)] [InlineData(5695, "cincomilésimo sexcentésimo nonagésimo quinto", GrammaticalGender.Masculine)] [InlineData(5695, "cincomilésima sexcentésima nonagésima quinta", GrammaticalGender.Feminine)] [InlineData(6000, "seismilésimo", GrammaticalGender.Masculine)] [InlineData(6000, "seismilésima", GrammaticalGender.Feminine)] [InlineData(6642, "seismilésimo sexcentésimo cuadragésimo segundo", GrammaticalGender.Masculine)] [InlineData(6642, "seismilésima sexcentésima cuadragésima segunda", GrammaticalGender.Feminine)] [InlineData(7000, "sietemilésimo", GrammaticalGender.Masculine)] [InlineData(7000, "sietemilésima", GrammaticalGender.Feminine)] [InlineData(7676, "sietemilésimo sexcentésimo septuagésimo sexto", GrammaticalGender.Masculine)] [InlineData(7676, "sietemilésima sexcentésima septuagésima sexta", GrammaticalGender.Feminine)] [InlineData(8000, "ochomilésimo", GrammaticalGender.Masculine)] [InlineData(8000, "ochomilésima", GrammaticalGender.Feminine)] [InlineData(8431, "ochomilésimo cuadringentésimo trigésimo primero", GrammaticalGender.Masculine)] [InlineData(8431, "ochomilésima cuadringentésima trigésima primera", GrammaticalGender.Feminine)] [InlineData(9000, "nuevemilésimo", GrammaticalGender.Masculine)] [InlineData(9000, "nuevemilésima", GrammaticalGender.Feminine)] [InlineData(9620, "nuevemilésimo sexcentésimo vigésimo", GrammaticalGender.Masculine)] [InlineData(9620, "nuevemilésima sexcentésima vigésima", GrammaticalGender.Feminine)] [InlineData(9999, "nuevemilésimo noningentésimo nonagésimo noveno", GrammaticalGender.Masculine)] [InlineData(9999, "nuevemilésima noningentésima nonagésima novena", GrammaticalGender.Feminine)] [InlineData(10000, "diezmilésimo", GrammaticalGender.Masculine)] [InlineData(10000, "diezmilésima", GrammaticalGender.Feminine)] [InlineData(11000, "oncemilésimo", GrammaticalGender.Masculine)] [InlineData(11000, "oncemilésima", GrammaticalGender.Feminine)] [InlineData(20000, "veintemilésimo", GrammaticalGender.Masculine)] [InlineData(21000, "veintiunmilésimo", GrammaticalGender.Masculine)] [InlineData(21000, "veintiunmilésima", GrammaticalGender.Feminine)] [InlineData(30000, "treintamilésimo", GrammaticalGender.Masculine)] [InlineData(31000, "treinta y un milésimo", GrammaticalGender.Masculine)] [InlineData(31000, "treinta y una milésima", GrammaticalGender.Feminine)] [InlineData(84301, "ochenta y cuatro milésimo tricentésimo primero", GrammaticalGender.Masculine)] [InlineData(84301, "ochenta y cuatro milésima tricentésima primera", GrammaticalGender.Feminine)] [InlineData(99999, "noventa y nueve milésimo noningentésimo nonagésimo noveno", GrammaticalGender.Masculine)] [InlineData(99999, "noventa y nueve milésima noningentésima nonagésima novena", GrammaticalGender.Feminine)] [InlineData(100000, "cienmilésimo", GrammaticalGender.Masculine)] [InlineData(100000, "cienmilésima", GrammaticalGender.Feminine)] [InlineData(200000, "doscientosmilésimo", GrammaticalGender.Masculine)] [InlineData(200000, "doscientasmilésima", GrammaticalGender.Feminine)] [InlineData(380000, "trescientos ochenta milésimo", GrammaticalGender.Masculine)] [InlineData(380000, "trescientas ochenta milésima", GrammaticalGender.Feminine)] [InlineData(850000, "ochocientos cincuenta milésimo", GrammaticalGender.Masculine)] [InlineData(850000, "ochocientas cincuenta milésima", GrammaticalGender.Feminine)] [InlineData(214748, "doscientos catorce milésimo septingentésimo cuadragésimo octavo", GrammaticalGender.Masculine)] [InlineData(214748, "doscientas catorce milésima septingentésima cuadragésima octava", GrammaticalGender.Feminine)] [InlineData(221221, "doscientos veintiún milésimo ducentésimo vigésimo primero", GrammaticalGender.Masculine)] [InlineData(221221, "doscientas veintiuna milésima ducentésima vigésima primera", GrammaticalGender.Feminine)] [InlineData(1000000, "millonésimo", GrammaticalGender.Masculine)] [InlineData(1000000, "millonésima", GrammaticalGender.Feminine)] [InlineData(2000000, "dosmillonésimo", GrammaticalGender.Masculine)] [InlineData(2000000, "dosmillonésima", GrammaticalGender.Feminine)] [InlineData(1001000, "un millón milésimo", GrammaticalGender.Masculine)] [InlineData(1221000, "un millón doscientos veintiún milésimo", GrammaticalGender.Masculine)] [InlineData(1221000, "un millón doscientas veintiuna milésima", GrammaticalGender.Feminine)] [InlineData(1500000, "un millón quinientos milésimo", GrammaticalGender.Masculine)] [InlineData(1500000, "un millón quinientas milésima", GrammaticalGender.Feminine)] [InlineData(10000000, "diezmillonésimo", GrammaticalGender.Masculine)] [InlineData(10000000, "diezmillonésima", GrammaticalGender.Feminine)] [InlineData(15000000, "quincemillonésimo", GrammaticalGender.Masculine)] [InlineData(15000000, "quincemillonésima", GrammaticalGender.Feminine)] [InlineData(21000000, "veintiunmillonésimo", GrammaticalGender.Masculine)] [InlineData(21000000, "veintiunmillonésima", GrammaticalGender.Feminine)] [InlineData(31000000, "treinta y un millonésimo", GrammaticalGender.Masculine)] [InlineData(31000000, "treinta y una millonésima", GrammaticalGender.Feminine)] [InlineData(50000000, "cincuentamillonésimo", GrammaticalGender.Masculine)] [InlineData(50000000, "cincuentamillonésima", GrammaticalGender.Feminine)] [InlineData(100000000, "cienmillonésimo", GrammaticalGender.Masculine)] [InlineData(100000000, "cienmillonésima", GrammaticalGender.Feminine)] [InlineData(150000000, "ciento cincuenta millonésimo", GrammaticalGender.Masculine)] [InlineData(150000000, "ciento cincuenta millonésima", GrammaticalGender.Feminine)] [InlineData(500000000, "quinientosmillonésimo", GrammaticalGender.Masculine)] [InlineData(500000000, "quinientasmillonésima", GrammaticalGender.Feminine)] [InlineData(1000000000, "milmillonésimo", GrammaticalGender.Masculine)] [InlineData(1000000000, "milmillonésima", GrammaticalGender.Feminine)] [InlineData(1001000000, "mil un millonésimo", GrammaticalGender.Masculine)] [InlineData(1001000000, "mil una millonésima", GrammaticalGender.Feminine)] [InlineData(1500000000, "mil quinientos millonésimo", GrammaticalGender.Masculine)] [InlineData(1500000000, "mil quinientas millonésima", GrammaticalGender.Feminine)] [InlineData(2000000000, "dos mil millonésimo", GrammaticalGender.Masculine)] [InlineData(2000000000, "dos mil millonésima", GrammaticalGender.Feminine)] [InlineData(2147483647, "dos mil ciento cuarenta y siete millones cuatrocientos ochenta y tres milésimo sexcentésimo cuadragésimo séptimo", GrammaticalGender.Masculine)] [InlineData(2147483647, "dos mil ciento cuarenta y siete millones cuatrocientas ochenta y tres milésima sexcentésima cuadragésima séptima", GrammaticalGender.Feminine)] public void ToOrdinalWords(int number, string words, GrammaticalGender gender) => Assert.Equal(words, number.ToOrdinalWords(gender)); [Theory] [InlineData(1, WordForm.Normal, "primero")] [InlineData(1, WordForm.Abbreviation, "primer")] [InlineData(2, WordForm.Normal, "segundo")] [InlineData(2, WordForm.Abbreviation, "segundo")] [InlineData(3, WordForm.Normal, "tercero")] [InlineData(3, WordForm.Abbreviation, "tercer")] [InlineData(21, WordForm.Normal, "vigésimo primero")] [InlineData(21, WordForm.Abbreviation, "vigésimo primer")] [InlineData(43, WordForm.Normal, "cuadragésimo tercero")] [InlineData(43, WordForm.Abbreviation, "cuadragésimo tercer")] public void ToOrdinalWordsWithWordForm(int number, WordForm wordForm, string expected) => Assert.Equal(expected, number.ToOrdinalWords(wordForm)); [Theory] [InlineData(1, WordForm.Normal, GrammaticalGender.Masculine, "primero")] [InlineData(1, WordForm.Abbreviation, GrammaticalGender.Masculine, "primer")] [InlineData(1, WordForm.Abbreviation, GrammaticalGender.Feminine, "primera")] [InlineData(2, WordForm.Normal, GrammaticalGender.Masculine, "segundo")] [InlineData(2, WordForm.Abbreviation, GrammaticalGender.Masculine, "segundo")] [InlineData(2, WordForm.Abbreviation, GrammaticalGender.Feminine, "segunda")] [InlineData(3, WordForm.Normal, GrammaticalGender.Masculine, "tercero")] [InlineData(3, WordForm.Abbreviation, GrammaticalGender.Masculine, "tercer")] [InlineData(3, WordForm.Abbreviation, GrammaticalGender.Feminine, "tercera")] [InlineData(21, WordForm.Normal, GrammaticalGender.Masculine, "vigésimo primero")] [InlineData(21, WordForm.Abbreviation, GrammaticalGender.Masculine, "vigésimo primer")] [InlineData(21, WordForm.Abbreviation, GrammaticalGender.Feminine, "vigésima primera")] [InlineData(43, WordForm.Normal, GrammaticalGender.Masculine, "cuadragésimo tercero")] [InlineData(43, WordForm.Abbreviation, GrammaticalGender.Masculine, "cuadragésimo tercer")] [InlineData(43, WordForm.Abbreviation, GrammaticalGender.Feminine, "cuadragésima tercera")] public void ToOrdinalWordsWithWordFormAndGender(int number, WordForm wordForm, GrammaticalGender gender, string expected) => Assert.Equal(expected, number.ToOrdinalWords(gender, wordForm)); [Theory] [InlineData(0, "cero veces")] [InlineData(2, "doble")] [InlineData(100, "cien veces")] public void ToTuple(int number, string expected) => Assert.Equal(expected, number.ToTuple()); [Theory] [InlineData(0, "cero")] [InlineData(1, "uno")] [InlineData(1, "una", GrammaticalGender.Feminine)] [InlineData(10, "diez")] [InlineData(11, "once")] [InlineData(15, "quince")] [InlineData(16, "dieciséis")] [InlineData(20, "veinte")] [InlineData(21, "veintiuno")] [InlineData(21, "veintiuna", GrammaticalGender.Feminine)] [InlineData(22, "veintidós")] [InlineData(25, "veinticinco")] [InlineData(35, "treinta y cinco")] [InlineData(122, "ciento veintidós")] [InlineData(1999, "mil novecientos noventa y nueve")] [InlineData(2014, "dos mil catorce")] [InlineData(2048, "dos mil cuarenta y ocho")] [InlineData(3501, "tres mil quinientos uno")] [InlineData(21000, "veintiún mil")] [InlineData(21000, "veintiuna mil", GrammaticalGender.Feminine)] [InlineData(21501, "veintiún mil quinientos uno")] [InlineData(21501, "veintiuna mil quinientas una", GrammaticalGender.Feminine)] [InlineData(31000, "treinta y un mil")] [InlineData(31000, "treinta y una mil", GrammaticalGender.Feminine)] [InlineData(31501, "treinta y un mil quinientos uno")] [InlineData(31501, "treinta y una mil quinientas una", GrammaticalGender.Feminine)] [InlineData(101501, "ciento un mil quinientos uno")] [InlineData(101501, "ciento una mil quinientas una", GrammaticalGender.Feminine)] [InlineData(100, "cien")] [InlineData(1000, "mil")] [InlineData(100000, "cien mil")] [InlineData(1000000, "un millón")] [InlineData(10000000, "diez millones")] [InlineData(100000000, "cien millones")] [InlineData(1000000000, "mil millones")] [InlineData(1000000000000, "un billón")] [InlineData(1_000_000_000_000_000_000, "un trillón")] [InlineData(111, "ciento once")] [InlineData(1111, "mil ciento once")] [InlineData(111111, "ciento once mil ciento once")] [InlineData(1111111, "un millón ciento once mil ciento once")] [InlineData(11111111, "once millones ciento once mil ciento once")] [InlineData(111111111, "ciento once millones ciento once mil ciento once")] [InlineData(1111111111, "mil ciento once millones ciento once mil ciento once")] [InlineData(1111111111111, "un billón ciento once mil ciento once millones ciento once mil ciento once")] [InlineData(1111111111111111, "mil ciento once billones ciento once mil ciento once millones ciento once mil ciento once")] [InlineData(1111111111111111111, "un trillón ciento once mil ciento once billones ciento once mil ciento once millones ciento once mil ciento once")] [InlineData(9223372036854775807, "nueve trillones doscientos veintitrés mil trescientos setenta y dos billones treinta y seis mil ochocientos cincuenta y cuatro millones setecientos setenta y cinco mil ochocientos siete")] [InlineData(1001111111, "mil un millones ciento once mil ciento once")] [InlineData(1001000001, "mil un millones uno")] [InlineData(1002000001, "mil dos millones uno")] [InlineData(2001000001, "dos mil un millones uno")] [InlineData(1001000000001, "un billón mil millones uno")] [InlineData(1001000000000001, "mil un billones uno")] [InlineData(1002000000000001, "mil dos billones uno")] [InlineData(2002000000000001, "dos mil dos billones uno")] [InlineData(123, "ciento veintitrés")] [InlineData(1234, "mil doscientos treinta y cuatro")] [InlineData(12345, "doce mil trescientos cuarenta y cinco")] [InlineData(123456, "ciento veintitrés mil cuatrocientos cincuenta y seis")] [InlineData(1234567, "un millón doscientos treinta y cuatro mil quinientos sesenta y siete")] [InlineData(12345678, "doce millones trescientos cuarenta y cinco mil seiscientos setenta y ocho")] [InlineData(123456789, "ciento veintitrés millones cuatrocientos cincuenta y seis mil setecientos ochenta y nueve")] [InlineData(1234567890, "mil doscientos treinta y cuatro millones quinientos sesenta y siete mil ochocientos noventa")] [InlineData(-15, "menos quince")] [InlineData(-123, "menos ciento veintitrés")] [InlineData(-1234567890, "menos mil doscientos treinta y cuatro millones quinientos sesenta y siete mil ochocientos noventa")] [InlineData(-9223372036854775808, "menos nueve trillones doscientos veintitrés mil trescientos setenta y dos billones treinta y seis mil ochocientos cincuenta y cuatro millones setecientos setenta y cinco mil ochocientos ocho")] public void ToWords(long number, string expected, GrammaticalGender gender = GrammaticalGender.Masculine) => Assert.Equal(expected, number.ToWords(gender)); [Theory] [InlineData(1, WordForm.Abbreviation, "un")] [InlineData(1, WordForm.Normal, "uno")] [InlineData(21, WordForm.Abbreviation, "veintiún")] [InlineData(21, WordForm.Normal, "veintiuno")] [InlineData(21501, WordForm.Abbreviation, "veintiún mil quinientos un")] [InlineData(21501, WordForm.Normal, "veintiún mil quinientos uno")] public void ToWordsIntWithWordForm(int number, WordForm wordForm, string expected) { Assert.Equal(expected, number.ToWords(wordForm)); Assert.Equal(expected, number.ToWords(wordForm: wordForm, addAnd: false)); Assert.Equal(expected, number.ToWords(wordForm: wordForm, addAnd: true)); } [Theory] [InlineData(1, WordForm.Abbreviation, GrammaticalGender.Masculine, "un")] [InlineData(1, WordForm.Abbreviation, GrammaticalGender.Feminine, "una")] [InlineData(21, WordForm.Abbreviation, GrammaticalGender.Masculine, "veintiún")] [InlineData(21, WordForm.Abbreviation, GrammaticalGender.Feminine, "veintiuna")] [InlineData(21501, WordForm.Abbreviation, GrammaticalGender.Masculine, "veintiún mil quinientos un")] [InlineData(21501, WordForm.Normal, GrammaticalGender.Masculine, "veintiún mil quinientos uno")] [InlineData(21501, WordForm.Abbreviation, GrammaticalGender.Feminine, "veintiuna mil quinientas una")] public void ToWordsIntWithWordFormAndGender(int number, WordForm wordForm, GrammaticalGender gender, string expected) => Assert.Equal(expected, number.ToWords(wordForm, gender)); [Theory] [InlineData((long)1, WordForm.Abbreviation, "un")] [InlineData((long)1, WordForm.Normal, "uno")] [InlineData((long)21, WordForm.Abbreviation, "veintiún")] [InlineData((long)21, WordForm.Normal, "veintiuno")] [InlineData((long)21501, WordForm.Abbreviation, "veintiún mil quinientos un")] [InlineData((long)21501, WordForm.Normal, "veintiún mil quinientos uno")] public void ToWordsLongWithWordForm(long number, WordForm wordForm, string expected) { Assert.Equal(expected, number.ToWords(wordForm)); Assert.Equal(expected, number.ToWords(wordForm: wordForm, addAnd: false)); Assert.Equal(expected, number.ToWords(wordForm: wordForm, addAnd: true)); } [Theory] [InlineData((long)1, WordForm.Abbreviation, GrammaticalGender.Masculine, "un")] [InlineData((long)1, WordForm.Abbreviation, GrammaticalGender.Feminine, "una")] [InlineData((long)21, WordForm.Abbreviation, GrammaticalGender.Masculine, "veintiún")] [InlineData((long)21, WordForm.Abbreviation, GrammaticalGender.Feminine, "veintiuna")] [InlineData((long)21501, WordForm.Abbreviation, GrammaticalGender.Masculine, "veintiún mil quinientos un")] [InlineData((long)21501, WordForm.Normal, GrammaticalGender.Masculine, "veintiún mil quinientos uno")] [InlineData((long)21501, WordForm.Abbreviation, GrammaticalGender.Feminine, "veintiuna mil quinientas una")] public void ToWordsLongWithWordFormAndGender(long number, WordForm wordForm, GrammaticalGender gender, string expected) => Assert.Equal(expected, number.ToWords(wordForm, gender)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/es/OrdinalizeTests.cs ================================================ namespace es; [UseCulture("es-ES")] public class OrdinalizeTests { [Theory] [InlineData(1, "1.º")] [InlineData(3, "3.º")] public void OrdinalizeDefaultGender(int number, string ordinalized) => Assert.Equal(number.Ordinalize(), ordinalized); [Theory] [InlineData(-1, "1.º")] [InlineData(int.MinValue, "0")] public void OrdinalizeZeroOrNegativeNumber(int number, string ordinalized) => Assert.Equal(number.Ordinalize(), ordinalized); [Theory] [InlineData(1, WordForm.Abbreviation, "1.er")] [InlineData(1, WordForm.Normal, "1.º")] [InlineData(2, WordForm.Abbreviation, "2.º")] [InlineData(2, WordForm.Normal, "2.º")] [InlineData(3, WordForm.Abbreviation, "3.er")] [InlineData(3, WordForm.Normal, "3.º")] [InlineData(21, WordForm.Abbreviation, "21.er")] [InlineData(21, WordForm.Normal, "21.º")] public void OrdinalizeWithWordForm(int number, WordForm wordForm, string expected) { Assert.Equal(expected, number.Ordinalize(wordForm)); Assert.Equal(expected, number.ToString(CultureInfo.CurrentUICulture).Ordinalize(wordForm)); } [Theory] [InlineData(1, GrammaticalGender.Masculine, WordForm.Abbreviation, "1.er")] [InlineData(1, GrammaticalGender.Masculine, WordForm.Normal, "1.º")] [InlineData(1, GrammaticalGender.Feminine, WordForm.Abbreviation, "1.ª")] [InlineData(1, GrammaticalGender.Feminine, WordForm.Normal, "1.ª")] [InlineData(1, GrammaticalGender.Neuter, WordForm.Abbreviation, "1.er")] [InlineData(1, GrammaticalGender.Neuter, WordForm.Normal, "1.º")] public void OrdinalizeWithWordFormAndGender(int number, GrammaticalGender gender, WordForm wordForm, string expected) { Assert.Equal(expected, number.Ordinalize(gender, wordForm)); Assert.Equal(expected, number.ToString(CultureInfo.CurrentUICulture).Ordinalize(gender, wordForm)); } [Theory] [InlineData("1", "1.º")] [InlineData("2", "2.º")] [InlineData("3", "3.º")] [InlineData("4", "4.º")] [InlineData("5", "5.º")] [InlineData("6", "6.º")] [InlineData("23", "23.º")] [InlineData("100", "100.º")] [InlineData("101", "101.º")] [InlineData("102", "102.º")] [InlineData("103", "103.º")] [InlineData("1001", "1001.º")] public void OrdinalizeString(string number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Masculine), ordinalized); [Theory] [InlineData("0", "0")] [InlineData("1", "1.ª")] [InlineData("2", "2.ª")] [InlineData("3", "3.ª")] [InlineData("4", "4.ª")] [InlineData("5", "5.ª")] [InlineData("6", "6.ª")] [InlineData("23", "23.ª")] [InlineData("100", "100.ª")] [InlineData("101", "101.ª")] [InlineData("102", "102.ª")] [InlineData("103", "103.ª")] [InlineData("1001", "1001.ª")] public void OrdinalizeStringFeminine(string number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Feminine), ordinalized); [Theory] [InlineData(0, "0")] [InlineData(1, "1.º")] [InlineData(2, "2.º")] [InlineData(3, "3.º")] [InlineData(4, "4.º")] [InlineData(5, "5.º")] [InlineData(6, "6.º")] [InlineData(10, "10.º")] [InlineData(23, "23.º")] [InlineData(100, "100.º")] [InlineData(101, "101.º")] [InlineData(102, "102.º")] [InlineData(103, "103.º")] [InlineData(1001, "1001.º")] public void OrdinalizeNumber(int number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Masculine), ordinalized); [Theory] [InlineData(0, "0")] [InlineData(1, "1.ª")] [InlineData(2, "2.ª")] [InlineData(3, "3.ª")] [InlineData(4, "4.ª")] [InlineData(5, "5.ª")] [InlineData(6, "6.ª")] [InlineData(10, "10.ª")] [InlineData(23, "23.ª")] [InlineData(100, "100.ª")] [InlineData(101, "101.ª")] [InlineData(102, "102.ª")] [InlineData(103, "103.ª")] [InlineData(1001, "1001.ª")] public void OrdinalizeNumberFeminine(int number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Feminine), ordinalized); } ================================================ FILE: tests/Humanizer.Tests/Localisation/es/TimeSpanHumanizeTests.cs ================================================ namespace es; [UseCulture("es-ES")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "1 año")] [InlineData(731, "2 años")] [InlineData(1096, "3 años")] [InlineData(4018, "11 años")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "1 mes")] [InlineData(61, "2 meses")] [InlineData(92, "3 meses")] [InlineData(335, "11 meses")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Fact] public void TwoWeeks() => Assert.Equal("2 semanas", TimeSpan.FromDays(14).Humanize()); [Fact] public void OneWeek() => Assert.Equal("1 semana", TimeSpan.FromDays(7).Humanize()); [Fact] public void SixDays() => Assert.Equal("6 días", TimeSpan.FromDays(6).Humanize()); [Fact] public void TwoDays() => Assert.Equal("2 días", TimeSpan.FromDays(2).Humanize()); [Fact] public void OneDay() => Assert.Equal("1 día", TimeSpan.FromDays(1).Humanize()); [Fact] public void TwoHours() => Assert.Equal("2 horas", TimeSpan.FromHours(2).Humanize()); [Fact] public void OneHour() => Assert.Equal("1 hora", TimeSpan.FromHours(1).Humanize()); [Fact] public void TwoMinutes() => Assert.Equal("2 minutos", TimeSpan.FromMinutes(2).Humanize()); [Fact] public void OneMinute() => Assert.Equal("1 minuto", TimeSpan.FromMinutes(1).Humanize()); [Fact] public void TwoSeconds() => Assert.Equal("2 segundos", TimeSpan.FromSeconds(2).Humanize()); [Fact] public void OneSecond() => Assert.Equal("1 segundo", TimeSpan.FromSeconds(1).Humanize()); [Fact] public void TwoMilliseconds() => Assert.Equal("2 milisegundos", TimeSpan.FromMilliseconds(2).Humanize()); [Fact] public void OneMillisecond() => Assert.Equal("1 milisegundo", TimeSpan.FromMilliseconds(1).Humanize()); [Theory] [InlineData(0, 0, 1, 1, 2, "un minuto, un segundo")] [InlineData(0, 0, 2, 2, 2, "dos minutos, dos segundos")] [InlineData(1, 2, 3, 4, 4, "un día, dos horas, tres minutos, cuatro segundos")] public void ComplexTimeSpan(int days, int hours, int minutes, int seconds, int precision, string expected) { var timeSpan = new TimeSpan(days, hours, minutes, seconds); Assert.Equal(expected, timeSpan.Humanize(precision, toWords: true)); } [Fact] public void NoTime() => // This one doesn't make a lot of sense but ... w/e Assert.Equal("0 milisegundos", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => // This one doesn't make a lot of sense but ... w/e Assert.Equal("nada", TimeSpan.Zero.Humanize(toWords: true)); [Fact] public void AllTimeSpansMustBeUniqueForASequenceOfDays() { var culture = new CultureInfo("es-ES"); var qry = from i in Enumerable.Range(0, 100000) let ts = TimeSpan.FromDays(i) let text = ts.Humanize(precision: 3, culture: culture, maxUnit: TimeUnit.Year) select text; var grouping = from t in qry group t by t into g select new { g.Key, Count = g.Count() }; var allUnique = grouping.All(g => g.Count == 1); Assert.True(allUnique); } [Theory] [InlineData(365, "11 meses, 30 días")] [InlineData(365 + 1, "1 año")] [InlineData(365 + 365, "1 año, 11 meses, 29 días")] [InlineData(365 + 365 + 1, "2 años")] [InlineData(365 + 365 + 365, "2 años, 11 meses, 29 días")] [InlineData(365 + 365 + 365 + 1, "3 años")] [InlineData(365 + 365 + 365 + 365, "3 años, 11 meses, 29 días")] [InlineData(365 + 365 + 365 + 365 + 1, "4 años")] [InlineData(365 + 365 + 365 + 365 + 366, "4 años, 11 meses, 30 días")] [InlineData(365 + 365 + 365 + 365 + 366 + 1, "5 años")] public void Year(int days, string expected) { var actual = TimeSpan.FromDays(days).Humanize(precision: 7, maxUnit: TimeUnit.Year); Assert.Equal(expected, actual); } [Theory] [InlineData(30, "4 semanas, 2 días")] [InlineData(30 + 1, "1 mes")] [InlineData(30 + 30, "1 mes, 29 días")] [InlineData(30 + 30 + 1, "2 meses")] [InlineData(30 + 30 + 31, "2 meses, 30 días")] [InlineData(30 + 30 + 31 + 1, "3 meses")] [InlineData(30 + 30 + 31 + 30, "3 meses, 29 días")] [InlineData(30 + 30 + 31 + 30 + 1, "4 meses")] [InlineData(30 + 30 + 31 + 30 + 31, "4 meses, 30 días")] [InlineData(30 + 30 + 31 + 30 + 31 + 1, "5 meses")] [InlineData(365, "11 meses, 30 días")] [InlineData(366, "1 año")] public void Month(int days, string expected) { var actual = TimeSpan.FromDays(days).Humanize(precision: 7, maxUnit: TimeUnit.Year); Assert.Equal(expected, actual); } [Theory] [InlineData(14, "2 semanas")] [InlineData(7, "1 semana")] [InlineData(-14, "2 semanas")] [InlineData(-7, "1 semana")] [InlineData(730, "104 semanas")] public void Weeks(int days, string expected) { var actual = TimeSpan.FromDays(days).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(6, "6 días")] [InlineData(2, "2 días")] [InlineData(1, "1 día")] [InlineData(-6, "6 días")] [InlineData(-2, "2 días")] [InlineData(-1, "1 día")] public void Days(int days, string expected) { var actual = TimeSpan.FromDays(days).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 horas")] [InlineData(1, "1 hora")] [InlineData(-2, "2 horas")] [InlineData(-1, "1 hora")] public void Hours(int hours, string expected) { var actual = TimeSpan.FromHours(hours).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 minutos")] [InlineData(1, "1 minuto")] [InlineData(-2, "2 minutos")] [InlineData(-1, "1 minuto")] public void Minutes(int minutes, string expected) { var actual = TimeSpan.FromMinutes(minutes).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(135, "2 minutos")] [InlineData(60, "1 minuto")] [InlineData(2, "2 segundos")] [InlineData(1, "1 segundo")] [InlineData(-135, "2 minutos")] [InlineData(-60, "1 minuto")] [InlineData(-2, "2 segundos")] [InlineData(-1, "1 segundo")] public void Seconds(int seconds, string expected) { var actual = TimeSpan.FromSeconds(seconds).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2500, "2 segundos")] [InlineData(1400, "1 segundo")] [InlineData(2, "2 milisegundos")] [InlineData(1, "1 milisegundo")] [InlineData(-2500, "2 segundos")] [InlineData(-1400, "1 segundo")] [InlineData(-2, "2 milisegundos")] [InlineData(-1, "1 milisegundo")] public void Milliseconds(int ms, string expected) { var actual = TimeSpan.FromMilliseconds(ms).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData((long)366 * 24 * 60 * 60 * 1000, "12 meses", TimeUnit.Month)] [InlineData((long)6 * 7 * 24 * 60 * 60 * 1000, "6 semanas", TimeUnit.Week)] [InlineData(7 * 24 * 60 * 60 * 1000, "7 días", TimeUnit.Day)] [InlineData(24 * 60 * 60 * 1000, "24 horas", TimeUnit.Hour)] [InlineData(60 * 60 * 1000, "60 minutos", TimeUnit.Minute)] [InlineData(60 * 1000, "60 segundos", TimeUnit.Second)] [InlineData(1000, "1000 milisegundos", TimeUnit.Millisecond)] public void TimeSpanWithMaxTimeUnit(long ms, string expected, TimeUnit maxUnit) { var actual = TimeSpan.FromMilliseconds(ms).Humanize(maxUnit: maxUnit); Assert.Equal(expected, actual); } [Theory] [InlineData(10, "10 milisegundos", TimeUnit.Millisecond)] [InlineData(10, "nada", TimeUnit.Second, true)] [InlineData(10, "nada", TimeUnit.Minute, true)] [InlineData(10, "nada", TimeUnit.Hour, true)] [InlineData(10, "nada", TimeUnit.Day, true)] [InlineData(10, "nada", TimeUnit.Week, true)] [InlineData(10, "0 segundos", TimeUnit.Second)] [InlineData(10, "0 minutos", TimeUnit.Minute)] [InlineData(10, "0 horas", TimeUnit.Hour)] [InlineData(10, "0 días", TimeUnit.Day)] [InlineData(10, "0 semanas", TimeUnit.Week)] [InlineData(2500, "2 segundos, 500 milisegundos", TimeUnit.Millisecond)] [InlineData(2500, "2 segundos", TimeUnit.Second)] [InlineData(2500, "nada", TimeUnit.Minute, true)] [InlineData(2500, "nada", TimeUnit.Hour, true)] [InlineData(2500, "nada", TimeUnit.Day, true)] [InlineData(2500, "nada", TimeUnit.Week, true)] [InlineData(2500, "0 minutos", TimeUnit.Minute)] [InlineData(2500, "0 horas", TimeUnit.Hour)] [InlineData(2500, "0 días", TimeUnit.Day)] [InlineData(2500, "0 semanas", TimeUnit.Week)] [InlineData(122500, "2 minutos, 2 segundos, 500 milisegundos", TimeUnit.Millisecond)] [InlineData(122500, "2 minutos, 2 segundos", TimeUnit.Second)] [InlineData(122500, "2 minutos", TimeUnit.Minute)] [InlineData(122500, "nada", TimeUnit.Hour, true)] [InlineData(122500, "nada", TimeUnit.Day, true)] [InlineData(122500, "nada", TimeUnit.Week, true)] [InlineData(122500, "0 horas", TimeUnit.Hour)] [InlineData(122500, "0 días", TimeUnit.Day)] [InlineData(122500, "0 semanas", TimeUnit.Week)] [InlineData(3722500, "1 hora, 2 minutos, 2 segundos, 500 milisegundos", TimeUnit.Millisecond)] [InlineData(3722500, "1 hora, 2 minutos, 2 segundos", TimeUnit.Second)] [InlineData(3722500, "1 hora, 2 minutos", TimeUnit.Minute)] [InlineData(3722500, "1 hora", TimeUnit.Hour)] [InlineData(3722500, "nada", TimeUnit.Day, true)] [InlineData(3722500, "nada", TimeUnit.Week, true)] [InlineData(3722500, "0 días", TimeUnit.Day)] [InlineData(3722500, "0 semanas", TimeUnit.Week)] [InlineData(90122500, "1 día, 1 hora, 2 minutos, 2 segundos, 500 milisegundos", TimeUnit.Millisecond)] [InlineData(90122500, "1 día, 1 hora, 2 minutos, 2 segundos", TimeUnit.Second)] [InlineData(90122500, "1 día, 1 hora, 2 minutos", TimeUnit.Minute)] [InlineData(90122500, "1 día, 1 hora", TimeUnit.Hour)] [InlineData(90122500, "1 día", TimeUnit.Day)] [InlineData(90122500, "nada", TimeUnit.Week, true)] [InlineData(90122500, "0 semanas", TimeUnit.Week)] [InlineData(694922500, "1 semana, 1 día, 1 hora, 2 minutos, 2 segundos, 500 milisegundos", TimeUnit.Millisecond)] [InlineData(694922500, "1 semana, 1 día, 1 hora, 2 minutos, 2 segundos", TimeUnit.Second)] [InlineData(694922500, "1 semana, 1 día, 1 hora, 2 minutos", TimeUnit.Minute)] [InlineData(694922500, "1 semana, 1 día, 1 hora", TimeUnit.Hour)] [InlineData(694922500, "1 semana, 1 día", TimeUnit.Day)] [InlineData(694922500, "1 semana", TimeUnit.Week)] [InlineData(2768462500, "1 mes, 1 día, 1 hora, 1 minuto, 2 segundos, 500 milisegundos", TimeUnit.Millisecond)] [InlineData(2768462500, "1 mes, 1 día, 1 hora, 1 minuto, 2 segundos", TimeUnit.Second)] [InlineData(2768462500, "1 mes, 1 día, 1 hora, 1 minuto", TimeUnit.Minute)] [InlineData(2768462500, "1 mes, 1 día, 1 hora", TimeUnit.Hour)] [InlineData(2768462500, "1 mes, 1 día", TimeUnit.Day)] [InlineData(2768462500, "1 mes", TimeUnit.Week)] [InlineData(2768462500, "1 mes", TimeUnit.Month)] [InlineData(2768462500, "nada", TimeUnit.Year, true)] [InlineData(2768462500, "0 años", TimeUnit.Year)] [InlineData(34390862500, "1 año, 1 mes, 2 días, 1 hora, 1 minuto, 2 segundos, 500 milisegundos", TimeUnit.Millisecond)] [InlineData(34390862500, "1 año, 1 mes, 2 días, 1 hora, 1 minuto, 2 segundos", TimeUnit.Second)] [InlineData(34390862500, "1 año, 1 mes, 2 días, 1 hora, 1 minuto", TimeUnit.Minute)] [InlineData(34390862500, "1 año, 1 mes, 2 días, 1 hora", TimeUnit.Hour)] [InlineData(34390862500, "1 año, 1 mes, 2 días", TimeUnit.Day)] [InlineData(34390862500, "1 año, 1 mes", TimeUnit.Week)] [InlineData(34390862500, "1 año, 1 mes", TimeUnit.Month)] [InlineData(34390862500, "1 año", TimeUnit.Year)] public void TimeSpanWithMinTimeUnit(long ms, string expected, TimeUnit minUnit, bool toWords = false) { var actual = TimeSpan.FromMilliseconds(ms).Humanize(minUnit: minUnit, precision: 7, maxUnit: TimeUnit.Year, toWords: toWords); Assert.Equal(expected, actual); } [Theory] [InlineData(0, 3, "nada", true)] [InlineData(0, 2, "nada", true)] [InlineData(0, 3, "0 milisegundos")] [InlineData(0, 2, "0 milisegundos")] [InlineData(10, 2, "10 milisegundos")] [InlineData(1400, 2, "1 segundo, 400 milisegundos")] [InlineData(2500, 2, "2 segundos, 500 milisegundos")] [InlineData(120000, 2, "2 minutos")] [InlineData(62000, 2, "1 minuto, 2 segundos")] [InlineData(62020, 2, "1 minuto, 2 segundos")] [InlineData(62020, 3, "1 minuto, 2 segundos, 20 milisegundos")] [InlineData(3600020, 4, "1 hora, 20 milisegundos")] [InlineData(3600020, 3, "1 hora, 20 milisegundos")] [InlineData(3600020, 2, "1 hora, 20 milisegundos")] [InlineData(3600020, 1, "1 hora")] [InlineData(3603001, 2, "1 hora, 3 segundos")] [InlineData(3603001, 3, "1 hora, 3 segundos, 1 milisegundo")] [InlineData(86400000, 3, "1 día")] [InlineData(86400000, 2, "1 día")] [InlineData(86400000, 1, "1 día")] [InlineData(86401000, 1, "1 día")] [InlineData(86401000, 2, "1 día, 1 segundo")] [InlineData(86401200, 2, "1 día, 1 segundo")] [InlineData(86401200, 3, "1 día, 1 segundo, 200 milisegundos")] [InlineData(1296000000, 1, "2 semanas")] [InlineData(1296000000, 2, "2 semanas, 1 día")] [InlineData(1299600000, 2, "2 semanas, 1 día")] [InlineData(1299600000, 3, "2 semanas, 1 día, 1 hora")] [InlineData(1299630020, 3, "2 semanas, 1 día, 1 hora")] [InlineData(1299630020, 4, "2 semanas, 1 día, 1 hora, 30 segundos")] [InlineData(1299630020, 5, "2 semanas, 1 día, 1 hora, 30 segundos, 20 milisegundos")] [InlineData(2768462500, 6, "1 mes, 1 día, 1 hora, 1 minuto, 2 segundos, 500 milisegundos")] [InlineData(2768462500, 5, "1 mes, 1 día, 1 hora, 1 minuto, 2 segundos")] [InlineData(2768462500, 4, "1 mes, 1 día, 1 hora, 1 minuto")] [InlineData(2768462500, 3, "1 mes, 1 día, 1 hora")] [InlineData(2768462500, 2, "1 mes, 1 día")] [InlineData(2768462500, 1, "1 mes")] [InlineData(34390862500, 7, "1 año, 1 mes, 2 días, 1 hora, 1 minuto, 2 segundos, 500 milisegundos")] [InlineData(34390862500, 6, "1 año, 1 mes, 2 días, 1 hora, 1 minuto, 2 segundos")] [InlineData(34390862500, 5, "1 año, 1 mes, 2 días, 1 hora, 1 minuto")] [InlineData(34390862500, 4, "1 año, 1 mes, 2 días, 1 hora")] [InlineData(34390862500, 3, "1 año, 1 mes, 2 días")] [InlineData(34390862500, 2, "1 año, 1 mes")] [InlineData(34390862500, 1, "1 año")] public void TimeSpanWithPrecision(long milliseconds, int precision, string expected, bool toWords = false) { var actual = TimeSpan.FromMilliseconds(milliseconds).Humanize(precision, maxUnit: TimeUnit.Year, toWords: toWords); Assert.Equal(expected, actual); } [Theory] [InlineData(3 * 7 + 4, 2, "3 semanas, 4 días")] [InlineData(6 * 7 + 3, 2, "6 semanas, 3 días")] [InlineData(72 * 7 + 6, 2, "72 semanas, 6 días")] public void DaysWithPrecision(int days, int precision, string expected) { var actual = TimeSpan.FromDays(days).Humanize(precision: precision); Assert.Equal(expected, actual); } [Theory] [InlineData(50)] [InlineData(52)] public void TimeSpanWithMinAndMaxUnits_DoesNotReportExcessiveTime(int minutes) { var actual = TimeSpan.FromMinutes(minutes).Humanize(2, null, TimeUnit.Hour, TimeUnit.Minute); var expected = TimeSpan.FromMinutes(minutes).Humanize(2); Assert.Equal(expected, actual); } [Theory] [InlineData(0, 3, "nada", true)] [InlineData(0, 2, "nada", true)] [InlineData(0, 3, "0 milisegundos")] [InlineData(0, 2, "0 milisegundos")] [InlineData(10, 2, "10 milisegundos")] [InlineData(1400, 2, "1 segundo, 400 milisegundos")] [InlineData(2500, 2, "2 segundos, 500 milisegundos")] [InlineData(60001, 1, "1 minuto")] [InlineData(60001, 2, "1 minuto")] [InlineData(60001, 3, "1 minuto, 1 milisegundo")] [InlineData(120000, 2, "2 minutos")] [InlineData(62000, 2, "1 minuto, 2 segundos")] [InlineData(62020, 2, "1 minuto, 2 segundos")] [InlineData(62020, 3, "1 minuto, 2 segundos, 20 milisegundos")] [InlineData(3600020, 4, "1 hora, 20 milisegundos")] [InlineData(3600020, 3, "1 hora")] [InlineData(3600020, 2, "1 hora")] [InlineData(3600020, 1, "1 hora")] [InlineData(3603001, 2, "1 hora")] [InlineData(3603001, 3, "1 hora, 3 segundos")] [InlineData(86400000, 3, "1 día")] [InlineData(86400000, 2, "1 día")] [InlineData(86400000, 1, "1 día")] [InlineData(86401000, 1, "1 día")] [InlineData(86401000, 2, "1 día")] [InlineData(86401000, 3, "1 día")] [InlineData(86401000, 4, "1 día, 1 segundo")] [InlineData(86401200, 4, "1 día, 1 segundo")] [InlineData(86401200, 5, "1 día, 1 segundo, 200 milisegundos")] [InlineData(1296000000, 1, "2 semanas")] [InlineData(1296000000, 2, "2 semanas, 1 día")] [InlineData(1299600000, 2, "2 semanas, 1 día")] [InlineData(1299600000, 3, "2 semanas, 1 día, 1 hora")] [InlineData(1299630020, 3, "2 semanas, 1 día, 1 hora")] [InlineData(1299630020, 4, "2 semanas, 1 día, 1 hora")] [InlineData(1299630020, 5, "2 semanas, 1 día, 1 hora, 30 segundos")] [InlineData(1299630020, 6, "2 semanas, 1 día, 1 hora, 30 segundos, 20 milisegundos")] public void TimeSpanWithPrecisionAndCountingEmptyUnits(int milliseconds, int precision, string expected, bool toWords = false) { var actual = TimeSpan.FromMilliseconds(milliseconds).Humanize(precision: precision, countEmptyUnits: true, toWords: toWords); Assert.Equal(expected, actual); } [Theory] [InlineData(0, 3, "nada", true)] [InlineData(0, 2, "nada", true)] [InlineData(0, 3, "0 milisegundos")] [InlineData(0, 2, "0 milisegundos")] [InlineData(10, 2, "10 milisegundos")] [InlineData(1400, 2, "1 segundo y 400 milisegundos")] [InlineData(2500, 2, "2 segundos y 500 milisegundos")] [InlineData(120000, 2, "2 minutos")] [InlineData(62000, 2, "1 minuto y 2 segundos")] [InlineData(62020, 2, "1 minuto y 2 segundos")] [InlineData(62020, 3, "1 minuto, 2 segundos y 20 milisegundos")] [InlineData(3600020, 4, "1 hora y 20 milisegundos")] [InlineData(3600020, 3, "1 hora y 20 milisegundos")] [InlineData(3600020, 2, "1 hora y 20 milisegundos")] [InlineData(3600020, 1, "1 hora")] [InlineData(3603001, 2, "1 hora y 3 segundos")] [InlineData(3603001, 3, "1 hora, 3 segundos y 1 milisegundo")] [InlineData(86400000, 3, "1 día")] [InlineData(86400000, 2, "1 día")] [InlineData(86400000, 1, "1 día")] [InlineData(86401000, 1, "1 día")] [InlineData(86401000, 2, "1 día y 1 segundo")] [InlineData(86401200, 2, "1 día y 1 segundo")] [InlineData(86401200, 3, "1 día, 1 segundo y 200 milisegundos")] [InlineData(1296000000, 1, "2 semanas")] [InlineData(1296000000, 2, "2 semanas y 1 día")] [InlineData(1299600000, 2, "2 semanas y 1 día")] [InlineData(1299600000, 3, "2 semanas, 1 día y 1 hora")] [InlineData(1299630020, 3, "2 semanas, 1 día y 1 hora")] [InlineData(1299630020, 4, "2 semanas, 1 día, 1 hora y 30 segundos")] [InlineData(1299630020, 5, "2 semanas, 1 día, 1 hora, 30 segundos y 20 milisegundos")] public void TimeSpanWithPrecisionAndAlternativeCollectionFormatter(int milliseconds, int precision, string expected, bool toWords = false) { var actual = TimeSpan.FromMilliseconds(milliseconds).Humanize(precision, collectionSeparator: null, toWords: toWords); Assert.Equal(expected, actual); } [Theory] [InlineData(0, 3, "nada")] [InlineData(0, 2, "nada")] [InlineData(10, 2, "diez milisegundos")] [InlineData(1400, 2, "un segundo, cuatrocientos milisegundos")] [InlineData(2500, 2, "dos segundos, quinientos milisegundos")] [InlineData(120000, 2, "dos minutos")] [InlineData(62000, 2, "un minuto, dos segundos")] [InlineData(62020, 2, "un minuto, dos segundos")] [InlineData(62020, 3, "un minuto, dos segundos, veinte milisegundos")] [InlineData(3600020, 4, "una hora, veinte milisegundos")] [InlineData(3600020, 3, "una hora, veinte milisegundos")] [InlineData(3600020, 2, "una hora, veinte milisegundos")] [InlineData(3600020, 1, "una hora")] [InlineData(3603001, 2, "una hora, tres segundos")] [InlineData(3603001, 3, "una hora, tres segundos, un milisegundo")] [InlineData(86400000, 3, "un día")] [InlineData(86400000, 2, "un día")] [InlineData(86400000, 1, "un día")] [InlineData(86401000, 1, "un día")] [InlineData(86401000, 2, "un día, un segundo")] [InlineData(86401200, 2, "un día, un segundo")] [InlineData(86401200, 3, "un día, un segundo, doscientos milisegundos")] [InlineData(1296000000, 1, "dos semanas")] [InlineData(1296000000, 2, "dos semanas, un día")] [InlineData(1299600000, 2, "dos semanas, un día")] [InlineData(1299600000, 3, "dos semanas, un día, una hora")] [InlineData(1299630020, 3, "dos semanas, un día, una hora")] [InlineData(1299630020, 4, "dos semanas, un día, una hora, treinta segundos")] [InlineData(1299630020, 5, "dos semanas, un día, una hora, treinta segundos, veinte milisegundos")] public void TimeSpanWithNumbersConvertedToWords(int milliseconds, int precision, string expected) { var actual = TimeSpan.FromMilliseconds(milliseconds).Humanize(precision, toWords: true); Assert.Equal(expected, actual); } } ================================================ FILE: tests/Humanizer.Tests/Localisation/es/TimeToClockNotationTests.cs ================================================ #if NET6_0_OR_GREATER namespace es; [UseCulture("es-ES")] public class TimeToClockNotationTests { [Theory] [InlineData(0, 0, "medianoche")] [InlineData(0, 7, "las doce y siete de la noche")] [InlineData(1, 11, "la una y once de la madrugada")] [InlineData(4, 0, "las cuatro de la madrugada")] [InlineData(5, 1, "las cinco y uno de la madrugada")] [InlineData(6, 0, "las seis de la mañana")] [InlineData(6, 5, "las seis y cinco de la mañana")] [InlineData(7, 10, "las siete y diez de la mañana")] [InlineData(8, 15, "las ocho y cuarto de la mañana")] [InlineData(9, 20, "las nueve y veinte de la mañana")] [InlineData(10, 25, "las diez y veinticinco de la mañana")] [InlineData(11, 30, "las once y media de la mañana")] [InlineData(12, 00, "mediodía")] [InlineData(12, 38, "las doce y treinta y ocho de la tarde")] [InlineData(12, 35, "la una menos veinticinco de la tarde")] [InlineData(15, 40, "las cuatro menos veinte de la tarde")] [InlineData(17, 45, "las seis menos cuarto de la tarde")] [InlineData(19, 50, "las ocho menos diez de la tarde")] [InlineData(21, 0, "las nueve de la noche")] [InlineData(21, 55, "las diez menos cinco de la noche")] [InlineData(22, 59, "las diez y cincuenta y nueve de la noche")] [InlineData(23, 43, "las once y cuarenta y tres de la noche")] public void ConvertToClockNotationTimeOnlyString(int hours, int minutes, string expectedResult) { var actualResult = new TimeOnly(hours, minutes).ToClockNotation(); Assert.Equal(expectedResult, actualResult); } [Theory] [InlineData(0, 0, "medianoche")] [InlineData(0, 7, "las doce y cinco de la noche")] [InlineData(1, 11, "la una y diez de la madrugada")] [InlineData(4, 0, "las cuatro de la madrugada")] [InlineData(5, 1, "las cinco de la madrugada")] [InlineData(6, 0, "las seis de la mañana")] [InlineData(6, 5, "las seis y cinco de la mañana")] [InlineData(7, 10, "las siete y diez de la mañana")] [InlineData(8, 15, "las ocho y cuarto de la mañana")] [InlineData(9, 20, "las nueve y veinte de la mañana")] [InlineData(10, 25, "las diez y veinticinco de la mañana")] [InlineData(11, 30, "las once y media de la mañana")] [InlineData(12, 00, "mediodía")] [InlineData(12, 38, "la una menos veinte de la tarde")] [InlineData(12, 35, "la una menos veinticinco de la tarde")] [InlineData(15, 40, "las cuatro menos veinte de la tarde")] [InlineData(17, 45, "las seis menos cuarto de la tarde")] [InlineData(19, 50, "las ocho menos diez de la tarde")] [InlineData(21, 0, "las nueve de la noche")] [InlineData(21, 55, "las diez menos cinco de la noche")] [InlineData(22, 59, "las once de la noche")] [InlineData(23, 43, "las doce menos cuarto de la noche")] public void ConvertToRoundedClockNotationTimeOnlyString(int hours, int minutes, string expectedResult) { var actualResult = new TimeOnly(hours, minutes).ToClockNotation(ClockNotationRounding.NearestFiveMinutes); Assert.Equal(expectedResult, actualResult); } } #endif ================================================ FILE: tests/Humanizer.Tests/Localisation/fa/DateHumanizeTests.cs ================================================ namespace fa; [UseCulture("fa")] public class DateHumanizeTests { [Theory] [InlineData(1, "فردا")] [InlineData(13, "13 روز بعد")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(-1, "دیروز")] [InlineData(-11, "11 روز پیش")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "یک ساعت بعد")] [InlineData(11, "11 ساعت بعد")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(-1, "یک ساعت پیش")] [InlineData(-11, "11 ساعت پیش")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "یک دقیقه بعد")] [InlineData(13, "13 دقیقه بعد")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(-1, "یک دقیقه پیش")] [InlineData(-13, "13 دقیقه پیش")] [InlineData(60, "یک ساعت پیش")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "یک ماه بعد")] [InlineData(10, "10 ماه بعد")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(-1, "یک ماه پیش")] [InlineData(-10, "10 ماه پیش")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "یک ثانیه بعد")] [InlineData(11, "11 ثانیه بعد")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(-1, "یک ثانیه پیش")] [InlineData(-11, "11 ثانیه پیش")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "یک سال بعد")] [InlineData(21, "21 سال بعد")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Theory] [InlineData(-1, "یک سال پیش")] [InlineData(-21, "21 سال پیش")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); } ================================================ FILE: tests/Humanizer.Tests/Localisation/fa/NumberToWordsTests.cs ================================================ namespace fa; [UseCulture("fa")] public class NumberToWordsTests { [Theory] [InlineData(1, "یک")] [InlineData(10, "ده")] [InlineData(11, "یازده")] [InlineData(122, "صد و بیست و دو")] [InlineData(3501, "سه هزار و پانصد و یک")] [InlineData(100, "صد")] [InlineData(1000, "یک هزار")] [InlineData(100000, "صد هزار")] [InlineData(1000000, "یک میلیون")] [InlineData(10000000, "ده میلیون")] [InlineData(100000000, "صد میلیون")] [InlineData(1000000000, "یک میلیارد")] [InlineData(1000000000000, "یک بیلیون")] [InlineData(1000000000000000, "یک بیلیارد")] [InlineData(1000000000000000000, "یک تریلیون")] [InlineData(111, "صد و یازده")] [InlineData(1111, "یک هزار و صد و یازده")] [InlineData(111111, "صد و یازده هزار و صد و یازده")] [InlineData(1111111, "یک میلیون و صد و یازده هزار و صد و یازده")] [InlineData(11111111, "یازده میلیون و صد و یازده هزار و صد و یازده")] [InlineData(111111111, "صد و یازده میلیون و صد و یازده هزار و صد و یازده")] [InlineData(1111111111, "یک میلیارد و صد و یازده میلیون و صد و یازده هزار و صد و یازده")] [InlineData(123, "صد و بیست و سه")] [InlineData(1234, "یک هزار و دویست و سی و چهار")] [InlineData(12345, "دوازده هزار و سیصد و چهل و پنج")] [InlineData(123456, "صد و بیست و سه هزار و چهارصد و پنجاه و شش")] [InlineData(1234567, "یک میلیون و دویست و سی و چهار هزار و پانصد و شصت و هفت")] [InlineData(12345678, "دوازده میلیون و سیصد و چهل و پنج هزار و ششصد و هفتاد و هشت")] [InlineData(123456789, "صد و بیست و سه میلیون و چهارصد و پنجاه و شش هزار و هفتصد و هشتاد و نه")] [InlineData(1234567890, "یک میلیارد و دویست و سی و چهار میلیون و پانصد و شصت و هفت هزار و هشتصد و نود")] [InlineData(long.MaxValue, "نه تریلیون و دویست و بیست و سه بیلیارد و سیصد و هفتاد و دو بیلیون و سی و شش میلیارد و هشتصد و پنجاه و چهار میلیون و هفتصد و هفتاد و پنج هزار و هشتصد و هفت")] public void ToWordsFarsi(long number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(0, "صفرم")] [InlineData(1, "اول")] [InlineData(2, "دوم")] [InlineData(3, "سوم")] [InlineData(4, "چهارم")] [InlineData(5, "پنجم")] [InlineData(6, "ششم")] [InlineData(7, "هفتم")] [InlineData(8, "هشتم")] [InlineData(9, "نهم")] [InlineData(10, "دهم")] [InlineData(11, "یازدهم")] [InlineData(12, "دوازدهم")] [InlineData(13, "سیزدهم")] [InlineData(21, "بیست و یکم")] [InlineData(22, "بیست و دوم")] [InlineData(23, "بیست و سوم")] [InlineData(24, "بیست و چهارم")] [InlineData(25, "بیست و پنجم")] [InlineData(30, "سی ام")] [InlineData(40, "چهلم")] [InlineData(50, "پنجاهم")] [InlineData(60, "شصتم")] [InlineData(70, "هفتادم")] [InlineData(80, "هشتادم")] [InlineData(90, "نودم")] [InlineData(100, "صدم")] [InlineData(200, "دویستم")] [InlineData(1000, "یک هزارم")] [InlineData(1333, "یک هزار و سیصد و سی و سوم")] [InlineData(1000000, "یک میلیونم")] public void ToOrdinalWords(int number, string words) => Assert.Equal(words, number.ToOrdinalWords()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/fa/TimeSpanHumanizeTests.cs ================================================ namespace fa; [UseCulture("fa")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Native speaker")] [InlineData(366, "یک سال")] [InlineData(731, "2 سال")] [InlineData(1096, "3 سال")] [InlineData(4018, "11 سال")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Native speaker")] [InlineData(31, "یک ماه")] [InlineData(61, "2 ماه")] [InlineData(92, "3 ماه")] [InlineData(335, "11 ماه")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(7, "یک هفته")] [InlineData(77, "11 هفته")] public void Weeks(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "یک روز")] [InlineData(3, "3 روز")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "یک ساعت")] [InlineData(11, "11 ساعت")] public void Hours(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); [Theory] [InlineData(1, "یک دقیقه")] [InlineData(11, "11 دقیقه")] public void Minutes(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); [Theory] [InlineData(1, "یک ثانیه")] [InlineData(11, "11 ثانیه")] public void Seconds(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); [Theory] [InlineData(1, "یک میلی ثانیه")] [InlineData(11, "11 میلی ثانیه")] public void Milliseconds(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); [Fact] public void NoTime() => Assert.Equal("0 میلی ثانیه", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => Assert.Equal("الآن", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/fi-FI/DateHumanizeTests.cs ================================================ namespace fiFI; [UseCulture("fi-FI")] public class DateHumanizeTests { [Theory] [InlineData(2, "2 päivää sitten")] [InlineData(1, "eilen")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(2, "2 tuntia sitten")] [InlineData(1, "tunti sitten")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(2, "2 minuuttia sitten")] [InlineData(1, "minuutti sitten")] [InlineData(60, "tunti sitten")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(2, "2 kuukautta sitten")] [InlineData(1, "kuukausi sitten")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(2, "2 sekuntia sitten")] [InlineData(1, "sekuntti sitten")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(2, "2 vuotta sitten")] [InlineData(1, "vuosi sitten")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); } ================================================ FILE: tests/Humanizer.Tests/Localisation/fi-FI/NumberToWordsTests.cs ================================================ namespace fiFI; [UseCulture("fi-FI")] public class NumberToWordsTests { [Theory] [InlineData(0, "nolla")] [InlineData(1, "yksi")] [InlineData(11, "yksitoista")] [InlineData(15, "viisitoista")] [InlineData(19, "yhdeksäntoista")] [InlineData(20, "kaksikymmentä")] [InlineData(25, "kaksikymmentäviisi")] [InlineData(50, "viisikymmentä")] [InlineData(90, "yhdeksänkymmentä")] [InlineData(100, "sata")] [InlineData(101, "satayksi")] [InlineData(345, "kolmesataaneljäkymmentäviisi")] [InlineData(678, "kuusisataaseitsemänkymmentäkahdeksan")] [InlineData(1000, "tuhat")] [InlineData(1001, "tuhat yksi")] [InlineData(1234, "tuhat kaksisataakolmekymmentäneljä")] [InlineData(4567, "neljätuhatta viisisataakuusikymmentäseitsemän")] [InlineData(10000, "kymmenentuhatta")] [InlineData(100000, "satatuhatta")] [InlineData(1000000, "miljoona")] [InlineData(10000000, "kymmenenmiljoonaa")] [InlineData(100000000, "satamiljoonaa")] [InlineData(1000000000, "miljardi")] [InlineData(2147483647, "kaksimiljardia sataneljäkymmentäseitsemänmiljoonaa neljäsataakahdeksankymmentäkolmetuhatta kuusisataaneljäkymmentäseitsemän")] // int.MaxValue [InlineData(-2147483647, "miinus kaksimiljardia sataneljäkymmentäseitsemänmiljoonaa neljäsataakahdeksankymmentäkolmetuhatta kuusisataaneljäkymmentäseitsemän")] // int.MinValue + 1 public void ToWords(int number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(0, "nollas")] [InlineData(1, "ensimmäinen")] [InlineData(2, "toinen")] [InlineData(10, "kymmenes")] [InlineData(11, "yhdestoista")] [InlineData(12, "kahdestoista")] [InlineData(19, "yhdeksästoista")] [InlineData(20, "kahdeskymmenes")] [InlineData(21, "kahdeskymmenesensimmäinen")] [InlineData(22, "kahdeskymmenestoinen")] [InlineData(28, "kahdeskymmeneskahdeksas")] [InlineData(75, "seitsemäskymmenesviides")] [InlineData(100, "sadas")] [InlineData(101, "sadasensimmäinen")] [InlineData(111, "sadasyhdestoista")] [InlineData(1000, "tuhannes")] [InlineData(1101, "tuhannessadasensimmäinen")] [InlineData(10000, "kymmenestuhannes")] [InlineData(100000, "sadastuhannes")] [InlineData(1000000, "miljoonas")] [InlineData(10000000, "kymmenesmiljoonas")] [InlineData(100000000, "sadasmiljoonas")] [InlineData(1000000000, "miljardis")] [InlineData(1000000001, "miljardisensimmäinen")] [InlineData(2147483647, "kahdesmiljardissadasneljäskymmenesseitsemäsmiljoonasneljässadaskahdeksaskymmeneskolmastuhanneskuudessadasneljäskymmenesseitsemäs")] // int.MaxValue public void ToOrdinalWords(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/fil-PH/TimeSpanHumanizeTests.cs ================================================ namespace filPH; [UseCulture("fil-PH")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google Translate")] [InlineData(366, "1 taon")] [InlineData(731, "2 taon")] [InlineData(1096, "3 taon")] [InlineData(4018, "11 taon")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google Translate")] [InlineData(31, "1 buwan")] [InlineData(61, "2 buwan")] [InlineData(92, "3 buwan")] [InlineData(335, "11 buwan")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google Translate")] [InlineData(7, "1 linggo")] [InlineData(14, "2 linggo")] [InlineData(21, "3 linggo")] [InlineData(77, "11 linggo")] public void Weeks(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [Trait("Translation", "Google Translate")] [InlineData(1, "1 araw")] [InlineData(2, "2 araw")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [Trait("Translation", "Google Translate")] [InlineData(1, "1 oras")] [InlineData(2, "2 oras")] public void Hours(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); [Theory] [Trait("Translation", "Google Translate")] [InlineData(1, "1 minuto")] [InlineData(2, "2 minuto")] public void Minutes(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); [Theory] [Trait("Translation", "Google Translate")] [InlineData(1, "1 segundo")] [InlineData(2, "2 segundo")] public void Seconds(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); [Theory] [Trait("Translation", "Google Translate")] [InlineData(1, "1 millisecond")] [InlineData(2, "2 milliseconds")] public void Milliseconds(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); [Fact] public void NoTime() => Assert.Equal("0 milliseconds", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => Assert.Equal("walang oras", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/fr/Bytes/ByteSizeExtensionsTests.cs ================================================ namespace fr.Bytes; [UseCulture("fr-FR")] public class ByteSizeExtensionsTests { [Theory] [InlineData(2, null, "2 To")] [InlineData(2, "GB", "2048 Go")] [InlineData(2.123, "#.#", "2,1 To")] public void HumanizesTerabytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Terabytes().Humanize(format)); [Theory] [InlineData(0, null, "0 b")] [InlineData(0, "GB", "0 Go")] [InlineData(2, null, "2 Go")] [InlineData(2, "MB", "2048 Mo")] [InlineData(2.123, "#.##", "2,12 Go")] public void HumanizesGigabytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Gigabytes().Humanize(format)); [Theory] [InlineData(0, null, "0 b")] [InlineData(0, "MB", "0 Mo")] [InlineData(2, null, "2 Mo")] [InlineData(2, "KB", "2048 Ko")] [InlineData(2.123, "#", "2 Mo")] public void HumanizesMegabytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Megabytes().Humanize(format)); [Theory] [InlineData(0, null, "0 b")] [InlineData(0, "KB", "0 Ko")] [InlineData(2, null, "2 Ko")] [InlineData(2, "B", "2048 o")] [InlineData(2.123, "#.####", "2,123 Ko")] public void HumanizesKilobytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Kilobytes().Humanize(format)); [Theory] [InlineData(0, null, "0 b")] [InlineData(0, "#.##", "0 b")] [InlineData(0, "#.## B", "0 o")] [InlineData(0, "B", "0 o")] [InlineData(2, null, "2 o")] [InlineData(2000, "KB", "1,95 Ko")] [InlineData(2123, "#.##", "2,07 Ko")] [InlineData(10000000, "KB", "9765,63 Ko")] [InlineData(10000000, "#,##0 KB", "9 766 Ko")] [InlineData(10000000, "#,##0.# KB", "9 765,6 Ko")] public void HumanizesBytes(double input, string? format, string expectedValue) { expectedValue = expectedValue.Replace(" ", NumberFormatInfo.CurrentInfo.NumberGroupSeparator); Assert.Equal( expectedValue, input .Bytes() .Humanize(format)); } [Theory] [InlineData(0, null, "0 b")] [InlineData(0, "b", "0 b")] [InlineData(2, null, "2 b")] [InlineData(12, "B", "1,5 o")] [InlineData(10000, "#.# KB", "1,2 Ko")] public void HumanizesBits(long input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Bits().Humanize(format)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/fr/Bytes/ToFullWordsTests.cs ================================================ namespace fr.Bytes; [UseCulture("fr-FR")] public class ToFullWordsTests { [Fact] public void ReturnsSingularBit() => Assert.Equal("1 bit", ByteSize.FromBits(1).ToFullWords()); [Fact] public void ReturnsPluralBits() => Assert.Equal("2 bits", ByteSize.FromBits(2).ToFullWords()); [Fact] public void ReturnsSingularByte() => Assert.Equal("1 octet", ByteSize.FromBytes(1).ToFullWords()); [Fact] public void ReturnsPluralBytes() => Assert.Equal("10 octets", ByteSize.FromBytes(10).ToFullWords()); [Fact] public void ReturnsSingularKiloByte() => Assert.Equal("1 kilooctet", ByteSize.FromKilobytes(1).ToFullWords()); [Fact] public void ReturnsPluralKilobytes() => Assert.Equal("10 kilooctets", ByteSize.FromKilobytes(10).ToFullWords()); [Fact] public void ReturnsSingularMegabyte() => Assert.Equal("1 mégaoctet", ByteSize.FromMegabytes(1).ToFullWords()); [Fact] public void ReturnsPluralMegabytes() => Assert.Equal("10 mégaoctets", ByteSize.FromMegabytes(10).ToFullWords()); [Fact] public void ReturnsSingularGigabyte() => Assert.Equal("1 gigaoctet", ByteSize.FromGigabytes(1).ToFullWords()); [Fact] public void ReturnsPluralGigabytes() => Assert.Equal("10 gigaoctets", ByteSize.FromGigabytes(10).ToFullWords()); [Fact] public void ReturnsSingularTerabyte() => Assert.Equal("1 téraoctet", ByteSize.FromTerabytes(1).ToFullWords()); [Fact] public void ReturnsPluralTerabytes() => Assert.Equal("10 téraoctets", ByteSize.FromTerabytes(10).ToFullWords()); [Theory] [InlineData(229376, "B", "229376 octets")] [InlineData(229376, "# KB", "224 kilooctets")] public void ToFullWordsFormatted(double input, string format, string expectedValue) => Assert.Equal(expectedValue, ByteSize.FromBytes(input).ToFullWords(format)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/fr/Bytes/ToStringTests.cs ================================================ namespace fr.Bytes; [UseCulture("fr-FR")] public class ToStringTests { [Fact] public void ReturnsLargestMetricSuffix() => Assert.Equal("10,5 Ko", ByteSize.FromKilobytes(10.5).ToString()); [Fact] public void ReturnsDefaultNumberFormat() => Assert.Equal("10,5 Ko", ByteSize.FromKilobytes(10.5).ToString("KB")); [Fact] public void ReturnsProvidedNumberFormat() => Assert.Equal("10,1234 Ko", ByteSize.FromKilobytes(10.1234).ToString("#.#### KB")); [Fact] public void ReturnsBits() => Assert.Equal("10 b", ByteSize.FromBits(10).ToString("##.#### b")); [Fact] public void ReturnsBytes() => Assert.Equal("10 o", ByteSize.FromBytes(10).ToString("##.#### B")); [Fact] public void ReturnsKilobytes() => Assert.Equal("10 Ko", ByteSize.FromKilobytes(10).ToString("##.#### KB")); [Fact] public void ReturnsMegabytes() => Assert.Equal("10 Mo", ByteSize.FromMegabytes(10).ToString("##.#### MB")); [Fact] public void ReturnsGigabytes() => Assert.Equal("10 Go", ByteSize.FromGigabytes(10).ToString("##.#### GB")); [Fact] public void ReturnsTerabytes() => Assert.Equal("10 To", ByteSize.FromTerabytes(10).ToString("##.#### TB")); [Fact] public void ReturnsSelectedFormat() => Assert.Equal("10,0 To", ByteSize.FromTerabytes(10).ToString("0.0 TB")); [Fact] public void ReturnsLargestMetricPrefixLargerThanZero() => Assert.Equal("512 Ko", ByteSize.FromMegabytes(.5).ToString("#.#")); [Fact] public void ReturnsLargestMetricPrefixLargerThanZeroForNegativeValues() => Assert.Equal("-512 Ko", ByteSize.FromMegabytes(-.5).ToString("#.#")); [Fact] public void ReturnsBytesViaGeneralFormat() => Assert.Equal("10 o", $"{ByteSize.FromBytes(10)}"); } ================================================ FILE: tests/Humanizer.Tests/Localisation/fr/DateHumanizeTests.cs ================================================ namespace fr; [UseCulture("fr")] public class DateHumanizeTests { [Theory] [InlineData(1, "il y a une seconde")] [InlineData(2, "il y a 2 secondes")] [InlineData(10, "il y a 10 secondes")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "dans une seconde")] [InlineData(2, "dans 2 secondes")] [InlineData(10, "dans 10 secondes")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(1, "il y a une minute")] [InlineData(2, "il y a 2 minutes")] [InlineData(10, "il y a 10 minutes")] [InlineData(60, "il y a une heure")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "dans une minute")] [InlineData(2, "dans 2 minutes")] [InlineData(10, "dans 10 minutes")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(1, "il y a une heure")] [InlineData(2, "il y a 2 heures")] [InlineData(10, "il y a 10 heures")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "dans une heure")] [InlineData(2, "dans 2 heures")] [InlineData(10, "dans 10 heures")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(1, "hier")] [InlineData(2, "avant-hier")] [InlineData(10, "il y a 10 jours")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "demain")] [InlineData(2, "après-demain")] [InlineData(10, "dans 10 jours")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(1, "il y a un mois")] [InlineData(2, "il y a 2 mois")] [InlineData(10, "il y a 10 mois")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "dans un mois")] [InlineData(2, "dans 2 mois")] [InlineData(10, "dans 10 mois")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(1, "il y a un an")] [InlineData(2, "il y a 2 ans")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "dans un an")] [InlineData(2, "dans 2 ans")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/fr/DateToOrdinalWordsTests.cs ================================================ namespace fr; [UseCulture("fr")] public class DateToOrdinalWordsTests { [Fact] public void OrdinalizeString() { Assert.Equal("1er janvier 2015", new DateTime(2015, 1, 1).ToOrdinalWords()); Assert.Equal("2 mars 2020", new DateTime(2020, 3, 2).ToOrdinalWords()); Assert.Equal("31 octobre 2021", new DateTime(2021, 10, 31).ToOrdinalWords()); } #if NET6_0_OR_GREATER [Fact] public void OrdinalizeDateOnlyString() { Assert.Equal("1er janvier 2015", new DateOnly(2015, 1, 1).ToOrdinalWords()); Assert.Equal("2 mars 2020", new DateOnly(2020, 3, 2).ToOrdinalWords()); Assert.Equal("31 octobre 2021", new DateOnly(2021, 10, 31).ToOrdinalWords()); } #endif } ================================================ FILE: tests/Humanizer.Tests/Localisation/fr/NumberToWordsTests.cs ================================================ namespace fr; [UseCulture("fr-FR")] public class NumberToWordsTests { [Theory] [InlineData(0, "zéro")] [InlineData(1, "un")] [InlineData(10, "dix")] [InlineData(11, "onze")] [InlineData(15, "quinze")] [InlineData(17, "dix-sept")] [InlineData(25, "vingt-cinq")] [InlineData(31, "trente et un")] [InlineData(70, "soixante-dix")] [InlineData(71, "soixante et onze")] [InlineData(80, "quatre-vingts")] [InlineData(81, "quatre-vingt-un")] [InlineData(90, "quatre-vingt-dix")] [InlineData(91, "quatre-vingt-onze")] [InlineData(122, "cent vingt-deux")] [InlineData(3501, "trois mille cinq cent un")] [InlineData(100, "cent")] [InlineData(1000, "mille")] [InlineData(100000, "cent mille")] [InlineData(1000000, "un million")] [InlineData(10000000, "dix millions")] [InlineData(100000000, "cent millions")] [InlineData(1000000000, "un milliard")] [InlineData(111, "cent onze")] [InlineData(1111, "mille cent onze")] [InlineData(111111, "cent onze mille cent onze")] [InlineData(1111111, "un million cent onze mille cent onze")] [InlineData(11111111, "onze millions cent onze mille cent onze")] [InlineData(111111111, "cent onze millions cent onze mille cent onze")] [InlineData(1111111111, "un milliard cent onze millions cent onze mille cent onze")] [InlineData(123, "cent vingt-trois")] [InlineData(1234, "mille deux cent trente-quatre")] [InlineData(12345, "douze mille trois cent quarante-cinq")] [InlineData(123456, "cent vingt-trois mille quatre cent cinquante-six")] [InlineData(1234567, "un million deux cent trente-quatre mille cinq cent soixante-sept")] [InlineData(12345678, "douze millions trois cent quarante-cinq mille six cent soixante-dix-huit")] [InlineData(123456789, "cent vingt-trois millions quatre cent cinquante-six mille sept cent quatre-vingt-neuf")] [InlineData(1234567890, "un milliard deux cent trente-quatre millions cinq cent soixante-sept mille huit cent quatre-vingt-dix")] [InlineData(1234567899, "un milliard deux cent trente-quatre millions cinq cent soixante-sept mille huit cent quatre-vingt-dix-neuf")] [InlineData(223, "deux cent vingt-trois")] [InlineData(2234, "deux mille deux cent trente-quatre")] [InlineData(22345, "vingt-deux mille trois cent quarante-cinq")] [InlineData(223456, "deux cent vingt-trois mille quatre cent cinquante-six")] [InlineData(2234567, "deux millions deux cent trente-quatre mille cinq cent soixante-sept")] [InlineData(22345678, "vingt-deux millions trois cent quarante-cinq mille six cent soixante-dix-huit")] [InlineData(223456789, "deux cent vingt-trois millions quatre cent cinquante-six mille sept cent quatre-vingt-neuf")] [InlineData(2147483646, "deux milliards cent quarante-sept millions quatre cent quatre-vingt-trois mille six cent quarante-six")] [InlineData(1999, "mille neuf cent quatre-vingt-dix-neuf")] [InlineData(2014, "deux mille quatorze")] [InlineData(2048, "deux mille quarante-huit")] [InlineData(400, "quatre cents")] [InlineData(401, "quatre cent un")] [InlineData(480, "quatre cent quatre-vingts")] [InlineData(80000, "quatre-vingt mille")] [InlineData(80000000, "quatre-vingts millions")] [InlineData(80080080, "quatre-vingts millions quatre-vingt mille quatre-vingts")] [InlineData(200200200, "deux cents millions deux cent mille deux cents")] [InlineData(200200202, "deux cents millions deux cent mille deux cent deux")] public void ToWordsInt(int number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(1, "une", GrammaticalGender.Feminine)] [InlineData(1, "un", GrammaticalGender.Masculine)] [InlineData(2, "deux", GrammaticalGender.Feminine)] [InlineData(2, "deux", GrammaticalGender.Masculine)] [InlineData(11, "onze", GrammaticalGender.Feminine)] [InlineData(11, "onze", GrammaticalGender.Masculine)] [InlineData(21, "vingt et une", GrammaticalGender.Feminine)] [InlineData(21, "vingt et un", GrammaticalGender.Masculine)] [InlineData(31, "trente et une", GrammaticalGender.Feminine)] [InlineData(31, "trente et un", GrammaticalGender.Masculine)] [InlineData(41, "quarante et une", GrammaticalGender.Feminine)] [InlineData(41, "quarante et un", GrammaticalGender.Masculine)] [InlineData(51, "cinquante et une", GrammaticalGender.Feminine)] [InlineData(51, "cinquante et un", GrammaticalGender.Masculine)] [InlineData(61, "soixante et une", GrammaticalGender.Feminine)] [InlineData(61, "soixante et un", GrammaticalGender.Masculine)] [InlineData(71, "soixante et onze", GrammaticalGender.Feminine)] [InlineData(71, "soixante et onze", GrammaticalGender.Masculine)] [InlineData(81, "quatre-vingt-une", GrammaticalGender.Feminine)] [InlineData(81, "quatre-vingt-un", GrammaticalGender.Masculine)] [InlineData(91, "quatre-vingt-onze", GrammaticalGender.Feminine)] [InlineData(91, "quatre-vingt-onze", GrammaticalGender.Masculine)] [InlineData(121, "cent vingt et une", GrammaticalGender.Feminine)] [InlineData(121, "cent vingt et un", GrammaticalGender.Masculine)] [InlineData(10121, "dix mille cent vingt et une", GrammaticalGender.Feminine)] [InlineData(10121, "dix mille cent vingt et un", GrammaticalGender.Masculine)] [InlineData(81000, "quatre-vingt-un mille", GrammaticalGender.Feminine)] [InlineData(81000, "quatre-vingt-un mille", GrammaticalGender.Masculine)] public void ToWordsIntWithGender(int number, string expected, GrammaticalGender gender) => Assert.Equal(expected, number.ToWords(gender)); [Theory] [InlineData(1L, "un")] [InlineData(11L, "onze")] [InlineData(111L, "cent onze")] [InlineData(1111L, "mille cent onze")] [InlineData(11111L, "onze mille cent onze")] [InlineData(111111L, "cent onze mille cent onze")] [InlineData(1111111L, "un million cent onze mille cent onze")] [InlineData(11111111L, "onze millions cent onze mille cent onze")] [InlineData(111111111L, "cent onze millions cent onze mille cent onze")] [InlineData(1111111111L, "un milliard cent onze millions cent onze mille cent onze")] [InlineData(11111111111L, "onze milliards cent onze millions cent onze mille cent onze")] [InlineData(111111111111L, "cent onze milliards cent onze millions cent onze mille cent onze")] [InlineData(1111111111111L, "un billion cent onze milliards cent onze millions cent onze mille cent onze")] [InlineData(11111111111111L, "onze billions cent onze milliards cent onze millions cent onze mille cent onze")] [InlineData(111111111111111L, "cent onze billions cent onze milliards cent onze millions cent onze mille cent onze")] [InlineData(1111111111111111L, "un billiard cent onze billions cent onze milliards cent onze millions cent onze mille cent onze")] [InlineData(11111111111111111L, "onze billiards cent onze billions cent onze milliards cent onze millions cent onze mille cent onze")] [InlineData(111111111111111111L, "cent onze billiards cent onze billions cent onze milliards cent onze millions cent onze mille cent onze")] [InlineData(1111111111111111111L, "un trillion cent onze billiards cent onze billions cent onze milliards cent onze millions cent onze mille cent onze")] public void ToWordsLong(long number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(0, "zérotième")] [InlineData(1, "premier")] [InlineData(2, "deuxième")] [InlineData(3, "troisième")] [InlineData(4, "quatrième")] [InlineData(5, "cinquième")] [InlineData(6, "sixième")] [InlineData(7, "septième")] [InlineData(8, "huitième")] [InlineData(9, "neuvième")] [InlineData(10, "dixième")] [InlineData(11, "onzième")] [InlineData(12, "douzième")] [InlineData(13, "treizième")] [InlineData(14, "quatorzième")] [InlineData(15, "quinzième")] [InlineData(16, "seizième")] [InlineData(17, "dix-septième")] [InlineData(18, "dix-huitième")] [InlineData(19, "dix-neuvième")] [InlineData(20, "vingtième")] [InlineData(21, "vingt et unième")] [InlineData(22, "vingt-deuxième")] [InlineData(30, "trentième")] [InlineData(40, "quarantième")] [InlineData(50, "cinquantième")] [InlineData(60, "soixantième")] [InlineData(70, "soixante-dixième")] [InlineData(80, "quatre-vingtième")] [InlineData(90, "quatre-vingt-dixième")] [InlineData(95, "quatre-vingt-quinzième")] [InlineData(96, "quatre-vingt-seizième")] [InlineData(100, "centième")] [InlineData(120, "cent vingtième")] [InlineData(121, "cent vingt et unième")] [InlineData(1000, "millième")] [InlineData(1001, "mille unième")] [InlineData(1021, "mille vingt et unième")] [InlineData(10000, "dix millième")] [InlineData(10121, "dix mille cent vingt et unième")] [InlineData(100000, "cent millième")] [InlineData(1000000, "millionième")] [InlineData(1000000000, "milliardième")] public void ToOrdinalWords(int number, string words) => Assert.Equal(words, number.ToOrdinalWords()); [Theory] [InlineData(1, "première", GrammaticalGender.Feminine)] [InlineData(1, "premier", GrammaticalGender.Masculine)] [InlineData(2, "deuxième", GrammaticalGender.Feminine)] [InlineData(2, "deuxième", GrammaticalGender.Masculine)] [InlineData(121, "cent vingt et unième", GrammaticalGender.Feminine)] [InlineData(121, "cent vingt et unième", GrammaticalGender.Masculine)] [InlineData(10121, "dix mille cent vingt et unième", GrammaticalGender.Feminine)] [InlineData(10121, "dix mille cent vingt et unième", GrammaticalGender.Masculine)] public void ToOrdinalWordsWithGender(int number, string expected, GrammaticalGender gender) => Assert.Equal(expected, number.ToOrdinalWords(gender)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/fr/OrdinalizeTests.cs ================================================ namespace fr; [UseCulture("fr")] public class OrdinalizeTests { [Theory] [InlineData("0", "0ème")] [InlineData("1", "1er")] [InlineData("2", "2ème")] [InlineData("3", "3ème")] [InlineData("4", "4ème")] [InlineData("5", "5ème")] [InlineData("6", "6ème")] [InlineData("23", "23ème")] [InlineData("100", "100ème")] [InlineData("101", "101ème")] [InlineData("102", "102ème")] [InlineData("103", "103ème")] [InlineData("1001", "1001ème")] public void OrdinalizeString(string number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Masculine), ordinalized); [Theory] [InlineData("0", "0ème")] [InlineData("1", "1ère")] [InlineData("2", "2ème")] [InlineData("3", "3ème")] [InlineData("4", "4ème")] [InlineData("5", "5ème")] [InlineData("6", "6ème")] [InlineData("23", "23ème")] [InlineData("100", "100ème")] [InlineData("101", "101ème")] [InlineData("102", "102ème")] [InlineData("103", "103ème")] [InlineData("1001", "1001ème")] public void OrdinalizeStringFeminine(string number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Feminine), ordinalized); [Theory] [InlineData("0", "0ème")] [InlineData("1", "1er")] [InlineData("2", "2ème")] [InlineData("3", "3ème")] [InlineData("4", "4ème")] [InlineData("5", "5ème")] [InlineData("6", "6ème")] [InlineData("23", "23ème")] [InlineData("100", "100ème")] [InlineData("101", "101ème")] [InlineData("102", "102ème")] [InlineData("103", "103ème")] [InlineData("1001", "1001ème")] public void OrdinalizeStringNeuter(string number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Neuter), ordinalized); [Theory] [InlineData(0, "0ème")] [InlineData(1, "1er")] [InlineData(2, "2ème")] [InlineData(3, "3ème")] [InlineData(4, "4ème")] [InlineData(5, "5ème")] [InlineData(6, "6ème")] [InlineData(10, "10ème")] [InlineData(23, "23ème")] [InlineData(100, "100ème")] [InlineData(101, "101ème")] [InlineData(102, "102ème")] [InlineData(103, "103ème")] [InlineData(1001, "1001ème")] public void OrdinalizeNumber(int number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Masculine), ordinalized); [Theory] [InlineData(0, "0ème")] [InlineData(1, "1ère")] [InlineData(2, "2ème")] [InlineData(3, "3ème")] [InlineData(4, "4ème")] [InlineData(5, "5ème")] [InlineData(6, "6ème")] [InlineData(10, "10ème")] [InlineData(23, "23ème")] [InlineData(100, "100ème")] [InlineData(101, "101ème")] [InlineData(102, "102ème")] [InlineData(103, "103ème")] [InlineData(1001, "1001ème")] public void OrdinalizeNumberFeminine(int number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Feminine), ordinalized); [Theory] [InlineData(0, "0ème")] [InlineData(1, "1er")] [InlineData(2, "2ème")] [InlineData(3, "3ème")] [InlineData(4, "4ème")] [InlineData(5, "5ème")] [InlineData(6, "6ème")] [InlineData(10, "10ème")] [InlineData(23, "23ème")] [InlineData(100, "100ème")] [InlineData(101, "101ème")] [InlineData(102, "102ème")] [InlineData(103, "103ème")] [InlineData(1001, "1001ème")] public void OrdinalizeNumberNeuter(int number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Neuter), ordinalized); } ================================================ FILE: tests/Humanizer.Tests/Localisation/fr/TimeOnlyHumanizeTests.cs ================================================ #if NET6_0_OR_GREATER namespace fr; [UseCulture("fr")] public class TimeOnlyHumanizeTests { [Fact] public void DefaultStrategy_SameTime() { var inputTime = new TimeOnly(13, 07, 05); var baseTime = new TimeOnly(13, 07, 05); const string expectedResult = "maintenant"; var actualResult = inputTime.Humanize(baseTime); Assert.Equal(expectedResult, actualResult); } [Fact] public void DefaultStrategy_HoursApart() { var inputTime = new TimeOnly(3, 08, 05); var baseTime = new TimeOnly(1, 08, 05); const string expectedResult = "dans 2 heures"; var actualResult = inputTime.Humanize(baseTime); Assert.Equal(expectedResult, actualResult); } [Fact] public void DefaultStrategy_HoursAgo() { var inputTime = new TimeOnly(13, 07, 02); var baseTime = new TimeOnly(17, 07, 05); const string expectedResult = "il y a 4 heures"; var actualResult = inputTime.Humanize(baseTime); Assert.Equal(expectedResult, actualResult); } [Fact] public void PrecisionStrategy_NextDay() { var inputTime = new TimeOnly(18, 10, 49); var baseTime = new TimeOnly(13, 07, 04); const string expectedResult = "dans 5 heures"; var actualResult = inputTime.Humanize(baseTime); Assert.Equal(expectedResult, actualResult); } [Fact] public void Never() { TimeOnly? never = null; Assert.Equal("jamais", never.Humanize()); } [Fact] public void Nullable_ExpectSame() { TimeOnly? never = new TimeOnly(23, 12, 7); Assert.Equal(never.Value.Humanize(), never.Humanize()); } } #endif ================================================ FILE: tests/Humanizer.Tests/Localisation/fr/TimeSpanHumanizeTests.cs ================================================ namespace fr; [UseCulture("fr")] public class TimeSpanHumanizeTests { [Theory] [InlineData(366, "1 an")] [InlineData(731, "2 ans")] [InlineData(1096, "3 ans")] [InlineData(4018, "11 ans")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan .FromDays(days) .Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(366, "un an")] [InlineData(731, "deux ans")] [InlineData(1096, "trois ans")] [InlineData(4018, "onze ans")] public void YearsToWord(int days, string expected) => Assert.Equal(expected, TimeSpan .FromDays(days) .Humanize(maxUnit: TimeUnit.Year, toWords: true)); [Theory] [InlineData(31, "1 mois")] [InlineData(61, "2 mois")] [InlineData(92, "3 mois")] [InlineData(335, "11 mois")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan .FromDays(days) .Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(31, "un mois")] [InlineData(61, "deux mois")] [InlineData(92, "trois mois")] [InlineData(335, "onze mois")] public void MonthsToWords(int days, string expected) => Assert.Equal(expected, TimeSpan .FromDays(days) .Humanize(maxUnit: TimeUnit.Year, toWords: true)); [Theory] [InlineData(14, "2 semaines")] [InlineData(7, "1 semaine")] public void Weeks(int days, string expected) { var actual = TimeSpan .FromDays(days) .Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(14, "deux semaines")] [InlineData(7, "une semaine")] public void WeeksToWords(int days, string expected) { var actual = TimeSpan .FromDays(days) .Humanize(toWords: true); Assert.Equal(expected, actual); } [Theory] [InlineData(6, "6 jours")] [InlineData(1, "1 jour")] public void Days(int days, string expected) { var actual = TimeSpan .FromDays(days) .Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(6, "six jours")] [InlineData(1, "un jour")] public void DaysToWords(int days, string expected) { var actual = TimeSpan .FromDays(days) .Humanize(toWords: true); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 heures")] [InlineData(1, "1 heure")] public void Hours(int hours, string expected) { var actual = TimeSpan .FromHours(hours) .Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "deux heures")] [InlineData(1, "une heure")] public void HoursToWords(int hours, string expected) { var actual = TimeSpan .FromHours(hours) .Humanize(toWords: true); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 minutes")] [InlineData(1, "1 minute")] public void Minutes(int minutes, string expected) { var actual = TimeSpan .FromMinutes(minutes) .Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "deux minutes")] [InlineData(1, "une minute")] public void MinutesToWords(int minutes, string expected) { var actual = TimeSpan .FromMinutes(minutes) .Humanize(toWords: true); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 secondes")] [InlineData(1, "1 seconde")] public void Seconds(int seconds, string expected) { var actual = TimeSpan .FromSeconds(seconds) .Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "deux secondes")] [InlineData(1, "une seconde")] public void SecondsToWords(int seconds, string expected) { var actual = TimeSpan .FromSeconds(seconds) .Humanize(toWords: true); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 millisecondes")] [InlineData(1, "1 milliseconde")] public void Milliseconds(int ms, string expected) { var actual = TimeSpan .FromMilliseconds(ms) .Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "deux millisecondes")] [InlineData(1, "une milliseconde")] public void MillisecondsToWords(int ms, string expected) { var actual = TimeSpan .FromMilliseconds(ms) .Humanize(toWords: true); Assert.Equal(expected, actual); } [Theory] [InlineData(4, false, "4 jours")] [InlineData(23, false, "3 semaines")] [InlineData(64, false, "2 mois")] [InlineData(367, true, "un an")] [InlineData(750, true, "deux ans")] public void Age(int days, bool toWords, string expected) { var actual = TimeSpan .FromDays(days) .ToAge(toWords: toWords); Assert.Equal(expected, actual); } [Theory] [InlineData(TimeUnit.Year, "0 an")] [InlineData(TimeUnit.Month, "0 mois")] [InlineData(TimeUnit.Week, "0 semaine")] [InlineData(TimeUnit.Day, "0 jour")] [InlineData(TimeUnit.Hour, "0 heure")] [InlineData(TimeUnit.Minute, "0 minute")] [InlineData(TimeUnit.Second, "0 seconde")] [InlineData(TimeUnit.Millisecond, "0 milliseconde")] public void NoTime(TimeUnit minUnit, string expected) { var noTime = TimeSpan.Zero; var actual = noTime.Humanize(minUnit: minUnit); Assert.Equal(expected, actual); } [Fact] public void NoTimeToWords() { var noTime = TimeSpan.Zero; var actual = noTime.Humanize(toWords: true); Assert.Equal("temps nul", actual); } } ================================================ FILE: tests/Humanizer.Tests/Localisation/fr/TimeToClockNotationTests.cs ================================================ #if NET6_0_OR_GREATER namespace fr; [UseCulture("fr")] public class TimeToClockNotationTests { [Theory] [InlineData(00, 00, "minuit")] [InlineData(00, 07, "minuit sept")] [InlineData(01, 11, "une heure onze")] [InlineData(04, 00, "quatre heures")] [InlineData(05, 01, "cinq heures une")] [InlineData(06, 05, "six heures cinq")] [InlineData(07, 10, "sept heures dix")] [InlineData(08, 15, "huit heures quinze")] [InlineData(09, 20, "neuf heures vingt")] [InlineData(10, 25, "dix heures vingt-cinq")] [InlineData(11, 30, "onze heures trente")] [InlineData(12, 00, "midi")] [InlineData(12, 38, "midi trente-huit")] [InlineData(15, 35, "quinze heures trente-cinq")] [InlineData(16, 40, "seize heures quarante")] [InlineData(17, 45, "dix-sept heures quarante-cinq")] [InlineData(18, 50, "dix-huit heures cinquante")] [InlineData(19, 55, "dix-neuf heures cinquante-cinq")] [InlineData(20, 59, "vingt heures cinquante-neuf")] public void ConvertToClockNotationTimeOnlyString(int hours, int minutes, string expectedResult) { var actualResult = new TimeOnly(hours, minutes).ToClockNotation(); Assert.Equal(expectedResult, actualResult); } [Theory] [InlineData(00, 00, "minuit")] [InlineData(00, 07, "minuit cinq")] [InlineData(01, 11, "une heure dix")] [InlineData(04, 00, "quatre heures")] [InlineData(05, 01, "cinq heures")] [InlineData(06, 05, "six heures cinq")] [InlineData(07, 10, "sept heures dix")] [InlineData(08, 15, "huit heures quinze")] [InlineData(09, 20, "neuf heures vingt")] [InlineData(10, 25, "dix heures vingt-cinq")] [InlineData(11, 30, "onze heures trente")] [InlineData(12, 00, "midi")] [InlineData(12, 38, "midi quarante")] [InlineData(13, 23, "treize heures vingt-cinq")] [InlineData(14, 32, "quatorze heures trente")] [InlineData(15, 35, "quinze heures trente-cinq")] [InlineData(16, 40, "seize heures quarante")] [InlineData(17, 45, "dix-sept heures quarante-cinq")] [InlineData(18, 50, "dix-huit heures cinquante")] [InlineData(19, 55, "dix-neuf heures cinquante-cinq")] [InlineData(20, 59, "vingt et une heures")] public void ConvertToRoundedClockNotationTimeOnlyString(int hours, int minutes, string expectedResult) { var actualResult = new TimeOnly(hours, minutes).ToClockNotation(ClockNotationRounding.NearestFiveMinutes); Assert.Equal(expectedResult, actualResult); } } #endif ================================================ FILE: tests/Humanizer.Tests/Localisation/fr/TimeUnitToSymbolTests.cs ================================================ namespace fr; [UseCulture("fr")] public class TimeUnitToSymbolTests { [Theory] [Trait("Translation", "Native speaker")] [InlineData(TimeUnit.Millisecond, "ms")] [InlineData(TimeUnit.Second, "s")] [InlineData(TimeUnit.Minute, "min")] [InlineData(TimeUnit.Hour, "h")] [InlineData(TimeUnit.Day, "j")] [InlineData(TimeUnit.Week, "semaine")] [InlineData(TimeUnit.Month, "mois")] [InlineData(TimeUnit.Year, "a")] public void ToSymbol(TimeUnit unit, string expected) => Assert.Equal(expected, unit.ToSymbol()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/fr-BE/DateHumanizeTests.cs ================================================ namespace frBE; [UseCulture("fr-BE")] public class DateHumanizeTests { [Theory] [InlineData(1, "il y a une seconde")] [InlineData(2, "il y a 2 secondes")] [InlineData(10, "il y a 10 secondes")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "dans une seconde")] [InlineData(2, "dans 2 secondes")] [InlineData(10, "dans 10 secondes")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(1, "il y a une minute")] [InlineData(2, "il y a 2 minutes")] [InlineData(10, "il y a 10 minutes")] [InlineData(60, "il y a une heure")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "dans une minute")] [InlineData(2, "dans 2 minutes")] [InlineData(10, "dans 10 minutes")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(1, "il y a une heure")] [InlineData(2, "il y a 2 heures")] [InlineData(10, "il y a 10 heures")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "dans une heure")] [InlineData(2, "dans 2 heures")] [InlineData(10, "dans 10 heures")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(1, "hier")] [InlineData(2, "avant-hier")] [InlineData(10, "il y a 10 jours")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "demain")] [InlineData(2, "après-demain")] [InlineData(10, "dans 10 jours")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(1, "il y a un mois")] [InlineData(2, "il y a 2 mois")] [InlineData(10, "il y a 10 mois")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "dans un mois")] [InlineData(2, "dans 2 mois")] [InlineData(10, "dans 10 mois")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(1, "il y a un an")] [InlineData(2, "il y a 2 ans")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "dans un an")] [InlineData(2, "dans 2 ans")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/fr-BE/NumberToWordsTests.cs ================================================ namespace frBE; [UseCulture("fr-BE")] public class NumberToWordsTests { [Theory] [InlineData(0, "zéro")] [InlineData(1, "un")] [InlineData(10, "dix")] [InlineData(11, "onze")] [InlineData(15, "quinze")] [InlineData(17, "dix-sept")] [InlineData(25, "vingt-cinq")] [InlineData(31, "trente et un")] [InlineData(71, "septante et un")] [InlineData(80, "quatre-vingts")] [InlineData(81, "quatre-vingt-un")] [InlineData(122, "cent vingt-deux")] [InlineData(3501, "trois mille cinq cent un")] [InlineData(100, "cent")] [InlineData(1000, "mille")] [InlineData(100000, "cent mille")] [InlineData(1000000, "un million")] [InlineData(10000000, "dix millions")] [InlineData(100000000, "cent millions")] [InlineData(200000000, "deux cents millions")] [InlineData(1000000000, "un milliard")] [InlineData(111, "cent onze")] [InlineData(1111, "mille cent onze")] [InlineData(111111, "cent onze mille cent onze")] [InlineData(1111111, "un million cent onze mille cent onze")] [InlineData(11111111, "onze millions cent onze mille cent onze")] [InlineData(111111111, "cent onze millions cent onze mille cent onze")] [InlineData(1111111111, "un milliard cent onze millions cent onze mille cent onze")] [InlineData(123, "cent vingt-trois")] [InlineData(1234, "mille deux cent trente-quatre")] [InlineData(12345, "douze mille trois cent quarante-cinq")] [InlineData(123456, "cent vingt-trois mille quatre cent cinquante-six")] [InlineData(1234567, "un million deux cent trente-quatre mille cinq cent soixante-sept")] [InlineData(12345678, "douze millions trois cent quarante-cinq mille six cent septante-huit")] [InlineData(123456789, "cent vingt-trois millions quatre cent cinquante-six mille sept cent quatre-vingt-neuf")] [InlineData(1234567890, "un milliard deux cent trente-quatre millions cinq cent soixante-sept mille huit cent nonante")] [InlineData(1234567899, "un milliard deux cent trente-quatre millions cinq cent soixante-sept mille huit cent nonante-neuf")] [InlineData(223, "deux cent vingt-trois")] [InlineData(2234, "deux mille deux cent trente-quatre")] [InlineData(22345, "vingt-deux mille trois cent quarante-cinq")] [InlineData(200456, "deux cent mille quatre cent cinquante-six")] [InlineData(223456, "deux cent vingt-trois mille quatre cent cinquante-six")] [InlineData(2234567, "deux millions deux cent trente-quatre mille cinq cent soixante-sept")] [InlineData(22345678, "vingt-deux millions trois cent quarante-cinq mille six cent septante-huit")] [InlineData(223456789, "deux cent vingt-trois millions quatre cent cinquante-six mille sept cent quatre-vingt-neuf")] [InlineData(2147483646, "deux milliards cent quarante-sept millions quatre cent quatre-vingt-trois mille six cent quarante-six")] [InlineData(1999, "mille neuf cent nonante-neuf")] [InlineData(2014, "deux mille quatorze")] [InlineData(2048, "deux mille quarante-huit")] [InlineData(400, "quatre cents")] [InlineData(401, "quatre cent un")] [InlineData(480, "quatre cent quatre-vingts")] [InlineData(80000, "quatre-vingt mille")] [InlineData(80000000, "quatre-vingts millions")] [InlineData(80080080, "quatre-vingts millions quatre-vingt mille quatre-vingts")] [InlineData(200200200, "deux cents millions deux cent mille deux cents")] [InlineData(200200202, "deux cents millions deux cent mille deux cent deux")] public void ToWords(int number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(1, "une", GrammaticalGender.Feminine)] [InlineData(1, "un", GrammaticalGender.Masculine)] [InlineData(2, "deux", GrammaticalGender.Feminine)] [InlineData(2, "deux", GrammaticalGender.Masculine)] [InlineData(11, "onze", GrammaticalGender.Feminine)] [InlineData(11, "onze", GrammaticalGender.Masculine)] [InlineData(21, "vingt et une", GrammaticalGender.Feminine)] [InlineData(21, "vingt et un", GrammaticalGender.Masculine)] [InlineData(31, "trente et une", GrammaticalGender.Feminine)] [InlineData(31, "trente et un", GrammaticalGender.Masculine)] [InlineData(41, "quarante et une", GrammaticalGender.Feminine)] [InlineData(41, "quarante et un", GrammaticalGender.Masculine)] [InlineData(51, "cinquante et une", GrammaticalGender.Feminine)] [InlineData(51, "cinquante et un", GrammaticalGender.Masculine)] [InlineData(61, "soixante et une", GrammaticalGender.Feminine)] [InlineData(61, "soixante et un", GrammaticalGender.Masculine)] [InlineData(71, "septante et une", GrammaticalGender.Feminine)] [InlineData(71, "septante et un", GrammaticalGender.Masculine)] [InlineData(81, "quatre-vingt-une", GrammaticalGender.Feminine)] [InlineData(81, "quatre-vingt-un", GrammaticalGender.Masculine)] [InlineData(91, "nonante et une", GrammaticalGender.Feminine)] [InlineData(91, "nonante et un", GrammaticalGender.Masculine)] [InlineData(121, "cent vingt et une", GrammaticalGender.Feminine)] [InlineData(121, "cent vingt et un", GrammaticalGender.Masculine)] [InlineData(10121, "dix mille cent vingt et une", GrammaticalGender.Feminine)] [InlineData(10121, "dix mille cent vingt et un", GrammaticalGender.Masculine)] public void ToWordsWithGender(int number, string expected, GrammaticalGender gender) => Assert.Equal(expected, number.ToWords(gender)); [Theory] [InlineData(0, "zérotième")] [InlineData(1, "premier")] [InlineData(2, "deuxième")] [InlineData(3, "troisième")] [InlineData(4, "quatrième")] [InlineData(5, "cinquième")] [InlineData(6, "sixième")] [InlineData(7, "septième")] [InlineData(8, "huitième")] [InlineData(9, "neuvième")] [InlineData(10, "dixième")] [InlineData(11, "onzième")] [InlineData(12, "douzième")] [InlineData(13, "treizième")] [InlineData(14, "quatorzième")] [InlineData(15, "quinzième")] [InlineData(16, "seizième")] [InlineData(17, "dix-septième")] [InlineData(18, "dix-huitième")] [InlineData(19, "dix-neuvième")] [InlineData(20, "vingtième")] [InlineData(21, "vingt et unième")] [InlineData(22, "vingt-deuxième")] [InlineData(30, "trentième")] [InlineData(40, "quarantième")] [InlineData(50, "cinquantième")] [InlineData(60, "soixantième")] [InlineData(70, "septantième")] [InlineData(80, "quatre-vingtième")] [InlineData(90, "nonantième")] [InlineData(95, "nonante-cinquième")] [InlineData(96, "nonante-sixième")] [InlineData(100, "centième")] [InlineData(120, "cent vingtième")] [InlineData(121, "cent vingt et unième")] [InlineData(1000, "millième")] [InlineData(1001, "mille unième")] [InlineData(1021, "mille vingt et unième")] [InlineData(10000, "dix millième")] [InlineData(10121, "dix mille cent vingt et unième")] [InlineData(100000, "cent millième")] [InlineData(1000000, "millionième")] [InlineData(1000000000, "milliardième")] public void ToOrdinalWords(int number, string words) => Assert.Equal(words, number.ToOrdinalWords()); [Theory] [InlineData(1, "première", GrammaticalGender.Feminine)] [InlineData(1, "premier", GrammaticalGender.Masculine)] [InlineData(2, "deuxième", GrammaticalGender.Feminine)] [InlineData(2, "deuxième", GrammaticalGender.Masculine)] [InlineData(121, "cent vingt et unième", GrammaticalGender.Feminine)] [InlineData(121, "cent vingt et unième", GrammaticalGender.Masculine)] [InlineData(10121, "dix mille cent vingt et unième", GrammaticalGender.Feminine)] [InlineData(10121, "dix mille cent vingt et unième", GrammaticalGender.Masculine)] public void ToOrdinalWordsWithGender(int number, string expected, GrammaticalGender gender) => Assert.Equal(expected, number.ToOrdinalWords(gender)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/fr-BE/TimeSpanHumanizeTests.cs ================================================ namespace frBE; [UseCulture("fr-BE")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "1 an")] [InlineData(731, "2 ans")] [InlineData(1096, "3 ans")] [InlineData(4018, "11 ans")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "1 mois")] [InlineData(61, "2 mois")] [InlineData(92, "3 mois")] [InlineData(335, "11 mois")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(14, "2 semaines")] [InlineData(7, "1 semaine")] public void Weeks(int days, string expected) { var actual = TimeSpan.FromDays(days).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(6, "6 jours")] [InlineData(1, "1 jour")] public void Days(int days, string expected) { var actual = TimeSpan.FromDays(days).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 heures")] [InlineData(1, "1 heure")] public void Hours(int hours, string expected) { var actual = TimeSpan.FromHours(hours).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 minutes")] [InlineData(1, "1 minute")] public void Minutes(int minutes, string expected) { var actual = TimeSpan.FromMinutes(minutes).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 secondes")] [InlineData(1, "1 seconde")] public void Seconds(int seconds, string expected) { var actual = TimeSpan.FromSeconds(seconds).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 millisecondes")] [InlineData(1, "1 milliseconde")] public void Milliseconds(int ms, string expected) { var actual = TimeSpan.FromMilliseconds(ms).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(TimeUnit.Year, "0 an")] [InlineData(TimeUnit.Month, "0 mois")] [InlineData(TimeUnit.Week, "0 semaine")] [InlineData(TimeUnit.Day, "0 jour")] [InlineData(TimeUnit.Hour, "0 heure")] [InlineData(TimeUnit.Minute, "0 minute")] [InlineData(TimeUnit.Second, "0 seconde")] [InlineData(TimeUnit.Millisecond, "0 milliseconde")] public void NoTime(TimeUnit minUnit, string expected) { var noTime = TimeSpan.Zero; var actual = noTime.Humanize(minUnit: minUnit); Assert.Equal(expected, actual); } [Fact] public void NoTimeToWords() { var noTime = TimeSpan.Zero; var actual = noTime.Humanize(toWords: true); Assert.Equal("temps nul", actual); } } ================================================ FILE: tests/Humanizer.Tests/Localisation/fr-CH/NumberToWordsTests.cs ================================================ namespace frCH; [UseCulture("fr-CH")] public class NumberToWordsTests { [Theory] [InlineData(0, "zéro")] [InlineData(1, "un")] [InlineData(10, "dix")] [InlineData(11, "onze")] [InlineData(15, "quinze")] [InlineData(17, "dix-sept")] [InlineData(25, "vingt-cinq")] [InlineData(31, "trente et un")] [InlineData(71, "septante et un")] [InlineData(80, "octante")] [InlineData(81, "octante et un")] [InlineData(122, "cent vingt-deux")] [InlineData(3501, "trois mille cinq cent un")] [InlineData(100, "cent")] [InlineData(1000, "mille")] [InlineData(100000, "cent mille")] [InlineData(1000000, "un million")] [InlineData(10000000, "dix millions")] [InlineData(100000000, "cent millions")] [InlineData(200000000, "deux cents millions")] [InlineData(1000000000, "un milliard")] [InlineData(111, "cent onze")] [InlineData(1111, "mille cent onze")] [InlineData(111111, "cent onze mille cent onze")] [InlineData(1111111, "un million cent onze mille cent onze")] [InlineData(11111111, "onze millions cent onze mille cent onze")] [InlineData(111111111, "cent onze millions cent onze mille cent onze")] [InlineData(1111111111, "un milliard cent onze millions cent onze mille cent onze")] [InlineData(123, "cent vingt-trois")] [InlineData(1234, "mille deux cent trente-quatre")] [InlineData(12345, "douze mille trois cent quarante-cinq")] [InlineData(123456, "cent vingt-trois mille quatre cent cinquante-six")] [InlineData(1234567, "un million deux cent trente-quatre mille cinq cent soixante-sept")] [InlineData(12345678, "douze millions trois cent quarante-cinq mille six cent septante-huit")] [InlineData(123456789, "cent vingt-trois millions quatre cent cinquante-six mille sept cent octante-neuf")] [InlineData(1234567890, "un milliard deux cent trente-quatre millions cinq cent soixante-sept mille huit cent nonante")] [InlineData(1234567899, "un milliard deux cent trente-quatre millions cinq cent soixante-sept mille huit cent nonante-neuf")] [InlineData(223, "deux cent vingt-trois")] [InlineData(2234, "deux mille deux cent trente-quatre")] [InlineData(22345, "vingt-deux mille trois cent quarante-cinq")] [InlineData(200456, "deux cent mille quatre cent cinquante-six")] [InlineData(223456, "deux cent vingt-trois mille quatre cent cinquante-six")] [InlineData(2234567, "deux millions deux cent trente-quatre mille cinq cent soixante-sept")] [InlineData(22345678, "vingt-deux millions trois cent quarante-cinq mille six cent septante-huit")] [InlineData(223456789, "deux cent vingt-trois millions quatre cent cinquante-six mille sept cent octante-neuf")] [InlineData(2147483646, "deux milliards cent quarante-sept millions quatre cent octante-trois mille six cent quarante-six")] [InlineData(1999, "mille neuf cent nonante-neuf")] [InlineData(2014, "deux mille quatorze")] [InlineData(2048, "deux mille quarante-huit")] [InlineData(400, "quatre cents")] [InlineData(401, "quatre cent un")] [InlineData(480, "quatre cent octante")] [InlineData(80000, "octante mille")] [InlineData(80000000, "octante millions")] [InlineData(80080080, "octante millions octante mille octante")] [InlineData(200200200, "deux cents millions deux cent mille deux cents")] [InlineData(200200202, "deux cents millions deux cent mille deux cent deux")] public void ToWords(int number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(1, "une", GrammaticalGender.Feminine)] [InlineData(1, "un", GrammaticalGender.Masculine)] [InlineData(2, "deux", GrammaticalGender.Feminine)] [InlineData(2, "deux", GrammaticalGender.Masculine)] [InlineData(11, "onze", GrammaticalGender.Feminine)] [InlineData(11, "onze", GrammaticalGender.Masculine)] [InlineData(21, "vingt et une", GrammaticalGender.Feminine)] [InlineData(21, "vingt et un", GrammaticalGender.Masculine)] [InlineData(31, "trente et une", GrammaticalGender.Feminine)] [InlineData(31, "trente et un", GrammaticalGender.Masculine)] [InlineData(41, "quarante et une", GrammaticalGender.Feminine)] [InlineData(41, "quarante et un", GrammaticalGender.Masculine)] [InlineData(51, "cinquante et une", GrammaticalGender.Feminine)] [InlineData(51, "cinquante et un", GrammaticalGender.Masculine)] [InlineData(61, "soixante et une", GrammaticalGender.Feminine)] [InlineData(61, "soixante et un", GrammaticalGender.Masculine)] [InlineData(71, "septante et une", GrammaticalGender.Feminine)] [InlineData(71, "septante et un", GrammaticalGender.Masculine)] [InlineData(81, "octante et une", GrammaticalGender.Feminine)] [InlineData(81, "octante et un", GrammaticalGender.Masculine)] [InlineData(91, "nonante et une", GrammaticalGender.Feminine)] [InlineData(91, "nonante et un", GrammaticalGender.Masculine)] [InlineData(121, "cent vingt et une", GrammaticalGender.Feminine)] [InlineData(121, "cent vingt et un", GrammaticalGender.Masculine)] [InlineData(10121, "dix mille cent vingt et une", GrammaticalGender.Feminine)] [InlineData(10121, "dix mille cent vingt et un", GrammaticalGender.Masculine)] public void ToWordsWithGender(int number, string expected, GrammaticalGender gender) => Assert.Equal(expected, number.ToWords(gender)); [Theory] [InlineData(0, "zérotième")] [InlineData(1, "premier")] [InlineData(2, "deuxième")] [InlineData(3, "troisième")] [InlineData(4, "quatrième")] [InlineData(5, "cinquième")] [InlineData(6, "sixième")] [InlineData(7, "septième")] [InlineData(8, "huitième")] [InlineData(9, "neuvième")] [InlineData(10, "dixième")] [InlineData(11, "onzième")] [InlineData(12, "douzième")] [InlineData(13, "treizième")] [InlineData(14, "quatorzième")] [InlineData(15, "quinzième")] [InlineData(16, "seizième")] [InlineData(17, "dix-septième")] [InlineData(18, "dix-huitième")] [InlineData(19, "dix-neuvième")] [InlineData(20, "vingtième")] [InlineData(21, "vingt et unième")] [InlineData(22, "vingt-deuxième")] [InlineData(30, "trentième")] [InlineData(40, "quarantième")] [InlineData(50, "cinquantième")] [InlineData(60, "soixantième")] [InlineData(70, "septantième")] [InlineData(80, "octantième")] [InlineData(90, "nonantième")] [InlineData(95, "nonante-cinquième")] [InlineData(96, "nonante-sixième")] [InlineData(100, "centième")] [InlineData(120, "cent vingtième")] [InlineData(121, "cent vingt et unième")] [InlineData(1000, "millième")] [InlineData(1001, "mille unième")] [InlineData(1021, "mille vingt et unième")] [InlineData(10000, "dix millième")] [InlineData(10121, "dix mille cent vingt et unième")] [InlineData(100000, "cent millième")] [InlineData(1000000, "millionième")] [InlineData(1000000000, "milliardième")] public void ToOrdinalWords(int number, string words) => Assert.Equal(words, number.ToOrdinalWords()); [Theory] [InlineData(1, "première", GrammaticalGender.Feminine)] [InlineData(1, "premier", GrammaticalGender.Masculine)] [InlineData(2, "deuxième", GrammaticalGender.Feminine)] [InlineData(2, "deuxième", GrammaticalGender.Masculine)] [InlineData(121, "cent vingt et unième", GrammaticalGender.Feminine)] [InlineData(121, "cent vingt et unième", GrammaticalGender.Masculine)] [InlineData(10121, "dix mille cent vingt et unième", GrammaticalGender.Feminine)] [InlineData(10121, "dix mille cent vingt et unième", GrammaticalGender.Masculine)] public void ToOrdinalWordsWithGender(int number, string expected, GrammaticalGender gender) => Assert.Equal(expected, number.ToOrdinalWords(gender)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/he/DateHumanizeTests.cs ================================================ namespace he; [UseCulture("he")] public class DateHumanizeTests { [Theory] [InlineData(1, "אתמול")] [InlineData(2, "לפני יומיים")] [InlineData(3, "לפני 3 ימים")] [InlineData(11, "לפני 11 יום")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(2, "לפני שעתיים")] [InlineData(1, "לפני שעה")] [InlineData(3, "לפני 3 שעות")] [InlineData(11, "לפני 11 שעות")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(2, "לפני 2 דקות")] [InlineData(1, "לפני דקה")] [InlineData(3, "לפני 3 דקות")] [InlineData(11, "לפני 11 דקות")] [InlineData(60, "לפני שעה")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(2, "לפני חודשיים")] [InlineData(1, "לפני חודש")] [InlineData(3, "לפני 3 חודשים")] [InlineData(11, "לפני 11 חודשים")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(2, "לפני 2 שניות")] [InlineData(1, "לפני שנייה")] [InlineData(3, "לפני 3 שניות")] [InlineData(11, "לפני 11 שניות")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(2, "לפני שנתיים")] [InlineData(1, "לפני שנה")] [InlineData(3, "לפני 3 שנים")] [InlineData(11, "לפני 11 שנה")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(2, "בעוד יומיים")] [InlineData(1, "מחר")] [InlineData(3, "בעוד 3 ימים")] [InlineData(11, "בעוד 11 יום")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(2, "בעוד חודשיים")] [InlineData(1, "בעוד חודש")] [InlineData(10, "בעוד 10 חודשים")] [InlineData(11, "בעוד 11 חודשים")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(2, "בעוד שנתיים")] [InlineData(1, "בעוד שנה")] [InlineData(3, "בעוד 3 שנים")] [InlineData(11, "בעוד 11 שנה")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Theory] [InlineData(2, "בעוד שעתיים")] [InlineData(1, "בעוד שעה")] [InlineData(3, "בעוד 3 שעות")] [InlineData(11, "בעוד 11 שעות")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(2, "בעוד 2 דקות")] [InlineData(1, "בעוד דקה")] [InlineData(3, "בעוד 3 דקות")] [InlineData(11, "בעוד 11 דקות")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(2, "בעוד 2 שניות")] [InlineData(1, "בעוד שנייה")] [InlineData(3, "בעוד 3 שניות")] [InlineData(11, "בעוד 11 שניות")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/he/NumberToWordsTests.cs ================================================ namespace he; [UseCulture("he")] public class NumberToWordsTests { [Theory] [InlineData(0, "אפס")] [InlineData(1, "אחת")] [InlineData(2, "שתיים")] [InlineData(3, "שלוש")] [InlineData(4, "ארבע")] [InlineData(5, "חמש")] [InlineData(6, "שש")] [InlineData(7, "שבע")] [InlineData(8, "שמונה")] [InlineData(9, "תשע")] [InlineData(10, "עשר")] [InlineData(11, "אחת עשרה")] [InlineData(12, "שתים עשרה")] [InlineData(19, "תשע עשרה")] [InlineData(20, "עשרים")] [InlineData(22, "עשרים ושתיים")] [InlineData(50, "חמישים")] [InlineData(99, "תשעים ותשע")] [InlineData(100, "מאה")] [InlineData(101, "מאה ואחת")] [InlineData(111, "מאה ואחת עשרה")] [InlineData(200, "מאתיים")] [InlineData(241, "מאתיים ארבעים ואחת")] [InlineData(500, "חמש מאות")] [InlineData(505, "חמש מאות וחמש")] [InlineData(725, "שבע מאות עשרים וחמש")] [InlineData(1000, "אלף")] [InlineData(1009, "אלף ותשע")] [InlineData(1011, "אלף ואחת עשרה")] [InlineData(1024, "אלף עשרים וארבע")] [InlineData(1040, "אלף ארבעים")] [InlineData(2000, "אלפיים")] [InlineData(7021, "שבעת אלפים עשרים ואחת")] [InlineData(20000, "עשרים אלף")] [InlineData(28123, "עשרים ושמונה אלף מאה עשרים ושלוש")] [InlineData(500000, "חמש מאות אלף")] [InlineData(500001, "חמש מאות אלף ואחת")] [InlineData(1000000, "מיליון")] [InlineData(1000001, "מיליון ואחת")] [InlineData(2000408, "שני מיליון ארבע מאות ושמונה")] [InlineData(1000000000, "מיליארד")] [InlineData(1000000001, "מיליארד ואחת")] [InlineData(int.MaxValue /* 2147483647 */, "שני מיליארד מאה ארבעים ושבעה מיליון ארבע מאות שמונים ושלוש אלף שש מאות ארבעים ושבע")] public void ToWords(int number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(0, "אפס")] [InlineData(1, "אחד")] [InlineData(2, "שניים")] [InlineData(3, "שלושה")] [InlineData(4, "ארבעה")] [InlineData(5, "חמישה")] [InlineData(6, "שישה")] [InlineData(7, "שבעה")] [InlineData(8, "שמונה")] [InlineData(9, "תשעה")] [InlineData(10, "עשרה")] [InlineData(11, "אחד עשר")] [InlineData(12, "שנים עשר")] [InlineData(19, "תשעה עשר")] [InlineData(20, "עשרים")] [InlineData(22, "עשרים ושניים")] [InlineData(50, "חמישים")] [InlineData(99, "תשעים ותשעה")] [InlineData(100, "מאה")] [InlineData(101, "מאה ואחד")] [InlineData(111, "מאה ואחד עשר")] [InlineData(200, "מאתיים")] [InlineData(241, "מאתיים ארבעים ואחד")] [InlineData(500, "חמש מאות")] [InlineData(505, "חמש מאות וחמישה")] [InlineData(725, "שבע מאות עשרים וחמישה")] [InlineData(1000, "אלף")] [InlineData(1009, "אלף ותשעה")] [InlineData(1011, "אלף ואחד עשר")] [InlineData(1024, "אלף עשרים וארבעה")] [InlineData(1040, "אלף ארבעים")] [InlineData(2000, "אלפיים")] [InlineData(7021, "שבעת אלפים עשרים ואחד")] [InlineData(20000, "עשרים אלף")] [InlineData(28123, "עשרים ושמונה אלף מאה עשרים ושלושה")] [InlineData(500000, "חמש מאות אלף")] [InlineData(500001, "חמש מאות אלף ואחד")] [InlineData(1000000, "מיליון")] [InlineData(1000001, "מיליון ואחד")] [InlineData(2000408, "שני מיליון ארבע מאות ושמונה")] [InlineData(1000000000, "מיליארד")] [InlineData(1000000001, "מיליארד ואחד")] [InlineData(int.MaxValue /* 2147483647 */, "שני מיליארד מאה ארבעים ושבעה מיליון ארבע מאות שמונים ושלוש אלף שש מאות ארבעים ושבעה")] public void ToWordsMasculine(int number, string expected) => Assert.Equal(expected, number.ToWords(GrammaticalGender.Masculine)); [Theory] [InlineData(-2, "מינוס שתיים")] public void NegativeToWords(int number, string expected) => Assert.Equal(expected, number.ToWords()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/he/TimeSpanHumanizeTests.cs ================================================ namespace he; [UseCulture("he")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Native speaker")] [InlineData(366, "שנה")] [InlineData(731, "שנתיים")] [InlineData(1096, "3 שנים")] [InlineData(4018, "11 שנים")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Native speaker")] [InlineData(31, "חודש")] [InlineData(61, "חודשיים")] [InlineData(92, "3 חודשים")] [InlineData(335, "11 חודשים")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(7, "שבוע")] [InlineData(14, "שבועיים")] [InlineData(21, "3 שבועות")] [InlineData(77, "11 שבועות")] public void Weeks(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "יום")] [InlineData(2, "יומיים")] [InlineData(3, "3 ימים")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "שעה")] [InlineData(2, "שעתיים")] [InlineData(3, "3 שעות")] [InlineData(11, "11 שעות")] public void Hours(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); [Theory] [InlineData(1, "דקה")] [InlineData(2, "שתי דקות")] [InlineData(3, "3 דקות")] [InlineData(11, "11 דקות")] public void Minutes(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); [Theory] [InlineData(1, "שנייה")] [InlineData(2, "שתי שניות")] [InlineData(3, "3 שניות")] [InlineData(11, "11 שניות")] public void Seconds(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); [Theory] [InlineData(1, "אלפית שנייה")] [InlineData(2, "שתי אלפיות שנייה")] [InlineData(3, "3 אלפיות שנייה")] [InlineData(11, "11 אלפיות שנייה")] public void Milliseconds(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); [Fact] public void NoTime() => Assert.Equal("0 אלפיות שנייה", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => Assert.Equal("אין זמן", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/hr/DateHumanizeTests.cs ================================================ namespace hr; [UseCulture("hr-HR")] public class DateHumanizeTests { [Theory] [InlineData(-22, "prije 22 godine")] [InlineData(-5, "prije 5 godina")] [InlineData(-4, "prije 4 godine")] [InlineData(-2, "prije 2 godine")] [InlineData(-1, "prije godinu dana")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(5, "za 5 godina")] [InlineData(4, "za 4 godine")] [InlineData(3, "za 3 godine")] [InlineData(2, "za 2 godine")] [InlineData(1, "za godinu dana")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Theory] [InlineData(-8, "prije 8 mjeseci")] [InlineData(-5, "prije 5 mjeseci")] [InlineData(-4, "prije 4 mjeseca")] [InlineData(-3, "prije 3 mjeseca")] [InlineData(-2, "prije 2 mjeseca")] [InlineData(-1, "prije mjesec dana")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(5, "za 5 mjeseci")] [InlineData(4, "za 4 mjeseca")] [InlineData(2, "za 2 mjeseca")] [InlineData(1, "za mjesec dana")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(-24, "prije 24 dana")] [InlineData(-22, "prije 22 dana")] [InlineData(-10, "prije 10 dana")] [InlineData(-5, "prije 5 dana")] [InlineData(-4, "prije 4 dana")] [InlineData(-3, "prije 3 dana")] [InlineData(-2, "prije 2 dana")] [InlineData(-1, "jučer")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(10, "za 10 dana")] [InlineData(5, "za 5 dana")] [InlineData(1, "sutra")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(-10, "prije 10 sati")] [InlineData(-5, "prije 5 sati")] [InlineData(-4, "prije 4 sata")] [InlineData(-3, "prije 3 sata")] [InlineData(-2, "prije 2 sata")] [InlineData(-1, "prije sat vremena")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(5, "za 5 sati")] [InlineData(4, "za 4 sata")] [InlineData(3, "za 3 sata")] [InlineData(2, "za 2 sata")] [InlineData(1, "za sat vremena")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(-10, "prije 10 minuta")] [InlineData(-5, "prije 5 minuta")] [InlineData(-4, "prije 4 minute")] [InlineData(-3, "prije 3 minute")] [InlineData(-2, "prije 2 minute")] [InlineData(-1, "prije jedne minute")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(5, "za 5 minuta")] [InlineData(4, "za 4 minute")] [InlineData(3, "za 3 minute")] [InlineData(2, "za 2 minute")] [InlineData(1, "za jednu minutu")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(-10, "prije 10 sekundi")] [InlineData(-5, "prije 5 sekundi")] [InlineData(-4, "prije 4 sekunde")] [InlineData(-3, "prije 3 sekunde")] [InlineData(-2, "prije 2 sekunde")] [InlineData(-1, "prije jedne sekunde")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(10, "za 10 sekundi")] [InlineData(5, "za 5 sekundi")] [InlineData(4, "za 4 sekunde")] [InlineData(3, "za 3 sekunde")] [InlineData(2, "za 2 sekunde")] [InlineData(1, "za jednu sekundu")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/hr/NumberToWordsTests.cs ================================================ namespace hr; [UseCulture("hr-HR")] public class NumberToWordsTests { [Theory] [InlineData(0, "nula")] [InlineData(1, "jedan")] [InlineData(10, "deset")] [InlineData(11, "jedanaest")] [InlineData(20, "dvadeset")] [InlineData(122, "sto dvadeset dva")] [InlineData(3501, "tri tisuće petsto jedan")] [InlineData(100, "sto")] [InlineData(200, "dvjesto")] [InlineData(300, "tristo")] [InlineData(400, "četiristo")] [InlineData(500, "petsto")] [InlineData(1000, "tisuću")] [InlineData(1001, "tisuću jedan")] [InlineData(2000, "dvije tisuće")] [InlineData(3000, "tri tisuće")] [InlineData(4000, "četiri tisuće")] [InlineData(5000, "pet tisuća")] [InlineData(10000, "deset tisuća")] [InlineData(20000, "dvadeset tisuća")] [InlineData(21000, "dvadeset jedna tisuća")] [InlineData(22000, "dvadeset dvije tisuće")] [InlineData(23000, "dvadeset tri tisuće")] [InlineData(24000, "dvadeset četiri tisuće")] [InlineData(25000, "dvadeset pet tisuća")] [InlineData(100000, "sto tisuća")] [InlineData(200000, "dvjesto tisuća")] [InlineData(201000, "dvjesto jedna tisuća")] [InlineData(202000, "dvjesto dvije tisuće")] [InlineData(203000, "dvjesto tri tisuće")] [InlineData(204000, "dvjesto četiri tisuće")] [InlineData(205000, "dvjesto pet tisuća")] [InlineData(222222, "dvjesto dvadeset dvije tisuće dvjesto dvadeset dva")] [InlineData(1000000, "milijun")] [InlineData(2000000, "dva milijuna")] [InlineData(10000000, "deset milijuna")] [InlineData(11000000, "jedanaest milijuna")] [InlineData(20000000, "dvadeset milijuna")] [InlineData(21000000, "dvadeset jedan milijun")] [InlineData(22000000, "dvadeset dva milijuna")] [InlineData(30000000, "trideset milijuna")] [InlineData(31000000, "trideset jedan milijun")] [InlineData(32000000, "trideset dva milijuna")] [InlineData(100000000, "sto milijuna")] [InlineData(101000000, "sto jedan milijun")] [InlineData(102000000, "sto dva milijuna")] [InlineData(111000000, "sto jedanaest milijuna")] [InlineData(200000000, "dvjesto milijuna")] [InlineData(201000000, "dvjesto jedan milijun")] [InlineData(202000000, "dvjesto dva milijuna")] [InlineData(211000000, "dvjesto jedanaest milijuna")] [InlineData(1000000000, "milijarda")] [InlineData(2100000000, "dvije milijarde sto milijuna")] [InlineData(2200000000, "dvije milijarde dvjesto milijuna")] [InlineData(2300000000, "dvije milijarde tristo milijuna")] [InlineData(2500000000, "dvije milijarde petsto milijuna")] [InlineData(10000000000, "deset milijardi")] [InlineData(11000000000, "jedanaest milijardi")] [InlineData(20000000000, "dvadeset milijardi")] [InlineData(21000000000, "dvadeset jedna milijarda")] [InlineData(22000000000, "dvadeset dvije milijarde")] [InlineData(23000000000, "dvadeset tri milijarde")] [InlineData(24000000000, "dvadeset četiri milijarde")] [InlineData(25000000000, "dvadeset pet milijardi")] [InlineData(111, "sto jedanaest")] [InlineData(1111, "tisuću sto jedanaest")] [InlineData(111111, "sto jedanaest tisuća sto jedanaest")] [InlineData(1111111, "milijun sto jedanaest tisuća sto jedanaest")] [InlineData(11111111, "jedanaest milijuna sto jedanaest tisuća sto jedanaest")] [InlineData(111111111, "sto jedanaest milijuna sto jedanaest tisuća sto jedanaest")] [InlineData(1111111111, "milijarda sto jedanaest milijuna sto jedanaest tisuća sto jedanaest")] [InlineData(101, "sto jedan")] [InlineData(1011, "tisuću jedanaest")] [InlineData(100011, "sto tisuća jedanaest")] [InlineData(1100001, "milijun sto tisuća jedan")] [InlineData(11000011, "jedanaest milijuna jedanaest")] [InlineData(110000011, "sto deset milijuna jedanaest")] [InlineData(1100000111, "milijarda sto milijuna sto jedanaest")] [InlineData(123, "sto dvadeset tri")] [InlineData(1234, "tisuću dvjesto trideset četiri")] [InlineData(12345, "dvanaest tisuća tristo četrdeset pet")] [InlineData(123456, "sto dvadeset tri tisuće četiristo pedeset šest")] [InlineData(1234567, "milijun dvjesto trideset četiri tisuće petsto šezdeset sedam")] [InlineData(12345678, "dvanaest milijuna tristo četrdeset pet tisuća šeststo sedamdeset osam")] [InlineData(123456789, "sto dvadeset tri milijuna četiristo pedeset šest tisuća sedamsto osamdeset devet")] [InlineData(1234567890, "milijarda dvjesto trideset četiri milijuna petsto šezdeset sedam tisuća osamsto devedeset")] [InlineData(1000000000000, "bilijun")] [InlineData(2000000000000, "dva bilijuna")] [InlineData(10000000000000, "deset bilijuna")] [InlineData(11000000000000, "jedanaest bilijuna")] [InlineData(20000000000000, "dvadeset bilijuna")] [InlineData(21000000000000, "dvadeset jedan bilijun")] [InlineData(22000000000000, "dvadeset dva bilijuna")] [InlineData(45678912345678, "četrdeset pet bilijuna šeststo sedamdeset osam milijardi devetsto dvanaest milijuna tristo četrdeset pet tisuća šeststo sedamdeset osam")] [InlineData(1000000000000000, "bilijarda")] [InlineData(2000000000000000, "dvije bilijarde")] [InlineData(3000000000000000, "tri bilijarde")] [InlineData(4000000000000000, "četiri bilijarde")] [InlineData(5000000000000000, "pet bilijardi")] [InlineData(10000000000000000, "deset bilijardi")] [InlineData(11000000000000000, "jedanaest bilijardi")] [InlineData(20000000000000000, "dvadeset bilijardi")] [InlineData(21000000000000000, "dvadeset jedna bilijarda")] [InlineData(22000000000000000, "dvadeset dvije bilijarde")] [InlineData(23000000000000000, "dvadeset tri bilijarde")] [InlineData(24000000000000000, "dvadeset četiri bilijarde")] [InlineData(25000000000000000, "dvadeset pet bilijardi")] [InlineData(1000000000000000000, "trilijun")] [InlineData(2000000000000000000, "dva trilijuna")] [InlineData(9000000000000000000, "devet trilijuna")] [InlineData(-7516, "minus sedam tisuća petsto šesnaest")] [InlineData(long.MaxValue, "devet trilijuna dvjesto dvadeset tri bilijarde tristo sedamdeset dva bilijuna trideset šest milijardi osamsto pedeset četiri milijuna sedamsto sedamdeset pet tisuća osamsto sedam")] [InlineData(long.MinValue, "minus devet trilijuna dvjesto dvadeset tri bilijarde tristo sedamdeset dva bilijuna trideset šest milijardi osamsto pedeset četiri milijuna sedamsto sedamdeset pet tisuća osamsto osam")] public void NumberToWords(long stubNumber, string expectedWords) { var actualWords = stubNumber.ToWords(); Assert.Equal(expectedWords, actualWords); } } ================================================ FILE: tests/Humanizer.Tests/Localisation/hr/TimeSpanHumanizeTests.cs ================================================ namespace hr; [UseCulture("hr-HR")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "1 godina")] [InlineData(731, "2 godine")] [InlineData(1096, "3 godine")] [InlineData(4018, "11 godina")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "1 mjesec")] [InlineData(61, "2 mjeseca")] [InlineData(92, "3 mjeseca")] [InlineData(335, "11 mjeseci")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(1, "1 dan")] [InlineData(2, "2 dana")] [InlineData(3, "3 dana")] [InlineData(4, "4 dana")] [InlineData(5, "5 dana")] [InlineData(7, "1 tjedan")] [InlineData(14, "2 tjedna")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/hu/DateHumanizeTests.cs ================================================ namespace hu; [UseCulture("hu-HU")] public class DateHumanizeTests { [Theory] [InlineData(1, "egy másodperce")] [InlineData(10, "10 másodperce")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "egy másodperc múlva")] [InlineData(10, "10 másodperc múlva")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(1, "egy perce")] [InlineData(10, "10 perce")] [InlineData(60, "egy órája")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "egy perc múlva")] [InlineData(10, "10 perc múlva")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(1, "egy órája")] [InlineData(10, "10 órája")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "egy óra múlva")] [InlineData(10, "10 óra múlva")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(1, "tegnap")] [InlineData(10, "10 napja")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "holnap")] [InlineData(10, "10 nap múlva")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(1, "egy hónapja")] [InlineData(10, "10 hónapja")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "egy hónap múlva")] [InlineData(10, "10 hónap múlva")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(1, "egy éve")] [InlineData(2, "2 éve")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "egy év múlva")] [InlineData(2, "2 év múlva")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/hu/NumberToWordsTests.cs ================================================ namespace hu; [UseCulture("hu-HU")] public class NumberToWordsTests { private readonly HungarianNumberToWordsConverter converter = new(); [Theory] [InlineData(0, "nulla")] [InlineData(1, "egy")] [InlineData(2, "kettő")] [InlineData(10, "tíz")] [InlineData(11, "tizenegy")] [InlineData(20, "húsz")] [InlineData(21, "huszonegy")] [InlineData(100, "száz")] [InlineData(101, "százegy")] [InlineData(111, "száztizenegy")] [InlineData(200, "kétszáz")] [InlineData(999, "kilencszázkilencvenkilenc")] [InlineData(1000, "ezer")] [InlineData(1001, "ezeregy")] [InlineData(1002, "ezerkettő")] [InlineData(1111, "ezerszáztizenegy")] [InlineData(2000, "kétezer")] [InlineData(2001, "kétezer-egy")] [InlineData(2002, "kétezer-kettő")] [InlineData(2111, "kétezer-száztizenegy")] [InlineData(3000, "háromezer")] [InlineData(3001, "háromezer-egy")] [InlineData(3002, "háromezer-kettő")] [InlineData(3122, "háromezer-százhuszonkettő")] [InlineData(12345, "tizenkétezer-háromszáznegyvenöt")] [InlineData(123456, "százhuszonháromezer-négyszázötvenhat")] [InlineData(1234567, "egymillió-kétszázharmincnégyezer-ötszázhatvanhét")] [InlineData(12345678, "tizenkétmillió-háromszáznegyvenötezer-hatszázhetvennyolc")] [InlineData(123456789, "százhuszonhárommillió-négyszázötvenhatezer-hétszáznyolcvankilenc")] [InlineData(1234567890, "egymilliárd-kétszázharmincnégymillió-ötszázhatvanhétezer-nyolcszázkilencven")] [InlineData(1000000, "egymillió")] [InlineData(2000000, "kétmillió")] [InlineData(12000000, "tizenkétmillió")] [InlineData(-1, "mínusz egy")] [InlineData(-18, "mínusz tizennyolc")] public void TestNumberConversion(long number, string expected) => Assert.Equal(expected, converter.Convert(number)); [Theory] [InlineData(0, "nulladik")] [InlineData(1, "első")] [InlineData(2, "második")] [InlineData(10, "tizedik")] [InlineData(11, "tizenegyedik")] [InlineData(20, "huszadik")] [InlineData(21, "huszonegyedik")] [InlineData(100, "századik")] [InlineData(101, "százegyedik")] [InlineData(111, "száztizenegyedik")] [InlineData(200, "kétszázadik")] [InlineData(999, "kilencszázkilencvenkilencedik")] [InlineData(1000, "ezredik")] [InlineData(1001, "ezeregyedik")] [InlineData(1002, "ezerkettedik")] [InlineData(1111, "ezerszáztizenegyedik")] [InlineData(2000, "kétezredik")] [InlineData(2001, "kétezer-egyedik")] [InlineData(2002, "kétezer-kettedik")] [InlineData(2111, "kétezer-száztizenegyedik")] [InlineData(3000, "háromezredik")] [InlineData(3001, "háromezer-egyedik")] [InlineData(3002, "háromezer-kettedik")] [InlineData(3122, "háromezer-százhuszonkettedik")] [InlineData(12345, "tizenkétezer-háromszáznegyvenötödik")] [InlineData(123456, "százhuszonháromezer-négyszázötvenhatodik")] [InlineData(1234567, "egymillió-kétszázharmincnégyezer-ötszázhatvanhetedik")] [InlineData(12345678, "tizenkétmillió-háromszáznegyvenötezer-hatszázhetvennyolcadik")] [InlineData(123456789, "százhuszonhárommillió-négyszázötvenhatezer-hétszáznyolcvankilencedik")] [InlineData(1234567890, "egymilliárd-kétszázharmincnégymillió-ötszázhatvanhétezer-nyolcszázkilencvenedik")] [InlineData(1000000, "egymilliomodik")] [InlineData(2000000, "kétmilliomodik")] [InlineData(12000000, "tizenkétmilliomodik")] [InlineData(-1, "mínusz első")] [InlineData(-18, "mínusz tizennyolcadik")] public void TestOrdinalConversion(int number, string expected) => Assert.Equal(expected, converter.ConvertToOrdinal(number)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/hu/TimeSpanHumanizeTests.cs ================================================ namespace hu; [UseCulture("hu-HU")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "1 év")] [InlineData(731, "2 év")] [InlineData(1096, "3 év")] [InlineData(4018, "11 év")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "1 hónap")] [InlineData(61, "2 hónap")] [InlineData(92, "3 hónap")] [InlineData(335, "11 hónap")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(14, "2 hét")] [InlineData(7, "1 hét")] public void Weeks(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(2, "2 nap")] [InlineData(1, "1 nap")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(2, "2 óra")] [InlineData(1, "1 óra")] public void Hours(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); [Theory] [InlineData(2, "2 perc")] [InlineData(1, "1 perc")] public void Minutes(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); [Theory] [InlineData(2, "2 másodperc")] [InlineData(1, "1 másodperc")] public void Seconds(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); [Theory] [Trait("Translation", "Google")] [InlineData(366, "egy év")] [InlineData(731, "kettő év")] [InlineData(1096, "három év")] [InlineData(4018, "tizenegy év")] public void YearsWithWords(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year, toWords: true)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "egy hónap")] [InlineData(61, "kettő hónap")] [InlineData(92, "három hónap")] [InlineData(335, "tizenegy hónap")] public void MonthsWithWords(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year, toWords: true)); [Theory] [InlineData(14, "kettő hét")] [InlineData(7, "egy hét")] public void WeeksWithWords(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(toWords: true)); [Theory] [InlineData(2, "kettő nap")] [InlineData(1, "egy nap")] public void DaysWithWords(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(toWords: true)); [Theory] [InlineData(2, "kettő óra")] [InlineData(1, "egy óra")] public void HoursWithWords(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize(toWords: true)); [Theory] [InlineData(2, "kettő perc")] [InlineData(1, "egy perc")] public void MinutesWithWords(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize(toWords: true)); [Theory] [InlineData(2, "kettő másodperc")] [InlineData(1, "egy másodperc")] public void SecondsWithWords(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize(toWords: true)); [Fact] public void NoTime() { var noTime = TimeSpan.Zero; var actual = noTime.Humanize(); Assert.Equal("0 ezredmásodperc", actual); } [Fact] public void NoTimeToWords() { var noTime = TimeSpan.Zero; var actual = noTime.Humanize(toWords: true); Assert.Equal("nincs idő", actual); } } ================================================ FILE: tests/Humanizer.Tests/Localisation/hy/DateHumanizeTests.cs ================================================ namespace hy; [UseCulture("hy")] public class DateHumanizeTests { [Theory] [InlineData(1, "մեկ վայրկյան առաջ")] [InlineData(2, "2 վայրկյան առաջ")] [InlineData(3, "3 վայրկյան առաջ")] [InlineData(4, "4 վայրկյան առաջ")] [InlineData(11, "11 վայրկյան առաջ")] [InlineData(21, "21 վայրկյան առաջ")] [InlineData(24, "24 վայրկյան առաջ")] [InlineData(40, "40 վայրկյան առաջ")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "մեկ վայրկյանից")] [InlineData(2, "2 վայրկյանից")] [InlineData(11, "11 վայրկյանից")] [InlineData(20, "20 վայրկյանից")] [InlineData(40, "40 վայրկյանից")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(1, "մեկ րոպե առաջ")] [InlineData(2, "2 րոպե առաջ")] [InlineData(10, "10 րոպե առաջ")] [InlineData(25, "25 րոպե առաջ")] [InlineData(40, "40 րոպե առաջ")] [InlineData(60, "մեկ ժամ առաջ")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "մեկ րոպեից")] [InlineData(2, "2 րոպեից")] [InlineData(19, "19 րոպեից")] [InlineData(25, "25 րոպեից")] [InlineData(40, "40 րոպեից")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(1, "մեկ ժամ առաջ")] [InlineData(2, "2 ժամ առաջ")] [InlineData(19, "19 ժամ առաջ")] [InlineData(20, "20 ժամ առաջ")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "մեկ ժամից")] [InlineData(5, "5 ժամից")] [InlineData(23, "23 ժամից")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(1, "երեկ")] [InlineData(2, "2 օր առաջ")] [InlineData(25, "25 օր առաջ")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "վաղը")] [InlineData(2, "2 օրից")] [InlineData(25, "25 օրից")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(1, "մեկ ամիս առաջ")] [InlineData(11, "11 ամիս առաջ")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "մեկ ամսից")] [InlineData(11, "11 ամսից")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(1, "մեկ տարի առաջ")] [InlineData(2, "2 տարի առաջ")] [InlineData(21, "21 տարի առաջ")] [InlineData(111, "111 տարի առաջ")] [InlineData(121, "121 տարի առաջ")] [InlineData(222, "222 տարի առաջ")] [InlineData(325, "325 տարի առաջ")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "մեկ տարուց")] [InlineData(2, "2 տարուց")] [InlineData(21, "21 տարուց")] [InlineData(111, "111 տարուց")] [InlineData(121, "121 տարուց")] [InlineData(222, "222 տարուց")] [InlineData(325, "325 տարուց")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Fact] public void Now() => DateHumanize.Verify("հիմա", 0, TimeUnit.Day, Tense.Past); } ================================================ FILE: tests/Humanizer.Tests/Localisation/hy/NumberToWordsTests.cs ================================================ namespace hy; [UseCulture("hy")] public class NumberToWordsTests { [Theory] [InlineData(0, "զրո")] [InlineData(1, "մեկ")] [InlineData(10, "տաս")] [InlineData(11, "տասնմեկ")] [InlineData(12, "տասներկու")] [InlineData(13, "տասներեք")] [InlineData(14, "տասնչորս")] [InlineData(15, "տասնհինգ")] [InlineData(16, "տասնվեց")] [InlineData(17, "տասնյոթ")] [InlineData(18, "տասնութ")] [InlineData(19, "տասնինը")] [InlineData(20, "քսան")] [InlineData(30, "երեսուն")] [InlineData(40, "քառասուն")] [InlineData(50, "հիսուն")] [InlineData(60, "վաթսուն")] [InlineData(70, "յոթանասուն")] [InlineData(80, "ութսուն")] [InlineData(90, "իննսուն")] [InlineData(100, "հարյուր")] [InlineData(200, "երկու հարյուր")] [InlineData(300, "երեք հարյուր")] [InlineData(400, "չորս հարյուր")] [InlineData(500, "հինգ հարյուր")] [InlineData(600, "վեց հարյուր")] [InlineData(700, "յոթ հարյուր")] [InlineData(800, "ութ հարյուր")] [InlineData(900, "ինը հարյուր")] [InlineData(1000, "հազար")] [InlineData(2000, "երկու հազար")] [InlineData(3000, "երեք հազար")] [InlineData(4000, "չորս հազար")] [InlineData(5000, "հինգ հազար")] [InlineData(10000, "տաս հազար")] [InlineData(100000, "հարյուր հազար")] [InlineData(1000000, "մեկ միլիոն")] [InlineData(2000000, "երկու միլիոն")] [InlineData(10000000, "տաս միլիոն")] [InlineData(100000000, "հարյուր միլիոն")] [InlineData(1000000000, "մեկ միլիարդ")] [InlineData(2000000000, "երկու միլիարդ")] [InlineData(3000000000, "երեք միլիարդ")] [InlineData(4000000000, "չորս միլիարդ")] [InlineData(122, "հարյուր քսաներկու")] [InlineData(3501, "երեք հազար հինգ հարյուր մեկ")] [InlineData(111, "հարյուր տասնմեկ")] [InlineData(1112, "հազար հարյուր տասներկու")] [InlineData(11213, "տասնմեկ հազար երկու հարյուր տասներեք")] [InlineData(121314, "հարյուր քսանմեկ հազար երեք հարյուր տասնչորս")] [InlineData(2132415, "երկու միլիոն հարյուր երեսուներկու հազար չորս հարյուր տասնհինգ")] [InlineData(12345516, "տասներկու միլիոն երեք հարյուր քառասունհինգ հազար հինգ հարյուր տասնվեց")] [InlineData(751633617, "յոթ հարյուր հիսունմեկ միլիոն վեց հարյուր երեսուներեք հազար վեց հարյուր տասնյոթ")] [InlineData(1111111118, "մեկ միլիարդ հարյուր տասնմեկ միլիոն հարյուր տասնմեկ հազար հարյուր տասնութ")] [InlineData(4111111118, "չորս միլիարդ հարյուր տասնմեկ միլիոն հարյուր տասնմեկ հազար հարյուր տասնութ")] [InlineData(-751633617, "մինուս յոթ հարյուր հիսունմեկ միլիոն վեց հարյուր երեսուներեք հազար վեց հարյուր տասնյոթ")] [InlineData(999999999999, "ինը հարյուր իննսունինը միլիարդ ինը հարյուր իննսունինը միլիոն ինը հարյուր իննսունինը հազար ինը հարյուր իննսունինը")] [InlineData(1_000_000_000_000, "մեկ տրիլիոն")] [InlineData(3_000_000_000_000, "երեք տրիլիոն")] [InlineData(5_000_000_000_000, "հինգ տրիլիոն")] [InlineData(999_000_000_000_000, "ինը հարյուր իննսունինը տրիլիոն")] [InlineData( long.MaxValue, "ինը քվինտիլիոն " + "երկու հարյուր քսաներեք կվադրիլիոն " + "երեք հարյուր յոթանասուներկու տրիլիոն " + "երեսունվեց միլիարդ " + "ութ հարյուր հիսունչորս միլիոն " + "յոթ հարյուր յոթանասունհինգ հազար " + "ութ հարյուր յոթ")] [InlineData( long.MinValue, "մինուս ինը քվինտիլիոն " + "երկու հարյուր քսաներեք կվադրիլիոն " + "երեք հարյուր յոթանասուներկու տրիլիոն " + "երեսունվեց միլիարդ " + "ութ հարյուր հիսունչորս միլիոն " + "յոթ հարյուր յոթանասունհինգ հազար " + "ութ հարյուր ութ")] public void ToWords(long number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(0, "զրոյական")] [InlineData(1, "առաջին")] [InlineData(2, "երկրորդ")] [InlineData(3, "երրորդ")] [InlineData(10, "տասերորդ")] [InlineData(11, "տասնմեկերորդ")] [InlineData(12, "տասներկուերորդ")] [InlineData(13, "տասներեքերորդ")] [InlineData(14, "տասնչորսերորդ")] [InlineData(15, "տասնհինգերորդ")] [InlineData(16, "տասնվեցերորդ")] [InlineData(17, "տասնյոթերորդ")] [InlineData(18, "տասնութերորդ")] [InlineData(19, "տասնինըերորդ")] [InlineData(20, "քսաներորդ")] [InlineData(30, "երեսուներորդ")] [InlineData(40, "քառասուներորդ")] [InlineData(50, "հիսուներորդ")] [InlineData(60, "վաթսուներորդ")] [InlineData(70, "յոթանասուներորդ")] [InlineData(80, "ութսուներորդ")] [InlineData(90, "իննսուներորդ")] [InlineData(100, "հարյուրերորդ")] [InlineData(200, "երկու հարյուրերորդ")] [InlineData(300, "երեք հարյուրերորդ")] [InlineData(400, "չորս հարյուրերորդ")] [InlineData(500, "հինգ հարյուրերորդ")] [InlineData(600, "վեց հարյուրերորդ")] [InlineData(700, "յոթ հարյուրերորդ")] [InlineData(800, "ութ հարյուրերորդ")] [InlineData(900, "ինը հարյուրերորդ")] [InlineData(1000, "հազարերորդ")] [InlineData(2000, "երկու հազարերորդ")] [InlineData(3000, "երեք հազարերորդ")] [InlineData(4000, "չորս հազարերորդ")] [InlineData(5000, "հինգ հազարերորդ")] [InlineData(10000, "տաս հազարերորդ")] [InlineData(21000, "քսանմեկ հազարերորդ")] [InlineData(100000, "հարյուր հազարերորդ")] [InlineData(101000, "հարյուր մեկ հազարերորդ")] [InlineData(1000000, "մեկ միլիոներորդ")] [InlineData(121000, "հարյուր քսանմեկ հազարերորդ")] [InlineData(200000, "երկու հարյուր հազարերորդ")] [InlineData(2000000, "երկու միլիոներորդ")] [InlineData(10000000, "տաս միլիոներորդ")] [InlineData(21000000, "քսանմեկ միլիոներորդ")] [InlineData(100000000, "հարյուր միլիոներորդ")] [InlineData(230000000, "երկու հարյուր երեսուն միլիոներորդ")] [InlineData(1000000000, "մեկ միլիարդերորդ")] [InlineData(2000000000, "երկու միլիարդերորդ")] [InlineData(122, "հարյուր քսաներկուերորդ")] [InlineData(3501, "երեք հազար հինգ հարյուր մեկերորդ")] [InlineData(111, "հարյուր տասնմեկերորդ")] [InlineData(1112, "հազար հարյուր տասներկուերորդ")] [InlineData(11213, "տասնմեկ հազար երկու հարյուր տասներեքերորդ")] [InlineData(121314, "հարյուր քսանմեկ հազար երեք հարյուր տասնչորսերորդ")] [InlineData(2132415, "երկու միլիոն հարյուր երեսուներկու հազար չորս հարյուր տասնհինգերորդ")] [InlineData(12345516, "տասներկու միլիոն երեք հարյուր քառասունհինգ հազար հինգ հարյուր տասնվեցերորդ")] [InlineData(751633617, "յոթ հարյուր հիսունմեկ միլիոն վեց հարյուր երեսուներեք հազար վեց հարյուր տասնյոթերորդ")] [InlineData(1111111118, "մեկ միլիարդ հարյուր տասնմեկ միլիոն հարյուր տասնմեկ հազար հարյուր տասնութերորդ")] [InlineData(1111111000, "մեկ միլիարդ հարյուր տասնմեկ միլիոն հարյուր տասնմեկ հազարերորդ")] [InlineData(1234567000, "մեկ միլիարդ երկու հարյուր երեսունչորս միլիոն հինգ հարյուր վաթսունյոթ հազարերորդ")] [InlineData(-751633617, "մինուս յոթ հարյուր հիսունմեկ միլիոն վեց հարյուր երեսուներեք հազար վեց հարյուր տասնյոթերորդ")] public void ToOrdinalWords(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/hy/OrdinalizeTests.cs ================================================ namespace hy; [UseCulture("hy")] public class OrdinalizeTests { [Theory] [InlineData("0", "0-րդ")] [InlineData("1", "1-ին")] [InlineData("2", "2-րդ")] [InlineData("103", "103-րդ")] [InlineData("1001", "1001-րդ")] public void OrdinalizeStringMasculine(string number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Masculine), ordinalized); [Theory] [InlineData("0", "0-րդ")] [InlineData("1", "1-ին")] [InlineData("2", "2-րդ")] [InlineData("103", "103-րդ")] [InlineData("1001", "1001-րդ")] public void OrdinalizeStringFeminine(string number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Feminine), ordinalized); [Theory] [InlineData("0", "0-րդ")] [InlineData("1", "1-ին")] [InlineData("2", "2-րդ")] [InlineData("103", "103-րդ")] [InlineData("1001", "1001-րդ")] public void OrdinalizeStringNeuter(string number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Neuter), ordinalized); } ================================================ FILE: tests/Humanizer.Tests/Localisation/hy/TimeSpanHumanizeTests.cs ================================================ namespace hy; [UseCulture("hy")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Native speaker")] [InlineData(366, "մեկ տարի")] [InlineData(731, "2 տարի")] [InlineData(1096, "3 տարի")] [InlineData(4018, "11 տարի")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Native speaker")] [InlineData(31, "մեկ ամիս")] [InlineData(61, "2 ամիս")] [InlineData(92, "3 ամիս")] [InlineData(335, "11 ամիս")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(7, "մեկ շաբաթ")] [InlineData(14, "2 շաբաթ")] [InlineData(21, "3 շաբաթ")] [InlineData(28, "4 շաբաթ")] [InlineData(35, "5 շաբաթ")] [InlineData(77, "11 շաբաթ")] public void Weeks(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "մեկ օր")] [InlineData(2, "2 օր")] [InlineData(3, "3 օր")] [InlineData(4, "4 օր")] [InlineData(5, "5 օր")] [InlineData(6, "6 օր")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "մեկ ժամ")] [InlineData(2, "2 ժամ")] [InlineData(3, "3 ժամ")] [InlineData(4, "4 ժամ")] [InlineData(5, "5 ժամ")] [InlineData(6, "6 ժամ")] [InlineData(10, "10 ժամ")] [InlineData(11, "11 ժամ")] [InlineData(19, "19 ժամ")] [InlineData(20, "20 ժամ")] [InlineData(21, "21 ժամ")] [InlineData(22, "22 ժամ")] [InlineData(23, "23 ժամ")] public void Hours(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); [Theory] [InlineData(1, "մեկ րոպե")] [InlineData(2, "2 րոպե")] [InlineData(3, "3 րոպե")] [InlineData(4, "4 րոպե")] [InlineData(5, "5 րոպե")] [InlineData(6, "6 րոպե")] [InlineData(10, "10 րոպե")] [InlineData(11, "11 րոպե")] [InlineData(19, "19 րոպե")] [InlineData(20, "20 րոպե")] [InlineData(21, "21 րոպե")] [InlineData(22, "22 րոպե")] [InlineData(23, "23 րոպե")] [InlineData(24, "24 րոպե")] [InlineData(25, "25 րոպե")] [InlineData(40, "40 րոպե")] public void Minutes(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); [Theory] [InlineData(1, "մեկ վայրկյան")] [InlineData(2, "2 վայրկյան")] [InlineData(3, "3 վայրկյան")] [InlineData(4, "4 վայրկյան")] [InlineData(5, "5 վայրկյան")] [InlineData(6, "6 վայրկյան")] [InlineData(10, "10 վայրկյան")] [InlineData(11, "11 վայրկյան")] [InlineData(19, "19 վայրկյան")] [InlineData(20, "20 վայրկյան")] [InlineData(21, "21 վայրկյան")] [InlineData(22, "22 վայրկյան")] [InlineData(23, "23 վայրկյան")] [InlineData(24, "24 վայրկյան")] [InlineData(25, "25 վայրկյան")] [InlineData(40, "40 վայրկյան")] public void Seconds(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); [Theory] [InlineData(1, "մեկ միլիվայրկյան")] [InlineData(2, "2 միլիվայրկյան")] [InlineData(3, "3 միլիվայրկյան")] [InlineData(4, "4 միլիվայրկյան")] [InlineData(5, "5 միլիվայրկյան")] [InlineData(6, "6 միլիվայրկյան")] [InlineData(10, "10 միլիվայրկյան")] [InlineData(11, "11 միլիվայրկյան")] [InlineData(19, "19 միլիվայրկյան")] [InlineData(20, "20 միլիվայրկյան")] [InlineData(21, "21 միլիվայրկյան")] [InlineData(22, "22 միլիվայրկյան")] [InlineData(23, "23 միլիվայրկյան")] [InlineData(24, "24 միլիվայրկյան")] [InlineData(25, "25 միլիվայրկյան")] [InlineData(40, "40 միլիվայրկյան")] public void Milliseconds(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); [Fact] public void NoTime() => Assert.Equal("0 միլիվայրկյան", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => // This one doesn't make a lot of sense but ... w/e Assert.Equal("ժամանակը բացակայում է", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/id/DateHumanizeTests.cs ================================================ namespace id; [UseCulture("id-ID")] public class DateHumanizeTests { [Theory] [InlineData(1, "sedetik yang lalu")] [InlineData(10, "10 detik yang lalu")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "sedetik dari sekarang")] [InlineData(10, "10 detik dari sekarang")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(1, "semenit yang lalu")] [InlineData(10, "10 menit yang lalu")] [InlineData(60, "sejam yang lalu")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "semenit dari sekarang")] [InlineData(10, "10 menit dari sekarang")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(1, "sejam yang lalu")] [InlineData(10, "10 jam yang lalu")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "sejam dari sekarang")] [InlineData(10, "10 jam dari sekarang")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(1, "kemarin")] [InlineData(10, "10 hari yang lalu")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "besok")] [InlineData(10, "10 hari dari sekarang")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(1, "sebulan yang lalu")] [InlineData(10, "10 bulan yang lalu")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "sebulan dari sekarang")] [InlineData(10, "10 bulan dari sekarang")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(1, "setahun yang lalu")] [InlineData(2, "2 tahun yang lalu")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "setahun dari sekarang")] [InlineData(2, "2 tahun dari sekarang")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/id/TimeSpanHumanizeTests.cs ================================================ namespace id; [UseCulture("id-ID")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "1 tahun")] [InlineData(731, "2 tahun")] [InlineData(1096, "3 tahun")] [InlineData(4018, "11 tahun")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "1 bulan")] [InlineData(61, "2 bulan")] [InlineData(92, "3 bulan")] [InlineData(335, "11 bulan")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(14, "2 minggu")] [InlineData(7, "1 minggu")] public void Weeks(int days, string expected) { var actual = TimeSpan.FromDays(days).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 hari")] [InlineData(1, "1 hari")] public void Days(int days, string expected) { var actual = TimeSpan.FromDays(days).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 jam")] [InlineData(1, "1 jam")] public void Hours(int hours, string expected) { var actual = TimeSpan.FromHours(hours).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 menit")] [InlineData(1, "1 menit")] public void Minutes(int minutes, string expected) { var actual = TimeSpan.FromMinutes(minutes).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 detik")] [InlineData(1, "1 detik")] public void Seconds(int seconds, string expected) { var actual = TimeSpan.FromSeconds(seconds).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 milidetik")] [InlineData(1, "1 milidetik")] public void Milliseconds(int ms, string expected) { var actual = TimeSpan.FromMilliseconds(ms).Humanize(); Assert.Equal(expected, actual); } [Fact] public void NoTime() { var noTime = TimeSpan.Zero; var actual = noTime.Humanize(); Assert.Equal("0 milidetik", actual); } [Fact] public void NoTimeToWords() { var noTime = TimeSpan.Zero; var actual = noTime.Humanize(toWords: true); Assert.Equal("waktu kosong", actual); } } ================================================ FILE: tests/Humanizer.Tests/Localisation/invariant/NumberToWordsTests.cs ================================================ namespace invariant; [UseCulture("")] public class NumberToWordsTests { [InlineData(1, "one")] [InlineData(10, "ten")] [InlineData(11, "eleven")] [InlineData(20, "twenty")] [InlineData(122, "one hundred and twenty-two")] [InlineData(3501, "three thousand five hundred and one")] [InlineData(100, "one hundred")] [InlineData(1000, "one thousand")] [InlineData(100000, "one hundred thousand")] [InlineData(1000000, "one million")] [InlineData(10000000, "ten million")] [InlineData(100000000, "one hundred million")] [InlineData(1000000000, "one billion")] [InlineData(111, "one hundred and eleven")] [InlineData(1111, "one thousand one hundred and eleven")] [InlineData(111111, "one hundred and eleven thousand one hundred and eleven")] [InlineData(1111111, "one million one hundred and eleven thousand one hundred and eleven")] [InlineData(11111111, "eleven million one hundred and eleven thousand one hundred and eleven")] [InlineData(111111111, "one hundred and eleven million one hundred and eleven thousand one hundred and eleven")] [InlineData(1111111111, "one billion one hundred and eleven million one hundred and eleven thousand one hundred and eleven")] [InlineData(123, "one hundred and twenty-three")] [InlineData(1234, "one thousand two hundred and thirty-four")] [InlineData(12345, "twelve thousand three hundred and forty-five")] [InlineData(123456, "one hundred and twenty-three thousand four hundred and fifty-six")] [InlineData(1234567, "one million two hundred and thirty-four thousand five hundred and sixty-seven")] [InlineData(12345678, "twelve million three hundred and forty-five thousand six hundred and seventy-eight")] [InlineData(123456789, "one hundred and twenty-three million four hundred and fifty-six thousand seven hundred and eighty-nine")] [InlineData(1234567890, "one billion two hundred and thirty-four million five hundred and sixty-seven thousand eight hundred and ninety")] [Theory] public void ToWordsInt(int number, string expected) => Assert.Equal(expected, number.ToWords()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/invariant/ToQuantityTests.cs ================================================ namespace invariant; [UseCulture("")] public class ToQuantityTests { [Theory] [InlineData("case", 0, "0 cases")] [InlineData("case", 1, "1 case")] [InlineData("case", 5, "5 cases")] [InlineData("man", 0, "0 men")] [InlineData("man", 1, "1 man")] [InlineData("man", 2, "2 men")] [InlineData("men", 2, "2 men")] [InlineData("process", 2, "2 processes")] [InlineData("process", 1, "1 process")] [InlineData("processes", 2, "2 processes")] [InlineData("processes", 1, "1 process")] public void ToQuantity(string word, int quantity, string expected) => Assert.Equal(expected, word.ToQuantity(quantity)); [Theory] [InlineData("case", 0, "cases")] [InlineData("case", 1, "case")] [InlineData("case", 5, "cases")] [InlineData("man", 0, "men")] [InlineData("man", 1, "man")] [InlineData("man", 2, "men")] [InlineData("men", 2, "men")] [InlineData("process", 2, "processes")] [InlineData("process", 1, "process")] [InlineData("processes", 2, "processes")] [InlineData("processes", 1, "process")] public void ToQuantityWithNoQuantity(string word, int quantity, string expected) => Assert.Equal(expected, word.ToQuantity(quantity, ShowQuantityAs.None)); [Theory] [InlineData("case", 0, "0 cases")] [InlineData("case", 1, "1 case")] [InlineData("case", 5, "5 cases")] [InlineData("man", 0, "0 men")] [InlineData("man", 1, "1 man")] [InlineData("man", 2, "2 men")] [InlineData("men", 2, "2 men")] [InlineData("process", 2, "2 processes")] [InlineData("process", 1, "1 process")] [InlineData("processes", 2, "2 processes")] [InlineData("processes", 1, "1 process")] public void ToQuantityNumeric(string word, int quantity, string expected) => // ReSharper disable once RedundantArgumentDefaultValue Assert.Equal(expected, word.ToQuantity(quantity, ShowQuantityAs.Numeric)); [Theory] [InlineData("case", 0, "zero cases")] [InlineData("case", 1, "one case")] [InlineData("case", 5, "five cases")] [InlineData("man", 0, "zero men")] [InlineData("man", 1, "one man")] [InlineData("man", 2, "two men")] [InlineData("men", 2, "two men")] [InlineData("process", 2, "two processes")] [InlineData("process", 1, "one process")] [InlineData("processes", 2, "two processes")] [InlineData("processes", 1200, "one thousand two hundred processes")] [InlineData("processes", 1, "one process")] public void ToQuantityWords(string word, int quantity, string expected) => Assert.Equal(expected, word.ToQuantity(quantity, ShowQuantityAs.Words)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/is/Bytes/ByteSizeExtensionsTests.cs ================================================ namespace @is.Bytes; [UseCulture("is")] public class ByteSizeExtensionsTests { [Theory] [InlineData(2, null, "2 TB")] [InlineData(2, "GB", "2048 GB")] [InlineData(2.123, "#.#", "2,1 TB")] public void HumanizesTerabytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Terabytes().Humanize(format)); [Theory] [InlineData(0, null, "0 b")] [InlineData(0, "GB", "0 GB")] [InlineData(2, null, "2 GB")] [InlineData(2, "MB", "2048 MB")] [InlineData(2.123, "#.##", "2,12 GB")] public void HumanizesGigabytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Gigabytes().Humanize(format)); [Theory] [InlineData(0, null, "0 b")] [InlineData(0, "MB", "0 MB")] [InlineData(2, null, "2 MB")] [InlineData(2, "KB", "2048 kB")] [InlineData(2.123, "#", "2 MB")] public void HumanizesMegabytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Megabytes().Humanize(format)); [Theory] [InlineData(0, null, "0 b")] [InlineData(0, "KB", "0 kB")] [InlineData(2, null, "2 kB")] [InlineData(2, "B", "2048 B")] [InlineData(2.123, "#.####", "2,123 kB")] public void HumanizesKilobytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Kilobytes().Humanize(format)); [Theory] [InlineData(0, null, "0 b")] [InlineData(0, "#.##", "0 b")] [InlineData(0, "#.## B", "0 B")] [InlineData(0, "B", "0 B")] [InlineData(2, null, "2 B")] [InlineData(2000, "KB", "1,95 kB")] [InlineData(2123, "#.##", "2,07 kB")] [InlineData(10000000, "KB", "9765,63 kB")] [InlineData(10000000, "#,##0 KB", "9.766 kB")] [InlineData(10000000, "#,##0.# KB", "9.765,6 kB")] public void HumanizesBytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Bytes().Humanize(format)); [Theory] [InlineData(0, null, "0 b")] [InlineData(0, "b", "0 b")] [InlineData(2, null, "2 b")] [InlineData(12, "B", "1,5 B")] [InlineData(10000, "#.# KB", "1,2 kB")] public void HumanizesBits(long input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Bits().Humanize(format)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/is/Bytes/ToFullWordsTests.cs ================================================ namespace @is.Bytes; [UseCulture("is")] public class ToFullWordsTests { [Fact] public void ReturnsSingularBit() => Assert.Equal("1 biti", ByteSize.FromBits(1).ToFullWords()); [Fact] public void ReturnsPluralBits() => Assert.Equal("2 biti", ByteSize.FromBits(2).ToFullWords()); [Fact] public void ReturnsSingularByte() => Assert.Equal("1 bæti", ByteSize.FromBytes(1).ToFullWords()); [Fact] public void ReturnsPluralBytes() => Assert.Equal("10 bæti", ByteSize.FromBytes(10).ToFullWords()); [Fact] public void ReturnsSingularKiloByte() => Assert.Equal("1 kílóbæti", ByteSize.FromKilobytes(1).ToFullWords()); [Fact] public void ReturnsPluralKilobytes() => Assert.Equal("10 kílóbæti", ByteSize.FromKilobytes(10).ToFullWords()); [Fact] public void ReturnsSingularMegabyte() => Assert.Equal("1 megabæti", ByteSize.FromMegabytes(1).ToFullWords()); [Fact] public void ReturnsPluralMegabytes() => Assert.Equal("10 megabæti", ByteSize.FromMegabytes(10).ToFullWords()); [Fact] public void ReturnsSingularGigabyte() => Assert.Equal("1 gígabæti", ByteSize.FromGigabytes(1).ToFullWords()); [Fact] public void ReturnsPluralGigabytes() => Assert.Equal("10 gígabæti", ByteSize.FromGigabytes(10).ToFullWords()); [Fact] public void ReturnsSingularTerabyte() => Assert.Equal("1 terabæti", ByteSize.FromTerabytes(1).ToFullWords()); [Fact] public void ReturnsPluralTerabytes() => Assert.Equal("10 terabæti", ByteSize.FromTerabytes(10).ToFullWords()); [Theory] [InlineData(229376, "B", "229376 bæti")] [InlineData(229376, "# KB", "224 kílóbæti")] public void ToFullWordsFormatted(double input, string format, string expectedValue) => Assert.Equal(expectedValue, ByteSize.FromBytes(input).ToFullWords(format)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/is/Bytes/ToStringTests.cs ================================================ namespace @is.Bytes; [UseCulture("is")] public class ToStringTests { [Fact] public void ReturnsLargestMetricSuffix() => Assert.Equal("10,5 kB", ByteSize.FromKilobytes(10.5).ToString()); [Fact] public void ReturnsDefaultNumberFormat() => Assert.Equal("10,5 kB", ByteSize.FromKilobytes(10.5).ToString("KB")); [Fact] public void ReturnsProvidedNumberFormat() => Assert.Equal("10,1234 kB", ByteSize.FromKilobytes(10.1234).ToString("#.#### KB")); [Fact] public void ReturnsBits() => Assert.Equal("10 b", ByteSize.FromBits(10).ToString("##.#### b")); [Fact] public void ReturnsBytes() => Assert.Equal("10 B", ByteSize.FromBytes(10).ToString("##.#### B")); [Fact] public void ReturnsKilobytes() => Assert.Equal("10 kB", ByteSize.FromKilobytes(10).ToString("##.#### KB")); [Fact] public void ReturnsMegabytes() => Assert.Equal("10 MB", ByteSize.FromMegabytes(10).ToString("##.#### MB")); [Fact] public void ReturnsGigabytes() => Assert.Equal("10 GB", ByteSize.FromGigabytes(10).ToString("##.#### GB")); [Fact] public void ReturnsTerabytes() => Assert.Equal("10 TB", ByteSize.FromTerabytes(10).ToString("##.#### TB")); [Fact] public void ReturnsSelectedFormat() => Assert.Equal("10,0 TB", ByteSize.FromTerabytes(10).ToString("0.0 TB")); [Fact] public void ReturnsLargestMetricPrefixLargerThanZero() => Assert.Equal("512 kB", ByteSize.FromMegabytes(.5).ToString("#.#")); [Fact] public void ReturnsLargestMetricPrefixLargerThanZeroForNegativeValues() => Assert.Equal("-512 kB", ByteSize.FromMegabytes(-.5).ToString("#.#")); [Fact] public void ReturnsBytesViaGeneralFormat() => Assert.Equal("10 B", $"{ByteSize.FromBytes(10)}"); } ================================================ FILE: tests/Humanizer.Tests/Localisation/is/CollectionFormatterTests.cs ================================================ namespace @is; [UseCulture("is")] public class CollectionFormatterTests { [Fact] public void OneItem() { var collection = new List([1]); var humanized = "1"; Assert.Equal(humanized, collection.Humanize()); } [Fact] public void TwoItems() { var collection = new List([1, 2]); var humanized = "1 og 2"; Assert.Equal(humanized, collection.Humanize()); } [Fact] public void MoreThanTwoItems() { var collection = new List([1, 2, 3]); var humanized = "1, 2 og 3"; Assert.Equal(humanized, collection.Humanize()); } } ================================================ FILE: tests/Humanizer.Tests/Localisation/is/DateHumanizeTests.cs ================================================ namespace @is; [UseCulture("is")] public class DateHumanizeTests { [Theory] [InlineData(2, "fyrir 2 dögum")] [InlineData(1, "í gær")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(2, "eftir 2 daga")] [InlineData(1, "á morgun")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(2, "fyrir 2 klukkustundum")] [InlineData(1, "fyrir einni klukkustund")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(2, "eftir 2 klukkustundir")] [InlineData(1, "eftir eina klukkustund")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(-2, "fyrir 2 mínútum")] [InlineData(-1, "fyrir einni mínútu")] [InlineData(60, "fyrir einni klukkustund")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(2, "eftir 2 mínútur")] [InlineData(1, "eftir eina mínútu")] [InlineData(10, "eftir 10 mínútur")] [InlineData(59, "eftir 59 mínútur")] [InlineData(60, "eftir eina klukkustund")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(2, "fyrir 2 mánuðum")] [InlineData(1, "fyrir einum mánuði")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(2, "eftir 2 mánuði")] [InlineData(1, "eftir einn mánuð")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(2, "fyrir 2 sekúndum")] [InlineData(1, "fyrir einni sekúndu")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(2, "eftir 2 sekúndur")] [InlineData(1, "eftir eina sekúndu")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(2, "fyrir 2 árum")] [InlineData(1, "fyrir einu ári")] [InlineData(20, "fyrir 20 árum")] [InlineData(30, "fyrir 30 árum")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(2, "eftir 2 ár")] [InlineData(1, "eftir eitt ár")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Theory] [InlineData(0, "núna")] public void RightNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/is/HeadingTests.cs ================================================ namespace @is; [UseCulture("is")] public class HeadingTests { [InlineData(0, "N")] [InlineData(11.2, "N")] [InlineData(11.3, "NNA")] [InlineData(22.5, "NNA")] [InlineData(33.7, "NNA")] [InlineData(33.8, "NA")] [InlineData(45, "NA")] [InlineData(56.2, "NA")] [InlineData(56.3, "ANA")] [InlineData(67.5, "ANA")] [InlineData(78.7, "ANA")] [InlineData(78.8, "A")] [InlineData(90, "A")] [InlineData(101.2, "A")] [InlineData(101.3, "ASA")] [InlineData(112.5, "ASA")] [InlineData(123.7, "ASA")] [InlineData(123.8, "SA")] [InlineData(135, "SA")] [InlineData(146.2, "SA")] [InlineData(146.3, "SSA")] [InlineData(157.5, "SSA")] [InlineData(168.7, "SSA")] [InlineData(168.8, "S")] [InlineData(180, "S")] [InlineData(191.2, "S")] [InlineData(191.3, "SSV")] [InlineData(202.5, "SSV")] [InlineData(213.7, "SSV")] [InlineData(213.8, "SV")] [InlineData(225, "SV")] [InlineData(236.2, "SV")] [InlineData(236.3, "VSV")] [InlineData(247.5, "VSV")] [InlineData(258.7, "VSV")] [InlineData(258.8, "V")] [InlineData(270, "V")] [InlineData(281.2, "V")] [InlineData(281.3, "VNV")] [InlineData(292.5, "VNV")] [InlineData(303.7, "VNV")] [InlineData(303.8, "NV")] [InlineData(315, "NV")] [InlineData(326.2, "NV")] [InlineData(326.3, "NNV")] [InlineData(337.5, "NNV")] [InlineData(348.7, "NNV")] [InlineData(348.8, "N")] [InlineData(720, "N")] [Theory] public void ToHeadingAbbreviated(double heading, string expected) => Assert.Equal(expected, heading.ToHeading()); [InlineData(0, "norður")] [InlineData(45, "norðaustur")] [InlineData(67.5, "austnorðaustur")] [InlineData(90, "austur")] [InlineData(112.5, "austsuðaustur")] [InlineData(135, "suðaustur")] [InlineData(157.5, "suðsuðaustur")] [InlineData(180, "suður")] [InlineData(202.5, "suðsuðvestur")] [InlineData(225, "suðvestur")] [InlineData(247.5, "vestsuðvestur")] [InlineData(270, "vestur")] [InlineData(292.5, "vestnorðvestur")] [InlineData(315, "norðvestur")] [InlineData(337.5, "norðnorðvestur")] [InlineData(720, "norður")] [Theory] public void ToHeading(double heading, string expected) => Assert.Equal(expected, heading.ToHeading(HeadingStyle.Full)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/is/NumberToWordsTests.cs ================================================ namespace @is; [UseCulture("is")] public class NumberToWordsTests { [Theory] [InlineData(0, "núll")] [InlineData(1, "einn")] [InlineData(-10, "mínus tíu")] [InlineData(10, "tíu")] [InlineData(11, "ellefu")] [InlineData(122, "eitt hundrað tuttugu og tveir")] [InlineData(3501, "þrjú þúsund fimm hundruð og einn")] [InlineData(100, "eitt hundrað")] [InlineData(1000, "eitt þúsund")] [InlineData(100000, "eitt hundrað þúsund")] [InlineData(1000000, "ein milljón")] [InlineData(10000000, "tíu milljónir")] [InlineData(100000000, "eitt hundrað milljónir")] [InlineData(100000001L, "eitt hundrað milljónir og einn")] [InlineData(100000001L, "eitt hundrað milljónir og ein", GrammaticalGender.Feminine)] [InlineData(100000001L, "eitt hundrað milljónir og eitt", GrammaticalGender.Neuter)] [InlineData(100000002L, "eitt hundrað milljónir og tveir")] [InlineData(100001999L, "eitt hundrað milljónir eitt þúsund níu hundruð níutíu og níu")] [InlineData(100002000L, "eitt hundrað milljónir og tvö þúsund")] [InlineData(100002000L, "eitt hundrað milljónir og tvö þúsund", GrammaticalGender.Feminine)] [InlineData(100002000L, "eitt hundrað milljónir og tvö þúsund", GrammaticalGender.Neuter)] [InlineData(100002001L, "eitt hundrað milljónir tvö þúsund og einn")] [InlineData(100002002L, "eitt hundrað milljónir tvö þúsund og tveir")] [InlineData(100031999L, "eitt hundrað milljónir þrjátíu og eitt þúsund níu hundruð níutíu og níu")] [InlineData(1000000000, "einn milljarður")] [InlineData(111, "eitt hundrað og ellefu")] [InlineData(1111, "eitt þúsund eitt hundrað og ellefu")] [InlineData(111111, "eitt hundrað og ellefu þúsund eitt hundrað og ellefu")] [InlineData(1111111, "ein milljón eitt hundrað og ellefu þúsund eitt hundrað og ellefu")] [InlineData(11111111, "ellefu milljónir eitt hundrað og ellefu þúsund eitt hundrað og ellefu")] [InlineData(111111111, "eitt hundrað og ellefu milljónir eitt hundrað og ellefu þúsund eitt hundrað og ellefu")] [InlineData(1111111111, "einn milljarður eitt hundrað og ellefu milljónir eitt hundrað og ellefu þúsund eitt hundrað og ellefu")] [InlineData(10000000000L, "tíu milljarðar")] [InlineData(10000000001L, "tíu milljarðar og einn")] [InlineData(10000000002L, "tíu milljarðar og tveir")] [InlineData(123, "eitt hundrað tuttugu og þrír")] [InlineData(124, "eitt hundrað tuttugu og fjórir")] [InlineData(1234, "eitt þúsund tvö hundruð þrjátíu og fjórir")] [InlineData(12345, "tólf þúsund þrjú hundruð fjörutíu og fimm")] [InlineData(123456, "eitt hundrað tuttugu og þrjú þúsund fjögur hundruð fimmtíu og sex")] [InlineData(1234567, "ein milljón tvö hundruð þrjátíu og fjögur þúsund fimm hundruð sextíu og sjö")] [InlineData(12345678, "tólf milljónir þrjú hundruð fjörutíu og fimm þúsund sex hundruð sjötíu og átta")] [InlineData(123456789, "eitt hundrað tuttugu og þrjár milljónir fjögur hundruð fimmtíu og sex þúsund sjö hundruð áttatíu og níu")] [InlineData(1234567890, "einn milljarður tvö hundruð þrjátíu og fjórar milljónir fimm hundruð sextíu og sjö þúsund átta hundruð og níutíu")] [InlineData(1234567899, "einn milljarður tvö hundruð þrjátíu og fjórar milljónir fimm hundruð sextíu og sjö þúsund átta hundruð níutíu og níu")] [InlineData(108, "eitt hundrað og átta")] [InlineData(678, "sex hundruð sjötíu og átta")] [InlineData(2013, "tvö þúsund og þrettán")] [InlineData(2577, "tvö þúsund fimm hundruð sjötíu og sjö")] [InlineData(17053980, "sautján milljónir fimmtíu og þrjú þúsund níu hundruð og áttatíu")] [InlineData(415618, "fjögur hundruð og fimmtán þúsund sex hundruð og átján")] [InlineData(16415618, "sextán milljónir fjögur hundruð og fimmtán þúsund sex hundruð og átján")] [InlineData(322, "þrjú hundruð tuttugu og tveir")] [InlineData(322, "þrjú hundruð tuttugu og tvær", GrammaticalGender.Feminine)] public void IntToWords(long number, string expected, GrammaticalGender gender = GrammaticalGender.Masculine) => Assert.Equal(expected, number.ToWords(gender)); [Theory] [InlineData(100_000_000_000L, "eitt hundrað milljarðar")] [InlineData(1_000_000_000_000L, "ein billjón")] [InlineData(100_000_000_000_000L, "eitt hundrað billjónir")] [InlineData(1_000_000_000_000_000L, "einn billjarður")] [InlineData(100_000_000_000_000_000L, "eitt hundrað billjarðar")] [InlineData(1_000_000_000_000_000_000L, "ein trilljón")] [InlineData(9_223_372_036_854_775_807L, "níu trilljónir tvö hundruð tuttugu og þrír billjarðar þrjú hundruð sjötíu og tvær billjónir þrjátíu og sex milljarðar átta hundruð fimmtíu og fjórar milljónir sjö hundruð sjötíu og fimm þúsund átta hundruð og sjö")] public void LongToWords(long number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(0, "núllti")] [InlineData(1, "fyrsti")] [InlineData(2, "annar", GrammaticalGender.Masculine)] [InlineData(2, "önnur", GrammaticalGender.Feminine)] [InlineData(2, "annað", GrammaticalGender.Neuter)] [InlineData(3, "þriðji")] [InlineData(4, "fjórði")] [InlineData(5, "fimmti")] [InlineData(5, "fimmta", GrammaticalGender.Neuter)] [InlineData(6, "sjötti")] [InlineData(7, "sjöundi")] [InlineData(8, "áttundi")] [InlineData(9, "níundi")] [InlineData(10, "tíundi")] [InlineData(11, "ellefti")] [InlineData(12, "tólfti")] [InlineData(13, "þrettándi")] [InlineData(14, "fjórtándi")] [InlineData(15, "fimmtándi")] [InlineData(16, "sextándi")] [InlineData(17, "sautjándi")] [InlineData(18, "átjándi")] [InlineData(19, "nítjándi")] [InlineData(6, "sjötta", GrammaticalGender.Feminine)] [InlineData(7, "sjöunda", GrammaticalGender.Feminine)] [InlineData(8, "áttunda", GrammaticalGender.Feminine)] [InlineData(9, "níunda", GrammaticalGender.Feminine)] [InlineData(10, "tíunda", GrammaticalGender.Feminine)] [InlineData(11, "ellefta", GrammaticalGender.Feminine)] [InlineData(12, "tólfta", GrammaticalGender.Feminine)] [InlineData(13, "þrettánda", GrammaticalGender.Feminine)] [InlineData(14, "fjórtánda", GrammaticalGender.Feminine)] [InlineData(15, "fimmtánda", GrammaticalGender.Feminine)] [InlineData(16, "sextánda", GrammaticalGender.Feminine)] [InlineData(17, "sautjánda", GrammaticalGender.Feminine)] [InlineData(18, "átjánda", GrammaticalGender.Feminine)] [InlineData(19, "nítjánda", GrammaticalGender.Feminine)] [InlineData(20, "tuttugasti")] [InlineData(21, "tuttugasti og fyrsti")] [InlineData(22, "tuttugasti og annar")] [InlineData(30, "þrítugasti")] [InlineData(40, "fertugasti")] [InlineData(50, "fimmtugasti")] [InlineData(60, "sextugasti")] [InlineData(70, "sjötugasti")] [InlineData(80, "áttugasti")] [InlineData(90, "nítugasti")] [InlineData(95, "nítugasti og fimmti")] [InlineData(96, "nítugasti og sjötti")] [InlineData(44, "fertugasta og fjórða", GrammaticalGender.Feminine)] [InlineData(44, "fertugasti og fjórði")] [InlineData(77, "sjötugasti og sjöundi")] [InlineData(87, "áttugasta og sjöunda", GrammaticalGender.Feminine)] [InlineData(99, "nítugasta og níunda", GrammaticalGender.Neuter)] [InlineData(100, "eitt hundraðasti")] [InlineData(101, "eitt hundraðasti og fyrsti")] [InlineData(106, "eitt hundraðasti og sjötti")] [InlineData(108, "eitt hundraðasti og áttundi")] [InlineData(112, "eitt hundraðasti og tólfti")] [InlineData(119, "eitt hundraðasti og nítjándi")] [InlineData(120, "eitt hundrað og tuttugasti")] [InlineData(121, "eitt hundrað tuttugasti og fyrsti")] [InlineData(130, "eitt hundrað og þrítugasti")] [InlineData(131, "eitt hundrað þrítugasti og fyrsti")] [InlineData(1000, "eitt þúsundasta", GrammaticalGender.Feminine)] [InlineData(1001, "eitt þúsundasti og fyrsti")] [InlineData(1005, "eitt þúsundasti og fimmti")] [InlineData(1008, "eitt þúsundasti og áttundi")] [InlineData(1012, "eitt þúsundasti og tólfti")] [InlineData(1021, "eitt þúsund tuttugasti og fyrsti")] [InlineData(10000, "tíu þúsundasti")] [InlineData(10121, "tíu þúsund eitt hundrað tuttugasti og fyrsti")] [InlineData(100000, "eitt hundrað þúsundasti")] [InlineData(100001, "eitt hundrað þúsundasti og fyrsti")] [InlineData(1000000, "ein milljónasti")] [InlineData(2000000, "tvær milljónasti")] // https://www.mbl.is/frettir/innlent/2012/12/19/tvo_milljonasti_eda_tvimilljonasti/ [InlineData(1530, "eitt þúsund fimm hundruð og þrítugasti")] [InlineData(530, "fimm hundruð og þrítugasti")] [InlineData(2070, "tvö þúsund og sjötugasti")] [InlineData(4444, "fjögur þúsund fjögur hundruð fertugasti og fjórði")] [InlineData(267, "tvö hundruð sextugasti og sjöundi")] [InlineData(700, "sjö hundruðasti")] [InlineData(707, "sjö hundruðasti og sjöundi")] [InlineData(717, "sjö hundruðasti og sautjándi")] [InlineData(777, "sjö hundruð sjötugasti og sjöundi")] [InlineData(3019, "þrjú þúsundasti og nítjándi")] [InlineData(5315, "fimm þúsund þrjú hundruðasti og fimmtándi")] [InlineData(6471, "sex þúsund fjögur hundruð sjötugasti og fyrsti")] [InlineData(7000, "sjö þúsundasti")] [InlineData(7007, "sjö þúsundasti og sjöundi")] [InlineData(7017, "sjö þúsundasti og sautjándi")] [InlineData(7777, "sjö þúsund sjö hundruð sjötugasti og sjöundi")] [InlineData(5315, "fimm þúsund þrjú hundruðasta og fimmtánda", GrammaticalGender.Feminine)] [InlineData(1044, "eitt þúsund fertugasti og fjórði")] [InlineData(315, "þrjú hundruðasti og fimmtándi")] [InlineData(777, "sjö hundruð sjötugasta og sjöunda", GrammaticalGender.Neuter)] [InlineData(102000, "eitt hundrað og tvö þúsundasti")] [InlineData(1002000, "ein milljón og tvö þúsundasti")] public void ToOrdinalWords(int number, string words, GrammaticalGender gender = GrammaticalGender.Masculine) => Assert.Equal(words, number.ToOrdinalWords(gender)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/is/OrdinalizeTests.cs ================================================ namespace @is; [UseCulture("is")] public class OrdinalizeTests { [Theory] [InlineData("0", "0.")] [InlineData("1", "1.")] [InlineData("2", "2.")] [InlineData("3", "3.")] [InlineData("4", "4.")] [InlineData("5", "5.")] [InlineData("6", "6.")] [InlineData("23", "23.")] [InlineData("100", "100.")] [InlineData("101", "101.")] [InlineData("102", "102.")] [InlineData("103", "103.")] [InlineData("1001", "1001.")] public void OrdinalizeString(string number, string ordinalized) => Assert.Equal(ordinalized, number.Ordinalize()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/is/ResourcesTests.cs ================================================ namespace @is; public class ResourcesTests { [Fact] [UseCulture("is")] public void GetCultureSpecificTranslationsWithImplicitCulture() { var format = Resources.GetResource("DateHumanize_MultipleYearsAgo"); Assert.Equal("fyrir {0} árum", format); } [Fact] public void GetCultureSpecificTranslationsWithExplicitCulture() { var format = Resources.GetResource("DateHumanize_SingleYearAgo", new("is")); Assert.Equal("fyrir einu ári", format); } } ================================================ FILE: tests/Humanizer.Tests/Localisation/is/TimeOnlyHumanizeTests.cs ================================================ #if NET6_0_OR_GREATER namespace @is; [UseCulture("is")] public class TimeOnlyHumanizeTests { [Theory] [InlineData("13:07:05", "13:07:05", "núna")] [InlineData("13:08:05", "1:08:05", "eftir 12 klukkustundir")] [InlineData("13:08:05", "13:38:05", "fyrir 30 mínútum")] [InlineData("13:07:02", "17:07:05", "fyrir 4 klukkustundum")] public void DefaultStrategy(string inputTime, string timeToCompareAgainst, string expectedResult) { Configurator.TimeOnlyHumanizeStrategy = new DefaultTimeOnlyHumanizeStrategy(); var parsedInputTime = TimeOnly.Parse(inputTime); var parsedBaseTime = TimeOnly.Parse(timeToCompareAgainst); var actualResult = parsedInputTime.Humanize(parsedBaseTime); Assert.Equal(expectedResult, actualResult); } [Theory] [InlineData("18:10:49", "13:07:04", "eftir 5 klukkustundir", 0.75)] [InlineData("13:10:49", "13:07:04", "eftir 4 mínútur", 0.5)] [InlineData("18:10:49", "13:07:04", "eftir 5 klukkustundir", 1.0)] public void PrecisionStrategy(string inputTime, string timeToCompareAgainst, string expectedResult, double precision) { Configurator.TimeOnlyHumanizeStrategy = new PrecisionTimeOnlyHumanizeStrategy(precision); var parsedInputTime = TimeOnly.Parse(inputTime); var parsedBaseTime = TimeOnly.Parse(timeToCompareAgainst); var actualResult = parsedInputTime.Humanize(parsedBaseTime); Assert.Equal(expectedResult, actualResult); } [Fact] public void TestNever() => Assert.Equal("aldrei", ((TimeOnly?)null).Humanize()); } #endif ================================================ FILE: tests/Humanizer.Tests/Localisation/is/TimeSpanHumanizeTests.cs ================================================ namespace @is; [UseCulture("is")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Native speaker")] [InlineData(366, "1 ár")] [InlineData(731, "2 ár")] [InlineData(1096, "3 ár")] [InlineData(4018, "11 ár")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Native speaker")] [InlineData(366, "eitt ár")] [InlineData(731, "tvö ár")] [InlineData(1096, "þrjú ár")] [InlineData(4018, "ellefu ár")] public void YearsToWords(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year, toWords: true)); [Theory] [Trait("Translation", "Native speaker")] [InlineData(31, "1 mánuður")] [InlineData(61, "2 mánuðir")] [InlineData(92, "3 mánuðir")] [InlineData(335, "11 mánuðir")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Native speaker")] [InlineData(31, "einn mánuður")] [InlineData(61, "tveir mánuðir")] [InlineData(92, "þrír mánuðir")] [InlineData(335, "ellefu mánuðir")] public void MonthsToWords(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year, toWords: true)); [Theory] [InlineData(7, "ein vika")] [InlineData(14, "2 vikur")] [InlineData(21, "3 vikur")] [InlineData(77, "11 vikur")] public void Weeks(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(7, "ein vika")] [InlineData(14, "tvær vikur")] [InlineData(21, "þrjár vikur")] [InlineData(77, "ellefu vikur")] public void WeeksToWords(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(toWords: true)); [Theory] [InlineData(1, "einn dagur")] [InlineData(2, "2 dagar")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "einn dagur")] [InlineData(2, "tveir dagar")] public void DaysToWords(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(toWords: true)); [Theory] [InlineData(1, "ein klukkustund")] [InlineData(2, "2 klukkustundir")] public void Hours(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); [Theory] [InlineData(1, "ein klukkustund")] [InlineData(2, "tvær klukkustundir")] public void HoursToWords(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize(toWords: true)); [Theory] [InlineData(1, "ein mínúta")] [InlineData(2, "2 mínútur")] public void Minutes(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); [Theory] [InlineData(1, "ein mínúta")] [InlineData(2, "tvær mínútur")] public void MinutesToWords(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize(toWords: true)); [Theory] [InlineData(1, "ein sekúnda")] [InlineData(2, "2 sekúndur")] public void Seconds(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); [Theory] [InlineData(1, "ein sekúnda")] [InlineData(2, "tvær sekúndur")] public void SecondsToWords(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize(toWords: true)); [Theory] [InlineData(1, "ein millisekúnda")] [InlineData(2, "2 millisekúndur")] public void Milliseconds(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); [Theory] [InlineData(1, "ein millisekúnda")] [InlineData(2, "tvær millisekúndur")] public void MillisecondsToWords(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize(toWords: true)); [Fact] public void NoTime() => Assert.Equal("0 millisekúndur", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => // This one doesn't make a lot of sense but ... w/e Assert.Equal("engin stund", TimeSpan.Zero.Humanize(toWords: true)); [Theory] [InlineData(1299630020, 5, "tvær vikur, einn dagur, ein klukkustund, þrjátíu sekúndur, tuttugu millisekúndur")] public void TimeSpanWithNumbersConvertedToWords(int milliseconds, int precision, string expected) { var actual = TimeSpan.FromMilliseconds(milliseconds).Humanize(precision, toWords: true); Assert.Equal(expected, actual); } } ================================================ FILE: tests/Humanizer.Tests/Localisation/it/CollectionFormatterTests.cs ================================================ namespace it; [UseCulture("it")] public class CollectionFormatterTests { [Fact] public void OneItem() { var collection = new List([1]); var humanized = "1"; Assert.Equal(humanized, collection.Humanize()); } [Fact] public void TwoItems() { var collection = new List([1, 2]); var humanized = "1 e 2"; Assert.Equal(humanized, collection.Humanize()); } [Fact] public void MoreThanTwoItems() { var collection = new List([1, 2, 3]); var humanized = "1, 2 e 3"; Assert.Equal(humanized, collection.Humanize()); } } ================================================ FILE: tests/Humanizer.Tests/Localisation/it/DateHumanizeTests.cs ================================================ namespace it; [UseCulture("it")] public class DateHumanizeTests { [Theory] [InlineData(-2, "2 giorni fa")] [InlineData(-1, "ieri")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(2, "tra 2 giorni")] [InlineData(1, "domani")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(-2, "2 ore fa")] [InlineData(-1, "un'ora fa")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(2, "tra 2 ore")] [InlineData(1, "tra un'ora")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(-2, "2 minuti fa")] [InlineData(-1, "un minuto fa")] [InlineData(60, "un'ora fa")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(2, "tra 2 minuti")] [InlineData(1, "tra un minuto")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(-2, "2 mesi fa")] [InlineData(-1, "un mese fa")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(2, "tra 2 mesi")] [InlineData(1, "tra un mese")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(-2, "2 secondi fa")] [InlineData(-1, "un secondo fa")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(2, "tra 2 secondi")] [InlineData(1, "tra un secondo")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(-2, "2 anni fa")] [InlineData(-1, "un anno fa")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(2, "tra 2 anni")] [InlineData(1, "tra un anno")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Theory] [InlineData(0, "adesso")] public void Now(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/it/NumberToWordsTests.cs ================================================ namespace it; [UseCulture("it")] public class NumberToWordsTests { [Theory] [InlineData(0, "zero")] [InlineData(1, "uno")] [InlineData(-1, "meno uno")] [InlineData(3, "tre")] [InlineData(10, "dieci")] [InlineData(11, "undici")] [InlineData(21, "ventuno")] [InlineData(38, "trentotto")] [InlineData(122, "centoventidue")] [InlineData(3501, "tremilacinquecentouno")] [InlineData(-3501, "meno tremilacinquecentouno")] [InlineData(100, "cento")] [InlineData(1000, "mille")] [InlineData(2000, "duemila")] [InlineData(10000, "diecimila")] [InlineData(100000, "centomila")] [InlineData(1000000, "un milione")] [InlineData(5000000, "cinque milioni")] [InlineData(10000000, "dieci milioni")] [InlineData(100000000, "cento milioni")] [InlineData(1000000000, "un miliardo")] [InlineData(2000000000, "due miliardi")] [InlineData(2147483647, "due miliardi centoquarantasette milioni quattrocentoottantatremilaseicentoquarantasette")] // int.MaxValue //[InlineData(9000000000, "nove miliardi")] // int = System.Int32, fixed in API, is not big enough //[InlineData(10000000000, "dieci miliardi")] // int = System.Int32, fixed in API, is not big enough //[InlineData(100000000000, "cento miliardi")] // int = System.Int32, fixed in API, is not big enough [InlineData(101, "centouno")] [InlineData(1001, "milleuno")] [InlineData(10001, "diecimilauno")] [InlineData(100001, "centomilauno")] [InlineData(1000001, "un milione uno")] [InlineData(10000001, "dieci milioni uno")] [InlineData(100000001, "cento milioni uno")] [InlineData(1000000001, "un miliardo uno")] [InlineData(111, "centoundici")] [InlineData(1111, "millecentoundici")] [InlineData(111111, "centoundicimilacentoundici")] [InlineData(1111101, "un milione centoundicimilacentouno")] [InlineData(1111111, "un milione centoundicimilacentoundici")] [InlineData(11111111, "undici milioni centoundicimilacentoundici")] [InlineData(111111111, "centoundici milioni centoundicimilacentoundici")] [InlineData(1101111101, "un miliardo centouno milioni centoundicimilacentouno")] [InlineData(1111111111, "un miliardo centoundici milioni centoundicimilacentoundici")] [InlineData(8100, "ottomilacento")] [InlineData(43, "quarantatré")] // Ref. http://dizionari.corriere.it/dizionario-si-dice/V/ventitre.shtml [InlineData(123, "centoventitré")] [InlineData(1234, "milleduecentotrentaquattro")] [InlineData(12345, "dodicimilatrecentoquarantacinque")] [InlineData(123456, "centoventitremilaquattrocentocinquantasei")] [InlineData(1234567, "un milione duecentotrentaquattromilacinquecentosessantasette")] [InlineData(12345678, "dodici milioni trecentoquarantacinquemilaseicentosettantotto")] [InlineData(123456789, "centoventitré milioni quattrocentocinquantaseimilasettecentoottantanove")] [InlineData(1234567890, "un miliardo duecentotrentaquattro milioni cinquecentosessantasettemilaottocentonovanta")] [InlineData(1999, "millenovecentonovantanove")] [InlineData(2014, "duemilaquattordici")] [InlineData(2048, "duemilaquarantotto")] public void ToWords(int number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(0, "zero")] [InlineData(1, "una")] [InlineData(-1, "meno una")] [InlineData(3, "tre")] [InlineData(21, "ventuno")] [InlineData(101, "centouno")] [InlineData(1001, "milleuno")] [InlineData(10001, "diecimilauno")] [InlineData(100001, "centomilauno")] public void ToFeminineWords(int number, string expected) => Assert.Equal(expected, number.ToWords(GrammaticalGender.Feminine)); [Theory] [InlineData(0, "zero")] [InlineData(1, "uno")] [InlineData(-1, "meno uno")] [InlineData(3, "tre")] [InlineData(21, "ventuno")] [InlineData(101, "centouno")] [InlineData(1001, "milleuno")] [InlineData(10001, "diecimilauno")] [InlineData(100001, "centomilauno")] public void ToMasculineWords(int number, string expected) => Assert.Equal(expected, number.ToWords(GrammaticalGender.Masculine)); [Theory] [InlineData(0, "zero")] [InlineData(1, "primo")] [InlineData(2, "secondo")] [InlineData(9, "nono")] [InlineData(10, "decimo")] [InlineData(11, "undicesimo")] [InlineData(15, "quindicesimo")] [InlineData(18, "diciottesimo")] [InlineData(20, "ventesimo")] [InlineData(21, "ventunesimo")] [InlineData(22, "ventiduesimo")] [InlineData(28, "ventottesimo")] [InlineData(30, "trentesimo")] [InlineData(44, "quarantaquattresimo")] [InlineData(55, "cinquantacinquesimo")] [InlineData(60, "sessantesimo")] [InlineData(63, "sessantatreesimo")] [InlineData(66, "sessantaseiesimo")] [InlineData(77, "settantasettesimo")] [InlineData(88, "ottantottesimo")] [InlineData(99, "novantanovesimo")] [InlineData(100, "centesimo")] [InlineData(101, "centounesimo")] [InlineData(102, "centoduesimo")] [InlineData(105, "centocinquesimo")] [InlineData(109, "centonovesimo")] [InlineData(110, "centodecimo")] [InlineData(119, "centodiciannovesimo")] [InlineData(120, "centoventesimo")] [InlineData(121, "centoventunesimo")] [InlineData(200, "duecentesimo")] [InlineData(201, "duecentounesimo")] [InlineData(240, "duecentoquarantesimo")] [InlineData(300, "trecentesimo")] [InlineData(900, "novecentesimo")] [InlineData(1000, "millesimo")] [InlineData(1001, "milleunesimo")] [InlineData(1002, "milleduesimo")] [InlineData(1003, "milletreesimo")] [InlineData(1009, "millenovesimo")] [InlineData(1010, "milledecimo")] [InlineData(1021, "milleventunesimo")] [InlineData(2000, "duemillesimo")] [InlineData(2001, "duemilaunesimo")] [InlineData(3000, "tremillesimo")] [InlineData(10000, "diecimillesimo")] [InlineData(10001, "diecimilaunesimo")] [InlineData(10121, "diecimilacentoventunesimo")] [InlineData(100000, "centomillesimo")] [InlineData(100001, "centomilaunesimo")] [InlineData(1000000, "milionesimo")] [InlineData(1000001, "un milione unesimo")] [InlineData(1000002, "un milione duesimo")] [InlineData(2000000, "duemilionesimo")] [InlineData(10000000, "diecimilionesimo")] [InlineData(100000000, "centomilionesimo")] [InlineData(1000000000, "miliardesimo")] [InlineData(2000000000, "duemiliardesimo")] public void ToOrdinalWords(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords()); [Theory] [InlineData(0, "zero")] [InlineData(1, "prima")] [InlineData(2, "seconda")] [InlineData(5, "quinta")] [InlineData(9, "nona")] [InlineData(10, "decima")] [InlineData(11, "undicesima")] [InlineData(18, "diciottesima")] [InlineData(20, "ventesima")] [InlineData(21, "ventunesima")] [InlineData(100, "centesima")] [InlineData(101, "centounesima")] [InlineData(200, "duecentesima")] [InlineData(1000, "millesima")] [InlineData(1001, "milleunesima")] [InlineData(10000, "diecimillesima")] public void ToFeminineOrdinalWords(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Feminine)); [Theory] [InlineData(0, "zero")] [InlineData(1, "primo")] [InlineData(2, "secondo")] [InlineData(5, "quinto")] [InlineData(9, "nono")] [InlineData(10, "decimo")] [InlineData(11, "undicesimo")] [InlineData(18, "diciottesimo")] [InlineData(20, "ventesimo")] [InlineData(21, "ventunesimo")] [InlineData(100, "centesimo")] [InlineData(101, "centounesimo")] [InlineData(200, "duecentesimo")] [InlineData(1000, "millesimo")] [InlineData(1001, "milleunesimo")] [InlineData(10000, "diecimillesimo")] public void ToMasculineOrdinalWords(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Masculine)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/it/OrdinalizerTests.cs ================================================ namespace it; [UseCulture("it")] public class OrdinalizerTests { [Theory] [InlineData(0, "0")] // No ordinal for 0 in italian (neologism apart) [InlineData(1, "1°")] [InlineData(11, "11°")] [InlineData(111, "111°")] public void GenderlessNumber(int number, string expected) => Assert.Equal(expected, number.Ordinalize()); [Theory] [InlineData("0", "0")] // No ordinal for 0 in italian (neologism apart) [InlineData("1", "1°")] [InlineData("11", "11°")] [InlineData("111", "111°")] public void GenderlessText(string number, string expected) => Assert.Equal(expected, number.Ordinalize()); [Theory] [InlineData(0, "0")] // No ordinal for 0 in italian (neologism apart) [InlineData(1, "1°")] [InlineData(11, "11°")] [InlineData(111, "111°")] public void MasculineNumber(int number, string expected) => Assert.Equal(expected, number.Ordinalize(GrammaticalGender.Masculine)); [Theory] [InlineData("0", "0")] // No ordinal for 0 in italian (neologism apart) [InlineData("1", "1°")] [InlineData("11", "11°")] [InlineData("111", "111°")] public void MasculineText(string number, string expected) => Assert.Equal(expected, number.Ordinalize(GrammaticalGender.Masculine)); [Theory] [InlineData(0, "0")] // No ordinal for 0 in italian (neologism apart) [InlineData(1, "1ª")] [InlineData(11, "11ª")] [InlineData(111, "111ª")] public void FeminineNumber(int number, string expected) => Assert.Equal(expected, number.Ordinalize(GrammaticalGender.Feminine)); [Theory] [InlineData("0", "0")] // No ordinal for 0 in italian (neologism apart) [InlineData("1", "1ª")] [InlineData("11", "11ª")] [InlineData("111", "111ª")] public void FeminineText(string number, string expected) => Assert.Equal(expected, number.Ordinalize(GrammaticalGender.Feminine)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/it/TimeSpanHumanizeTests.cs ================================================ namespace it; [UseCulture("it")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "1 anno")] [InlineData(366, "un anno", true)] [InlineData(731, "2 anni")] [InlineData(1096, "3 anni")] [InlineData(4018, "11 anni")] public void Years(int days, string expected, bool toWords = false) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year, toWords: toWords)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "1 mese")] [InlineData(31, "un mese", true)] [InlineData(61, "2 mesi")] [InlineData(92, "3 mesi")] [InlineData(335, "11 mesi")] public void Months(int days, string expected, bool toWords = false) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year, toWords: toWords)); [Theory] [InlineData(7, "1 settimana")] [InlineData(7, "una settimana", true)] [InlineData(14, "2 settimane")] public void Weeks(int days, string expected, bool toWords = false) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(toWords: toWords)); [Theory] [InlineData(1, "1 giorno")] [InlineData(1, "un giorno", true)] [InlineData(2, "2 giorni")] public void Days(int days, string expected, bool toWords = false) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(toWords: toWords)); [Theory] [InlineData(1, "1 ora")] [InlineData(1, "una ora", true)] [InlineData(2, "2 ore")] public void Hours(int hours, string expected, bool toWords = false) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize(toWords: toWords)); [Theory] [InlineData(1, "1 minuto")] [InlineData(1, "un minuto", true)] [InlineData(2, "2 minuti")] public void Minutes(int minutes, string expected, bool toWords = false) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize(toWords: toWords)); [Theory] [InlineData(1, "1 secondo")] [InlineData(1, "un secondo", true)] [InlineData(2, "2 secondi")] public void Seconds(int seconds, string expected, bool toWords = false) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize(toWords: toWords)); [Theory] [InlineData(1, "1 millisecondo")] [InlineData(1, "un millisecondo", true)] [InlineData(2, "2 millisecondi")] public void Milliseconds(int milliseconds, string expected, bool toWords = false) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize(toWords: toWords)); [Fact] public void NoTime() => Assert.Equal("0 millisecondi", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => // This does not make much sense in italian, anyway Assert.Equal("0 secondi", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ja/DateHumanizeTests.cs ================================================ namespace ja; [UseCulture("ja")] public class DateHumanizeTests { [Theory] [InlineData(1, "1 秒前")] [InlineData(2, "2 秒前")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "1 秒後")] [InlineData(2, "2 秒後")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(1, "1 分前")] [InlineData(2, "2 分前")] [InlineData(60, "1 時間前")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "1 分後")] [InlineData(2, "2 分後")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(1, "1 時間前")] [InlineData(2, "2 時間前")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "1 時間後")] [InlineData(2, "2 時間後")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(1, "昨日")] [InlineData(2, "2 日前")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "明日")] [InlineData(2, "2 日後")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(1, "先月")] [InlineData(2, "2 か月前")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "来月")] [InlineData(2, "2 か月後")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(1, "去年")] [InlineData(2, "2 年前")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "来年")] [InlineData(2, "2 年後")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Fact] public void Now() => DateHumanize.Verify("今", 0, TimeUnit.Day, Tense.Past); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ja/NumberToWordsTests.cs ================================================ namespace ja; [UseCulture("ja")] public class NumberToWordsTests { [Theory] [InlineData(0, "〇")] [InlineData(1, "一")] [InlineData(10, "十")] [InlineData(11, "十一")] [InlineData(122, "百二十二")] [InlineData(3501, "三千五百一")] [InlineData(100, "百")] [InlineData(1000, "千")] [InlineData(10000, "一万")] [InlineData(100000, "十万")] [InlineData(1000000, "百万")] [InlineData(10000000, "千万")] [InlineData(100000000, "一億")] [InlineData(1000000000, "十億")] [InlineData(111, "百十一")] [InlineData(1111, "千百十一")] [InlineData(11111, "一万千百十一")] [InlineData(111111, "十一万千百十一")] [InlineData(1111111, "百十一万千百十一")] [InlineData(11111111, "千百十一万千百十一")] [InlineData(111111111, "一億千百十一万千百十一")] [InlineData(1111111111, "十一億千百十一万千百十一")] [InlineData(123, "百二十三")] [InlineData(1234, "千二百三十四")] [InlineData(12345, "一万二千三百四十五")] [InlineData(123456, "十二万三千四百五十六")] [InlineData(1234567, "百二十三万四千五百六十七")] [InlineData(12345678, "千二百三十四万五千六百七十八")] [InlineData(123456789, "一億二千三百四十五万六千七百八十九")] [InlineData(1234567890, "十二億三千四百五十六万七千八百九十")] [InlineData(-123, "マイナス 百二十三")] public void ToWordsInt(int number, string expected) => 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, "百十一京千百十一兆千百十一億千百十一万千百十一")] public void ToWordsLong(long number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(0, "〇番目")] [InlineData(1, "一番目")] [InlineData(2, "二番目")] [InlineData(3, "三番目")] [InlineData(10, "十番目")] [InlineData(11, "十一番目")] [InlineData(100, "百番目")] [InlineData(112, "百十二番目")] [InlineData(1000000, "百万番目")] public void ToOrdinalWords(int number, string words) => Assert.Equal(words, number.ToOrdinalWords()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ja/TimeSpanHumanizeTests.cs ================================================ namespace ja; [UseCulture("ja")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "1 年")] [InlineData(731, "2 年")] [InlineData(1096, "3 年")] [InlineData(4018, "11 年")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "1 ヶ月")] [InlineData(61, "2 ヶ月")] [InlineData(92, "3 ヶ月")] [InlineData(335, "11 ヶ月")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(7, "1 週間")] [InlineData(14, "2 週間")] public void Weeks(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "1 日")] [InlineData(2, "2 日")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "1 時間")] [InlineData(2, "2 時間")] public void Hours(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); [Theory] [InlineData(1, "1 分")] [InlineData(2, "2 分")] public void Minutes(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); [Theory] [InlineData(1, "1 秒")] [InlineData(2, "2 秒")] public void Seconds(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); [Theory] [InlineData(1, "1 ミリ秒")] [InlineData(2, "2 ミリ秒")] public void Milliseconds(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); [Fact] public void NoTime() => Assert.Equal("0 ミリ秒", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => Assert.Equal("0 秒", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ko-KR/NumberToWordsTests.cs ================================================ namespace koKR; [UseCulture("ko-KR")] public class NumberToWordsTests { [Theory] [InlineData(0, "영")] [InlineData(1, "일")] [InlineData(10, "십")] [InlineData(11, "십일")] [InlineData(122, "백이십이")] [InlineData(3501, "삼천오백일")] [InlineData(100, "백")] [InlineData(1000, "천")] [InlineData(10000, "일만")] [InlineData(100000, "십만")] [InlineData(1000000, "백만")] [InlineData(10000000, "천만")] [InlineData(100000000, "일억")] [InlineData(1000000000, "십억")] [InlineData(111, "백십일")] [InlineData(1111, "천백십일")] [InlineData(11111, "일만천백십일")] [InlineData(111111, "십일만천백십일")] [InlineData(1111111, "백십일만천백십일")] [InlineData(11111111, "천백십일만천백십일")] [InlineData(111111111, "일억천백십일만천백십일")] [InlineData(1111111111, "십일억천백십일만천백십일")] [InlineData(123, "백이십삼")] [InlineData(1234, "천이백삼십사")] [InlineData(12345, "일만이천삼백사십오")] [InlineData(123456, "십이만삼천사백오십육")] [InlineData(1234567, "백이십삼만사천오백육십칠")] [InlineData(12345678, "천이백삼십사만오천육백칠십팔")] [InlineData(123456789, "일억이천삼백사십오만육천칠백팔십구")] [InlineData(1234567890, "십이억삼천사백오십육만칠천팔백구십")] [InlineData(-123, "마이너스 백이십삼")] public void ToWordsInt(int number, string expected) => 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, "백십일경천백십일조천백십일억천백십일만천백십일")] public void ToWordsLong(long number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(0, "영번째")] [InlineData(1, "첫번째")] [InlineData(2, "두번째")] [InlineData(3, "세번째")] [InlineData(10, "열번째")] [InlineData(11, "열한번째")] [InlineData(100, "백번째")] [InlineData(112, "백십이번째")] [InlineData(1000000, "백만번째")] public void ToOrdinalWords(int number, string words) => Assert.Equal(words, number.ToOrdinalWords()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ko-KR/TimeSpanHumanizeTests.cs ================================================ namespace koKR; [UseCulture("ko-KR")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "1년")] [InlineData(731, "2년")] [InlineData(1096, "3년")] [InlineData(4018, "11년")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "1개월")] [InlineData(61, "2개월")] [InlineData(92, "3개월")] [InlineData(335, "11개월")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(7, "1주")] [InlineData(14, "2주")] public void Weeks(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [Trait("Translation", "Google")] [InlineData(1, "1일")] [InlineData(2, "2일")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [Trait("Translation", "Google")] [InlineData(1, "1시간")] [InlineData(2, "2시간")] public void Hours(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); [Theory] [Trait("Translation", "Google")] [InlineData(1, "1분")] [InlineData(2, "2분")] public void Minutes(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); [Theory] [Trait("Translation", "Google")] [InlineData(1, "1초")] [InlineData(2, "2초")] public void Seconds(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); [Theory] [Trait("Translation", "Google")] [InlineData(1, "1밀리초")] [InlineData(2, "2밀리초")] public void Milliseconds(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); [Fact] [Trait("Translation", "Google")] public void NoTime() => Assert.Equal("0밀리초", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => Assert.Equal("방금", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ku/DateHumanizeTests.cs ================================================ namespace ku; [UseCulture("ku")] public class DateHumanizeTests { [Theory] [InlineData(-1, "دوێنێ")] [InlineData(-2, "2 ڕۆژ لەمەوبەر")] [InlineData(-3, "3 ڕۆژ لەمەوبەر")] [InlineData(-11, "11 ڕۆژ لەمەوبەر")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "بەیانی")] [InlineData(2, "2 ڕۆژی دیکە")] [InlineData(10, "10 ڕۆژی دیکە")] [InlineData(17, "17 ڕۆژی دیکە")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(-2, "2 کاتژمێر لەمەوبەر")] [InlineData(-1, "کاتژمێرێک لەمەوبەر")] [InlineData(-3, "3 کاتژمێر لەمەوبەر")] [InlineData(-11, "11 کاتژمێر لەمەوبەر")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "کاتژمێرێکی دیکە")] [InlineData(2, "2 کاتژمێری دیکە")] [InlineData(10, "10 کاتژمێری دیکە")] [InlineData(23, "23 کاتژمێری دیکە")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(-2, "2 خولەک لەمەوبەر")] [InlineData(-1, "خولەکێک لەمەوبەر")] [InlineData(-3, "3 خولەک لەمەوبەر")] [InlineData(-11, "11 خولەک لەمەوبەر")] [InlineData(60, "کاتژمێرێک لەمەوبەر")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "خولەکێکی دیکە")] [InlineData(2, "2 خولەکی دیکە")] [InlineData(10, "10 خولەکی دیکە")] [InlineData(23, "23 خولەکی دیکە")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(-2, "2 مانگ لەمەوبەر")] [InlineData(-1, "مانگێک لەمەوبەر")] [InlineData(-3, "3 مانگ لەمەوبەر")] [InlineData(-11, "11 مانگ لەمەوبەر")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "مانگێکی دیکە")] [InlineData(2, "2 مانگی دیکە")] [InlineData(10, "10 مانگی دیکە")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(-2, "2 چرکە لەمەوبەر")] [InlineData(-1, "چرکەیەک لەمەوبەر")] [InlineData(-3, "3 چرکە لەمەوبەر")] [InlineData(-11, "11 چرکە لەمەوبەر")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(0, "ئێستا")] [InlineData(1, "چرکەیەکی دیکە")] [InlineData(2, "2 چرکەی دیکە")] [InlineData(10, "10 چرکەی دیکە")] [InlineData(24, "24 چرکەی دیکە")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(-2, "2 ساڵ لەمەوبەر")] [InlineData(-1, "ساڵێک لەمەوبەر")] [InlineData(-3, "3 ساڵ لەمەوبەر")] [InlineData(-11, "11 ساڵ لەمەوبەر")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "ساڵێکی دیکە")] [InlineData(2, "2 ساڵی دیکە")] [InlineData(7, "7 ساڵی دیکە")] [InlineData(55, "55 ساڵی دیکە")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ku/NumberToWordsTests.cs ================================================ namespace ku; [UseCulture("ku")] public class NumberToWordsTests { [Theory] [InlineData(-1, "نێگەتیڤ یەک")] [InlineData(-10, "نێگەتیڤ دە")] [InlineData(-100, "نێگەتیڤ سەد")] [InlineData(-999, "نێگەتیڤ نۆ سەد و نەوەد و نۆ")] [InlineData(-1000, "نێگەتیڤ هەزار")] [InlineData(-1000000, "نێگەتیڤ یەک میلیۆن")] [InlineData(1, "یەک")] [InlineData(10, "دە")] [InlineData(11, "یازدە")] [InlineData(122, "سەد و بیست و دوو")] [InlineData(3501, "سێ هەزار و پێنج سەد و یەک")] [InlineData(100, "سەد")] [InlineData(1000, "هەزار")] [InlineData(100000, "سەد هەزار")] [InlineData(100001, "سەد هەزار و یەک")] [InlineData(101000, "سەد و یەک هەزار")] [InlineData(1000000, "یەک میلیۆن")] [InlineData(51000, "پەنجا و یەک هەزار")] [InlineData(151000, "سەد و پەنجا و یەک هەزار")] [InlineData(10000000, "دە میلیۆن")] [InlineData(100000000, "سەد میلیۆن")] [InlineData(1000000000, "یەک میلیارد")] [InlineData(111, "سەد و یازدە")] [InlineData(1111, "هەزار و سەد و یازدە")] [InlineData(111111, "سەد و یازدە هەزار و سەد و یازدە")] [InlineData(1001001, "یەک میلیۆن و یەک هەزار و یەک")] [InlineData(1111111, "یەک میلیۆن و سەد و یازدە هەزار و سەد و یازدە")] [InlineData(11111111, "یازدە میلیۆن و سەد و یازدە هەزار و سەد و یازدە")] [InlineData(111111111, "سەد و یازدە میلیۆن و سەد و یازدە هەزار و سەد و یازدە")] [InlineData(1111111111, "یەک میلیارد و سەد و یازدە میلیۆن و سەد و یازدە هەزار و سەد و یازدە")] [InlineData(123, "سەد و بیست و سێ")] [InlineData(1234, "هەزار و دوو سەد و سی و چوار")] [InlineData(12345, "دوازدە هەزار و سێ سەد و چل و پێنج")] [InlineData(123456, "سەد و بیست و سێ هەزار و چوار سەد و پەنجا و شەش")] [InlineData(1234567, "یەک میلیۆن و دوو سەد و سی و چوار هەزار و پێنج سەد و شەست و حەوت")] [InlineData(12345678, "دوازدە میلیۆن و سێ سەد و چل و پێنج هەزار و شەش سەد و حەفتا و هەشت")] [InlineData(123456789, "سەد و بیست و سێ میلیۆن و چوار سەد و پەنجا و شەش هەزار و حەوت سەد و هەشتا و نۆ")] [InlineData(1234567890, "یەک میلیارد و دوو سەد و سی و چوار میلیۆن و پێنج سەد و شەست و حەوت هەزار و هەشت سەد و نەوەد")] public void ToWordsKurdish(int number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(0, "سفرەم")] [InlineData(1, "یەکەم")] [InlineData(2, "دووەم")] [InlineData(3, "سێیەم")] [InlineData(4, "چوارەم")] [InlineData(5, "پێنجەم")] [InlineData(6, "شەشەم")] [InlineData(7, "حەوتەم")] [InlineData(8, "هەشتەم")] [InlineData(9, "نۆیەم")] [InlineData(10, "دەیەم")] [InlineData(11, "یازدەیەم")] [InlineData(12, "دوازدەیەم")] [InlineData(13, "سێزدەیەم")] [InlineData(21, "بیست و یەکەم")] [InlineData(22, "بیست و دووەم")] [InlineData(23, "بیست و سێیەم")] [InlineData(24, "بیست و چوارەم")] [InlineData(25, "بیست و پێنجەم")] [InlineData(30, "سییەم")] [InlineData(40, "چلەم")] [InlineData(50, "پەنجایەم")] [InlineData(60, "شەستەم")] [InlineData(70, "حەفتایەم")] [InlineData(80, "هەشتایەم")] [InlineData(90, "نەوەدەم")] [InlineData(100, "سەدەم")] [InlineData(200, "دوو سەدەم")] [InlineData(1000, "هەزارەم")] [InlineData(1001, "هەزار و یەکەم")] [InlineData(1333, "هەزار و سێ سەد و سی و سێیەم")] [InlineData(1000000, "یەک میلیۆنەم")] public void ToOrdinalWordsKurdish(int number, string words) => Assert.Equal(words, number.ToOrdinalWords()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ku/TimeSpanHumanizeTests.cs ================================================ namespace ku; [UseCulture("ku")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Native speaker")] [InlineData(366, "1 ساڵ")] [InlineData(731, "2 ساڵ")] [InlineData(1096, "3 ساڵ")] [InlineData(4018, "11 ساڵ")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Native speaker")] [InlineData(31, "1 مانگ")] [InlineData(61, "2 مانگ")] [InlineData(92, "3 مانگ")] [InlineData(335, "11 مانگ")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(7, "1 هەفتە")] [InlineData(77, "11 هەفتە")] public void Weeks(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "1 ڕۆژ")] [InlineData(3, "3 ڕۆژ")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "1 کاتژمێر")] [InlineData(11, "11 کاتژمێر")] public void Hours(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); [Theory] [InlineData(1, "1 خولەک")] [InlineData(11, "11 خولەک")] public void Minutes(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); [Theory] [InlineData(1, "1 چرکە")] [InlineData(11, "11 چرکە")] public void Seconds(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); [Theory] [InlineData(1, "1 میلیچرکە")] [InlineData(11, "11 میلیچرکە")] public void Milliseconds(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); [Fact] public void NoTime() => Assert.Equal("0 میلیچرکە", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => Assert.Equal("ئێستا", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/lb/Bytes/ByteRateTests.cs ================================================ namespace lb.Bytes; [UseCulture("lb-LU")] public class ByteRateTests { [Theory] [InlineData(400, 1, "400 B/s")] [InlineData(4 * 1024, 1, "4 KB/s")] [InlineData(4 * 1024 * 1024, 1, "4 MB/s")] [InlineData(4 * 2 * 1024 * 1024, 2, "4 MB/s")] [InlineData(4 * 1024, 0.1, "40 KB/s")] [InlineData(15 * 60 * 1024 * 1024, 60, "15 MB/s")] public void HumanizesRates(long inputBytes, double perSeconds, string expectedValue) { var size = new ByteSize(inputBytes); var interval = TimeSpan.FromSeconds(perSeconds); var rate = size .Per(interval) .Humanize(); Assert.Equal(expectedValue, rate); } [Theory] [InlineData(1, 1, TimeUnit.Second, "1 MB/s")] [InlineData(1, 60, TimeUnit.Minute, "1 MB/min")] [InlineData(1, 60 * 60, TimeUnit.Hour, "1 MB/h")] [InlineData(10, 1, TimeUnit.Second, "10 MB/s")] [InlineData(10, 60, TimeUnit.Minute, "10 MB/min")] [InlineData(10, 60 * 60, TimeUnit.Hour, "10 MB/h")] [InlineData(1, 10 * 1, TimeUnit.Second, "102,4 KB/s")] [InlineData(1, 10 * 60, TimeUnit.Minute, "102,4 KB/min")] [InlineData(1, 10 * 60 * 60, TimeUnit.Hour, "102,4 KB/h")] public void TimeUnitTests(long megabytes, double measurementIntervalSeconds, TimeUnit displayInterval, string expectedValue) { var size = ByteSize.FromMegabytes(megabytes); var measurementInterval = TimeSpan.FromSeconds(measurementIntervalSeconds); var rate = size.Per(measurementInterval); var text = rate.Humanize(displayInterval); Assert.Equal(expectedValue, text); } [Theory] [InlineData(19854651984, 1, TimeUnit.Second, null, "18,49 GB/s")] [InlineData(19854651984, 1, TimeUnit.Second, "#.##", "18,49 GB/s")] public void FormattedTimeUnitTests(long bytes, int measurementIntervalSeconds, TimeUnit displayInterval, string? format, string expectedValue) { var size = ByteSize.FromBytes(bytes); var measurementInterval = TimeSpan.FromSeconds(measurementIntervalSeconds); var rate = size.Per(measurementInterval); var text = rate.Humanize(format, displayInterval); Assert.Equal(expectedValue, text); } [Theory] [InlineData(TimeUnit.Millisecond)] [InlineData(TimeUnit.Day)] [InlineData(TimeUnit.Month)] [InlineData(TimeUnit.Week)] [InlineData(TimeUnit.Year)] public void ThrowsOnUnsupportedData(TimeUnit units) { var dummyRate = ByteSize .FromBits(1) .Per(TimeSpan.FromSeconds(1)); Assert.Throws(() => dummyRate.Humanize(units)); } } ================================================ FILE: tests/Humanizer.Tests/Localisation/lb/Bytes/ByteSizeExtensionsTests.cs ================================================ namespace lb.Bytes; [UseCulture("lb-LU")] public class ByteSizeExtensionsTests { [Theory] [InlineData(2, null, "2 TB")] [InlineData(2, "GB", "2048 GB")] [InlineData(2.123, "#.#", "2,1 TB")] public void HumanizesTerabytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Terabytes().Humanize(format)); [Theory] [InlineData(0, null, "0 bit")] [InlineData(0, "GB", "0 GB")] [InlineData(2, null, "2 GB")] [InlineData(2, "MB", "2048 MB")] [InlineData(2.123, "#.##", "2,12 GB")] public void HumanizesGigabytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Gigabytes().Humanize(format)); [Theory] [InlineData(0, null, "0 bit")] [InlineData(0, "MB", "0 MB")] [InlineData(2, null, "2 MB")] [InlineData(2, "KB", "2048 KB")] [InlineData(2.123, "#", "2 MB")] public void HumanizesMegabytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Megabytes().Humanize(format)); [Theory] [InlineData(0, null, "0 bit")] [InlineData(0, "KB", "0 KB")] [InlineData(2, null, "2 KB")] [InlineData(2, "B", "2048 B")] [InlineData(2.123, "#.####", "2,123 KB")] public void HumanizesKilobytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Kilobytes().Humanize(format)); #if NET6_0_OR_GREATER // the lb/lb-LU locales apparently don't have the correct group separator pre .NET 6 [Theory] [InlineData(0, null, "0 bit")] [InlineData(0, "#.##", "0 bit")] [InlineData(0, "#.## B", "0 B")] [InlineData(0, "B", "0 B")] [InlineData(2, null, "2 B")] [InlineData(2000, "KB", "1,95 KB")] [InlineData(2123, "#.##", "2,07 KB")] [InlineData(10000000, "KB", "9765,63 KB")] [InlineData(10000000, "#,##0 KB", "9.766 KB")] [InlineData(10000000, "#,##0.# KB", "9.765,6 KB")] public void HumanizesBytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Bytes().Humanize(format)); #endif [Theory] [InlineData(0, null, "0 bit")] [InlineData(0, "b", "0 bit")] [InlineData(2, null, "2 bit")] [InlineData(12, "B", "1,5 B")] [InlineData(10000, "#.# KB", "1,2 KB")] public void HumanizesBits(long input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Bits().Humanize(format)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/lb/Bytes/ToFullWordsTests.cs ================================================ namespace lb.Bytes; [UseCulture("lb-LU")] public class ToFullWordsTests { [Fact] public void ReturnsSingularBit() => Assert.Equal("1 Bit", ByteSize.FromBits(1).ToFullWords()); [Fact] public void ReturnsPluralBits() => Assert.Equal("2 Bit", ByteSize.FromBits(2).ToFullWords()); [Fact] public void ReturnsSingularByte() => Assert.Equal("1 Byte", ByteSize.FromBytes(1).ToFullWords()); [Fact] public void ReturnsPluralBytes() => Assert.Equal("10 Byte", ByteSize.FromBytes(10).ToFullWords()); [Fact] public void ReturnsSingularKiloByte() => Assert.Equal("1 Kilobyte", ByteSize.FromKilobytes(1).ToFullWords()); [Fact] public void ReturnsPluralKilobytes() => Assert.Equal("10 Kilobyte", ByteSize.FromKilobytes(10).ToFullWords()); [Fact] public void ReturnsSingularMegabyte() => Assert.Equal("1 Megabyte", ByteSize.FromMegabytes(1).ToFullWords()); [Fact] public void ReturnsPluralMegabytes() => Assert.Equal("10 Megabyte", ByteSize.FromMegabytes(10).ToFullWords()); [Fact] public void ReturnsSingularGigabyte() => Assert.Equal("1 Gigabyte", ByteSize.FromGigabytes(1).ToFullWords()); [Fact] public void ReturnsPluralGigabytes() => Assert.Equal("10 Gigabyte", ByteSize.FromGigabytes(10).ToFullWords()); [Fact] public void ReturnsSingularTerabyte() => Assert.Equal("1 Terabyte", ByteSize.FromTerabytes(1).ToFullWords()); [Fact] public void ReturnsPluralTerabytes() => Assert.Equal("10 Terabyte", ByteSize.FromTerabytes(10).ToFullWords()); [Theory] [InlineData(229376, "B", "229376 Byte")] [InlineData(229376, "# KB", "224 Kilobyte")] public void ToFullWordsFormatted(double input, string format, string expectedValue) => Assert.Equal(expectedValue, ByteSize.FromBytes(input).ToFullWords(format)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/lb/Bytes/ToStringTests.cs ================================================ namespace lb.Bytes; [UseCulture("lb-LU")] public class ToStringTests { [Fact] public void ReturnsLargestMetricSuffix() => Assert.Equal("10,5 KB", ByteSize.FromKilobytes(10.5).ToString()); [Fact] public void ReturnsDefaultNumberFormat() => Assert.Equal("10,5 KB", ByteSize.FromKilobytes(10.5).ToString("KB")); [Fact] public void ReturnsProvidedNumberFormat() => Assert.Equal("10,1234 KB", ByteSize.FromKilobytes(10.1234).ToString("#.#### KB")); [Fact] public void ReturnsBits() => Assert.Equal("10 bit", ByteSize.FromBits(10).ToString("##.#### b")); [Fact] public void ReturnsBytes() => Assert.Equal("10 B", ByteSize.FromBytes(10).ToString("##.#### B")); [Fact] public void ReturnsKilobytes() => Assert.Equal("10 KB", ByteSize.FromKilobytes(10).ToString("##.#### KB")); [Fact] public void ReturnsMegabytes() => Assert.Equal("10 MB", ByteSize.FromMegabytes(10).ToString("##.#### MB")); [Fact] public void ReturnsGigabytes() => Assert.Equal("10 GB", ByteSize.FromGigabytes(10).ToString("##.#### GB")); [Fact] public void ReturnsTerabytes() => Assert.Equal("10 TB", ByteSize.FromTerabytes(10).ToString("##.#### TB")); [Fact] public void ReturnsSelectedFormat() => Assert.Equal("10,0 TB", ByteSize.FromTerabytes(10).ToString("0.0 TB")); [Fact] public void ReturnsLargestMetricPrefixLargerThanZero() => Assert.Equal("512 KB", ByteSize.FromMegabytes(.5).ToString("#.#")); [Fact] public void ReturnsLargestMetricPrefixLargerThanZeroForNegativeValues() => Assert.Equal("-512 KB", ByteSize.FromMegabytes(-.5).ToString("#.#")); [Fact] public void ReturnsBytesViaGeneralFormat() => Assert.Equal("10 B", $"{ByteSize.FromBytes(10)}"); } ================================================ FILE: tests/Humanizer.Tests/Localisation/lb/CollectionFormatterTests.cs ================================================ namespace lb; [UseCulture("lb-LU")] public class CollectionFormatterTests { [Fact] public void OneItem() { var collection = new List([1]); var humanized = "1"; Assert.Equal(humanized, collection.Humanize()); } [Fact] public void TwoItems() { var collection = new List([1, 2]); var humanized = "1 an 2"; Assert.Equal(humanized, collection.Humanize()); } [Fact] public void MoreThanTwoItems() { var collection = new List([1, 2, 3]); var humanized = "1, 2 an 3"; Assert.Equal(humanized, collection.Humanize()); } } ================================================ FILE: tests/Humanizer.Tests/Localisation/lb/DateHumanizeTests.cs ================================================ namespace lb; [UseCulture("lb-LU")] public class DateHumanizeTests { [Theory] [InlineData(1, "virun enger Sekonn")] [InlineData(2, "virun 2 Sekonnen")] [InlineData(4, "viru 4 Sekonnen")] [InlineData(10, "virun 10 Sekonnen")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "an enger Sekonn")] [InlineData(2, "an 2 Sekonnen")] [InlineData(4, "a 4 Sekonnen")] [InlineData(10, "an 10 Sekonnen")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(1, "virun enger Minutt")] [InlineData(2, "virun 2 Minutten")] [InlineData(4, "viru 4 Minutten")] [InlineData(10, "virun 10 Minutten")] [InlineData(60, "virun enger Stonn")] [InlineData(240, "viru 4 Stonnen")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "an enger Minutt")] [InlineData(2, "an 2 Minutten")] [InlineData(4, "a 4 Minutten")] [InlineData(10, "an 10 Minutten")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(1, "virun enger Stonn")] [InlineData(2, "virun 2 Stonnen")] [InlineData(4, "viru 4 Stonnen")] [InlineData(10, "virun 10 Stonnen")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "an enger Stonn")] [InlineData(2, "an 2 Stonnen")] [InlineData(4, "a 4 Stonnen")] [InlineData(10, "an 10 Stonnen")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(1, "gëschter")] [InlineData(2, "virgëschter")] [InlineData(4, "viru 4 Deeg")] [InlineData(10, "virun 10 Deeg")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "muer")] [InlineData(2, "iwwermuer")] [InlineData(4, "a 4 Deeg")] [InlineData(10, "an 10 Deeg")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(1, "virun engem Mount")] [InlineData(2, "virun 2 Méint")] [InlineData(4, "viru 4 Méint")] [InlineData(10, "virun 10 Méint")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "an engem Mount")] [InlineData(2, "an 2 Méint")] [InlineData(4, "a 4 Méint")] [InlineData(10, "an 10 Méint")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(1, "virun engem Joer")] [InlineData(2, "virun 2 Joer")] [InlineData(4, "viru 4 Joer")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "an engem Joer")] [InlineData(2, "an 2 Joer")] [InlineData(4, "a 4 Joer")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/lb/DateToOrdinalWordsTests.cs ================================================ namespace lb; [UseCulture("lb-LU")] public class DateToOrdinalWordsTests { [Fact] public void OrdinalizeString() => Assert.Equal("1. Abrëll 2015", new DateTime(2015, 4, 1).ToOrdinalWords()); #if NET6_0_OR_GREATER [Fact] public void OrdinalizeDateOnlyString() => Assert.Equal("1. Abrëll 2015", new DateOnly(2015, 4, 1).ToOrdinalWords()); #endif } ================================================ FILE: tests/Humanizer.Tests/Localisation/lb/NumberToWordsTests.cs ================================================ namespace lb; [UseCulture("lb-LU")] public class NumberToWordsTests { [Theory] [InlineData(0, "null")] [InlineData(1, "een")] [InlineData(2, "zwee")] [InlineData(3, "dräi")] [InlineData(4, "véier")] [InlineData(5, "fënnef")] [InlineData(6, "sechs")] [InlineData(7, "siwen")] [InlineData(8, "aacht")] [InlineData(9, "néng")] [InlineData(10, "zéng")] [InlineData(20, "zwanzeg")] [InlineData(30, "drësseg")] [InlineData(40, "véierzeg")] [InlineData(50, "fofzeg")] [InlineData(60, "sechzeg")] [InlineData(70, "siwwenzeg")] [InlineData(80, "achtzeg")] [InlineData(90, "nonzeg")] [InlineData(100, "eenhonnert")] [InlineData(200, "zweehonnert")] [InlineData(1000, "eendausend")] [InlineData(10000, "zéngdausend")] [InlineData(100000, "eenhonnertdausend")] [InlineData(1000000, "eng Millioun")] [InlineData(10000000, "zéng Milliounen")] [InlineData(100000000, "eenhonnert Milliounen")] [InlineData(1000000000, "eng Milliard")] [InlineData(2000000000, "zwou Milliarden")] [InlineData(122, "eenhonnertzweeanzwanzeg")] [InlineData(3501, "dräidausendfënnefhonnerteen")] [InlineData(111, "eenhonnerteelef")] [InlineData(1112, "eendausendeenhonnertzwielef")] [InlineData(11213, "eelefdausendzweehonnertdräizéng")] [InlineData(121314, "eenhonnerteenanzwanzegdausenddräihonnertvéierzéng")] [InlineData(2132415, "zwou Milliounen eenhonnertzweeandrëssegdausendvéierhonnertfofzéng")] [InlineData(12345516, "zwielef Milliounen dräihonnertfënnefavéierzegdausendfënnefhonnertsiechzéng")] [InlineData(751633617, "siwenhonnerteenafofzeg Milliounen sechshonnertdräiandrëssegdausendsechshonnertsiwwenzéng")] [InlineData(1111111118, "eng Milliard eenhonnerteelef Milliounen eenhonnerteelefdausendeenhonnertuechtzéng")] [InlineData(35484694489515, "fënnefandrësseg Billiounen véierhonnertvéieranachtzeg Milliarden sechshonnertvéierannonzeg Milliounen véierhonnertnénganachtzegdausendfënnefhonnertfofzéng")] [InlineData(8183162164626926, "aacht Billiarden eenhonnertdräianachtzeg Billiounen eenhonnertzweeasechzeg Milliarden eenhonnertvéierasechzeg Milliounen sechshonnertsechsanzwanzegdausendnénghonnertsechsanzwanzeg")] [InlineData(4564121926659524672, "véier Trilliounen fënnefhonnertvéierasechzeg Billiarden eenhonnerteenanzwanzeg Billiounen nénghonnertsechsanzwanzeg Milliarden sechshonnertnéngafofzeg Milliounen fënnefhonnertvéieranzwanzegdausendsechshonnertzweeasiwwenzeg")] [InlineData(-751633619, "minus siwenhonnerteenafofzeg Milliounen sechshonnertdräiandrëssegdausendsechshonnertnonzéng")] public void ToWords(long number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(1, "eng")] [InlineData(2, "zwou")] [InlineData(3501, "dräidausendfënnefhonnerteng")] [InlineData(3502, "dräidausendfënnefhonnertzwou")] public void ToWordsFeminine(long number, string expected) => Assert.Equal(expected, number.ToWords(GrammaticalGender.Feminine)); [Theory] [InlineData(0, "nullten")] [InlineData(1, "éischten")] [InlineData(2, "zweeten")] [InlineData(3, "drëtten")] [InlineData(4, "véierten")] [InlineData(5, "fënneften")] [InlineData(6, "sechsten")] [InlineData(7, "siwenten")] [InlineData(8, "aachten")] [InlineData(9, "néngten")] [InlineData(10, "zéngten")] [InlineData(20, "zwanzegsten")] [InlineData(30, "drëssegsten")] [InlineData(40, "véierzegsten")] [InlineData(50, "fofzegsten")] [InlineData(60, "sechzegsten")] [InlineData(70, "siwwenzegsten")] [InlineData(80, "achtzegsten")] [InlineData(90, "nonzegsten")] [InlineData(100, "eenhonnertsten")] [InlineData(200, "zweehonnertsten")] [InlineData(1000, "eendausendsten")] [InlineData(10000, "zéngdausendsten")] [InlineData(100000, "eenhonnertdausendsten")] [InlineData(1000000, "eemilliounsten")] [InlineData(10000000, "zéngmilliounsten")] [InlineData(100000000, "eenhonnertmilliounsten")] [InlineData(1000000000, "eemilliardsten")] [InlineData(2000000000, "zwoumilliardsten")] [InlineData(122, "eenhonnertzweeanzwanzegsten")] [InlineData(3501, "dräidausendfënnefhonnertéischten")] [InlineData(111, "eenhonnerteeleften")] [InlineData(1112, "eendausendeenhonnertzwieleften")] [InlineData(11213, "eelefdausendzweehonnertdräizéngten")] [InlineData(121314, "eenhonnerteenanzwanzegdausenddräihonnertvéierzéngten")] [InlineData(2132415, "zwoumilliouneneenhonnertzweeandrëssegdausendvéierhonnertfofzéngten")] [InlineData(12345516, "zwielefmilliounendräihonnertfënnefavéierzegdausendfënnefhonnertsiechzéngten")] [InlineData(751633617, "siwenhonnerteenafofzegmilliounensechshonnertdräiandrëssegdausendsechshonnertsiwwenzéngten")] [InlineData(1111111118, "engmilliardeenhonnerteelefmilliouneneenhonnerteelefdausendeenhonnertuechtzéngten")] [InlineData(-751633619, "minus siwenhonnerteenafofzegmilliounensechshonnertdräiandrëssegdausendsechshonnertnonzéngten")] public void ToOrdinalWords(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords()); [Theory] [InlineData(0, "nullt")] [InlineData(1, "éischt")] [InlineData(2, "zweet")] [InlineData(3, "drëtt")] [InlineData(4, "véiert")] [InlineData(5, "fënneft")] [InlineData(6, "sechst")] [InlineData(7, "siwent")] [InlineData(8, "aacht")] [InlineData(9, "néngt")] [InlineData(10, "zéngt")] [InlineData(111, "eenhonnerteeleft")] [InlineData(1112, "eendausendeenhonnertzwieleft")] [InlineData(11213, "eelefdausendzweehonnertdräizéngt")] [InlineData(121314, "eenhonnerteenanzwanzegdausenddräihonnertvéierzéngt")] [InlineData(2132415, "zwoumilliouneneenhonnertzweeandrëssegdausendvéierhonnertfofzéngt")] [InlineData(12345516, "zwielefmilliounendräihonnertfënnefavéierzegdausendfënnefhonnertsiechzéngt")] [InlineData(751633617, "siwenhonnerteenafofzegmilliounensechshonnertdräiandrëssegdausendsechshonnertsiwwenzéngt")] [InlineData(1111111118, "engmilliardeenhonnerteelefmilliouneneenhonnerteelefdausendeenhonnertuechtzéngt")] [InlineData(-751633619, "minus siwenhonnerteenafofzegmilliounensechshonnertdräiandrëssegdausendsechshonnertnonzéngt")] public void ToOrdinalWordsFeminine(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Feminine)); [Theory] [InlineData(0, "nullt")] [InlineData(1, "éischt")] [InlineData(2, "zweet")] [InlineData(3, "drëtt")] [InlineData(4, "véiert")] [InlineData(5, "fënneft")] [InlineData(6, "sechst")] [InlineData(7, "siwent")] [InlineData(8, "aacht")] [InlineData(9, "néngt")] [InlineData(10, "zéngt")] [InlineData(111, "eenhonnerteeleft")] [InlineData(1112, "eendausendeenhonnertzwieleft")] [InlineData(11213, "eelefdausendzweehonnertdräizéngt")] [InlineData(121314, "eenhonnerteenanzwanzegdausenddräihonnertvéierzéngt")] [InlineData(2132415, "zwoumilliouneneenhonnertzweeandrëssegdausendvéierhonnertfofzéngt")] [InlineData(12345516, "zwielefmilliounendräihonnertfënnefavéierzegdausendfënnefhonnertsiechzéngt")] [InlineData(751633617, "siwenhonnerteenafofzegmilliounensechshonnertdräiandrëssegdausendsechshonnertsiwwenzéngt")] [InlineData(1111111118, "engmilliardeenhonnerteelefmilliouneneenhonnerteelefdausendeenhonnertuechtzéngt")] [InlineData(-751633619, "minus siwenhonnerteenafofzegmilliounensechshonnertdräiandrëssegdausendsechshonnertnonzéngt")] public void ToOrdinalWordsNeuter(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Neuter)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/lb/OrdinalizeTests.cs ================================================ namespace lb; [UseCulture("lb-LU")] public class OrdinalizeTests { [Theory] [InlineData("0", "0.")] [InlineData("1", "1.")] [InlineData("2", "2.")] [InlineData("3", "3.")] [InlineData("4", "4.")] [InlineData("5", "5.")] [InlineData("6", "6.")] [InlineData("23", "23.")] [InlineData("100", "100.")] [InlineData("101", "101.")] [InlineData("102", "102.")] [InlineData("103", "103.")] [InlineData("1001", "1001.")] public void OrdinalizeString(string number, string ordinalized) => Assert.Equal(ordinalized, number.Ordinalize()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/lb/TimeOnlyHumanizeTests.cs ================================================ #if NET6_0_OR_GREATER namespace lb; [UseCulture("lb-LU")] public class TimeOnlyHumanizeTests { [Fact] public void DefaultStrategy_SameTime() { var inputTime = new TimeOnly(13, 07, 05); var baseTime = new TimeOnly(13, 07, 05); const string expectedResult = "elo"; var actualResult = inputTime.Humanize(baseTime); Assert.Equal(expectedResult, actualResult); } [Fact] public void DefaultStrategy_HoursApart() { var inputTime = new TimeOnly(3, 08, 05); var baseTime = new TimeOnly(1, 08, 05); const string expectedResult = "an 2 Stonnen"; var actualResult = inputTime.Humanize(baseTime); Assert.Equal(expectedResult, actualResult); } [Fact] public void DefaultStrategy_HoursAgo() { var inputTime = new TimeOnly(13, 07, 02); var baseTime = new TimeOnly(17, 07, 05); const string expectedResult = "viru 4 Stonnen"; var actualResult = inputTime.Humanize(baseTime); Assert.Equal(expectedResult, actualResult); } [Fact] public void PrecisionStrategy_NextDay() { var inputTime = new TimeOnly(18, 10, 49); var baseTime = new TimeOnly(13, 07, 04); const string expectedResult = "a 5 Stonnen"; var actualResult = inputTime.Humanize(baseTime); Assert.Equal(expectedResult, actualResult); } [Fact] public void Never() { TimeOnly? never = null; Assert.Equal("ni", never.Humanize()); } [Fact] public void Nullable_ExpectSame() { TimeOnly? never = new TimeOnly(23, 12, 7); Assert.Equal(never.Value.Humanize(), never.Humanize()); } } #endif ================================================ FILE: tests/Humanizer.Tests/Localisation/lb/TimeSpanHumanizeTests.cs ================================================ namespace lb; [UseCulture("lb-LU")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Native speaker")] [InlineData(366, "1 Joer")] [InlineData(731, "2 Joer")] [InlineData(1096, "3 Joer")] [InlineData(4018, "11 Joer")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Native speaker")] [InlineData(366, "ee Joer")] [InlineData(731, "zwee Joer")] [InlineData(1096, "dräi Joer")] [InlineData(4018, "eelef Joer")] public void YearsToWords(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year, toWords: true)); [Theory] [Trait("Translation", "Native speaker")] [InlineData(31, "1 Mount")] [InlineData(61, "2 Méint")] [InlineData(92, "3 Méint")] [InlineData(335, "11 Méint")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Native speaker")] [InlineData(31, "ee Mount")] [InlineData(61, "zwee Méint")] [InlineData(92, "dräi Méint")] [InlineData(335, "eelef Méint")] public void MonthsToWords(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year, toWords: true)); [Theory] [InlineData(7, "1 Woch")] [InlineData(14, "2 Wochen")] [InlineData(21, "3 Wochen")] [InlineData(77, "11 Wochen")] public void Weeks(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(7, "eng Woch")] [InlineData(14, "zwou Wochen")] [InlineData(21, "dräi Wochen")] [InlineData(77, "eelef Wochen")] public void WeeksToWords(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(toWords: true)); [Theory] [InlineData(1, "1 Dag")] [InlineData(2, "2 Deeg")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "een Dag")] [InlineData(2, "zwee Deeg")] public void DaysToWords(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(toWords: true)); [Theory] [InlineData(1, "1 Stonn")] [InlineData(2, "2 Stonnen")] public void Hours(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); [Theory] [InlineData(1, "eng Stonn")] [InlineData(2, "zwou Stonnen")] public void HoursToWords(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize(toWords: true)); [Theory] [InlineData(1, "1 Minutt")] [InlineData(2, "2 Minutten")] public void Minutes(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); [Theory] [InlineData(1, "eng Minutt")] [InlineData(2, "zwou Minutten")] public void MinutesToWords(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize(toWords: true)); [Theory] [InlineData(1, "1 Sekonn")] [InlineData(2, "2 Sekonnen")] public void Seconds(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); [Theory] [InlineData(1, "eng Sekonn")] [InlineData(2, "zwou Sekonnen")] public void SecondsToWords(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize(toWords: true)); [Theory] [InlineData(1, "1 Millisekonn")] [InlineData(2, "2 Millisekonnen")] public void Milliseconds(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); [Theory] [InlineData(1, "eng Millisekonn")] [InlineData(2, "zwou Millisekonnen")] public void MillisecondsToWords(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize(toWords: true)); [Theory] [InlineData(TimeUnit.Year, "0 Joer")] [InlineData(TimeUnit.Month, "0 Méint")] [InlineData(TimeUnit.Week, "0 Wochen")] [InlineData(TimeUnit.Day, "0 Deeg")] [InlineData(TimeUnit.Hour, "0 Stonnen")] [InlineData(TimeUnit.Minute, "0 Minutten")] [InlineData(TimeUnit.Second, "0 Sekonnen")] [InlineData(TimeUnit.Millisecond, "0 Millisekonnen")] public void NoTime(TimeUnit minUnit, string expected) { var noTime = TimeSpan.Zero; var actual = noTime.Humanize(minUnit: minUnit); Assert.Equal(expected, actual); } [Fact] public void NoTimeToWords() => // This one doesn't make a lot of sense but ... w/e Assert.Equal("Keng Zäit", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/lb/TimeToClockNotationTests.cs ================================================ #if NET6_0_OR_GREATER namespace lb; [UseCulture("lb-LU")] public class TimeToClockNotationTests { [Theory] [InlineData(00, 00, "Mëtternuecht")] [InlineData(00, 07, "siwe Minutten op zwielef")] [InlineData(01, 11, "eelef Minutten op eng")] [InlineData(04, 00, "véier Auer")] [InlineData(05, 01, "eng Minutt op fënnef")] [InlineData(06, 05, "fënnef op sechs")] [InlineData(07, 10, "zéng op siwen")] [InlineData(08, 15, "Véirel op aacht")] [InlineData(09, 20, "zwanzeg op néng")] [InlineData(10, 25, "fënnef vir hallwer eelef")] [InlineData(11, 30, "hallwer zwielef")] [InlineData(12, 00, "Mëtteg")] [InlineData(12, 39, "eenanzwanzeg Minutten vir eng")] [InlineData(13, 23, "dräianzwanzeg Minutten op eng")] [InlineData(14, 32, "zwou Minutten op hallwer dräi")] [InlineData(15, 35, "fënnef op hallwer véier")] [InlineData(16, 40, "zwanzeg vir fënnef")] [InlineData(17, 45, "Véirel vir sechs")] [InlineData(18, 50, "zéng vir siwen")] [InlineData(19, 52, "aacht Minutten vir aacht")] [InlineData(20, 55, "fënnef vir néng")] [InlineData(21, 58, "zwou Minutten vir zéng")] [InlineData(22, 59, "eng Minutt vir eelef")] public void ConvertToClockNotationTimeOnlyString(int hours, int minutes, string expectedResult) { var actualResult = new TimeOnly(hours, minutes).ToClockNotation(); Assert.Equal(expectedResult, actualResult); } [Theory] [InlineData(00, 00, "Mëtternuecht")] [InlineData(00, 07, "fënnef op zwielef")] [InlineData(01, 11, "zéng op eng")] [InlineData(04, 00, "véier Auer")] [InlineData(05, 01, "fënnef Auer")] [InlineData(06, 05, "fënnef op sechs")] [InlineData(07, 10, "zéng op siwen")] [InlineData(08, 15, "Véirel op aacht")] [InlineData(09, 20, "zwanzeg op néng")] [InlineData(10, 25, "fënnef vir hallwer eelef")] [InlineData(11, 30, "hallwer zwielef")] [InlineData(12, 00, "Mëtteg")] [InlineData(12, 39, "zwanzeg vir eng")] [InlineData(13, 23, "fënnef vir hallwer zwou")] [InlineData(14, 32, "hallwer dräi")] [InlineData(15, 35, "fënnef op hallwer véier")] [InlineData(16, 40, "zwanzeg vir fënnef")] [InlineData(17, 45, "Véirel vir sechs")] [InlineData(18, 50, "zéng vir siwen")] [InlineData(19, 52, "zéng vir aacht")] [InlineData(20, 55, "fënnef vir néng")] [InlineData(21, 58, "zéng Auer")] [InlineData(22, 59, "eelef Auer")] public void ConvertToRoundedClockNotationTimeOnlyString(int hours, int minutes, string expectedResult) { var actualResult = new TimeOnly(hours, minutes).ToClockNotation(ClockNotationRounding.NearestFiveMinutes); Assert.Equal(expectedResult, actualResult); } } #endif ================================================ FILE: tests/Humanizer.Tests/Localisation/lt/DateHumanizeTests.cs ================================================ namespace lt; [UseCulture("lt")] public class DateHumanizeTests { [Fact] public void Now() => DateHumanize.Verify("dabar", 0, TimeUnit.Millisecond, Tense.Past); } ================================================ FILE: tests/Humanizer.Tests/Localisation/lt/DateToOrdinalWordsTests.cs ================================================ namespace lt; [UseCulture("lt")] public class DateToOrdinalWordsTests { [Fact] public void OrdinalizeString() => Assert.Equal("2015 m. sausio 1 d.", new DateTime(2015, 1, 1).ToOrdinalWords()); #if NET6_0_OR_GREATER [Fact] public void OrdinalizeDateOnlyString() => Assert.Equal("2015 m. sausio 1 d.", new DateOnly(2015, 1, 1).ToOrdinalWords()); #endif } ================================================ FILE: tests/Humanizer.Tests/Localisation/lt/NumberToWordsTests.cs ================================================ namespace lt; [UseCulture("lt")] public class NumberToWordsTests { [Theory] [InlineData(-1, "minus vienas")] [InlineData(0, "nulis")] [InlineData(1, "vienas")] [InlineData(11, "vienuolika")] [InlineData(21, "dvidešimt vienas")] [InlineData(22, "dvidešimt du")] [InlineData(26, "dvidešimt šeši")] [InlineData(30, "trisdešimt")] [InlineData(31, "trisdešimt vienas")] [InlineData(33, "trisdešimt trys")] [InlineData(37, "trisdešimt septyni")] [InlineData(40, "keturiasdešimt")] [InlineData(41, "keturiasdešimt vienas")] [InlineData(44, "keturiasdešimt keturi")] [InlineData(48, "keturiasdešimt aštuoni")] [InlineData(50, "penkiasdešimt")] [InlineData(51, "penkiasdešimt vienas")] [InlineData(55, "penkiasdešimt penki")] [InlineData(59, "penkiasdešimt devyni")] [InlineData(60, "šešiasdešimt")] [InlineData(61, "šešiasdešimt vienas")] [InlineData(62, "šešiasdešimt du")] [InlineData(66, "šešiasdešimt šeši")] [InlineData(70, "septyniasdešimt")] [InlineData(71, "septyniasdešimt vienas")] [InlineData(73, "septyniasdešimt trys")] [InlineData(77, "septyniasdešimt septyni")] [InlineData(80, "aštuoniasdešimt")] [InlineData(81, "aštuoniasdešimt vienas")] [InlineData(84, "aštuoniasdešimt keturi")] [InlineData(88, "aštuoniasdešimt aštuoni")] [InlineData(90, "devyniasdešimt")] [InlineData(91, "devyniasdešimt vienas")] [InlineData(95, "devyniasdešimt penki")] [InlineData(99, "devyniasdešimt devyni")] [InlineData(100, "šimtas")] [InlineData(101, "šimtas vienas")] [InlineData(105, "šimtas penki")] [InlineData(110, "šimtas dešimt")] [InlineData(151, "šimtas penkiasdešimt vienas")] [InlineData(200, "du šimtai")] [InlineData(202, "du šimtai du")] [InlineData(206, "du šimtai šeši")] [InlineData(220, "du šimtai dvidešimt")] [InlineData(262, "du šimtai šešiasdešimt du")] [InlineData(300, "trys šimtai")] [InlineData(303, "trys šimtai trys")] [InlineData(307, "trys šimtai septyni")] [InlineData(330, "trys šimtai trisdešimt")] [InlineData(373, "trys šimtai septyniasdešimt trys")] [InlineData(400, "keturi šimtai")] [InlineData(404, "keturi šimtai keturi")] [InlineData(408, "keturi šimtai aštuoni")] [InlineData(440, "keturi šimtai keturiasdešimt")] [InlineData(484, "keturi šimtai aštuoniasdešimt keturi")] [InlineData(500, "penki šimtai")] [InlineData(505, "penki šimtai penki")] [InlineData(509, "penki šimtai devyni")] [InlineData(550, "penki šimtai penkiasdešimt")] [InlineData(595, "penki šimtai devyniasdešimt penki")] [InlineData(600, "šeši šimtai")] [InlineData(601, "šeši šimtai vienas")] [InlineData(606, "šeši šimtai šeši")] [InlineData(616, "šeši šimtai šešiolika")] [InlineData(660, "šeši šimtai šešiasdešimt")] [InlineData(700, "septyni šimtai")] [InlineData(702, "septyni šimtai du")] [InlineData(707, "septyni šimtai septyni")] [InlineData(727, "septyni šimtai dvidešimt septyni")] [InlineData(770, "septyni šimtai septyniasdešimt")] [InlineData(800, "aštuoni šimtai")] [InlineData(803, "aštuoni šimtai trys")] [InlineData(808, "aštuoni šimtai aštuoni")] [InlineData(838, "aštuoni šimtai trisdešimt aštuoni")] [InlineData(880, "aštuoni šimtai aštuoniasdešimt")] [InlineData(900, "devyni šimtai")] [InlineData(904, "devyni šimtai keturi")] [InlineData(909, "devyni šimtai devyni")] [InlineData(949, "devyni šimtai keturiasdešimt devyni")] [InlineData(990, "devyni šimtai devyniasdešimt")] [InlineData(1000, "tūkstantis")] [InlineData(1001, "tūkstantis vienas")] [InlineData(1012, "tūkstantis dvylika")] [InlineData(1100, "tūkstantis šimtas")] [InlineData(1234, "tūkstantis du šimtai trisdešimt keturi")] [InlineData(2000, "du tūkstančiai")] [InlineData(2002, "du tūkstančiai du")] [InlineData(2023, "du tūkstančiai dvidešimt trys")] [InlineData(2345, "du tūkstančiai trys šimtai keturiasdešimt penki")] [InlineData(3000, "trys tūkstančiai")] [InlineData(3003, "trys tūkstančiai trys")] [InlineData(3034, "trys tūkstančiai trisdešimt keturi")] [InlineData(3456, "trys tūkstančiai keturi šimtai penkiasdešimt šeši")] [InlineData(4000, "keturi tūkstančiai")] [InlineData(4004, "keturi tūkstančiai keturi")] [InlineData(4045, "keturi tūkstančiai keturiasdešimt penki")] [InlineData(4567, "keturi tūkstančiai penki šimtai šešiasdešimt septyni")] [InlineData(5000, "penki tūkstančiai")] [InlineData(5005, "penki tūkstančiai penki")] [InlineData(5056, "penki tūkstančiai penkiasdešimt šeši")] [InlineData(5678, "penki tūkstančiai šeši šimtai septyniasdešimt aštuoni")] [InlineData(6000, "šeši tūkstančiai")] [InlineData(6006, "šeši tūkstančiai šeši")] [InlineData(6067, "šeši tūkstančiai šešiasdešimt septyni")] [InlineData(6789, "šeši tūkstančiai septyni šimtai aštuoniasdešimt devyni")] [InlineData(7000, "septyni tūkstančiai")] [InlineData(7007, "septyni tūkstančiai septyni")] [InlineData(7078, "septyni tūkstančiai septyniasdešimt aštuoni")] [InlineData(7890, "septyni tūkstančiai aštuoni šimtai devyniasdešimt")] [InlineData(8000, "aštuoni tūkstančiai")] [InlineData(8008, "aštuoni tūkstančiai aštuoni")] [InlineData(8089, "aštuoni tūkstančiai aštuoniasdešimt devyni")] [InlineData(8901, "aštuoni tūkstančiai devyni šimtai vienas")] [InlineData(9000, "devyni tūkstančiai")] [InlineData(9009, "devyni tūkstančiai devyni")] [InlineData(9012, "devyni tūkstančiai dvylika")] [InlineData(9090, "devyni tūkstančiai devyniasdešimt")] [InlineData(10000, "dešimt tūkstančių")] [InlineData(10001, "dešimt tūkstančių vienas")] [InlineData(20020, "dvidešimt tūkstančių dvidešimt")] [InlineData(30300, "trisdešimt tūkstančių trys šimtai")] [InlineData(44000, "keturiasdešimt keturi tūkstančiai")] [InlineData(44231, "keturiasdešimt keturi tūkstančiai du šimtai trisdešimt vienas")] [InlineData(100000, "šimtas tūkstančių")] [InlineData(500000, "penki šimtai tūkstančių")] [InlineData(1000000, "milijonas")] [InlineData(6000000, "šeši milijonai")] [InlineData(10000000, "dešimt milijonų")] [InlineData(70000000, "septyniasdešimt milijonų")] [InlineData(100000000, "šimtas milijonų")] [InlineData(800000000, "aštuoni šimtai milijonų")] [InlineData(9223372036854775807, "devyni kvintilijonai du šimtai dvidešimt trys kvadrilijonai trys šimtai septyniasdešimt du trilijonai trisdešimt šeši milijardai aštuoni šimtai penkiasdešimt keturi milijonai septyni šimtai septyniasdešimt penki tūkstančiai aštuoni šimtai septyni")] public void ToWordsMasculine(long number, string expected) => Assert.Equal(expected, number.ToWords(gender: GrammaticalGender.Masculine)); [Theory] [InlineData(-1, "minus viena")] [InlineData(0, "nulis")] [InlineData(1, "viena")] [InlineData(11, "vienuolika")] [InlineData(21, "dvidešimt viena")] [InlineData(22, "dvidešimt dvi")] [InlineData(26, "dvidešimt šešios")] [InlineData(30, "trisdešimt")] [InlineData(31, "trisdešimt viena")] [InlineData(33, "trisdešimt trys")] [InlineData(37, "trisdešimt septynios")] [InlineData(40, "keturiasdešimt")] [InlineData(41, "keturiasdešimt viena")] [InlineData(44, "keturiasdešimt keturios")] [InlineData(48, "keturiasdešimt aštuonios")] [InlineData(50, "penkiasdešimt")] [InlineData(51, "penkiasdešimt viena")] [InlineData(55, "penkiasdešimt penkios")] [InlineData(59, "penkiasdešimt devynios")] [InlineData(60, "šešiasdešimt")] [InlineData(61, "šešiasdešimt viena")] [InlineData(62, "šešiasdešimt dvi")] [InlineData(66, "šešiasdešimt šešios")] [InlineData(70, "septyniasdešimt")] [InlineData(71, "septyniasdešimt viena")] [InlineData(73, "septyniasdešimt trys")] [InlineData(77, "septyniasdešimt septynios")] [InlineData(80, "aštuoniasdešimt")] [InlineData(81, "aštuoniasdešimt viena")] [InlineData(84, "aštuoniasdešimt keturios")] [InlineData(88, "aštuoniasdešimt aštuonios")] [InlineData(90, "devyniasdešimt")] [InlineData(91, "devyniasdešimt viena")] [InlineData(95, "devyniasdešimt penkios")] [InlineData(99, "devyniasdešimt devynios")] [InlineData(100, "šimtas")] [InlineData(101, "šimtas viena")] [InlineData(105, "šimtas penkios")] [InlineData(110, "šimtas dešimt")] [InlineData(151, "šimtas penkiasdešimt viena")] [InlineData(200, "du šimtai")] [InlineData(202, "du šimtai dvi")] [InlineData(206, "du šimtai šešios")] [InlineData(220, "du šimtai dvidešimt")] [InlineData(262, "du šimtai šešiasdešimt dvi")] [InlineData(300, "trys šimtai")] [InlineData(303, "trys šimtai trys")] [InlineData(307, "trys šimtai septynios")] [InlineData(330, "trys šimtai trisdešimt")] [InlineData(373, "trys šimtai septyniasdešimt trys")] [InlineData(400, "keturi šimtai")] [InlineData(404, "keturi šimtai keturios")] [InlineData(408, "keturi šimtai aštuonios")] [InlineData(440, "keturi šimtai keturiasdešimt")] [InlineData(484, "keturi šimtai aštuoniasdešimt keturios")] [InlineData(500, "penki šimtai")] [InlineData(505, "penki šimtai penkios")] [InlineData(509, "penki šimtai devynios")] [InlineData(550, "penki šimtai penkiasdešimt")] [InlineData(595, "penki šimtai devyniasdešimt penkios")] [InlineData(600, "šeši šimtai")] [InlineData(601, "šeši šimtai viena")] [InlineData(606, "šeši šimtai šešios")] [InlineData(616, "šeši šimtai šešiolika")] [InlineData(660, "šeši šimtai šešiasdešimt")] [InlineData(700, "septyni šimtai")] [InlineData(702, "septyni šimtai dvi")] [InlineData(707, "septyni šimtai septynios")] [InlineData(727, "septyni šimtai dvidešimt septynios")] [InlineData(770, "septyni šimtai septyniasdešimt")] [InlineData(800, "aštuoni šimtai")] [InlineData(803, "aštuoni šimtai trys")] [InlineData(808, "aštuoni šimtai aštuonios")] [InlineData(838, "aštuoni šimtai trisdešimt aštuonios")] [InlineData(880, "aštuoni šimtai aštuoniasdešimt")] [InlineData(900, "devyni šimtai")] [InlineData(904, "devyni šimtai keturios")] [InlineData(909, "devyni šimtai devynios")] [InlineData(949, "devyni šimtai keturiasdešimt devynios")] [InlineData(990, "devyni šimtai devyniasdešimt")] [InlineData(1000, "tūkstantis")] [InlineData(1001, "tūkstantis viena")] [InlineData(1012, "tūkstantis dvylika")] [InlineData(1100, "tūkstantis šimtas")] [InlineData(1234, "tūkstantis du šimtai trisdešimt keturios")] [InlineData(2000, "du tūkstančiai")] [InlineData(2002, "du tūkstančiai dvi")] [InlineData(2023, "du tūkstančiai dvidešimt trys")] [InlineData(2345, "du tūkstančiai trys šimtai keturiasdešimt penkios")] [InlineData(3000, "trys tūkstančiai")] [InlineData(3003, "trys tūkstančiai trys")] [InlineData(3034, "trys tūkstančiai trisdešimt keturios")] [InlineData(3456, "trys tūkstančiai keturi šimtai penkiasdešimt šešios")] [InlineData(4000, "keturi tūkstančiai")] [InlineData(4004, "keturi tūkstančiai keturios")] [InlineData(4045, "keturi tūkstančiai keturiasdešimt penkios")] [InlineData(4567, "keturi tūkstančiai penki šimtai šešiasdešimt septynios")] [InlineData(5000, "penki tūkstančiai")] [InlineData(5005, "penki tūkstančiai penkios")] [InlineData(5056, "penki tūkstančiai penkiasdešimt šešios")] [InlineData(5678, "penki tūkstančiai šeši šimtai septyniasdešimt aštuonios")] [InlineData(6000, "šeši tūkstančiai")] [InlineData(6006, "šeši tūkstančiai šešios")] [InlineData(6067, "šeši tūkstančiai šešiasdešimt septynios")] [InlineData(6789, "šeši tūkstančiai septyni šimtai aštuoniasdešimt devynios")] [InlineData(7000, "septyni tūkstančiai")] [InlineData(7007, "septyni tūkstančiai septynios")] [InlineData(7078, "septyni tūkstančiai septyniasdešimt aštuonios")] [InlineData(7890, "septyni tūkstančiai aštuoni šimtai devyniasdešimt")] [InlineData(8000, "aštuoni tūkstančiai")] [InlineData(8008, "aštuoni tūkstančiai aštuonios")] [InlineData(8089, "aštuoni tūkstančiai aštuoniasdešimt devynios")] [InlineData(8901, "aštuoni tūkstančiai devyni šimtai viena")] [InlineData(9000, "devyni tūkstančiai")] [InlineData(9009, "devyni tūkstančiai devynios")] [InlineData(9012, "devyni tūkstančiai dvylika")] [InlineData(9090, "devyni tūkstančiai devyniasdešimt")] [InlineData(10000, "dešimt tūkstančių")] [InlineData(10001, "dešimt tūkstančių viena")] [InlineData(20020, "dvidešimt tūkstančių dvidešimt")] [InlineData(30300, "trisdešimt tūkstančių trys šimtai")] [InlineData(44000, "keturiasdešimt keturi tūkstančiai")] [InlineData(44231, "keturiasdešimt keturi tūkstančiai du šimtai trisdešimt viena")] [InlineData(100000, "šimtas tūkstančių")] [InlineData(500000, "penki šimtai tūkstančių")] [InlineData(1000000, "milijonas")] [InlineData(6000000, "šeši milijonai")] [InlineData(10000000, "dešimt milijonų")] [InlineData(70000000, "septyniasdešimt milijonų")] [InlineData(100000000, "šimtas milijonų")] [InlineData(800000000, "aštuoni šimtai milijonų")] [InlineData(9223372036854775807, "devyni kvintilijonai du šimtai dvidešimt trys kvadrilijonai trys šimtai septyniasdešimt du trilijonai trisdešimt šeši milijardai aštuoni šimtai penkiasdešimt keturi milijonai septyni šimtai septyniasdešimt penki tūkstančiai aštuoni šimtai septynios")] public void ToWordsFeminine(long number, string expected) => Assert.Equal(expected, number.ToWords(gender: GrammaticalGender.Feminine)); [Theory] [InlineData(-1, "minus pirmas")] [InlineData(0, "nulinis")] [InlineData(1, "pirmas")] [InlineData(21, "dvidešimt pirmas")] [InlineData(22, "dvidešimt antras")] [InlineData(26, "dvidešimt šeštas")] [InlineData(30, "trisdešimtas")] [InlineData(31, "trisdešimt pirmas")] [InlineData(33, "trisdešimt trečias")] [InlineData(37, "trisdešimt septintas")] [InlineData(40, "keturiasdešimtas")] [InlineData(41, "keturiasdešimt pirmas")] [InlineData(44, "keturiasdešimt ketvirtas")] [InlineData(48, "keturiasdešimt aštuntas")] [InlineData(50, "penkiasdešimtas")] [InlineData(51, "penkiasdešimt pirmas")] [InlineData(55, "penkiasdešimt penktas")] [InlineData(59, "penkiasdešimt devintas")] [InlineData(60, "šešiasdešimtas")] [InlineData(61, "šešiasdešimt pirmas")] [InlineData(62, "šešiasdešimt antras")] [InlineData(66, "šešiasdešimt šeštas")] [InlineData(70, "septyniasdešimtas")] [InlineData(71, "septyniasdešimt pirmas")] [InlineData(73, "septyniasdešimt trečias")] [InlineData(77, "septyniasdešimt septintas")] [InlineData(80, "aštuoniasdešimtas")] [InlineData(81, "aštuoniasdešimt pirmas")] [InlineData(84, "aštuoniasdešimt ketvirtas")] [InlineData(88, "aštuoniasdešimt aštuntas")] [InlineData(90, "devyniasdešimtas")] [InlineData(91, "devyniasdešimt pirmas")] [InlineData(95, "devyniasdešimt penktas")] [InlineData(99, "devyniasdešimt devintas")] [InlineData(100, "šimtas")] [InlineData(101, "šimtas pirmas")] [InlineData(105, "šimtas penktas")] [InlineData(110, "šimtas dešimtas")] [InlineData(151, "šimtas penkiasdešimt pirmas")] [InlineData(200, "du šimtas")] [InlineData(202, "du šimtai antras")] [InlineData(206, "du šimtai šeštas")] [InlineData(220, "du šimtai dvidešimtas")] [InlineData(262, "du šimtai šešiasdešimt antras")] [InlineData(300, "trys šimtas")] [InlineData(303, "trys šimtai trečias")] [InlineData(307, "trys šimtai septintas")] [InlineData(330, "trys šimtai trisdešimtas")] [InlineData(373, "trys šimtai septyniasdešimt trečias")] [InlineData(400, "keturi šimtas")] [InlineData(404, "keturi šimtai ketvirtas")] [InlineData(408, "keturi šimtai aštuntas")] [InlineData(440, "keturi šimtai keturiasdešimtas")] [InlineData(484, "keturi šimtai aštuoniasdešimt ketvirtas")] [InlineData(500, "penki šimtas")] [InlineData(505, "penki šimtai penktas")] [InlineData(509, "penki šimtai devintas")] [InlineData(550, "penki šimtai penkiasdešimtas")] [InlineData(595, "penki šimtai devyniasdešimt penktas")] [InlineData(600, "šeši šimtas")] [InlineData(601, "šeši šimtai pirmas")] [InlineData(606, "šeši šimtai šeštas")] [InlineData(616, "šeši šimtai šešioliktas")] [InlineData(660, "šeši šimtai šešiasdešimtas")] [InlineData(700, "septyni šimtas")] [InlineData(702, "septyni šimtai antras")] [InlineData(707, "septyni šimtai septintas")] [InlineData(727, "septyni šimtai dvidešimt septintas")] [InlineData(770, "septyni šimtai septyniasdešimtas")] [InlineData(800, "aštuoni šimtas")] [InlineData(803, "aštuoni šimtai trečias")] [InlineData(808, "aštuoni šimtai aštuntas")] [InlineData(838, "aštuoni šimtai trisdešimt aštuntas")] [InlineData(880, "aštuoni šimtai aštuoniasdešimtas")] [InlineData(900, "devyni šimtas")] [InlineData(904, "devyni šimtai ketvirtas")] [InlineData(909, "devyni šimtai devintas")] [InlineData(949, "devyni šimtai keturiasdešimt devintas")] [InlineData(990, "devyni šimtai devyniasdešimtas")] [InlineData(1000, "tūkstantas")] [InlineData(1001, "tūkstantis pirmas")] [InlineData(1012, "tūkstantis dvyliktas")] [InlineData(1100, "tūkstantis šimtas")] [InlineData(1234, "tūkstantis du šimtai trisdešimt ketvirtas")] [InlineData(2000, "du tūkstantas")] [InlineData(2002, "du tūkstančiai antras")] [InlineData(2023, "du tūkstančiai dvidešimt trečias")] [InlineData(2345, "du tūkstančiai trys šimtai keturiasdešimt penktas")] [InlineData(3000, "trys tūkstantas")] [InlineData(3003, "trys tūkstančiai trečias")] [InlineData(3034, "trys tūkstančiai trisdešimt ketvirtas")] [InlineData(3456, "trys tūkstančiai keturi šimtai penkiasdešimt šeštas")] [InlineData(4000, "keturi tūkstantas")] [InlineData(4004, "keturi tūkstančiai ketvirtas")] [InlineData(4045, "keturi tūkstančiai keturiasdešimt penktas")] [InlineData(4567, "keturi tūkstančiai penki šimtai šešiasdešimt septintas")] [InlineData(5000, "penki tūkstantas")] [InlineData(5005, "penki tūkstančiai penktas")] [InlineData(5056, "penki tūkstančiai penkiasdešimt šeštas")] [InlineData(5678, "penki tūkstančiai šeši šimtai septyniasdešimt aštuntas")] [InlineData(6000, "šeši tūkstantas")] [InlineData(6006, "šeši tūkstančiai šeštas")] [InlineData(6067, "šeši tūkstančiai šešiasdešimt septintas")] [InlineData(6789, "šeši tūkstančiai septyni šimtai aštuoniasdešimt devintas")] [InlineData(7000, "septyni tūkstantas")] [InlineData(7007, "septyni tūkstančiai septintas")] [InlineData(7078, "septyni tūkstančiai septyniasdešimt aštuntas")] [InlineData(7890, "septyni tūkstančiai aštuoni šimtai devyniasdešimtas")] [InlineData(8000, "aštuoni tūkstantas")] [InlineData(8008, "aštuoni tūkstančiai aštuntas")] [InlineData(8089, "aštuoni tūkstančiai aštuoniasdešimt devintas")] [InlineData(8901, "aštuoni tūkstančiai devyni šimtai pirmas")] [InlineData(9000, "devyni tūkstantas")] [InlineData(9009, "devyni tūkstančiai devintas")] [InlineData(9012, "devyni tūkstančiai dvyliktas")] [InlineData(9090, "devyni tūkstančiai devyniasdešimtas")] [InlineData(10000, "dešimt tūkstantas")] [InlineData(10001, "dešimt tūkstančių pirmas")] [InlineData(20020, "dvidešimt tūkstančių dvidešimtas")] [InlineData(30300, "trisdešimt tūkstančių trys šimtas")] [InlineData(44000, "keturiasdešimt keturi tūkstantas")] [InlineData(44231, "keturiasdešimt keturi tūkstančiai du šimtai trisdešimt pirmas")] [InlineData(100000, "šimtas tūkstantas")] [InlineData(500000, "penki šimtai tūkstantas")] [InlineData(1000000, "milijonas")] [InlineData(6000000, "šeši milijonas")] [InlineData(10000000, "dešimt milijonas")] [InlineData(70000000, "septyniasdešimt milijonas")] [InlineData(100000000, "šimtas milijonas")] [InlineData(800000000, "aštuoni šimtai milijonas")] public void ToOrdinalWordsMasculine(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Masculine)); [Theory] [InlineData(-1, "minus pirma")] [InlineData(0, "nulinė")] [InlineData(1, "pirma")] [InlineData(21, "dvidešimt pirma")] [InlineData(22, "dvidešimt antra")] [InlineData(26, "dvidešimt šešta")] [InlineData(30, "trisdešimta")] [InlineData(31, "trisdešimt pirma")] [InlineData(33, "trisdešimt trečia")] [InlineData(37, "trisdešimt septinta")] [InlineData(40, "keturiasdešimta")] [InlineData(41, "keturiasdešimt pirma")] [InlineData(44, "keturiasdešimt ketvirta")] [InlineData(48, "keturiasdešimt aštunta")] [InlineData(50, "penkiasdešimta")] [InlineData(51, "penkiasdešimt pirma")] [InlineData(55, "penkiasdešimt penkta")] [InlineData(59, "penkiasdešimt devinta")] [InlineData(60, "šešiasdešimta")] [InlineData(61, "šešiasdešimt pirma")] [InlineData(62, "šešiasdešimt antra")] [InlineData(66, "šešiasdešimt šešta")] [InlineData(70, "septyniasdešimta")] [InlineData(71, "septyniasdešimt pirma")] [InlineData(73, "septyniasdešimt trečia")] [InlineData(77, "septyniasdešimt septinta")] [InlineData(80, "aštuoniasdešimta")] [InlineData(81, "aštuoniasdešimt pirma")] [InlineData(84, "aštuoniasdešimt ketvirta")] [InlineData(88, "aštuoniasdešimt aštunta")] [InlineData(90, "devyniasdešimta")] [InlineData(91, "devyniasdešimt pirma")] [InlineData(95, "devyniasdešimt penkta")] [InlineData(99, "devyniasdešimt devinta")] [InlineData(100, "šimta")] [InlineData(101, "šimtas pirma")] [InlineData(105, "šimtas penkta")] [InlineData(110, "šimtas dešimta")] [InlineData(151, "šimtas penkiasdešimt pirma")] [InlineData(200, "du šimta")] [InlineData(202, "du šimtai antra")] [InlineData(206, "du šimtai šešta")] [InlineData(220, "du šimtai dvidešimta")] [InlineData(262, "du šimtai šešiasdešimt antra")] [InlineData(300, "trys šimta")] [InlineData(303, "trys šimtai trečia")] [InlineData(307, "trys šimtai septinta")] [InlineData(330, "trys šimtai trisdešimta")] [InlineData(373, "trys šimtai septyniasdešimt trečia")] [InlineData(400, "keturi šimta")] [InlineData(404, "keturi šimtai ketvirta")] [InlineData(408, "keturi šimtai aštunta")] [InlineData(440, "keturi šimtai keturiasdešimta")] [InlineData(484, "keturi šimtai aštuoniasdešimt ketvirta")] [InlineData(500, "penki šimta")] [InlineData(505, "penki šimtai penkta")] [InlineData(509, "penki šimtai devinta")] [InlineData(550, "penki šimtai penkiasdešimta")] [InlineData(595, "penki šimtai devyniasdešimt penkta")] [InlineData(600, "šeši šimta")] [InlineData(601, "šeši šimtai pirma")] [InlineData(606, "šeši šimtai šešta")] [InlineData(616, "šeši šimtai šešiolikta")] [InlineData(660, "šeši šimtai šešiasdešimta")] [InlineData(700, "septyni šimta")] [InlineData(702, "septyni šimtai antra")] [InlineData(707, "septyni šimtai septinta")] [InlineData(727, "septyni šimtai dvidešimt septinta")] [InlineData(770, "septyni šimtai septyniasdešimta")] [InlineData(800, "aštuoni šimta")] [InlineData(803, "aštuoni šimtai trečia")] [InlineData(808, "aštuoni šimtai aštunta")] [InlineData(838, "aštuoni šimtai trisdešimt aštunta")] [InlineData(880, "aštuoni šimtai aštuoniasdešimta")] [InlineData(900, "devyni šimta")] [InlineData(904, "devyni šimtai ketvirta")] [InlineData(909, "devyni šimtai devinta")] [InlineData(949, "devyni šimtai keturiasdešimt devinta")] [InlineData(990, "devyni šimtai devyniasdešimta")] [InlineData(1000, "tūkstanta")] [InlineData(1001, "tūkstantis pirma")] [InlineData(1012, "tūkstantis dvylikta")] [InlineData(1100, "tūkstantis šimta")] [InlineData(1234, "tūkstantis du šimtai trisdešimt ketvirta")] [InlineData(2000, "du tūkstanta")] [InlineData(2002, "du tūkstančiai antra")] [InlineData(2023, "du tūkstančiai dvidešimt trečia")] [InlineData(2345, "du tūkstančiai trys šimtai keturiasdešimt penkta")] [InlineData(3000, "trys tūkstanta")] [InlineData(3003, "trys tūkstančiai trečia")] [InlineData(3034, "trys tūkstančiai trisdešimt ketvirta")] [InlineData(3456, "trys tūkstančiai keturi šimtai penkiasdešimt šešta")] [InlineData(4000, "keturi tūkstanta")] [InlineData(4004, "keturi tūkstančiai ketvirta")] [InlineData(4045, "keturi tūkstančiai keturiasdešimt penkta")] [InlineData(4567, "keturi tūkstančiai penki šimtai šešiasdešimt septinta")] [InlineData(5000, "penki tūkstanta")] [InlineData(5005, "penki tūkstančiai penkta")] [InlineData(5056, "penki tūkstančiai penkiasdešimt šešta")] [InlineData(5678, "penki tūkstančiai šeši šimtai septyniasdešimt aštunta")] [InlineData(6000, "šeši tūkstanta")] [InlineData(6006, "šeši tūkstančiai šešta")] [InlineData(6067, "šeši tūkstančiai šešiasdešimt septinta")] [InlineData(6789, "šeši tūkstančiai septyni šimtai aštuoniasdešimt devinta")] [InlineData(7000, "septyni tūkstanta")] [InlineData(7007, "septyni tūkstančiai septinta")] [InlineData(7078, "septyni tūkstančiai septyniasdešimt aštunta")] [InlineData(7890, "septyni tūkstančiai aštuoni šimtai devyniasdešimta")] [InlineData(8000, "aštuoni tūkstanta")] [InlineData(8008, "aštuoni tūkstančiai aštunta")] [InlineData(8089, "aštuoni tūkstančiai aštuoniasdešimt devinta")] [InlineData(8901, "aštuoni tūkstančiai devyni šimtai pirma")] [InlineData(9000, "devyni tūkstanta")] [InlineData(9009, "devyni tūkstančiai devinta")] [InlineData(9012, "devyni tūkstančiai dvylikta")] [InlineData(9090, "devyni tūkstančiai devyniasdešimta")] [InlineData(10000, "dešimt tūkstanta")] [InlineData(10001, "dešimt tūkstančių pirma")] [InlineData(20020, "dvidešimt tūkstančių dvidešimta")] [InlineData(30300, "trisdešimt tūkstančių trys šimta")] [InlineData(44000, "keturiasdešimt keturi tūkstanta")] [InlineData(44231, "keturiasdešimt keturi tūkstančiai du šimtai trisdešimt pirma")] [InlineData(100000, "šimtas tūkstanta")] [InlineData(500000, "penki šimtai tūkstanta")] [InlineData(1000000, "milijona")] [InlineData(6000000, "šeši milijona")] [InlineData(10000000, "dešimt milijona")] [InlineData(70000000, "septyniasdešimt milijona")] [InlineData(100000000, "šimtas milijona")] [InlineData(800000000, "aštuoni šimtai milijona")] public void ToOrdinalWordsFeminine(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Feminine)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/lt/TimeSpanHumanizeTests.cs ================================================ namespace lt; [UseCulture("lt")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Native speaker")] [InlineData(366, "1 metai")] [InlineData(731, "2 metai")] [InlineData(1096, "3 metai")] [InlineData(4018, "11 metų")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Native speaker")] [InlineData(31, "1 mėnuo")] [InlineData(61, "2 mėnesiai")] [InlineData(280, "9 mėnesiai")] [InlineData(330, "10 mėnesių")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(7, "1 savaitė")] [InlineData(14, "2 savaitės")] [InlineData(21, "3 savaitės")] [InlineData(77, "11 savaičių")] [InlineData(147, "21 savaitė")] public void Weeks(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "1 diena")] [InlineData(2, "2 dienos")] [InlineData(9, "9 dienos")] [InlineData(10, "10 dienų")] [InlineData(17, "17 dienų")] [InlineData(21, "21 diena")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Day)); [Theory] [InlineData(1, "1 valanda")] [InlineData(2, "2 valandos")] [InlineData(3, "3 valandos")] [InlineData(9, "9 valandos")] [InlineData(10, "10 valandų")] [InlineData(19, "19 valandų")] [InlineData(21, "21 valanda")] public void Hours(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); [Theory] [InlineData(1, "1 minutė")] [InlineData(2, "2 minutės")] [InlineData(3, "3 minutės")] [InlineData(9, "9 minutės")] [InlineData(10, "10 minučių")] [InlineData(19, "19 minučių")] [InlineData(21, "21 minutė")] public void Minutes(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); [Theory] [InlineData(1, "1 sekundė")] [InlineData(2, "2 sekundės")] [InlineData(3, "3 sekundės")] [InlineData(9, "9 sekundės")] [InlineData(10, "10 sekundžių")] [InlineData(19, "19 sekundžių")] [InlineData(21, "21 sekundė")] public void Seconds(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); [Theory] [InlineData(1, "1 milisekundė")] [InlineData(2, "2 milisekundės")] [InlineData(3, "3 milisekundės")] [InlineData(9, "9 milisekundės")] [InlineData(10, "10 milisekundžių")] [InlineData(19, "19 milisekundžių")] [InlineData(21, "21 milisekundė")] public void Milliseconds(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); [Fact] public void NoTime() => Assert.Equal("0 milisekundžių", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => Assert.Equal("nėra laiko", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/lv/DateToOrdinalWordsTests.cs ================================================ namespace lv; [UseCulture("lv")] public class DateToOrdinalWordsTests { [Fact] public void OrdinalizeString() => Assert.Equal("1 janvāris 2015", new DateTime(2015, 1, 1).ToOrdinalWords()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/lv/NumberToWordsTests.cs ================================================ namespace lv; [UseCulture("lv-LV")] public class NumberToWordsTests { [Theory] [InlineData(21, "divdesmit viens")] [InlineData(22, "divdesmit divi")] [InlineData(26, "divdesmit seši")] [InlineData(30, "trīsdesmit")] [InlineData(31, "trīsdesmit viens")] [InlineData(33, "trīsdesmit trīs")] [InlineData(37, "trīsdesmit septiņi")] [InlineData(40, "četrdesmit")] [InlineData(41, "četrdesmit viens")] [InlineData(44, "četrdesmit četri")] [InlineData(48, "četrdesmit astoņi")] [InlineData(50, "piecdesmit")] [InlineData(51, "piecdesmit viens")] [InlineData(55, "piecdesmit pieci")] [InlineData(59, "piecdesmit deviņi")] [InlineData(60, "sešdesmit")] [InlineData(61, "sešdesmit viens")] [InlineData(62, "sešdesmit divi")] [InlineData(66, "sešdesmit seši")] [InlineData(70, "septiņdesmit")] [InlineData(71, "septiņdesmit viens")] [InlineData(73, "septiņdesmit trīs")] [InlineData(77, "septiņdesmit septiņi")] [InlineData(80, "astoņdesmit")] [InlineData(81, "astoņdesmit viens")] [InlineData(84, "astoņdesmit četri")] [InlineData(88, "astoņdesmit astoņi")] [InlineData(90, "deviņdesmit")] [InlineData(91, "deviņdesmit viens")] [InlineData(95, "deviņdesmit pieci")] [InlineData(99, "deviņdesmit deviņi")] [InlineData(100, "simts")] [InlineData(101, "simtu viens")] [InlineData(105, "simtu pieci")] [InlineData(110, "simtu desmit")] [InlineData(151, "simtu piecdesmit viens")] [InlineData(200, "divi simti")] [InlineData(202, "divi simti divi")] [InlineData(206, "divi simti seši")] [InlineData(220, "divi simti divdesmit")] [InlineData(262, "divi simti sešdesmit divi")] [InlineData(300, "trīs simti")] [InlineData(303, "trīs simti trīs")] [InlineData(307, "trīs simti septiņi")] [InlineData(330, "trīs simti trīsdesmit")] [InlineData(373, "trīs simti septiņdesmit trīs")] [InlineData(400, "četri simti")] [InlineData(404, "četri simti četri")] [InlineData(408, "četri simti astoņi")] [InlineData(440, "četri simti četrdesmit")] [InlineData(484, "četri simti astoņdesmit četri")] [InlineData(500, "pieci simti")] [InlineData(505, "pieci simti pieci")] [InlineData(509, "pieci simti deviņi")] [InlineData(550, "pieci simti piecdesmit")] [InlineData(595, "pieci simti deviņdesmit pieci")] [InlineData(600, "seši simti")] [InlineData(601, "seši simti viens")] [InlineData(606, "seši simti seši")] [InlineData(616, "seši simti sešpadsmit")] [InlineData(660, "seši simti sešdesmit")] [InlineData(700, "septiņi simti")] [InlineData(702, "septiņi simti divi")] [InlineData(707, "septiņi simti septiņi")] [InlineData(727, "septiņi simti divdesmit septiņi")] [InlineData(770, "septiņi simti septiņdesmit")] [InlineData(800, "astoņi simti")] [InlineData(803, "astoņi simti trīs")] [InlineData(808, "astoņi simti astoņi")] [InlineData(838, "astoņi simti trīsdesmit astoņi")] [InlineData(880, "astoņi simti astoņdesmit")] [InlineData(900, "deviņi simti")] [InlineData(904, "deviņi simti četri")] [InlineData(909, "deviņi simti deviņi")] [InlineData(949, "deviņi simti četrdesmit deviņi")] [InlineData(990, "deviņi simti deviņdesmit")] [InlineData(1000, "tūkstotis")] [InlineData(1001, "tūkstoš viens")] [InlineData(1012, "tūkstoš divpadsmit")] [InlineData(1100, "tūkstoš viens simts")] [InlineData(1234, "tūkstoš divi simti trīsdesmit četri")] [InlineData(2000, "divi tūkstoši")] [InlineData(2002, "divi tūkstoši divi")] [InlineData(2023, "divi tūkstoši divdesmit trīs")] [InlineData(2345, "divi tūkstoši trīs simti četrdesmit pieci")] [InlineData(3000, "trīs tūkstoši")] [InlineData(3003, "trīs tūkstoši trīs")] [InlineData(3034, "trīs tūkstoši trīsdesmit četri")] [InlineData(3456, "trīs tūkstoši četri simti piecdesmit seši")] [InlineData(4000, "četri tūkstoši")] [InlineData(4004, "četri tūkstoši četri")] [InlineData(4045, "četri tūkstoši četrdesmit pieci")] [InlineData(4567, "četri tūkstoši pieci simti sešdesmit septiņi")] [InlineData(5000, "pieci tūkstoši")] [InlineData(5005, "pieci tūkstoši pieci")] [InlineData(5056, "pieci tūkstoši piecdesmit seši")] [InlineData(5678, "pieci tūkstoši seši simti septiņdesmit astoņi")] [InlineData(6000, "seši tūkstoši")] [InlineData(6006, "seši tūkstoši seši")] [InlineData(6067, "seši tūkstoši sešdesmit septiņi")] [InlineData(6789, "seši tūkstoši septiņi simti astoņdesmit deviņi")] [InlineData(7000, "septiņi tūkstoši")] [InlineData(7007, "septiņi tūkstoši septiņi")] [InlineData(7078, "septiņi tūkstoši septiņdesmit astoņi")] [InlineData(7890, "septiņi tūkstoši astoņi simti deviņdesmit")] [InlineData(8000, "astoņi tūkstoši")] [InlineData(8008, "astoņi tūkstoši astoņi")] [InlineData(8089, "astoņi tūkstoši astoņdesmit deviņi")] [InlineData(8901, "astoņi tūkstoši deviņi simti viens")] [InlineData(9000, "deviņi tūkstoši")] [InlineData(9009, "deviņi tūkstoši deviņi")] [InlineData(9012, "deviņi tūkstoši divpadsmit")] [InlineData(9090, "deviņi tūkstoši deviņdesmit")] [InlineData(10000, "desmit tūkstoši")] [InlineData(10001, "desmit tūkstoši viens")] [InlineData(20020, "divdesmit tūkstoši divdesmit")] [InlineData(30300, "trīsdesmit tūkstoši trīs simti")] [InlineData(44000, "četrdesmit četri tūkstoši")] [InlineData(44231, "četrdesmit četri tūkstoši divi simti trīsdesmit viens")] [InlineData(100000, "simts tūkstoši")] [InlineData(500000, "pieci simti tūkstoši")] [InlineData(1000000, "miljons")] [InlineData(6000000, "seši miljoni")] [InlineData(10000000, "desmit miljoni")] [InlineData(70000000, "septiņdesmit miljoni")] [InlineData(100000000, "simts miljoni")] [InlineData(800000000, "astoņi simti miljoni")] public void ToWords(int number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(21, "divdesmit pirmais")] [InlineData(22, "divdesmit otrais")] [InlineData(26, "divdesmit sestais")] [InlineData(30, "trīsdesmitais")] [InlineData(31, "trīsdesmit pirmais")] [InlineData(33, "trīsdesmit trešais")] [InlineData(37, "trīsdesmit septītais")] [InlineData(40, "četrdesmitais")] [InlineData(41, "četrdesmit pirmais")] [InlineData(44, "četrdesmit ceturtais")] [InlineData(48, "četrdesmit astotais")] [InlineData(50, "piecdesmitais")] [InlineData(51, "piecdesmit pirmais")] [InlineData(55, "piecdesmit piektais")] [InlineData(59, "piecdesmit devītais")] [InlineData(60, "sešdesmitais")] [InlineData(61, "sešdesmit pirmais")] [InlineData(62, "sešdesmit otrais")] [InlineData(66, "sešdesmit sestais")] [InlineData(70, "septiņdesmitais")] [InlineData(71, "septiņdesmit pirmais")] [InlineData(73, "septiņdesmit trešais")] [InlineData(77, "septiņdesmit septītais")] [InlineData(80, "astoņdesmitais")] [InlineData(81, "astoņdesmit pirmais")] [InlineData(84, "astoņdesmit ceturtais")] [InlineData(88, "astoņdesmit astotais")] [InlineData(90, "deviņdesmitais")] [InlineData(91, "deviņdesmit pirmais")] [InlineData(95, "deviņdesmit piektais")] [InlineData(99, "deviņdesmit devītais")] [InlineData(100, "simtais")] [InlineData(101, "simtu pirmais")] [InlineData(105, "simtu piektais")] [InlineData(110, "simtu desmitais")] [InlineData(151, "simtu piecdesmit pirmais")] [InlineData(200, "divsimtais")] [InlineData(202, "divi simti otrais")] [InlineData(206, "divi simti sestais")] [InlineData(220, "divi simti divdesmitais")] [InlineData(262, "divi simti sešdesmit otrais")] [InlineData(300, "trīssimtais")] [InlineData(303, "trīs simti trešais")] [InlineData(307, "trīs simti septītais")] [InlineData(330, "trīs simti trīsdesmitais")] [InlineData(373, "trīs simti septiņdesmit trešais")] [InlineData(400, "četrsimtais")] [InlineData(404, "četri simti ceturtais")] [InlineData(408, "četri simti astotais")] [InlineData(440, "četri simti četrdesmitais")] [InlineData(484, "četri simti astoņdesmit ceturtais")] [InlineData(500, "piecsimtais")] [InlineData(505, "pieci simti piektais")] [InlineData(509, "pieci simti devītais")] [InlineData(550, "pieci simti piecdesmitais")] [InlineData(595, "pieci simti deviņdesmit piektais")] [InlineData(600, "sešsimtais")] [InlineData(601, "seši simti pirmais")] [InlineData(606, "seši simti sestais")] [InlineData(616, "seši simti sešpadsmitais")] [InlineData(660, "seši simti sešdesmitais")] [InlineData(700, "septiņsimtais")] [InlineData(702, "septiņi simti otrais")] [InlineData(707, "septiņi simti septītais")] [InlineData(727, "septiņi simti divdesmit septītais")] [InlineData(770, "septiņi simti septiņdesmitais")] [InlineData(800, "astoņsimtais")] [InlineData(803, "astoņi simti trešais")] [InlineData(808, "astoņi simti astotais")] [InlineData(838, "astoņi simti trīsdesmit astotais")] [InlineData(880, "astoņi simti astoņdesmitais")] [InlineData(900, "deviņsimtais")] [InlineData(904, "deviņi simti ceturtais")] [InlineData(909, "deviņi simti devītais")] [InlineData(949, "deviņi simti četrdesmit devītais")] [InlineData(990, "deviņi simti deviņdesmitais")] [InlineData(1000, "tūkstošais")] [InlineData(1001, "tūkstoš pirmais")] [InlineData(1012, "tūkstoš divpadsmitais")] [InlineData(1100, "tūkstoš simtais")] [InlineData(1234, "tūkstoš divi simti trīsdesmit ceturtais")] [InlineData(2000, "divi tūkstošais")] [InlineData(2002, "divi tūkstoši otrais")] [InlineData(2023, "divi tūkstoši divdesmit trešais")] [InlineData(2345, "divi tūkstoši trīs simti četrdesmit piektais")] [InlineData(3000, "trīs tūkstošais")] [InlineData(3003, "trīs tūkstoši trešais")] [InlineData(3034, "trīs tūkstoši trīsdesmit ceturtais")] [InlineData(3456, "trīs tūkstoši četri simti piecdesmit sestais")] [InlineData(4000, "četri tūkstošais")] [InlineData(4004, "četri tūkstoši ceturtais")] [InlineData(4045, "četri tūkstoši četrdesmit piektais")] [InlineData(4567, "četri tūkstoši pieci simti sešdesmit septītais")] [InlineData(5000, "pieci tūkstošais")] [InlineData(5005, "pieci tūkstoši piektais")] [InlineData(5056, "pieci tūkstoši piecdesmit sestais")] [InlineData(5678, "pieci tūkstoši seši simti septiņdesmit astotais")] [InlineData(6000, "seši tūkstošais")] [InlineData(6006, "seši tūkstoši sestais")] [InlineData(6067, "seši tūkstoši sešdesmit septītais")] [InlineData(6789, "seši tūkstoši septiņi simti astoņdesmit devītais")] [InlineData(7000, "septiņi tūkstošais")] [InlineData(7007, "septiņi tūkstoši septītais")] [InlineData(7078, "septiņi tūkstoši septiņdesmit astotais")] [InlineData(7890, "septiņi tūkstoši astoņi simti deviņdesmitais")] [InlineData(8000, "astoņi tūkstošais")] [InlineData(8008, "astoņi tūkstoši astotais")] [InlineData(8089, "astoņi tūkstoši astoņdesmit devītais")] [InlineData(8901, "astoņi tūkstoši deviņi simti pirmais")] [InlineData(9000, "deviņi tūkstošais")] [InlineData(9009, "deviņi tūkstoši devītais")] [InlineData(9012, "deviņi tūkstoši divpadsmitais")] [InlineData(9090, "deviņi tūkstoši deviņdesmitais")] [InlineData(10000, "desmit tūkstošais")] [InlineData(10001, "desmit tūkstoši pirmais")] [InlineData(20020, "divdesmit tūkstoši divdesmitais")] [InlineData(30300, "trīsdesmit tūkstoši trīssimtais")] [InlineData(44000, "četrdesmit četri tūkstošais")] [InlineData(44231, "četrdesmit četri tūkstoši divi simti trīsdesmit pirmais")] [InlineData(100000, "simts tūkstošais")] [InlineData(500000, "pieci simti tūkstošais")] [InlineData(1000000, "miljonais")] [InlineData(6000000, "seši miljonais")] [InlineData(10000000, "desmit miljonais")] [InlineData(70000000, "septiņdesmit miljonais")] [InlineData(100000000, "simts miljonais")] [InlineData(800000000, "astoņi simti miljonais")] public void ToOrdinalWordsMasculine(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Masculine)); [Theory] [InlineData(21, "divdesmit pirmā")] [InlineData(22, "divdesmit otrā")] [InlineData(26, "divdesmit sestā")] [InlineData(30, "trīsdesmitā")] [InlineData(31, "trīsdesmit pirmā")] [InlineData(33, "trīsdesmit trešā")] [InlineData(37, "trīsdesmit septītā")] [InlineData(40, "četrdesmitā")] [InlineData(41, "četrdesmit pirmā")] [InlineData(44, "četrdesmit ceturtā")] [InlineData(48, "četrdesmit astotā")] [InlineData(50, "piecdesmitā")] [InlineData(51, "piecdesmit pirmā")] [InlineData(55, "piecdesmit piektā")] [InlineData(59, "piecdesmit devītā")] [InlineData(60, "sešdesmitā")] [InlineData(61, "sešdesmit pirmā")] [InlineData(62, "sešdesmit otrā")] [InlineData(66, "sešdesmit sestā")] [InlineData(70, "septiņdesmitā")] [InlineData(71, "septiņdesmit pirmā")] [InlineData(73, "septiņdesmit trešā")] [InlineData(77, "septiņdesmit septītā")] [InlineData(80, "astoņdesmitā")] [InlineData(81, "astoņdesmit pirmā")] [InlineData(84, "astoņdesmit ceturtā")] [InlineData(88, "astoņdesmit astotā")] [InlineData(90, "deviņdesmitā")] [InlineData(91, "deviņdesmit pirmā")] [InlineData(95, "deviņdesmit piektā")] [InlineData(99, "deviņdesmit devītā")] [InlineData(100, "simtā")] [InlineData(101, "simtu pirmā")] [InlineData(105, "simtu piektā")] [InlineData(110, "simtu desmitā")] [InlineData(151, "simtu piecdesmit pirmā")] [InlineData(200, "divsimtā")] [InlineData(202, "divi simti otrā")] [InlineData(206, "divi simti sestā")] [InlineData(220, "divi simti divdesmitā")] [InlineData(262, "divi simti sešdesmit otrā")] [InlineData(300, "trīssimtā")] [InlineData(303, "trīs simti trešā")] [InlineData(307, "trīs simti septītā")] [InlineData(330, "trīs simti trīsdesmitā")] [InlineData(373, "trīs simti septiņdesmit trešā")] [InlineData(400, "četrsimtā")] [InlineData(404, "četri simti ceturtā")] [InlineData(408, "četri simti astotā")] [InlineData(440, "četri simti četrdesmitā")] [InlineData(484, "četri simti astoņdesmit ceturtā")] [InlineData(500, "piecsimtā")] [InlineData(505, "pieci simti piektā")] [InlineData(509, "pieci simti devītā")] [InlineData(550, "pieci simti piecdesmitā")] [InlineData(595, "pieci simti deviņdesmit piektā")] [InlineData(600, "sešsimtā")] [InlineData(601, "seši simti pirmā")] [InlineData(606, "seši simti sestā")] [InlineData(616, "seši simti sešpadsmitā")] [InlineData(660, "seši simti sešdesmitā")] [InlineData(700, "septiņsimtā")] [InlineData(702, "septiņi simti otrā")] [InlineData(707, "septiņi simti septītā")] [InlineData(727, "septiņi simti divdesmit septītā")] [InlineData(770, "septiņi simti septiņdesmitā")] [InlineData(800, "astoņsimtā")] [InlineData(803, "astoņi simti trešā")] [InlineData(808, "astoņi simti astotā")] [InlineData(838, "astoņi simti trīsdesmit astotā")] [InlineData(880, "astoņi simti astoņdesmitā")] [InlineData(900, "deviņsimtā")] [InlineData(904, "deviņi simti ceturtā")] [InlineData(909, "deviņi simti devītā")] [InlineData(949, "deviņi simti četrdesmit devītā")] [InlineData(990, "deviņi simti deviņdesmitā")] [InlineData(1000, "tūkstošā")] [InlineData(1001, "tūkstoš pirmā")] [InlineData(1012, "tūkstoš divpadsmitā")] [InlineData(1100, "tūkstoš simtā")] [InlineData(1234, "tūkstoš divi simti trīsdesmit ceturtā")] [InlineData(2000, "divi tūkstošā")] [InlineData(2002, "divi tūkstoši otrā")] [InlineData(2023, "divi tūkstoši divdesmit trešā")] [InlineData(2345, "divi tūkstoši trīs simti četrdesmit piektā")] [InlineData(3000, "trīs tūkstošā")] [InlineData(3003, "trīs tūkstoši trešā")] [InlineData(3034, "trīs tūkstoši trīsdesmit ceturtā")] [InlineData(3456, "trīs tūkstoši četri simti piecdesmit sestā")] [InlineData(4000, "četri tūkstošā")] [InlineData(4004, "četri tūkstoši ceturtā")] [InlineData(4045, "četri tūkstoši četrdesmit piektā")] [InlineData(4567, "četri tūkstoši pieci simti sešdesmit septītā")] [InlineData(5000, "pieci tūkstošā")] [InlineData(5005, "pieci tūkstoši piektā")] [InlineData(5056, "pieci tūkstoši piecdesmit sestā")] [InlineData(5678, "pieci tūkstoši seši simti septiņdesmit astotā")] [InlineData(6000, "seši tūkstošā")] [InlineData(6006, "seši tūkstoši sestā")] [InlineData(6067, "seši tūkstoši sešdesmit septītā")] [InlineData(6789, "seši tūkstoši septiņi simti astoņdesmit devītā")] [InlineData(7000, "septiņi tūkstošā")] [InlineData(7007, "septiņi tūkstoši septītā")] [InlineData(7078, "septiņi tūkstoši septiņdesmit astotā")] [InlineData(7890, "septiņi tūkstoši astoņi simti deviņdesmitā")] [InlineData(8000, "astoņi tūkstošā")] [InlineData(8008, "astoņi tūkstoši astotā")] [InlineData(8089, "astoņi tūkstoši astoņdesmit devītā")] [InlineData(8901, "astoņi tūkstoši deviņi simti pirmā")] [InlineData(9000, "deviņi tūkstošā")] [InlineData(9009, "deviņi tūkstoši devītā")] [InlineData(9012, "deviņi tūkstoši divpadsmitā")] [InlineData(9090, "deviņi tūkstoši deviņdesmitā")] [InlineData(10000, "desmit tūkstošā")] [InlineData(10001, "desmit tūkstoši pirmā")] [InlineData(20020, "divdesmit tūkstoši divdesmitā")] [InlineData(30300, "trīsdesmit tūkstoši trīssimtā")] [InlineData(44000, "četrdesmit četri tūkstošā")] [InlineData(44231, "četrdesmit četri tūkstoši divi simti trīsdesmit pirmā")] [InlineData(100000, "simts tūkstošā")] [InlineData(500000, "pieci simti tūkstošā")] [InlineData(1000000, "miljonā")] [InlineData(6000000, "seši miljonā")] [InlineData(10000000, "desmit miljonā")] [InlineData(70000000, "septiņdesmit miljonā")] [InlineData(100000000, "simts miljonā")] [InlineData(800000000, "astoņi simti miljonā")] public void ToOrdinalWordsFeminine(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Feminine)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/lv/TimeSpanHumanizeTests.cs ================================================ namespace lv; [UseCulture("lv")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "1 gads")] [InlineData(731, "2 gadi")] [InlineData(1096, "3 gadi")] [InlineData(4018, "11 gadi")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "1 mēnesis")] [InlineData(61, "2 mēneši")] [InlineData(92, "3 mēneši")] [InlineData(335, "11 mēneši")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(7, "1 nedēļa")] [InlineData(14, "2 nedēļas")] public void Weeks(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [Trait("Translation", "Google")] [InlineData(1, "1 diena")] [InlineData(2, "2 dienas")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [Trait("Translation", "Google")] [InlineData(1, "1 stunda")] [InlineData(2, "2 stundas")] public void Hours(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); [Theory] [Trait("Translation", "Google")] [InlineData(1, "1 minūte")] [InlineData(2, "2 minūtes")] public void Minutes(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); [Theory] [Trait("Translation", "Google")] [InlineData(1, "1 sekunde")] [InlineData(2, "2 sekundes")] public void Seconds(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); [Theory] [Trait("Translation", "Google")] [InlineData(1, "1 milisekunde")] [InlineData(2, "2 milisekundes")] public void Milliseconds(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); [Fact] [Trait("Translation", "Google")] public void NoTime() => Assert.Equal("0 milisekundes", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => Assert.Equal("bez laika", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ms-MY/TimeSpanHumanizeTests.cs ================================================ namespace msMY; [UseCulture("ms-MY")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "1 tahun")] [InlineData(731, "2 tahun")] [InlineData(1096, "3 tahun")] [InlineData(4018, "11 tahun")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "1 bulan")] [InlineData(61, "2 bulan")] [InlineData(92, "3 bulan")] [InlineData(335, "11 bulan")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(7, "1 minggu")] [InlineData(14, "2 minggu")] public void Weeks(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [Trait("Translation", "Google")] [InlineData(1, "1 hari")] [InlineData(2, "2 hari")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [Trait("Translation", "Google")] [InlineData(1, "1 jam")] [InlineData(2, "2 jam")] public void Hours(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); [Theory] [Trait("Translation", "Google")] [InlineData(1, "1 minit")] [InlineData(2, "2 minit")] public void Minutes(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); [Theory] [Trait("Translation", "Google")] [InlineData(1, "1 saat")] [InlineData(2, "2 saat")] public void Seconds(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); [Theory] [Trait("Translation", "Google")] [InlineData(1, "1 milisaat")] [InlineData(2, "2 milisaat")] public void Milliseconds(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); [Fact] [Trait("Translation", "Google")] public void NoTime() => Assert.Equal("0 milisaat", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => Assert.Equal("tiada masa", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/mt/DateHumanizeTests.cs ================================================ namespace mt; [UseCulture("mt")] public class DateHumanizeTests { [Theory] [InlineData(-3, "3 jiem ilu")] [InlineData(-2, "jumejn ilu")] [InlineData(-1, "il-bieraħ")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(3, "3 jiem oħra")] [InlineData(2, "pitgħada")] [InlineData(1, "għada")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(-3, "3 siegħat ilu")] [InlineData(-2, "sagħtejn ilu")] [InlineData(-1, "siegħa ilu")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(3, "3 siegħat oħra")] [InlineData(2, "sagħtejn oħra")] [InlineData(1, "siegħa oħra")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(-3, "3 minuti ilu")] [InlineData(-2, "2 minuti ilu")] [InlineData(-1, "minuta ilu")] [InlineData(60, "siegħa ilu")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(2, "2 minuti oħra")] [InlineData(1, "minuta oħra")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(-3, "3 xhur ilu")] [InlineData(-2, "xahrejn ilu")] [InlineData(-1, "xahar ilu")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(3, "3 xhur oħra")] [InlineData(2, "xahrejn oħra")] [InlineData(1, "xahar ieħor")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(-2, "2 sekondi ilu")] [InlineData(-1, "sekonda ilu")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(2, "2 sekondi oħra")] [InlineData(1, "sekonda oħra")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(-3, "3 snin ilu")] [InlineData(-2, "sentejn ilu")] [InlineData(-1, "sena ilu")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(3, "3 snin oħra")] [InlineData(2, "sentejn oħra")] [InlineData(1, "sena oħra")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Theory] [InlineData(0, "issa")] public void Now(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/mt/NumberToWordsTests.cs ================================================ namespace mt; [UseCulture("mt")] public class NumberToWordsTests { [Theory] [InlineData(0, "żero")] [InlineData(1, "wieħed")] [InlineData(-1, "wieħed inqas minn żero")] [InlineData(3, "tlieta")] [InlineData(10, "għaxra")] [InlineData(11, "ħdax")] [InlineData(20, "għoxrin")] [InlineData(-20, "għoxrin inqas minn żero")] [InlineData(21, "wieħed u għoxrin")] [InlineData(38, "tmienja u tletin")] [InlineData(43, "tlieta u erbgħin")] [InlineData(78, "tmienja u sebgħin")] [InlineData(99, "disgħa u disgħin")] [InlineData(100, "mija")] [InlineData(101, "mija u wieħed")] [InlineData(103, "mija u tlieta")] [InlineData(110, "mija u għaxra")] [InlineData(111, "mija u ħdax")] [InlineData(121, "mija u wieħed u għoxrin")] [InlineData(122, "mija u tnejn u għoxrin")] [InlineData(123, "mija u tlieta u għoxrin")] [InlineData(138, "mija u tmienja u tletin")] [InlineData(143, "mija u tlieta u erbgħin")] [InlineData(178, "mija u tmienja u sebgħin")] [InlineData(199, "mija u disgħa u disgħin")] [InlineData(200, "mitejn")] [InlineData(201, "mitejn u wieħed")] [InlineData(203, "mitejn u tlieta")] [InlineData(210, "mitejn u għaxra")] [InlineData(211, "mitejn u ħdax")] [InlineData(221, "mitejn u wieħed u għoxrin")] [InlineData(222, "mitejn u tnejn u għoxrin")] [InlineData(223, "mitejn u tlieta u għoxrin")] [InlineData(238, "mitejn u tmienja u tletin")] [InlineData(243, "mitejn u tlieta u erbgħin")] [InlineData(278, "mitejn u tmienja u sebgħin")] [InlineData(299, "mitejn u disgħa u disgħin")] [InlineData(300, "tlett mija")] [InlineData(401, "erbgħa mija u wieħed")] [InlineData(503, "ħames mija u tlieta")] [InlineData(610, "sitt mija u għaxra")] [InlineData(711, "sebgħa mija u ħdax")] [InlineData(821, "tminn mija u wieħed u għoxrin")] [InlineData(922, "disgħa mija u tnejn u għoxrin")] [InlineData(323, "tlett mija u tlieta u għoxrin")] [InlineData(438, "erbgħa mija u tmienja u tletin")] [InlineData(543, "ħames mija u tlieta u erbgħin")] [InlineData(678, "sitt mija u tmienja u sebgħin")] [InlineData(799, "sebgħa mija u disgħa u disgħin")] [InlineData(1000, "elf")] [InlineData(1001, "elf u wieħed")] [InlineData(1111, "elf u mija u ħdax")] [InlineData(1234, "elf u mitejn u erbgħa u tletin")] [InlineData(1999, "elf u disgħa mija u disgħa u disgħin")] [InlineData(2000, "elfejn")] [InlineData(2014, "elfejn u erbatax")] [InlineData(2048, "elfejn u tmienja u erbgħin")] [InlineData(3000, "tlett elef")] [InlineData(3501, "tlett elef u ħames mija u wieħed")] [InlineData(8100, "tmint elef u mija")] [InlineData(10000, "għaxart elef")] [InlineData(10001, "għaxart elef u wieħed")] [InlineData(12345, "tnax-il elf u tlett mija u ħamsa u erbgħin")] [InlineData(18000, "tmintax-il elf")] [InlineData(100000, "mitt elf")] [InlineData(100001, "mitt elf u wieħed")] [InlineData(111111, "mija u ħdax-il elf u mija u ħdax")] [InlineData(123456, "mija u tlieta u għoxrin elf u erbgħa mija u sitta u ħamsin")] [InlineData(1000000, "miljun")] [InlineData(1000001, "miljun u wieħed")] [InlineData(1111101, "miljun u mija u ħdax-il elf u mija u wieħed")] [InlineData(1111111, "miljun u mija u ħdax-il elf u mija u ħdax")] [InlineData(1234567, "miljun u mitejn u erbgħa u tletin elf u ħames mija u sebgħa u sittin")] [InlineData(5000000, "ħames miljuni")] [InlineData(10000000, "għaxar miljuni")] [InlineData(10000001, "għaxar miljuni u wieħed")] [InlineData(11111111, "ħdax-il miljun u mija u ħdax-il elf u mija u ħdax")] [InlineData(12345678, "tnax-il miljun u tlett mija u ħamsa u erbgħin elf u sitt mija u tmienja u sebgħin")] [InlineData(100000000, "mitt miljun")] [InlineData(100000001, "mitt miljun u wieħed")] [InlineData(111111111, "mija u ħdax-il miljun u mija u ħdax-il elf u mija u ħdax")] [InlineData(123456789, "mija u tlieta u għoxrin miljun u erbgħa mija u sitta u ħamsin elf u sebgħa mija u disgħa u tmenin")] [InlineData(1000000000, "biljun")] [InlineData(1000000001, "biljun u wieħed")] [InlineData(1101111101, "biljun u mija u miljun u mija u ħdax-il elf u mija u wieħed")] [InlineData(2000000000, "żewġ biljuni")] [InlineData(2147483647, "żewġ biljuni u mija u sebgħa u erbgħin miljun u erbgħa mija u tlieta u tmenin elf u sitt mija u sebgħa u erbgħin")] [InlineData(-2147483647, "żewġ biljuni u mija u sebgħa u erbgħin miljun u erbgħa mija u tlieta u tmenin elf u sitt mija u sebgħa u erbgħin inqas minn żero")] public void ToWords(int number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(1, "waħda")] [InlineData(1001, "elf u waħda")] [InlineData(100001, "mitt elf u waħda")] [InlineData(1000000001, "biljun u waħda")] public void ToFeminineWords(int number, string expected) => Assert.Equal(expected, number.ToWords(GrammaticalGender.Feminine)); [Theory] [InlineData(0, "żero")] [InlineData(1, "wieħed")] [InlineData(3, "tlieta")] [InlineData(10, "għaxra")] [InlineData(11, "ħdax")] [InlineData(20, "għoxrin")] [InlineData(21, "wieħed u għoxrin")] [InlineData(38, "tmienja u tletin")] [InlineData(43, "tlieta u erbgħin")] [InlineData(78, "tmienja u sebgħin")] [InlineData(99, "disgħa u disgħin")] [InlineData(100, "mija")] [InlineData(101, "mija u wieħed")] [InlineData(103, "mija u tlieta")] [InlineData(110, "mija u għaxra")] [InlineData(111, "mija u ħdax")] [InlineData(121, "mija u wieħed u għoxrin")] [InlineData(122, "mija u tnejn u għoxrin")] [InlineData(123, "mija u tlieta u għoxrin")] [InlineData(138, "mija u tmienja u tletin")] [InlineData(143, "mija u tlieta u erbgħin")] [InlineData(178, "mija u tmienja u sebgħin")] [InlineData(199, "mija u disgħa u disgħin")] [InlineData(200, "mitejn")] [InlineData(201, "mitejn u wieħed")] [InlineData(203, "mitejn u tlieta")] [InlineData(210, "mitejn u għaxra")] [InlineData(211, "mitejn u ħdax")] [InlineData(221, "mitejn u wieħed u għoxrin")] [InlineData(222, "mitejn u tnejn u għoxrin")] [InlineData(223, "mitejn u tlieta u għoxrin")] [InlineData(238, "mitejn u tmienja u tletin")] [InlineData(243, "mitejn u tlieta u erbgħin")] [InlineData(278, "mitejn u tmienja u sebgħin")] [InlineData(299, "mitejn u disgħa u disgħin")] [InlineData(300, "tlett mija")] [InlineData(401, "erbgħa mija u wieħed")] [InlineData(503, "ħames mija u tlieta")] [InlineData(610, "sitt mija u għaxra")] [InlineData(711, "sebgħa mija u ħdax")] [InlineData(821, "tminn mija u wieħed u għoxrin")] [InlineData(922, "disgħa mija u tnejn u għoxrin")] [InlineData(323, "tlett mija u tlieta u għoxrin")] [InlineData(438, "erbgħa mija u tmienja u tletin")] [InlineData(543, "ħames mija u tlieta u erbgħin")] [InlineData(678, "sitt mija u tmienja u sebgħin")] [InlineData(799, "sebgħa mija u disgħa u disgħin")] [InlineData(1000, "elf")] [InlineData(1001, "elf u wieħed")] [InlineData(1111, "elf u mija u ħdax")] [InlineData(1234, "elf u mitejn u erbgħa u tletin")] [InlineData(1999, "elf u disgħa mija u disgħa u disgħin")] [InlineData(2000, "elfejn")] [InlineData(2014, "elfejn u erbatax")] [InlineData(2048, "elfejn u tmienja u erbgħin")] [InlineData(3000, "tlett elef")] [InlineData(3501, "tlett elef u ħames mija u wieħed")] [InlineData(8100, "tmint elef u mija")] [InlineData(10000, "għaxart elef")] [InlineData(10001, "għaxart elef u wieħed")] [InlineData(12345, "tnax-il elf u tlett mija u ħamsa u erbgħin")] [InlineData(18000, "tmintax-il elf")] [InlineData(100000, "mitt elf")] [InlineData(100001, "mitt elf u wieħed")] [InlineData(111111, "mija u ħdax-il elf u mija u ħdax")] [InlineData(123456, "mija u tlieta u għoxrin elf u erbgħa mija u sitta u ħamsin")] [InlineData(1000000, "miljun")] [InlineData(1000001, "miljun u wieħed")] [InlineData(1111101, "miljun u mija u ħdax-il elf u mija u wieħed")] [InlineData(1111111, "miljun u mija u ħdax-il elf u mija u ħdax")] [InlineData(1234567, "miljun u mitejn u erbgħa u tletin elf u ħames mija u sebgħa u sittin")] [InlineData(5000000, "ħames miljuni")] [InlineData(10000000, "għaxar miljuni")] [InlineData(10000001, "għaxar miljuni u wieħed")] [InlineData(11111111, "ħdax-il miljun u mija u ħdax-il elf u mija u ħdax")] [InlineData(12345678, "tnax-il miljun u tlett mija u ħamsa u erbgħin elf u sitt mija u tmienja u sebgħin")] [InlineData(100000000, "mitt miljun")] [InlineData(100000001, "mitt miljun u wieħed")] [InlineData(111111111, "mija u ħdax-il miljun u mija u ħdax-il elf u mija u ħdax")] [InlineData(123456789, "mija u tlieta u għoxrin miljun u erbgħa mija u sitta u ħamsin elf u sebgħa mija u disgħa u tmenin")] [InlineData(1000000000, "biljun")] [InlineData(1000000001, "biljun u wieħed")] [InlineData(1101111101, "biljun u mija u miljun u mija u ħdax-il elf u mija u wieħed")] [InlineData(2000000000, "żewġ biljuni")] [InlineData(2147483647, "żewġ biljuni u mija u sebgħa u erbgħin miljun u erbgħa mija u tlieta u tmenin elf u sitt mija u sebgħa u erbgħin")] public void ToMasculineWords(int number, string expected) => Assert.Equal(expected, number.ToWords(GrammaticalGender.Masculine)); [Theory] [InlineData(0, "0")] [InlineData(1, "l-ewwel")] [InlineData(2, "it-tieni")] [InlineData(9, "id-disa'")] [InlineData(10, "l-għaxar")] [InlineData(11, "il-ħdax")] [InlineData(15, "il-ħmistax")] [InlineData(18, "it-tmintax")] [InlineData(20, "l-għoxrin")] [InlineData(21, "il-wieħed u għoxrin")] [InlineData(22, "it-tnejn u għoxrin")] [InlineData(28, "it-tmienja u għoxrin")] [InlineData(44, "l-erbgħa u erbgħin")] [InlineData(55, "il-ħamsa u ħamsin")] [InlineData(60, "is-sittin")] [InlineData(99, "id-disgħa u disgħin")] [InlineData(100, "il-mija")] [InlineData(101, "il-mija u wieħed")] [InlineData(1000, "l-elf")] [InlineData(1001, "l-elf u wieħed")] [InlineData(2000, "l-elfejn")] [InlineData(3000, "it-tlett elef")] public void ToOrdinalWords(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords()); [Theory] [InlineData(0, "0")] [InlineData(1, "l-ewwel")] [InlineData(2, "it-tieni")] [InlineData(9, "id-disa'")] [InlineData(10, "l-għaxar")] [InlineData(11, "il-ħdax")] [InlineData(15, "il-ħmistax")] [InlineData(18, "it-tmintax")] [InlineData(20, "l-għoxrin")] [InlineData(21, "il-wieħed u għoxrin")] [InlineData(22, "it-tnejn u għoxrin")] [InlineData(28, "it-tmienja u għoxrin")] [InlineData(44, "l-erbgħa u erbgħin")] [InlineData(55, "il-ħamsa u ħamsin")] [InlineData(60, "is-sittin")] [InlineData(99, "id-disgħa u disgħin")] [InlineData(100, "il-mija")] [InlineData(101, "il-mija u waħda")] [InlineData(1000, "l-elf")] [InlineData(1001, "l-elf u waħda")] [InlineData(2000, "l-elfejn")] [InlineData(3000, "it-tlett elef")] public void ToFeminineOrdinalWords(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Feminine)); [Theory] [InlineData(0, "0")] [InlineData(1, "l-ewwel")] [InlineData(2, "it-tieni")] [InlineData(9, "id-disa'")] [InlineData(10, "l-għaxar")] [InlineData(11, "il-ħdax")] [InlineData(15, "il-ħmistax")] [InlineData(18, "it-tmintax")] [InlineData(20, "l-għoxrin")] [InlineData(21, "il-wieħed u għoxrin")] [InlineData(22, "it-tnejn u għoxrin")] [InlineData(28, "it-tmienja u għoxrin")] [InlineData(44, "l-erbgħa u erbgħin")] [InlineData(55, "il-ħamsa u ħamsin")] [InlineData(60, "is-sittin")] [InlineData(99, "id-disgħa u disgħin")] [InlineData(100, "il-mija")] [InlineData(101, "il-mija u wieħed")] [InlineData(1000, "l-elf")] [InlineData(1001, "l-elf u wieħed")] [InlineData(2000, "l-elfejn")] [InlineData(3000, "it-tlett elef")] public void ToMasculineOrdinalWords(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Masculine)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/mt/TimeSpanHumanizeTests.cs ================================================ namespace mt; [UseCulture("mt")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "sena")] [InlineData(731, "sentejn")] [InlineData(1096, "3 snin")] [InlineData(4018, "11 snin")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "xahar")] [InlineData(61, "xahrejn")] [InlineData(92, "3 xhur")] [InlineData(335, "11 xhur")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(7, "ġimgħa")] [InlineData(14, "ġimgħatejn")] [InlineData(21, "3 ġimgħat")] public void Weeks(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "ġurnata")] [InlineData(2, "jumejn")] [InlineData(3, "3 jiem")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "siegħa")] [InlineData(2, "sagħtejn")] [InlineData(3, "3 siegħat")] public void Hours(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); [Theory] [InlineData(1, "minuta")] [InlineData(2, "2 minuti")] [InlineData(3, "3 minuti")] public void Minutes(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); [Theory] [InlineData(1, "sekonda")] [InlineData(2, "2 sekondi")] [InlineData(3, "3 sekondi")] public void Seconds(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); [Theory] [InlineData(1, "millisekonda")] [InlineData(2, "2 millisekondi")] [InlineData(3, "3 millisekondi")] public void Milliseconds(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); [Fact] public void NoTime() => Assert.Equal("0 millisekondi", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => Assert.Equal("xejn", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/nb/DateHumanizeTests.cs ================================================ namespace nb; [UseCulture("nb")] public class DateHumanizeTests { [Theory] [InlineData(-2, "2 dager siden")] [InlineData(-1, "i går")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "i morgen")] [InlineData(10, "10 dager fra nå")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(1, "ett sekund fra nå")] [InlineData(10, "10 sekunder fra nå")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(-2, "2 timer siden")] [InlineData(-1, "en time siden")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "en time fra nå")] [InlineData(10, "10 timer fra nå")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(-2, "2 minutter siden")] [InlineData(-1, "ett minutt siden")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "ett minutt fra nå")] [InlineData(10, "10 minutter fra nå")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(-2, "2 måneder siden")] [InlineData(-1, "en måned siden")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "en måned fra nå")] [InlineData(10, "10 måneder fra nå")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(-2, "2 sekunder siden")] [InlineData(-1, "ett sekund siden")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(-2, "2 år siden")] [InlineData(-1, "ett år siden")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "ett år fra nå")] [InlineData(2, "2 år fra nå")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Theory] [InlineData(0, "nå")] public void Now(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/nb/NumberToWordsTests.cs ================================================ namespace nb; [UseCulture("nb-NO")] public class NumberToWordsTests { [Theory] [InlineData(0, "null")] [InlineData(1, "en")] [InlineData(2, "to")] [InlineData(3, "tre")] [InlineData(4, "fire")] [InlineData(5, "fem")] [InlineData(6, "seks")] [InlineData(7, "sju")] [InlineData(8, "åtte")] [InlineData(9, "ni")] [InlineData(10, "ti")] [InlineData(20, "tjue")] [InlineData(30, "tretti")] [InlineData(40, "førti")] [InlineData(50, "femti")] [InlineData(60, "seksti")] [InlineData(70, "sytti")] [InlineData(80, "åtti")] [InlineData(90, "nitti")] [InlineData(98, "nittiåtte")] [InlineData(99, "nittini")] [InlineData(100, "hundre")] [InlineData(200, "tohundre")] [InlineData(1000, "tusen")] [InlineData(100000, "hundretusen")] [InlineData(1000000, "en million")] [InlineData(10000000, "ti millioner")] [InlineData(100000000, "hundre millioner")] [InlineData(1000000000, "en milliard")] [InlineData(2000000000, "to milliarder")] [InlineData(122, "hundreogtjueto")] [InlineData(3501, "tretusenfemhundreogen")] [InlineData(111, "hundreogelleve")] [InlineData(1001, "tusenogen")] [InlineData(1099, "tusenognittini")] [InlineData(1100, "ettusenethundre")] [InlineData(1112, "ettusenethundreogtolv")] [InlineData(11213, "ellevetusentohundreogtretten")] [InlineData(121314, "hundreogtjueentusentrehundreogfjorten")] [InlineData(2132415, "to millioner hundreogtrettitotusenfirehundreogfemten")] [InlineData(12345516, "tolv millioner trehundreogførtifemtusenfemhundreogseksten")] [InlineData(751633617, "sjuhundreogfemtien millioner sekshundreogtrettitretusensekshundreogsytten")] [InlineData(1111111118, "en milliard hundreogelleve millioner hundreogellevetusenethundreogatten")] [InlineData(-751633619, "minus sjuhundreogfemtien millioner sekshundreogtrettitretusensekshundreognitten")] [InlineData(1000010, "en million og ti")] [InlineData(1001009, "en million tusenogni")] [InlineData(1000099, "en million og nittini")] [InlineData(1000000010, "en milliard og ti")] [InlineData(1000110, "en million ethundreogti")] public void ToWords(int number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(0, "nullte")] [InlineData(1, "første")] [InlineData(2, "andre")] [InlineData(3, "tredje")] [InlineData(4, "fjerde")] [InlineData(5, "femte")] [InlineData(6, "sjette")] [InlineData(7, "sjuende")] [InlineData(8, "åttende")] [InlineData(9, "niende")] [InlineData(10, "tiende")] [InlineData(20, "tjuende")] [InlineData(30, "trettiende")] [InlineData(40, "førtiende")] [InlineData(50, "femtiende")] [InlineData(60, "sekstiende")] [InlineData(70, "syttiende")] [InlineData(80, "åttiende")] [InlineData(90, "nittiende")] [InlineData(98, "nittiåttende")] [InlineData(99, "nittiniende")] [InlineData(100, "hundrede")] [InlineData(200, "tohundrede")] [InlineData(1000, "tusende")] [InlineData(10000, "titusende")] [InlineData(100000, "hundretusende")] [InlineData(1000000, "millionte")] [InlineData(10000000, "ti millionte")] [InlineData(100000000, "hundre millionte")] [InlineData(1000000000, "milliardte")] [InlineData(2000000000, "to milliardte")] [InlineData(122, "hundreogtjueandre")] [InlineData(3501, "tretusenfemhundreogførste")] [InlineData(111, "hundreogellevte")] [InlineData(1112, "ettusenethundreogtolvte")] [InlineData(11213, "ellevetusentohundreogtrettende")] [InlineData(121314, "hundreogtjueentusentrehundreogfjortende")] [InlineData(2132415, "to millioner hundreogtrettitotusenfirehundreogfemtende")] [InlineData(12345516, "tolv millioner trehundreogførtifemtusenfemhundreogsekstende")] [InlineData(751633617, "sjuhundreogfemtien millioner sekshundreogtrettitretusensekshundreogsyttende")] [InlineData(1111111118, "en milliard hundreogelleve millioner hundreogellevetusenethundreogattende")] [InlineData(-751633619, "minus sjuhundreogfemtien millioner sekshundreogtrettitretusensekshundreognittende")] [InlineData(1000010, "en million og tiende")] [InlineData(1001009, "en million tusenogniende")] [InlineData(1000099, "en million og nittiniende")] [InlineData(1000000010, "en milliard og tiende")] [InlineData(1000110, "en million ethundreogtiende")] public void ToOrdinalWords(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords()); [Theory] [InlineData(2, "to")] [InlineData(1, "ei")] [InlineData(0, "null")] [InlineData(-1, "minus ei")] [InlineData(-2, "minus to")] public void ToWordsFeminine(int number, string expected) => Assert.Equal(expected, number.ToWords(GrammaticalGender.Feminine)); [Theory] [InlineData(2, "to")] [InlineData(1, "et")] [InlineData(0, "null")] [InlineData(-1, "minus et")] [InlineData(-2, "minus to")] public void ToWordsNeuter(int number, string expected) => Assert.Equal(expected, number.ToWords(GrammaticalGender.Neuter)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/nb/TimeSpanHumanizeTests.cs ================================================ namespace nb; [UseCulture("nb")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Native speaker")] [InlineData(366, "1 år")] [InlineData(731, "2 år")] [InlineData(1096, "3 år")] [InlineData(4018, "11 år")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Native speaker")] [InlineData(31, "1 måned")] [InlineData(61, "2 måneder")] [InlineData(92, "3 måneder")] [InlineData(335, "11 måneder")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(7, "1 uke")] [InlineData(14, "2 uker")] public void Weeks(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "1 dag")] [InlineData(2, "2 dager")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "1 time")] [InlineData(2, "2 timer")] public void Hours(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); [Theory] [InlineData(1, "1 minutt")] [InlineData(2, "2 minutter")] public void Minutes(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); [Theory] [InlineData(1, "1 sekund")] [InlineData(2, "2 sekunder")] public void Seconds(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); [Theory] [InlineData(1, "1 millisekund")] [InlineData(2, "2 millisekunder")] public void Milliseconds(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); [Fact] public void NoTime() => Assert.Equal("0 millisekunder", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => Assert.Equal("ingen tid", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/nb-NO/DateHumanizeTests.cs ================================================ namespace nbNO; [UseCulture("nb-NO")] public class DateHumanizeTests { [Theory] [InlineData(-2, "2 dager siden")] [InlineData(-1, "i går")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "i morgen")] [InlineData(10, "10 dager fra nå")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(1, "ett sekund fra nå")] [InlineData(10, "10 sekunder fra nå")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(-2, "2 timer siden")] [InlineData(-1, "en time siden")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "en time fra nå")] [InlineData(10, "10 timer fra nå")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(-2, "2 minutter siden")] [InlineData(-1, "ett minutt siden")] [InlineData(60, "en time siden")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "ett minutt fra nå")] [InlineData(59, "59 minutter fra nå")] [InlineData(60, "en time fra nå")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(-2, "2 måneder siden")] [InlineData(-1, "en måned siden")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "en måned fra nå")] [InlineData(10, "10 måneder fra nå")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(-2, "2 sekunder siden")] [InlineData(-1, "ett sekund siden")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(-2, "2 år siden")] [InlineData(-1, "ett år siden")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "ett år fra nå")] [InlineData(2, "2 år fra nå")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Theory] [InlineData(0, "nå")] public void Now(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/nb-NO/TimeSpanHumanizeTests.cs ================================================ namespace nbNO; [UseCulture("nb-NO")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Native speaker")] [InlineData(366, "1 år")] [InlineData(731, "2 år")] [InlineData(1096, "3 år")] [InlineData(4018, "11 år")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Native speaker")] [InlineData(31, "1 måned")] [InlineData(61, "2 måneder")] [InlineData(92, "3 måneder")] [InlineData(335, "11 måneder")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(7, "1 uke")] [InlineData(14, "2 uker")] public void Weeks(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "1 dag")] [InlineData(2, "2 dager")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "1 time")] [InlineData(2, "2 timer")] public void Hours(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); [Theory] [InlineData(1, "1 minutt")] [InlineData(2, "2 minutter")] public void Minutes(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); [Theory] [InlineData(1, "1 sekund")] [InlineData(2, "2 sekunder")] public void Seconds(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); [Theory] [InlineData(1, "1 millisekund")] [InlineData(2, "2 millisekunder")] public void Milliseconds(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); [Fact] public void NoTime() => Assert.Equal("0 millisekunder", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => Assert.Equal("ingen tid", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/nl/DateHumanizeTests.cs ================================================ namespace nl; [UseCulture("nl-NL")] public class DateHumanizeTests { [Theory] [InlineData(2, "2 dagen geleden")] [InlineData(1, "gisteren")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(2, "2 uur geleden")] [InlineData(1, "1 uur geleden")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(2, "2 minuten geleden")] [InlineData(1, "1 minuut geleden")] [InlineData(60, "1 uur geleden")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(2, "2 maanden geleden")] [InlineData(1, "1 maand geleden")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(2, "2 seconden geleden")] [InlineData(1, "1 seconde geleden")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(2, "2 jaar geleden")] [InlineData(1, "1 jaar geleden")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(2, "over 2 dagen")] [InlineData(1, "morgen")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(2, "over 2 uur")] [InlineData(1, "over 1 uur")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(2, "over 2 minuten")] [InlineData(1, "over 1 minuut")] [InlineData(60, "over 1 uur")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(2, "over 2 maanden")] [InlineData(1, "over 1 maand")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(2, "over 2 seconden")] [InlineData(1, "over 1 seconde")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(2, "over 2 jaar")] [InlineData(1, "over 1 jaar")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Theory] [InlineData(0, "nu")] public void RightNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/nl/NumberToWordsTests.cs ================================================ namespace nl; [UseCulture("nl-NL")] public class NumberToWordsTests { [Theory] [InlineData(0, "nul")] [InlineData(1, "een")] [InlineData(-10, "min tien")] [InlineData(10, "tien")] [InlineData(11, "elf")] [InlineData(122, "honderdtweeëntwintig")] [InlineData(3501, "drieduizend vijfhonderdeen")] [InlineData(100, "honderd")] [InlineData(1000, "duizend")] [InlineData(100000, "honderdduizend")] [InlineData(1000000, "een miljoen")] [InlineData(10000000, "tien miljoen")] [InlineData(100000000, "honderd miljoen")] [InlineData(1000000000, "een miljard")] [InlineData(111, "honderdelf")] [InlineData(1111, "duizend honderdelf")] [InlineData(111111, "honderdelfduizend honderdelf")] [InlineData(1111111, "een miljoen honderdelfduizend honderdelf")] [InlineData(11111111, "elf miljoen honderdelfduizend honderdelf")] [InlineData(111111111, "honderdelf miljoen honderdelfduizend honderdelf")] [InlineData(1111111111, "een miljard honderdelf miljoen honderdelfduizend honderdelf")] [InlineData(123, "honderddrieëntwintig")] [InlineData(124, "honderdvierentwintig")] [InlineData(1234, "duizend tweehonderdvierendertig")] [InlineData(12345, "twaalfduizend driehonderdvijfenveertig")] [InlineData(123456, "honderddrieëntwintigduizend vierhonderdzesenvijftig")] [InlineData(1234567, "een miljoen tweehonderdvierendertigduizend vijfhonderdzevenenzestig")] [InlineData(12345678, "twaalf miljoen driehonderdvijfenveertigduizend zeshonderdachtenzeventig")] [InlineData(123456789, "honderddrieëntwintig miljoen vierhonderdzesenvijftigduizend zevenhonderdnegenentachtig")] [InlineData(1234567890, "een miljard tweehonderdvierendertig miljoen vijfhonderdzevenenzestigduizend achthonderdnegentig")] [InlineData(1234567899, "een miljard tweehonderdvierendertig miljoen vijfhonderdzevenenzestigduizend achthonderdnegenennegentig")] [InlineData(108, "honderdacht")] [InlineData(678, "zeshonderdachtenzeventig")] [InlineData(2013, "tweeduizend dertien")] [InlineData(2577, "tweeduizend vijfhonderdzevenenzeventig")] [InlineData(17053980, "zeventien miljoen drieënvijftigduizend negenhonderdtachtig")] [InlineData(415618, "vierhonderdvijftienduizend zeshonderdachttien")] [InlineData(16415618, "zestien miljoen vierhonderdvijftienduizend zeshonderdachttien")] [InlineData(322, "driehonderdtweeëntwintig")] public void IntToWords(int number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(100_000_000_000L, "honderd miljard")] [InlineData(1_000_000_000_000L, "een biljoen")] [InlineData(100_000_000_000_000L, "honderd biljoen")] [InlineData(1_000_000_000_000_000L, "een biljard")] [InlineData(100_000_000_000_000_000L, "honderd biljard")] [InlineData(1_000_000_000_000_000_000L, "een triljoen")] [InlineData(9_223_372_036_854_775_807L, "negen triljoen tweehonderddrieëntwintig biljard driehonderdtweeënzeventig biljoen zesendertig miljard achthonderdvierenvijftig miljoen zevenhonderdvijfenzeventigduizend achthonderdzeven")] public void LongToWords(long number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(0, "nulde")] [InlineData(1, "eerste")] [InlineData(2, "tweede")] [InlineData(3, "derde")] [InlineData(4, "vierde")] [InlineData(5, "vijfde")] [InlineData(6, "zesde")] [InlineData(7, "zevende")] [InlineData(8, "achtste")] [InlineData(9, "negende")] [InlineData(10, "tiende")] [InlineData(11, "elfde")] [InlineData(12, "twaalfde")] [InlineData(13, "dertiende")] [InlineData(14, "veertiende")] [InlineData(15, "vijftiende")] [InlineData(16, "zestiende")] [InlineData(17, "zeventiende")] [InlineData(18, "achttiende")] [InlineData(19, "negentiende")] [InlineData(20, "twintigste")] [InlineData(21, "eenentwintigste")] [InlineData(22, "tweeëntwintigste")] [InlineData(30, "dertigste")] [InlineData(40, "veertigste")] [InlineData(50, "vijftigste")] [InlineData(60, "zestigste")] [InlineData(70, "zeventigste")] [InlineData(80, "tachtigste")] [InlineData(90, "negentigste")] [InlineData(95, "vijfennegentigste")] [InlineData(96, "zesennegentigste")] [InlineData(100, "honderdste")] [InlineData(101, "honderdeerste")] [InlineData(106, "honderdzesde")] [InlineData(108, "honderdachtste")] [InlineData(112, "honderdtwaalfde")] [InlineData(120, "honderdtwintigste")] [InlineData(121, "honderdeenentwintigste")] [InlineData(1000, "duizendste")] [InlineData(1001, "duizend eerste")] [InlineData(1005, "duizend vijfde")] [InlineData(1008, "duizend achtste")] [InlineData(1012, "duizend twaalfde")] [InlineData(1021, "duizend eenentwintigste")] [InlineData(10000, "tienduizendste")] [InlineData(10121, "tienduizend honderdeenentwintigste")] [InlineData(100000, "honderdduizendste")] [InlineData(100001, "honderdduizend eerste")] [InlineData(1000000, "een miljoenste")] [InlineData(1000001, "een miljoen eerste")] public void ToOrdinalWords(int number, string words) => Assert.Equal(words, number.ToOrdinalWords()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/nl/OrdinalizeTests.cs ================================================ namespace nl; [UseCulture("nl")] public class OrdinalizeTests { [Theory] [InlineData("0", "0")] [InlineData("1", "1e")] [InlineData("2", "2e")] [InlineData("3", "3e")] [InlineData("4", "4e")] [InlineData("5", "5e")] [InlineData("6", "6e")] [InlineData("23", "23e")] [InlineData("100", "100e")] [InlineData("101", "101e")] [InlineData("102", "102e")] [InlineData("103", "103e")] [InlineData("1001", "1001e")] public void OrdinalizeString(string number, string ordinalized) => Assert.Equal(number.Ordinalize(), ordinalized); } ================================================ FILE: tests/Humanizer.Tests/Localisation/nl/TimeSpanHumanizeTests.cs ================================================ namespace nl; [UseCulture("nl-NL")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Native speaker")] [InlineData(366, "1 jaar")] [InlineData(731, "2 jaar")] [InlineData(1096, "3 jaar")] [InlineData(4018, "11 jaar")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Native speaker")] [InlineData(31, "1 maand")] [InlineData(61, "2 maanden")] [InlineData(92, "3 maanden")] [InlineData(335, "11 maanden")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Fact] public void TwoWeeks() => Assert.Equal("2 weken", TimeSpan.FromDays(14).Humanize()); [Fact] public void OneWeek() => Assert.Equal("1 week", TimeSpan.FromDays(7).Humanize()); [Fact] public void SixDays() => Assert.Equal("6 dagen", TimeSpan.FromDays(6).Humanize()); [Fact] public void TwoDays() => Assert.Equal("2 dagen", TimeSpan.FromDays(2).Humanize()); [Fact] public void OneDay() => Assert.Equal("1 dag", TimeSpan.FromDays(1).Humanize()); [Fact] public void TwoHours() => Assert.Equal("2 uur", TimeSpan.FromHours(2).Humanize()); [Fact] public void OneHour() => Assert.Equal("1 uur", TimeSpan.FromHours(1).Humanize()); [Fact] public void TwoMinutes() => Assert.Equal("2 minuten", TimeSpan.FromMinutes(2).Humanize()); [Fact] public void OneMinute() => Assert.Equal("1 minuut", TimeSpan.FromMinutes(1).Humanize()); [Fact] public void TwoSeconds() => Assert.Equal("2 seconden", TimeSpan.FromSeconds(2).Humanize()); [Fact] public void OneSecond() => Assert.Equal("1 seconde", TimeSpan.FromSeconds(1).Humanize()); [Fact] public void TwoMilliseconds() => Assert.Equal("2 milliseconden", TimeSpan.FromMilliseconds(2).Humanize()); [Fact] public void OneMillisecond() => Assert.Equal("1 milliseconde", TimeSpan.FromMilliseconds(1).Humanize()); [Fact] public void NoTime() => Assert.Equal("0 milliseconden", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => Assert.Equal("geen tijd", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/pl/DateHumanizeTests.cs ================================================ namespace pl; [UseCulture("pl")] public class DateHumanizeTests { [Theory] [InlineData(1, "za sekundę")] [InlineData(2, "za 2 sekundy")] [InlineData(3, "za 3 sekundy")] [InlineData(4, "za 4 sekundy")] [InlineData(5, "za 5 sekund")] [InlineData(6, "za 6 sekund")] [InlineData(10, "za 10 sekund")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(1, "za minutę")] [InlineData(2, "za 2 minuty")] [InlineData(3, "za 3 minuty")] [InlineData(4, "za 4 minuty")] [InlineData(5, "za 5 minut")] [InlineData(6, "za 6 minut")] [InlineData(10, "za 10 minut")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(1, "za godzinę")] [InlineData(2, "za 2 godziny")] [InlineData(3, "za 3 godziny")] [InlineData(4, "za 4 godziny")] [InlineData(5, "za 5 godzin")] [InlineData(6, "za 6 godzin")] [InlineData(10, "za 10 godzin")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(1, "jutro")] [InlineData(2, "za 2 dni")] [InlineData(3, "za 3 dni")] [InlineData(4, "za 4 dni")] [InlineData(5, "za 5 dni")] [InlineData(6, "za 6 dni")] [InlineData(10, "za 10 dni")] public void DayFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(1, "za miesiąc")] [InlineData(2, "za 2 miesiące")] [InlineData(3, "za 3 miesiące")] [InlineData(4, "za 4 miesiące")] [InlineData(5, "za 5 miesięcy")] [InlineData(6, "za 6 miesięcy")] [InlineData(10, "za 10 miesięcy")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(1, "za rok")] [InlineData(2, "za 2 lata")] [InlineData(3, "za 3 lata")] [InlineData(4, "za 4 lata")] [InlineData(5, "za 5 lat")] [InlineData(6, "za 6 lat")] [InlineData(10, "za 10 lat")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Theory] [InlineData(1, "przed sekundą")] [InlineData(2, "przed 2 sekundami")] [InlineData(3, "przed 3 sekundami")] [InlineData(4, "przed 4 sekundami")] [InlineData(5, "przed 5 sekundami")] [InlineData(6, "przed 6 sekundami")] [InlineData(10, "przed 10 sekundami")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "przed minutą")] [InlineData(2, "przed 2 minutami")] [InlineData(3, "przed 3 minutami")] [InlineData(4, "przed 4 minutami")] [InlineData(5, "przed 5 minutami")] [InlineData(6, "przed 6 minutami")] [InlineData(10, "przed 10 minutami")] [InlineData(60, "przed godziną")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "przed godziną")] [InlineData(2, "przed 2 godzinami")] [InlineData(3, "przed 3 godzinami")] [InlineData(4, "przed 4 godzinami")] [InlineData(5, "przed 5 godzinami")] [InlineData(6, "przed 6 godzinami")] [InlineData(10, "przed 10 godzinami")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "wczoraj")] [InlineData(2, "przed 2 dniami")] [InlineData(3, "przed 3 dniami")] [InlineData(4, "przed 4 dniami")] [InlineData(9, "przed 9 dniami")] [InlineData(10, "przed 10 dniami")] public void DayAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "przed miesiącem")] [InlineData(2, "przed 2 miesiącami")] [InlineData(3, "przed 3 miesiącami")] [InlineData(4, "przed 4 miesiącami")] [InlineData(5, "przed 5 miesiącami")] [InlineData(6, "przed 6 miesiącami")] [InlineData(10, "przed 10 miesiącami")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "przed rokiem")] [InlineData(2, "przed 2 laty")] [InlineData(3, "przed 3 laty")] [InlineData(4, "przed 4 laty")] [InlineData(5, "przed 5 laty")] [InlineData(6, "przed 6 laty")] [InlineData(10, "przed 10 laty")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Fact] public void Now() => DateHumanize.Verify("teraz", 0, TimeUnit.Day, Tense.Past); } ================================================ FILE: tests/Humanizer.Tests/Localisation/pl/NumberToWordsTests.cs ================================================ namespace pl; [UseCulture("pl")] public class NumberToWordsTests { [Theory] [InlineData(0, "zero")] [InlineData(1, "jeden")] [InlineData(2, "dwa")] [InlineData(3, "trzy")] [InlineData(4, "cztery")] [InlineData(5, "pięć")] [InlineData(6, "sześć")] [InlineData(7, "siedem")] [InlineData(8, "osiem")] [InlineData(9, "dziewięć")] [InlineData(10, "dziesięć")] [InlineData(11, "jedenaście")] [InlineData(12, "dwanaście")] [InlineData(13, "trzynaście")] [InlineData(14, "czternaście")] [InlineData(15, "piętnaście")] [InlineData(16, "szesnaście")] [InlineData(17, "siedemnaście")] [InlineData(18, "osiemnaście")] [InlineData(19, "dziewiętnaście")] [InlineData(20, "dwadzieścia")] [InlineData(30, "trzydzieści")] [InlineData(40, "czterdzieści")] [InlineData(50, "pięćdziesiąt")] [InlineData(60, "sześćdziesiąt")] [InlineData(70, "siedemdziesiąt")] [InlineData(80, "osiemdziesiąt")] [InlineData(90, "dziewięćdziesiąt")] [InlineData(100, "sto")] [InlineData(112, "sto dwanaście")] [InlineData(128, "sto dwadzieścia osiem")] [InlineData(1000, "tysiąc")] [InlineData(2000, "dwa tysiące")] [InlineData(5000, "pięć tysięcy")] [InlineData(10000, "dziesięć tysięcy")] [InlineData(12000, "dwanaście tysięcy")] [InlineData(20000, "dwadzieścia tysięcy")] [InlineData(22000, "dwadzieścia dwa tysiące")] [InlineData(25000, "dwadzieścia pięć tysięcy")] [InlineData(31000, "trzydzieści jeden tysięcy")] [InlineData(34000, "trzydzieści cztery tysiące")] [InlineData(100000, "sto tysięcy")] [InlineData(500000, "pięćset tysięcy")] [InlineData(1000000, "milion")] [InlineData(2000000, "dwa miliony")] [InlineData(5000000, "pięć milionów")] [InlineData(1000000000, "miliard")] [InlineData(2000000000, "dwa miliardy")] [InlineData(1501001892, "miliard pięćset jeden milionów tysiąc osiemset dziewięćdziesiąt dwa")] [InlineData(2147483647, "dwa miliardy sto czterdzieści siedem milionów czterysta osiemdziesiąt trzy tysiące sześćset czterdzieści siedem")] [InlineData(-1501001892, "minus miliard pięćset jeden milionów tysiąc osiemset dziewięćdziesiąt dwa")] [InlineData(long.MaxValue, "dziewięć trylionów " + "dwieście dwadzieścia trzy biliardy " + "trzysta siedemdziesiąt dwa biliony " + "trzydzieści sześć miliardów " + "osiemset pięćdziesiąt cztery miliony " + "siedemset siedemdziesiąt pięć tysięcy " + "osiemset siedem")] [InlineData(long.MinValue, "minus dziewięć trylionów " + "dwieście dwadzieścia trzy biliardy " + "trzysta siedemdziesiąt dwa biliony " + "trzydzieści sześć miliardów " + "osiemset pięćdziesiąt cztery miliony " + "siedemset siedemdziesiąt pięć tysięcy " + "osiemset osiem")] public void ToWordsPolish(long number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(-1, "minus jeden", GrammaticalGender.Masculine)] [InlineData(-1, "minus jedna", GrammaticalGender.Feminine)] [InlineData(-1, "minus jedno", GrammaticalGender.Neuter)] [InlineData(-2, "minus dwa", GrammaticalGender.Masculine)] [InlineData(-2, "minus dwie", GrammaticalGender.Feminine)] [InlineData(-2, "minus dwa", GrammaticalGender.Neuter)] [InlineData(1, "jeden", GrammaticalGender.Masculine)] [InlineData(1, "jedna", GrammaticalGender.Feminine)] [InlineData(1, "jedno", GrammaticalGender.Neuter)] [InlineData(2, "dwa", GrammaticalGender.Masculine)] [InlineData(2, "dwie", GrammaticalGender.Feminine)] [InlineData(2, "dwa", GrammaticalGender.Neuter)] [InlineData(121, "sto dwadzieścia jeden", GrammaticalGender.Masculine)] [InlineData(121, "sto dwadzieścia jeden", GrammaticalGender.Feminine)] [InlineData(121, "sto dwadzieścia jeden", GrammaticalGender.Neuter)] [InlineData(122, "sto dwadzieścia dwa", GrammaticalGender.Masculine)] [InlineData(122, "sto dwadzieścia dwie", GrammaticalGender.Feminine)] [InlineData(122, "sto dwadzieścia dwa", GrammaticalGender.Neuter)] [InlineData(-2542, "minus dwa tysiące pięćset czterdzieści dwa", GrammaticalGender.Masculine)] [InlineData(-2542, "minus dwa tysiące pięćset czterdzieści dwie", GrammaticalGender.Feminine)] [InlineData(-2542, "minus dwa tysiące pięćset czterdzieści dwa", GrammaticalGender.Neuter)] [InlineData(1000001, "milion jeden", GrammaticalGender.Feminine)] [InlineData(-1000001, "minus milion jeden", GrammaticalGender.Feminine)] [InlineData(1000002, "milion dwa", GrammaticalGender.Masculine)] [InlineData(1000002, "milion dwie", GrammaticalGender.Feminine)] [InlineData(1000002, "milion dwa", GrammaticalGender.Neuter)] public void ToWordsPolishWithGender(int number, string expected, GrammaticalGender gender) => Assert.Equal(expected, number.ToWords(gender)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/pl/TimeSpanHumanizeTests.cs ================================================ namespace pl; [UseCulture("pl")] public class TimeSpanHumanizeTests { [Theory] [InlineData(1, "1 milisekunda")] [InlineData(2, "2 milisekundy")] [InlineData(3, "3 milisekundy")] [InlineData(4, "4 milisekundy")] [InlineData(5, "5 milisekund")] [InlineData(6, "6 milisekund")] [InlineData(10, "10 milisekund")] public void Milliseconds(int number, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(number).Humanize()); [Theory] [InlineData(1, "1 sekunda")] [InlineData(2, "2 sekundy")] [InlineData(3, "3 sekundy")] [InlineData(4, "4 sekundy")] [InlineData(5, "5 sekund")] [InlineData(6, "6 sekund")] [InlineData(10, "10 sekund")] public void Seconds(int number, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(number).Humanize()); [Theory] [InlineData(1, "1 minuta")] [InlineData(2, "2 minuty")] [InlineData(3, "3 minuty")] [InlineData(4, "4 minuty")] [InlineData(5, "5 minut")] [InlineData(6, "6 minut")] [InlineData(10, "10 minut")] public void Minutes(int number, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(number).Humanize()); [Theory] [InlineData(1, "1 godzina")] [InlineData(2, "2 godziny")] [InlineData(3, "3 godziny")] [InlineData(4, "4 godziny")] [InlineData(5, "5 godzin")] [InlineData(6, "6 godzin")] [InlineData(10, "10 godzin")] public void Hours(int number, string expected) => Assert.Equal(expected, TimeSpan.FromHours(number).Humanize()); [Theory] [InlineData(1, "1 dzień")] [InlineData(2, "2 dni")] [InlineData(3, "3 dni")] [InlineData(4, "4 dni")] [InlineData(5, "5 dni")] [InlineData(6, "6 dni")] public void Days(int number, string expected) => Assert.Equal(expected, TimeSpan.FromDays(number).Humanize()); [Theory] [InlineData(1, "1 tydzień")] [InlineData(2, "2 tygodnie")] [InlineData(3, "3 tygodnie")] [InlineData(4, "4 tygodnie")] [InlineData(5, "5 tygodni")] [InlineData(6, "6 tygodni")] public void Weeks(int number, string expected) => Assert.Equal(expected, TimeSpan.FromDays(number * 7).Humanize()); [Theory] [Trait("Translation", "Google")] [InlineData(31, "1 miesiąc")] [InlineData(61, "2 miesiące")] [InlineData(92, "3 miesiące")] [InlineData(335, "11 miesięcy")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(366, "1 rok")] [InlineData(731, "2 lata")] [InlineData(1096, "3 lata")] [InlineData(4018, "11 lat")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Fact] public void NoTime() => Assert.Equal("0 milisekund", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => Assert.Equal("brak czasu", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/pt/Bytes/ByteSizeExtensionsTests.cs ================================================ namespace pt.Bytes; [UseCulture("pt")] public class ByteSizeExtensionsTests { [Theory] [InlineData(2, null, "2 TB")] [InlineData(2, "GB", "2048 GB")] [InlineData(2.123, "#.#", "2,1 TB")] public void HumanizesTerabytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Terabytes().Humanize(format)); [Theory] [InlineData(0, null, "0 bit")] [InlineData(0, "GB", "0 GB")] [InlineData(2, null, "2 GB")] [InlineData(2, "MB", "2048 MB")] [InlineData(2.123, "#.##", "2,12 GB")] public void HumanizesGigabytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Gigabytes().Humanize(format)); [Theory] [InlineData(0, null, "0 bit")] [InlineData(0, "MB", "0 MB")] [InlineData(2, null, "2 MB")] [InlineData(2, "KB", "2048 KB")] [InlineData(2.123, "#", "2 MB")] public void HumanizesMegabytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Megabytes().Humanize(format)); [Theory] [InlineData(0, null, "0 bit")] [InlineData(0, "KB", "0 KB")] [InlineData(2, null, "2 KB")] [InlineData(2, "B", "2048 B")] [InlineData(2.123, "#.####", "2,123 KB")] public void HumanizesKilobytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Kilobytes().Humanize(format)); [Theory] [InlineData(0, null, "0 bit")] [InlineData(0, "#.##", "0 bit")] [InlineData(0, "#.## B", "0 B")] [InlineData(0, "B", "0 B")] [InlineData(2, null, "2 B")] [InlineData(2000, "KB", "1,95 KB")] [InlineData(2123, "#.##", "2,07 KB")] [InlineData(10000000, "KB", "9765,63 KB")] [InlineData(10000000, "#,##0 KB", "9.766 KB")] [InlineData(10000000, "#,##0.# KB", "9.765,6 KB")] public void HumanizesBytes(double input, string? format, string expectedValue) { expectedValue = expectedValue.Replace(".", NumberFormatInfo.CurrentInfo.NumberGroupSeparator); Assert.Equal( expectedValue, input .Bytes() .Humanize(format)); } [Theory] [InlineData(0, null, "0 bit")] [InlineData(0, "b", "0 bit")] [InlineData(2, null, "2 bit")] [InlineData(12, "B", "1,5 B")] [InlineData(10000, "#.# KB", "1,2 KB")] public void HumanizesBits(long input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Bits().Humanize(format)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/pt/DateHumanizeTests.cs ================================================ namespace pt; [UseCulture("pt")] public class DateHumanizeTests { [Theory] [InlineData(-2, "há 2 segundos")] [InlineData(-1, "há um segundo")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "daqui a um segundo")] [InlineData(2, "daqui a 2 segundos")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(-2, "há 2 minutos")] [InlineData(-1, "há um minuto")] [InlineData(60, "há uma hora")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "daqui a um minuto")] [InlineData(2, "daqui a 2 minutos")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(-2, "há 2 horas")] [InlineData(-1, "há uma hora")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "daqui a uma hora")] [InlineData(2, "daqui a 2 horas")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(-2, "há 2 dias")] [InlineData(-1, "ontem")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "amanhã")] [InlineData(2, "daqui a 2 dias")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(-2, "há 2 meses")] [InlineData(-1, "há um mês")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "daqui a um mês")] [InlineData(2, "daqui a 2 meses")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(-2, "há 2 anos")] [InlineData(-1, "há um ano")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "daqui a um ano")] [InlineData(2, "daqui a 2 anos")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Fact] public void Now() => DateHumanize.Verify("agora", 0, TimeUnit.Day, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/pt/NumberToWordsTests.cs ================================================ namespace pt; [UseCulture("pt")] public class NumberToWordsTests { [Theory] [InlineData(0, "zero")] [InlineData(1, "um")] [InlineData(2, "dois")] [InlineData(3, "três")] [InlineData(4, "quatro")] [InlineData(5, "cinco")] [InlineData(6, "seis")] [InlineData(7, "sete")] [InlineData(8, "oito")] [InlineData(9, "nove")] [InlineData(10, "dez")] [InlineData(11, "onze")] [InlineData(12, "doze")] [InlineData(13, "treze")] [InlineData(14, "quatorze")] [InlineData(15, "quinze")] [InlineData(16, "dezasseis")] [InlineData(17, "dezassete")] [InlineData(18, "dezoito")] [InlineData(19, "dezanove")] [InlineData(20, "vinte")] [InlineData(30, "trinta")] [InlineData(40, "quarenta")] [InlineData(50, "cinquenta")] [InlineData(51, "cinquenta e um")] [InlineData(60, "sessenta")] [InlineData(66, "sessenta e seis")] [InlineData(70, "setenta")] [InlineData(80, "oitenta")] [InlineData(90, "noventa")] [InlineData(100, "cem")] [InlineData(200, "duzentos")] [InlineData(300, "trezentos")] [InlineData(400, "quatrocentos")] [InlineData(500, "quinhentos")] [InlineData(600, "seiscentos")] [InlineData(700, "setecentos")] [InlineData(800, "oitocentos")] [InlineData(900, "novecentos")] [InlineData(1000, "mil")] [InlineData(2000, "dois mil")] [InlineData(3000, "três mil")] [InlineData(4000, "quatro mil")] [InlineData(5000, "cinco mil")] [InlineData(6000, "seis mil")] [InlineData(7000, "sete mil")] [InlineData(8000, "oito mil")] [InlineData(9000, "nove mil")] [InlineData(10000, "dez mil")] [InlineData(100000, "cem mil")] [InlineData(1000000, "um milhão")] [InlineData(1000000000, "mil milhões")] [InlineData(37, "trinta e sete")] [InlineData(637, "seiscentos e trinta e sete")] [InlineData(1637, "mil seiscentos e trinta e sete")] [InlineData(61637, "sessenta e um mil seiscentos e trinta e sete")] [InlineData(961637, "novecentos e sessenta e um mil seiscentos e trinta e sete")] [InlineData(5961637, "cinco milhões novecentos e sessenta e um mil seiscentos e trinta e sete")] [InlineData(25961637, "vinte e cinco milhões novecentos e sessenta e um mil seiscentos e trinta e sete")] [InlineData(425961637, "quatrocentos e vinte e cinco milhões novecentos e sessenta e um mil seiscentos e trinta e sete")] [InlineData(10000000, "dez milhões")] [InlineData(100000000, "cem milhões")] [InlineData(1101111101, "mil milhões cento e um milhões cento e onze mil cento e um")] [InlineData(111, "cento e onze")] [InlineData(1111, "mil cento e onze")] [InlineData(1111101, "um milhão cento e onze mil cento e um")] [InlineData(111111, "cento e onze mil cento e onze")] [InlineData(1111111, "um milhão cento e onze mil cento e onze")] [InlineData(11111111, "onze milhões cento e onze mil cento e onze")] [InlineData(111111111, "cento e onze milhões cento e onze mil cento e onze")] [InlineData(1111111111, "mil milhões cento e onze milhões cento e onze mil cento e onze")] [InlineData(122, "cento e vinte e dois")] [InlineData(123, "cento e vinte e três")] [InlineData(1234, "mil duzentos e trinta e quatro")] [InlineData(12345, "doze mil trezentos e quarenta e cinco")] [InlineData(123456, "cento e vinte e três mil quatrocentos e cinquenta e seis")] [InlineData(1234567, "um milhão duzentos e trinta e quatro mil quinhentos e sessenta e sete")] [InlineData(12345678, "doze milhões trezentos e quarenta e cinco mil seiscentos e setenta e oito")] [InlineData(123456789, "cento e vinte e três milhões quatrocentos e cinquenta e seis mil setecentos e oitenta e nove")] [InlineData(1234567890, "mil milhões duzentos e trinta e quatro milhões quinhentos e sessenta e sete mil oitocentos e noventa")] [InlineData(1999, "mil novecentos e noventa e nove")] [InlineData(2000000, "dois milhões")] [InlineData(2000000000, "dois mil milhões")] [InlineData(2001000000, "dois mil milhões um milhão")] [InlineData(2014, "dois mil e quatorze")] [InlineData(2048, "dois mil e quarenta e oito")] [InlineData(21, "vinte e um")] [InlineData(211, "duzentos e onze")] [InlineData(2111101, "dois milhões cento e onze mil cento e um")] [InlineData(221, "duzentos e vinte e um")] [InlineData(3501, "três mil quinhentos e um")] [InlineData(8100, "oito mil e cem")] [InlineData(999999999999, "novecentos e noventa e nove mil milhões novecentos e noventa e nove milhões novecentos e noventa e nove mil novecentos e noventa e nove")] [InlineData(-999999999999, "menos novecentos e noventa e nove mil milhões novecentos e noventa e nove milhões novecentos e noventa e nove mil novecentos e noventa e nove")] public void ToWords(long number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(0, "zero")] [InlineData(1, "uma")] [InlineData(2, "duas")] [InlineData(3, "três")] [InlineData(11, "onze")] [InlineData(21, "vinte e uma")] [InlineData(122, "cento e vinte e duas")] [InlineData(232, "duzentas e trinta e duas")] [InlineData(343, "trezentas e quarenta e três")] [InlineData(3501, "três mil quinhentas e uma")] [InlineData(100, "cem")] [InlineData(1000, "mil")] [InlineData(111, "cento e onze")] [InlineData(1111, "mil cento e onze")] [InlineData(111111, "cento e onze mil cento e onze")] [InlineData(1111101, "um milhão cento e onze mil cento e uma")] [InlineData(1111111, "um milhão cento e onze mil cento e onze")] [InlineData(2111102, "dois milhões cento e onze mil cento e duas")] [InlineData(3111101, "três milhões cento e onze mil cento e uma")] [InlineData(1101111101, "mil milhões cento e um milhões cento e onze mil cento e uma")] [InlineData(2101111101, "dois mil milhões cento e um milhões cento e onze mil cento e uma")] [InlineData(1234, "mil duzentas e trinta e quatro")] [InlineData(8100, "oito mil e cem")] [InlineData(12345, "doze mil trezentas e quarenta e cinco")] public void ToFeminineWords(int number, string expected) => Assert.Equal(expected, number.ToWords(GrammaticalGender.Feminine)); [Theory] [InlineData(0, "zero")] [InlineData(1, "primeiro")] [InlineData(2, "segundo")] [InlineData(3, "terceiro")] [InlineData(4, "quarto")] [InlineData(5, "quinto")] [InlineData(6, "sexto")] [InlineData(7, "sétimo")] [InlineData(8, "oitavo")] [InlineData(9, "nono")] [InlineData(10, "décimo")] [InlineData(11, "décimo primeiro")] [InlineData(12, "décimo segundo")] [InlineData(13, "décimo terceiro")] [InlineData(14, "décimo quarto")] [InlineData(15, "décimo quinto")] [InlineData(16, "décimo sexto")] [InlineData(17, "décimo sétimo")] [InlineData(18, "décimo oitavo")] [InlineData(19, "décimo nono")] [InlineData(20, "vigésimo")] [InlineData(21, "vigésimo primeiro")] [InlineData(22, "vigésimo segundo")] [InlineData(30, "trigésimo")] [InlineData(40, "quadragésimo")] [InlineData(50, "quinquagésimo")] [InlineData(60, "sexagésimo")] [InlineData(70, "septuagésimo")] [InlineData(80, "octogésimo")] [InlineData(90, "nonagésimo")] [InlineData(95, "nonagésimo quinto")] [InlineData(96, "nonagésimo sexto")] [InlineData(100, "centésimo")] [InlineData(120, "centésimo vigésimo")] [InlineData(121, "centésimo vigésimo primeiro")] [InlineData(200, "ducentésimo")] [InlineData(300, "trecentésimo")] [InlineData(400, "quadringentésimo")] [InlineData(500, "quingentésimo")] [InlineData(600, "sexcentésimo")] [InlineData(700, "septingentésimo")] [InlineData(800, "octingentésimo")] [InlineData(900, "noningentésimo")] [InlineData(1000, "milésimo")] [InlineData(1001, "milésimo primeiro")] [InlineData(1021, "milésimo vigésimo primeiro")] [InlineData(2021, "segundo milésimo vigésimo primeiro")] [InlineData(10000, "décimo milésimo")] [InlineData(10121, "décimo milésimo centésimo vigésimo primeiro")] [InlineData(100000, "centésimo milésimo")] [InlineData(1000000, "milionésimo")] [InlineData(1000000000, "milésimo milionésimo")] public void ToOrdinalWords(int number, string words) => Assert.Equal(words, number.ToOrdinalWords()); [Theory] [InlineData(0, "zero")] [InlineData(1, "primeira")] [InlineData(2, "segunda")] [InlineData(3, "terceira")] [InlineData(4, "quarta")] [InlineData(5, "quinta")] [InlineData(6, "sexta")] [InlineData(7, "sétima")] [InlineData(8, "oitava")] [InlineData(9, "nona")] [InlineData(10, "décima")] [InlineData(11, "décima primeira")] [InlineData(12, "décima segunda")] [InlineData(13, "décima terceira")] [InlineData(14, "décima quarta")] [InlineData(15, "décima quinta")] [InlineData(16, "décima sexta")] [InlineData(17, "décima sétima")] [InlineData(18, "décima oitava")] [InlineData(19, "décima nona")] [InlineData(20, "vigésima")] [InlineData(21, "vigésima primeira")] [InlineData(22, "vigésima segunda")] [InlineData(30, "trigésima")] [InlineData(40, "quadragésima")] [InlineData(50, "quinquagésima")] [InlineData(60, "sexagésima")] [InlineData(70, "septuagésima")] [InlineData(80, "octogésima")] [InlineData(90, "nonagésima")] [InlineData(95, "nonagésima quinta")] [InlineData(96, "nonagésima sexta")] [InlineData(100, "centésima")] [InlineData(120, "centésima vigésima")] [InlineData(121, "centésima vigésima primeira")] [InlineData(200, "ducentésima")] [InlineData(300, "trecentésima")] [InlineData(400, "quadringentésima")] [InlineData(500, "quingentésima")] [InlineData(600, "sexcentésima")] [InlineData(700, "septingentésima")] [InlineData(800, "octingentésima")] [InlineData(900, "noningentésima")] [InlineData(1000, "milésima")] [InlineData(1001, "milésima primeira")] [InlineData(1021, "milésima vigésima primeira")] [InlineData(2021, "segunda milésima vigésima primeira")] [InlineData(10000, "décima milésima")] [InlineData(10121, "décima milésima centésima vigésima primeira")] [InlineData(100000, "centésima milésima")] [InlineData(1000000, "milionésima")] [InlineData(1000000000, "milésima milionésima")] public void ToFeminineOrdinalWords(int number, string words) => Assert.Equal(words, number.ToOrdinalWords(GrammaticalGender.Feminine)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/pt/OrdinalizeTests.cs ================================================ namespace pt; [UseCulture("pt")] public class OrdinalizeTests { [Theory] [InlineData("0", "0")] [InlineData("1", "1º")] [InlineData("2", "2º")] [InlineData("3", "3º")] [InlineData("4", "4º")] [InlineData("5", "5º")] [InlineData("6", "6º")] [InlineData("23", "23º")] [InlineData("100", "100º")] [InlineData("101", "101º")] [InlineData("102", "102º")] [InlineData("103", "103º")] [InlineData("1001", "1001º")] public void OrdinalizeString(string number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Masculine), ordinalized); [Theory] [InlineData("0", "0")] [InlineData("1", "1ª")] [InlineData("2", "2ª")] [InlineData("3", "3ª")] [InlineData("4", "4ª")] [InlineData("5", "5ª")] [InlineData("6", "6ª")] [InlineData("23", "23ª")] [InlineData("100", "100ª")] [InlineData("101", "101ª")] [InlineData("102", "102ª")] [InlineData("103", "103ª")] [InlineData("1001", "1001ª")] public void OrdinalizeStringFeminine(string number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Feminine), ordinalized); [Theory] [InlineData(0, "0")] [InlineData(1, "1º")] [InlineData(2, "2º")] [InlineData(3, "3º")] [InlineData(4, "4º")] [InlineData(5, "5º")] [InlineData(6, "6º")] [InlineData(10, "10º")] [InlineData(23, "23º")] [InlineData(100, "100º")] [InlineData(101, "101º")] [InlineData(102, "102º")] [InlineData(103, "103º")] [InlineData(1001, "1001º")] public void OrdinalizeNumber(int number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Masculine), ordinalized); [Theory] [InlineData(0, "0")] [InlineData(1, "1ª")] [InlineData(2, "2ª")] [InlineData(3, "3ª")] [InlineData(4, "4ª")] [InlineData(5, "5ª")] [InlineData(6, "6ª")] [InlineData(10, "10ª")] [InlineData(23, "23ª")] [InlineData(100, "100ª")] [InlineData(101, "101ª")] [InlineData(102, "102ª")] [InlineData(103, "103ª")] [InlineData(1001, "1001ª")] public void OrdinalizeNumberFeminine(int number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Feminine), ordinalized); } ================================================ FILE: tests/Humanizer.Tests/Localisation/pt/TimeSpanHumanizeTests.cs ================================================ namespace pt; [UseCulture("pt")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "1 ano")] [InlineData(731, "2 anos")] [InlineData(1096, "3 anos")] [InlineData(4018, "11 anos")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "1 mês")] [InlineData(61, "2 meses")] [InlineData(92, "3 meses")] [InlineData(335, "11 meses")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Fact] public void TwoWeeks() => Assert.Equal("2 semanas", TimeSpan.FromDays(14).Humanize()); [Fact] public void OneWeek() => Assert.Equal("1 semana", TimeSpan.FromDays(7).Humanize()); [Fact] public void SixDays() => Assert.Equal("6 dias", TimeSpan.FromDays(6).Humanize()); [Fact] public void TwoDays() => Assert.Equal("2 dias", TimeSpan.FromDays(2).Humanize()); [Fact] public void OneDay() => Assert.Equal("1 dia", TimeSpan.FromDays(1).Humanize()); [Fact] public void TwoHours() => Assert.Equal("2 horas", TimeSpan.FromHours(2).Humanize()); [Fact] public void OneHour() => Assert.Equal("1 hora", TimeSpan.FromHours(1).Humanize()); [Fact] public void TwoMinutes() => Assert.Equal("2 minutos", TimeSpan.FromMinutes(2).Humanize()); [Fact] public void OneMinute() => Assert.Equal("1 minuto", TimeSpan.FromMinutes(1).Humanize()); [Fact] public void TwoSeconds() => Assert.Equal("2 segundos", TimeSpan.FromSeconds(2).Humanize()); [Fact] public void OneSecond() => Assert.Equal("1 segundo", TimeSpan.FromSeconds(1).Humanize()); [Fact] public void TwoMilliseconds() => Assert.Equal("2 milisegundos", TimeSpan.FromMilliseconds(2).Humanize()); [Fact] public void OneMillisecond() => Assert.Equal("1 milisegundo", TimeSpan.FromMilliseconds(1).Humanize()); [Fact] public void NoTime() => Assert.Equal("0 milisegundos", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => // This one doesn't make a lot of sense but ... w/e Assert.Equal("sem horário", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/pt/TimeToClockNotationTests.cs ================================================ #if NET6_0_OR_GREATER namespace pt; [UseCulture("pt")] public class TimeToClockNotationTests { [Theory] [InlineData(00, 00, "meia-noite")] [InlineData(04, 00, "quatro horas")] [InlineData(05, 01, "cinco e um")] [InlineData(06, 05, "seis e cinco")] [InlineData(07, 10, "sete e dez")] [InlineData(08, 15, "oito e um quarto")] [InlineData(09, 20, "nove e vinte")] [InlineData(10, 25, "dez e vinte e cinco")] [InlineData(11, 30, "onze e meia")] [InlineData(12, 00, "meio-dia")] [InlineData(15, 35, "três e trinta e cinco")] [InlineData(16, 40, "cinco menos vinte")] [InlineData(17, 45, "seis menos um quarto")] [InlineData(18, 50, "sete menos dez")] [InlineData(19, 55, "oito menos cinco")] [InlineData(20, 59, "oito e cinquenta e nove")] public void ConvertToClockNotationTimeOnlyStringPtBr(int hours, int minutes, string expectedResult) { var actualResult = new TimeOnly(hours, minutes).ToClockNotation(); Assert.Equal(expectedResult, actualResult); } [Theory] [InlineData(00, 00, "meia-noite")] [InlineData(04, 00, "quatro horas")] [InlineData(05, 01, "cinco horas")] [InlineData(06, 05, "seis e cinco")] [InlineData(07, 10, "sete e dez")] [InlineData(08, 15, "oito e um quarto")] [InlineData(09, 20, "nove e vinte")] [InlineData(10, 25, "dez e vinte e cinco")] [InlineData(11, 30, "onze e meia")] [InlineData(12, 00, "meio-dia")] [InlineData(13, 23, "uma e vinte e cinco")] [InlineData(14, 32, "duas e meia")] [InlineData(15, 35, "três e trinta e cinco")] [InlineData(16, 40, "cinco menos vinte")] [InlineData(17, 45, "seis menos um quarto")] [InlineData(18, 50, "sete menos dez")] [InlineData(19, 55, "oito menos cinco")] [InlineData(20, 59, "nove horas")] public void ConvertToRoundedClockNotationTimeOnlyStringPtBr(int hours, int minutes, string expectedResult) { var actualResult = new TimeOnly(hours, minutes).ToClockNotation(ClockNotationRounding.NearestFiveMinutes); Assert.Equal(expectedResult, actualResult); } } #endif ================================================ FILE: tests/Humanizer.Tests/Localisation/pt/TimeUnitToSymbolTests.cs ================================================ namespace pt; [UseCulture("pt")] public class TimeUnitToSymbolTests { [Theory] [Trait("Translation", "Native speaker")] [InlineData(TimeUnit.Millisecond, "ms")] [InlineData(TimeUnit.Second, "s")] [InlineData(TimeUnit.Minute, "min")] [InlineData(TimeUnit.Hour, "h")] [InlineData(TimeUnit.Day, "d")] [InlineData(TimeUnit.Week, "semana")] [InlineData(TimeUnit.Month, "m")] [InlineData(TimeUnit.Year, "a")] public void ToSymbol(TimeUnit unit, string expected) => Assert.Equal(expected, unit.ToSymbol()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/pt-BR/Bytes/ByteSizeExtensionsTests.cs ================================================ namespace pt_BR.Bytes; [UseCulture("pt-BR")] public class ByteSizeExtensionsTests { [Theory] [InlineData(2, null, "2 TB")] [InlineData(2, "GB", "2048 GB")] [InlineData(2.123, "#.#", "2,1 TB")] public void HumanizesTerabytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Terabytes().Humanize(format)); [Theory] [InlineData(0, null, "0 bit")] [InlineData(0, "GB", "0 GB")] [InlineData(2, null, "2 GB")] [InlineData(2, "MB", "2048 MB")] [InlineData(2.123, "#.##", "2,12 GB")] public void HumanizesGigabytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Gigabytes().Humanize(format)); [Theory] [InlineData(0, null, "0 bit")] [InlineData(0, "MB", "0 MB")] [InlineData(2, null, "2 MB")] [InlineData(2, "KB", "2048 KB")] [InlineData(2.123, "#", "2 MB")] public void HumanizesMegabytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Megabytes().Humanize(format)); [Theory] [InlineData(0, null, "0 bit")] [InlineData(0, "KB", "0 KB")] [InlineData(2, null, "2 KB")] [InlineData(2, "B", "2048 B")] [InlineData(2.123, "#.####", "2,123 KB")] public void HumanizesKilobytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Kilobytes().Humanize(format)); [Theory] [InlineData(0, null, "0 bit")] [InlineData(0, "#.##", "0 bit")] [InlineData(0, "#.## B", "0 B")] [InlineData(0, "B", "0 B")] [InlineData(2, null, "2 B")] [InlineData(2000, "KB", "1,95 KB")] [InlineData(2123, "#.##", "2,07 KB")] [InlineData(10000000, "KB", "9765,63 KB")] [InlineData(10000000, "#,##0 KB", "9.766 KB")] [InlineData(10000000, "#,##0.# KB", "9.765,6 KB")] public void HumanizesBytes(double input, string? format, string expectedValue) { expectedValue = expectedValue.Replace(".", NumberFormatInfo.CurrentInfo.NumberGroupSeparator); Assert.Equal( expectedValue, input .Bytes() .Humanize(format)); } [Theory] [InlineData(0, null, "0 bit")] [InlineData(0, "b", "0 bit")] [InlineData(2, null, "2 bit")] [InlineData(12, "B", "1,5 B")] [InlineData(10000, "#.# KB", "1,2 KB")] public void HumanizesBits(long input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Bits().Humanize(format)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/pt-BR/DateHumanizeTests.cs ================================================ namespace ptBR; [UseCulture("pt-BR")] public class DateHumanizeTests { [Theory] [InlineData(-2, "2 segundos atrás")] [InlineData(-1, "um segundo atrás")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "em um segundo")] [InlineData(2, "em 2 segundos")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(-2, "2 minutos atrás")] [InlineData(-1, "um minuto atrás")] [InlineData(60, "uma hora atrás")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "em um minuto")] [InlineData(2, "em 2 minutos")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(-2, "2 horas atrás")] [InlineData(-1, "uma hora atrás")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "em uma hora")] [InlineData(2, "em 2 horas")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(-2, "2 dias atrás")] [InlineData(-1, "ontem")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "amanhã")] [InlineData(2, "em 2 dias")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(-2, "2 meses atrás")] [InlineData(-1, "um mês atrás")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "em um mês")] [InlineData(2, "em 2 meses")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(-2, "2 anos atrás")] [InlineData(-1, "um ano atrás")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "em um ano")] [InlineData(2, "em 2 anos")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Fact] public void Now() => DateHumanize.Verify("agora", 0, TimeUnit.Day, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/pt-BR/NumberToWordsTests.cs ================================================ namespace ptBR; [UseCulture("pt-BR")] public class NumberToWordsTests { [Theory] [InlineData(1, "um")] [InlineData(2, "dois")] [InlineData(3, "três")] [InlineData(4, "quatro")] [InlineData(5, "cinco")] [InlineData(6, "seis")] [InlineData(7, "sete")] [InlineData(8, "oito")] [InlineData(9, "nove")] [InlineData(10, "dez")] [InlineData(11, "onze")] [InlineData(12, "doze")] [InlineData(13, "treze")] [InlineData(14, "quatorze")] [InlineData(15, "quinze")] [InlineData(16, "dezesseis")] [InlineData(17, "dezessete")] [InlineData(18, "dezoito")] [InlineData(19, "dezenove")] [InlineData(20, "vinte")] [InlineData(30, "trinta")] [InlineData(40, "quarenta")] [InlineData(50, "cinquenta")] [InlineData(51, "cinquenta e um")] [InlineData(60, "sessenta")] [InlineData(66, "sessenta e seis")] [InlineData(70, "setenta")] [InlineData(80, "oitenta")] [InlineData(90, "noventa")] [InlineData(100, "cem")] [InlineData(200, "duzentos")] [InlineData(300, "trezentos")] [InlineData(400, "quatrocentos")] [InlineData(500, "quinhentos")] [InlineData(600, "seiscentos")] [InlineData(700, "setecentos")] [InlineData(800, "oitocentos")] [InlineData(900, "novecentos")] [InlineData(1000, "mil")] [InlineData(2000, "dois mil")] [InlineData(3000, "três mil")] [InlineData(4000, "quatro mil")] [InlineData(5000, "cinco mil")] [InlineData(6000, "seis mil")] [InlineData(7000, "sete mil")] [InlineData(8000, "oito mil")] [InlineData(9000, "nove mil")] [InlineData(10000, "dez mil")] [InlineData(100000, "cem mil")] [InlineData(1000000, "um milhão")] [InlineData(1000000000, "um bilhão")] [InlineData(37, "trinta e sete")] [InlineData(637, "seiscentos e trinta e sete")] [InlineData(1637, "mil seiscentos e trinta e sete")] [InlineData(61637, "sessenta e um mil seiscentos e trinta e sete")] [InlineData(961637, "novecentos e sessenta e um mil seiscentos e trinta e sete")] [InlineData(5961637, "cinco milhões novecentos e sessenta e um mil seiscentos e trinta e sete")] [InlineData(25961637, "vinte e cinco milhões novecentos e sessenta e um mil seiscentos e trinta e sete")] [InlineData(425961637, "quatrocentos e vinte e cinco milhões novecentos e sessenta e um mil seiscentos e trinta e sete")] [InlineData(10000000, "dez milhões")] [InlineData(100000000, "cem milhões")] [InlineData(1101111101, "um bilhão cento e um milhões cento e onze mil cento e um")] [InlineData(111, "cento e onze")] [InlineData(1111, "mil cento e onze")] [InlineData(1111101, "um milhão cento e onze mil cento e um")] [InlineData(111111, "cento e onze mil cento e onze")] [InlineData(1111111, "um milhão cento e onze mil cento e onze")] [InlineData(11111111, "onze milhões cento e onze mil cento e onze")] [InlineData(111111111, "cento e onze milhões cento e onze mil cento e onze")] [InlineData(1111111111, "um bilhão cento e onze milhões cento e onze mil cento e onze")] [InlineData(122, "cento e vinte e dois")] [InlineData(123, "cento e vinte e três")] [InlineData(1234, "mil duzentos e trinta e quatro")] [InlineData(12345, "doze mil trezentos e quarenta e cinco")] [InlineData(123456, "cento e vinte e três mil quatrocentos e cinquenta e seis")] [InlineData(1234567, "um milhão duzentos e trinta e quatro mil quinhentos e sessenta e sete")] [InlineData(12345678, "doze milhões trezentos e quarenta e cinco mil seiscentos e setenta e oito")] [InlineData(123456789, "cento e vinte e três milhões quatrocentos e cinquenta e seis mil setecentos e oitenta e nove")] [InlineData(1234567890, "um bilhão duzentos e trinta e quatro milhões quinhentos e sessenta e sete mil oitocentos e noventa")] [InlineData(1999, "mil novecentos e noventa e nove")] [InlineData(2000000, "dois milhões")] [InlineData(2000000000, "dois bilhões")] [InlineData(2001000000, "dois bilhões um milhão")] [InlineData(2014, "dois mil e quatorze")] [InlineData(2048, "dois mil e quarenta e oito")] [InlineData(21, "vinte e um")] [InlineData(211, "duzentos e onze")] [InlineData(2111101, "dois milhões cento e onze mil cento e um")] [InlineData(221, "duzentos e vinte e um")] [InlineData(3501, "três mil quinhentos e um")] [InlineData(8100, "oito mil e cem")] [InlineData(999999999999, "novecentos e noventa e nove bilhões novecentos e noventa e nove milhões novecentos e noventa e nove mil novecentos e noventa e nove")] [InlineData(-999999999999, "menos novecentos e noventa e nove bilhões novecentos e noventa e nove milhões novecentos e noventa e nove mil novecentos e noventa e nove")] public void ToWords(long number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(1, "uma")] [InlineData(2, "duas")] [InlineData(3, "três")] [InlineData(11, "onze")] [InlineData(21, "vinte e uma")] [InlineData(122, "cento e vinte e duas")] [InlineData(232, "duzentas e trinta e duas")] [InlineData(343, "trezentas e quarenta e três")] [InlineData(3501, "três mil quinhentas e uma")] [InlineData(100, "cem")] [InlineData(1000, "mil")] [InlineData(111, "cento e onze")] [InlineData(1111, "mil cento e onze")] [InlineData(111111, "cento e onze mil cento e onze")] [InlineData(1111101, "um milhão cento e onze mil cento e uma")] [InlineData(1111111, "um milhão cento e onze mil cento e onze")] [InlineData(2111102, "dois milhões cento e onze mil cento e duas")] [InlineData(3111101, "três milhões cento e onze mil cento e uma")] [InlineData(1101111101, "um bilhão cento e um milhões cento e onze mil cento e uma")] [InlineData(2101111101, "dois bilhões cento e um milhões cento e onze mil cento e uma")] [InlineData(1234, "mil duzentas e trinta e quatro")] [InlineData(8100, "oito mil e cem")] [InlineData(12345, "doze mil trezentas e quarenta e cinco")] public void ToFeminineWords(int number, string expected) => Assert.Equal(expected, number.ToWords(GrammaticalGender.Feminine)); [Theory] [InlineData(0, "zero")] [InlineData(1, "primeiro")] [InlineData(2, "segundo")] [InlineData(3, "terceiro")] [InlineData(4, "quarto")] [InlineData(5, "quinto")] [InlineData(6, "sexto")] [InlineData(7, "sétimo")] [InlineData(8, "oitavo")] [InlineData(9, "nono")] [InlineData(10, "décimo")] [InlineData(11, "décimo primeiro")] [InlineData(12, "décimo segundo")] [InlineData(13, "décimo terceiro")] [InlineData(14, "décimo quarto")] [InlineData(15, "décimo quinto")] [InlineData(16, "décimo sexto")] [InlineData(17, "décimo sétimo")] [InlineData(18, "décimo oitavo")] [InlineData(19, "décimo nono")] [InlineData(20, "vigésimo")] [InlineData(21, "vigésimo primeiro")] [InlineData(22, "vigésimo segundo")] [InlineData(30, "trigésimo")] [InlineData(40, "quadragésimo")] [InlineData(50, "quinquagésimo")] [InlineData(60, "sexagésimo")] [InlineData(70, "septuagésimo")] [InlineData(80, "octogésimo")] [InlineData(90, "nonagésimo")] [InlineData(95, "nonagésimo quinto")] [InlineData(96, "nonagésimo sexto")] [InlineData(100, "centésimo")] [InlineData(120, "centésimo vigésimo")] [InlineData(121, "centésimo vigésimo primeiro")] [InlineData(200, "ducentésimo")] [InlineData(300, "trecentésimo")] [InlineData(400, "quadringentésimo")] [InlineData(500, "quingentésimo")] [InlineData(600, "sexcentésimo")] [InlineData(700, "septingentésimo")] [InlineData(800, "octingentésimo")] [InlineData(900, "noningentésimo")] [InlineData(1000, "milésimo")] [InlineData(1001, "milésimo primeiro")] [InlineData(1021, "milésimo vigésimo primeiro")] [InlineData(2021, "segundo milésimo vigésimo primeiro")] [InlineData(10000, "décimo milésimo")] [InlineData(10121, "décimo milésimo centésimo vigésimo primeiro")] [InlineData(100000, "centésimo milésimo")] [InlineData(1000000, "milionésimo")] [InlineData(1000000000, "bilionésimo")] public void ToOrdinalWords(int number, string words) => Assert.Equal(words, number.ToOrdinalWords()); [Theory] [InlineData(0, "zero")] [InlineData(1, "primeira")] [InlineData(2, "segunda")] [InlineData(3, "terceira")] [InlineData(4, "quarta")] [InlineData(5, "quinta")] [InlineData(6, "sexta")] [InlineData(7, "sétima")] [InlineData(8, "oitava")] [InlineData(9, "nona")] [InlineData(10, "décima")] [InlineData(11, "décima primeira")] [InlineData(12, "décima segunda")] [InlineData(13, "décima terceira")] [InlineData(14, "décima quarta")] [InlineData(15, "décima quinta")] [InlineData(16, "décima sexta")] [InlineData(17, "décima sétima")] [InlineData(18, "décima oitava")] [InlineData(19, "décima nona")] [InlineData(20, "vigésima")] [InlineData(21, "vigésima primeira")] [InlineData(22, "vigésima segunda")] [InlineData(30, "trigésima")] [InlineData(40, "quadragésima")] [InlineData(50, "quinquagésima")] [InlineData(60, "sexagésima")] [InlineData(70, "septuagésima")] [InlineData(80, "octogésima")] [InlineData(90, "nonagésima")] [InlineData(95, "nonagésima quinta")] [InlineData(96, "nonagésima sexta")] [InlineData(100, "centésima")] [InlineData(120, "centésima vigésima")] [InlineData(121, "centésima vigésima primeira")] [InlineData(200, "ducentésima")] [InlineData(300, "trecentésima")] [InlineData(400, "quadringentésima")] [InlineData(500, "quingentésima")] [InlineData(600, "sexcentésima")] [InlineData(700, "septingentésima")] [InlineData(800, "octingentésima")] [InlineData(900, "noningentésima")] [InlineData(1000, "milésima")] [InlineData(1001, "milésima primeira")] [InlineData(1021, "milésima vigésima primeira")] [InlineData(2021, "segunda milésima vigésima primeira")] [InlineData(10000, "décima milésima")] [InlineData(10121, "décima milésima centésima vigésima primeira")] [InlineData(100000, "centésima milésima")] [InlineData(1000000, "milionésima")] [InlineData(1000000000, "bilionésima")] public void ToFeminineOrdinalWords(int number, string words) => Assert.Equal(words, number.ToOrdinalWords(GrammaticalGender.Feminine)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/pt-BR/OrdinalizeTests.cs ================================================ namespace ptBR; [UseCulture("pt-BR")] public class OrdinalizeTests { [Theory] [InlineData("0", "0")] [InlineData("1", "1º")] [InlineData("2", "2º")] [InlineData("3", "3º")] [InlineData("4", "4º")] [InlineData("5", "5º")] [InlineData("6", "6º")] [InlineData("23", "23º")] [InlineData("100", "100º")] [InlineData("101", "101º")] [InlineData("102", "102º")] [InlineData("103", "103º")] [InlineData("1001", "1001º")] public void OrdinalizeString(string number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Masculine), ordinalized); [Theory] [InlineData("0", "0")] [InlineData("1", "1ª")] [InlineData("2", "2ª")] [InlineData("3", "3ª")] [InlineData("4", "4ª")] [InlineData("5", "5ª")] [InlineData("6", "6ª")] [InlineData("23", "23ª")] [InlineData("100", "100ª")] [InlineData("101", "101ª")] [InlineData("102", "102ª")] [InlineData("103", "103ª")] [InlineData("1001", "1001ª")] public void OrdinalizeStringFeminine(string number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Feminine), ordinalized); [Theory] [InlineData(0, "0")] [InlineData(1, "1º")] [InlineData(2, "2º")] [InlineData(3, "3º")] [InlineData(4, "4º")] [InlineData(5, "5º")] [InlineData(6, "6º")] [InlineData(10, "10º")] [InlineData(23, "23º")] [InlineData(100, "100º")] [InlineData(101, "101º")] [InlineData(102, "102º")] [InlineData(103, "103º")] [InlineData(1001, "1001º")] public void OrdinalizeNumber(int number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Masculine), ordinalized); [Theory] [InlineData(0, "0")] [InlineData(1, "1ª")] [InlineData(2, "2ª")] [InlineData(3, "3ª")] [InlineData(4, "4ª")] [InlineData(5, "5ª")] [InlineData(6, "6ª")] [InlineData(10, "10ª")] [InlineData(23, "23ª")] [InlineData(100, "100ª")] [InlineData(101, "101ª")] [InlineData(102, "102ª")] [InlineData(103, "103ª")] [InlineData(1001, "1001ª")] public void OrdinalizeNumberFeminine(int number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Feminine), ordinalized); } ================================================ FILE: tests/Humanizer.Tests/Localisation/pt-BR/TimeSpanHumanizeTests.cs ================================================ namespace ptBR; [UseCulture("pt-BR")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "1 ano")] [InlineData(731, "2 anos")] [InlineData(1096, "3 anos")] [InlineData(4018, "11 anos")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "1 mês")] [InlineData(61, "2 meses")] [InlineData(92, "3 meses")] [InlineData(335, "11 meses")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Fact] public void TwoWeeks() => Assert.Equal("2 semanas", TimeSpan.FromDays(14).Humanize()); [Fact] public void OneWeek() => Assert.Equal("1 semana", TimeSpan.FromDays(7).Humanize()); [Fact] public void SixDays() => Assert.Equal("6 dias", TimeSpan.FromDays(6).Humanize()); [Fact] public void TwoDays() => Assert.Equal("2 dias", TimeSpan.FromDays(2).Humanize()); [Fact] public void OneDay() => Assert.Equal("1 dia", TimeSpan.FromDays(1).Humanize()); [Fact] public void TwoHours() => Assert.Equal("2 horas", TimeSpan.FromHours(2).Humanize()); [Fact] public void OneHour() => Assert.Equal("1 hora", TimeSpan.FromHours(1).Humanize()); [Fact] public void TwoMinutes() => Assert.Equal("2 minutos", TimeSpan.FromMinutes(2).Humanize()); [Fact] public void OneMinute() => Assert.Equal("1 minuto", TimeSpan.FromMinutes(1).Humanize()); [Fact] public void TwoSeconds() => Assert.Equal("2 segundos", TimeSpan.FromSeconds(2).Humanize()); [Fact] public void OneSecond() => Assert.Equal("1 segundo", TimeSpan.FromSeconds(1).Humanize()); [Fact] public void TwoMilliseconds() => Assert.Equal("2 milisegundos", TimeSpan.FromMilliseconds(2).Humanize()); [Fact] public void OneMillisecond() => Assert.Equal("1 milisegundo", TimeSpan.FromMilliseconds(1).Humanize()); [Fact] public void NoTime() => Assert.Equal("0 milisegundos", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => // This one doesn't make a lot of sense but ... w/e Assert.Equal("sem horário", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/pt-BR/TimeToClockNotationTests.cs ================================================ #if NET6_0_OR_GREATER namespace ptBR; [UseCulture("pt-BR")] public class TimeToClockNotationTests { [Theory] [InlineData(00, 00, "meia-noite")] [InlineData(04, 00, "quatro em ponto")] [InlineData(05, 01, "cinco e um")] [InlineData(06, 05, "seis e cinco")] [InlineData(07, 10, "sete e dez")] [InlineData(08, 15, "oito e quinze")] [InlineData(09, 20, "nove e vinte")] [InlineData(10, 25, "dez e vinte e cinco")] [InlineData(11, 30, "onze e meia")] [InlineData(12, 00, "meio-dia")] [InlineData(15, 35, "três e trinta e cinco")] [InlineData(16, 40, "vinte para as cinco")] [InlineData(17, 45, "quinze para as seis")] [InlineData(18, 50, "dez para as sete")] [InlineData(19, 55, "cinco para as oito")] [InlineData(20, 59, "oito e cinquenta e nove")] public void ConvertToClockNotationTimeOnlyStringPtBr(int hours, int minutes, string expectedResult) { var actualResult = new TimeOnly(hours, minutes).ToClockNotation(); Assert.Equal(expectedResult, actualResult); } [Theory] [InlineData(00, 00, "meia-noite")] [InlineData(04, 00, "quatro em ponto")] [InlineData(05, 01, "cinco em ponto")] [InlineData(06, 05, "seis e cinco")] [InlineData(07, 10, "sete e dez")] [InlineData(08, 15, "oito e quinze")] [InlineData(09, 20, "nove e vinte")] [InlineData(10, 25, "dez e vinte e cinco")] [InlineData(11, 30, "onze e meia")] [InlineData(12, 00, "meio-dia")] [InlineData(13, 23, "uma e vinte e cinco")] [InlineData(14, 32, "duas e meia")] [InlineData(15, 35, "três e trinta e cinco")] [InlineData(16, 40, "vinte para as cinco")] [InlineData(17, 45, "quinze para as seis")] [InlineData(18, 50, "dez para as sete")] [InlineData(19, 55, "cinco para as oito")] [InlineData(20, 59, "nove em ponto")] public void ConvertToRoundedClockNotationTimeOnlyStringPtBr(int hours, int minutes, string expectedResult) { var actualResult = new TimeOnly(hours, minutes).ToClockNotation(ClockNotationRounding.NearestFiveMinutes); Assert.Equal(expectedResult, actualResult); } } #endif ================================================ FILE: tests/Humanizer.Tests/Localisation/pt-BR/TimeUnitToSymbolTests.cs ================================================ namespace pt_BR; [UseCulture("pt-BR")] public class TimeUnitToSymbolTests { [Theory] [Trait("Translation", "Native speaker")] [InlineData(TimeUnit.Millisecond, "ms")] [InlineData(TimeUnit.Second, "s")] [InlineData(TimeUnit.Minute, "min")] [InlineData(TimeUnit.Hour, "h")] [InlineData(TimeUnit.Day, "d")] [InlineData(TimeUnit.Week, "semana")] [InlineData(TimeUnit.Month, "m")] [InlineData(TimeUnit.Year, "a")] public void ToSymbol(TimeUnit unit, string expected) => Assert.Equal(expected, unit.ToSymbol()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ro-Ro/CollectionFormatterTests.cs ================================================ namespace roRO; [UseCulture("ro-RO")] public class CollectionFormatterTests { [Fact] public void OneItem() { var collection = new List([1]); var humanized = "1"; Assert.Equal(humanized, collection.Humanize()); } [Fact] public void TwoItems() { var collection = new List([1, 2]); var humanized = "1 și 2"; Assert.Equal(humanized, collection.Humanize()); } [Fact] public void MoreThanTwoItems() { var collection = new List([1, 2, 3]); var humanized = "1, 2 și 3"; Assert.Equal(humanized, collection.Humanize()); } } ================================================ FILE: tests/Humanizer.Tests/Localisation/ro-Ro/DateHumanizeTests.cs ================================================ namespace roRO; /// /// Test that for values bigger than 19 "de" is added between the numeral /// and the time unit: http://ebooks.unibuc.ro/filologie/NForascu-DGLR/numerale.htm. /// There is no test for months since there are only 12 of them in a year. /// [UseCulture("ro-RO")] public class DateHumanizeTests { [Theory] [InlineData(3, "acum 3 ore")] [InlineData(20, "acum 20 de ore")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(19, "acum 19 minute")] [InlineData(60, "acum o oră")] [InlineData(44, "acum 44 de minute")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(2, "acum 2 secunde")] [InlineData(59, "acum 59 de secunde")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(10, "acum 10 zile")] [InlineData(23, "acum 23 de zile")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(119, "acum 119 ani")] [InlineData(100, "acum 100 de ani")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "acum")] [InlineData(22, "acum")] public void MillisecondsAgo(int milliseconds, string expected) => DateHumanize.Verify(expected, milliseconds, TimeUnit.Millisecond, Tense.Past); [Theory] [InlineData(19, "peste 19 secunde")] [InlineData(21, "peste 21 de secunde")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(19, "peste 19 minute")] [InlineData(22, "peste 22 de minute")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(3, "peste 3 ore")] [InlineData(23, "peste 23 de ore")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(5, "peste 5 zile")] [InlineData(23, "peste 23 de zile")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(5, "peste 5 ani")] [InlineData(21, "peste 21 de ani")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ro-Ro/NumberToWordsTests.cs ================================================ namespace roRO; [UseCulture("ro-RO")] public class NumberToWordsTests { [Theory] [InlineData(-1, "minus unu")] [InlineData(0, "zero")] [InlineData(1, "unu")] [InlineData(2, "doi")] [InlineData(3, "trei")] [InlineData(4, "patru")] [InlineData(5, "cinci")] [InlineData(6, "șase")] [InlineData(7, "șapte")] [InlineData(8, "opt")] [InlineData(9, "nouă")] [InlineData(10, "zece")] [InlineData(11, "unsprezece")] [InlineData(12, "doisprezece")] [InlineData(13, "treisprezece")] [InlineData(14, "paisprezece")] [InlineData(15, "cincisprezece")] [InlineData(16, "șaisprezece")] [InlineData(17, "șaptesprezece")] [InlineData(18, "optsprezece")] [InlineData(19, "nouăsprezece")] [InlineData(20, "douăzeci")] [InlineData(21, "douăzeci și unu")] [InlineData(22, "douăzeci și doi")] [InlineData(30, "treizeci")] [InlineData(40, "patruzeci")] [InlineData(50, "cincizeci")] [InlineData(60, "șaizeci")] [InlineData(70, "șaptezeci")] [InlineData(80, "optzeci")] [InlineData(90, "nouăzeci")] [InlineData(100, "o sută")] [InlineData(101, "o sută unu")] [InlineData(102, "o sută doi")] [InlineData(111, "o sută unsprezece")] [InlineData(120, "o sută douăzeci")] [InlineData(121, "o sută douăzeci și unu")] [InlineData(122, "o sută douăzeci și doi")] [InlineData(200, "două sute")] [InlineData(1000, "o mie")] [InlineData(1001, "o mie unu")] [InlineData(1002, "o mie doi")] [InlineData(1100, "o mie o sută")] [InlineData(1200, "o mie două sute")] [InlineData(2000, "două mii")] [InlineData(10000, "zece mii")] [InlineData(12000, "douăsprezece mii")] [InlineData(20000, "douăzeci de mii")] [InlineData(21000, "douăzeci și una de mii")] [InlineData(22371, "douăzeci și două de mii trei sute șaptezeci și unu")] [InlineData(100000, "o sută de mii")] [InlineData(1000000, "un milion")] [InlineData(2000000, "două milioane")] [InlineData(1000000000, "un miliard")] [InlineData(2000000000, "două miliarde")] public void ToWords(int number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(-1, "minus unu")] [InlineData(0, "zero")] [InlineData(1, "unu")] [InlineData(2, "doi")] [InlineData(3, "trei")] [InlineData(4, "patru")] [InlineData(5, "cinci")] [InlineData(6, "șase")] [InlineData(7, "șapte")] [InlineData(8, "opt")] [InlineData(9, "nouă")] [InlineData(10, "zece")] [InlineData(11, "unsprezece")] [InlineData(12, "doisprezece")] [InlineData(13, "treisprezece")] [InlineData(14, "paisprezece")] [InlineData(15, "cincisprezece")] [InlineData(16, "șaisprezece")] [InlineData(17, "șaptesprezece")] [InlineData(18, "optsprezece")] [InlineData(19, "nouăsprezece")] [InlineData(20, "douăzeci")] [InlineData(21, "douăzeci și unu")] [InlineData(22, "douăzeci și doi")] [InlineData(30, "treizeci")] [InlineData(40, "patruzeci")] [InlineData(50, "cincizeci")] [InlineData(60, "șaizeci")] [InlineData(70, "șaptezeci")] [InlineData(80, "optzeci")] [InlineData(90, "nouăzeci")] [InlineData(100, "o sută")] [InlineData(101, "o sută unu")] [InlineData(102, "o sută doi")] [InlineData(111, "o sută unsprezece")] [InlineData(120, "o sută douăzeci")] [InlineData(121, "o sută douăzeci și unu")] [InlineData(122, "o sută douăzeci și doi")] [InlineData(200, "două sute")] [InlineData(1000, "o mie")] [InlineData(1001, "o mie unu")] [InlineData(1002, "o mie doi")] [InlineData(1100, "o mie o sută")] [InlineData(1200, "o mie două sute")] [InlineData(2000, "două mii")] [InlineData(10000, "zece mii")] [InlineData(12000, "douăsprezece mii")] [InlineData(20000, "douăzeci de mii")] [InlineData(21000, "douăzeci și una de mii")] [InlineData(22371, "douăzeci și două de mii trei sute șaptezeci și unu")] [InlineData(100000, "o sută de mii")] [InlineData(1000000, "un milion")] [InlineData(2000000, "două milioane")] [InlineData(1000000000, "un miliard")] [InlineData(2000000000, "două miliarde")] public void ToMasculineWords(int number, string expected) => Assert.Equal(expected, number.ToWords(GrammaticalGender.Masculine)); [Theory] [InlineData(-1, "minus una")] [InlineData(0, "zero")] [InlineData(1, "una")] [InlineData(2, "două")] [InlineData(3, "trei")] [InlineData(4, "patru")] [InlineData(5, "cinci")] [InlineData(6, "șase")] [InlineData(7, "șapte")] [InlineData(8, "opt")] [InlineData(9, "nouă")] [InlineData(10, "zece")] [InlineData(11, "unsprezece")] [InlineData(12, "douăsprezece")] // DOOM 2 (dicționarul ortografic, ortoepic și morfologic al limbii române) [InlineData(13, "treisprezece")] [InlineData(14, "paisprezece")] [InlineData(15, "cincisprezece")] [InlineData(16, "șaisprezece")] [InlineData(17, "șaptesprezece")] [InlineData(18, "optsprezece")] [InlineData(19, "nouăsprezece")] [InlineData(20, "douăzeci")] [InlineData(21, "douăzeci și una")] [InlineData(22, "douăzeci și două")] [InlineData(30, "treizeci")] [InlineData(40, "patruzeci")] [InlineData(50, "cincizeci")] [InlineData(60, "șaizeci")] [InlineData(70, "șaptezeci")] [InlineData(80, "optzeci")] [InlineData(90, "nouăzeci")] [InlineData(100, "o sută")] [InlineData(101, "o sută una")] [InlineData(102, "o sută două")] [InlineData(111, "o sută unsprezece")] [InlineData(120, "o sută douăzeci")] [InlineData(121, "o sută douăzeci și una")] [InlineData(122, "o sută douăzeci și două")] [InlineData(200, "două sute")] [InlineData(1000, "o mie")] [InlineData(1001, "o mie una")] [InlineData(1002, "o mie două")] [InlineData(1100, "o mie o sută")] [InlineData(1200, "o mie două sute")] [InlineData(2000, "două mii")] [InlineData(10000, "zece mii")] [InlineData(12000, "douăsprezece mii")] [InlineData(20000, "douăzeci de mii")] [InlineData(21000, "douăzeci și una de mii")] [InlineData(22371, "douăzeci și două de mii trei sute șaptezeci și una")] [InlineData(100000, "o sută de mii")] [InlineData(1000000, "un milion")] [InlineData(2000000, "două milioane")] [InlineData(1000000000, "un miliard")] [InlineData(2000000000, "două miliarde")] public void ToFeminineWords(int number, string expected) => Assert.Equal(expected, number.ToWords(GrammaticalGender.Feminine)); [Theory] [InlineData(-1, "minus unu")] [InlineData(0, "zero")] [InlineData(1, "unu")] [InlineData(2, "două")] [InlineData(3, "trei")] [InlineData(4, "patru")] [InlineData(5, "cinci")] public void ToNeuterWords(int number, string expected) => Assert.Equal(expected, number.ToWords(GrammaticalGender.Neuter)); // Test cases taken from Romanian Grammar, Mika Sarlin. [Theory] [InlineData(0, "zero")] [InlineData(1, "primul")] [InlineData(2, "al doilea")] [InlineData(3, "al treilea")] [InlineData(4, "al patrulea")] [InlineData(5, "al cincilea")] [InlineData(6, "al șaselea")] [InlineData(7, "al șaptelea")] [InlineData(8, "al optulea")] [InlineData(9, "al nouălea")] [InlineData(10, "al zecelea")] [InlineData(11, "al unsprezecelea")] [InlineData(12, "al doisprezecelea")] [InlineData(13, "al treisprezecelea")] [InlineData(14, "al paisprezecelea")] [InlineData(15, "al cincisprezecelea")] [InlineData(16, "al șaisprezecelea")] [InlineData(17, "al șaptesprezecelea")] [InlineData(18, "al optsprezecelea")] [InlineData(19, "al nouăsprezecelea")] [InlineData(20, "al douăzecilea")] [InlineData(21, "al douăzeci și unulea")] [InlineData(22, "al douăzeci și doilea")] [InlineData(30, "al treizecilea")] [InlineData(40, "al patruzecilea")] [InlineData(50, "al cincizecilea")] [InlineData(60, "al șaizecilea")] [InlineData(70, "al șaptezecilea")] [InlineData(80, "al optzecilea")] [InlineData(90, "al nouăzecilea")] [InlineData(100, "al o sutălea")] [InlineData(101, "al o sută unulea")] [InlineData(102, "al o sută doilea")] [InlineData(199, "al o sută nouăzeci și nouălea")] [InlineData(200, "al două sutelea")] [InlineData(300, "al trei sutelea")] [InlineData(1000, "al o mielea")] [InlineData(1001, "al o mie unulea")] [InlineData(2000, "al două miilea")] [InlineData(10000, "al zece miilea")] [InlineData(20000, "al douăzeci miilea")] [InlineData(50000, "al cincizeci miilea")] [InlineData(1000000, "al un milionulea")] [InlineData(2000000, "al două milioanelea")] [InlineData(20000000, "al douăzeci milioanelea")] [InlineData(1000000000, "al un miliardulea")] [InlineData(2000000000, "al două miliardelea")] public void ToOrdinalWords(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords()); [Theory] [InlineData(0, "zero")] [InlineData(1, "primul")] [InlineData(2, "al doilea")] [InlineData(3, "al treilea")] [InlineData(4, "al patrulea")] [InlineData(5, "al cincilea")] [InlineData(6, "al șaselea")] [InlineData(7, "al șaptelea")] [InlineData(8, "al optulea")] [InlineData(9, "al nouălea")] [InlineData(10, "al zecelea")] [InlineData(11, "al unsprezecelea")] [InlineData(12, "al doisprezecelea")] [InlineData(13, "al treisprezecelea")] [InlineData(14, "al paisprezecelea")] [InlineData(15, "al cincisprezecelea")] [InlineData(16, "al șaisprezecelea")] [InlineData(17, "al șaptesprezecelea")] [InlineData(18, "al optsprezecelea")] [InlineData(19, "al nouăsprezecelea")] [InlineData(20, "al douăzecilea")] [InlineData(21, "al douăzeci și unulea")] [InlineData(22, "al douăzeci și doilea")] [InlineData(30, "al treizecilea")] [InlineData(40, "al patruzecilea")] [InlineData(50, "al cincizecilea")] [InlineData(60, "al șaizecilea")] [InlineData(70, "al șaptezecilea")] [InlineData(80, "al optzecilea")] [InlineData(90, "al nouăzecilea")] [InlineData(100, "al o sutălea")] [InlineData(101, "al o sută unulea")] [InlineData(102, "al o sută doilea")] [InlineData(199, "al o sută nouăzeci și nouălea")] [InlineData(200, "al două sutelea")] [InlineData(300, "al trei sutelea")] [InlineData(1000, "al o mielea")] [InlineData(1001, "al o mie unulea")] [InlineData(2000, "al două miilea")] [InlineData(10000, "al zece miilea")] [InlineData(20000, "al douăzeci miilea")] [InlineData(50000, "al cincizeci miilea")] [InlineData(1000000, "al un milionulea")] [InlineData(2000000, "al două milioanelea")] [InlineData(20000000, "al douăzeci milioanelea")] [InlineData(1000000000, "al un miliardulea")] [InlineData(2000000000, "al două miliardelea")] public void ToMasculineOrdinalWords(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Masculine)); [Theory] [InlineData(0, "zero")] [InlineData(1, "prima")] [InlineData(2, "a doua")] [InlineData(3, "a treia")] [InlineData(4, "a patra")] [InlineData(5, "a cincea")] [InlineData(6, "a șasea")] [InlineData(7, "a șaptea")] [InlineData(8, "a opta")] [InlineData(9, "a noua")] [InlineData(10, "a zecea")] [InlineData(11, "a unsprezecea")] [InlineData(12, "a douăsprezecea")] [InlineData(13, "a treisprezecea")] [InlineData(14, "a paisprezecea")] [InlineData(15, "a cincisprezecea")] [InlineData(16, "a șaisprezecea")] [InlineData(17, "a șaptesprezecea")] [InlineData(18, "a optsprezecea")] [InlineData(19, "a nouăsprezecea")] [InlineData(20, "a douăzecea")] [InlineData(21, "a douăzeci și una")] [InlineData(22, "a douăzeci și doua")] [InlineData(30, "a treizecea")] [InlineData(40, "a patruzecea")] [InlineData(50, "a cincizecea")] [InlineData(60, "a șaizecea")] [InlineData(70, "a șaptezecea")] [InlineData(80, "a optzecea")] [InlineData(90, "a nouăzecea")] [InlineData(100, "a o suta")] [InlineData(101, "a o sută una")] [InlineData(102, "a o sută doua")] [InlineData(199, "a o sută nouăzeci și noua")] [InlineData(200, "a două suta")] [InlineData(300, "a trei suta")] [InlineData(1000, "a o mia")] [InlineData(1001, "a o mie una")] [InlineData(2000, "a două mia")] [InlineData(10000, "a zece mia")] [InlineData(20000, "a douăzeci mia")] [InlineData(50000, "a cincizeci mia")] [InlineData(1000000, "a milioana")] [InlineData(2000000, "a două milioana")] [InlineData(20000000, "a douăzecea milioana")] [InlineData(1000000000, "a miliarda")] [InlineData(2000000000, "a două miliarda")] public void ToFeminineOrdinalWords(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Feminine)); [Theory] [InlineData(0, "zero")] [InlineData(1, "primul")] [InlineData(2, "al doilea")] [InlineData(3, "al treilea")] [InlineData(4, "al patrulea")] [InlineData(5, "al cincilea")] public void ToNeuterOrdinalWords(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Neuter)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ro-Ro/OrdinalizerTests.cs ================================================ namespace roRO; [UseCulture("ro-RO")] public class OrdinalizerTests { [Theory] [InlineData(0, "0")] // No ordinal for 0 (zero) in Romanian. [InlineData(1, "primul")] [InlineData(2, "al 2-lea")] [InlineData(3, "al 3-lea")] [InlineData(10, "al 10-lea")] public void GenderlessNumber(int number, string expected) => Assert.Equal(expected, number.Ordinalize()); [Theory] [InlineData("0", "0")] // No ordinal for 0 (zero) in Romanian. [InlineData("1", "primul")] [InlineData("2", "al 2-lea")] [InlineData("3", "al 3-lea")] [InlineData("10", "al 10-lea")] public void GenderlessText(string number, string expected) => Assert.Equal(expected, number.Ordinalize()); [Theory] [InlineData(0, "0")] // No ordinal for 0 (zero) in Romanian. [InlineData(1, "primul")] [InlineData(2, "al 2-lea")] [InlineData(3, "al 3-lea")] [InlineData(10, "al 10-lea")] public void MasculineNumber(int number, string expected) => Assert.Equal(expected, number.Ordinalize(GrammaticalGender.Masculine)); [Theory] [InlineData("0", "0")] // No ordinal for 0 (zero) in Romanian. [InlineData("1", "primul")] [InlineData("2", "al 2-lea")] [InlineData("3", "al 3-lea")] [InlineData("10", "al 10-lea")] public void MasculineText(string number, string expected) => Assert.Equal(expected, number.Ordinalize(GrammaticalGender.Masculine)); [Theory] [InlineData(0, "0")] // No ordinal for 0 (zero) in Romanian. [InlineData(1, "prima")] [InlineData(2, "a 2-a")] [InlineData(10, "a 10-a")] public void FeminineNumber(int number, string expected) => Assert.Equal(expected, number.Ordinalize(GrammaticalGender.Feminine)); [Theory] [InlineData("0", "0")] // No ordinal for 0 (zero) in Romanian. [InlineData("1", "prima")] [InlineData("2", "a 2-a")] [InlineData("10", "a 10-a")] public void FeminineText(string number, string expected) => Assert.Equal(expected, number.Ordinalize(GrammaticalGender.Feminine)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ro-Ro/TimeSpanHumanizerTests.cs ================================================ namespace roRO; /// /// Test that for values bigger than 19 "de" is added between the numeral /// and the time unit: http://ebooks.unibuc.ro/filologie/NForascu-DGLR/numerale.htm. /// There is no test for months since there are only 12 of them in a year. /// [UseCulture("ro-RO")] public class TimeSpanHumanizerTests { [Theory] [InlineData(1, "1 milisecundă")] [InlineData(14, "14 milisecunde")] [InlineData(21, "21 de milisecunde")] [InlineData(3000, "3 secunde")] public void Milliseconds(int milliseconds, string expected) { var actual = TimeSpan.FromMilliseconds(milliseconds).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(0, "0 secunde", true)] [InlineData(0, "0 de secunde")] [InlineData(1, "1 secundă")] [InlineData(14, "14 secunde")] [InlineData(21, "21 de secunde")] [InlineData(156, "2 minute")] public void Seconds(int seconds, string expected, bool toWords = false) { var actual = TimeSpan.FromSeconds(seconds).Humanize(minUnit: TimeUnit.Second, toWords: toWords); Assert.Equal(expected, actual); } [Theory] [InlineData(1, "1 minut")] [InlineData(14, "14 minute")] [InlineData(21, "21 de minute")] [InlineData(156, "2 ore")] public void Minutes(int minutes, string expected) { var actual = TimeSpan.FromMinutes(minutes).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(1, "1 oră")] [InlineData(14, "14 ore")] [InlineData(21, "21 de ore")] [InlineData(48, "2 zile")] public void Hours(int hours, string expected) { var actual = TimeSpan.FromHours(hours).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(1, "1 zi")] [InlineData(6, "6 zile")] [InlineData(7, "1 săptămână")] [InlineData(14, "2 săptămâni")] [InlineData(21, "3 săptămâni")] public void Days(int days, string expected) { var actual = TimeSpan.FromDays(days).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(1, "1 săptămână")] [InlineData(14, "14 săptămâni")] [InlineData(21, "21 de săptămâni")] public void Weeks(int weeks, string expected) { var actual = TimeSpan.FromDays(7 * weeks).Humanize(); Assert.Equal(expected, actual); } [Theory] [Trait("Translation", "Native speaker")] [InlineData(31, "1 lună")] [InlineData(61, "2 luni")] [InlineData(92, "3 luni")] [InlineData(335, "11 luni")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Native speaker")] [InlineData(366, "1 an")] [InlineData(731, "2 ani")] [InlineData(1096, "3 ani")] [InlineData(4018, "11 ani")] [InlineData(7500, "20 de ani")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Fact] public void NoTime() => Assert.Equal("0 de milisecunde", TimeSpan.Zero.Humanize()); [Fact, CustomDescription("The name of this test is confusing because has no sense. Instead should be read as an interval with duration zero and not the absence of time.")] public void NoTimeToWords() => // Usage in Romanian: "Timp execuție: 0 secunde." // Should be equivalent with TimeSpan.FromSeconds(0).Humanize() Assert.Equal("0 secunde", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ru-RU/Bytes/ByteRateTests.cs ================================================ namespace ruRU.Bytes; [UseCulture("ru-RU")] public class ByteRateTests { [Theory] [InlineData(400, 1, "400 Б/сек.")] [InlineData(4 * 1024, 1, "4 КБ/сек.")] [InlineData(4 * 1024 * 1024, 1, "4 МБ/сек.")] [InlineData(4 * 2 * 1024 * 1024, 2, "4 МБ/сек.")] [InlineData(4 * 1024, 0.1, "40 КБ/сек.")] [InlineData(15 * 60 * 1024 * 1024, 60, "15 МБ/сек.")] public void HumanizesRates(long inputBytes, double perSeconds, string expectedValue) { var size = new ByteSize(inputBytes); var interval = TimeSpan.FromSeconds(perSeconds); var rate = size.Per(interval).Humanize(); Assert.Equal(expectedValue, rate); } [Theory] [InlineData(1, 1, TimeUnit.Second, "1 МБ/сек.")] [InlineData(1, 60, TimeUnit.Minute, "1 МБ/мин.")] [InlineData(1, 60 * 60, TimeUnit.Hour, "1 МБ/ч.")] [InlineData(10, 1, TimeUnit.Second, "10 МБ/сек.")] [InlineData(10, 60, TimeUnit.Minute, "10 МБ/мин.")] [InlineData(10, 60 * 60, TimeUnit.Hour, "10 МБ/ч.")] [InlineData(1, 10 * 1, TimeUnit.Second, "102,4 КБ/сек.")] [InlineData(1, 10 * 60, TimeUnit.Minute, "102,4 КБ/мин.")] [InlineData(1, 10 * 60 * 60, TimeUnit.Hour, "102,4 КБ/ч.")] public void TimeUnitTests(long megabytes, double measurementIntervalSeconds, TimeUnit displayInterval, string expectedValue) { var size = ByteSize.FromMegabytes(megabytes); var measurementInterval = TimeSpan.FromSeconds(measurementIntervalSeconds); var rate = size.Per(measurementInterval); var text = rate.Humanize(displayInterval); Assert.Equal(expectedValue, text); } [Theory] [InlineData(19854651984, 1, TimeUnit.Second, null, "18,49 ГБ/сек.")] [InlineData(19854651984, 1, TimeUnit.Second, "#.##", "18,49 ГБ/сек.")] public void FormattedTimeUnitTests(long bytes, int measurementIntervalSeconds, TimeUnit displayInterval, string? format, string expectedValue) { var size = ByteSize.FromBytes(bytes); var measurementInterval = TimeSpan.FromSeconds(measurementIntervalSeconds); var rate = size.Per(measurementInterval); var text = rate.Humanize(format, displayInterval); Assert.Equal(expectedValue, text); } [Theory] [InlineData(TimeUnit.Millisecond)] [InlineData(TimeUnit.Day)] [InlineData(TimeUnit.Month)] [InlineData(TimeUnit.Week)] [InlineData(TimeUnit.Year)] public void ThrowsOnUnsupportedData(TimeUnit units) { var dummyRate = ByteSize.FromBits(1).Per(TimeSpan.FromSeconds(1)); Assert.Throws(() => dummyRate.Humanize(units)); } } ================================================ FILE: tests/Humanizer.Tests/Localisation/ru-RU/Bytes/ByteSizeExtensionsTests.cs ================================================ namespace ruRU.Bytes; [UseCulture("ru-RU")] public class ByteSizeExtensionsTests { [Theory] [InlineData(2, null, "2 ТБ")] [InlineData(2, "GB", "2048 ГБ")] [InlineData(2.1, null, "2,1 ТБ")] [InlineData(2.123, "#.#", "2,1 ТБ")] public void HumanizesTerabytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Terabytes().Humanize(format)); [Theory] [InlineData(0, null, "0 бит")] [InlineData(0, "GB", "0 ГБ")] [InlineData(2, null, "2 ГБ")] [InlineData(2, "MB", "2048 МБ")] [InlineData(2.123, "#.##", "2,12 ГБ")] public void HumanizesGigabytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Gigabytes().Humanize(format)); [Theory] [InlineData(0, null, "0 бит")] [InlineData(0, "MB", "0 МБ")] [InlineData(2, null, "2 МБ")] [InlineData(2, "KB", "2048 КБ")] [InlineData(2.123, "#", "2 МБ")] public void HumanizesMegabytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Megabytes().Humanize(format)); [Theory] [InlineData(0, null, "0 бит")] [InlineData(0, "KB", "0 КБ")] [InlineData(2, null, "2 КБ")] [InlineData(2, "B", "2048 Б")] [InlineData(2.123, "#.####", "2,123 КБ")] public void HumanizesKilobytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Kilobytes().Humanize(format)); [Theory] [InlineData(0, null, "0 бит")] [InlineData(0, "#.##", "0 бит")] [InlineData(0, "#.## B", "0 Б")] [InlineData(0, "B", "0 Б")] [InlineData(2, null, "2 Б")] [InlineData(2000, "KB", "1,95 КБ")] [InlineData(2123, "#.##", "2,07 КБ")] [InlineData(10000000, "KB", "9765,63 КБ")] [InlineData(10000000, "#,##0 KB", "9 766 КБ")] [InlineData(10000000, "#,##0.# KB", "9 765,6 КБ")] public void HumanizesBytes(double input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Bytes().Humanize(format)); [Theory] [InlineData(0, null, "0 бит")] [InlineData(0, "b", "0 бит")] [InlineData(2, null, "2 бит")] [InlineData(12, "B", "1,5 Б")] [InlineData(10000, "#.# KB", "1,2 КБ")] public void HumanizesBits(long input, string? format, string expectedValue) => Assert.Equal(expectedValue, input.Bits().Humanize(format)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ru-RU/Bytes/ToFullWordsTests.cs ================================================ namespace ruRU.Bytes; [UseCulture("ru-RU")] public class ToFullWordsTests { [Fact] public void ReturnsSingularBit() => Assert.Equal("1 бит", ByteSize.FromBits(1).ToFullWords()); [Fact] public void ReturnsPluralBits() => Assert.Equal("2 бит", ByteSize.FromBits(2).ToFullWords()); [Fact] public void ReturnsSingularByte() => Assert.Equal("1 байт", ByteSize.FromBytes(1).ToFullWords()); [Fact] public void ReturnsPluralBytes() => Assert.Equal("10 байт", ByteSize.FromBytes(10).ToFullWords()); [Fact] public void ReturnsSingularKiloByte() => Assert.Equal("1 килобайт", ByteSize.FromKilobytes(1).ToFullWords()); [Fact] public void ReturnsPluralKilobytes() => Assert.Equal("10 килобайт", ByteSize.FromKilobytes(10).ToFullWords()); [Fact] public void ReturnsSingularMegabyte() => Assert.Equal("1 мегабайт", ByteSize.FromMegabytes(1).ToFullWords()); [Fact] public void ReturnsPluralMegabytes() => Assert.Equal("10 мегабайт", ByteSize.FromMegabytes(10).ToFullWords()); [Fact] public void ReturnsSingularGigabyte() => Assert.Equal("1 гигабайт", ByteSize.FromGigabytes(1).ToFullWords()); [Fact] public void ReturnsPluralGigabytes() => Assert.Equal("10 гигабайт", ByteSize.FromGigabytes(10).ToFullWords()); [Fact] public void ReturnsSingularTerabyte() => Assert.Equal("1 терабайт", ByteSize.FromTerabytes(1).ToFullWords()); [Fact] public void ReturnsPluralTerabytes() => Assert.Equal("10 терабайт", ByteSize.FromTerabytes(10).ToFullWords()); [Theory] [InlineData(229376, "B", "229376 байт")] [InlineData(229376, "# KB", "224 килобайт")] public void ToFullWordsFormatted(double input, string format, string expectedValue) => Assert.Equal(expectedValue, ByteSize.FromBytes(input).ToFullWords(format)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ru-RU/Bytes/ToStringTests.cs ================================================ namespace ruRU.Bytes; [UseCulture("ru-RU")] public class ToStringTests { [Fact] public void ReturnsLargestMetricSuffix() => Assert.Equal("10,5 КБ", ByteSize.FromKilobytes(10.5).ToString()); [Fact] public void ReturnsDefaultNumberFormat() => Assert.Equal("10,5 КБ", ByteSize.FromKilobytes(10.5).ToString("KB")); [Fact] public void ReturnsProvidedNumberFormat() => Assert.Equal("10,1234 КБ", ByteSize.FromKilobytes(10.1234).ToString("#.#### KB")); [Fact] public void ReturnsBits() => Assert.Equal("10 бит", ByteSize.FromBits(10).ToString("##.#### b")); [Fact] public void ReturnsBytes() => Assert.Equal("10 Б", ByteSize.FromBytes(10).ToString("##.#### B")); [Fact] public void ReturnsKilobytes() => Assert.Equal("10 КБ", ByteSize.FromKilobytes(10).ToString("##.#### KB")); [Fact] public void ReturnsMegabytes() => Assert.Equal("10 МБ", ByteSize.FromMegabytes(10).ToString("##.#### MB")); [Fact] public void ReturnsGigabytes() => Assert.Equal("10 ГБ", ByteSize.FromGigabytes(10).ToString("##.#### GB")); [Fact] public void ReturnsTerabytes() => Assert.Equal("10 ТБ", ByteSize.FromTerabytes(10).ToString("##.#### TB")); [Fact] public void ReturnsSelectedFormat() => Assert.Equal("10,0 ТБ", ByteSize.FromTerabytes(10).ToString("0.0 TB")); [Fact] public void ReturnsLargestMetricPrefixLargerThanZero() => Assert.Equal("512 КБ", ByteSize.FromMegabytes(.5).ToString("#.#")); [Fact] public void ReturnsLargestMetricPrefixLargerThanZeroForNegativeValues() => Assert.Equal("-512 КБ", ByteSize.FromMegabytes(-.5).ToString("#.#")); [Fact] public void ReturnsBytesViaGeneralFormat() => Assert.Equal("10 Б", $"{ByteSize.FromBytes(10)}"); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ru-RU/DateHumanizeTests.cs ================================================ namespace ruRU; [UseCulture("ru-RU")] public class DateHumanizeTests { [Theory] [InlineData(1, "секунду назад")] [InlineData(2, "2 секунды назад")] [InlineData(3, "3 секунды назад")] [InlineData(4, "4 секунды назад")] [InlineData(5, "5 секунд назад")] [InlineData(6, "6 секунд назад")] [InlineData(10, "10 секунд назад")] [InlineData(11, "11 секунд назад")] [InlineData(19, "19 секунд назад")] [InlineData(20, "20 секунд назад")] [InlineData(21, "21 секунду назад")] [InlineData(22, "22 секунды назад")] [InlineData(23, "23 секунды назад")] [InlineData(24, "24 секунды назад")] [InlineData(25, "25 секунд назад")] [InlineData(40, "40 секунд назад")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "через секунду")] [InlineData(2, "через 2 секунды")] [InlineData(3, "через 3 секунды")] [InlineData(4, "через 4 секунды")] [InlineData(5, "через 5 секунд")] [InlineData(6, "через 6 секунд")] [InlineData(10, "через 10 секунд")] [InlineData(11, "через 11 секунд")] [InlineData(19, "через 19 секунд")] [InlineData(20, "через 20 секунд")] [InlineData(21, "через 21 секунду")] [InlineData(22, "через 22 секунды")] [InlineData(23, "через 23 секунды")] [InlineData(24, "через 24 секунды")] [InlineData(25, "через 25 секунд")] [InlineData(40, "через 40 секунд")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(1, "минуту назад")] [InlineData(2, "2 минуты назад")] [InlineData(3, "3 минуты назад")] [InlineData(4, "4 минуты назад")] [InlineData(5, "5 минут назад")] [InlineData(6, "6 минут назад")] [InlineData(10, "10 минут назад")] [InlineData(11, "11 минут назад")] [InlineData(19, "19 минут назад")] [InlineData(20, "20 минут назад")] [InlineData(21, "21 минуту назад")] [InlineData(22, "22 минуты назад")] [InlineData(23, "23 минуты назад")] [InlineData(24, "24 минуты назад")] [InlineData(25, "25 минут назад")] [InlineData(40, "40 минут назад")] [InlineData(60, "час назад")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "через минуту")] [InlineData(2, "через 2 минуты")] [InlineData(3, "через 3 минуты")] [InlineData(4, "через 4 минуты")] [InlineData(5, "через 5 минут")] [InlineData(6, "через 6 минут")] [InlineData(10, "через 10 минут")] [InlineData(11, "через 11 минут")] [InlineData(19, "через 19 минут")] [InlineData(20, "через 20 минут")] [InlineData(21, "через 21 минуту")] [InlineData(22, "через 22 минуты")] [InlineData(23, "через 23 минуты")] [InlineData(24, "через 24 минуты")] [InlineData(25, "через 25 минут")] [InlineData(40, "через 40 минут")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(1, "час назад")] [InlineData(2, "2 часа назад")] [InlineData(3, "3 часа назад")] [InlineData(4, "4 часа назад")] [InlineData(5, "5 часов назад")] [InlineData(6, "6 часов назад")] [InlineData(10, "10 часов назад")] [InlineData(11, "11 часов назад")] [InlineData(19, "19 часов назад")] [InlineData(20, "20 часов назад")] [InlineData(21, "21 час назад")] [InlineData(22, "22 часа назад")] [InlineData(23, "23 часа назад")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "через час")] [InlineData(2, "через 2 часа")] [InlineData(3, "через 3 часа")] [InlineData(4, "через 4 часа")] [InlineData(5, "через 5 часов")] [InlineData(6, "через 6 часов")] [InlineData(10, "через 10 часов")] [InlineData(11, "через 11 часов")] [InlineData(19, "через 19 часов")] [InlineData(20, "через 20 часов")] [InlineData(21, "через 21 час")] [InlineData(22, "через 22 часа")] [InlineData(23, "через 23 часа")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(1, "вчера")] [InlineData(2, "2 дня назад")] [InlineData(3, "3 дня назад")] [InlineData(4, "4 дня назад")] [InlineData(5, "5 дней назад")] [InlineData(6, "6 дней назад")] [InlineData(10, "10 дней назад")] [InlineData(11, "11 дней назад")] [InlineData(19, "19 дней назад")] [InlineData(20, "20 дней назад")] [InlineData(21, "21 день назад")] [InlineData(22, "22 дня назад")] [InlineData(23, "23 дня назад")] [InlineData(24, "24 дня назад")] [InlineData(25, "25 дней назад")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "завтра")] [InlineData(2, "через 2 дня")] [InlineData(3, "через 3 дня")] [InlineData(4, "через 4 дня")] [InlineData(5, "через 5 дней")] [InlineData(6, "через 6 дней")] [InlineData(10, "через 10 дней")] [InlineData(11, "через 11 дней")] [InlineData(19, "через 19 дней")] [InlineData(20, "через 20 дней")] [InlineData(21, "через 21 день")] [InlineData(22, "через 22 дня")] [InlineData(23, "через 23 дня")] [InlineData(24, "через 24 дня")] [InlineData(25, "через 25 дней")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(1, "месяц назад")] [InlineData(2, "2 месяца назад")] [InlineData(3, "3 месяца назад")] [InlineData(4, "4 месяца назад")] [InlineData(5, "5 месяцев назад")] [InlineData(6, "6 месяцев назад")] [InlineData(10, "10 месяцев назад")] [InlineData(11, "11 месяцев назад")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "через месяц")] [InlineData(2, "через 2 месяца")] [InlineData(3, "через 3 месяца")] [InlineData(4, "через 4 месяца")] [InlineData(5, "через 5 месяцев")] [InlineData(6, "через 6 месяцев")] [InlineData(10, "через 10 месяцев")] [InlineData(11, "через 11 месяцев")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(1, "год назад")] [InlineData(2, "2 года назад")] [InlineData(3, "3 года назад")] [InlineData(4, "4 года назад")] [InlineData(5, "5 лет назад")] [InlineData(6, "6 лет назад")] [InlineData(10, "10 лет назад")] [InlineData(11, "11 лет назад")] [InlineData(19, "19 лет назад")] [InlineData(21, "21 год назад")] [InlineData(111, "111 лет назад")] [InlineData(121, "121 год назад")] [InlineData(222, "222 года назад")] [InlineData(325, "325 лет назад")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "через год")] [InlineData(2, "через 2 года")] [InlineData(3, "через 3 года")] [InlineData(4, "через 4 года")] [InlineData(5, "через 5 лет")] [InlineData(6, "через 6 лет")] [InlineData(10, "через 10 лет")] [InlineData(11, "через 11 лет")] [InlineData(19, "через 19 лет")] [InlineData(20, "через 20 лет")] [InlineData(21, "через 21 год")] [InlineData(111, "через 111 лет")] [InlineData(121, "через 121 год")] [InlineData(222, "через 222 года")] [InlineData(325, "через 325 лет")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Fact] public void Now() => DateHumanize.Verify("сейчас", 0, TimeUnit.Day, Tense.Past); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ru-RU/HeadingTests.cs ================================================ namespace ruRU; [UseCulture("ru-RU")] public class HeadingTests { [InlineData(0, "С")] [InlineData(11.2, "С")] [InlineData(11.3, "ССВ")] [InlineData(22.5, "ССВ")] [InlineData(33.7, "ССВ")] [InlineData(33.8, "СВ")] [InlineData(45, "СВ")] [InlineData(56.2, "СВ")] [InlineData(56.3, "ВСВ")] [InlineData(67.5, "ВСВ")] [InlineData(78.7, "ВСВ")] [InlineData(78.8, "В")] [InlineData(90, "В")] [InlineData(101.2, "В")] [InlineData(101.3, "ВЮВ")] [InlineData(112.5, "ВЮВ")] [InlineData(123.7, "ВЮВ")] [InlineData(123.8, "ЮВ")] [InlineData(135, "ЮВ")] [InlineData(146.2, "ЮВ")] [InlineData(146.3, "ЮЮВ")] [InlineData(157.5, "ЮЮВ")] [InlineData(168.7, "ЮЮВ")] [InlineData(168.8, "Ю")] [InlineData(180, "Ю")] [InlineData(191.2, "Ю")] [InlineData(191.3, "ЮЮЗ")] [InlineData(202.5, "ЮЮЗ")] [InlineData(213.7, "ЮЮЗ")] [InlineData(213.8, "ЮЗ")] [InlineData(225, "ЮЗ")] [InlineData(236.2, "ЮЗ")] [InlineData(236.3, "ЗЮЗ")] [InlineData(247.5, "ЗЮЗ")] [InlineData(258.7, "ЗЮЗ")] [InlineData(258.8, "З")] [InlineData(270, "З")] [InlineData(281.2, "З")] [InlineData(281.3, "ЗСЗ")] [InlineData(292.5, "ЗСЗ")] [InlineData(303.7, "ЗСЗ")] [InlineData(303.8, "СЗ")] [InlineData(315, "СЗ")] [InlineData(326.2, "СЗ")] [InlineData(326.3, "ССЗ")] [InlineData(337.5, "ССЗ")] [InlineData(348.7, "ССЗ")] [InlineData(348.8, "С")] [InlineData(360, "С")] [InlineData(720, "С")] [Theory] public void ToHeadingAbbreviated(double heading, string expected) => Assert.Equal(expected, heading.ToHeading()); [InlineData(0, "север")] [InlineData(22.5, "северо-северо-восток")] [InlineData(45, "северо-восток")] [InlineData(67.5, "востоко-северо-восток")] [InlineData(90, "восток")] [InlineData(112.5, "востоко-юго-восток")] [InlineData(135, "юго-восток")] [InlineData(157.5, "юго-юго-восток")] [InlineData(180, "юг")] [InlineData(202.5, "юго-юго-запад")] [InlineData(225, "юго-запад")] [InlineData(247.5, "западо-юго-запад")] [InlineData(270, "запад")] [InlineData(292.5, "западо-северо-запад")] [InlineData(315, "северо-запад")] [InlineData(337.5, "северо-северо-запад")] [InlineData(360, "север")] [InlineData(720, "север")] [Theory] public void ToHeading(double heading, string expected) => Assert.Equal(expected, heading.ToHeading(HeadingStyle.Full)); [InlineData("С", 0)] [InlineData("ССВ", 22.5)] [InlineData("СВ", 45)] [InlineData("ВСВ", 67.5)] [InlineData("В", 90)] [InlineData("ВЮВ", 112.5)] [InlineData("ЮВ", 135)] [InlineData("ЮЮВ", 157.5)] [InlineData("Ю", 180)] [InlineData("ЮЮЗ", 202.5)] [InlineData("ЮЗ", 225)] [InlineData("ЗЮЗ", 247.5)] [InlineData("З", 270)] [InlineData("ЗСЗ", 292.5)] [InlineData("СЗ", 315)] [InlineData("ССЗ", 337.5)] [Theory] public void FromShortHeading(string heading, double expected) => Assert.Equal(expected, heading.FromAbbreviatedHeading()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ru-RU/NumberToWordsTests.cs ================================================ namespace ruRU; [UseCulture("ru-RU")] public class NumberToWordsTests { [Theory] [InlineData(-123, "минус сто двадцать три")] [InlineData(0, "ноль")] [InlineData(1, "один")] [InlineData(10, "десять")] [InlineData(11, "одиннадцать")] [InlineData(12, "двенадцать")] [InlineData(13, "тринадцать")] [InlineData(14, "четырнадцать")] [InlineData(15, "пятнадцать")] [InlineData(16, "шестнадцать")] [InlineData(17, "семнадцать")] [InlineData(18, "восемнадцать")] [InlineData(19, "девятнадцать")] [InlineData(20, "двадцать")] [InlineData(30, "тридцать")] [InlineData(40, "сорок")] [InlineData(50, "пятьдесят")] [InlineData(60, "шестьдесят")] [InlineData(70, "семьдесят")] [InlineData(80, "восемьдесят")] [InlineData(90, "девяносто")] [InlineData(100, "сто")] [InlineData(200, "двести")] [InlineData(300, "триста")] [InlineData(400, "четыреста")] [InlineData(500, "пятьсот")] [InlineData(600, "шестьсот")] [InlineData(700, "семьсот")] [InlineData(800, "восемьсот")] [InlineData(900, "девятьсот")] [InlineData(1000, "одна тысяча")] [InlineData(2000, "две тысячи")] [InlineData(3000, "три тысячи")] [InlineData(4000, "четыре тысячи")] [InlineData(5000, "пять тысяч")] [InlineData(10000, "десять тысяч")] [InlineData(100000, "сто тысяч")] [InlineData(1000000, "один миллион")] [InlineData(2000000, "два миллиона")] [InlineData(10000000, "десять миллионов")] [InlineData(100000000, "сто миллионов")] [InlineData(1000000000, "один миллиард")] [InlineData(2000000000, "два миллиарда")] [InlineData(3000000000, "три миллиарда")] [InlineData(4000000000, "четыре миллиарда")] [InlineData(122, "сто двадцать два")] [InlineData(3501, "три тысячи пятьсот один")] [InlineData(111, "сто одиннадцать")] [InlineData(1112, "одна тысяча сто двенадцать")] [InlineData(11213, "одиннадцать тысяч двести тринадцать")] [InlineData(121314, "сто двадцать одна тысяча триста четырнадцать")] [InlineData(2132415, "два миллиона сто тридцать две тысячи четыреста пятнадцать")] [InlineData(12345516, "двенадцать миллионов триста сорок пять тысяч пятьсот шестнадцать")] [InlineData(751633617, "семьсот пятьдесят один миллион шестьсот тридцать три тысячи шестьсот семнадцать")] [InlineData(1111111118, "один миллиард сто одиннадцать миллионов сто одиннадцать тысяч сто восемнадцать")] [InlineData(4111111118, "четыре миллиарда сто одиннадцать миллионов сто одиннадцать тысяч сто восемнадцать")] [InlineData(-751633617, "минус семьсот пятьдесят один миллион шестьсот тридцать три тысячи шестьсот семнадцать")] [InlineData(999999999999, "девятьсот девяносто девять миллиардов девятьсот девяносто девять миллионов девятьсот девяносто девять тысяч девятьсот девяносто девять")] [InlineData(1_000_000_000_000, "один триллион")] [InlineData(3_000_000_000_000, "три триллиона")] [InlineData(5_000_000_000_000, "пять триллионов")] [InlineData(999_000_000_000_000, "девятьсот девяносто девять триллионов")] [InlineData( long.MaxValue, "девять квинтиллионов " + "двести двадцать три квадриллиона " + "триста семьдесят два триллиона " + "тридцать шесть миллиардов " + "восемьсот пятьдесят четыре миллиона " + "семьсот семьдесят пять тысяч " + "восемьсот семь")] [InlineData( long.MinValue, "минус девять квинтиллионов " + "двести двадцать три квадриллиона " + "триста семьдесят два триллиона " + "тридцать шесть миллиардов " + "восемьсот пятьдесят четыре миллиона " + "семьсот семьдесят пять тысяч " + "восемьсот восемь")] public void ToWords(long number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(122, "сто двадцать две", GrammaticalGender.Feminine)] [InlineData(3501, "три тысячи пятьсот одна", GrammaticalGender.Feminine)] [InlineData(3501, "три тысячи пятьсот одно", GrammaticalGender.Neuter)] public void ToWordsWithGender(int number, string expected, GrammaticalGender gender) => Assert.Equal(expected, number.ToWords(gender)); [Theory] [InlineData(0, "нулевой")] [InlineData(1, "первый")] [InlineData(2, "второй")] [InlineData(3, "третий")] [InlineData(10, "десятый")] [InlineData(11, "одиннадцатый")] [InlineData(12, "двенадцатый")] [InlineData(13, "тринадцатый")] [InlineData(14, "четырнадцатый")] [InlineData(15, "пятнадцатый")] [InlineData(16, "шестнадцатый")] [InlineData(17, "семнадцатый")] [InlineData(18, "восемнадцатый")] [InlineData(19, "девятнадцатый")] [InlineData(20, "двадцатый")] [InlineData(30, "тридцатый")] [InlineData(40, "сороковой")] [InlineData(50, "пятидесятый")] [InlineData(60, "шестидесятый")] [InlineData(70, "семидесятый")] [InlineData(80, "восьмидесятый")] [InlineData(90, "девяностый")] [InlineData(100, "сотый")] [InlineData(101, "сто первый")] [InlineData(140, "сто сороковой")] [InlineData(200, "двухсотый")] [InlineData(300, "трёхсотый")] [InlineData(400, "четырёхсотый")] [InlineData(500, "пятисотый")] [InlineData(600, "шестисотый")] [InlineData(700, "семисотый")] [InlineData(800, "восьмисотый")] [InlineData(900, "девятисотый")] [InlineData(1000, "тысячный")] [InlineData(1001, "одна тысяча первый")] [InlineData(1040, "одна тысяча сороковой")] [InlineData(2000, "двухтысячный")] [InlineData(3000, "трёхтысячный")] [InlineData(4000, "четырёхтысячный")] [InlineData(5000, "пятитысячный")] [InlineData(10000, "десятитысячный")] [InlineData(21000, "двадцатиоднотысячный")] [InlineData(100000, "стотысячный")] [InlineData(101000, "стооднотысячный")] [InlineData(121000, "стодвадцатиоднотысячный")] [InlineData(200000, "двухсоттысячный")] [InlineData(1000000, "миллионный")] [InlineData(2000000, "двухмиллионный")] [InlineData(10000000, "десятимиллионный")] [InlineData(21000000, "двадцатиодномиллионный")] [InlineData(100000000, "стомиллионный")] [InlineData(230000000, "двухсоттридцатимиллионный")] [InlineData(1000000000, "миллиардный")] [InlineData(2000000000, "двухмиллиардный")] [InlineData(122, "сто двадцать второй")] [InlineData(3501, "три тысячи пятьсот первый")] [InlineData(111, "сто одиннадцатый")] [InlineData(1112, "одна тысяча сто двенадцатый")] [InlineData(11213, "одиннадцать тысяч двести тринадцатый")] [InlineData(121314, "сто двадцать одна тысяча триста четырнадцатый")] [InlineData(2132415, "два миллиона сто тридцать две тысячи четыреста пятнадцатый")] [InlineData(12345516, "двенадцать миллионов триста сорок пять тысяч пятьсот шестнадцатый")] [InlineData(751633617, "семьсот пятьдесят один миллион шестьсот тридцать три тысячи шестьсот семнадцатый")] [InlineData(1111111118, "один миллиард сто одиннадцать миллионов сто одиннадцать тысяч сто восемнадцатый")] [InlineData(1111111000, "один миллиард сто одиннадцать миллионов стоодиннадцатитысячный")] [InlineData(1234567000, "один миллиард двести тридцать четыре миллиона пятисотшестидесятисемитысячный")] [InlineData(-751633617, "минус семьсот пятьдесят один миллион шестьсот тридцать три тысячи шестьсот семнадцатый")] public void ToOrdinalWords(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords()); [Theory] [InlineData(0, "нулевая")] [InlineData(1, "первая")] [InlineData(2, "вторая")] [InlineData(3, "третья")] [InlineData(10, "десятая")] [InlineData(11, "одиннадцатая")] [InlineData(12, "двенадцатая")] [InlineData(13, "тринадцатая")] [InlineData(14, "четырнадцатая")] [InlineData(15, "пятнадцатая")] [InlineData(16, "шестнадцатая")] [InlineData(17, "семнадцатая")] [InlineData(18, "восемнадцатая")] [InlineData(19, "девятнадцатая")] [InlineData(20, "двадцатая")] [InlineData(30, "тридцатая")] [InlineData(40, "сороковая")] [InlineData(50, "пятидесятая")] [InlineData(60, "шестидесятая")] [InlineData(70, "семидесятая")] [InlineData(80, "восьмидесятая")] [InlineData(90, "девяностая")] [InlineData(100, "сотая")] [InlineData(200, "двухсотая")] [InlineData(300, "трёхсотая")] [InlineData(400, "четырёхсотая")] [InlineData(500, "пятисотая")] [InlineData(600, "шестисотая")] [InlineData(700, "семисотая")] [InlineData(800, "восьмисотая")] [InlineData(900, "девятисотая")] [InlineData(1000, "тысячная")] [InlineData(2000, "двухтысячная")] [InlineData(3000, "трёхтысячная")] [InlineData(4000, "четырёхтысячная")] [InlineData(5000, "пятитысячная")] [InlineData(10000, "десятитысячная")] [InlineData(90000, "девяностотысячная")] [InlineData(100000, "стотысячная")] [InlineData(990000, "девятисотдевяностотысячная")] [InlineData(990001, "девятьсот девяносто тысяч первая")] [InlineData(1000000, "миллионная")] [InlineData(2000000, "двухмиллионная")] [InlineData(10000000, "десятимиллионная")] [InlineData(100000000, "стомиллионная")] [InlineData(1000000000, "миллиардная")] [InlineData(2000000000, "двухмиллиардная")] [InlineData(122, "сто двадцать вторая")] [InlineData(3501, "три тысячи пятьсот первая")] [InlineData(111, "сто одиннадцатая")] [InlineData(1112, "одна тысяча сто двенадцатая")] [InlineData(11000, "одиннадцатитысячная")] [InlineData(11001, "одиннадцать тысяч первая")] [InlineData(11213, "одиннадцать тысяч двести тринадцатая")] [InlineData(15000, "пятнадцатитысячная")] [InlineData(20000, "двадцатитысячная")] [InlineData(121314, "сто двадцать одна тысяча триста четырнадцатая")] [InlineData(2132415, "два миллиона сто тридцать две тысячи четыреста пятнадцатая")] [InlineData(12345516, "двенадцать миллионов триста сорок пять тысяч пятьсот шестнадцатая")] [InlineData(751633617, "семьсот пятьдесят один миллион шестьсот тридцать три тысячи шестьсот семнадцатая")] [InlineData(1111111118, "один миллиард сто одиннадцать миллионов сто одиннадцать тысяч сто восемнадцатая")] [InlineData(-751633617, "минус семьсот пятьдесят один миллион шестьсот тридцать три тысячи шестьсот семнадцатая")] public void ToOrdinalWordsFeminine(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Feminine)); [Theory] [InlineData(3, "третье")] [InlineData(111, "сто одиннадцатое")] [InlineData(1112, "одна тысяча сто двенадцатое")] [InlineData(11213, "одиннадцать тысяч двести тринадцатое")] [InlineData(121314, "сто двадцать одна тысяча триста четырнадцатое")] [InlineData(2132415, "два миллиона сто тридцать две тысячи четыреста пятнадцатое")] [InlineData(12345516, "двенадцать миллионов триста сорок пять тысяч пятьсот шестнадцатое")] [InlineData(751633617, "семьсот пятьдесят один миллион шестьсот тридцать три тысячи шестьсот семнадцатое")] [InlineData(1111111118, "один миллиард сто одиннадцать миллионов сто одиннадцать тысяч сто восемнадцатое")] [InlineData(-751633617, "минус семьсот пятьдесят один миллион шестьсот тридцать три тысячи шестьсот семнадцатое")] public void ToOrdinalWordsNeuter(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Neuter)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ru-RU/OrdinalizeTests.cs ================================================ namespace ruRU; [UseCulture("ru-RU")] public class OrdinalizeTests { [Theory] [InlineData("0", "0-й")] [InlineData("1", "1-й")] [InlineData("2", "2-й")] [InlineData("3", "3-й")] [InlineData("4", "4-й")] [InlineData("5", "5-й")] [InlineData("6", "6-й")] [InlineData("23", "23-й")] [InlineData("100", "100-й")] [InlineData("101", "101-й")] [InlineData("102", "102-й")] [InlineData("103", "103-й")] [InlineData("1001", "1001-й")] public void OrdinalizeString(string number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Masculine), ordinalized); [Theory] [InlineData("0", "0-я")] [InlineData("1", "1-я")] [InlineData("2", "2-я")] [InlineData("3", "3-я")] [InlineData("4", "4-я")] [InlineData("5", "5-я")] [InlineData("6", "6-я")] [InlineData("23", "23-я")] [InlineData("100", "100-я")] [InlineData("101", "101-я")] [InlineData("102", "102-я")] [InlineData("103", "103-я")] [InlineData("1001", "1001-я")] public void OrdinalizeStringFeminine(string number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Feminine), ordinalized); [Theory] [InlineData("0", "0-е")] [InlineData("1", "1-е")] [InlineData("2", "2-е")] [InlineData("3", "3-е")] [InlineData("4", "4-е")] [InlineData("5", "5-е")] [InlineData("6", "6-е")] [InlineData("23", "23-е")] [InlineData("100", "100-е")] [InlineData("101", "101-е")] [InlineData("102", "102-е")] [InlineData("103", "103-е")] [InlineData("1001", "1001-е")] public void OrdinalizeStringNeuter(string number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Neuter), ordinalized); [Theory] [InlineData(0, "0-й")] [InlineData(1, "1-й")] [InlineData(2, "2-й")] [InlineData(3, "3-й")] [InlineData(4, "4-й")] [InlineData(5, "5-й")] [InlineData(6, "6-й")] [InlineData(10, "10-й")] [InlineData(23, "23-й")] [InlineData(100, "100-й")] [InlineData(101, "101-й")] [InlineData(102, "102-й")] [InlineData(103, "103-й")] [InlineData(1001, "1001-й")] public void OrdinalizeNumber(int number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Masculine), ordinalized); [Theory] [InlineData(0, "0-я")] [InlineData(1, "1-я")] [InlineData(2, "2-я")] [InlineData(3, "3-я")] [InlineData(4, "4-я")] [InlineData(5, "5-я")] [InlineData(6, "6-я")] [InlineData(10, "10-я")] [InlineData(23, "23-я")] [InlineData(100, "100-я")] [InlineData(101, "101-я")] [InlineData(102, "102-я")] [InlineData(103, "103-я")] [InlineData(1001, "1001-я")] public void OrdinalizeNumberFeminine(int number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Feminine), ordinalized); [Theory] [InlineData(0, "0-е")] [InlineData(1, "1-е")] [InlineData(2, "2-е")] [InlineData(3, "3-е")] [InlineData(4, "4-е")] [InlineData(5, "5-е")] [InlineData(6, "6-е")] [InlineData(23, "23-е")] [InlineData(100, "100-е")] [InlineData(101, "101-е")] [InlineData(102, "102-е")] [InlineData(103, "103-е")] [InlineData(1001, "1001-е")] public void OrdinalizeNumberNeuter(int number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Neuter), ordinalized); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ru-RU/TimeSpanHumanizeTests.cs ================================================ namespace ruRU; [UseCulture("ru-RU")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Native speaker")] [InlineData(4, false, "4 дня")] [InlineData(23, false, "3 недели")] [InlineData(64, false, "2 месяца")] [InlineData(367, true, "один год")] [InlineData(750, true, "два года")] public void Age(int days, bool toWords, string expected) { var actual = TimeSpan.FromDays(days).ToAge(toWords: toWords); Assert.Equal(expected, actual); } [Theory] [Trait("Translation", "Native speaker")] [InlineData(366, "один год", true)] [InlineData(366, "1 год")] [InlineData(731, "2 года")] [InlineData(1096, "3 года")] [InlineData(4018, "11 лет")] public void Years(int days, string expected, bool toWords = false) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year, toWords: toWords)); [Theory] [Trait("Translation", "Native speaker")] [InlineData(31, "один месяц", true)] [InlineData(31, "1 месяц")] [InlineData(61, "2 месяца")] [InlineData(92, "3 месяца")] [InlineData(335, "11 месяцев")] public void Months(int days, string expected, bool toWords = false) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year, toWords: toWords)); [Theory] [InlineData(7, "одна неделя", true)] [InlineData(7, "1 неделя")] [InlineData(14, "2 недели")] [InlineData(21, "3 недели")] [InlineData(28, "4 недели")] [InlineData(35, "5 недель")] [InlineData(77, "11 недель")] public void Weeks(int days, string expected, bool toWords = false) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(toWords: toWords)); [Theory] [InlineData(1, "один день", true)] [InlineData(1, "1 день")] [InlineData(2, "2 дня")] [InlineData(3, "3 дня")] [InlineData(4, "4 дня")] [InlineData(5, "5 дней")] [InlineData(6, "6 дней")] public void Days(int days, string expected, bool toWords = false) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(toWords: toWords)); [Theory] [InlineData(1, "один час", true)] [InlineData(1, "1 час")] [InlineData(2, "2 часа")] [InlineData(3, "3 часа")] [InlineData(4, "4 часа")] [InlineData(5, "5 часов")] [InlineData(6, "6 часов")] [InlineData(10, "10 часов")] [InlineData(11, "11 часов")] [InlineData(19, "19 часов")] [InlineData(20, "20 часов")] [InlineData(21, "21 час")] [InlineData(22, "22 часа")] [InlineData(23, "23 часа")] public void Hours(int hours, string expected, bool toWords = false) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize(toWords: toWords)); [Theory] [InlineData(1, "одна минута", true)] [InlineData(1, "1 минута")] [InlineData(2, "2 минуты")] [InlineData(3, "3 минуты")] [InlineData(4, "4 минуты")] [InlineData(5, "5 минут")] [InlineData(6, "6 минут")] [InlineData(10, "10 минут")] [InlineData(11, "11 минут")] [InlineData(19, "19 минут")] [InlineData(20, "20 минут")] [InlineData(21, "21 минута")] [InlineData(21, "двадцать одна минута", true)] [InlineData(22, "22 минуты")] [InlineData(23, "23 минуты")] [InlineData(24, "24 минуты")] [InlineData(25, "25 минут")] [InlineData(40, "40 минут")] public void Minutes(int minutes, string expected, bool toWords = false) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize(toWords: toWords)); [Theory] [InlineData(1, "одна секунда", true)] [InlineData(1, "1 секунда")] [InlineData(2, "2 секунды")] [InlineData(3, "3 секунды")] [InlineData(4, "4 секунды")] [InlineData(5, "5 секунд")] [InlineData(6, "6 секунд")] [InlineData(10, "10 секунд")] [InlineData(11, "11 секунд")] [InlineData(19, "19 секунд")] [InlineData(20, "20 секунд")] [InlineData(21, "21 секунда")] [InlineData(21, "двадцать одна секунда", true)] [InlineData(22, "22 секунды")] [InlineData(23, "23 секунды")] [InlineData(24, "24 секунды")] [InlineData(25, "25 секунд")] [InlineData(40, "40 секунд")] public void Seconds(int seconds, string expected, bool toWords = false) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize(toWords: toWords)); [Theory] [InlineData(1, "одна миллисекунда", true)] [InlineData(1, "1 миллисекунда")] [InlineData(2, "2 миллисекунды")] [InlineData(3, "3 миллисекунды")] [InlineData(4, "4 миллисекунды")] [InlineData(5, "5 миллисекунд")] [InlineData(6, "6 миллисекунд")] [InlineData(10, "10 миллисекунд")] [InlineData(11, "11 миллисекунд")] [InlineData(19, "19 миллисекунд")] [InlineData(20, "20 миллисекунд")] [InlineData(21, "21 миллисекунда")] [InlineData(21, "двадцать одна миллисекунда", true)] [InlineData(22, "22 миллисекунды")] [InlineData(22, "двадцать две миллисекунды", true)] [InlineData(23, "23 миллисекунды")] [InlineData(24, "24 миллисекунды")] [InlineData(25, "25 миллисекунд")] [InlineData(40, "40 миллисекунд")] public void Milliseconds(int milliseconds, string expected, bool toWords = false) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize(toWords: toWords)); [Fact] public void NoTime() => Assert.Equal("0 миллисекунд", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => // This one doesn't make a lot of sense but ... w/e Assert.Equal("нет времени", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ru-RU/TimeUnitToSymbolTests.cs ================================================ namespace ruRU; [UseCulture("ru-RU")] public class TimeUnitToSymbolTests { [Theory] [Trait("Translation", "Native speaker")] [InlineData(TimeUnit.Millisecond, "мс.")] [InlineData(TimeUnit.Second, "сек.")] [InlineData(TimeUnit.Minute, "мин.")] [InlineData(TimeUnit.Hour, "ч.")] [InlineData(TimeUnit.Day, "д.")] [InlineData(TimeUnit.Week, "нед.")] [InlineData(TimeUnit.Month, "мес.")] [InlineData(TimeUnit.Year, "г.")] public void ToSymbol(TimeUnit unit, string expected) => Assert.Equal(expected, unit.ToSymbol()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/sk/DateHumanizeTests.cs ================================================ namespace sk; [UseCulture("sk-SK")] public class DateHumanizeTests { [Theory] [InlineData(1, "o sekundu")] [InlineData(2, "o 2 sekundy")] [InlineData(3, "o 3 sekundy")] [InlineData(4, "o 4 sekundy")] [InlineData(5, "o 5 sekúnd")] [InlineData(6, "o 6 sekúnd")] [InlineData(10, "o 10 sekúnd")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(1, "o minútu")] [InlineData(2, "o 2 minúty")] [InlineData(3, "o 3 minúty")] [InlineData(4, "o 4 minúty")] [InlineData(5, "o 5 minút")] [InlineData(6, "o 6 minút")] [InlineData(10, "o 10 minút")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(1, "o hodinu")] [InlineData(2, "o 2 hodiny")] [InlineData(3, "o 3 hodiny")] [InlineData(4, "o 4 hodiny")] [InlineData(5, "o 5 hodín")] [InlineData(6, "o 6 hodín")] [InlineData(10, "o 10 hodín")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(1, "zajtra")] [InlineData(2, "o 2 dni")] [InlineData(3, "o 3 dni")] [InlineData(4, "o 4 dni")] [InlineData(9, "o 9 dní")] [InlineData(10, "o 10 dní")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(1, "o mesiac")] [InlineData(2, "o 2 mesiace")] [InlineData(3, "o 3 mesiace")] [InlineData(4, "o 4 mesiace")] [InlineData(5, "o 5 mesiacov")] [InlineData(6, "o 6 mesiacov")] [InlineData(10, "o 10 mesiacov")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(1, "o rok")] [InlineData(2, "o 2 roky")] [InlineData(3, "o 3 roky")] [InlineData(4, "o 4 roky")] [InlineData(5, "o 5 rokov")] [InlineData(6, "o 6 rokov")] [InlineData(10, "o 10 rokov")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Theory] [InlineData(1, "pred sekundou")] [InlineData(2, "pred 2 sekundami")] [InlineData(3, "pred 3 sekundami")] [InlineData(4, "pred 4 sekundami")] [InlineData(5, "pred 5 sekundami")] [InlineData(6, "pred 6 sekundami")] [InlineData(10, "pred 10 sekundami")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "pred minútou")] [InlineData(2, "pred 2 minútami")] [InlineData(3, "pred 3 minútami")] [InlineData(4, "pred 4 minútami")] [InlineData(5, "pred 5 minútami")] [InlineData(6, "pred 6 minútami")] [InlineData(10, "pred 10 minútami")] [InlineData(60, "pred hodinou")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "pred hodinou")] [InlineData(2, "pred 2 hodinami")] [InlineData(3, "pred 3 hodinami")] [InlineData(4, "pred 4 hodinami")] [InlineData(5, "pred 5 hodinami")] [InlineData(6, "pred 6 hodinami")] [InlineData(10, "pred 10 hodinami")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "včera")] [InlineData(2, "pred 2 dňami")] [InlineData(3, "pred 3 dňami")] [InlineData(4, "pred 4 dňami")] [InlineData(9, "pred 9 dňami")] [InlineData(10, "pred 10 dňami")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "pred mesiacom")] [InlineData(2, "pred 2 mesiacmi")] [InlineData(3, "pred 3 mesiacmi")] [InlineData(4, "pred 4 mesiacmi")] [InlineData(5, "pred 5 mesiacmi")] [InlineData(6, "pred 6 mesiacmi")] [InlineData(10, "pred 10 mesiacmi")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "pred rokom")] [InlineData(2, "pred 2 rokmi")] [InlineData(3, "pred 3 rokmi")] [InlineData(4, "pred 4 rokmi")] [InlineData(5, "pred 5 rokmi")] [InlineData(6, "pred 6 rokmi")] [InlineData(10, "pred 10 rokmi")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); } ================================================ FILE: tests/Humanizer.Tests/Localisation/sk/TimeSpanHumanizeTests.cs ================================================ namespace sk; [UseCulture("sk-SK")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "1 rok")] [InlineData(731, "2 roky")] [InlineData(1096, "3 roky")] [InlineData(4018, "11 rokov")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "1 mesiac")] [InlineData(61, "2 mesiace")] [InlineData(92, "3 mesiace")] [InlineData(335, "11 mesiacov")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(1, "1 milisekunda")] [InlineData(2, "2 milisekundy")] [InlineData(3, "3 milisekundy")] [InlineData(4, "4 milisekundy")] [InlineData(5, "5 milisekúnd")] [InlineData(6, "6 milisekúnd")] [InlineData(10, "10 milisekúnd")] public void Milliseconds(int number, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(number).Humanize()); [Theory] [InlineData(1, "1 sekunda")] [InlineData(2, "2 sekundy")] [InlineData(3, "3 sekundy")] [InlineData(4, "4 sekundy")] [InlineData(5, "5 sekúnd")] [InlineData(6, "6 sekúnd")] [InlineData(10, "10 sekúnd")] public void Seconds(int number, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(number).Humanize()); [Theory] [InlineData(1, "1 minúta")] [InlineData(2, "2 minúty")] [InlineData(3, "3 minúty")] [InlineData(4, "4 minúty")] [InlineData(5, "5 minút")] [InlineData(6, "6 minút")] [InlineData(10, "10 minút")] public void Minutes(int number, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(number).Humanize()); [Theory] [InlineData(1, "1 hodina")] [InlineData(2, "2 hodiny")] [InlineData(3, "3 hodiny")] [InlineData(4, "4 hodiny")] [InlineData(5, "5 hodín")] [InlineData(6, "6 hodín")] [InlineData(10, "10 hodín")] public void Hours(int number, string expected) => Assert.Equal(expected, TimeSpan.FromHours(number).Humanize()); [Theory] [InlineData(1, "1 deň")] [InlineData(2, "2 dni")] [InlineData(3, "3 dni")] [InlineData(4, "4 dni")] [InlineData(5, "5 dní")] [InlineData(6, "6 dní")] public void Days(int number, string expected) => Assert.Equal(expected, TimeSpan.FromDays(number).Humanize()); [Theory] [InlineData(1, "1 týždeň")] [InlineData(2, "2 týždne")] [InlineData(3, "3 týždne")] [InlineData(4, "4 týždne")] [InlineData(5, "5 týždňov")] [InlineData(6, "6 týždňov")] public void Weeks(int number, string expected) => Assert.Equal(expected, TimeSpan.FromDays(number * 7).Humanize()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/sl/DateHumanizeTests.cs ================================================ namespace sl; [UseCulture("sl-SI")] public class DateHumanizeTests { [Theory] [InlineData(-10, "pred 10 leti")] [InlineData(-5, "pred 5 leti")] [InlineData(-4, "pred 4 leti")] [InlineData(-3, "pred 3 leti")] [InlineData(-2, "pred 2 letoma")] [InlineData(-1, "pred enim letom")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(5, "čez 5 let")] [InlineData(4, "čez 4 leta")] [InlineData(3, "čez 3 leta")] [InlineData(2, "čez 2 leti")] [InlineData(1, "čez eno leto")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Theory] [InlineData(-10, "pred 10 meseci")] [InlineData(-5, "pred 5 meseci")] [InlineData(-4, "pred 4 meseci")] [InlineData(-3, "pred 3 meseci")] [InlineData(-2, "pred 2 mesecema")] [InlineData(-1, "pred enim mesecem")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(5, "čez 5 mesecev")] [InlineData(4, "čez 4 mesece")] [InlineData(3, "čez 3 mesece")] [InlineData(2, "čez 2 meseca")] [InlineData(1, "čez en mesec")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(-10, "pred 10 dnevi")] [InlineData(-5, "pred 5 dnevi")] [InlineData(-4, "pred 4 dnevi")] [InlineData(-3, "pred 3 dnevi")] [InlineData(-2, "pred 2 dnevoma")] [InlineData(-1, "včeraj")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(5, "čez 5 dni")] [InlineData(4, "čez 4 dni")] [InlineData(3, "čez 3 dni")] [InlineData(2, "čez 2 dni")] [InlineData(1, "jutri")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(-10, "pred 10 urami")] [InlineData(-5, "pred 5 urami")] [InlineData(-4, "pred 4 urami")] [InlineData(-3, "pred 3 urami")] [InlineData(-2, "pred 2 urama")] [InlineData(-1, "pred eno uro")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(5, "čez 5 ur")] [InlineData(4, "čez 4 ure")] [InlineData(3, "čez 3 ure")] [InlineData(2, "čez 2 uri")] [InlineData(1, "čez eno uro")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(-10, "pred 10 minutami")] [InlineData(-5, "pred 5 minutami")] [InlineData(-4, "pred 4 minutami")] [InlineData(-3, "pred 3 minutami")] [InlineData(-2, "pred 2 minutama")] [InlineData(-1, "pred eno minuto")] [InlineData(60, "pred eno uro")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(5, "čez 5 minut")] [InlineData(4, "čez 4 minute")] [InlineData(3, "čez 3 minute")] [InlineData(2, "čez 2 minuti")] [InlineData(1, "čez eno minuto")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(-10, "pred 10 sekundami")] [InlineData(-5, "pred 5 sekundami")] [InlineData(-4, "pred 4 sekundami")] [InlineData(-3, "pred 3 sekundami")] [InlineData(-2, "pred 2 sekundama")] [InlineData(-1, "pred eno sekundo")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(10, "čez 10 sekund")] [InlineData(5, "čez 5 sekund")] [InlineData(4, "čez 4 sekunde")] [InlineData(3, "čez 3 sekunde")] [InlineData(2, "čez 2 sekundi")] [InlineData(1, "čez eno sekundo")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/sl/NumberToWordsTests.cs ================================================ namespace sl; [UseCulture("sl-SI")] public class NumberToWordsTests { [Theory] [InlineData(0, "nič")] [InlineData(1, "ena")] [InlineData(2, "dva")] [InlineData(3, "tri")] [InlineData(4, "štiri")] [InlineData(5, "pet")] [InlineData(6, "šest")] [InlineData(7, "sedem")] [InlineData(8, "osem")] [InlineData(9, "devet")] [InlineData(10, "deset")] [InlineData(20, "dvajset")] [InlineData(30, "trideset")] [InlineData(40, "štirideset")] [InlineData(50, "petdeset")] [InlineData(60, "šestdeset")] [InlineData(70, "sedemdeset")] [InlineData(80, "osemdeset")] [InlineData(90, "devetdeset")] [InlineData(100, "sto")] [InlineData(200, "dvesto")] [InlineData(1000, "tisoč")] [InlineData(10000, "deset tisoč")] [InlineData(100000, "sto tisoč")] [InlineData(1000000, "milijon")] [InlineData(10000000, "deset milijonov")] [InlineData(100000000, "sto milijonov")] [InlineData(1000000000, "milijarda")] [InlineData(2000000000, "dve milijardi")] [InlineData(122, "sto dvaindvajset")] [InlineData(3501, "tri tisoč petsto ena")] [InlineData(111, "sto enajst")] [InlineData(1112, "tisoč sto dvanajst")] [InlineData(11213, "enajst tisoč dvesto trinajst")] [InlineData(121314, "sto enaindvajset tisoč tristo štirinajst")] [InlineData(2132415, "dva milijona sto dvaintrideset tisoč štiristo petnajst")] [InlineData(12345516, "dvanajst milijonov tristo petinštirideset tisoč petsto šestnajst")] [InlineData(751633617, "sedemsto enainpetdeset milijonov šeststo triintrideset tisoč šeststo sedemnajst")] [InlineData(1111111118, "milijarda sto enajst milijonov sto enajst tisoč sto osemnajst")] [InlineData(-751633619, "minus sedemsto enainpetdeset milijonov šeststo triintrideset tisoč šeststo devetnajst")] public void ToWords(int number, string expected) => Assert.Equal(expected, number.ToWords()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/sl/TimeSpanHumanizeTests.cs ================================================ namespace sl; [UseCulture("sl-SI")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "1 leto")] [InlineData(731, "2 leti")] [InlineData(1096, "3 leta")] [InlineData(4018, "11 let")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "1 mesec")] [InlineData(61, "2 meseca")] [InlineData(92, "3 mesece")] [InlineData(335, "11 mesecev")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(7, "1 teden")] [InlineData(14, "2 tedna")] [InlineData(21, "3 tedne")] [InlineData(28, "4 tedne")] [InlineData(35, "5 tednov")] [InlineData(77, "11 tednov")] public void Weeks(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "1 dan")] [InlineData(2, "2 dneva")] [InlineData(3, "3 dni")] [InlineData(4, "4 dni")] [InlineData(5, "5 dni")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "1 ura")] [InlineData(2, "2 uri")] [InlineData(3, "3 ure")] [InlineData(4, "4 ure")] [InlineData(5, "5 ur")] public void Hours(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); [Theory] [InlineData(1, "1 minuta")] [InlineData(2, "2 minuti")] [InlineData(3, "3 minute")] [InlineData(4, "4 minute")] [InlineData(5, "5 minut")] public void Minutes(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); [Theory] [InlineData(1, "1 sekunda")] [InlineData(2, "2 sekundi")] [InlineData(3, "3 sekunde")] [InlineData(4, "4 sekunde")] [InlineData(5, "5 sekund")] public void Seconds(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); [Theory] [InlineData(1, "1 milisekunda")] [InlineData(2, "2 milisekundi")] [InlineData(3, "3 milisekunde")] [InlineData(4, "4 milisekunde")] [InlineData(5, "5 milisekund")] public void Milliseconds(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); [Fact] public void NoTime() => Assert.Equal("0 milisekund", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => Assert.Equal("nič časa", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/sr/DateHumanizeTests.cs ================================================ namespace sr; [UseCulture("sr")] public class DateHumanizeDefaultStrategyTests { [Theory] [InlineData(1, "пре секунд")] [InlineData(10, "пре 10 секунди")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "за секунд")] [InlineData(10, "за 10 секунди")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(1, "пре минут")] [InlineData(10, "пре 10 минута")] [InlineData(60, "пре сат времена")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "за минут")] [InlineData(10, "за 10 минута")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(1, "пре сат времена")] [InlineData(10, "пре 10 сати")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "за сат времена")] [InlineData(10, "за 10 сати")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(1, "јуче")] [InlineData(10, "пре 10 дана")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "сутра")] [InlineData(10, "за 10 дана")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(1, "пре месец дана")] [InlineData(10, "пре 10 месеци")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "за месец дана")] [InlineData(10, "за 10 месеци")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(1, "пре годину дана")] [InlineData(2, "пре 2 године")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "за годину дана")] [InlineData(2, "за 2 године")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Fact] public void Now() => DateHumanize.Verify("сада", 0, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/sr/NumberToWordsTest.cs ================================================ namespace sr; [UseCulture("sr")] public class NumberToWordsTest { [Theory] [InlineData(0, "нула")] [InlineData(1, "један")] [InlineData(2, "два")] [InlineData(3, "три")] [InlineData(4, "четири")] [InlineData(5, "пет")] [InlineData(6, "шест")] [InlineData(7, "седам")] [InlineData(8, "осам")] [InlineData(9, "девет")] [InlineData(10, "десет")] [InlineData(20, "двадесет")] [InlineData(30, "тридесет")] [InlineData(40, "четрдесет")] [InlineData(50, "петдесет")] [InlineData(60, "шестдесет")] [InlineData(70, "седамдесет")] [InlineData(80, "осамдесет")] [InlineData(90, "деветдесет")] [InlineData(100, "сто")] [InlineData(200, "двесто")] [InlineData(1000, "хиљаду")] [InlineData(10000, "десет хиљада")] [InlineData(100000, "сто хиљада")] [InlineData(1000000, "милион")] [InlineData(10000000, "десет милиона")] [InlineData(100000000, "сто милиона")] [InlineData(1000000000, "милијарда")] [InlineData(2000000000, "две милијарде")] [InlineData(15, "петнаест")] [InlineData(43, "четрдесет три")] [InlineData(81, "осамдесет један")] [InlineData(213, "двесто тринаест")] [InlineData(547, "петсто четрдесет седам")] public void ToWordsSr(int number, string expected) => Assert.Equal(expected, number.ToWords()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/sr/TimeSpanHumanizeTests.cs ================================================ namespace sr; [UseCulture("sr")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "1 година")] [InlineData(731, "2 године")] [InlineData(1096, "3 године")] [InlineData(4018, "11 година")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan .FromDays(days) .Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "1 месец")] [InlineData(61, "2 месеца")] [InlineData(92, "3 месеца")] [InlineData(335, "11 месеци")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan .FromDays(days) .Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(35, "5 недеља")] [InlineData(14, "2 недеље")] [InlineData(7, "1 недеља")] public void Weeks(int days, string expected) { var actual = TimeSpan .FromDays(days) .Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(6, "6 дана")] [InlineData(2, "2 дана")] [InlineData(1, "1 дан")] public void Days(int days, string expected) { var actual = TimeSpan .FromDays(days) .Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(5, "5 сати")] [InlineData(2, "2 сата")] [InlineData(1, "1 сат")] public void Hours(int hours, string expected) { var actual = TimeSpan .FromHours(hours) .Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 минута")] [InlineData(1, "1 минут")] public void Minutes(int minutes, string expected) { var actual = TimeSpan .FromMinutes(minutes) .Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 секунде")] [InlineData(1, "1 секунда")] public void Seconds(int seconds, string expected) { var actual = TimeSpan .FromSeconds(seconds) .Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 милисекунде")] [InlineData(1, "1 милисекунда")] public void Milliseconds(int ms, string expected) { var actual = TimeSpan .FromMilliseconds(ms) .Humanize(); Assert.Equal(expected, actual); } [Fact] public void NoTime() { var noTime = TimeSpan.Zero; var actual = noTime.Humanize(); Assert.Equal("0 милисекунди", actual); } [Fact] public void NoTimeToWords() { var noTime = TimeSpan.Zero; var actual = noTime.Humanize(toWords: true); Assert.Equal("без протеклог времена", actual); } } ================================================ FILE: tests/Humanizer.Tests/Localisation/sr-Latn/DateHumanizeTests.cs ================================================ namespace srLatn; [UseCulture("sr-Latn")] public class DateHumanizeDefaultStrategyTests { [Theory] [InlineData(1, "pre sekund")] [InlineData(10, "pre 10 sekundi")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "za sekund")] [InlineData(10, "za 10 sekundi")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(1, "pre minut")] [InlineData(10, "pre 10 minuta")] [InlineData(60, "pre sat vremena")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "za minut")] [InlineData(10, "za 10 minuta")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(1, "pre sat vremena")] [InlineData(10, "pre 10 sati")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "za sat vremena")] [InlineData(10, "za 10 sati")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(1, "juče")] [InlineData(10, "pre 10 dana")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "sutra")] [InlineData(10, "za 10 dana")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(1, "pre mesec dana")] [InlineData(10, "pre 10 meseci")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "za mesec dana")] [InlineData(10, "za 10 meseci")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(1, "pre godinu dana")] [InlineData(2, "pre 2 godine")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "za godinu dana")] [InlineData(2, "za 2 godine")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Fact] public void Now() => DateHumanize.Verify("sada", 0, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/sr-Latn/NumberToWordsTest.cs ================================================ namespace sr_Latn; [UseCulture("sr-Latn")] public class NumberToWordsTest { [Theory] [InlineData(0, "nula")] [InlineData(1, "jedan")] [InlineData(2, "dva")] [InlineData(3, "tri")] [InlineData(4, "četiri")] [InlineData(5, "pet")] [InlineData(6, "šest")] [InlineData(7, "sedam")] [InlineData(8, "osam")] [InlineData(9, "devet")] [InlineData(10, "deset")] [InlineData(20, "dvadeset")] [InlineData(30, "trideset")] [InlineData(40, "četrdeset")] [InlineData(50, "petdeset")] [InlineData(60, "šestdeset")] [InlineData(70, "sedamdeset")] [InlineData(80, "osamdeset")] [InlineData(90, "devetdeset")] [InlineData(100, "sto")] [InlineData(200, "dvesto")] [InlineData(1000, "hiljadu")] [InlineData(10000, "deset hiljada")] [InlineData(100000, "sto hiljada")] [InlineData(1000000, "milion")] [InlineData(10000000, "deset miliona")] [InlineData(100000000, "sto miliona")] [InlineData(1000000000, "milijarda")] [InlineData(2000000000, "dve milijarde")] [InlineData(15, "petnaest")] [InlineData(43, "četrdeset tri")] [InlineData(81, "osamdeset jedan")] [InlineData(213, "dvesto trinaest")] [InlineData(547, "petsto četrdeset sedam")] public void ToWords(int number, string expected) => Assert.Equal(expected, number.ToWords()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/sr-Latn/TimeSpanHumanizeTests.cs ================================================ namespace srLatn; [UseCulture("sr-Latn")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "1 godina")] [InlineData(731, "2 godine")] [InlineData(1096, "3 godine")] [InlineData(4018, "11 godina")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan .FromDays(days) .Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "1 mesec")] [InlineData(61, "2 meseca")] [InlineData(92, "3 meseca")] [InlineData(335, "11 meseci")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan .FromDays(days) .Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(35, "5 nedelja")] [InlineData(14, "2 nedelje")] [InlineData(7, "1 nedelja")] public void Weeks(int days, string expected) { var actual = TimeSpan .FromDays(days) .Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 dana")] [InlineData(1, "1 dan")] public void Days(int days, string expected) { var actual = TimeSpan .FromDays(days) .Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 sata")] [InlineData(1, "1 sat")] public void Hours(int hours, string expected) { var actual = TimeSpan .FromHours(hours) .Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 minuta")] [InlineData(1, "1 minut")] public void Minutes(int minutes, string expected) { var actual = TimeSpan .FromMinutes(minutes) .Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 sekunde")] [InlineData(1, "1 sekunda")] public void Seconds(int seconds, string expected) { var actual = TimeSpan .FromSeconds(seconds) .Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 milisekunde")] [InlineData(1, "1 milisekunda")] public void Milliseconds(int ms, string expected) { var actual = TimeSpan .FromMilliseconds(ms) .Humanize(); Assert.Equal(expected, actual); } [Fact] public void NoTime() { var noTime = TimeSpan.Zero; var actual = noTime.Humanize(); Assert.Equal("0 milisekundi", actual); } [Fact] public void NoTimeToWords() { var noTime = TimeSpan.Zero; var actual = noTime.Humanize(toWords: true); Assert.Equal("bez proteklog vremena", actual); } } ================================================ FILE: tests/Humanizer.Tests/Localisation/sv/CollectionFormatterTests.cs ================================================ namespace sv; [UseCulture("sv-SE")] public class CollectionFormatterTests { [Fact] public void MoreThanTwoItems() { var collection = new List([1, 2, 3]); var humanized = "1, 2 och 3"; Assert.Equal(humanized, collection.Humanize()); } [Fact] public void OneItem() { var collection = new List([1]); var humanized = "1"; Assert.Equal(humanized, collection.Humanize()); } [Fact] public void TwoItems() { var collection = new List([1, 2]); var humanized = "1 och 2"; Assert.Equal(humanized, collection.Humanize()); } } ================================================ FILE: tests/Humanizer.Tests/Localisation/sv/DateHumanizeTests.cs ================================================ namespace sv; [UseCulture("sv-SE")] public class DateHumanizeTests { [Theory] [InlineData(1, "om en sekund")] [InlineData(2, "om 2 sekunder")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(1, "om en minut")] [InlineData(2, "om 2 minuter")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(1, "om en timme")] [InlineData(2, "om 2 timmar")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(1, "i morgon")] [InlineData(2, "om 2 dagar")] public void DayFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(1, "om en månad")] [InlineData(2, "om 2 månader")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(1, "om ett år")] [InlineData(2, "om 2 år")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Theory] [InlineData(1, "en sekund sedan")] [InlineData(2, "för 2 sekunder sedan")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "en minut sedan")] [InlineData(2, "för 2 minuter sedan")] [InlineData(60, "en timme sedan")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "en timme sedan")] [InlineData(2, "för 2 timmar sedan")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "igår")] [InlineData(2, "för 2 dagar sedan")] public void DayAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "en månad sedan")] [InlineData(2, "för 2 månader sedan")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "ett år sedan")] [InlineData(2, "för 2 år sedan")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); } ================================================ FILE: tests/Humanizer.Tests/Localisation/sv/NumberToWordsTests.cs ================================================ namespace sv; [UseCulture("sv-SE")] public class NumberToWordsTests { [Theory] [InlineData(0, "noll")] [InlineData(1, "ett")] [InlineData(2, "två")] [InlineData(3, "tre")] [InlineData(4, "fyra")] [InlineData(5, "fem")] [InlineData(6, "sex")] [InlineData(7, "sju")] [InlineData(8, "åtta")] [InlineData(9, "nio")] [InlineData(10, "tio")] [InlineData(20, "tjugo")] [InlineData(30, "trettio")] [InlineData(40, "fyrtio")] [InlineData(50, "femtio")] [InlineData(60, "sextio")] [InlineData(70, "sjuttio")] [InlineData(80, "åttio")] [InlineData(90, "nittio")] [InlineData(100, "hundra")] [InlineData(200, "tvåhundra")] [InlineData(201, "tvåhundraett")] [InlineData(211, "tvåhundraelva")] [InlineData(221, "tvåhundratjugoett")] [InlineData(1000, "ett tusen")] [InlineData(10000, "tio tusen")] [InlineData(100000, "hundra tusen")] [InlineData(1000000, "en miljon")] [InlineData(10000000, "tio miljoner")] [InlineData(100000000, "hundra miljoner")] [InlineData(1000000000, "en miljard")] [InlineData(2000000000, "två miljarder")] [InlineData(122, "hundratjugotvå")] [InlineData(3501, "tre tusen femhundraett")] [InlineData(111, "hundraelva")] [InlineData(1112, "ett tusen hundratolv")] [InlineData(11213, "elva tusen tvåhundratretton")] public void ToWords(long number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(0, "nollte")] [InlineData(1, "första")] [InlineData(2, "andra")] [InlineData(3, "tredje")] [InlineData(4, "fjärde")] [InlineData(5, "femte")] [InlineData(6, "sjätte")] [InlineData(7, "sjunde")] [InlineData(8, "åttonde")] [InlineData(9, "nionde")] [InlineData(10, "tionde")] [InlineData(20, "tjugonde")] [InlineData(30, "trettionde")] [InlineData(40, "fyrtionde")] [InlineData(50, "femtionde")] [InlineData(60, "sextionde")] [InlineData(70, "sjuttionde")] [InlineData(80, "åttionde")] [InlineData(90, "nittionde")] [InlineData(100, "hundrade")] [InlineData(200, "tvåhundrade")] [InlineData(201, "tvåhundraförsta")] [InlineData(211, "tvåhundraelfte")] [InlineData(221, "tvåhundratjugoförsta")] [InlineData(1000, "ett tusende")] [InlineData(10000, "tio tusende")] [InlineData(100000, "hundra tusende")] [InlineData(1000000, "en miljonte")] public void ToOrdinalWords(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/sv/TimeSpanHumanizeTests.cs ================================================ namespace sv; [UseCulture("sv-SE")] public class TimeSpanHumanizeTests { [Theory] [InlineData(1, "1 millisekund")] [InlineData(2, "2 millisekunder")] public void Milliseconds(int number, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(number).Humanize()); [Theory] [InlineData(1, "1 sekund")] [InlineData(2, "2 sekunder")] public void Seconds(int number, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(number).Humanize()); [Theory] [InlineData(1, "1 minut")] [InlineData(2, "2 minuter")] public void Minutes(int number, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(number).Humanize()); [Theory] [InlineData(1, "1 timma")] [InlineData(2, "2 timmar")] public void Hours(int number, string expected) => Assert.Equal(expected, TimeSpan.FromHours(number).Humanize()); [Theory] [InlineData(1, "1 dag")] [InlineData(2, "2 dagar")] public void Days(int number, string expected) => Assert.Equal(expected, TimeSpan.FromDays(number).Humanize()); [Theory] [InlineData(1, "1 vecka")] [InlineData(2, "2 veckor")] public void Weeks(int number, string expected) => Assert.Equal(expected, TimeSpan.FromDays(number * 7).Humanize()); [Theory] [Trait("Translation", "Native speaker")] [InlineData(31, "en månad")] [InlineData(61, "2 månader")] [InlineData(92, "3 månader")] [InlineData(335, "11 månader")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Native speaker")] [InlineData(366, "ett år")] [InlineData(731, "2 år")] [InlineData(1096, "3 år")] [InlineData(4018, "11 år")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/ta/NumberToWordsTests.cs ================================================ namespace ta; [UseCulture("ta")] public class NumberToWordsTests { //http://tnschools.gov.in/media/textbooks/3rd_Maths_Science_and_Social_science_TM_Combine_pd_Full_Book.pdf page 12 [Theory] [InlineData(0, "சுழியம்")] [InlineData(1, "ஒன்று")] [InlineData(2, "இரண்டு")] [InlineData(3, "மூன்று")] [InlineData(4, "நான்கு")] [InlineData(5, "ஐந்து")] [InlineData(6, "ஆறு")] [InlineData(7, "ஏழு")] [InlineData(8, "எட்டு")] [InlineData(9, "ஒன்பது")] [InlineData(10, "பத்து")] [InlineData(11, "பதினொன்று")] [InlineData(12, "பனிரெண்டு")] [InlineData(13, "பதிமூன்று")] [InlineData(14, "பதினான்கு")] [InlineData(15, "பதினைந்து")] [InlineData(16, "பதினாறு")] [InlineData(17, "பதினேழு")] [InlineData(18, "பதினெட்டு")] [InlineData(19, "பத்தொன்பது")] [InlineData(20, "இருபது")] [InlineData(21, "இருபத்து ஒன்று")] [InlineData(30, "முப்பது")] [InlineData(31, "முப்பத்து ஒன்று")] [InlineData(40, "நாற்பது")] [InlineData(41, "நாற்பத்தி ஒன்று")] [InlineData(50, "ஐம்பது")] [InlineData(60, "அறுபது")] [InlineData(64, "அறுபத்து நான்கு")] [InlineData(70, "எழுபது")] [InlineData(80, "எண்பது")] [InlineData(89, "எண்பத்தி ஒன்பது")] [InlineData(90, "தொண்ணூறு")] [InlineData(95, "தொண்ணூற்றி ஐந்து")] [InlineData(100, "நூறு")] [InlineData(101, "நூற்று ஒன்று")] [InlineData(121, "நூற்று இருபத்து ஒன்று")] [InlineData(191, "நூற்று தொண்ணூற்றி ஒன்று")] [InlineData(200, "இருநூறு")] [InlineData(201, "இருநூற்று ஒன்று")] [InlineData(411, "நானூற்று பதினொன்று")] [InlineData(535, "ஐந்நூற்று முப்பத்து ஐந்து")] [InlineData(985, "தொள்ளாயிரத்து எண்பத்தி ஐந்து")] [InlineData(1000, "ஆயிரம்")] [InlineData(1535, "ஆயிரத்து ஐந்நூற்று முப்பத்து ஐந்து")] [InlineData(2000, "இரண்டாயிரம்")] [InlineData(3000, "மூன்றாயிரம்")] [InlineData(4000, "நான்காயிரம்")] [InlineData(5000, "ஐந்தாயிரம்")] [InlineData(6000, "ஆறாயிரம்")] [InlineData(7000, "ஏழாயிரம்")] [InlineData(8000, "எட்டாயிரம்")] [InlineData(8888, "எட்டாயிரத்து எண்ணூற்று எண்பத்தி எட்டு")] [InlineData(9000, "ஒன்பதாயிரம்")] [InlineData(9999, "ஒன்பதாயிரத்து தொள்ளாயிரத்து தொண்ணூற்றி ஒன்பது")] [InlineData(10000, "பத்தாயிரம்")] [InlineData(20000, "இருபதாயிரம்")] [InlineData(20005, "இருபதாயிரத்து ஐந்து")] [InlineData(20205, "இருபதாயிரத்து இருநூற்று ஐந்து")] [InlineData(25435, "இருபத்து ஐந்தாயிரத்து நானூற்று முப்பத்து ஐந்து")] [InlineData(90995, "தொண்ணூறாயிரத்து தொள்ளாயிரத்து தொண்ணூற்றி ஐந்து")] [InlineData(100000, "ஒரு இலட்சம்")] [InlineData(1000000, "பத்து இலட்சம்")] [InlineData(10000000, "ஒரு கோடி")] [InlineData(100000000, "பத்து கோடி")] [InlineData(1000000000, "நூறு கோடி")] [InlineData(2000000000, "இருநூறு கோடி")] [InlineData(122, "நூற்று இருபத்து இரண்டு")] [InlineData(3501, "மூன்றாயிரத்து ஐந்நூற்று ஒன்று")] [InlineData(111, "நூற்று பதினொன்று")] [InlineData(1112, "ஆயிரத்து நூற்று பனிரெண்டு")] [InlineData(11213, "பதினொன்றாயிரத்து இருநூற்று பதிமூன்று")] [InlineData(121314, "ஒரு இலட்சத்து இருபத்து ஓராயிரத்து முன்னூற்று பதினான்கு")] [InlineData(2132415, "இருபத்து ஒன்று இலட்சத்து முப்பத்து இரண்டாயிரத்து நானூற்று பதினைந்து")] [InlineData(12345516, "ஒரு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்தி ஐந்தாயிரத்து ஐந்நூற்று பதினாறு")] [InlineData(751633617, "எழுபத்தி ஐந்து கோடியே பதினாறு இலட்சத்து முப்பத்து மூன்றாயிரத்து அறுநூற்று பதினேழு")] [InlineData(1111111118, "நூற்று பதினொன்று கோடியே பதினொன்று இலட்சத்து பதினொன்றாயிரத்து நூற்று பதினெட்டு")] [InlineData(35484694489515, "முப்பத்து ஐந்து இலட்சத்து நாற்பத்தி எட்டாயிரத்து நானூற்று அறுபத்து ஒன்பது கோடியே நாற்பத்தி நான்கு இலட்சத்து எண்பத்தி ஒன்பதாயிரத்து ஐந்நூற்று பதினைந்து")] //[InlineData(8183162164626926, "எட்டு quadrillion கோடியே நாற்பத்தி ஆறு இலட்சத்து இருபத்து ஆறாயிரத்து தொள்ளாயிரத்து இருபத்து ஆறு")] //[InlineData(4564121926659524672, "நான்கு quintillion ஐந்நூற்று அறுபத்து நான்கு quadrillion கோடியே தொண்ணூற்றி ஐந்து இலட்சத்து இருபத்து நான்காயிரத்து அறுநூற்று எழுபத்தி இரண்டு")] [InlineData(-751633619, "கழித்தல் எழுபத்தி ஐந்து கோடியே பதினாறு இலட்சத்து முப்பத்து மூன்றாயிரத்து அறுநூற்று பத்தொன்பது")] public void ToWords(long number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(1, "ஒன்று")] [InlineData(3501, "மூன்றாயிரத்து ஐந்நூற்று ஒன்று")] public void ToWordsFeminine(long number, string expected) => Assert.Equal(expected, number.ToWords(GrammaticalGender.Feminine)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/th-TH/DateHumanizeTests.cs ================================================ namespace thTH; [UseCulture("th-TH")] public class DateHumanizeTests { [Theory] [InlineData(1, "หนึ่งวินาทีที่แล้ว")] [InlineData(10, "10 วินาทีที่แล้ว")] [InlineData(59, "59 วินาทีที่แล้ว")] [InlineData(60, "หนึ่งนาทีที่แล้ว")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); } ================================================ FILE: tests/Humanizer.Tests/Localisation/th-TH/NumberToWordsTests.cs ================================================ namespace thTH; [UseCulture("th-TH")] public class NumberToWordsTests { [InlineData(1, "หนึ่ง")] [InlineData(10, "สิบ")] [InlineData(11, "สิบเอ็ด")] [InlineData(20, "ยี่สิบ")] [InlineData(-122, "ลบหนึ่งร้อยยี่สิบสอง")] [InlineData(3501, "สามพันห้าร้อยหนึ่ง")] [InlineData(100, "หนึ่งร้อย")] [InlineData(1000, "หนึ่งพัน")] [InlineData(10000, "หนึ่งหมื่น")] [InlineData(-100000, "ลบหนึ่งแสน")] [InlineData(1000000, "หนึ่งล้าน")] [InlineData(10000000, "สิบล้าน")] [InlineData(100000000, "หนึ่งร้อยล้าน")] [InlineData(1000000000, "หนึ่งพันล้าน")] [InlineData(111, "หนึ่งร้อยสิบเอ็ด")] [InlineData(1111, "หนึ่งพันหนึ่งร้อยสิบเอ็ด")] [InlineData(-111111, "ลบหนึ่งแสนหนึ่งหมื่นหนึ่งพันหนึ่งร้อยสิบเอ็ด")] [InlineData(1111111, "หนึ่งล้านหนึ่งแสนหนึ่งหมื่นหนึ่งพันหนึ่งร้อยสิบเอ็ด")] [InlineData(11111111, "สิบเอ็ดล้านหนึ่งแสนหนึ่งหมื่นหนึ่งพันหนึ่งร้อยสิบเอ็ด")] [InlineData(111111111, "หนึ่งร้อยสิบเอ็ดล้านหนึ่งแสนหนึ่งหมื่นหนึ่งพันหนึ่งร้อยสิบเอ็ด")] [InlineData(1111111111, "หนึ่งพันหนึ่งร้อยสิบเอ็ดล้านหนึ่งแสนหนึ่งหมื่นหนึ่งพันหนึ่งร้อยสิบเอ็ด")] [Theory] public void ToWords(int number, string expected) => Assert.Equal(expected, number.ToWords()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/tr/DateHumanizeTests.cs ================================================ namespace tr; [UseCulture("tr")] public class DateHumanizeTests { [Theory] [InlineData(1, "bir saniye önce")] [InlineData(10, "10 saniye önce")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "bir saniye sonra")] [InlineData(10, "10 saniye sonra")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(1, "bir dakika önce")] [InlineData(10, "10 dakika önce")] [InlineData(60, "bir saat önce")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "bir dakika sonra")] [InlineData(10, "10 dakika sonra")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(1, "bir saat önce")] [InlineData(10, "10 saat önce")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "bir saat sonra")] [InlineData(10, "10 saat sonra")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(1, "dün")] [InlineData(10, "10 gün önce")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "yarın")] [InlineData(10, "10 gün sonra")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(1, "bir ay önce")] [InlineData(10, "10 ay önce")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "bir ay sonra")] [InlineData(10, "10 ay sonra")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(1, "bir yıl önce")] [InlineData(2, "2 yıl önce")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "bir yıl sonra")] [InlineData(2, "2 yıl sonra")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Fact] public void Now() => DateHumanize.Verify("şimdi", 0, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/tr/NumberToWordsTests.cs ================================================ namespace tr; [UseCulture("tr")] public class NumberToWordsTests { [Theory] [InlineData("sıfır", 0)] [InlineData("bir", 1)] [InlineData("iki", 2)] [InlineData("on", 10)] [InlineData("yüz on iki", 112)] [InlineData("bin dört yüz kırk", 1440)] [InlineData("yirmi iki", 22)] [InlineData("on bir", 11)] [InlineData("üç bin beş yüz bir", 3501)] [InlineData("bir milyon bir", 1000001)] [InlineData("eksi bir milyon üç yüz kırk altı bin yedi yüz on bir", -1346711)] [InlineData("dokuz kentilyon iki yüz yirmi üç katrilyon üç yüz yetmiş iki trilyon otuz altı milyar sekiz yüz elli dört milyon yedi yüz yetmiş beş bin sekiz yüz yedi", 9223372036854775807)] public void ToWords(string expected, long number) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(0, "sıfırıncı")] [InlineData(1, "birinci")] [InlineData(2, "ikinci")] [InlineData(3, "üçüncü")] [InlineData(4, "dördüncü")] [InlineData(5, "beşinci")] [InlineData(6, "altıncı")] [InlineData(7, "yedinci")] [InlineData(8, "sekizinci")] [InlineData(9, "dokuzuncu")] [InlineData(10, "onuncu")] [InlineData(11, "on birinci")] [InlineData(12, "on ikinci")] [InlineData(13, "on üçüncü")] [InlineData(14, "on dördüncü")] [InlineData(15, "on beşinci")] [InlineData(16, "on altıncı")] [InlineData(17, "on yedinci")] [InlineData(18, "on sekizinci")] [InlineData(19, "on dokuzuncu")] [InlineData(20, "yirminci")] [InlineData(21, "yirmi birinci")] [InlineData(30, "otuzuncu")] [InlineData(40, "kırkıncı")] [InlineData(50, "ellinci")] [InlineData(60, "altmışıncı")] [InlineData(70, "yetmişinci")] [InlineData(80, "sekseninci")] [InlineData(90, "doksanıncı")] [InlineData(100, "yüzüncü")] [InlineData(120, "yüz yirminci")] [InlineData(121, "yüz yirmi birinci")] [InlineData(200, "iki yüzüncü")] [InlineData(221, "iki yüz yirmi birinci")] [InlineData(300, "üç yüzüncü")] [InlineData(321, "üç yüz yirmi birinci")] [InlineData(1000, "bininci")] [InlineData(1001, "bin birinci")] [InlineData(10000, "on bininci")] [InlineData(100000, "yüz bininci")] [InlineData(1000000, "bir milyonuncu")] [InlineData(1022135, "bir milyon yirmi iki bin yüz otuz beşinci")] public void ToOrdinalWords(int number, string words) => Assert.Equal(words, number.ToOrdinalWords()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/tr/OrdinalizeTests.cs ================================================ namespace tr; [UseCulture("tr")] public class OrdinalizeTests { [Theory] [InlineData("0", "0.")] [InlineData("1", "1.")] [InlineData("2", "2.")] [InlineData("3", "3.")] [InlineData("4", "4.")] [InlineData("5", "5.")] [InlineData("6", "6.")] [InlineData("23", "23.")] [InlineData("100", "100.")] [InlineData("101", "101.")] [InlineData("102", "102.")] [InlineData("103", "103.")] [InlineData("1001", "1001.")] public void OrdinalizeString(string number, string ordinalized) => Assert.Equal(number.Ordinalize(), ordinalized); [Theory] [InlineData(0, "0.")] [InlineData(1, "1.")] [InlineData(2, "2.")] [InlineData(3, "3.")] [InlineData(4, "4.")] [InlineData(5, "5.")] [InlineData(6, "6.")] [InlineData(10, "10.")] [InlineData(23, "23.")] [InlineData(100, "100.")] [InlineData(101, "101.")] [InlineData(102, "102.")] [InlineData(103, "103.")] [InlineData(1001, "1001.")] public void OrdinalizeNumber(int number, string ordinalized) => Assert.Equal(number.Ordinalize(), ordinalized); } ================================================ FILE: tests/Humanizer.Tests/Localisation/tr/TimeSpanHumanizeTests.cs ================================================ namespace tr; [UseCulture("tr")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "1 yıl")] [InlineData(731, "2 yıl")] [InlineData(1096, "3 yıl")] [InlineData(4018, "11 yıl")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "1 ay")] [InlineData(61, "2 ay")] [InlineData(92, "3 ay")] [InlineData(335, "11 ay")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(14, "2 hafta")] [InlineData(7, "1 hafta")] public void Weeks(int days, string expected) { var actual = TimeSpan.FromDays(days).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(6, "6 gün")] [InlineData(2, "2 gün")] public void Days(int days, string expected) { var actual = TimeSpan.FromDays(days).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 saat")] [InlineData(1, "1 saat")] public void Hours(int hours, string expected) { var actual = TimeSpan.FromHours(hours).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 dakika")] [InlineData(1, "1 dakika")] public void Minutes(int minutes, string expected) { var actual = TimeSpan.FromMinutes(minutes).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 saniye")] [InlineData(1, "1 saniye")] public void Seconds(int seconds, string expected) { var actual = TimeSpan.FromSeconds(seconds).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 milisaniye")] [InlineData(1, "1 milisaniye")] public void Milliseconds(int ms, string expected) { var actual = TimeSpan.FromMilliseconds(ms).Humanize(); Assert.Equal(expected, actual); } [Fact] public void NoTime() { var noTime = TimeSpan.Zero; var actual = noTime.Humanize(); Assert.Equal("0 milisaniye", actual); } [Fact] public void NoTimeToWords() { var noTime = TimeSpan.Zero; var actual = noTime.Humanize(toWords: true); Assert.Equal("zaman farkı yok", actual); } } ================================================ FILE: tests/Humanizer.Tests/Localisation/uk-UA/DateHumanizeTests.cs ================================================ namespace ukUA; [UseCulture("uk-UA")] public class DateHumanizeTests { [Theory] [InlineData(1, "секунду тому")] [InlineData(2, "2 секунди тому")] [InlineData(3, "3 секунди тому")] [InlineData(4, "4 секунди тому")] [InlineData(5, "5 секунд тому")] [InlineData(6, "6 секунд тому")] [InlineData(10, "10 секунд тому")] [InlineData(11, "11 секунд тому")] [InlineData(19, "19 секунд тому")] [InlineData(20, "20 секунд тому")] [InlineData(21, "21 секунду тому")] [InlineData(22, "22 секунди тому")] [InlineData(23, "23 секунди тому")] [InlineData(24, "24 секунди тому")] [InlineData(25, "25 секунд тому")] [InlineData(40, "40 секунд тому")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "через секунду")] [InlineData(2, "через 2 секунди")] [InlineData(3, "через 3 секунди")] [InlineData(4, "через 4 секунди")] [InlineData(5, "через 5 секунд")] [InlineData(6, "через 6 секунд")] [InlineData(10, "через 10 секунд")] [InlineData(11, "через 11 секунд")] [InlineData(19, "через 19 секунд")] [InlineData(20, "через 20 секунд")] [InlineData(21, "через 21 секунду")] [InlineData(22, "через 22 секунди")] [InlineData(23, "через 23 секунди")] [InlineData(24, "через 24 секунди")] [InlineData(25, "через 25 секунд")] [InlineData(40, "через 40 секунд")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(1, "хвилину тому")] [InlineData(2, "2 хвилини тому")] [InlineData(3, "3 хвилини тому")] [InlineData(4, "4 хвилини тому")] [InlineData(5, "5 хвилин тому")] [InlineData(6, "6 хвилин тому")] [InlineData(10, "10 хвилин тому")] [InlineData(11, "11 хвилин тому")] [InlineData(19, "19 хвилин тому")] [InlineData(20, "20 хвилин тому")] [InlineData(21, "21 хвилину тому")] [InlineData(22, "22 хвилини тому")] [InlineData(23, "23 хвилини тому")] [InlineData(24, "24 хвилини тому")] [InlineData(25, "25 хвилин тому")] [InlineData(40, "40 хвилин тому")] [InlineData(60, "годину тому")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "через хвилину")] [InlineData(2, "через 2 хвилини")] [InlineData(3, "через 3 хвилини")] [InlineData(4, "через 4 хвилини")] [InlineData(5, "через 5 хвилин")] [InlineData(6, "через 6 хвилин")] [InlineData(10, "через 10 хвилин")] [InlineData(11, "через 11 хвилин")] [InlineData(19, "через 19 хвилин")] [InlineData(20, "через 20 хвилин")] [InlineData(21, "через 21 хвилину")] [InlineData(22, "через 22 хвилини")] [InlineData(23, "через 23 хвилини")] [InlineData(24, "через 24 хвилини")] [InlineData(25, "через 25 хвилин")] [InlineData(40, "через 40 хвилин")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(1, "годину тому")] [InlineData(2, "2 години тому")] [InlineData(3, "3 години тому")] [InlineData(4, "4 години тому")] [InlineData(5, "5 годин тому")] [InlineData(6, "6 годин тому")] [InlineData(10, "10 годин тому")] [InlineData(11, "11 годин тому")] [InlineData(19, "19 годин тому")] [InlineData(20, "20 годин тому")] [InlineData(21, "21 годину тому")] [InlineData(22, "22 години тому")] [InlineData(23, "23 години тому")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "через годину")] [InlineData(2, "через 2 години")] [InlineData(3, "через 3 години")] [InlineData(4, "через 4 години")] [InlineData(5, "через 5 годин")] [InlineData(6, "через 6 годин")] [InlineData(10, "через 10 годин")] [InlineData(11, "через 11 годин")] [InlineData(19, "через 19 годин")] [InlineData(20, "через 20 годин")] [InlineData(21, "через 21 годину")] [InlineData(22, "через 22 години")] [InlineData(23, "через 23 години")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(1, "вчора")] [InlineData(2, "2 дні тому")] [InlineData(3, "3 дні тому")] [InlineData(4, "4 дні тому")] [InlineData(5, "5 днів тому")] [InlineData(6, "6 днів тому")] [InlineData(10, "10 днів тому")] [InlineData(11, "11 днів тому")] [InlineData(19, "19 днів тому")] [InlineData(20, "20 днів тому")] [InlineData(21, "21 день тому")] [InlineData(22, "22 дні тому")] [InlineData(23, "23 дні тому")] [InlineData(24, "24 дні тому")] [InlineData(25, "25 днів тому")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "завтра")] [InlineData(2, "через 2 дні")] [InlineData(3, "через 3 дні")] [InlineData(4, "через 4 дні")] [InlineData(5, "через 5 днів")] [InlineData(6, "через 6 днів")] [InlineData(10, "через 10 днів")] [InlineData(11, "через 11 днів")] [InlineData(19, "через 19 днів")] [InlineData(20, "через 20 днів")] [InlineData(21, "через 21 день")] [InlineData(22, "через 22 дні")] [InlineData(23, "через 23 дні")] [InlineData(24, "через 24 дні")] [InlineData(25, "через 25 днів")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(1, "місяць тому")] [InlineData(2, "2 місяці тому")] [InlineData(3, "3 місяці тому")] [InlineData(4, "4 місяці тому")] [InlineData(5, "5 місяців тому")] [InlineData(6, "6 місяців тому")] [InlineData(10, "10 місяців тому")] [InlineData(11, "11 місяців тому")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "через місяць")] [InlineData(2, "через 2 місяці")] [InlineData(3, "через 3 місяці")] [InlineData(4, "через 4 місяці")] [InlineData(5, "через 5 місяців")] [InlineData(6, "через 6 місяців")] [InlineData(10, "через 10 місяців")] [InlineData(11, "через 11 місяців")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(1, "рік тому")] [InlineData(2, "2 роки тому")] [InlineData(3, "3 роки тому")] [InlineData(4, "4 роки тому")] [InlineData(5, "5 років тому")] [InlineData(6, "6 років тому")] [InlineData(10, "10 років тому")] [InlineData(11, "11 років тому")] [InlineData(19, "19 років тому")] [InlineData(21, "21 рік тому")] [InlineData(111, "111 років тому")] [InlineData(121, "121 рік тому")] [InlineData(222, "222 роки тому")] [InlineData(325, "325 років тому")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "через рік")] [InlineData(2, "через 2 роки")] [InlineData(3, "через 3 роки")] [InlineData(4, "через 4 роки")] [InlineData(5, "через 5 років")] [InlineData(6, "через 6 років")] [InlineData(10, "через 10 років")] [InlineData(11, "через 11 років")] [InlineData(19, "через 19 років")] [InlineData(20, "через 20 років")] [InlineData(21, "через 21 рік")] [InlineData(111, "через 111 років")] [InlineData(121, "через 121 рік")] [InlineData(222, "через 222 роки")] [InlineData(325, "через 325 років")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Fact] public void Now() => DateHumanize.Verify("зараз", 0, TimeUnit.Day, Tense.Past); } ================================================ FILE: tests/Humanizer.Tests/Localisation/uk-UA/NumberToWordsTests.cs ================================================ namespace ukUA; [UseCulture("uk-UA")] public class NumberToWordsTests { [Theory] [InlineData(-123, "мінус сто двадцять три")] [InlineData(0, "нуль")] [InlineData(1, "один")] [InlineData(10, "десять")] [InlineData(11, "одинадцять")] [InlineData(12, "дванадцять")] [InlineData(13, "тринадцять")] [InlineData(14, "чотирнадцять")] [InlineData(15, "п'ятнадцять")] [InlineData(16, "шістнадцять")] [InlineData(17, "сімнадцять")] [InlineData(18, "вісімнадцять")] [InlineData(19, "дев'ятнадцять")] [InlineData(20, "двадцять")] [InlineData(30, "тридцять")] [InlineData(40, "сорок")] [InlineData(50, "п'ятдесят")] [InlineData(60, "шістдесят")] [InlineData(70, "сімдесят")] [InlineData(80, "вісімдесят")] [InlineData(90, "дев'яносто")] [InlineData(100, "сто")] [InlineData(200, "двісті")] [InlineData(300, "триста")] [InlineData(400, "чотириста")] [InlineData(500, "п'ятсот")] [InlineData(600, "шістсот")] [InlineData(700, "сімсот")] [InlineData(800, "вісімсот")] [InlineData(900, "дев'ятсот")] [InlineData(1000, "одна тисяча")] [InlineData(2000, "дві тисячі")] [InlineData(3000, "три тисячі")] [InlineData(4000, "чотири тисячі")] [InlineData(5000, "п'ять тисяч")] [InlineData(10000, "десять тисяч")] [InlineData(100000, "сто тисяч")] [InlineData(1000000, "один мільйон")] [InlineData(2000000, "два мільйона")] [InlineData(10000000, "десять мільйонів")] [InlineData(100000000, "сто мільйонів")] [InlineData(1000000000, "один мільярд")] [InlineData(2000000000, "два мільярда")] [InlineData(122, "сто двадцять два")] [InlineData(3501, "три тисячі п'ятсот один")] [InlineData(111, "сто одинадцять")] [InlineData(1112, "одна тисяча сто дванадцять")] [InlineData(11213, "одинадцять тисяч двісті тринадцять")] [InlineData(121314, "сто двадцять одна тисяча триста чотирнадцять")] [InlineData(2132415, "два мільйона сто тридцять дві тисячі чотириста п'ятнадцять")] [InlineData(12345516, "дванадцять мільйонів триста сорок п'ять тисяч п'ятсот шістнадцять")] [InlineData(751633617, "сімсот п'ятдесят один мільйон шістсот тридцять три тисячі шістсот сімнадцять")] [InlineData(1111111118, "один мільярд сто одинадцять мільйонів сто одинадцять тисяч сто вісімнадцять")] [InlineData(-751633617, "мінус сімсот п'ятдесят один мільйон шістсот тридцять три тисячі шістсот сімнадцять")] [InlineData(1_000_000_000_000, "один трильйон")] [InlineData(3_000_000_000_000, "три трильйона")] [InlineData(5_000_000_000_000, "п'ять трильйонів")] [InlineData(999_000_000_000_000, "дев'ятсот дев'яносто дев'ять трильйонів")] [InlineData( long.MaxValue, "дев'ять квінтильйонів " + "двісті двадцять три квадрильйона " + "триста сімдесят два трильйона " + "тридцять шість мільярдів " + "вісімсот п'ятдесят чотири мільйона " + "сімсот сімдесят п'ять тисяч " + "вісімсот сім")] [InlineData( long.MinValue, "мінус дев'ять квінтильйонів " + "двісті двадцять три квадрильйона " + "триста сімдесят два трильйона " + "тридцять шість мільярдів " + "вісімсот п'ятдесят чотири мільйона " + "сімсот сімдесят п'ять тисяч " + "вісімсот вісім")] public void ToWords(long number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(122, "сто двадцять дві", GrammaticalGender.Feminine)] [InlineData(3501, "три тисячі п'ятсот одна", GrammaticalGender.Feminine)] [InlineData(3501, "три тисячі п'ятсот одне", GrammaticalGender.Neuter)] public void ToWordsWithGender(int number, string expected, GrammaticalGender gender) => Assert.Equal(expected, number.ToWords(gender)); [Theory] [InlineData(0, "нульовий")] [InlineData(1, "перший")] [InlineData(2, "другий")] [InlineData(3, "третій")] [InlineData(4, "четвертий")] [InlineData(10, "десятий")] [InlineData(11, "одинадцятий")] [InlineData(12, "дванадцятий")] [InlineData(13, "тринадцятий")] [InlineData(14, "чотирнадцятий")] [InlineData(15, "п'ятнадцятий")] [InlineData(16, "шістнадцятий")] [InlineData(17, "сімнадцятий")] [InlineData(18, "вісімнадцятий")] [InlineData(19, "дев'ятнадцятий")] [InlineData(20, "двадцятий")] [InlineData(30, "тридцятий")] [InlineData(40, "сороковий")] [InlineData(50, "п'ятдесятий")] [InlineData(60, "шістдесятий")] [InlineData(70, "сімдесятий")] [InlineData(80, "вісімдесятий")] [InlineData(90, "дев'яностий")] [InlineData(100, "сотий")] [InlineData(101, "сто перший")] [InlineData(140, "сто сороковий")] [InlineData(200, "двохсотий")] [InlineData(300, "трьохсотий")] [InlineData(400, "чотирьохсотий")] [InlineData(500, "п'ятисотий")] [InlineData(600, "шестисотий")] [InlineData(700, "семисотий")] [InlineData(800, "восьмисотий")] [InlineData(900, "дев'ятисотий")] [InlineData(1000, "тисячний")] [InlineData(1001, "одна тисяча перший")] [InlineData(1040, "одна тисяча сороковий")] [InlineData(2000, "двохтисячний")] [InlineData(3000, "трьохтисячний")] [InlineData(4000, "чотирьохтисячний")] [InlineData(5000, "п'ятитисячний")] [InlineData(10000, "десятитисячний")] [InlineData(21000, "двадцятиоднотисячний")] [InlineData(100000, "стотисячний")] [InlineData(101000, "стооднотисячний")] [InlineData(121000, "стодвадцятиоднотисячний")] [InlineData(200000, "двохсоттисячний")] [InlineData(1000000, "мільйонний")] [InlineData(2000000, "двохмільйонний")] [InlineData(10000000, "десятимільйонний")] [InlineData(21000000, "двадцятиодномільйонний")] [InlineData(100000000, "стомільйонний")] [InlineData(230000000, "двохсоттридцятимільйонний")] [InlineData(1000000000, "мільярдний")] [InlineData(2000000000, "двохмільярдний")] [InlineData(122, "сто двадцять другий")] [InlineData(3501, "три тисячі п'ятсот перший")] [InlineData(111, "сто одинадцятий")] [InlineData(1112, "одна тисяча сто дванадцятий")] [InlineData(11213, "одинадцять тисяч двісті тринадцятий")] [InlineData(121314, "сто двадцять одна тисяча триста чотирнадцятий")] [InlineData(2132415, "два мільйона сто тридцять дві тисячі чотириста п'ятнадцятий")] [InlineData(12345516, "дванадцять мільйонів триста сорок п'ять тисяч п'ятсот шістнадцятий")] [InlineData(751633617, "сімсот п'ятдесят один мільйон шістсот тридцять три тисячі шістсот сімнадцятий")] [InlineData(1111111118, "один мільярд сто одинадцять мільйонів сто одинадцять тисяч сто вісімнадцятий")] [InlineData(1111111000, "один мільярд сто одинадцять мільйонів стоодинадцятитисячний")] [InlineData(1234567000, "один мільярд двісті тридцять чотири мільйона п'ятисотшістдесятисемитисячний")] [InlineData(-751633617, "мінус сімсот п'ятдесят один мільйон шістсот тридцять три тисячі шістсот сімнадцятий")] public void ToOrdinalWords(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords()); [Theory] [InlineData(0, "нульова")] [InlineData(1, "перша")] [InlineData(2, "друга")] [InlineData(3, "третя")] [InlineData(4, "четверта")] [InlineData(10, "десята")] [InlineData(11, "одинадцята")] [InlineData(12, "дванадцята")] [InlineData(13, "тринадцята")] [InlineData(14, "чотирнадцята")] [InlineData(15, "п'ятнадцята")] [InlineData(16, "шістнадцята")] [InlineData(17, "сімнадцята")] [InlineData(18, "вісімнадцята")] [InlineData(19, "дев'ятнадцята")] [InlineData(20, "двадцята")] [InlineData(30, "тридцята")] [InlineData(40, "сорокова")] [InlineData(50, "п'ятдесята")] [InlineData(60, "шістдесята")] [InlineData(70, "сімдесята")] [InlineData(80, "вісімдесята")] [InlineData(90, "дев'яноста")] [InlineData(100, "сота")] [InlineData(200, "двохсота")] [InlineData(300, "трьохсота")] [InlineData(400, "чотирьохсота")] [InlineData(500, "п'ятисота")] [InlineData(600, "шестисота")] [InlineData(700, "семисота")] [InlineData(800, "восьмисота")] [InlineData(900, "дев'ятисота")] [InlineData(1000, "тисячна")] [InlineData(2000, "двохтисячна")] [InlineData(3000, "трьохтисячна")] [InlineData(4000, "чотирьохтисячна")] [InlineData(5000, "п'ятитисячна")] [InlineData(10000, "десятитисячна")] [InlineData(90000, "дев'яностотисячна")] [InlineData(100000, "стотисячна")] [InlineData(990000, "дев'ятисотдев'яностотисячна")] [InlineData(990001, "дев'ятсот дев'яносто тисяч перша")] [InlineData(1000000, "мільйонна")] [InlineData(2000000, "двохмільйонна")] [InlineData(10000000, "десятимільйонна")] [InlineData(100000000, "стомільйонна")] [InlineData(1000000000, "мільярдна")] [InlineData(2000000000, "двохмільярдна")] [InlineData(122, "сто двадцять друга")] [InlineData(3501, "три тисячі п'ятсот перша")] [InlineData(111, "сто одинадцята")] [InlineData(1112, "одна тисяча сто дванадцята")] [InlineData(11000, "одинадцятитисячна")] [InlineData(11001, "одинадцять тисяч перша")] [InlineData(11213, "одинадцять тисяч двісті тринадцята")] [InlineData(15000, "п'ятнадцятитисячна")] [InlineData(20000, "двадцятитисячна")] [InlineData(121314, "сто двадцять одна тисяча триста чотирнадцята")] [InlineData(2132415, "два мільйона сто тридцять дві тисячі чотириста п'ятнадцята")] [InlineData(12345516, "дванадцять мільйонів триста сорок п'ять тисяч п'ятсот шістнадцята")] [InlineData(751633617, "сімсот п'ятдесят один мільйон шістсот тридцять три тисячі шістсот сімнадцята")] [InlineData(1111111118, "один мільярд сто одинадцять мільйонів сто одинадцять тисяч сто вісімнадцята")] [InlineData(-751633617, "мінус сімсот п'ятдесят один мільйон шістсот тридцять три тисячі шістсот сімнадцята")] public void ToOrdinalWordsFeminine(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Feminine)); [Theory] [InlineData(3, "третє")] [InlineData(111, "сто одинадцяте")] [InlineData(1112, "одна тисяча сто дванадцяте")] [InlineData(11213, "одинадцять тисяч двісті тринадцяте")] [InlineData(121314, "сто двадцять одна тисяча триста чотирнадцяте")] [InlineData(2132415, "два мільйона сто тридцять дві тисячі чотириста п'ятнадцяте")] [InlineData(12345516, "дванадцять мільйонів триста сорок п'ять тисяч п'ятсот шістнадцяте")] [InlineData(751633617, "сімсот п'ятдесят один мільйон шістсот тридцять три тисячі шістсот сімнадцяте")] [InlineData(1111111118, "один мільярд сто одинадцять мільйонів сто одинадцять тисяч сто вісімнадцяте")] [InlineData(-751633617, "мінус сімсот п'ятдесят один мільйон шістсот тридцять три тисячі шістсот сімнадцяте")] public void ToOrdinalWordsNeuter(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords(GrammaticalGender.Neuter)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/uk-UA/OrdinalizeTests.cs ================================================ namespace ukUA; [UseCulture("uk-UA")] public class OrdinalizeTests { [Theory] [InlineData("0", "0-й")] [InlineData("1", "1-й")] [InlineData("2", "2-й")] [InlineData("3", "3-й")] [InlineData("4", "4-й")] [InlineData("5", "5-й")] [InlineData("6", "6-й")] [InlineData("23", "23-й")] [InlineData("100", "100-й")] [InlineData("101", "101-й")] [InlineData("102", "102-й")] [InlineData("103", "103-й")] [InlineData("1001", "1001-й")] public void OrdinalizeString(string number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Masculine), ordinalized); [Theory] [InlineData("0", "0-а")] [InlineData("1", "1-а")] [InlineData("2", "2-а")] [InlineData("3", "3-я")] [InlineData("4", "4-а")] [InlineData("5", "5-а")] [InlineData("6", "6-а")] [InlineData("23", "23-я")] [InlineData("100", "100-а")] [InlineData("101", "101-а")] [InlineData("102", "102-а")] [InlineData("103", "103-я")] [InlineData("1001", "1001-а")] public void OrdinalizeStringFeminine(string number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Feminine), ordinalized); [Theory] [InlineData("0", "0-е")] [InlineData("1", "1-е")] [InlineData("2", "2-е")] [InlineData("3", "3-є")] [InlineData("4", "4-е")] [InlineData("5", "5-е")] [InlineData("6", "6-е")] [InlineData("23", "23-є")] [InlineData("100", "100-е")] [InlineData("101", "101-е")] [InlineData("102", "102-е")] [InlineData("103", "103-є")] [InlineData("1001", "1001-е")] public void OrdinalizeStringNeuter(string number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Neuter), ordinalized); [Theory] [InlineData(0, "0-й")] [InlineData(1, "1-й")] [InlineData(2, "2-й")] [InlineData(3, "3-й")] [InlineData(4, "4-й")] [InlineData(5, "5-й")] [InlineData(6, "6-й")] [InlineData(10, "10-й")] [InlineData(23, "23-й")] [InlineData(100, "100-й")] [InlineData(101, "101-й")] [InlineData(102, "102-й")] [InlineData(103, "103-й")] [InlineData(1001, "1001-й")] public void OrdinalizeNumber(int number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Masculine), ordinalized); [Theory] [InlineData(0, "0-а")] [InlineData(1, "1-а")] [InlineData(2, "2-а")] [InlineData(3, "3-я")] [InlineData(4, "4-а")] [InlineData(5, "5-а")] [InlineData(6, "6-а")] [InlineData(10, "10-а")] [InlineData(23, "23-я")] [InlineData(100, "100-а")] [InlineData(101, "101-а")] [InlineData(102, "102-а")] [InlineData(103, "103-я")] [InlineData(1001, "1001-а")] public void OrdinalizeNumberFeminine(int number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Feminine), ordinalized); [Theory] [InlineData(0, "0-е")] [InlineData(1, "1-е")] [InlineData(2, "2-е")] [InlineData(3, "3-є")] [InlineData(4, "4-е")] [InlineData(5, "5-е")] [InlineData(6, "6-е")] [InlineData(23, "23-є")] [InlineData(100, "100-е")] [InlineData(101, "101-е")] [InlineData(102, "102-е")] [InlineData(103, "103-є")] [InlineData(1001, "1001-е")] public void OrdinalizeNumberNeuter(int number, string ordinalized) => Assert.Equal(number.Ordinalize(GrammaticalGender.Neuter), ordinalized); } ================================================ FILE: tests/Humanizer.Tests/Localisation/uk-UA/TimeSpanHumanizeTests.cs ================================================ namespace ukUA; [UseCulture("uk-UA")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "один рік", true)] [InlineData(366, "1 рік")] [InlineData(731, "2 роки")] [InlineData(1096, "3 роки")] [InlineData(4018, "11 років")] public void Years(int days, string expected, bool toWords = false) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year, toWords: toWords)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "один місяць", true)] [InlineData(31, "1 місяць")] [InlineData(61, "2 місяці")] [InlineData(92, "3 місяці")] [InlineData(335, "11 місяців")] public void Months(int days, string expected, bool toWords = false) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year, toWords: toWords)); [Theory] [InlineData(7, "один тиждень", true)] [InlineData(7, "1 тиждень")] [InlineData(14, "2 тижні")] [InlineData(21, "3 тижні")] [InlineData(28, "4 тижні")] [InlineData(35, "5 тижнів")] [InlineData(77, "11 тижнів")] [InlineData(147, "двадцять один тиждень", true)] public void Weeks(int days, string expected, bool toWords = false) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(toWords: toWords)); [Theory] [InlineData(1, "один день", true)] [InlineData(1, "1 день")] [InlineData(2, "2 дні")] [InlineData(3, "3 дні")] [InlineData(4, "4 дні")] [InlineData(5, "5 днів")] [InlineData(6, "6 днів")] [InlineData(21, "двадцять один день", true)] public void Days(int days, string expected, bool toWords = false) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(toWords: toWords, maxUnit: TimeUnit.Day)); [Theory] [InlineData(1, "одна година", true)] [InlineData(1, "1 година")] [InlineData(2, "2 години")] [InlineData(3, "3 години")] [InlineData(4, "4 години")] [InlineData(5, "5 годин")] [InlineData(6, "6 годин")] [InlineData(10, "10 годин")] [InlineData(11, "11 годин")] [InlineData(19, "19 годин")] [InlineData(20, "20 годин")] [InlineData(21, "21 година")] [InlineData(21, "двадцять одна година", true)] [InlineData(22, "22 години")] [InlineData(23, "23 години")] public void Hours(int hours, string expected, bool toWords = false) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize(toWords: toWords)); [Theory] [InlineData(1, "одна хвилина", true)] [InlineData(1, "1 хвилина")] [InlineData(2, "2 хвилини")] [InlineData(3, "3 хвилини")] [InlineData(4, "4 хвилини")] [InlineData(5, "5 хвилин")] [InlineData(6, "6 хвилин")] [InlineData(10, "10 хвилин")] [InlineData(11, "11 хвилин")] [InlineData(19, "19 хвилин")] [InlineData(20, "20 хвилин")] [InlineData(21, "21 хвилина")] [InlineData(21, "двадцять одна хвилина", true)] [InlineData(22, "22 хвилини")] [InlineData(23, "23 хвилини")] [InlineData(24, "24 хвилини")] [InlineData(25, "25 хвилин")] [InlineData(40, "40 хвилин")] public void Minutes(int minutes, string expected, bool toWords = false) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize(toWords: toWords)); [Theory] [InlineData(1, "одна секунда", true)] [InlineData(1, "1 секунда")] [InlineData(2, "2 секунди")] [InlineData(3, "3 секунди")] [InlineData(4, "4 секунди")] [InlineData(5, "5 секунд")] [InlineData(6, "6 секунд")] [InlineData(10, "10 секунд")] [InlineData(11, "11 секунд")] [InlineData(19, "19 секунд")] [InlineData(20, "20 секунд")] [InlineData(21, "21 секунда")] [InlineData(21, "двадцять одна секунда", true)] [InlineData(22, "22 секунди")] [InlineData(23, "23 секунди")] [InlineData(24, "24 секунди")] [InlineData(25, "25 секунд")] [InlineData(40, "40 секунд")] public void Seconds(int seconds, string expected, bool toWords = false) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize(toWords: toWords)); [Theory] [InlineData(1, "одна мілісекунда", true)] [InlineData(1, "1 мілісекунда")] [InlineData(2, "2 мілісекунди")] [InlineData(3, "3 мілісекунди")] [InlineData(4, "4 мілісекунди")] [InlineData(5, "5 мілісекунд")] [InlineData(6, "6 мілісекунд")] [InlineData(10, "10 мілісекунд")] [InlineData(11, "11 мілісекунд")] [InlineData(19, "19 мілісекунд")] [InlineData(20, "20 мілісекунд")] [InlineData(21, "21 мілісекунда")] [InlineData(21, "двадцять одна мілісекунда", true)] [InlineData(22, "22 мілісекунди")] [InlineData(23, "23 мілісекунди")] [InlineData(24, "24 мілісекунди")] [InlineData(25, "25 мілісекунд")] [InlineData(40, "40 мілісекунд")] public void Milliseconds(int milliseconds, string expected, bool toWords = false) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize(toWords: toWords)); [Fact] public void NoTime() => Assert.Equal("0 мілісекунд", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => Assert.Equal("без часу", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/uz-Cyrl-UZ/DateHumanizeTests.cs ================================================ namespace uzCyrl; [UseCulture("uz-Cyrl-UZ")] public class DateHumanizeTests { [Theory] [InlineData(1, "бир сония аввал")] [InlineData(10, "10 секунд аввал")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "бир сониядан сўнг")] [InlineData(10, "10 секунддан сўнг")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(1, "бир дақиқа аввал")] [InlineData(10, "10 минут аввал")] [InlineData(60, "бир соат аввал")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "бир дақиқадан сўнг")] [InlineData(10, "10 минутдан сўнг")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(1, "бир соат аввал")] [InlineData(10, "10 соат аввал")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "бир соатдан сўнг")] [InlineData(10, "10 соатдан сўнг")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(1, "кеча")] [InlineData(10, "10 кун аввал")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "эртага")] [InlineData(10, "10 кундан сўнг")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(1, "бир ой аввал")] [InlineData(10, "10 ой аввал")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "бир ойдан сўнг")] [InlineData(10, "10 ойдан сўнг")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(1, "бир йил аввал")] [InlineData(2, "2 йил аввал")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "бир йилдан сўнг")] [InlineData(2, "2 йилдан сўнг")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Fact] public void Now() => DateHumanize.Verify("ҳозир", 0, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/uz-Cyrl-UZ/NumberToWordsTests.cs ================================================ namespace uzCyrl; [UseCulture("uz-Cyrl-UZ")] public class NumberToWordsTests { [Theory] [InlineData(0, "нол")] [InlineData(1, "бир")] [InlineData(10, "ўн")] [InlineData(11, "ўн бир")] [InlineData(12, "ўн икки")] [InlineData(13, "ўн уч")] [InlineData(14, "ўн тўрт")] [InlineData(15, "ўн беш")] [InlineData(16, "ўн олти")] [InlineData(17, "ўн етти")] [InlineData(18, "ўн саккиз")] [InlineData(19, "ўн тўққиз")] [InlineData(20, "йигирма")] [InlineData(30, "ўттиз")] [InlineData(40, "қирқ")] [InlineData(50, "эллик")] [InlineData(60, "олтмиш")] [InlineData(70, "етмиш")] [InlineData(80, "саксон")] [InlineData(90, "тўқсон")] [InlineData(100, "юз")] [InlineData(200, "икки юз")] [InlineData(300, "уч юз")] [InlineData(400, "тўрт юз")] [InlineData(500, "беш юз")] [InlineData(600, "олти юз")] [InlineData(700, "етти юз")] [InlineData(800, "саккиз юз")] [InlineData(900, "тўққиз юз")] [InlineData(1000, "бир минг")] [InlineData(2000, "икки минг")] [InlineData(3000, "уч минг")] [InlineData(10000, "ўн минг")] [InlineData(100000, "юз минг")] [InlineData(100100, "юз минг бир юз")] [InlineData(200100, "икки юз минг бир юз")] [InlineData(1000000, "бир миллион")] [InlineData(1001000, "бир миллион бир минг")] [InlineData(1000100, "бир миллион бир юз")] [InlineData(2000000, "икки миллион")] [InlineData(10000000, "ўн миллион")] [InlineData(100000000, "юз миллион")] [InlineData(100001000, "юз миллион бир минг")] [InlineData(1000000000, "бир миллиард")] [InlineData(2000000000, "икки миллиард")] [InlineData(122, "бир юз йигирма икки")] [InlineData(3501, "уч минг беш юз бир")] [InlineData(111, "бир юз ўн бир")] [InlineData(1112, "бир минг бир юз ўн икки")] [InlineData(11213, "ўн бир минг икки юз ўн уч")] [InlineData(121314, "бир юз йигирма бир минг уч юз ўн тўрт")] [InlineData(2132415, "икки миллион бир юз ўттиз икки минг тўрт юз ўн беш")] [InlineData(12345516, "ўн икки миллион уч юз қирқ беш минг беш юз ўн олти")] [InlineData(751633617, "етти юз эллик бир миллион олти юз ўттиз уч минг олти юз ўн етти")] [InlineData(1111111118, "бир миллиард бир юз ўн бир миллион бир юз ўн бир минг бир юз ўн саккиз")] [InlineData(-751633617, "минус етти юз эллик бир миллион олти юз ўттиз уч минг олти юз ўн етти")] public void ToWords(int number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(0, "нолинчи")] [InlineData(1, "биринчи")] [InlineData(10, "ўнинчи")] [InlineData(11, "ўн биринчи")] [InlineData(12, "ўн иккинчи")] [InlineData(13, "ўн учинчи")] [InlineData(14, "ўн тўртинчи")] [InlineData(15, "ўн бешинчи")] [InlineData(16, "ўн олтинчи")] [InlineData(17, "ўн еттинчи")] [InlineData(18, "ўн саккизинчи")] [InlineData(19, "ўн тўққизинчи")] [InlineData(20, "йигирманчи")] [InlineData(30, "ўттизинчи")] [InlineData(40, "қирқинчи")] [InlineData(50, "элликинчи")] [InlineData(60, "олтмишинчи")] [InlineData(70, "етмишинчи")] [InlineData(80, "саксонинчи")] [InlineData(90, "тўқсонинчи")] [InlineData(100, "юзинчи")] [InlineData(200, "икки юзинчи")] [InlineData(1000, "бир мингинчи")] [InlineData(2000000, "икки миллионинчи")] [InlineData(1000000000, "бир миллиардинчи")] [InlineData(122, "бир юз йигирма иккинчи")] [InlineData(3501, "уч минг беш юз биринчи")] [InlineData(111, "бир юз ўн биринчи")] [InlineData(751633617, "етти юз эллик бир миллион олти юз ўттиз уч минг олти юз ўн еттинчи")] [InlineData(1111111118, "бир миллиард бир юз ўн бир миллион бир юз ўн бир минг бир юз ўн саккизинчи")] [InlineData(-751633617, "минус етти юз эллик бир миллион олти юз ўттиз уч минг олти юз ўн еттинчи")] public void ToOrdinalWords(int number, string words) => Assert.Equal(words, number.ToOrdinalWords()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/uz-Cyrl-UZ/TimeSpanHumanizeTests.cs ================================================ namespace uzCyrl; [UseCulture("uz-Cyrl-UZ")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "1 йил")] [InlineData(731, "2 йил")] [InlineData(1096, "3 йил")] [InlineData(4018, "11 йил")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "1 ой")] [InlineData(61, "2 ой")] [InlineData(92, "3 ой")] [InlineData(335, "11 ой")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(14, "2 ҳафта")] [InlineData(7, "1 ҳафта")] public void Weeks(int days, string expected) { var actual = TimeSpan.FromDays(days).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(6, "6 кун")] [InlineData(2, "2 кун")] public void Days(int days, string expected) { var actual = TimeSpan.FromDays(days).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 соат")] [InlineData(1, "1 соат")] public void Hours(int hours, string expected) { var actual = TimeSpan.FromHours(hours).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 минут")] [InlineData(1, "1 минут")] public void Minutes(int minutes, string expected) { var actual = TimeSpan.FromMinutes(minutes).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 секунд")] [InlineData(1, "1 секунд")] public void Seconds(int seconds, string expected) { var actual = TimeSpan.FromSeconds(seconds).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 миллисекунд")] [InlineData(1, "1 миллисекунд")] public void Milliseconds(int ms, string expected) { var actual = TimeSpan.FromMilliseconds(ms).Humanize(); Assert.Equal(expected, actual); } [Fact] public void NoTime() { var noTime = TimeSpan.Zero; var actual = noTime.Humanize(); Assert.Equal("0 миллисекунд", actual); } [Fact] public void NoTimeToWords() { var noTime = TimeSpan.Zero; var actual = noTime.Humanize(toWords: true); Assert.Equal("вақт йўқ", actual); } } ================================================ FILE: tests/Humanizer.Tests/Localisation/uz-Latn-UZ/DateHumanizeTests.cs ================================================ namespace uzLatn; [UseCulture("uz-Latn-UZ")] public class DateHumanizeTests { [Theory] [InlineData(1, "bir soniya avval")] [InlineData(10, "10 sekund avval")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "bir soniyadan so`ng")] [InlineData(10, "10 sekunddan so`ng")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(1, "bir daqiqa avval")] [InlineData(10, "10 minut avval")] [InlineData(60, "bir soat avval")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "bir daqiqadan so`ng")] [InlineData(10, "10 minutdan so`ng")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(1, "bir soat avval")] [InlineData(10, "10 soat avval")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "bir soatdan so`ng")] [InlineData(10, "10 soatdan so`ng")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(1, "kecha")] [InlineData(10, "10 kun avval")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "ertaga")] [InlineData(10, "10 kundan so`ng")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(1, "bir oy avval")] [InlineData(10, "10 oy avval")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "bir oydan so`ng")] [InlineData(10, "10 oydan so`ng")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(1, "bir yil avval")] [InlineData(2, "2 yil avval")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "bir yildan so`ng")] [InlineData(2, "2 yildan so`ng")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); [Fact] public void Now() => DateHumanize.Verify("hozir", 0, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/uz-Latn-UZ/NumberToWordsTests.cs ================================================ namespace uzLatn; [UseCulture("uz-Latn-UZ")] public class NumberToWordsTests { [Theory] [InlineData(0, "nol")] [InlineData(1, "bir")] [InlineData(10, "o`n")] [InlineData(11, "o`n bir")] [InlineData(12, "o`n ikki")] [InlineData(13, "o`n uch")] [InlineData(14, "o`n to`rt")] [InlineData(15, "o`n besh")] [InlineData(16, "o`n olti")] [InlineData(17, "o`n yetti")] [InlineData(18, "o`n sakkiz")] [InlineData(19, "o`n to`qqiz")] [InlineData(20, "yigirma")] [InlineData(30, "o`ttiz")] [InlineData(40, "qirq")] [InlineData(50, "ellik")] [InlineData(60, "oltmish")] [InlineData(70, "yetmish")] [InlineData(80, "sakson")] [InlineData(90, "to`qson")] [InlineData(100, "yuz")] [InlineData(200, "ikki yuz")] [InlineData(300, "uch yuz")] [InlineData(400, "to`rt yuz")] [InlineData(500, "besh yuz")] [InlineData(600, "olti yuz")] [InlineData(700, "yetti yuz")] [InlineData(800, "sakkiz yuz")] [InlineData(900, "to`qqiz yuz")] [InlineData(1000, "bir ming")] [InlineData(2000, "ikki ming")] [InlineData(3000, "uch ming")] [InlineData(10000, "o`n ming")] [InlineData(100000, "yuz ming")] [InlineData(100100, "yuz ming bir yuz")] [InlineData(200100, "ikki yuz ming bir yuz")] [InlineData(1000000, "bir million")] [InlineData(1001000, "bir million bir ming")] [InlineData(1000100, "bir million bir yuz")] [InlineData(2000000, "ikki million")] [InlineData(10000000, "o`n million")] [InlineData(100000000, "yuz million")] [InlineData(100001000, "yuz million bir ming")] [InlineData(1000000000, "bir milliard")] [InlineData(2000000000, "ikki milliard")] [InlineData(122, "bir yuz yigirma ikki")] [InlineData(3501, "uch ming besh yuz bir")] [InlineData(111, "bir yuz o`n bir")] [InlineData(1112, "bir ming bir yuz o`n ikki")] [InlineData(11213, "o`n bir ming ikki yuz o`n uch")] [InlineData(121314, "bir yuz yigirma bir ming uch yuz o`n to`rt")] [InlineData(2132415, "ikki million bir yuz o`ttiz ikki ming to`rt yuz o`n besh")] [InlineData(12345516, "o`n ikki million uch yuz qirq besh ming besh yuz o`n olti")] [InlineData(751633617, "yetti yuz ellik bir million olti yuz o`ttiz uch ming olti yuz o`n yetti")] [InlineData(1111111118, "bir milliard bir yuz o`n bir million bir yuz o`n bir ming bir yuz o`n sakkiz")] [InlineData(-751633617, "minus yetti yuz ellik bir million olti yuz o`ttiz uch ming olti yuz o`n yetti")] public void ToWords(int number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(0, "nolinchi")] [InlineData(1, "birinchi")] [InlineData(10, "o`ninchi")] [InlineData(11, "o`n birinchi")] [InlineData(12, "o`n ikkinchi")] [InlineData(13, "o`n uchinchi")] [InlineData(14, "o`n to`rtinchi")] [InlineData(15, "o`n beshinchi")] [InlineData(16, "o`n oltinchi")] [InlineData(17, "o`n yettinchi")] [InlineData(18, "o`n sakkizinchi")] [InlineData(19, "o`n to`qqizinchi")] [InlineData(20, "yigirmanchi")] [InlineData(30, "o`ttizinchi")] [InlineData(40, "qirqinchi")] [InlineData(50, "ellikinchi")] [InlineData(60, "oltmishinchi")] [InlineData(70, "yetmishinchi")] [InlineData(80, "saksoninchi")] [InlineData(90, "to`qsoninchi")] [InlineData(100, "yuzinchi")] [InlineData(200, "ikki yuzinchi")] [InlineData(1000, "bir minginchi")] [InlineData(2000000, "ikki millioninchi")] [InlineData(1000000000, "bir milliardinchi")] [InlineData(122, "bir yuz yigirma ikkinchi")] [InlineData(3501, "uch ming besh yuz birinchi")] [InlineData(111, "bir yuz o`n birinchi")] [InlineData(751633617, "yetti yuz ellik bir million olti yuz o`ttiz uch ming olti yuz o`n yettinchi")] [InlineData(1111111118, "bir milliard bir yuz o`n bir million bir yuz o`n bir ming bir yuz o`n sakkizinchi")] [InlineData(-751633617, "minus yetti yuz ellik bir million olti yuz o`ttiz uch ming olti yuz o`n yettinchi")] public void ToOrdinalWords(int number, string words) => Assert.Equal(words, number.ToOrdinalWords()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/uz-Latn-UZ/TimeSpanHumanizeTests.cs ================================================ namespace uzLatn; [UseCulture("uz-Latn-UZ")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "1 yil")] [InlineData(731, "2 yil")] [InlineData(1096, "3 yil")] [InlineData(4018, "11 yil")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "1 oy")] [InlineData(61, "2 oy")] [InlineData(92, "3 oy")] [InlineData(335, "11 oy")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(14, "2 hafta")] [InlineData(7, "1 hafta")] public void Weeks(int days, string expected) { var actual = TimeSpan.FromDays(days).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(6, "6 kun")] [InlineData(2, "2 kun")] public void Days(int days, string expected) { var actual = TimeSpan.FromDays(days).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 soat")] [InlineData(1, "1 soat")] public void Hours(int hours, string expected) { var actual = TimeSpan.FromHours(hours).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 minut")] [InlineData(1, "1 minut")] public void Minutes(int minutes, string expected) { var actual = TimeSpan.FromMinutes(minutes).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 sekund")] [InlineData(1, "1 sekund")] public void Seconds(int seconds, string expected) { var actual = TimeSpan.FromSeconds(seconds).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 millisekund")] [InlineData(1, "1 millisekund")] public void Milliseconds(int ms, string expected) { var actual = TimeSpan.FromMilliseconds(ms).Humanize(); Assert.Equal(expected, actual); } [Fact] public void NoTime() { var noTime = TimeSpan.Zero; var actual = noTime.Humanize(); Assert.Equal("0 millisekund", actual); } [Fact] public void NoTimeToWords() { var noTime = TimeSpan.Zero; var actual = noTime.Humanize(toWords: true); Assert.Equal("vaqt yo`q", actual); } } ================================================ FILE: tests/Humanizer.Tests/Localisation/vi/DateHumanizeTests.cs ================================================ namespace vi; [UseCulture("vi")] public class DateHumanizeTests { [Theory] [InlineData(1, "cách đây một giây")] [InlineData(10, "cách đây 10 giây")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(1, "một giây nữa")] [InlineData(10, "10 giây nữa")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(1, "cách đây một phút")] [InlineData(10, "cách đây 10 phút")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(1, "một phút nữa")] [InlineData(10, "10 phút nữa")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(1, "cách đây một tiếng")] [InlineData(10, "cách đây 10 tiếng")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(1, "một tiếng nữa")] [InlineData(10, "10 tiếng nữa")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(1, "hôm qua")] [InlineData(10, "cách đây 10 ngày")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(1, "ngày mai")] [InlineData(10, "10 ngày nữa")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(1, "cách đây một tháng")] [InlineData(10, "cách đây 10 tháng")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(1, "một tháng nữa")] [InlineData(10, "10 tháng nữa")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(1, "cách đây một năm")] [InlineData(2, "cách đây 2 năm")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(1, "một năm nữa")] [InlineData(2, "2 năm nữa")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/vi/NumberToWordsTests.cs ================================================ namespace Humanizer.Tests.Localisation.vi; [UseCulture("vi")] public class NumberToWordsTests { [Theory] [InlineData(0, "không")] [InlineData(1, "một")] [InlineData(2, "hai")] [InlineData(3, "ba")] [InlineData(4, "bốn")] [InlineData(5, "năm")] [InlineData(6, "sáu")] [InlineData(7, "bảy")] [InlineData(8, "tám")] [InlineData(9, "chín")] [InlineData(10, "mười")] [InlineData(11, "mười một")] [InlineData(14, "mười bốn")] [InlineData(15, "mười lăm")] [InlineData(21, "hai mươi mốt")] [InlineData(24, "hai mươi tư")] [InlineData(25, "hai mươi lăm")] [InlineData(50, "năm mươi")] [InlineData(55, "năm mươi lăm")] [InlineData(100, "một trăm")] [InlineData(105, "một trăm linh năm")] [InlineData(110, "một trăm mười")] [InlineData(114, "một trăm mười bốn")] [InlineData(115, "một trăm mười lăm")] [InlineData(134, "một trăm ba mươi tư")] [InlineData(500, "năm trăm")] [InlineData(505, "năm trăm linh năm")] [InlineData(555, "năm trăm năm mươi lăm")] [InlineData(1000, "một nghìn")] [InlineData(1005, "một nghìn linh năm")] [InlineData(1115, "một nghìn một trăm mười lăm")] [InlineData(10005, "mười nghìn linh năm")] [InlineData(10115, "mười nghìn một trăm mười lăm")] [InlineData(11115, "mười một nghìn một trăm mười lăm")] [InlineData(30005, "ba mươi nghìn linh năm")] [InlineData(100005, "một trăm nghìn linh năm")] [InlineData(1000000, "một triệu")] [InlineData(100001005, "một trăm triệu một nghìn linh năm")] [InlineData(1000000000, "một tỉ")] [InlineData(1111111111111111, "một triệu một trăm mười một nghìn một trăm mười một tỉ một trăm mười một triệu một trăm mười một nghìn một trăm mười một")] [InlineData(5101101101101151101, "năm tỉ một trăm linh một triệu một trăm linh một nghìn một trăm linh một tỉ một trăm linh một triệu một trăm năm mươi mốt nghìn một trăm linh một")] [InlineData(-1, "trừ một")] [InlineData(-30005, "trừ ba mươi nghìn linh năm")] [InlineData(-1111111111111111, "trừ một triệu một trăm mười một nghìn một trăm mười một tỉ một trăm mười một triệu một trăm mười một nghìn một trăm mười một")] public void ToWords(long number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(0, "thứ không")] [InlineData(1, "thứ nhất")] [InlineData(2, "thứ nhì")] [InlineData(3, "thứ ba")] [InlineData(4, "thứ tư")] [InlineData(5, "thứ năm")] [InlineData(6, "thứ sáu")] [InlineData(7, "thứ bảy")] [InlineData(8, "thứ tám")] [InlineData(9, "thứ chín")] [InlineData(10, "thứ mười")] [InlineData(11, "thứ mười một")] [InlineData(14, "thứ mười bốn")] [InlineData(15, "thứ mười lăm")] [InlineData(21, "thứ hai mươi mốt")] [InlineData(24, "thứ hai mươi tư")] [InlineData(25, "thứ hai mươi lăm")] public void ToOrdinalWords(int number, string expected) => Assert.Equal(expected, number.ToOrdinalWords()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/vi/TimeSpanHumanizeTests.cs ================================================ namespace vi; [UseCulture("vi")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Google")] [InlineData(366, "1 năm")] [InlineData(731, "2 năm")] [InlineData(1096, "3 năm")] [InlineData(4018, "11 năm")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan .FromDays(days) .Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Google")] [InlineData(31, "1 tháng")] [InlineData(61, "2 tháng")] [InlineData(92, "3 tháng")] [InlineData(335, "11 tháng")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan .FromDays(days) .Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(14, "2 tuần")] [InlineData(7, "1 tuần")] public void Weeks(int days, string expected) { var actual = TimeSpan .FromDays(days) .Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 ngày")] [InlineData(1, "1 ngày")] public void Days(int days, string expected) { var actual = TimeSpan .FromDays(days) .Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 giờ")] [InlineData(1, "1 giờ")] public void Hours(int hours, string expected) { var actual = TimeSpan .FromHours(hours) .Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 phút")] [InlineData(1, "1 phút")] public void Minutes(int minutes, string expected) { var actual = TimeSpan .FromMinutes(minutes) .Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 giây")] [InlineData(1, "1 giây")] public void Seconds(int seconds, string expected) { var actual = TimeSpan .FromSeconds(seconds) .Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 phần ngàn giây")] [InlineData(1, "1 phần ngàn giây")] public void Milliseconds(int ms, string expected) { var actual = TimeSpan .FromMilliseconds(ms) .Humanize(); Assert.Equal(expected, actual); } [Fact] public void NoTime() { var noTime = TimeSpan.Zero; var actual = noTime.Humanize(); Assert.Equal("0 phần ngàn giây", actual); } [Fact] public void NoTimeToWords() { var noTime = TimeSpan.Zero; var actual = noTime.Humanize(toWords: true); Assert.Equal("không giờ", actual); } } ================================================ FILE: tests/Humanizer.Tests/Localisation/zh-CN/DateHumanizeTests.cs ================================================ namespace zhCN; [UseCulture("zh-CN")] public class DateHumanizeTests { [Theory] [InlineData(2, "2 天前")] [InlineData(1, "昨天")] [InlineData(0, "现在")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(2, "2 天后")] [InlineData(1, "明天")] [InlineData(0, "现在")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(2, "2 小时前")] [InlineData(1, "1 小时前")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(2, "2 小时后")] [InlineData(1, "1 小时后")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(-2, "2 分钟前")] [InlineData(-1, "1 分钟前")] [InlineData(60, "1 小时前")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(2, "2 分钟后")] [InlineData(1, "1 分钟后")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(-2, "2 个月前")] [InlineData(-1, "1 个月前")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(2, "2 个月后")] [InlineData(1, "1 个月后")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(-2, "2 秒钟前")] [InlineData(-1, "1 秒钟前")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(2, "2 秒钟后")] [InlineData(1, "1 秒钟后")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(-2, "2 年前")] [InlineData(-1, "去年")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(2, "2 年后")] [InlineData(1, "明年")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/zh-CN/NumberToWordsTests.cs ================================================ namespace zhCN; [UseCulture("zh-CN")] public class NumberToWordsTests { [InlineData(1, "一")] [InlineData(2, "二")] [InlineData(3, "三")] [InlineData(4, "四")] [InlineData(-5, "负 五")] [InlineData(6, "六")] [InlineData(7, "七")] [InlineData(8, "八")] [InlineData(9, "九")] [InlineData(10, "十")] [InlineData(13, "十三")] [InlineData(15, "十五")] [InlineData(19, "十九")] [InlineData(28, "二十八")] [InlineData(37, "三十七")] [InlineData(46, "四十六")] [InlineData(55, "五十五")] [InlineData(64, "六十四")] [InlineData(73, "七十三")] [InlineData(82, "八十二")] [InlineData(-91, "负 九十一")] [InlineData(100, "一百")] [InlineData(507, "五百零七")] [InlineData(719, "七百一十九")] [InlineData(1356, "一千三百五十六")] [InlineData(20089, "二万零八十九")] [InlineData(335478, "三十三万五千四百七十八")] [InlineData(4214599, "四百二十一万四千五百九十九")] [InlineData(-54367865, "负 五千四百三十六万七千八百六十五")] [InlineData(650004076, "六亿五千万四千零七十六")] [InlineData(7156404367L, "七十一亿五千六百四十万四千三百六十七")] [InlineData(89043267890L, "八百九十亿四千三百二十六万七千八百九十")] [InlineData(500007893401L, "五千亿零七百八十九万三千四百零一")] [InlineData(500000003401L, "五千亿零三千四百零一")] [InlineData(500000000001L, "五千亿零一")] [InlineData(500000000000L, "五千亿")] [InlineData(6067823149088L, "六兆零六百七十八亿二千三百一十四万九千零八十八")] [Theory] public void ToWords(long number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(1, "第 一")] [InlineData(15, "第 十五")] [InlineData(10000, "第 一万")] [InlineData(31234, "第 三万一千二百三十四")] public void ToOrdinalWords(int number, string words) => Assert.Equal(words, number.ToOrdinalWords()); } ================================================ FILE: tests/Humanizer.Tests/Localisation/zh-CN/TimeSpanHumanizeTests.cs ================================================ namespace zhCN; [UseCulture("zh-CN")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Native speaker")] [InlineData(366, "1 年")] [InlineData(731, "2 年")] [InlineData(1096, "3 年")] [InlineData(4018, "11 年")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Native speaker")] [InlineData(31, "1 个月")] [InlineData(61, "2 个月")] [InlineData(92, "3 个月")] [InlineData(335, "11 个月")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(7, "1 周")] [InlineData(14, "2 周")] [InlineData(21, "3 周")] [InlineData(77, "11 周")] public void Weeks(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "1 天")] [InlineData(2, "2 天")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "1 小时")] [InlineData(2, "2 小时")] public void Hours(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); [Theory] [InlineData(1, "1 分")] [InlineData(2, "2 分")] public void Minutes(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); [Theory] [InlineData(1, "1 秒")] [InlineData(2, "2 秒")] public void Seconds(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); [Theory] [InlineData(1, "1 毫秒")] [InlineData(2, "2 毫秒")] public void Milliseconds(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); [Fact] public void NoTime() => Assert.Equal("0 毫秒", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => // This one doesn't make a lot of sense but ... w/e Assert.Equal("没有时间", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/zh-HK/DateHumanizeTests.cs ================================================ namespace zhHK; [UseCulture("zh-HK")] public class DateHumanizeTests { [Theory] [InlineData(2, "2 天前")] [InlineData(1, "昨天")] [InlineData(0, "現在")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(2, "2 天後")] [InlineData(1, "明天")] [InlineData(0, "現在")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(2, "2 小時前")] [InlineData(1, "1 小時前")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(2, "2 小時後")] [InlineData(1, "1 小時後")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(-2, "2 分鐘前")] [InlineData(-1, "1 分鐘前")] [InlineData(60, "1 小時前")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(2, "2 分鐘後")] [InlineData(1, "1 分鐘後")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(-2, "2 個月前")] [InlineData(-1, "1 個月前")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(2, "2 個月後")] [InlineData(1, "1 個月後")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(-2, "2 秒鐘前")] [InlineData(-1, "1 秒鐘前")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(2, "2 秒鐘後")] [InlineData(1, "1 秒鐘後")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(-2, "2 年前")] [InlineData(-1, "去年")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(2, "2 年後")] [InlineData(1, "明年")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/zh-HK/TimeSpanHumanizeTests.cs ================================================ namespace zhHK; [UseCulture("zh-HK")] public class TimeSpanHumanizeTests { [Theory] [InlineData(366, "1 年")] [InlineData(731, "2 年")] [InlineData(1096, "3 年")] [InlineData(4018, "11 年")] public void Years(int days, string expected) { Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); } [Theory] [InlineData(31, "1 個月")] [InlineData(61, "2 個月")] [InlineData(92, "3 個月")] [InlineData(335, "11 個月")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(7, "1 周")] [InlineData(14, "2 周")] [InlineData(21, "3 周")] [InlineData(77, "11 周")] public void Weeks(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "1 天")] [InlineData(2, "2 天")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "1 小時")] [InlineData(2, "2 小時")] public void Hours(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); [Theory] [InlineData(1, "1 分")] [InlineData(2, "2 分")] public void Minutes(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); [Theory] [InlineData(1, "1 秒")] [InlineData(2, "2 秒")] public void Seconds(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); [Theory] [InlineData(1, "1 毫秒")] [InlineData(2, "2 毫秒")] public void Milliseconds(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); [Fact] public void NoTime() => Assert.Equal("0 毫秒", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => // This one doesn't make a lot of sense but ... w/e Assert.Equal("沒有時間", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/zh-Hans/DateHumanizeTests.cs ================================================ namespace zhHans; [UseCulture("zh-Hans")] public class DateHumanizeTests { [Theory] [InlineData(2, "2 天前")] [InlineData(1, "昨天")] [InlineData(0, "现在")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(2, "2 天后")] [InlineData(1, "明天")] [InlineData(0, "现在")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(2, "2 小时前")] [InlineData(1, "1 小时前")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(2, "2 小时后")] [InlineData(1, "1 小时后")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(-2, "2 分钟前")] [InlineData(-1, "1 分钟前")] [InlineData(60, "1 小时前")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(2, "2 分钟后")] [InlineData(1, "1 分钟后")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(-2, "2 个月前")] [InlineData(-1, "1 个月前")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(2, "2 个月后")] [InlineData(1, "1 个月后")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(-2, "2 秒钟前")] [InlineData(-1, "1 秒钟前")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(2, "2 秒钟后")] [InlineData(1, "1 秒钟后")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(-2, "2 年前")] [InlineData(-1, "去年")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(2, "2 年后")] [InlineData(1, "明年")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/zh-Hans/TimeSpanHumanizeTests.cs ================================================ namespace zhHans; [UseCulture("zh-Hans")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Native speaker")] [InlineData(366, "1 年")] [InlineData(731, "2 年")] [InlineData(1096, "3 年")] [InlineData(4018, "11 年")] public void Years(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [Trait("Translation", "Native speaker")] [InlineData(31, "1 个月")] [InlineData(61, "2 个月")] [InlineData(92, "3 个月")] [InlineData(335, "11 个月")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(7, "1 周")] [InlineData(14, "2 周")] [InlineData(21, "3 周")] [InlineData(77, "11 周")] public void Weeks(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "1 天")] [InlineData(2, "2 天")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "1 小时")] [InlineData(2, "2 小时")] public void Hours(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); [Theory] [InlineData(1, "1 分")] [InlineData(2, "2 分")] public void Minutes(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); [Theory] [InlineData(1, "1 秒")] [InlineData(2, "2 秒")] public void Seconds(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); [Theory] [InlineData(1, "1 毫秒")] [InlineData(2, "2 毫秒")] public void Milliseconds(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); [Fact] public void NoTime() => Assert.Equal("0 毫秒", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => // This one doesn't make a lot of sense but ... w/e Assert.Equal("没有时间", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/Localisation/zh-Hant/DateHumanizeTests.cs ================================================ namespace zhHant; [UseCulture("zh-Hant")] public class DateHumanizeTests { [Theory] [InlineData(2, "2 天前")] [InlineData(1, "昨天")] [InlineData(0, "現在")] public void DaysAgo(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past); [Theory] [InlineData(2, "2 天後")] [InlineData(1, "明天")] [InlineData(0, "現在")] public void DaysFromNow(int days, string expected) => DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future); [Theory] [InlineData(2, "2 小時前")] [InlineData(1, "1 小時前")] public void HoursAgo(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past); [Theory] [InlineData(2, "2 小時後")] [InlineData(1, "1 小時後")] public void HoursFromNow(int hours, string expected) => DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future); [Theory] [InlineData(-2, "2 分鐘前")] [InlineData(-1, "1 分鐘前")] [InlineData(60, "1 小時前")] public void MinutesAgo(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past); [Theory] [InlineData(2, "2 分鐘後")] [InlineData(1, "1 分鐘後")] public void MinutesFromNow(int minutes, string expected) => DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future); [Theory] [InlineData(-2, "2 個月前")] [InlineData(-1, "1 個月前")] public void MonthsAgo(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past); [Theory] [InlineData(2, "2 個月後")] [InlineData(1, "1 個月後")] public void MonthsFromNow(int months, string expected) => DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future); [Theory] [InlineData(-2, "2 秒鐘前")] [InlineData(-1, "1 秒鐘前")] public void SecondsAgo(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past); [Theory] [InlineData(2, "2 秒鐘後")] [InlineData(1, "1 秒鐘後")] public void SecondsFromNow(int seconds, string expected) => DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future); [Theory] [InlineData(-2, "2 年前")] [InlineData(-1, "去年")] public void YearsAgo(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past); [Theory] [InlineData(2, "2 年後")] [InlineData(1, "明年")] public void YearsFromNow(int years, string expected) => DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future); } ================================================ FILE: tests/Humanizer.Tests/Localisation/zh-Hant/TimeSpanHumanizeTests.cs ================================================ namespace zhHant; [UseCulture("zh-Hant")] public class TimeSpanHumanizeTests { [Theory] [Trait("Translation", "Native speaker")] [InlineData(366, "1 年")] [InlineData(731, "2 年")] [InlineData(1096, "3 年")] [InlineData(4018, "11 年")] public void Years(int days, string expected) { Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); } [Theory] [Trait("Translation", "Native speaker")] [InlineData(31, "1 個月")] [InlineData(61, "2 個月")] [InlineData(92, "3 個月")] [InlineData(335, "11 個月")] public void Months(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize(maxUnit: TimeUnit.Year)); [Theory] [InlineData(7, "1 周")] [InlineData(14, "2 周")] [InlineData(21, "3 周")] [InlineData(77, "11 周")] public void Weeks(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "1 天")] [InlineData(2, "2 天")] public void Days(int days, string expected) => Assert.Equal(expected, TimeSpan.FromDays(days).Humanize()); [Theory] [InlineData(1, "1 小時")] [InlineData(2, "2 小時")] public void Hours(int hours, string expected) => Assert.Equal(expected, TimeSpan.FromHours(hours).Humanize()); [Theory] [InlineData(1, "1 分")] [InlineData(2, "2 分")] public void Minutes(int minutes, string expected) => Assert.Equal(expected, TimeSpan.FromMinutes(minutes).Humanize()); [Theory] [InlineData(1, "1 秒")] [InlineData(2, "2 秒")] public void Seconds(int seconds, string expected) => Assert.Equal(expected, TimeSpan.FromSeconds(seconds).Humanize()); [Theory] [InlineData(1, "1 毫秒")] [InlineData(2, "2 毫秒")] public void Milliseconds(int milliseconds, string expected) => Assert.Equal(expected, TimeSpan.FromMilliseconds(milliseconds).Humanize()); [Fact] public void NoTime() => Assert.Equal("0 毫秒", TimeSpan.Zero.Humanize()); [Fact] public void NoTimeToWords() => // This one doesn't make a lot of sense but ... w/e Assert.Equal("沒有時間", TimeSpan.Zero.Humanize(toWords: true)); } ================================================ FILE: tests/Humanizer.Tests/MetricNumeralTests.cs ================================================ [UseCulture("en-US")] public class MetricNumeralTests { // Return a sequence of -24 -> 26 public static IEnumerable SymbolRange => Enumerable .Range(-24, 51) .Select(e => new object[] { e }); [Theory] [InlineData(0, "0")] [InlineData(123d, "123")] [InlineData(-123d, "-123")] [InlineData(1230d, "1.23k")] [InlineData(1000d, "1 k")] [InlineData(1000d, "1 kilo")] [InlineData(1E-3, "1milli")] public void FromMetric(double expected, string input) => Assert.Equal(expected, input.FromMetric()); [Theory] [InlineData("")] [InlineData(" ")] [InlineData("\t")] [InlineData("12yy")] [InlineData("-8e")] [InlineData("0.12c")] [InlineData("0.02l")] [InlineData("0.12kilkilo")] [InlineData("0.02alois")] public void FromMetricOnInvalid(string input) => Assert.Throws(() => input.FromMetric()); [Fact] public void FromMetricOnNull() => Assert.Throws(() => MetricNumeralExtensions.FromMetric(null!)); [Theory] [MemberData(nameof(SymbolRange))] public void TestAllSymbols(int e) { var origin = Math.Pow(10, e); var to = origin.ToMetric(); var from = to.FromMetric(); var c = Equals( origin.ToString("0.##E+0", CultureInfo.InvariantCulture), from.ToString("0.##E+0", CultureInfo.InvariantCulture)); Assert.True(c); } [Theory] [InlineData(-9)] [InlineData(-3)] [InlineData(-2)] [InlineData(-1)] [InlineData(0)] [InlineData(1)] [InlineData(2)] [InlineData(3)] [InlineData(9)] public void TestAllSymbolsAsInt(int exponent) { var origin = Convert.ToInt32(Math.Pow(10, exponent)); var isEquals = Equals( origin.ToString("0.##E+0", CultureInfo.InvariantCulture), origin .ToMetric() .FromMetric() .ToString("0.##E+0", CultureInfo.InvariantCulture)); Assert.True(isEquals); } [Theory] [InlineData(0, 0, "0")] [InlineData(0, 1, "0.0")] [InlineData(0, 3, "0.000")] [InlineData(0, 20, "0.00000000000000000000")] [InlineData(123, 0, "123")] [InlineData(123, 1, "123.0")] [InlineData(123, 3, "123.000")] [InlineData(123, 20, "123.00000000000000000000")] [InlineData(123456, null, "123.456k")] [InlineData(123456, 0, "123k")] [InlineData(123456, 1, "123.5k")] [InlineData(123456, 2, "123.46k")] [InlineData(123456, 3, "123.456k")] [InlineData(123456, 20, "123.45600000000000000000k")] [InlineData(123456789, null, "123.456789M")] [InlineData(123456789, 0, "123M")] [InlineData(123456789, 1, "123.5M")] [InlineData(123456789, 2, "123.46M")] [InlineData(123456789, 3, "123.457M")] [InlineData(123456789, 5, "123.45679M")] [InlineData(123456789, 20, "123.45678900000000000000M")] [InlineData(123456789987, 5, "123.45679G")] [InlineData(123456789987, 20, "123.45678998700000000000G")] [InlineData(123456789987654, 5, "123.45679T")] [InlineData(123456789987654, 20, "123.45678998765400000000T")] [InlineData(123456789987654321, 5, "123.45679P")] [InlineData(123456789987654321, 20, "123.45678998765432100000P")] [InlineData(9223372036854775807, null, "9.223372036854775807E")] [InlineData(9223372036854775807, 0, "9E")] [InlineData(9223372036854775807, 3, "9.223E")] [InlineData(9223372036854775807, 20, "9.22337203685477580700E")] [InlineData(-1, null, "-1")] [InlineData(-123, null, "-123")] [InlineData(-123456, null, "-123.456k")] [InlineData(-123456789, null, "-123.456789M")] [InlineData(-9223372036854775808, null, "-9.223372036854775808E")] [InlineData(-9223372036854775808, 0, "-9E")] [InlineData(-9223372036854775808, 3, "-9.223E")] [InlineData(-9223372036854775808, 20, "-9.22337203685477580800E")] public void TestAllSymbolsAsLong(long subject, int? decimals, string expected) => Assert.Equal(expected, subject.ToMetric(decimals: decimals)); [Theory] [InlineData("1.3M", 1300000, null, null)] [InlineData("1.3million", 1300000, MetricNumeralFormats.UseShortScaleWord, null)] [InlineData("1.3 million", 1300000, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseShortScaleWord, null)] [InlineData("1.3 million", 1300000, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseLongScaleWord, null)] [InlineData("0", 0d, null, null)] [InlineData("123", 123d, null, null)] [InlineData("-123", -123d, null, null)] [InlineData("1.23k", 1230d, null, null)] [InlineData("1 k", 1000d, MetricNumeralFormats.WithSpace, null)] [InlineData("1milli", 1E-3, MetricNumeralFormats.UseName, null)] [InlineData("1.23milli", 1.234E-3, MetricNumeralFormats.UseName, 2)] [InlineData("12.34k", 12345, null, 2)] [InlineData("12k", 12345, null, 0)] [InlineData("1M", 999500d, null, 0)] [InlineData("-3.9m", -3.91e-3, null, 1)] [InlineData("10 ", 10, MetricNumeralFormats.WithSpace, 0)] [InlineData("1.2", 1.23, null, 1)] [InlineData("1thousand", 1000d, MetricNumeralFormats.UseShortScaleWord, null)] [InlineData("1.23 thousand", 1230d, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseShortScaleWord, null)] [InlineData("1Y", 1E24, null, null)] [InlineData("1 yotta", 1E24, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseName, null)] [InlineData("1 septillion", 1E24, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseShortScaleWord, null)] [InlineData("1 quadrillion", 1E24, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseLongScaleWord, null)] [InlineData("1Z", 1E21, null, null)] [InlineData("1 zetta", 1E21, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseName, null)] [InlineData("1 sextillion", 1E21, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseShortScaleWord, null)] [InlineData("1 trilliard", 1E21, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseLongScaleWord, null)] [InlineData("1E", 1E18, null, null)] [InlineData("1 exa", 1E18, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseName, null)] [InlineData("1 quintillion", 1E18, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseShortScaleWord, null)] [InlineData("1 trillion", 1E18, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseLongScaleWord, null)] [InlineData("1P", 1E15, null, null)] [InlineData("1 peta", 1E15, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseName, null)] [InlineData("1 quadrillion", 1E15, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseShortScaleWord, null)] [InlineData("1 billiard", 1E15, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseLongScaleWord, null)] [InlineData("1T", 1E12, null, null)] [InlineData("1 tera", 1E12, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseName, null)] [InlineData("1 trillion", 1E12, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseShortScaleWord, null)] [InlineData("1 billion", 1E12, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseLongScaleWord, null)] [InlineData("1G", 1E9, null, null)] [InlineData("1 giga", 1E9, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseName, null)] [InlineData("1 billion", 1E9, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseShortScaleWord, null)] [InlineData("1 milliard", 1E9, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseLongScaleWord, null)] [InlineData("1M", 1E6, null, null)] [InlineData("1 mega", 1E6, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseName, null)] [InlineData("1 million", 1E6, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseShortScaleWord, null)] [InlineData("1 million", 1E6, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseLongScaleWord, null)] [InlineData("1k", 1E3, null, null)] [InlineData("1 kilo", 1E3, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseName, null)] [InlineData("1 thousand", 1E3, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseShortScaleWord, null)] [InlineData("1 thousand", 1E3, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseLongScaleWord, null)] [InlineData("1y", 1E-24, null, null)] [InlineData("1 yocto", 1E-24, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseName, null)] [InlineData("1 septillionth", 1E-24, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseShortScaleWord, null)] [InlineData("1 quadrillionth", 1E-24, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseLongScaleWord, null)] [InlineData("1z", 1E-21, null, null)] [InlineData("1 zepto", 1E-21, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseName, null)] [InlineData("1 sextillionth", 1E-21, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseShortScaleWord, null)] [InlineData("1 trilliardth", 1E-21, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseLongScaleWord, null)] [InlineData("1a", 1E-18, null, null)] [InlineData("1 atto", 1E-18, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseName, null)] [InlineData("1 quintillionth", 1E-18, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseShortScaleWord, null)] [InlineData("1 trillionth", 1E-18, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseLongScaleWord, null)] [InlineData("1f", 1E-15, null, null)] [InlineData("1 femto", 1E-15, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseName, null)] [InlineData("1 quadrillionth", 1E-15, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseShortScaleWord, null)] [InlineData("1 billiardth", 1E-15, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseLongScaleWord, null)] [InlineData("1p", 1E-12, null, null)] [InlineData("1 pico", 1E-12, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseName, null)] [InlineData("1 trillionth", 1E-12, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseShortScaleWord, null)] [InlineData("1 billionth", 1E-12, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseLongScaleWord, null)] [InlineData("1n", 1E-9, null, null)] [InlineData("1 nano", 1E-9, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseName, null)] [InlineData("1 billionth", 1E-9, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseShortScaleWord, null)] [InlineData("1 milliardth", 1E-9, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseLongScaleWord, null)] [InlineData("1μ", 1E-6, null, null)] [InlineData("1 micro", 1E-6, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseName, null)] [InlineData("1 millionth", 1E-6, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseShortScaleWord, null)] [InlineData("1 millionth", 1E-6, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseLongScaleWord, null)] [InlineData("1m", 1E-3, null, null)] [InlineData("1 milli", 1E-3, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseName, null)] [InlineData("1 thousandth", 1E-3, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseShortScaleWord, null)] [InlineData("1 thousandth", 1E-3, MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseLongScaleWord, null)] public void ToMetric(string expected, double input, MetricNumeralFormats? format, int? decimals) => Assert.Equal(expected, input.ToMetric(format, decimals)); [Theory] [InlineData(1E+27)] [InlineData(1E-27)] [InlineData(-1E+27)] [InlineData(-1E-27)] public void ToMetricOnInvalid(double input) => Assert.Throws(() => input.ToMetric()); } ================================================ FILE: tests/Humanizer.Tests/ModuleInitializer.cs ================================================ using VerifyTests.DiffPlex; public static class ModuleInitializer { [ModuleInitializer] public static void Initialize() { VerifyDiffPlex.Initialize(OutputType.Compact); VerifierSettings.InitializePlugins(); } } ================================================ FILE: tests/Humanizer.Tests/NumberToNumberTests.cs ================================================ public class NumberToNumberTests { [Fact] public void IntToTens() { const int number = 1; Assert.Equal(10, number.Tens()); } [Fact] public void UintToTens() { const uint number = 1; Assert.Equal(10U, number.Tens()); } [Fact] public void LongToTens() { const long number = 1; Assert.Equal(10L, number.Tens()); } [Fact] public void UlongToTens() { const ulong number = 1; Assert.Equal(10UL, number.Tens()); } [Fact] public void DoubleToTens() { const double number = 1; Assert.Equal(10d, number.Tens()); } [Fact] public void IntToHundreds() { const int number = 2; Assert.Equal(200, number.Hundreds()); } [Fact] public void UintToHundreds() { const uint number = 2; Assert.Equal(200U, number.Hundreds()); } [Fact] public void LongToHundreds() { const long number = 2; Assert.Equal(200L, number.Hundreds()); } [Fact] public void UlongToHundreds() { const ulong number = 2; Assert.Equal(200UL, number.Hundreds()); } [Fact] public void DoubleToHundreds() { const double number = 2; Assert.Equal(200d, number.Hundreds()); } [Fact] public void IntToThousands() { const int number = 3; Assert.Equal(3000, number.Thousands()); } [Fact] public void UintToThousands() { const uint number = 3; Assert.Equal(3000U, number.Thousands()); } [Fact] public void LongToThousands() { const long number = 3; Assert.Equal(3000L, number.Thousands()); } [Fact] public void UlongToThousands() { const ulong number = 3; Assert.Equal(3000UL, number.Thousands()); } [Fact] public void DoubleToThousands() { const double number = 3; Assert.Equal(3000d, number.Thousands()); } [Fact] public void IntToMillions() { const int number = 4; Assert.Equal(4000000, number.Millions()); } [Fact] public void UintToMillions() { const uint number = 4; Assert.Equal(4000000U, number.Millions()); } [Fact] public void LongToMillions() { const long number = 4; Assert.Equal(4000000L, number.Millions()); } [Fact] public void UlongToMillions() { const ulong number = 4; Assert.Equal(4000000UL, number.Millions()); } [Fact] public void DoubleToMillions() { const double number = 4; Assert.Equal(4000000d, number.Millions()); } [Fact] public void IntToBillions() { const int number = 1; Assert.Equal(1000000000, number.Billions()); } [Fact] public void UintToBillions() { const uint number = 1; Assert.Equal(1000000000U, number.Billions()); } [Fact] public void LongToBillions() { const long number = 1; Assert.Equal(1000000000L, number.Billions()); } [Fact] public void UlongToBillions() { const ulong number = 1; Assert.Equal(1000000000UL, number.Billions()); } [Fact] public void DoubleToBillions() { const double number = 1; Assert.Equal(1000000000d, number.Billions()); } } ================================================ FILE: tests/Humanizer.Tests/NumberToTimeSpanTests.cs ================================================ public class NumberToTimeSpanTests { [Fact] public void ByteToMilliseconds() { const byte number = 1; Assert.Equal(new(0, 0, 0, 0, 1), number.Milliseconds()); } [Fact] public void SbyteToMilliseconds() { const sbyte number = 1; Assert.Equal(new(0, 0, 0, 0, 1), number.Milliseconds()); } [Fact] public void ShortToMilliseconds() { const short number = 1; Assert.Equal(new(0, 0, 0, 0, 1), number.Milliseconds()); } [Fact] public void UshortToMilliseconds() { const ushort number = 1; Assert.Equal(new(0, 0, 0, 0, 1), number.Milliseconds()); } [Fact] public void IntToMilliseconds() { const int number = 1; Assert.Equal(new(0, 0, 0, 0, 1), number.Milliseconds()); } [Fact] public void UintToMilliseconds() { const uint number = 1; Assert.Equal(new(0, 0, 0, 0, 1), number.Milliseconds()); } [Fact] public void LongToMilliseconds() { const long number = 1; Assert.Equal(new(0, 0, 0, 0, 1), number.Milliseconds()); } [Fact] public void UlongToMilliseconds() { const ulong number = 1; Assert.Equal(new(0, 0, 0, 0, 1), number.Milliseconds()); } [Fact] public void ByteToMinutes() { const byte number = 2; Assert.Equal(new(0, 0, 2, 0), number.Minutes()); } [Fact] public void SbyteToMinutes() { const sbyte number = 2; Assert.Equal(new(0, 0, 2, 0), number.Minutes()); } [Fact] public void ShortToMinutes() { const short number = 2; Assert.Equal(new(0, 0, 2, 0), number.Minutes()); } [Fact] public void UshortToMinutes() { const ushort number = 2; Assert.Equal(new(0, 0, 2, 0), number.Minutes()); } [Fact] public void IntToMinutes() { const int number = 2; Assert.Equal(new(0, 0, 2, 0), number.Minutes()); } [Fact] public void UintToMinutes() { const uint number = 2; Assert.Equal(new(0, 0, 2, 0), number.Minutes()); } [Fact] public void LongToMinutes() { const long number = 2; Assert.Equal(new(0, 0, 2, 0), number.Minutes()); } [Fact] public void UlongToMinutes() { const ulong number = 2; Assert.Equal(new(0, 0, 2, 0), number.Minutes()); } [Fact] public void ByteToSeconds() { const byte number = 3; Assert.Equal(new(0, 0, 0, 3), number.Seconds()); } [Fact] public void SbyteToSeconds() { const sbyte number = 3; Assert.Equal(new(0, 0, 0, 3), number.Seconds()); } [Fact] public void ShortToSeconds() { const short number = 3; Assert.Equal(new(0, 0, 0, 3), number.Seconds()); } [Fact] public void UshortToSeconds() { const ushort number = 3; Assert.Equal(new(0, 0, 0, 3), number.Seconds()); } [Fact] public void IntToSeconds() { const int number = 3; Assert.Equal(new(0, 0, 0, 3), number.Seconds()); } [Fact] public void UintToSeconds() { const uint number = 3; Assert.Equal(new(0, 0, 0, 3), number.Seconds()); } [Fact] public void LongToSeconds() { const long number = 3; Assert.Equal(new(0, 0, 0, 3), number.Seconds()); } [Fact] public void UlongToSeconds() { const ulong number = 3; Assert.Equal(new(0, 0, 0, 3), number.Seconds()); } [Fact] public void ByteToHours() { const byte number = 4; Assert.Equal(new(0, 4, 0, 0), number.Hours()); } [Fact] public void SbyteToHours() { const sbyte number = 4; Assert.Equal(new(0, 4, 0, 0), number.Hours()); } [Fact] public void ShortToHours() { const short number = 4; Assert.Equal(new(0, 4, 0, 0), number.Hours()); } [Fact] public void UshortToHours() { const ushort number = 4; Assert.Equal(new(0, 4, 0, 0), number.Hours()); } [Fact] public void IntToHours() { const int number = 4; Assert.Equal(new(0, 4, 0, 0), number.Hours()); } [Fact] public void UintToHours() { const uint number = 4; Assert.Equal(new(0, 4, 0, 0), number.Hours()); } [Fact] public void LongToHours() { const long number = 4; Assert.Equal(new(0, 4, 0, 0), number.Hours()); } [Fact] public void UlongToHours() { const ulong number = 4; Assert.Equal(new(0, 4, 0, 0), number.Hours()); } [Fact] public void ByteToDays() { const byte number = 5; Assert.Equal(new(5, 0, 0, 0), number.Days()); } [Fact] public void SbyteToDays() { const sbyte number = 5; Assert.Equal(new(5, 0, 0, 0), number.Days()); } [Fact] public void ShortToDays() { const short number = 5; Assert.Equal(new(5, 0, 0, 0), number.Days()); } [Fact] public void UshortToDays() { const ushort number = 5; Assert.Equal(new(5, 0, 0, 0), number.Days()); } [Fact] public void IntToDays() { const int number = 5; Assert.Equal(new(5, 0, 0, 0), number.Days()); } [Fact] public void UintToDays() { const uint number = 5; Assert.Equal(new(5, 0, 0, 0), number.Days()); } [Fact] public void LongToDays() { const long number = 5; Assert.Equal(new(5, 0, 0, 0), number.Days()); } [Fact] public void UlongToDays() { const ulong number = 5; Assert.Equal(new(5, 0, 0, 0), number.Days()); } [Fact] public void ByteToWeeks() { const byte number = 6; var now = DateTime.Now; Assert.Equal(now.AddDays(42), now.Add(number.Weeks())); } [Fact] public void SbyteToWeeks() { const sbyte number = 6; var now = DateTime.Now; Assert.Equal(now.AddDays(42), now.Add(number.Weeks())); } [Fact] public void ShortToWeeks() { const short number = 6; var now = DateTime.Now; Assert.Equal(now.AddDays(42), now.Add(number.Weeks())); } [Fact] public void UshortToWeeks() { const ushort number = 6; var now = DateTime.Now; Assert.Equal(now.AddDays(42), now.Add(number.Weeks())); } [Fact] public void IntToWeeks() { const int number = 6; var now = DateTime.Now; Assert.Equal(now.AddDays(42), now.Add(number.Weeks())); } [Fact] public void UintToWeeks() { const uint number = 6; var now = DateTime.Now; Assert.Equal(now.AddDays(42), now.Add(number.Weeks())); } [Fact] public void LongToWeeks() { const long number = 6; var now = DateTime.Now; Assert.Equal(now.AddDays(42), now.Add(number.Weeks())); } [Fact] public void UlongToWeeks() { const ulong number = 6; var now = DateTime.Now; Assert.Equal(now.AddDays(42), now.Add(number.Weeks())); } } ================================================ FILE: tests/Humanizer.Tests/NumberToWordsTests.cs ================================================ [UseCulture("en-US")] public class NumberToWordsTests { [Theory] [InlineData(0, "zeroth")] [InlineData(1, "first")] [InlineData(2, "second")] [InlineData(3, "third")] [InlineData(4, "fourth")] [InlineData(5, "fifth")] [InlineData(6, "sixth")] [InlineData(7, "seventh")] [InlineData(8, "eighth")] [InlineData(9, "ninth")] [InlineData(10, "tenth")] [InlineData(11, "eleventh")] [InlineData(12, "twelfth")] [InlineData(13, "thirteenth")] [InlineData(14, "fourteenth")] [InlineData(15, "fifteenth")] [InlineData(16, "sixteenth")] [InlineData(17, "seventeenth")] [InlineData(18, "eighteenth")] [InlineData(19, "nineteenth")] [InlineData(20, "twentieth")] [InlineData(21, "twenty-first")] [InlineData(22, "twenty-second")] [InlineData(30, "thirtieth")] [InlineData(40, "fortieth")] [InlineData(50, "fiftieth")] [InlineData(60, "sixtieth")] [InlineData(70, "seventieth")] [InlineData(80, "eightieth")] [InlineData(90, "ninetieth")] [InlineData(95, "ninety-fifth")] [InlineData(96, "ninety-sixth")] [InlineData(100, "hundredth")] [InlineData(112, "hundred and twelfth")] [InlineData(120, "hundred and twentieth")] [InlineData(121, "hundred and twenty-first")] [InlineData(1000, "thousandth")] [InlineData(1001, "thousand and first")] [InlineData(1021, "thousand and twenty-first")] [InlineData(10000, "ten thousandth")] [InlineData(10121, "ten thousand one hundred and twenty-first")] [InlineData(100000, "hundred thousandth")] [InlineData(1000000, "millionth")] public void ToOrdinalWords(int number, string words) => Assert.Equal(words, number.ToOrdinalWords()); [Theory] [InlineData(1021, "en-US", "thousand and twenty-first")] [InlineData(21, "ar", "الحادي و العشرون")] [InlineData(1112, "ru", "одна тысяча сто двенадцатый")] public void ToOrdinalWords_CanSpecifyCultureExplicitly(int number, string culture, string expected) => Assert.Equal(expected, number.ToOrdinalWords(new(culture))); [Theory] [InlineData(1, "first")] [InlineData(2, "second")] [InlineData(3, "third")] public void ToOrdinalWords_WordFormIsIgnored(int number, string expected) { var normalForm1 = number.ToOrdinalWords(WordForm.Normal); var abbrForm1 = number.ToOrdinalWords(WordForm.Abbreviation); var normalForm2 = number.ToOrdinalWords(default, WordForm.Normal); var abbrForm2 = number.ToOrdinalWords(default, WordForm.Abbreviation); Assert.All( [ normalForm1, abbrForm1, normalForm2, abbrForm2 ], item => Assert.Equal(expected, item)); } [Theory] [InlineData(1, "en-US", "first")] [InlineData(3, "en-US", "third")] [InlineData(1, "sv-SE", "första")] [InlineData(3, "sv-SE", "tredje")] [InlineData(1, "ko-KR", "첫번째")] [InlineData(3, "ko-KR", "세번째")] public void ToOrdinalWords_WordFormIsIgnoredWithSpecificCulture(int number, string culture, string expected) { var cultureInfo = new CultureInfo(culture); var cultureSpecificNumber = number.ToOrdinalWords(cultureInfo); var normalForm1 = number.ToOrdinalWords(WordForm.Normal, cultureInfo); var abbrForm1 = number.ToOrdinalWords(WordForm.Abbreviation, cultureInfo); var normalForm2 = number.ToOrdinalWords(default, WordForm.Normal, cultureInfo); var abbrForm2 = number.ToOrdinalWords(default, WordForm.Abbreviation, cultureInfo); Assert.All( [ cultureSpecificNumber, normalForm1, abbrForm1, normalForm2, abbrForm2 ], item => Assert.Equal(expected, item)); } [Theory] [InlineData(0, "0-tuple")] [InlineData(1, "single")] [InlineData(2, "double")] [InlineData(3, "triple")] [InlineData(4, "quadruple")] [InlineData(5, "quintuple")] [InlineData(6, "sextuple")] [InlineData(7, "septuple")] [InlineData(8, "octuple")] [InlineData(9, "nonuple")] [InlineData(10, "decuple")] [InlineData(100, "centuple")] [InlineData(1000, "milluple")] public void ToTuple(int number, string expected) => Assert.Equal(expected, number.ToTuple()); [Theory] [InlineData(11, "en-US", "eleven")] [InlineData(22, "ar", "اثنان و عشرون")] [InlineData(40, "ru", "сорок")] [InlineData(1021, "hr", "tisuću dvadeset jedan")] [InlineData(11, "ta", "பதினொன்று")] [InlineData(12, "ta", "பனிரெண்டு")] [InlineData(555, "ta", "ஐந்நூற்று ஐம்பத்து ஐந்து")] public void ToWords_CanSpecifyCultureExplicitly(int number, string culture, string expected) => Assert.Equal(expected, number.ToWords(new(culture))); [Theory] [InlineData(1, "one")] [InlineData(3, "three")] public void ToWords_WordFormIsIgnored(int number, string expected) { var normalForm1 = number.ToWords(WordForm.Normal); var abbrForm1 = number.ToWords(WordForm.Abbreviation); var normalForm2 = number.ToWords(addAnd: true, WordForm.Normal); var abbrForm2 = number.ToWords(addAnd: true, WordForm.Abbreviation); var normalForm3 = ((long)number).ToWords(WordForm.Normal, default(GrammaticalGender)); var abbrFrom3 = ((long)number).ToWords(WordForm.Abbreviation, default(GrammaticalGender)); Assert.All( [ normalForm1, abbrForm1, normalForm2, abbrForm2, normalForm3, normalForm3, abbrFrom3 ], item => Assert.Equal(expected, item)); } [Theory] [InlineData(1, "en-US", "one")] [InlineData(3, "en-US", "three")] [InlineData(1, "sv-SE", "ett")] [InlineData(3, "sv-SE", "tre")] [InlineData(1, "ko-KR", "일")] [InlineData(3, "ko-KR", "삼")] public void ToWords_WordFormIsIgnoredWithSpecificCulture(int number, string culture, string expected) { var cultureInfo = new CultureInfo(culture); var cultureSpecificNumber = number.ToWords(cultureInfo); var normalForm1 = number.ToWords(addAnd: true, WordForm.Normal, cultureInfo); var abbrForm1 = number.ToWords(addAnd: true, WordForm.Abbreviation, cultureInfo); var normalForm2 = ((long)number).ToWords(WordForm.Normal, default, cultureInfo); var abbrForm2 = ((long)number).ToWords(WordForm.Abbreviation, default, cultureInfo); Assert.All( [ cultureSpecificNumber, normalForm1, abbrForm1, normalForm2, abbrForm2 ], item => Assert.Equal(expected, item)); } [Theory] [InlineData(-1, "minus one")] [InlineData(1, "one")] [InlineData(10, "ten")] [InlineData(11, "eleven")] [InlineData(20, "twenty")] [InlineData(122, "one hundred and twenty-two")] [InlineData(3501, "three thousand five hundred and one")] [InlineData(100, "one hundred")] [InlineData(1000, "one thousand")] [InlineData(1001, "one thousand and one")] [InlineData(1010, "one thousand and ten")] [InlineData(100000, "one hundred thousand")] [InlineData(1000000, "one million")] [InlineData(10000000, "ten million")] [InlineData(100000000, "one hundred million")] [InlineData(1000000000, "one billion")] [InlineData(111, "one hundred and eleven")] [InlineData(1111, "one thousand one hundred and eleven")] [InlineData(111111, "one hundred and eleven thousand one hundred and eleven")] [InlineData(1111111, "one million one hundred and eleven thousand one hundred and eleven")] [InlineData(11111111, "eleven million one hundred and eleven thousand one hundred and eleven")] [InlineData(111111111, "one hundred and eleven million one hundred and eleven thousand one hundred and eleven")] [InlineData(1111111111, "one billion one hundred and eleven million one hundred and eleven thousand one hundred and eleven")] [InlineData(123, "one hundred and twenty-three")] [InlineData(1234, "one thousand two hundred and thirty-four")] [InlineData(12345, "twelve thousand three hundred and forty-five")] [InlineData(123456, "one hundred and twenty-three thousand four hundred and fifty-six")] [InlineData(1234567, "one million two hundred and thirty-four thousand five hundred and sixty-seven")] [InlineData(12345678, "twelve million three hundred and forty-five thousand six hundred and seventy-eight")] [InlineData(123456789, "one hundred and twenty-three million four hundred and fifty-six thousand seven hundred and eighty-nine")] [InlineData(1234567890, "one billion two hundred and thirty-four million five hundred and sixty-seven thousand eight hundred and ninety")] public void ToWordsInt(int number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(-1L, "minus one")] [InlineData(1L, "one")] [InlineData(11L, "eleven")] [InlineData(111L, "one hundred and eleven")] [InlineData(1111L, "one thousand one hundred and eleven")] [InlineData(11111L, "eleven thousand one hundred and eleven")] [InlineData(111111L, "one hundred and eleven thousand one hundred and eleven")] [InlineData(1111111L, "one million one hundred and eleven thousand one hundred and eleven")] [InlineData(11111111L, "eleven million one hundred and eleven thousand one hundred and eleven")] [InlineData(111111111L, "one hundred and eleven million one hundred and eleven thousand one hundred and eleven")] [InlineData(1111111111L, "one billion one hundred and eleven million one hundred and eleven thousand one hundred and eleven")] [InlineData(11111111111L, "eleven billion one hundred and eleven million one hundred and eleven thousand one hundred and eleven")] [InlineData(111111111111L, "one hundred and eleven billion one hundred and eleven million one hundred and eleven thousand one hundred and eleven")] [InlineData(1111111111111L, "one trillion one hundred and eleven billion one hundred and eleven million one hundred and eleven thousand one hundred and eleven")] [InlineData(11111111111111L, "eleven trillion one hundred and eleven billion one hundred and eleven million one hundred and eleven thousand one hundred and eleven")] [InlineData(111111111111111L, "one hundred and eleven trillion one hundred and eleven billion one hundred and eleven million one hundred and eleven thousand one hundred and eleven")] [InlineData(1111111111111111L, "one quadrillion one hundred and eleven trillion one hundred and eleven billion one hundred and eleven million one hundred and eleven thousand one hundred and eleven")] [InlineData(11111111111111111L, "eleven quadrillion one hundred and eleven trillion one hundred and eleven billion one hundred and eleven million one hundred and eleven thousand one hundred and eleven")] [InlineData(111111111111111111L, "one hundred and eleven quadrillion one hundred and eleven trillion one hundred and eleven billion one hundred and eleven million one hundred and eleven thousand one hundred and eleven")] [InlineData(1111111111111111111L, "one quintillion one hundred and eleven quadrillion one hundred and eleven trillion one hundred and eleven billion one hundred and eleven million one hundred and eleven thousand one hundred and eleven")] public void ToWordsLong(long number, string expected) => Assert.Equal(expected, number.ToWords()); [Theory] [InlineData(3501L, "three thousand five hundred one", false)] public void ToWordsWithoutAnd(int number, string expected, bool addAnd) => Assert.Equal(expected, number.ToWords(addAnd)); } ================================================ FILE: tests/Humanizer.Tests/OrdinalizeTests.cs ================================================ [UseCulture("en-US")] public class OrdinalizeTests { [Theory] [InlineData("0", "0th")] [InlineData("1", "1st")] [InlineData("2", "2nd")] [InlineData("3", "3rd")] [InlineData("4", "4th")] [InlineData("5", "5th")] [InlineData("6", "6th")] [InlineData("7", "7th")] [InlineData("8", "8th")] [InlineData("9", "9th")] [InlineData("10", "10th")] [InlineData("11", "11th")] [InlineData("12", "12th")] [InlineData("13", "13th")] [InlineData("14", "14th")] [InlineData("20", "20th")] [InlineData("21", "21st")] [InlineData("22", "22nd")] [InlineData("23", "23rd")] [InlineData("24", "24th")] [InlineData("100", "100th")] [InlineData("101", "101st")] [InlineData("102", "102nd")] [InlineData("103", "103rd")] [InlineData("104", "104th")] [InlineData("110", "110th")] [InlineData("1000", "1000th")] [InlineData("1001", "1001st")] public void OrdinalizeString(string number, string ordinalized) => Assert.Equal(number.Ordinalize(), ordinalized); [Theory] [InlineData(0, "0th")] [InlineData(1, "1st")] [InlineData(2, "2nd")] [InlineData(3, "3rd")] [InlineData(4, "4th")] [InlineData(5, "5th")] [InlineData(6, "6th")] [InlineData(7, "7th")] [InlineData(8, "8th")] [InlineData(9, "9th")] [InlineData(10, "10th")] [InlineData(11, "11th")] [InlineData(12, "12th")] [InlineData(13, "13th")] [InlineData(14, "14th")] [InlineData(20, "20th")] [InlineData(21, "21st")] [InlineData(22, "22nd")] [InlineData(23, "23rd")] [InlineData(24, "24th")] [InlineData(100, "100th")] [InlineData(101, "101st")] [InlineData(102, "102nd")] [InlineData(103, "103rd")] [InlineData(104, "104th")] [InlineData(110, "110th")] [InlineData(1000, "1000th")] [InlineData(1001, "1001st")] public void OrdinalizeNumber(int number, string ordinalized) => Assert.Equal(number.Ordinalize(), ordinalized); [Theory] [InlineData(0)] [InlineData(1)] [InlineData(8)] public void OrdinalizeNumberGenderIsImmaterial(int number) { var masculineOrdinalized = number.Ordinalize(GrammaticalGender.Masculine); var feminineOrdinalized = number.Ordinalize(GrammaticalGender.Feminine); Assert.Equal(masculineOrdinalized, feminineOrdinalized); } [Theory] [InlineData("0")] [InlineData("1")] [InlineData("8")] public void OrdinalizeStringGenderIsImmaterial(string number) { var masculineOrdinalized = number.Ordinalize(GrammaticalGender.Masculine); var feminineOrdinalized = number.Ordinalize(GrammaticalGender.Feminine); Assert.Equal(masculineOrdinalized, feminineOrdinalized); } [Theory] [InlineData("en-US", "1", "1st")] [InlineData("nl-NL", "1", "1e")] public void OrdinalizeStringWithCultureOverridesCurrentCulture(string cultureName, string number, string ordinalized) { var culture = new CultureInfo(cultureName); Assert.Equal(number.Ordinalize(culture), ordinalized); } [Theory] [InlineData("en-US", 1, "1st")] [InlineData("nl-NL", 1, "1e")] public void OrdinalizeNumberWithCultureOverridesCurrentCulture(string cultureName, int number, string ordinalized) { var culture = new CultureInfo(cultureName); Assert.Equal(number.Ordinalize(culture), ordinalized); } [Theory] [InlineData(0)] [InlineData(1)] [InlineData(8)] public void OrdinalizeNumberWithOverridenCultureGenderIsImmaterial(int number) { var culture = new CultureInfo("nl-NL"); var masculineOrdinalized = number.Ordinalize(GrammaticalGender.Masculine, culture); var feminineOrdinalized = number.Ordinalize(GrammaticalGender.Feminine, culture); Assert.Equal(masculineOrdinalized, feminineOrdinalized); } [Theory] [InlineData("0")] [InlineData("1")] [InlineData("8")] public void OrdinalizeStringWithOverridenGenderIsImmaterial(string number) { var culture = new CultureInfo("nl-NL"); var masculineOrdinalized = number.Ordinalize(GrammaticalGender.Masculine, culture); var feminineOrdinalized = number.Ordinalize(GrammaticalGender.Feminine, culture); Assert.Equal(masculineOrdinalized, feminineOrdinalized); } [Theory] [InlineData(1, WordForm.Normal, "es-ES", "1.º")] [InlineData(1, WordForm.Abbreviation, "es-ES", "1.er")] [InlineData(1, WordForm.Normal, "en-US", "1st")] [InlineData(1, WordForm.Abbreviation, "en-US", "1st")] public void OrdinalizeNumberWithOverridenCultureAndSpecificForm(int number, WordForm wordForm, string cultureName, string expected) { var culture = new CultureInfo(cultureName); Assert.Equal(expected, number.Ordinalize(culture, wordForm)); Assert.Equal(expected, number .ToString(culture) .Ordinalize(culture, wordForm)); } [Theory] [InlineData(1, WordForm.Normal, GrammaticalGender.Masculine, "es-ES", "1.º")] [InlineData(1, WordForm.Abbreviation, GrammaticalGender.Masculine, "es-ES", "1.er")] [InlineData(1, WordForm.Normal, GrammaticalGender.Feminine, "es-ES", "1.ª")] [InlineData(1, WordForm.Abbreviation, GrammaticalGender.Feminine, "es-ES", "1.ª")] [InlineData(1, WordForm.Normal, GrammaticalGender.Masculine, "en-US", "1st")] [InlineData(1, WordForm.Normal, GrammaticalGender.Feminine, "en-US", "1st")] public void OrdinalizeNumberWithOverridenCultureAndGenderAndForm( int number, WordForm wordForm, GrammaticalGender gender, string cultureName, string expected) { var culture = new CultureInfo(cultureName); Assert.Equal(expected, number.Ordinalize(gender, culture, wordForm)); Assert.Equal(expected, number .ToString(culture) .Ordinalize(gender, culture, wordForm)); } } ================================================ FILE: tests/Humanizer.Tests/ResourceKeyTests.cs ================================================ #pragma warning disable xUnit1026 // Theory methods should use all of their parameters public class ResourceKeyTests { [Theory] [MemberData(nameof(DateHumanizeResourceKeys))] public void DateHumanizeKeysGeneration(int instance, string expected, string actual) => Assert.Equal(expected, actual); [Theory] [MemberData(nameof(TimeSpanHumanizeResourceKeys))] public void TimeSpanHumanizeKeysGeneration(int instance, string expected, string actual) => Assert.Equal(expected, actual); [Theory] [MemberData(nameof(DateHumanizeResourceKeys))] public void DateHumanizeKeysExistence(int instance, string expectedResourceKey, string generatedResourceKey) => Assert.NotNull(Resources.GetResource(generatedResourceKey)); [Theory] [MemberData(nameof(TimeSpanHumanizeResourceKeys))] public void TimeSpanHumanizeKeysExistence(int instance, string expectedResourceKey, string generatedResourceKey) => Assert.NotNull(Resources.GetResource(generatedResourceKey)); public static IEnumerable DateHumanizeResourceKeys => [ [0, "DateHumanize_SingleSecondAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Second, Tense.Past)], [0, "DateHumanize_SingleMinuteAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Minute, Tense.Past)], [0, "DateHumanize_SingleHourAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Hour, Tense.Past)], [0, "DateHumanize_SingleDayAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Day, Tense.Past)], [0, "DateHumanize_SingleMonthAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Month, Tense.Past)], [0, "DateHumanize_SingleYearAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Year, Tense.Past)], [0, "DateHumanize_MultipleSecondsAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Second, Tense.Past, count: 10)], [0, "DateHumanize_MultipleMinutesAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Minute, Tense.Past, count: 10)], [0, "DateHumanize_MultipleHoursAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Hour, Tense.Past, count: 10)], [0, "DateHumanize_MultipleDaysAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Day, Tense.Past, count: 10)], [0, "DateHumanize_MultipleMonthsAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Month, Tense.Past, count: 10)], [0, "DateHumanize_MultipleYearsAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Year, Tense.Past, count: 10)], [0, "DateHumanize_SingleSecondFromNow", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Second, timeUnitTense: Tense.Future, count: 1)], [0, "DateHumanize_SingleMinuteFromNow", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Minute, timeUnitTense: Tense.Future, count: 1)], [0, "DateHumanize_SingleHourFromNow", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Hour, timeUnitTense: Tense.Future, count: 1)], [0, "DateHumanize_SingleDayFromNow", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Day, timeUnitTense: Tense.Future, count: 1)], [0, "DateHumanize_SingleMonthFromNow", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Month, timeUnitTense: Tense.Future, count: 1)], [0, "DateHumanize_SingleYearFromNow", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Year, timeUnitTense: Tense.Future, count: 1)], [0, "DateHumanize_MultipleSecondsFromNow", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Second, timeUnitTense: Tense.Future, count: 10)], [0, "DateHumanize_MultipleMinutesFromNow", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Minute, timeUnitTense: Tense.Future, count: 10)], [0, "DateHumanize_MultipleHoursFromNow", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Hour, timeUnitTense: Tense.Future, count: 10)], [0, "DateHumanize_MultipleDaysFromNow", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Day, timeUnitTense: Tense.Future, count: 10)], [0, "DateHumanize_MultipleMonthsFromNow", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Month, timeUnitTense: Tense.Future, count: 10)], [0, "DateHumanize_MultipleYearsFromNow", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Year, timeUnitTense: Tense.Future, count: 10)], [0, "DateHumanize_Now", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Millisecond, Tense.Past, count: 0)], [1, "DateHumanize_Now", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Second, Tense.Past, count: 0)], [2, "DateHumanize_Now", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Minute, Tense.Past, count: 0)], [3, "DateHumanize_Now", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Hour, Tense.Past, count: 0)], [4, "DateHumanize_Now", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Day, Tense.Past, count: 0)], [5, "DateHumanize_Now", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Week, Tense.Past, count: 0)], [6, "DateHumanize_Now", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Month, Tense.Past, count: 0)], [7, "DateHumanize_Now", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Year, Tense.Past, count: 0)], [8, "DateHumanize_Now", ResourceKeys.DateHumanize.Now] ]; public static IEnumerable TimeSpanHumanizeResourceKeys => [ [0, "TimeSpanHumanize_SingleMillisecond", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Millisecond)], [0, "TimeSpanHumanize_SingleSecond", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Second)], [0, "TimeSpanHumanize_SingleMinute", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Minute)], [0, "TimeSpanHumanize_SingleHour", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Hour)], [0, "TimeSpanHumanize_SingleDay", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Day)], [0, "TimeSpanHumanize_SingleWeek", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Week)], [0, "TimeSpanHumanize_SingleMonth", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Month)], [0, "TimeSpanHumanize_SingleYear", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Year)], [0, "TimeSpanHumanize_MultipleMilliseconds", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Millisecond, 10)], [0, "TimeSpanHumanize_MultipleSeconds", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Second, 10)], [0, "TimeSpanHumanize_MultipleMinutes", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Minute, 10)], [0, "TimeSpanHumanize_MultipleHours", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Hour, 10)], [0, "TimeSpanHumanize_MultipleDays", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Day, 10)], [0, "TimeSpanHumanize_MultipleWeeks", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Week, 10)], [0, "TimeSpanHumanize_MultipleMonths", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Month, 10)], [0, "TimeSpanHumanize_MultipleYears", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Year, 10)], [0, "TimeSpanHumanize_Zero", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Millisecond, 0, true)], [1, "TimeSpanHumanize_Zero", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Second, 0, true)], [2, "TimeSpanHumanize_Zero", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Minute, 0, true)], [3, "TimeSpanHumanize_Zero", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Hour, 0, true)], [4, "TimeSpanHumanize_Zero", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Day, 0, true)], [5, "TimeSpanHumanize_Zero", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Week, 0, true)], [6, "TimeSpanHumanize_Zero", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Month, 0, true)], [7, "TimeSpanHumanize_Zero", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Year, 0, true)], [1, "TimeSpanHumanize_MultipleMilliseconds", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Millisecond, 0)], [2, "TimeSpanHumanize_MultipleSeconds", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Second, 0)], [3, "TimeSpanHumanize_MultipleMinutes", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Minute, 0)], [4, "TimeSpanHumanize_MultipleHours", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Hour, 0)], [5, "TimeSpanHumanize_MultipleDays", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Day, 0)], [6, "TimeSpanHumanize_MultipleWeeks", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Week, 0)], [7, "TimeSpanHumanize_MultipleMonths", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Month, 0)], [8, "TimeSpanHumanize_MultipleYears", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Year, 0)] ]; } #pragma warning restore xUnit1026 // Theory methods should use all of their parameters ================================================ FILE: tests/Humanizer.Tests/RomanNumeralTests.cs ================================================ public class RomanNumeralTests { [Theory] [InlineData(1, "I")] [InlineData(2, "II")] [InlineData(3, "III")] [InlineData(4, "IV")] [InlineData(5, "V")] [InlineData(6, "VI")] [InlineData(7, "VII")] [InlineData(8, "VIII")] [InlineData(9, "IX")] [InlineData(10, "X")] [InlineData(11, "XI")] [InlineData(12, "XII")] [InlineData(40, "XL")] [InlineData(50, "L")] [InlineData(90, "XC")] [InlineData(100, "C")] [InlineData(400, "CD")] [InlineData(500, "D")] [InlineData(3999, "MMMCMXCIX")] public void ToRoman(int input, string expected) => Assert.Equal(expected, input.ToRoman()); [Theory] [InlineData(1, "I")] [InlineData(2, "II")] [InlineData(3, "III")] [InlineData(4, "IV")] [InlineData(5, "V")] [InlineData(6, "VI")] [InlineData(7, "VII")] [InlineData(8, "VIII")] [InlineData(9, "IX")] [InlineData(10, "X")] [InlineData(11, "XI")] [InlineData(12, "XII")] [InlineData(40, "XL")] [InlineData(50, "L")] [InlineData(90, "XC")] [InlineData(100, "C")] [InlineData(400, "CD")] [InlineData(500, "D")] [InlineData(3999, "MMMCMXCIX")] public void FromRoman(int expected, string input) => Assert.Equal(expected, input.FromRoman()); } ================================================ FILE: tests/Humanizer.Tests/StringDehumanizeTests.cs ================================================ public class StringDehumanizeTests { [Theory] [InlineData("", "")] [InlineData("Pascal case sentence is pascalized", "PascalCaseSentenceIsPascalized")] [InlineData("Title Case Sentence Is Pascalized", "TitleCaseSentenceIsPascalized")] [InlineData("Mixed case sentence Is Pascalized", "MixedCaseSentenceIsPascalized")] [InlineData("lower case sentence is pascalized", "LowerCaseSentenceIsPascalized")] [InlineData("A special character is removed?", "ASpecialCharacterIsRemoved")] [InlineData("A special character is removed after a space ?", "ASpecialCharacterIsRemovedAfterASpace")] [InlineData("Internal special characters ?)@ are removed", "InternalSpecialCharactersAreRemoved")] [InlineData("AlreadyDehumanizedStringIsUntouched", "AlreadyDehumanizedStringIsUntouched")] [InlineData("CanDehumanizeIntoAPascalCaseWord", "CanDehumanizeIntoAPascalCaseWord")] [InlineData("CanDehumanizeIntoAPascalCaseWord AndAnother", "CanDehumanizeIntoAPascalCaseWordAndAnother")] [InlineData("OneAndTwo", "OneAndTwo")] [InlineData("OneOrTwo", "OneOrTwo")] [InlineData("OneOfTwo", "OneOfTwo")] [InlineData("OneButTwo", "OneButTwo")] [InlineData("OneATwo", "OneATwo")] [InlineData("OneAsTwo", "OneAsTwo")] [InlineData("OneYetTwo", "OneYetTwo")] [InlineData("OneNorTwo", "OneNorTwo")] [InlineData("WordSoTwo", "WordSoTwo")] public void CanDehumanizeIntoAPascalCaseWord(string input, string expectedResult) => Assert.Equal(expectedResult, input.Dehumanize()); } ================================================ FILE: tests/Humanizer.Tests/StringHumanizeTests.cs ================================================ public class StringHumanizeTests { [Theory] [InlineData("PascalCaseInputStringIsTurnedIntoSentence", "Pascal case input string is turned into sentence")] [InlineData("WhenIUseAnInputAHere", "When I use an input a here")] [InlineData("10IsInTheBegining", "10 is in the begining")] [InlineData("NumberIsFollowedByLowerCase5th", "Number is followed by lower case 5th")] [InlineData("NumberIsAtTheEnd100", "Number is at the end 100")] [InlineData("XIsFirstWordInTheSentence", "X is first word in the sentence")] [InlineData("XIsFirstWordInTheSentence ThenThereIsASpace", "X is first word in the sentence then there is a space")] [InlineData("ContainsSpecial?)@Characters", "Contains special characters")] [InlineData("a", "A")] [InlineData("A", "A")] [InlineData("?)@", "")] [InlineData("?", "")] [InlineData("", "")] [InlineData("JeNeParlePasFrançais", "Je ne parle pas français")] public void CanHumanizeStringInPascalCase(string input, string expectedResult) => Assert.Equal(expectedResult, input.Humanize()); [Theory, UseCulture("tr-TR")] [InlineData("istanbul", "İstanbul")] [InlineData("diyarbakır", "Diyarbakır")] public void CanHumanizeStringInPascalCaseInTurkish(string input, string expectedResult) => Assert.Equal(expectedResult, input.Humanize()); [Theory, UseCulture("ar")] [InlineData("جمهورية ألمانيا الاتحادية", "جمهورية ألمانيا الاتحادية")] public void CanHumanizeOtherUnicodeLetter(string input, string expectedResult) => Assert.Equal(expectedResult, input.Humanize()); [Theory] [InlineData("Underscored_input_string_is_turned_into_sentence", "Underscored input string is turned into sentence")] [InlineData("Underscored_input_String_is_turned_INTO_sentence", "Underscored input String is turned INTO sentence")] [InlineData("TEST 1 - THIS IS A TEST", "TEST 1 THIS IS A TEST")] [InlineData("TEST 1 -THIS IS A TEST", "TEST 1 THIS IS A TEST")] [InlineData("TEST 1- THIS IS A TEST", "TEST 1 THIS IS A TEST")] [InlineData("TEST 1_ THIS IS A TEST", "TEST 1 THIS IS A TEST")] [InlineData("TEST 1 _THIS IS A TEST", "TEST 1 THIS IS A TEST")] [InlineData("TEST 1 _ THIS IS A TEST", "TEST 1 THIS IS A TEST")] [InlineData("TEST 1 - THIS_IS_A_TEST", "TEST 1 THIS IS A TEST")] [InlineData("TEST 1 - THIS is A Test", "TEST 1 THIS is A test")] public void CanHumanizeStringWithUnderscoresAndDashes(string input, string expectedResult) => Assert.Equal(expectedResult, input.Humanize()); [Theory] [InlineData("HTML", "HTML")] [InlineData("TheHTMLLanguage", "The HTML language")] [InlineData("HTMLIsTheLanguage", "HTML is the language")] [InlineData("TheLanguage IsHTML", "The language is HTML")] [InlineData("TheLanguageIsHTML", "The language is HTML")] [InlineData("HTML5", "HTML 5")] [InlineData("1HTML", "1 HTML")] public void CanHumanizeStringWithAcronyms(string input, string expectedValue) => Assert.Equal(expectedValue, input.Humanize()); [Theory] [InlineData("CanReturnTitleCase", "Can Return Title Case")] [InlineData("Can_return_title_Case", "Can Return Title Case")] [InlineData("In titles use lower case for prepositions an article or conjunctions", "In Titles Use Lower Case for Prepositions an Article or Conjunctions")] [InlineData("Title_humanization_Honors_ALLCAPS", "Title Humanization Honors ALLCAPS")] [InlineData("MühldorferStraße23", "Mühldorfer Straße 23")] [InlineData("mühldorfer_STRAẞE_23", "Mühldorfer STRAẞE 23")] [InlineData("CAN RETURN TITLE CASE", "Can Return Title Case")] public void CanHumanizeIntoTitleCase(string input, string expectedResult) => Assert.Equal(expectedResult, input.Humanize(LetterCasing.Title)); [Theory] [InlineData("CanReturnLowerCase", "can return lower case")] [InlineData("LOWERCASE", "lowercase")] [InlineData("STRAẞE", "straße")] public void CanHumanizeIntoLowerCase(string input, string expectedResult) => Assert.Equal(expectedResult, input.Humanize(LetterCasing.LowerCase)); [Theory] [InlineData("CanReturnSentenceCase", "Can return sentence case")] [InlineData("", "")] [InlineData("égoïste", "Égoïste")] [InlineData("Normal; Normal and PascalCase", "Normal; normal and pascal case")] [InlineData("I,and No One else", "I, and no one else")] public void CanHumanizeIntoSentenceCase(string input, string expectedResult) => Assert.Equal(expectedResult, input.Humanize(LetterCasing.Sentence)); [Theory] [InlineData("CanHumanizeIntoUpperCase", "CAN HUMANIZE INTO UPPER CASE")] [InlineData("Can_Humanize_into_Upper_case", "CAN HUMANIZE INTO UPPER CASE")] [InlineData("coûts_privés", "COÛTS PRIVÉS")] public void CanHumanizeIntoUpperCase(string input, string expectedResult) => Assert.Equal(expectedResult, input.Humanize(LetterCasing.AllCaps)); } ================================================ FILE: tests/Humanizer.Tests/TimeOnlyHumanizeTests.cs ================================================ #if NET6_0_OR_GREATER [UseCulture("en-US")] public class TimeOnlyHumanizeTests { [Fact] public void DefaultStrategy_SameTime() { Configurator.TimeOnlyHumanizeStrategy = new DefaultTimeOnlyHumanizeStrategy(); var inputTime = new TimeOnly(13, 07, 05); var baseTime = new TimeOnly(13, 07, 05); const string expectedResult = "now"; var actualResult = inputTime.Humanize(baseTime); Assert.Equal(expectedResult, actualResult); } [Fact] public void DefaultStrategy_HoursApart() { Configurator.TimeOnlyHumanizeStrategy = new DefaultTimeOnlyHumanizeStrategy(); var inputTime = new TimeOnly(13, 08, 05); var baseTime = new TimeOnly(1, 08, 05); const string expectedResult = "12 hours from now"; var actualResult = inputTime.Humanize(baseTime); Assert.Equal(expectedResult, actualResult); } [Fact] public void DefaultStrategy_HoursAgo() { Configurator.TimeOnlyHumanizeStrategy = new DefaultTimeOnlyHumanizeStrategy(); var inputTime = new TimeOnly(13, 07, 02); var baseTime = new TimeOnly(17, 07, 05); const string expectedResult = "4 hours ago"; var actualResult = inputTime.Humanize(baseTime); Assert.Equal(expectedResult, actualResult); } [Fact] public void PrecisionStrategy_NextDay() { Configurator.TimeOnlyHumanizeStrategy = new PrecisionTimeOnlyHumanizeStrategy(0.75); var inputTime = new TimeOnly(18, 10, 49); var baseTime = new TimeOnly(13, 07, 04); const string expectedResult = "5 hours from now"; var actualResult = inputTime.Humanize(baseTime); Assert.Equal(expectedResult, actualResult); } [Fact] public void Never() { TimeOnly? never = null; Assert.Equal("never", never.Humanize()); } [Fact] public void Nullable_ExpectSame() { TimeOnly? never = new TimeOnly(23, 12, 7); Assert.Equal(never.Value.Humanize(), never.Humanize()); } } #endif ================================================ FILE: tests/Humanizer.Tests/TimeSpanHumanizeTests.cs ================================================ [UseCulture("en-US")] public class TimeSpanHumanizeTests { [Fact] public void AllTimeSpansMustBeUniqueForASequenceOfDays() { var culture = new CultureInfo("en-US"); var qry = from i in Enumerable.Range(0, 100000) let ts = TimeSpan.FromDays(i) let text = ts.Humanize(precision: 3, culture: culture, maxUnit: TimeUnit.Year) select text; var grouping = from t in qry group t by t into g select new { g.Key, Count = g.Count() }; var allUnique = grouping.All(g => g.Count == 1); Assert.True(allUnique); } [Theory] [InlineData(365, "11 months, 30 days")] [InlineData(365 + 1, "1 year")] [InlineData(365 + 365, "1 year, 11 months, 29 days")] [InlineData(365 + 365 + 1, "2 years")] [InlineData(365 + 365 + 365, "2 years, 11 months, 29 days")] [InlineData(365 + 365 + 365 + 1, "3 years")] [InlineData(365 + 365 + 365 + 365, "3 years, 11 months, 29 days")] [InlineData(365 + 365 + 365 + 365 + 1, "4 years")] [InlineData(365 + 365 + 365 + 365 + 366, "4 years, 11 months, 30 days")] [InlineData(365 + 365 + 365 + 365 + 366 + 1, "5 years")] public void Years(int days, string expected) { var actual = TimeSpan.FromDays(days).Humanize(precision: 7, maxUnit: TimeUnit.Year); Assert.Equal(expected, actual); } [Theory] [InlineData(30, "4 weeks, 2 days")] [InlineData(30 + 1, "1 month")] [InlineData(30 + 30, "1 month, 29 days")] [InlineData(30 + 30 + 1, "2 months")] [InlineData(30 + 30 + 31, "2 months, 30 days")] [InlineData(30 + 30 + 31 + 1, "3 months")] [InlineData(30 + 30 + 31 + 30, "3 months, 29 days")] [InlineData(30 + 30 + 31 + 30 + 1, "4 months")] [InlineData(30 + 30 + 31 + 30 + 31, "4 months, 30 days")] [InlineData(30 + 30 + 31 + 30 + 31 + 1, "5 months")] [InlineData(365, "11 months, 30 days")] [InlineData(366, "1 year")] public void Months(int days, string expected) { var actual = TimeSpan.FromDays(days).Humanize(precision: 7, maxUnit: TimeUnit.Year); Assert.Equal(expected, actual); } [Theory] [InlineData(14, "2 weeks")] [InlineData(7, "1 week")] [InlineData(-14, "2 weeks")] [InlineData(-7, "1 week")] [InlineData(730, "104 weeks")] public void Weeks(int days, string expected) { var actual = TimeSpan.FromDays(days).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(6, "6 days")] [InlineData(2, "2 days")] [InlineData(1, "1 day")] [InlineData(-6, "6 days")] [InlineData(-2, "2 days")] [InlineData(-1, "1 day")] public void Days(int days, string expected) { var actual = TimeSpan.FromDays(days).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 hours")] [InlineData(1, "1 hour")] [InlineData(-2, "2 hours")] [InlineData(-1, "1 hour")] public void Hours(int hours, string expected) { var actual = TimeSpan.FromHours(hours).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2, "2 minutes")] [InlineData(1, "1 minute")] [InlineData(-2, "2 minutes")] [InlineData(-1, "1 minute")] public void Minutes(int minutes, string expected) { var actual = TimeSpan.FromMinutes(minutes).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(135, "2 minutes")] [InlineData(60, "1 minute")] [InlineData(2, "2 seconds")] [InlineData(1, "1 second")] [InlineData(-135, "2 minutes")] [InlineData(-60, "1 minute")] [InlineData(-2, "2 seconds")] [InlineData(-1, "1 second")] public void Seconds(int seconds, string expected) { var actual = TimeSpan.FromSeconds(seconds).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(2500, "2 seconds")] [InlineData(1400, "1 second")] [InlineData(2, "2 milliseconds")] [InlineData(1, "1 millisecond")] [InlineData(-2500, "2 seconds")] [InlineData(-1400, "1 second")] [InlineData(-2, "2 milliseconds")] [InlineData(-1, "1 millisecond")] public void Milliseconds(int ms, string expected) { var actual = TimeSpan.FromMilliseconds(ms).Humanize(); Assert.Equal(expected, actual); } [Theory] [InlineData(4, false, "4 days old")] [InlineData(23, false, "3 weeks old")] [InlineData(64, false, "2 months old")] [InlineData(367, true, "one year old")] [InlineData(750, true, "two years old")] public void Age(int days, bool toWords, string expected) { var actual = TimeSpan.FromDays(days).ToAge(toWords: toWords); Assert.Equal(expected, actual); } [Theory] [InlineData((long)366 * 24 * 60 * 60 * 1000, "12 months", TimeUnit.Month)] [InlineData((long)6 * 7 * 24 * 60 * 60 * 1000, "6 weeks", TimeUnit.Week)] [InlineData(7 * 24 * 60 * 60 * 1000, "7 days", TimeUnit.Day)] [InlineData(24 * 60 * 60 * 1000, "24 hours", TimeUnit.Hour)] [InlineData(60 * 60 * 1000, "60 minutes", TimeUnit.Minute)] [InlineData(60 * 1000, "60 seconds", TimeUnit.Second)] [InlineData(1000, "1000 milliseconds", TimeUnit.Millisecond)] public void TimeSpanWithMaxTimeUnit(long ms, string expected, TimeUnit maxUnit) { var actual = TimeSpan.FromMilliseconds(ms).Humanize(maxUnit: maxUnit); Assert.Equal(expected, actual); } [Theory] [InlineData(10, "10 milliseconds", TimeUnit.Millisecond)] [InlineData(10, "no time", TimeUnit.Second, true)] [InlineData(10, "no time", TimeUnit.Minute, true)] [InlineData(10, "no time", TimeUnit.Hour, true)] [InlineData(10, "no time", TimeUnit.Day, true)] [InlineData(10, "no time", TimeUnit.Week, true)] [InlineData(10, "0 seconds", TimeUnit.Second)] [InlineData(10, "0 minutes", TimeUnit.Minute)] [InlineData(10, "0 hours", TimeUnit.Hour)] [InlineData(10, "0 days", TimeUnit.Day)] [InlineData(10, "0 weeks", TimeUnit.Week)] [InlineData(2500, "2 seconds, 500 milliseconds", TimeUnit.Millisecond)] [InlineData(2500, "2 seconds", TimeUnit.Second)] [InlineData(2500, "no time", TimeUnit.Minute, true)] [InlineData(2500, "no time", TimeUnit.Hour, true)] [InlineData(2500, "no time", TimeUnit.Day, true)] [InlineData(2500, "no time", TimeUnit.Week, true)] [InlineData(2500, "0 minutes", TimeUnit.Minute)] [InlineData(2500, "0 hours", TimeUnit.Hour)] [InlineData(2500, "0 days", TimeUnit.Day)] [InlineData(2500, "0 weeks", TimeUnit.Week)] [InlineData(122500, "2 minutes, 2 seconds, 500 milliseconds", TimeUnit.Millisecond)] [InlineData(122500, "2 minutes, 2 seconds", TimeUnit.Second)] [InlineData(122500, "2 minutes", TimeUnit.Minute)] [InlineData(122500, "no time", TimeUnit.Hour, true)] [InlineData(122500, "no time", TimeUnit.Day, true)] [InlineData(122500, "no time", TimeUnit.Week, true)] [InlineData(122500, "0 hours", TimeUnit.Hour)] [InlineData(122500, "0 days", TimeUnit.Day)] [InlineData(122500, "0 weeks", TimeUnit.Week)] [InlineData(3722500, "1 hour, 2 minutes, 2 seconds, 500 milliseconds", TimeUnit.Millisecond)] [InlineData(3722500, "1 hour, 2 minutes, 2 seconds", TimeUnit.Second)] [InlineData(3722500, "1 hour, 2 minutes", TimeUnit.Minute)] [InlineData(3722500, "1 hour", TimeUnit.Hour)] [InlineData(3722500, "no time", TimeUnit.Day, true)] [InlineData(3722500, "no time", TimeUnit.Week, true)] [InlineData(3722500, "0 days", TimeUnit.Day)] [InlineData(3722500, "0 weeks", TimeUnit.Week)] [InlineData(90122500, "1 day, 1 hour, 2 minutes, 2 seconds, 500 milliseconds", TimeUnit.Millisecond)] [InlineData(90122500, "1 day, 1 hour, 2 minutes, 2 seconds", TimeUnit.Second)] [InlineData(90122500, "1 day, 1 hour, 2 minutes", TimeUnit.Minute)] [InlineData(90122500, "1 day, 1 hour", TimeUnit.Hour)] [InlineData(90122500, "1 day", TimeUnit.Day)] [InlineData(90122500, "no time", TimeUnit.Week, true)] [InlineData(90122500, "0 weeks", TimeUnit.Week)] [InlineData(694922500, "1 week, 1 day, 1 hour, 2 minutes, 2 seconds, 500 milliseconds", TimeUnit.Millisecond)] [InlineData(694922500, "1 week, 1 day, 1 hour, 2 minutes, 2 seconds", TimeUnit.Second)] [InlineData(694922500, "1 week, 1 day, 1 hour, 2 minutes", TimeUnit.Minute)] [InlineData(694922500, "1 week, 1 day, 1 hour", TimeUnit.Hour)] [InlineData(694922500, "1 week, 1 day", TimeUnit.Day)] [InlineData(694922500, "1 week", TimeUnit.Week)] [InlineData(2768462500, "1 month, 1 day, 1 hour, 1 minute, 2 seconds, 500 milliseconds", TimeUnit.Millisecond)] [InlineData(2768462500, "1 month, 1 day, 1 hour, 1 minute, 2 seconds", TimeUnit.Second)] [InlineData(2768462500, "1 month, 1 day, 1 hour, 1 minute", TimeUnit.Minute)] [InlineData(2768462500, "1 month, 1 day, 1 hour", TimeUnit.Hour)] [InlineData(2768462500, "1 month, 1 day", TimeUnit.Day)] [InlineData(2768462500, "1 month", TimeUnit.Week)] [InlineData(2768462500, "1 month", TimeUnit.Month)] [InlineData(2768462500, "no time", TimeUnit.Year, true)] [InlineData(2768462500, "0 years", TimeUnit.Year)] [InlineData(34390862500, "1 year, 1 month, 2 days, 1 hour, 1 minute, 2 seconds, 500 milliseconds", TimeUnit.Millisecond)] [InlineData(34390862500, "1 year, 1 month, 2 days, 1 hour, 1 minute, 2 seconds", TimeUnit.Second)] [InlineData(34390862500, "1 year, 1 month, 2 days, 1 hour, 1 minute", TimeUnit.Minute)] [InlineData(34390862500, "1 year, 1 month, 2 days, 1 hour", TimeUnit.Hour)] [InlineData(34390862500, "1 year, 1 month, 2 days", TimeUnit.Day)] [InlineData(34390862500, "1 year, 1 month", TimeUnit.Week)] [InlineData(34390862500, "1 year, 1 month", TimeUnit.Month)] [InlineData(34390862500, "1 year", TimeUnit.Year)] public void TimeSpanWithMinTimeUnit(long ms, string expected, TimeUnit minUnit, bool toWords = false) { var actual = TimeSpan.FromMilliseconds(ms).Humanize(minUnit: minUnit, precision: 7, maxUnit: TimeUnit.Year, toWords: toWords); Assert.Equal(expected, actual); } [Theory] [InlineData(0, 3, "no time", true)] [InlineData(0, 2, "no time", true)] [InlineData(0, 3, "0 milliseconds")] [InlineData(0, 2, "0 milliseconds")] [InlineData(10, 2, "10 milliseconds")] [InlineData(1400, 2, "1 second, 400 milliseconds")] [InlineData(2500, 2, "2 seconds, 500 milliseconds")] [InlineData(120000, 2, "2 minutes")] [InlineData(62000, 2, "1 minute, 2 seconds")] [InlineData(62020, 2, "1 minute, 2 seconds")] [InlineData(62020, 3, "1 minute, 2 seconds, 20 milliseconds")] [InlineData(3600020, 4, "1 hour, 20 milliseconds")] [InlineData(3600020, 3, "1 hour, 20 milliseconds")] [InlineData(3600020, 2, "1 hour, 20 milliseconds")] [InlineData(3600020, 1, "1 hour")] [InlineData(3603001, 2, "1 hour, 3 seconds")] [InlineData(3603001, 3, "1 hour, 3 seconds, 1 millisecond")] [InlineData(86400000, 3, "1 day")] [InlineData(86400000, 2, "1 day")] [InlineData(86400000, 1, "1 day")] [InlineData(86401000, 1, "1 day")] [InlineData(86401000, 2, "1 day, 1 second")] [InlineData(86401200, 2, "1 day, 1 second")] [InlineData(86401200, 3, "1 day, 1 second, 200 milliseconds")] [InlineData(1296000000, 1, "2 weeks")] [InlineData(1296000000, 2, "2 weeks, 1 day")] [InlineData(1299600000, 2, "2 weeks, 1 day")] [InlineData(1299600000, 3, "2 weeks, 1 day, 1 hour")] [InlineData(1299630020, 3, "2 weeks, 1 day, 1 hour")] [InlineData(1299630020, 4, "2 weeks, 1 day, 1 hour, 30 seconds")] [InlineData(1299630020, 5, "2 weeks, 1 day, 1 hour, 30 seconds, 20 milliseconds")] [InlineData(2768462500, 6, "1 month, 1 day, 1 hour, 1 minute, 2 seconds, 500 milliseconds")] [InlineData(2768462500, 5, "1 month, 1 day, 1 hour, 1 minute, 2 seconds")] [InlineData(2768462500, 4, "1 month, 1 day, 1 hour, 1 minute")] [InlineData(2768462500, 3, "1 month, 1 day, 1 hour")] [InlineData(2768462500, 2, "1 month, 1 day")] [InlineData(2768462500, 1, "1 month")] [InlineData(34390862500, 7, "1 year, 1 month, 2 days, 1 hour, 1 minute, 2 seconds, 500 milliseconds")] [InlineData(34390862500, 6, "1 year, 1 month, 2 days, 1 hour, 1 minute, 2 seconds")] [InlineData(34390862500, 5, "1 year, 1 month, 2 days, 1 hour, 1 minute")] [InlineData(34390862500, 4, "1 year, 1 month, 2 days, 1 hour")] [InlineData(34390862500, 3, "1 year, 1 month, 2 days")] [InlineData(34390862500, 2, "1 year, 1 month")] [InlineData(34390862500, 1, "1 year")] public void TimeSpanWithPrecision(long milliseconds, int precision, string expected, bool toWords = false) { var actual = TimeSpan.FromMilliseconds(milliseconds).Humanize(precision, maxUnit: TimeUnit.Year, toWords: toWords); Assert.Equal(expected, actual); } [Theory] [InlineData(3 * 7 + 4, 2, "3 weeks, 4 days")] [InlineData(6 * 7 + 3, 2, "6 weeks, 3 days")] [InlineData(72 * 7 + 6, 2, "72 weeks, 6 days")] public void DaysWithPrecision(int days, int precision, string expected) { var actual = TimeSpan.FromDays(days).Humanize(precision: precision); Assert.Equal(expected, actual); } [Theory] [InlineData(50)] [InlineData(52)] public void TimeSpanWithMinAndMaxUnits_DoesNotReportExcessiveTime(int minutes) { var actual = TimeSpan.FromMinutes(minutes).Humanize(2, null, TimeUnit.Hour, TimeUnit.Minute); var expected = TimeSpan.FromMinutes(minutes).Humanize(2); Assert.Equal(expected, actual); } [Theory] [InlineData(0, 3, "no time", true)] [InlineData(0, 2, "no time", true)] [InlineData(0, 3, "0 milliseconds")] [InlineData(0, 2, "0 milliseconds")] [InlineData(10, 2, "10 milliseconds")] [InlineData(1400, 2, "1 second, 400 milliseconds")] [InlineData(2500, 2, "2 seconds, 500 milliseconds")] [InlineData(60001, 1, "1 minute")] [InlineData(60001, 2, "1 minute")] [InlineData(60001, 3, "1 minute, 1 millisecond")] [InlineData(120000, 2, "2 minutes")] [InlineData(62000, 2, "1 minute, 2 seconds")] [InlineData(62020, 2, "1 minute, 2 seconds")] [InlineData(62020, 3, "1 minute, 2 seconds, 20 milliseconds")] [InlineData(3600020, 4, "1 hour, 20 milliseconds")] [InlineData(3600020, 3, "1 hour")] [InlineData(3600020, 2, "1 hour")] [InlineData(3600020, 1, "1 hour")] [InlineData(3603001, 2, "1 hour")] [InlineData(3603001, 3, "1 hour, 3 seconds")] [InlineData(86400000, 3, "1 day")] [InlineData(86400000, 2, "1 day")] [InlineData(86400000, 1, "1 day")] [InlineData(86401000, 1, "1 day")] [InlineData(86401000, 2, "1 day")] [InlineData(86401000, 3, "1 day")] [InlineData(86401000, 4, "1 day, 1 second")] [InlineData(86401200, 4, "1 day, 1 second")] [InlineData(86401200, 5, "1 day, 1 second, 200 milliseconds")] [InlineData(1296000000, 1, "2 weeks")] [InlineData(1296000000, 2, "2 weeks, 1 day")] [InlineData(1299600000, 2, "2 weeks, 1 day")] [InlineData(1299600000, 3, "2 weeks, 1 day, 1 hour")] [InlineData(1299630020, 3, "2 weeks, 1 day, 1 hour")] [InlineData(1299630020, 4, "2 weeks, 1 day, 1 hour")] [InlineData(1299630020, 5, "2 weeks, 1 day, 1 hour, 30 seconds")] [InlineData(1299630020, 6, "2 weeks, 1 day, 1 hour, 30 seconds, 20 milliseconds")] public void TimeSpanWithPrecisionAndCountingEmptyUnits(int milliseconds, int precision, string expected, bool toWords = false) { var actual = TimeSpan.FromMilliseconds(milliseconds).Humanize(precision: precision, countEmptyUnits: true, toWords: toWords); Assert.Equal(expected, actual); } [Theory] [InlineData(0, 3, "no time", true)] [InlineData(0, 2, "no time", true)] [InlineData(0, 3, "0 milliseconds")] [InlineData(0, 2, "0 milliseconds")] [InlineData(10, 2, "10 milliseconds")] [InlineData(1400, 2, "1 second and 400 milliseconds")] [InlineData(2500, 2, "2 seconds and 500 milliseconds")] [InlineData(120000, 2, "2 minutes")] [InlineData(62000, 2, "1 minute and 2 seconds")] [InlineData(62020, 2, "1 minute and 2 seconds")] [InlineData(62020, 3, "1 minute, 2 seconds, and 20 milliseconds")] [InlineData(3600020, 4, "1 hour and 20 milliseconds")] [InlineData(3600020, 3, "1 hour and 20 milliseconds")] [InlineData(3600020, 2, "1 hour and 20 milliseconds")] [InlineData(3600020, 1, "1 hour")] [InlineData(3603001, 2, "1 hour and 3 seconds")] [InlineData(3603001, 3, "1 hour, 3 seconds, and 1 millisecond")] [InlineData(86400000, 3, "1 day")] [InlineData(86400000, 2, "1 day")] [InlineData(86400000, 1, "1 day")] [InlineData(86401000, 1, "1 day")] [InlineData(86401000, 2, "1 day and 1 second")] [InlineData(86401200, 2, "1 day and 1 second")] [InlineData(86401200, 3, "1 day, 1 second, and 200 milliseconds")] [InlineData(1296000000, 1, "2 weeks")] [InlineData(1296000000, 2, "2 weeks and 1 day")] [InlineData(1299600000, 2, "2 weeks and 1 day")] [InlineData(1299600000, 3, "2 weeks, 1 day, and 1 hour")] [InlineData(1299630020, 3, "2 weeks, 1 day, and 1 hour")] [InlineData(1299630020, 4, "2 weeks, 1 day, 1 hour, and 30 seconds")] [InlineData(1299630020, 5, "2 weeks, 1 day, 1 hour, 30 seconds, and 20 milliseconds")] public void TimeSpanWithPrecisionAndAlternativeCollectionFormatter(int milliseconds, int precision, string expected, bool toWords = false) { var actual = TimeSpan.FromMilliseconds(milliseconds).Humanize(precision, collectionSeparator: null, toWords: toWords); Assert.Equal(expected, actual); } [Theory] [InlineData(0, 3, "no time")] [InlineData(0, 2, "no time")] [InlineData(10, 2, "ten milliseconds")] [InlineData(1400, 2, "one second, four hundred milliseconds")] [InlineData(2500, 2, "two seconds, five hundred milliseconds")] [InlineData(120000, 2, "two minutes")] [InlineData(62000, 2, "one minute, two seconds")] [InlineData(62020, 2, "one minute, two seconds")] [InlineData(62020, 3, "one minute, two seconds, twenty milliseconds")] [InlineData(3600020, 4, "one hour, twenty milliseconds")] [InlineData(3600020, 3, "one hour, twenty milliseconds")] [InlineData(3600020, 2, "one hour, twenty milliseconds")] [InlineData(3600020, 1, "one hour")] [InlineData(3603001, 2, "one hour, three seconds")] [InlineData(3603001, 3, "one hour, three seconds, one millisecond")] [InlineData(86400000, 3, "one day")] [InlineData(86400000, 2, "one day")] [InlineData(86400000, 1, "one day")] [InlineData(86401000, 1, "one day")] [InlineData(86401000, 2, "one day, one second")] [InlineData(86401200, 2, "one day, one second")] [InlineData(86401200, 3, "one day, one second, two hundred milliseconds")] [InlineData(1296000000, 1, "two weeks")] [InlineData(1296000000, 2, "two weeks, one day")] [InlineData(1299600000, 2, "two weeks, one day")] [InlineData(1299600000, 3, "two weeks, one day, one hour")] [InlineData(1299630020, 3, "two weeks, one day, one hour")] [InlineData(1299630020, 4, "two weeks, one day, one hour, thirty seconds")] [InlineData(1299630020, 5, "two weeks, one day, one hour, thirty seconds, twenty milliseconds")] public void TimeSpanWithNumbersConvertedToWords(int milliseconds, int precision, string expected) { var actual = TimeSpan.FromMilliseconds(milliseconds).Humanize(precision, toWords: true); Assert.Equal(expected, actual); } [Fact] public void NoTime() { var noTime = TimeSpan.Zero; var actual = noTime.Humanize(); Assert.Equal("0 milliseconds", actual); } [Fact] public void NoTimeToWords() { var noTime = TimeSpan.Zero; var actual = noTime.Humanize(toWords: true); Assert.Equal("no time", actual); } [Theory] [InlineData(1, 1, "en-US", "1 millisecond", ", ")] [InlineData(6 * 24 * 60 * 60 * 1000, 1, "ru-RU", "6 дней", ", ")] [InlineData(11 * 60 * 60 * 1000, 1, "ar", "11 ساعة", ", ")] [InlineData(3603001, 2, "it-IT", "1 ora e 3 secondi", null)] public void CanSpecifyCultureExplicitly(int ms, int precision, string culture, string expected, string? collectionSeparator) { var actual = TimeSpan.FromMilliseconds(ms).Humanize(precision: precision, culture: new(culture), collectionSeparator: collectionSeparator); Assert.Equal(expected, actual); } [Theory] [InlineData(31 * 4, 1, "en-US", "four months")] [InlineData(236, 2, "ar", "سبعة أشهر, اثنان و عشرون يوم")] [InlineData(321, 2, "es", "diez meses, dieciséis días")] public void CanSpecifyCultureExplicitlyToWords(int days, int precision, string culture, string expected) { var timeSpan = new TimeSpan(days, 0, 0, 0); var actual = timeSpan.Humanize(precision: precision, culture: new(culture), maxUnit: TimeUnit.Year, toWords: true); Assert.Equal(expected: expected, actual); } } ================================================ FILE: tests/Humanizer.Tests/TimeUnitToSymbolTests.cs ================================================ [UseCulture("en-US")] public class TimeUnitToSymbolTests { [Theory] [InlineData(TimeUnit.Millisecond, "ms")] [InlineData(TimeUnit.Second, "s")] [InlineData(TimeUnit.Minute, "min")] [InlineData(TimeUnit.Hour, "h")] [InlineData(TimeUnit.Day, "d")] [InlineData(TimeUnit.Week, "week")] [InlineData(TimeUnit.Month, "mo")] [InlineData(TimeUnit.Year, "y")] public void ToSymbol(TimeUnit unit, string expected) => Assert.Equal(expected, unit.ToSymbol()); } ================================================ FILE: tests/Humanizer.Tests/ToQuantityTests.cs ================================================ [UseCulture("en-US")] public class ToQuantityTests { [Theory] [InlineData("case", 0, "0 cases")] [InlineData("case", 1, "1 case")] [InlineData("case", -1, "-1 case")] [InlineData("case", 5, "5 cases")] [InlineData("case", -5, "-5 cases")] [InlineData("man", 0, "0 men")] [InlineData("man", 1, "1 man")] [InlineData("man", -1, "-1 man")] [InlineData("man", 2, "2 men")] [InlineData("man", -2, "-2 men")] [InlineData("men", 2, "2 men")] [InlineData("men", -2, "-2 men")] [InlineData("process", 2, "2 processes")] [InlineData("process", -2, "-2 processes")] [InlineData("process", 1, "1 process")] [InlineData("process", -1, "-1 process")] [InlineData("processes", 2, "2 processes")] [InlineData("processes", -2, "-2 processes")] [InlineData("processes", 1, "1 process")] [InlineData("processes", -1, "-1 process")] [InlineData("slice", 1, "1 slice")] [InlineData("slice", -1, "-1 slice")] [InlineData("slice", 2, "2 slices")] [InlineData("slice", -2, "-2 slices")] [InlineData("slices", 1, "1 slice")] [InlineData("slices", -1, "-1 slice")] [InlineData("slices", 2, "2 slices")] [InlineData("slices", -2, "-2 slices")] public void ToQuantity(string word, int quantity, string expected) => Assert.Equal(expected, word.ToQuantity(quantity)); [Theory] [InlineData("case", 0, "cases")] [InlineData("case", 1, "case")] [InlineData("case", -1, "case")] [InlineData("case", 5, "cases")] [InlineData("case", -5, "cases")] [InlineData("man", 0, "men")] [InlineData("man", 1, "man")] [InlineData("man", -1, "man")] [InlineData("man", 2, "men")] [InlineData("man", -2, "men")] [InlineData("men", 2, "men")] [InlineData("men", -2, "men")] [InlineData("process", 2, "processes")] [InlineData("process", -2, "processes")] [InlineData("process", 1, "process")] [InlineData("process", -1, "process")] [InlineData("processes", 2, "processes")] [InlineData("processes", -2, "processes")] [InlineData("processes", 1, "process")] [InlineData("processes", -1, "process")] public void ToQuantityWithNoQuantity(string word, int quantity, string expected) => Assert.Equal(expected, word.ToQuantity(quantity, ShowQuantityAs.None)); [Theory] [InlineData("case", 0, "0 cases")] [InlineData("case", 1, "1 case")] [InlineData("case", -1, "-1 case")] [InlineData("case", 5, "5 cases")] [InlineData("case", -5, "-5 cases")] [InlineData("man", 0, "0 men")] [InlineData("man", 1, "1 man")] [InlineData("man", -1, "-1 man")] [InlineData("man", 2, "2 men")] [InlineData("man", -2, "-2 men")] [InlineData("men", 2, "2 men")] [InlineData("men", -2, "-2 men")] [InlineData("process", 2, "2 processes")] [InlineData("process", -2, "-2 processes")] [InlineData("process", 1, "1 process")] [InlineData("process", -1, "-1 process")] [InlineData("processes", 2, "2 processes")] [InlineData("processes", -2, "-2 processes")] [InlineData("processes", 1, "1 process")] [InlineData("processes", -1, "-1 process")] public void ToQuantityNumeric(string word, int quantity, string expected) => Assert.Equal(expected, word.ToQuantity(quantity)); [Fact] public void ToQuantityPublicApiIncludesIntOverloads() { var hasCountOverload = false; var hasFormatOverload = false; foreach (var method in typeof(ToQuantityExtensions).GetMethods(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static)) { if (method.Name != "ToQuantity") { continue; } var parameters = method.GetParameters(); if (parameters.Length == 3 && parameters[0].ParameterType == typeof(string) && parameters[1].ParameterType == typeof(int) && parameters[2].ParameterType == typeof(ShowQuantityAs)) { hasCountOverload = true; } if (parameters.Length == 4 && parameters[0].ParameterType == typeof(string) && parameters[1].ParameterType == typeof(int) && parameters[2].ParameterType == typeof(string) && parameters[3].ParameterType == typeof(IFormatProvider)) { hasFormatOverload = true; } } Assert.True(hasCountOverload); Assert.True(hasFormatOverload); } [Theory] [InlineData("hour", -1, "-1 hour")] [InlineData("hour", -0.5, "-0.5 hours")] [InlineData("hour", -22.4, "-22.4 hours")] [InlineData("hour", 1, "1 hour")] [InlineData("hour", 0.5, "0.5 hours")] [InlineData("hour", 22.4, "22.4 hours")] public void ToDoubleQuantityNumeric(string word, double quantity, string expected) => // ReSharper disable once RedundantArgumentDefaultValue Assert.Equal(expected, word.ToQuantity(quantity)); [Theory] [InlineData("case", 0, "zero cases")] [InlineData("case", 1, "one case")] [InlineData("case", -1, "minus one case")] [InlineData("case", 5, "five cases")] [InlineData("case", -5, "minus five cases")] [InlineData("man", 0, "zero men")] [InlineData("man", 1, "one man")] [InlineData("man", -1, "minus one man")] [InlineData("man", 2, "two men")] [InlineData("man", -2, "minus two men")] [InlineData("men", 2, "two men")] [InlineData("men", -2, "minus two men")] [InlineData("process", 2, "two processes")] [InlineData("process", -2, "minus two processes")] [InlineData("process", 1, "one process")] [InlineData("process", -1, "minus one process")] [InlineData("processes", 2, "two processes")] [InlineData("processes", -2, "minus two processes")] [InlineData("processes", 1200, "one thousand two hundred processes")] [InlineData("processes", -1200, "minus one thousand two hundred processes")] [InlineData("processes", 1, "one process")] [InlineData("processes", -1, "minus one process")] public void ToQuantityWords(string word, int quantity, string expected) => Assert.Equal(expected, word.ToQuantity(quantity, ShowQuantityAs.Words)); [Theory] [InlineData("case", 0, null, "0 cases")] [InlineData("case", 1, null, "1 case")] [InlineData("case", -1, null, "-1 case")] [InlineData("case", 2, null, "2 cases")] [InlineData("case", -2, null, "-2 cases")] [InlineData("case", 1, "N0", "1 case")] [InlineData("case", -1, "N0", "-1 case")] [InlineData("case", 2, "N0", "2 cases")] [InlineData("case", -2, "N0", "-2 cases")] [InlineData("case", 123456, "N0", "123,456 cases")] [InlineData("case", -123456, "N0", "-123,456 cases")] [InlineData("case", 123456, "N2", "123,456.00 cases")] [InlineData("case", -123456, "N2", "-123,456.00 cases")] [InlineData("dollar", 0, "C0", "$0 dollars")] [InlineData("dollar", 1, "C0", "$1 dollar")] [InlineData("dollar", 2, "C0", "$2 dollars")] [InlineData("dollar", 2, "C2", "$2.00 dollars")] public void ToQuantityWordsWithCurrentCultureFormatting(string word, int quantity, string? format, string expected) => Assert.Equal(expected, word.ToQuantity(quantity, format)); [Theory] [InlineData("case", 0, "N0", "it-IT", "0 cases")] [InlineData("case", 1, "N0", "it-IT", "1 case")] [InlineData("case", -1, "N0", "it-IT", "-1 case")] [InlineData("case", 2, "N0", "it-IT", "2 cases")] [InlineData("case", -2, "N0", "it-IT", "-2 cases")] [InlineData("case", 1234567, "N0", "it-IT", "1.234.567 cases")] [InlineData("case", -1234567, "N0", "it-IT", "-1.234.567 cases")] [InlineData("case", 1234567, "N2", "it-IT", "1.234.567,00 cases")] [InlineData("case", -1234567, "N2", "it-IT", "-1.234.567,00 cases")] [InlineData("euro", 0, "C0", "es-ES", "0 € euros")] [InlineData("euro", 1, "C0", "es-ES", "1 € euro")] [InlineData("euro", -1, "C0", "es-ES", "-1 € euro")] [InlineData("euro", 2, "C0", "es-ES", "2 € euros")] [InlineData("euro", -2, "C0", "es-ES", "-2 € euros")] [InlineData("euro", 2, "C2", "es-ES", "2,00 € euros")] [InlineData("euro", -2, "C2", "es-ES", "-2,00 € euros")] public void ToQuantityWordsWithCustomCultureFormatting(string word, int quantity, string format, string cultureCode, string expected) { var culture = new CultureInfo(cultureCode); Assert.Equal(expected, word.ToQuantity(quantity, format, culture), GetStringComparer(culture)); } internal static StringComparer GetStringComparer(CultureInfo culture) => StringComparer.Create(culture, false); } ================================================ FILE: tests/Humanizer.Tests/TransformersTests.cs ================================================ public class TransformersTests { [Theory] [InlineData("lower case statement", "Lower Case Statement")] [InlineData("Sentence casing", "Sentence Casing")] [InlineData("honors UPPER case", "Honors UPPER Case")] [InlineData("INvalid caSEs arE corrected", "Invalid Cases Are Corrected")] [InlineData("Can deal w 1 letter words as i do", "Can Deal W 1 Letter Words as I Do")] [InlineData(" random spaces are HONORED too ", " Random Spaces Are HONORED Too ")] [InlineData("Title Case", "Title Case")] [InlineData("a great movie", "A Great Movie")] [InlineData("apostrophe's aren't capitalized", "Apostrophe's Aren't Capitalized")] [InlineData("titles with, commas work too", "Titles With, Commas Work Too")] public void TransformToTitleCase(string input, string expectedOutput) => Assert.Equal(expectedOutput, input.Transform(To.TitleCase)); [Theory] [InlineData("lower case statement", "lower case statement")] [InlineData("Sentence casing", "sentence casing")] [InlineData("No honor for UPPER case", "no honor for upper case")] [InlineData("Title Case", "title case")] public void TransformToLowerCase(string input, string expectedOutput) => Assert.Equal(expectedOutput, input.Transform(To.LowerCase)); [Theory] [InlineData("lower case statement", "Lower case statement")] [InlineData("Sentence casing", "Sentence casing")] [InlineData("honors UPPER case", "Honors UPPER case")] public void TransformToSentenceCase(string input, string expectedOutput) => Assert.Equal(expectedOutput, input.Transform(To.SentenceCase)); [Theory] [InlineData("lower case statement", "LOWER CASE STATEMENT")] [InlineData("Sentence casing", "SENTENCE CASING")] [InlineData("Title Case", "TITLE CASE")] public void TransformToUpperCase(string input, string expectedOutput) => Assert.Equal(expectedOutput, input.Transform(To.UpperCase)); } ================================================ FILE: tests/Humanizer.Tests/TruncatorTests.cs ================================================ public class TruncatorTests { [Theory(DisplayName = "01 - Truncate")] [InlineData(null, 10, null)] [InlineData("", 10, "")] [InlineData("a", 1, "a")] [InlineData("Text longer than truncate length", 10, "Text long…")] [InlineData("Text with length equal to truncate length", 41, "Text with length equal to truncate length")] [InlineData("Text smaller than truncate length", 34, "Text smaller than truncate length")] public void Truncate(string? input, int length, string? expectedOutput) => Assert.Equal(expectedOutput, input.Truncate(length)); [Theory(DisplayName = "02.1 - TruncateWithFixedLengthTruncator")] [InlineData("short text", 20, null, "short text")] [InlineData("short text", 20, "trunc", "short text")] [InlineData("short text", 20, "very long truncation string", "short text")] [InlineData("Text longer than truncate length", 10, "very long truncation string", "Text longe")] [InlineData("Text longer than truncate length", 10, "trunc", "Text trunc")] public void TruncateWithCustomTruncationString(string? input, int length, string? trunactionString, string? expectedOutput) => Assert.Equal(expectedOutput, input.Truncate(length, trunactionString)); [Theory(DisplayName = "02.2 - TruncateWithFixedLengthTruncator")] [InlineData(null, 10, null)] [InlineData("", 10, "")] [InlineData("a", 1, "a")] [InlineData("Text longer than truncate length", 10, "Text long…")] [InlineData("Text with length equal to truncate length", 41, "Text with length equal to truncate length")] [InlineData("Text smaller than truncate length", 34, "Text smaller than truncate length")] public void TruncateWithFixedLengthTruncator(string? input, int length, string? expectedOutput) => Assert.Equal(expectedOutput, input.Truncate(length, Truncator.FixedLength)); [Theory(DisplayName = "03 - TruncateWithFixedNumberOfCharactersTruncator")] [InlineData(null, 10, null)] [InlineData("", 10, "")] [InlineData("a", 1, "a")] [InlineData("Text with more characters than truncate length", 10, "Text with m…")] [InlineData("Text with number of characters equal to truncate length", 47, "Text with number of characters equal to truncate length")] [InlineData("Text with less characters than truncate length", 41, "Text with less characters than truncate length")] public void TruncateWithFixedNumberOfCharactersTruncator(string? input, int length, string? expectedOutput) => Assert.Equal(expectedOutput, input.Truncate(length, Truncator.FixedNumberOfCharacters)); [Theory(DisplayName = "04 - TruncateWithFixedNumberOfCharactersTruncator")] [InlineData(null, 10, null)] [InlineData("", 10, "")] [InlineData("a", 1, "a")] [InlineData("Text with more words than truncate length", 4, "Text with more words…")] [InlineData("Text with number of words equal to truncate length", 9, "Text with number of words equal to truncate length")] [InlineData("Text with less words than truncate length", 8, "Text with less words than truncate length")] [InlineData("Words are\nsplit\rby\twhitespace", 4, "Words are\nsplit\rby…")] public void TruncateWithFixedNumberOfWordsTruncator(string? input, int length, string? expectedOutput) => Assert.Equal(expectedOutput, input.Truncate(length, Truncator.FixedNumberOfWords)); [Theory(DisplayName = "05 - TruncateWithDynamicLengthAndPreserveWordsTruncator")] [InlineData(null, 10, null)] [InlineData("", 10, "")] [InlineData("a", 1, "a")] [InlineData("Text longer than truncate length", 10, "Text…")] [InlineData("Text with length equal to truncate length", 41, "Text with length equal to truncate length")] [InlineData("Text smaller than truncate length", 34, "Text smaller than truncate length")] [InlineData("Textual with delimiter length less than truncate length and starting word longer than truncate length to truncation string alone", 4, "…")] [InlineData("A Text with delimiter length less than truncate length and the last word fit", 1, "…")] [InlineData("A Text with delimiter length less than truncate length and the last word fit", 2, "A…")] public void TruncateWithDynamicLengthAndPreserveWordsTruncator(string? input, int length, string? expectedOutput) => Assert.Equal(expectedOutput, input.Truncate(length, Truncator.DynamicLengthAndPreserveWords)); [Theory(DisplayName = "06 - TruncateWithDynamicNumberOfCharactersAndPreserveWordsTruncator")] [InlineData(null, 10, null)] [InlineData("", 10, "")] [InlineData("a", 1, "a")] [InlineData("Text with more characters than truncate length", 10, "Text with…")] [InlineData("Text with number of characters equal to truncate length", 47, "Text with number of characters equal to truncate length")] [InlineData("Text with less characters than truncate length", 41, "Text with less characters than truncate length")] [InlineData("Textual with delimiter length less than truncate length and starting word longer than truncate length to truncation string alone", 4, "…")] [InlineData("A Text with delimiter length less than truncate length and the first word fit", 2, "A…")] [InlineData("A Text with delimiter length equal to truncate length and the first word fit", 1, "…")] public void TruncateWithDynamicNumberOfCharactersAndPreserveWordsTruncator(string? input, int length, string? expectedOutput) => Assert.Equal(expectedOutput, input.Truncate(length, Truncator.DynamicNumberOfCharactersAndPreserveWords)); [Theory(DisplayName = "07 - TruncateWithTruncationString")] [InlineData(null, 10, "...", null)] [InlineData("", 10, "...", "")] [InlineData("a", 1, "...", "a")] [InlineData("Text longer than truncate length", 10, "...", "Text lo...")] [InlineData("Text with length equal to truncate length", 41, "...", "Text with length equal to truncate length")] [InlineData("Text smaller than truncate length", 34, "...", "Text smaller than truncate length")] [InlineData("Text with delimiter length greater than truncate length truncates to fixed length without truncation string", 2, "...", "Te")] [InlineData("Null truncation string truncates to truncate length without truncation string", 4, null, "Null")] public void TruncateWithTruncationString(string? input, int length, string? truncationString, string? expectedOutput) => Assert.Equal(expectedOutput, input.Truncate(length, truncationString)); [Theory(DisplayName = "08 - TruncateWithTruncationStringAndFixedLengthTruncator")] [InlineData(null, 10, "...", null)] [InlineData("", 10, "...", "")] [InlineData("a", 1, "...", "a")] [InlineData("Text longer than truncate length", 10, "...", "Text lo...")] [InlineData("Text with different truncation string", 10, "---", "Text wi---")] [InlineData("Text with length equal to truncate length", 41, "...", "Text with length equal to truncate length")] [InlineData("Text smaller than truncate length", 34, "...", "Text smaller than truncate length")] [InlineData("Text with delimiter length greater than truncate length truncates to fixed length without truncation string", 2, "...", "Te")] [InlineData("Null truncation string truncates to truncate length without truncation string", 4, null, "Null")] public void TruncateWithTruncationStringAndFixedLengthTruncator(string? input, int length, string? truncationString, string? expectedOutput) => Assert.Equal(expectedOutput, input.Truncate(length, truncationString, Truncator.FixedLength)); [Theory(DisplayName = "09 - TruncateWithTruncationStringAndFixedNumberOfCharactersTruncator")] [InlineData(null, 10, "...", null)] [InlineData("", 10, "...", "")] [InlineData("a", 1, "...", "a")] [InlineData("Text with more characters than truncate length", 10, "...", "Text wit...")] [InlineData("Text with different truncation string", 10, "---", "Text wit---")] [InlineData("Text with number of characters equal to truncate length", 47, "...", "Text with number of characters equal to truncate length")] [InlineData("Text with less characters than truncate length", 41, "...", "Text with less characters than truncate length")] [InlineData("Text with delimiter length greater than truncate length truncates to fixed length without truncation string", 2, "...", "Te")] [InlineData("Text with additional spaces and null truncate string", 10, null, "Text with ad")] [InlineData("Text with additional spaces and empty string as truncate string", 10, "", "Text with ad")] public void TruncateWithTruncationStringAndFixedNumberOfCharactersTruncator(string? input, int length, string? truncationString, string? expectedOutput) => Assert.Equal(expectedOutput, input.Truncate(length, truncationString, Truncator.FixedNumberOfCharacters)); [Theory(DisplayName = "10 - TruncateWithTruncationStringAndFixedNumberOfWordsTruncator")] [InlineData(null, 10, "...", null)] [InlineData("", 10, "...", "")] [InlineData("a", 1, "...", "a")] [InlineData("Text with more words than truncate length", 4, "...", "Text with more words...")] [InlineData("Text with different truncation string", 4, "---", "Text with different truncation---")] [InlineData("Text with number of words equal to truncate length", 9, "...", "Text with number of words equal to truncate length")] [InlineData("Text with less words than truncate length", 8, "...", "Text with less words than truncate length")] [InlineData("Words are\nsplit\rby\twhitespace", 4, "...", "Words are\nsplit\rby...")] [InlineData("Null truncation string truncates to truncate length without truncation string", 4, null, "Null truncation string truncates")] public void TruncateWithTruncationStringAndFixedNumberOfWordsTruncator(string? input, int length, string? truncationString, string? expectedOutput) => Assert.Equal(expectedOutput, input.Truncate(length, truncationString, Truncator.FixedNumberOfWords)); [Theory(DisplayName = "11 - TruncateWithTruncationStringAndDynamicLengthAndPreserveWordsTruncator")] [InlineData(null, 10, "...", null)] [InlineData("", 10, "...", "")] [InlineData("a", 1, "...", "a")] [InlineData("Text longer than truncate length", 10, "...", "Text...")] [InlineData("Text with different truncation string", 10, "---", "Text---")] [InlineData("Text with length equal to truncate length", 41, "...", "Text with length equal to truncate length")] [InlineData("Text smaller than truncate length", 34, "...", "Text smaller than truncate length")] [InlineData("Text with delimiter length greater than truncate length truncates to fixed length without truncation string", 2, "...", "Te")] [InlineData("Text with delimiter length greater than truncate length truncates nothingness without truncation string", 2, "", "")] [InlineData("Textual with delimiter length less than truncate length and starting word longer than truncate length to truncation string alone", 4, "...", "...")] [InlineData("Text with delimiter length less than truncate length and the last word fit", 4, "...", "...")] [InlineData("Text with delimiter length less than truncate length and the last word fit", 5, "...", "...")] [InlineData("Null truncation string truncates to truncate length without truncation string", 3, null, "")] [InlineData("Null truncation string truncates to truncate length without truncation string", 4, null, "Null")] public void TruncateWithTruncationStringAndDynamicLengthAndPreserveWordsTruncator(string? input, int length, string? truncationString, string? expectedOutput) => Assert.Equal(expectedOutput, input.Truncate(length, truncationString, Truncator.DynamicLengthAndPreserveWords)); [Theory(DisplayName = "12 - TruncateWithTruncationStringAndDynamicNumberOfCharactersAndPreserveWordsTruncator")] [InlineData(null, 10, "...", null)] [InlineData("", 10, "...", "")] [InlineData("a", 1, "...", "a")] [InlineData("Text with more characters than truncate length", 10, "...", "Text...")] [InlineData("Text with different truncation string", 10, "---", "Text---")] [InlineData("Text with number of characters equal to truncate length", 47, "...", "Text with number of characters equal to truncate length")] [InlineData("Text with less characters than truncate length", 41, "...", "Text with less characters than truncate length")] [InlineData("Text with delimiter length greater than truncate length truncates to fixed length without truncation string", 2, "...", "")] [InlineData("Text with additional spaces and null truncate string", 10, null, "Text with")] [InlineData("Text with additional spaces and empty string as truncate string", 10, "", "Text with")] [InlineData("Text with delimiter length greater than truncate length truncates nothingness without truncation string", 2, "", "")] [InlineData("Text delimiter length less than truncate length and starting word longer than truncate length to truncation string alone", 4, "...", "...")] [InlineData("Text with delimiter length less than truncate length and the last word fit", 4, "...", "...")] [InlineData("Text with delimiter length less than truncate length and the last word fit", 5, "...", "...")] [InlineData("Text with delimiter length less than truncate length and the last word fit", 7, "...", "Text...")] [InlineData("Null truncation string truncates to truncate length without truncation string", 2, null, "")] [InlineData("Null truncation string truncates to truncate length without truncation string", 3, null, "")] [InlineData("Null truncation string truncates to truncate length without truncation string", 4, null, "Null")] [InlineData("Null truncation string truncates to truncate length without truncation string", 5, null, "Null")] public void TruncateWithTruncationStringAndDynamicNumberOfCharactersAndPreserveWordsTruncator(string? input, int length, string? truncationString, string? expectedOutput) => Assert.Equal(expectedOutput, input.Truncate(length, truncationString, Truncator.DynamicNumberOfCharactersAndPreserveWords)); [Theory(DisplayName = "13 - TruncateWithFixedLengthTruncatorTruncateFromLeft")] [InlineData(null, 10, null)] [InlineData("", 10, "")] [InlineData("a", 1, "a")] [InlineData("Text longer than truncate length", 10, "…te length")] [InlineData("Text with length equal to truncate length", 41, "Text with length equal to truncate length")] [InlineData("Text smaller than truncate length", 34, "Text smaller than truncate length")] public void TruncateWithFixedLengthTruncatorTruncateFromLeft(string? input, int length, string? expectedOutput) => Assert.Equal(expectedOutput, input.Truncate(length, Truncator.FixedLength, TruncateFrom.Left)); [Theory(DisplayName = "14 - TruncateWithFixedNumberOfCharactersTruncatorTruncateFromLeft")] [InlineData(null, 10, null)] [InlineData("", 10, "")] [InlineData("a", 1, "a")] [InlineData("Text with more characters than truncate length", 10, "…ate length")] [InlineData("Text with number of characters equal to truncate length", 47, "Text with number of characters equal to truncate length")] [InlineData("Text with less characters than truncate length", 41, "Text with less characters than truncate length")] [InlineData("Text with strange characters ^$(*^ and more ^$**)% ", 10, "…rs ^$(*^ and more ^$**)% ")] public void TruncateWithFixedNumberOfCharactersTruncatorTruncateFromLeft(string? input, int length, string? expectedOutput) => Assert.Equal(expectedOutput, input.Truncate(length, Truncator.FixedNumberOfCharacters, TruncateFrom.Left)); [Theory(DisplayName = "15 - TruncateWithFixedNumberOfWordsTruncatorTruncateFromLeft")] [InlineData(null, 10, null)] [InlineData("", 10, "")] [InlineData("a", 1, "a")] [InlineData("Text with more words than truncate length", 4, "…words than truncate length")] [InlineData("Text with number of words equal to truncate length", 9, "Text with number of words equal to truncate length")] [InlineData("Text with less words than truncate length", 8, "Text with less words than truncate length")] [InlineData("Words are\nsplit\rby\twhitespace", 4, "…are\nsplit\rby\twhitespace")] [InlineData("Text with whitespace at the end ", 4, "…whitespace at the end")] public void TruncateWithFixedNumberOfWordsTruncatorTruncateFromLeft(string? input, int length, string? expectedOutput) => Assert.Equal(expectedOutput, input.Truncate(length, Truncator.FixedNumberOfWords, TruncateFrom.Left)); [Theory(DisplayName = "16 - TruncateWithDynamicLengthAndPreserveWordsTruncatorTruncateFromLeft")] [InlineData(null, 10, null)] [InlineData("", 10, "")] [InlineData("a", 1, "a")] [InlineData("Text longer than truncate length", 10, "…length")] [InlineData("Text with length equal to truncate length", 41, "Text with length equal to truncate length")] [InlineData("Text smaller than truncate length", 34, "Text smaller than truncate length")] [InlineData("Textual with delimiter length less than truncate length and starting word longer than truncate length to truncation string alone", 4, "…")] [InlineData("A Text with delimiter length less than truncate length and the last word fit", 5, "…fit")] [InlineData("A Text with delimiter length less than truncate length and the last word fit", 4, "…fit")] [InlineData("A Text with delimiter length less than truncate length and the last word fit", 3, "…")] public void TruncateWithDynamicLengthAndPreserveWordsTruncatorTruncateFromLeft(string? input, int length, string? expectedOutput) => Assert.Equal(expectedOutput, input.Truncate(length, Truncator.DynamicLengthAndPreserveWords, TruncateFrom.Left)); [Theory(DisplayName = "17 - TruncateWithDynamicNumberOfCharactersAndPreserveWordsTruncatorTruncateFromLeft")] [InlineData(null, 10, null)] [InlineData("", 10, "")] [InlineData("a", 1, "a")] [InlineData("Text with more characters than truncate length", 10, "…length")] [InlineData("Text with number of characters equal to truncate length", 47, "Text with number of characters equal to truncate length")] [InlineData("Text with less characters than truncate length", 41, "Text with less characters than truncate length")] [InlineData("Text with strange characters ^$(*^ and more ^$**)% ", 10, "…^$(*^ and more ^$**)% ")] [InlineData("Textual with delimiter length less than truncate length and starting word longer than truncate length to truncation string alone", 4, "…")] [InlineData("A Text with delimiter length less than truncate length and the last word fit", 4, "…fit")] [InlineData("A Text with delimiter length less than truncate length and the last word fit", 3, "…")] public void TruncateWithDynamicNumberOfCharactersAndPreserveWordsTruncatorTruncateFromLeft(string? input, int length, string? expectedOutput) => Assert.Equal(expectedOutput, input.Truncate(length, Truncator.DynamicNumberOfCharactersAndPreserveWords, TruncateFrom.Left)); [Theory(DisplayName = "18 - TruncateWithTruncationStringAndFixedLengthTruncatorTruncateFromLeft")] [InlineData(null, 10, "...", null)] [InlineData("", 10, "...", "")] [InlineData("a", 1, "...", "a")] [InlineData("Text longer than truncate length", 10, "...", "... length")] [InlineData("Text with different truncation string", 10, "---", "--- string")] [InlineData("Text with length equal to truncate length", 41, "...", "Text with length equal to truncate length")] [InlineData("Text smaller than truncate length", 34, "...", "Text smaller than truncate length")] [InlineData("Text with delimiter length greater than truncate length truncates to fixed length without truncation string", 2, "...", "ng")] [InlineData("Null truncation string truncates to truncate length without truncation string", 4, null, "ring")] public void TruncateWithTruncationStringAndFixedLengthTruncatorTruncateFromLeft(string? input, int length, string? truncationString, string? expectedOutput) => Assert.Equal(expectedOutput, input.Truncate(length, truncationString, Truncator.FixedLength, TruncateFrom.Left)); [Theory(DisplayName = "19 - TruncateWithTruncationStringAndFixedNumberOfCharactersTruncatorTruncateFromLeft")] [InlineData(null, 10, "...", null)] [InlineData("", 10, "...", "")] [InlineData("a", 1, "...", "a")] [InlineData("Text with more characters than truncate length", 10, "...", "...e length")] [InlineData("Text with different truncation string", 10, "---", "---n string")] [InlineData("Text with number of characters equal to truncate length", 47, "...", "Text with number of characters equal to truncate length")] [InlineData("Text with less characters than truncate length", 41, "...", "Text with less characters than truncate length")] [InlineData("Text with delimiter length greater than truncate length truncates to fixed number of characters without truncation string", 2, "...", "ng")] [InlineData("Null truncation string truncates to truncate length without truncation string", 4, null, "ring")] public void TruncateWithTruncationStringAndFixedNumberOfCharactersTruncatorTruncateFromLeft(string? input, int length, string? truncationString, string? expectedOutput) => Assert.Equal(expectedOutput, input.Truncate(length, truncationString, Truncator.FixedNumberOfCharacters, TruncateFrom.Left)); [Theory(DisplayName = "20 - TruncateWithTruncationStringAndFixedNumberOfWordsTruncatorTruncateFromLeft")] [InlineData(null, 10, "...", null)] [InlineData("", 10, "...", "")] [InlineData("a", 1, "...", "a")] [InlineData("Text with more words than truncate length", 4, "...", "...words than truncate length")] [InlineData("Text with different truncation string", 4, "---", "---with different truncation string")] [InlineData("Text with number of words equal to truncate length", 9, "...", "Text with number of words equal to truncate length")] [InlineData("Text with less words than truncate length", 8, "...", "Text with less words than truncate length")] [InlineData("Words are\nsplit\rby\twhitespace", 4, "...", "...are\nsplit\rby\twhitespace")] [InlineData("Null truncation string truncates to truncate length without truncation string", 4, null, "length without truncation string")] [InlineData("Text with whitespace at the end ", 4, "...", "...whitespace at the end")] public void TruncateWithTruncationStringAndFixedNumberOfWordsTruncatorTruncateFromLeft(string? input, int length, string? truncationString, string? expectedOutput) => Assert.Equal(expectedOutput, input.Truncate(length, truncationString, Truncator.FixedNumberOfWords, TruncateFrom.Left)); [Theory(DisplayName = "20 - TruncateWithTruncationStringAndDynamicLengthAndPreserveWordsTruncatorTruncateFromLeft")] [InlineData(null, 10, "...", null)] [InlineData("", 10, "...", "")] [InlineData("a", 1, "...", "a")] [InlineData("Text longer than truncate length", 10, "...", "...length")] [InlineData("Text with different truncation string", 10, "---", "---string")] [InlineData("Text with length equal to truncate length", 41, "...", "Text with length equal to truncate length")] [InlineData("Text smaller than truncate length", 34, "...", "Text smaller than truncate length")] [InlineData("Text with delimiter length greater than truncate length truncates nothingness without truncation string", 2, "", "")] [InlineData("Textual with delimiter length less than truncate length and starting word longer than truncate length to truncation string alone", 4, "...", "...")] [InlineData("Textual with delimiter length less than truncate length and starting word longer than truncate length to truncation string alone", 5, "...", "...")] [InlineData("Textual with delimiter length less than truncate length and starting word longer than truncate length to truncation string alone", 6, "...", "...")] [InlineData("Textual with delimiter length less than truncate length and starting word longer than truncate length to truncation string alone", 7, "...", "...")] [InlineData("Textual with delimiter length less than truncate length and starting word longer than truncate length to truncation string alone", 9, "...", "...alone")] [InlineData("A Text with delimiter length less than truncate length and the last word fit", 4, "...", "...")] [InlineData("A Text with delimiter length less than truncate length and the last word fit", 3, "...", "...")] [InlineData("Null truncation string truncates to truncate length without truncation string", 4, null, "")] [InlineData("Null truncation string truncates to truncate length without truncation string", 6, null, "string")] [InlineData("Null truncation string truncates to truncate length without truncation string", 7, null, "string")] [InlineData("Null truncation string truncates to truncate length without truncation string", 10, null, "string")] public void TruncateWithTruncationStringAndDynamicLengthAndPreserveWordsTruncatorTruncateFromLeft(string? input, int length, string? truncationString, string? expectedOutput) => Assert.Equal(expectedOutput, input.Truncate(length, truncationString, Truncator.DynamicLengthAndPreserveWords, TruncateFrom.Left)); [Theory(DisplayName = "21 - TruncateWithTruncationStringAndDynamicNumberOfCharactersAndPreserveWordsTruncatorTruncateFromLeft")] [InlineData(null, 10, "...", null)] [InlineData("", 10, "...", "")] [InlineData("a", 1, "...", "a")] [InlineData("Text with more characters than truncate length", 10, "...", "...length")] [InlineData("Text with different truncation string", 10, "---", "---string")] [InlineData("Text with number of characters equal to truncate length", 47, "...", "Text with number of characters equal to truncate length")] [InlineData("Text with less characters than truncate length", 41, "...", "Text with less characters than truncate length")] [InlineData("Text with delimiter length greater than truncate length truncates nothingness without truncation string", 2, "", "")] [InlineData("Textual with delimiter length less than truncate length and starting word longer than truncate length to truncation string alone", 2, "...", "")] [InlineData("Textual with delimiter length less than truncate length and starting word longer than truncate length to truncation string alone", 4, "...", "...")] [InlineData("Textual with delimiter length less than truncate length and starting word longer than truncate length to truncation string alone", 5, "...", "...")] [InlineData("Textual with delimiter length less than truncate length and starting word longer than truncate length to truncation string alone", 6, "...", "...")] [InlineData("Textual with delimiter length less than truncate length and starting word longer than truncate length to truncation string alone", 8, "...", "...alone")] [InlineData("Textual with delimiter length less than truncate length and starting word longer than truncate length to truncation string alone", 9, "...", "...alone")] [InlineData("A Text with delimiter length less than truncate length and the last word fit", 2, "...", "")] [InlineData("A Text with delimiter length less than truncate length and the last word fit", 4, ".....", "fit")] [InlineData("A Text with delimiter length less than truncate length and the last word fit", 5, ".....", ".....")] [InlineData("A Text with delimiter length less than truncate length and the last word fit", 6, ".....", ".....")] [InlineData("Null truncation string truncates to truncate length without truncation string", 4, null, "")] [InlineData("Null truncation string truncates to truncate length without truncation string", 6, null, "string")] [InlineData("Null truncation string truncates to truncate length without truncation string", 7, null, "string")] public void TruncateWithTruncationStringAndDynamicNumberOfCharactersAndPreserveWordsTruncatorTruncateFromLeft(string? input, int length, string? truncationString, string? expectedOutput) => Assert.Equal(expectedOutput, input.Truncate(length, truncationString, Truncator.DynamicNumberOfCharactersAndPreserveWords, TruncateFrom.Left)); } ================================================ FILE: tests/Humanizer.Tests/TupleizeTests.cs ================================================ // ReSharper disable IdentifierTypo // ReSharper disable StringLiteralTypo public class TupleizeTests { [Theory] [InlineData(1, "single")] [InlineData(2, "double")] [InlineData(3, "triple")] [InlineData(4, "quadruple")] [InlineData(5, "quintuple")] [InlineData(6, "sextuple")] [InlineData(7, "septuple")] [InlineData(8, "octuple")] [InlineData(9, "nonuple")] [InlineData(10, "decuple")] [InlineData(100, "centuple")] [InlineData(1000, "milluple")] public void Given_int_with_named_tuple_gives_correct_result(int n, string expected) => Assert.Equal(expected, n.Tupleize()); [Theory] [InlineData(0)] [InlineData(-1)] [InlineData(int.MinValue)] [InlineData(int.MaxValue)] public void Given_other_number_returns_n_tuple(int n) => Assert.Equal($"{n}-tuple", n.Tupleize()); } ================================================ FILE: tests/Humanizer.Tests/UseCultureAttribute.cs ================================================ using System.Reflection; /// /// Apply this attribute to your test method to replace the /// and /// with another culture. /// /// /// Replaces the culture and UI culture of the current thread with /// /// /// /// /// This constructor overload uses for both /// and . /// /// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class UseCultureAttribute(string culture) : BeforeAfterTestAttribute { readonly Lazy culture = new(() => new CultureInfo(culture)); CultureInfo? originalCulture; CultureInfo? originalUICulture; public CultureInfo Culture => culture.Value; /// /// Stores the current /// and /// and replaces them with the new cultures defined in the constructor. /// /// The method under test public override void Before(MethodInfo methodUnderTest, IXunitTest test) { originalCulture = CultureInfo.CurrentCulture; originalUICulture = CultureInfo.CurrentUICulture; CultureInfo.CurrentCulture = Culture; CultureInfo.CurrentUICulture = Culture; } /// /// Restores the original and /// to /// /// The method under test public override void After(MethodInfo methodUnderTest, IXunitTest test) { CultureInfo.CurrentCulture = originalCulture!; CultureInfo.CurrentUICulture = originalUICulture!; } } ================================================ FILE: tests/Humanizer.Tests/WordsToNumberTests.cs ================================================ namespace Humanizer.Tests; [UseCulture("en-US")] public class WordsToNumberTests_US { [Theory] [InlineData("zero", 0)] [InlineData("one", 1)] [InlineData("minus five", -5)] [InlineData("eleven", 11)] [InlineData("ninety five", 95)] [InlineData("hundred five", 105)] [InlineData("one hundred ninety six", 196)] [InlineData("minus one hundred and five", -105)] [InlineData("seventeenth", 17)] [InlineData("thirtieth", 30)] [InlineData("twenty-seventh", 27)] [InlineData("thirty-first", 31)] [InlineData("minus twenty-first", -21)] [InlineData("two thousand twenty three", 2023)] [InlineData("one million two hundred thirty four thousand five hundred sixty seven", 1234567)] [InlineData("one hundred and third", 103)] [InlineData("two hundred and first", 201)] [InlineData("five thousand and ninth", 5009)] [InlineData("17th", 17)] [InlineData("31st", 31)] [InlineData("100th", 100)] [InlineData("203rd", 203)] [InlineData("minus 21st", -21)] [InlineData("negative five", -5)] [InlineData("negative one hundred and five", -105)] [InlineData("negative twenty-first", -21)] public void ToNumber_US(string words, int expectedNumber) => Assert.Equal(expectedNumber, words.ToNumber(CultureInfo.CurrentCulture)); [Theory] [InlineData("zero", 0, null)] [InlineData("one", 1, null)] [InlineData("minus five", -5, null)] [InlineData("eleven", 11, null)] [InlineData("ninety five", 95, null)] [InlineData("hundred five", 105, null)] [InlineData("one hundred ninety six", 196, null)] [InlineData("minus one hundred and five", -105, null)] [InlineData("seventeenth", 17, null)] [InlineData("thirtieth", 30, null)] [InlineData("twenty-seventh", 27, null)] [InlineData("thirty-first", 31, null)] [InlineData("minus twenty-first", -21, null)] [InlineData("two thousand twenty three", 2023, null)] [InlineData("one million two hundred thirty four thousand five hundred sixty seven", 1234567, null)] [InlineData("one hundred and third", 103, null)] [InlineData("two hundred and first", 201, null)] [InlineData("five thousand and ninth", 5009, null)] [InlineData("17th", 17, null)] [InlineData("31st", 31, null)] [InlineData("100th", 100, null)] [InlineData("203rd", 203, null)] [InlineData("minus 21st", -21, null)] [InlineData("negative five", -5, null)] [InlineData("negative one hundred and five", -105, null)] [InlineData("negative twenty-first", -21, null)] public void TryToNumber_ValidInput_US(string words, int expectedNumber, string? expectedUnrecognizedWord) { Assert.True(words.TryToNumber(out var parsedNumber, CultureInfo.CurrentCulture, out var unrecognizedWord)); Assert.Equal(unrecognizedWord, expectedUnrecognizedWord); Assert.Equal(expectedNumber, parsedNumber); } [Theory] [InlineData("twenty nine hello", 0, "hello")] [InlineData("mister three", 0, "mister")] [InlineData("tenn", 0, "tenn")] [InlineData("twenty sveen", 0, "sveen")] [InlineData("minus fift five", 0, "fift")] [InlineData("sixty two j", 0, "j")] [InlineData("two hundred , ninetyy sevennn", 0, "ninetyy")] [InlineData("invalidinput", 0, "invalidinput")] [InlineData("30rmd", 0, "30rmd")] [InlineData("negative energy", 0, "energy")] public void TryToNumber_InvalidInput_US(string words, int expectedNumber, string? expectedUnrecognizedWord) { Assert.False(words.TryToNumber(out var parsedNumber, CultureInfo.CurrentCulture, out var unrecognizedWord)); Assert.Equal(unrecognizedWord, expectedUnrecognizedWord); Assert.Equal(expectedNumber, parsedNumber); } } [UseCulture("en-GB")] public class WordsToNumberTests_GB { [Theory] [InlineData("zero", 0, null)] [InlineData("one", 1, null)] [InlineData("minus five", -5, null)] [InlineData("eleven", 11, null)] [InlineData("ninety five", 95, null)] [InlineData("hundred five", 105, null)] [InlineData("one hundred ninety six", 196, null)] [InlineData("minus one hundred and five", -105, null)] [InlineData("seventeenth", 17, null)] [InlineData("thirtieth", 30, null)] [InlineData("twenty-seventh", 27, null)] [InlineData("thirty-first", 31, null)] [InlineData("minus twenty-first", -21, null)] [InlineData("two thousand twenty three", 2023, null)] [InlineData("one million two hundred thirty four thousand five hundred sixty seven", 1234567, null)] [InlineData("one hundred and third", 103, null)] [InlineData("two hundred and first", 201, null)] [InlineData("five thousand and ninth", 5009, null)] [InlineData("17th", 17, null)] [InlineData("31st", 31, null)] [InlineData("100th", 100, null)] [InlineData("203rd", 203, null)] [InlineData("minus 21st", -21, null)] [InlineData("negative five", -5, null)] [InlineData("negative one hundred and five", -105, null)] [InlineData("negative twenty-first", -21, null)] public void TryToNumber_ValidInput_GB(string words, int expectedNumber, string? expectedUnrecognizedWord) { Assert.True(words.TryToNumber(out var parsedNumber, CultureInfo.CurrentCulture, out var unrecognizedWord)); Assert.Equal(unrecognizedWord, expectedUnrecognizedWord); Assert.Equal(expectedNumber, parsedNumber); } [Theory] [InlineData("twenty nine hello", 0, "hello")] [InlineData("mister three", 0, "mister")] [InlineData("tenn", 0, "tenn")] [InlineData("twenty sveen", 0, "sveen")] [InlineData("minus fift five", 0, "fift")] [InlineData("sixty two j", 0, "j")] [InlineData("two hundred , ninetyy sevennn", 0, "ninetyy")] [InlineData("invalidinput", 0, "invalidinput")] [InlineData("30rmd", 0, "30rmd")] [InlineData("negative energy", 0, "energy")] public void TryToNumber_InvalidInput_GB(string words, int expectedNumber, string? expectedUnrecognizedWord) { Assert.False(words.TryToNumber(out var parsedNumber, CultureInfo.CurrentCulture, out var unrecognizedWord)); Assert.Equal(unrecognizedWord, expectedUnrecognizedWord); Assert.Equal(expectedNumber, parsedNumber); } } public class WordsToNumberTests_NonEnglish { [Theory] [InlineData("es-ES", "veinte")] [InlineData("fr-FR", "vingt")] public void ThrowsForNonEnglishWords(string cultureName, string word) { var culture = new CultureInfo(cultureName); var ex = Assert.Throws(() => word.ToNumber(culture)); Assert.Contains($"'{culture.TwoLetterISOLanguageName}'", ex.Message); } } ================================================ FILE: tests/Humanizer.Tests/testconfig.json ================================================ { "xUnit": { "diagnosticMessages": true, "methodDisplay": "method", "parallelizeAssembly": true, "parallelizeTestCollections": false, "showLiveOutput": true }, "codeCoverage": { "Configuration": { "Format": "cobertura", "CodeCoverage": { "Attributes": { "Exclude": [ "^System\\.Diagnostics\\.DebuggerHiddenAttribute$", "^System\\.Diagnostics\\.DebuggerNonUserCodeAttribute$", "^System\\.CodeDom\\.Compiler\\.GeneratedCodeAttribute$", "^System\\.Diagnostics\\.CodeAnalysis\\.ExcludeFromCodeCoverageAttribute$" ] } } } } } ================================================ FILE: tests/fixtures/PackageSmoke/AnalyzerProbe.cs ================================================ namespace Humanizer.Bytes { public class StubFormatter { } } ================================================ FILE: tests/fixtures/PackageSmoke/BlazorConsumer/App.razor ================================================

Hello

================================================ FILE: tests/fixtures/PackageSmoke/BlazorConsumer/Consumer.csproj.template ================================================ __TARGET_FRAMEWORK__ enable enable __PACKAGE_REFERENCES__ ================================================ FILE: tests/fixtures/PackageSmoke/BlazorConsumer/Program.cs ================================================ using Consumer; using Humanizer; using System.Globalization; var builder = WebApplication.CreateBuilder(args); builder.Services.AddRazorComponents(); var app = builder.Build(); if (args.Contains("--humanizer-smoke-exit", StringComparer.Ordinal)) { Console.WriteLine(2.ToWords(new CultureInfo("fr"))); return; } app.MapRazorComponents(); app.Run(); ================================================ FILE: tests/fixtures/PackageSmoke/ConsoleConsumer/Consumer.csproj.template ================================================ Exe __TARGET_FRAMEWORK__ disable enable disable enable __PACKAGE_REFERENCES__ ================================================ FILE: tests/fixtures/PackageSmoke/ConsoleConsumer/Program.cs ================================================ using System; using Humanizer; using System.Globalization; public static class Program { public static void Main() { Console.WriteLine(2.ToWords(new CultureInfo("fr"))); } } ================================================ FILE: tests/fixtures/PackageSmoke/WebApiConsumer/Consumer.csproj.template ================================================ __TARGET_FRAMEWORK__ enable enable __PACKAGE_REFERENCES__ ================================================ FILE: tests/fixtures/PackageSmoke/WebApiConsumer/Program.cs ================================================ using Humanizer; using System.Globalization; var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); if (args.Contains("--humanizer-smoke-exit", StringComparer.Ordinal)) { Console.WriteLine(2.ToWords(new CultureInfo("fr"))); return; } app.MapGet("/", () => "ok"); app.Run(); ================================================ FILE: tests/fixtures/WapProjSmoke/EntryPointApp/EntryPointApp.csproj.template ================================================ WinExe net8.0-windows10.0.19041.0 enable enable win-x64 true __PACKAGES_PATH__ ================================================ FILE: tests/fixtures/WapProjSmoke/EntryPointApp/Program.cs ================================================ using Humanizer; using System.Globalization; Console.WriteLine(2.ToWords(new CultureInfo("fr"))); ================================================ FILE: tests/fixtures/WapProjSmoke/Package/Package.appxmanifest ================================================ HumanizerWapProbe Humanizer Images\StoreLogo.png ================================================ FILE: tests/fixtures/WapProjSmoke/Package/Package.wapproj.template ================================================ 15.0 Release x64 $(MSBuildExtensionsPath)\Microsoft\DesktopBridge\ {5A6E0905-0F24-4E09-8A57-4E16E7E7E0AA} 10.0.19041.0 10.0.17763.0 en-US false ..\EntryPointApp\EntryPointApp.csproj CoreClr @(PackageOutputGroups);__GetPublishItems __PACKAGES_PATH__ Designer EntryPointApp\EntryPointApp.exe ================================================ FILE: tests/verify-packages.ps1 ================================================ <# .SYNOPSIS Verifies Humanizer NuGet packages structure, dependencies, and SDK compatibility. .DESCRIPTION This script validates that Humanizer NuGet packages are correctly built and can be restored across multiple .NET SDK versions. It performs the following checks: 1. Verifies all expected packages exist (main metapackage, core package, and satellite packages) 2. Tests package restoration and build on multiple .NET SDK versions (8, 9, 10, and 11) - Creates isolated test environments with global.json for each SDK version - Validates that packages can be restored and built successfully 3. Verifies that the main Humanizer metapackage includes all satellite packages as dependencies 4. Runs package smoke tests for metapackage and core-plus-language consumer scenarios The script is designed to run in CI/CD pipelines (Azure DevOps) and provides detailed logging with Azure DevOps-specific formatting. .PARAMETER PackageVersion The version of the Humanizer packages to verify (e.g., "3.0.0-rc.14"). .PARAMETER PackagesDirectory The directory containing the built NuGet packages (.nupkg files). .PARAMETER MinimumPassingSdkVersion Optional minimum .NET SDK version (e.g., "9.0.200") that is expected to restore packages successfully. SDK targets with versions lower than this threshold are treated as expected failures (the script reports success when they fail and failure when they succeed). The default value is 9.0.200. .EXAMPLE .\tests\verify-packages.ps1 -PackageVersion "3.0.0" -PackagesDirectory ".\artifacts\packages" .NOTES - The script requires .NET SDK 8, 9, 10, and/or 11 to be installed - SDKs that are not installed will be skipped with a warning - Package smoke tests cover net8.0, net9.0, net10.0, net11.0, and net48 across console, Web API, and Blazor hosts - WAP project smoke testing is Windows-only and opt-in via -IncludeWapProjSmokeTest #> param( [Parameter(Mandatory=$true)] [string]$PackageVersion, [Parameter(Mandatory=$true)] [string]$PackagesDirectory, [string]$MinimumPassingSdkVersion = "9.0.200", [switch]$IncludeWapProjSmokeTest ) $ErrorActionPreference = "Stop" $script:AzureDevOpsErrorLogged = $false $script:AzureDevOpsWarningLogged = $false function ConvertTo-AzureDevOpsCommandValue { param([string]$Value) if ([string]::IsNullOrEmpty($Value)) { return $Value } return $Value.Replace('%', '%25').Replace("`r", '%0D').Replace("`n", '%0A').Replace(';', '%3B').Replace(']', '%5D') } function Write-AzureDevOpsSection { param([string]$Message) Write-Host "##[section]$Message" } function Write-AzureDevOpsError { param([string]$Message) if (-not [string]::IsNullOrEmpty($Message)) { $escaped = ConvertTo-AzureDevOpsCommandValue $Message Write-Host "##vso[task.logissue type=error;]$escaped" $script:AzureDevOpsErrorLogged = $true } } function Write-AzureDevOpsWarning { param([string]$Message) if (-not [string]::IsNullOrEmpty($Message)) { $escaped = ConvertTo-AzureDevOpsCommandValue $Message Write-Host "##vso[task.logissue type=warning;]$escaped" $script:AzureDevOpsWarningLogged = $true } } function Invoke-CommandText { param( [Parameter(Mandatory = $true)][string]$FilePath, [string[]]$ArgumentList = @(), [string]$WorkingDirectory ) $currentLocation = Get-Location try { if ($WorkingDirectory) { Set-Location $WorkingDirectory } $output = & $FilePath @ArgumentList 2>&1 | ForEach-Object { $_.ToString() } return [PSCustomObject]@{ ExitCode = $LASTEXITCODE Output = ($output -join "`n") } } finally { if ($WorkingDirectory) { Set-Location $currentLocation } } } function Get-NormalizedVersionString { param([string]$Version) if ([string]::IsNullOrWhiteSpace($Version)) { return $Version } $prefix = $Version.Split('-')[0].Split('+')[0] $segments = $prefix.Split('.') if ($segments.Length -le 3) { return $prefix } return ($segments[0..2] -join '.') } function ConvertTo-VersionObject { param([string]$VersionString) if ([string]::IsNullOrWhiteSpace($VersionString)) { return $null } $normalized = Get-NormalizedVersionString $VersionString if ([string]::IsNullOrWhiteSpace($normalized)) { return $null } $parts = $normalized.Split('.') while ($parts.Length -lt 3) { $parts += '0' } $joined = ($parts[0..2] -join '.') try { return [Version]::Parse($joined) } catch { return $null } } function Write-FilteredProcessOutput { param([PSCustomObject]$ProcessResult) if ($null -eq $ProcessResult) { return } if ([string]::IsNullOrWhiteSpace($ProcessResult.Output)) { return } $combined = $ProcessResult.Output $lines = $combined -split "(`r`n|`r|`n)" foreach ($line in $lines) { if ([string]::IsNullOrWhiteSpace($line)) { continue } $trimmed = $line.Trim() if ($trimmed -match '^(?i)info\s*:') { continue } $match = [regex]::Match($trimmed, '(?i)\b(error|warning)\b\s*:?.*') if ($match.Success) { $message = $match.Value.Trim() if (-not [string]::IsNullOrWhiteSpace($message)) { Write-Host $message } } } } function New-RestoreProjectFile { param( [Parameter(Mandatory = $true)][string]$Directory, [Parameter(Mandatory = $true)][string]$ProjectName, [Parameter(Mandatory = $true)][string]$TargetFramework, [Parameter(Mandatory = $true)][string]$PackageVersion ) if (-not (Test-Path $Directory)) { New-Item -ItemType Directory -Path $Directory -Force | Out-Null } $projectContent = @" $TargetFramework true true "@ $projectPath = Join-Path $Directory "$ProjectName.csproj" Set-Content -Path $projectPath -Value $projectContent -Encoding UTF8 return $projectPath } function Format-RestoreSummaryLine { param( [PSCustomObject]$Result, [string]$PrefixSymbol ) if ($null -eq $Result) { return $null } $line = " $PrefixSymbol $($Result.DisplayName)" if ($Result.Success -and $Result.FailureExpected) { if ($Result.ExpectationReason) { $line += " (expected failure: $($Result.ExpectationReason))" } else { $line += " (expected failure)" } } elseif (-not $Result.Success -and $Result.FailureExpected) { if ($Result.ExpectationReason) { $line += " (unexpected success; expected failure: $($Result.ExpectationReason))" } else { $line += " (unexpected success; expected failure)" } } return $line } function Get-MSBuildProductName { param([string]$Path) if ([string]::IsNullOrWhiteSpace($Path)) { return $null } if ($Path -match "Microsoft Visual Studio\\(\\d{4})\\([^\\]+)") { $year = $Matches[1] $segment = $Matches[2] switch -Regex ($segment) { '^BuildTools$' { return "VS $year Build Tools" } '^Preview$' { return "VS $year Preview" } default { return "VS $year $segment" } } } return $null } function Get-MSBuildInfos { param([bool]$RunningOnWindows) if (-not $RunningOnWindows) { return @() } $msbuildPaths = @() $msbuildCommands = @(Get-Command msbuild.exe -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Source -Unique) if ($msbuildCommands) { $msbuildPaths += $msbuildCommands } $programFilesX86 = [Environment]::GetEnvironmentVariable("ProgramFiles(x86)") if (-not [string]::IsNullOrWhiteSpace($programFilesX86)) { $vswherePath = Join-Path $programFilesX86 "Microsoft Visual Studio/Installer/vswhere.exe" if (Test-Path $vswherePath) { $vswhereArguments = @( "-prerelease", "-products", "*", "-requires", "Microsoft.Component.MSBuild", "-find", "MSBuild/**/Bin/MSBuild.exe", "-all" ) $vswhereOutput = & $vswherePath @vswhereArguments 2>$null if ($vswhereOutput) { $msbuildPaths += $vswhereOutput } } } $msbuildPaths = $msbuildPaths | Where-Object { $_ -and (Test-Path $_) } | Sort-Object -Unique $msbuildInfos = @() foreach ($msbuildPath in $msbuildPaths) { $msbuildItem = Get-Item $msbuildPath $msbuildVersion = $null try { $msbuildVersion = $msbuildItem.VersionInfo.ProductVersion if (-not $msbuildVersion -and $msbuildItem.VersionInfo.FileVersion) { $msbuildVersion = $msbuildItem.VersionInfo.FileVersion } } catch { $msbuildVersion = $null } $normalizedMsbuildVersion = Get-NormalizedVersionString $msbuildVersion $productName = Get-MSBuildProductName $msbuildPath if (-not $productName -and $msbuildItem.VersionInfo -and $msbuildItem.VersionInfo.ProductName) { $productName = $msbuildItem.VersionInfo.ProductName } $baseName = if ($normalizedMsbuildVersion) { "MSBuild $normalizedMsbuildVersion" } else { "MSBuild" } $displayName = if ($productName) { "$baseName ($productName)" } else { $baseName } $msbuildInfos += [PSCustomObject]@{ Path = $msbuildPath RawVersion = $msbuildVersion Version = $normalizedMsbuildVersion ProductName = $productName DisplayName = $displayName } } return $msbuildInfos } function Write-AzureDevOpsErrorDetail { param( [string]$Summary, [string]$Details ) if ([string]::IsNullOrWhiteSpace($Summary) -and [string]::IsNullOrWhiteSpace($Details)) { return } $message = $null if (-not [string]::IsNullOrWhiteSpace($Summary)) { $message = $Summary.Trim() } if (-not [string]::IsNullOrWhiteSpace($Details)) { $normalizedDetails = ($Details -replace "(`r`n|`r)", "`n").Trim("`n") if ($message) { $message = "$message`n$normalizedDetails" } else { $message = $normalizedDetails } } Write-AzureDevOpsError $message } function Get-RestoreDiagnostics { param([string]$Output) if ([string]::IsNullOrEmpty($Output)) { return [PSCustomObject]@{ Errors = @(); Warnings = @() } } $lines = $Output -split "(`r`n|`r|`n)" $errorLines = @() $warningLines = @() foreach ($line in $lines) { $trimmed = $line.TrimEnd() if ([string]::IsNullOrWhiteSpace($trimmed)) { continue } if ($trimmed -match "(?i)\berror\b\s*:?\s*[A-Z0-9]+:") { $match = [regex]::Match($trimmed, "(?i)\berror\b\s*:?\s*[A-Z0-9]+:.*") if ($match.Success) { $errorLines += $match.Value.Trim() } else { $errorLines += $trimmed } continue } if ($trimmed -match "(?i)\bwarning\b\s*:?\s*[A-Z0-9]+:") { $match = [regex]::Match($trimmed, "(?i)\bwarning\b\s*:?\s*[A-Z0-9]+:.*") if ($match.Success) { $warningLines += $match.Value.Trim() } else { $warningLines += $trimmed } } } return [PSCustomObject]@{ Errors = $errorLines | Select-Object -Unique Warnings = $warningLines | Select-Object -Unique } } function Get-RestoreTargets { param( [bool]$RunningOnWindows, [string]$MinimumPassingSdkVersion ) Write-AzureDevOpsSection "Detecting installed .NET SDKs and MSBuild tools" $restoreTargets = @() $minimumPassingVersionObject = ConvertTo-VersionObject $MinimumPassingSdkVersion $listSdksResult = Invoke-CommandText -FilePath "dotnet" -ArgumentList @("--list-sdks") if ($listSdksResult.ExitCode -ne 0) { Write-AzureDevOpsErrorDetail "Failed to enumerate installed SDKs" $listSdksResult.Output Write-FilteredProcessOutput -ProcessResult $listSdksResult throw "Unable to determine installed SDKs" } Write-FilteredProcessOutput -ProcessResult $listSdksResult $installedSdkLines = @() if ($listSdksResult.Output) { $installedSdkLines = ($listSdksResult.Output -split "(`r`n|`r|`n)") | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } } $sdksByMajor = @{} foreach ($line in $installedSdkLines) { if ($line -match '^(?[^\s]+)\s+\[(?.+)\]$') { $version = $Matches['version'] $major = $version.Split('.')[0] if (-not $sdksByMajor.ContainsKey($major)) { $sdksByMajor[$major] = @() } $sdksByMajor[$major] += $version } } $sdkVersionsToTest = @( @{ Version = "8.0.100"; RollForward = "latestFeature"; Name = "SDK 8"; MajorVersion = 8; TargetFramework = "net8.0" }, @{ Version = "9.0.100"; RollForward = "latestFeature"; Name = "SDK 9"; MajorVersion = 9; TargetFramework = "net9.0" }, @{ Version = "10.0.100"; RollForward = "latestFeature"; Name = "SDK 10"; MajorVersion = 10; TargetFramework = "net10.0" }, @{ Version = "11.0.100"; RollForward = "latestFeature"; Name = "SDK 11"; MajorVersion = 11; TargetFramework = "net11.0" }, # Validate downlevel consumers on the latest installed SDK to avoid relying on older restore behavior. @{ Version = "11.0.100"; RollForward = "latestFeature"; Name = "SDK 11"; MajorVersion = 11; TargetFramework = "net8.0" }, @{ Version = "11.0.100"; RollForward = "latestFeature"; Name = "SDK 11"; MajorVersion = 11; TargetFramework = "net10.0" } ) foreach ($sdkConfig in $sdkVersionsToTest) { $majorKey = [string]$sdkConfig.MajorVersion if ($sdksByMajor.ContainsKey($majorKey)) { $availableVersions = $sdksByMajor[$majorKey] | Sort-Object -Descending $selectedVersion = $availableVersions | Select-Object -First 1 $normalizedVersion = Get-NormalizedVersionString $selectedVersion if (-not $normalizedVersion) { $normalizedVersion = Get-NormalizedVersionString $sdkConfig.Version } $baseDisplayName = if ($normalizedVersion) { ".NET $normalizedVersion" } else { ".NET $($sdkConfig.MajorVersion)" } $displayName = "$baseDisplayName ($($sdkConfig.TargetFramework))" $targetFrameworkId = ($sdkConfig.TargetFramework -replace '[^A-Za-z0-9]', '') $selectedVersionObject = ConvertTo-VersionObject $normalizedVersion $failureExpected = $false $expectationReason = $null if ($minimumPassingVersionObject -and $selectedVersionObject -ne $null -and $selectedVersionObject -lt $minimumPassingVersionObject) { $failureExpected = $true $expectationReason = "SDK version below minimum $MinimumPassingSdkVersion" } $restoreTargets += [PSCustomObject]@{ Kind = 'dotnet' Id = "sdk$($sdkConfig.MajorVersion)-$targetFrameworkId" DisplayName = $displayName Version = $normalizedVersion TargetFramework = $sdkConfig.TargetFramework GlobalJsonVersion = $selectedVersion RollForward = $sdkConfig.RollForward FailureExpected = $failureExpected ExpectationReason = $expectationReason } } else { Write-AzureDevOpsWarning "$($sdkConfig.Name) not installed, skipping" } } $dotnetTargets = $restoreTargets | Where-Object { $_.Kind -eq 'dotnet' } if ($dotnetTargets.Count -eq 0) { $sdkMajorVersions = ($sdkVersionsToTest | ForEach-Object { $_.MajorVersion }) -join ", " Write-AzureDevOpsWarning "No target SDK versions ($sdkMajorVersions) are installed" } if ($RunningOnWindows) { $msbuildInfos = Get-MSBuildInfos -RunningOnWindows $RunningOnWindows if ($msbuildInfos.Count -eq 0) { Write-AzureDevOpsWarning "No MSBuild installations detected" } else { $index = 0 foreach ($info in $msbuildInfos) { $index++ $displayName = if ($info.Version) { "MSBuild $($info.Version)" } else { "MSBuild" } if ($info.ProductName) { $displayName = "$displayName ($($info.ProductName))" } $restoreTargets += [PSCustomObject]@{ Kind = 'msbuild' Id = "msbuild$index" DisplayName = $displayName Version = $info.Version Path = $info.Path FailureExpected = $false ExpectationReason = $null } } } } else { Write-AzureDevOpsWarning "MSBuild restore tests skipped (non-Windows environment)" } if ($restoreTargets.Count -gt 0) { Write-Host "Discovered restore targets:" foreach ($target in $restoreTargets) { if ($target.FailureExpected -and $target.ExpectationReason) { Write-Host " - $($target.DisplayName) (expected failure: $($target.ExpectationReason))" } elseif ($target.FailureExpected) { Write-Host " - $($target.DisplayName) (expected failure)" } else { Write-Host " - $($target.DisplayName)" } } } else { Write-AzureDevOpsWarning "No restore targets were discovered" } return $restoreTargets } function Invoke-DotnetRestoreTarget { param( [PSCustomObject]$Target, [string]$TempDir, [string]$NuGetConfig, [string]$PackageVersion ) $resultRecord = [PSCustomObject]@{ Kind = 'dotnet' DisplayName = $Target.DisplayName Version = $Target.Version Success = $false Details = $null FailureExpected = [bool]$Target.FailureExpected ExpectationReason = $Target.ExpectationReason } $sdkTestDir = Join-Path $TempDir $Target.Id New-Item -ItemType Directory -Path $sdkTestDir -Force | Out-Null $currentLocation = Get-Location try { Set-Location $sdkTestDir $globalJsonContent = @" { "sdk": { "version": "$($Target.GlobalJsonVersion)", "rollForward": "$($Target.RollForward)" } } "@ Set-Content -Path "global.json" -Value $globalJsonContent Write-Host "Created global.json targeting $($Target.GlobalJsonVersion) (rollForward $($Target.RollForward))" $projectRoot = Join-Path (Get-Location).Path "MetaTest" New-Item -ItemType Directory -Path $projectRoot -Force | Out-Null $projectPath = New-RestoreProjectFile -Directory $projectRoot -ProjectName "MetaTest" -TargetFramework $Target.TargetFramework -PackageVersion $PackageVersion Set-Location $projectRoot Write-Host "Restoring packages..." $restoreArguments = @("restore", "--configfile", $NuGetConfig, "--verbosity", "minimal") $restoreResult = Invoke-CommandText -FilePath "dotnet" -ArgumentList $restoreArguments -WorkingDirectory (Get-Location).Path $restoreSucceeded = ($restoreResult.ExitCode -eq 0) if (-not $restoreSucceeded) { $severity = if ($Target.FailureExpected) { 'none' } else { 'error' } $context = "Restore failed for $($Target.DisplayName) during dotnet restore" if ($Target.FailureExpected -and $Target.ExpectationReason) { $context = "$context (expected: $($Target.ExpectationReason))" } elseif ($Target.FailureExpected) { $context = "$context (expected failure)" } $diagnostics = Publish-RestoreFailure $context $Target.DisplayName $restoreResult $severity $resultRecord.Details = Get-FailureDetailText -Diagnostics $diagnostics -ProcessResult $restoreResult if ($Target.FailureExpected) { $resultRecord.Success = $true } return $resultRecord } $objPath = "obj/project.assets.json" if (-not (Test-Path $objPath)) { Write-AzureDevOpsError "$($Target.DisplayName): project.assets.json not found after restore" $resultRecord.Details = "project.assets.json missing" return $resultRecord } Publish-RestoreSuccess "Restore succeeded: $($Target.DisplayName)" $Target.DisplayName $restoreResult if ($Target.FailureExpected) { $message = "$($Target.DisplayName): restore succeeded but failure was expected" if ($Target.ExpectationReason) { $message = "$message ($($Target.ExpectationReason))" } Write-Host "##[command]✗ $message" Write-AzureDevOpsError $message $resultRecord.Details = $message return $resultRecord } Write-Host "Building project..." $buildArguments = @("build", "--no-restore", "--verbosity", "minimal") $buildResult = Invoke-CommandText -FilePath "dotnet" -ArgumentList $buildArguments -WorkingDirectory (Get-Location).Path $buildSucceeded = ($buildResult.ExitCode -eq 0) if (-not $buildSucceeded) { $context = "Build failed for $($Target.DisplayName) during dotnet build" $diagnostics = Publish-RestoreFailure $context $Target.DisplayName $buildResult $resultRecord.Details = Get-FailureDetailText -Diagnostics $diagnostics -ProcessResult $buildResult return $resultRecord } Publish-RestoreSuccess "Build succeeded: $($Target.DisplayName)" $Target.DisplayName $buildResult $resultRecord.Success = $true return $resultRecord } catch { $exceptionText = $_ | Out-String $exceptionTrimmed = $exceptionText.Trim() Write-AzureDevOpsErrorDetail "Exception testing $($Target.DisplayName): $($_.Exception.Message)" $exceptionTrimmed if ($exceptionText) { Write-Host $exceptionText } $resultRecord.Details = $exceptionTrimmed return $resultRecord } finally { Set-Location $currentLocation } } function Invoke-MSBuildRestoreTarget { param( [PSCustomObject]$Target, [string]$TempDir, [string]$NuGetConfig, [string]$PackageVersion ) $resultRecord = [PSCustomObject]@{ Kind = 'msbuild' DisplayName = $Target.DisplayName Version = $Target.Version Success = $false Details = $null FailureExpected = [bool]$Target.FailureExpected ExpectationReason = $Target.ExpectationReason } $msbuildTestDir = Join-Path $TempDir $Target.Id New-Item -ItemType Directory -Path $msbuildTestDir -Force | Out-Null $currentLocation = Get-Location try { Set-Location $msbuildTestDir $projectRoot = Join-Path (Get-Location).Path "MetaTest" New-Item -ItemType Directory -Path $projectRoot -Force | Out-Null Set-Location $projectRoot $projectFile = New-RestoreProjectFile -Directory (Get-Location).Path -ProjectName "MetaTest" -TargetFramework "net48" -PackageVersion $PackageVersion $msbuildRestoreResult = Invoke-CommandText -FilePath $Target.Path -ArgumentList @($projectFile, "/t:Restore", "/p:RestoreConfigFile=$NuGetConfig", "/nologo") -WorkingDirectory (Get-Location).Path $restoreSucceeded = ($msbuildRestoreResult.ExitCode -eq 0) if (-not $restoreSucceeded) { $severity = if ($Target.FailureExpected) { 'none' } else { 'error' } $context = "Restore failed for $($Target.DisplayName) during MSBuild restore" if ($Target.FailureExpected -and $Target.ExpectationReason) { $context = "$context (expected: $($Target.ExpectationReason))" } elseif ($Target.FailureExpected) { $context = "$context (expected failure)" } $diagnostics = Publish-RestoreFailure $context $Target.DisplayName $msbuildRestoreResult $severity $resultRecord.Details = Get-FailureDetailText -Diagnostics $diagnostics -ProcessResult $msbuildRestoreResult if ($Target.FailureExpected) { $resultRecord.Success = $true } return $resultRecord } $msbuildAssetsPath = "obj/project.assets.json" if (-not (Test-Path $msbuildAssetsPath)) { Write-AzureDevOpsError "$($Target.DisplayName): project.assets.json not found after restore" $resultRecord.Details = "project.assets.json missing" return $resultRecord } Publish-RestoreSuccess "Restore succeeded: $($Target.DisplayName)" $Target.DisplayName $msbuildRestoreResult if ($Target.FailureExpected) { $message = "$($Target.DisplayName): restore succeeded but failure was expected" if ($Target.ExpectationReason) { $message = "$message ($($Target.ExpectationReason))" } Write-Host "##[command]✗ $message" Write-AzureDevOpsError $message $resultRecord.Details = $message return $resultRecord } Write-Host "Building project..." $msbuildBuildResult = Invoke-CommandText -FilePath $Target.Path -ArgumentList @($projectFile, "/t:Build", "/p:Restore=false", "/nologo") -WorkingDirectory (Get-Location).Path $buildSucceeded = ($msbuildBuildResult.ExitCode -eq 0) if (-not $buildSucceeded) { $context = "Build failed for $($Target.DisplayName) during MSBuild build" $diagnostics = Publish-RestoreFailure $context $Target.DisplayName $msbuildBuildResult $resultRecord.Details = Get-FailureDetailText -Diagnostics $diagnostics -ProcessResult $msbuildBuildResult return $resultRecord } Publish-RestoreSuccess "Build succeeded: $($Target.DisplayName)" $Target.DisplayName $msbuildBuildResult $resultRecord.Success = $true return $resultRecord } catch { $exceptionText = $_ | Out-String $exceptionTrimmed = $exceptionText.Trim() Write-AzureDevOpsErrorDetail "Exception testing $($Target.DisplayName): $($_.Exception.Message)" $exceptionTrimmed if ($exceptionText) { Write-Host $exceptionText } $resultRecord.Details = $exceptionTrimmed return $resultRecord } finally { Set-Location $currentLocation } } function Write-RestoreDiagnosticLines { param( [string]$DisplayName, [PSCustomObject]$Diagnostics, [ValidateSet('error','warning','none')] [string]$ErrorSeverity = 'error' ) if ($null -eq $Diagnostics) { return } if ($Diagnostics.Warnings -and $Diagnostics.Warnings.Count -gt 0) { foreach ($warningLine in $Diagnostics.Warnings | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) { $message = "${DisplayName}: $($warningLine.Trim())" Write-Host $message if ($ErrorSeverity -ne 'none') { Write-AzureDevOpsWarning $message } } } if ($Diagnostics.Errors -and $Diagnostics.Errors.Count -gt 0) { foreach ($errorLine in $Diagnostics.Errors | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) { $message = "${DisplayName}: $($errorLine.Trim())" Write-Host $message switch ($ErrorSeverity) { 'warning' { Write-AzureDevOpsWarning $message } 'error' { Write-AzureDevOpsError $message } } } } } function Publish-RestoreFailure { param( [string]$Context, [string]$DisplayName, [PSCustomObject]$ProcessResult, [ValidateSet('error','warning','none')] [string]$ErrorSeverity = 'error' ) if (-not [string]::IsNullOrWhiteSpace($Context)) { Write-Host "##[command]✗ $Context" } if ($null -eq $ProcessResult) { if (-not [string]::IsNullOrWhiteSpace($Context)) { if ($ErrorSeverity -eq 'warning') { Write-AzureDevOpsWarning $Context } elseif ($ErrorSeverity -eq 'error') { Write-AzureDevOpsError $Context } } return $null } if ($ErrorSeverity -ne 'none') { Write-FilteredProcessOutput -ProcessResult $ProcessResult } $diagnostics = Get-RestoreDiagnostics -Output $ProcessResult.Output Write-RestoreDiagnosticLines -DisplayName $DisplayName -Diagnostics $diagnostics -ErrorSeverity $ErrorSeverity if (($diagnostics.Errors.Count -eq 0) -and ($diagnostics.Warnings.Count -eq 0)) { $fallbackMessage = $ProcessResult.Output if (-not [string]::IsNullOrWhiteSpace($fallbackMessage)) { $fallbackLines = ($fallbackMessage -split "(`r`n|`r|`n)") | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } foreach ($line in $fallbackLines) { $trimmedFallback = $line.Trim() if ([string]::IsNullOrWhiteSpace($trimmedFallback)) { continue } if ($trimmedFallback -match '^(?i)info\s*:') { continue } $message = "${DisplayName}: $trimmedFallback" Write-Host $message if ($ErrorSeverity -eq 'warning') { Write-AzureDevOpsWarning $message } elseif ($ErrorSeverity -eq 'error') { Write-AzureDevOpsError $message } } } } return $diagnostics } function Publish-RestoreSuccess { param( [string]$Context, [string]$DisplayName, [PSCustomObject]$ProcessResult ) if (-not [string]::IsNullOrWhiteSpace($Context)) { Write-Host "##[command]✓ $Context" } if ($null -eq $ProcessResult) { return $null } $diagnostics = Get-RestoreDiagnostics -Output $ProcessResult.Output Write-RestoreDiagnosticLines -DisplayName $DisplayName -Diagnostics $diagnostics return $diagnostics } function Get-FailureDetailText { param( [PSCustomObject]$Diagnostics, [PSCustomObject]$ProcessResult ) if ($Diagnostics) { if ($Diagnostics.Errors -and $Diagnostics.Errors.Count -gt 0) { return ($Diagnostics.Errors -join "`n").Trim() } if ($Diagnostics.Warnings -and $Diagnostics.Warnings.Count -gt 0) { return ($Diagnostics.Warnings -join "`n").Trim() } } if ($ProcessResult) { if (-not [string]::IsNullOrWhiteSpace($ProcessResult.Output)) { return $ProcessResult.Output.Trim() } } return $null } function Invoke-WapProjSmokeTest { param( [Parameter(Mandatory = $true)][string]$PackageVersion, [Parameter(Mandatory = $true)][string]$PackagesDirectory, [Parameter(Mandatory = $true)][string]$MsbuildPath, [Parameter(Mandatory = $true)][string]$TempDir ) $resultRecord = [PSCustomObject]@{ DisplayName = "WAP project smoke test" Success = $false Executed = $false Details = $null } $fixtureRoot = Join-Path $PSScriptRoot "fixtures\WapProjSmoke" if (-not (Test-Path $fixtureRoot)) { $resultRecord.Details = "WAP project fixture directory not found: $fixtureRoot" return $resultRecord } $smokeRoot = Join-Path $TempDir "WapProjSmoke" if (Test-Path $smokeRoot) { Remove-Item -Path $smokeRoot -Recurse -Force -ErrorAction SilentlyContinue } $localPackagesDirectory = Join-Path $smokeRoot ".nuget\packages" New-Item -ItemType Directory -Path $smokeRoot -Force | Out-Null Copy-Item -Path (Join-Path $fixtureRoot "EntryPointApp") -Destination (Join-Path $smokeRoot "EntryPointApp") -Recurse -Force Copy-Item -Path (Join-Path $fixtureRoot "Package") -Destination (Join-Path $smokeRoot "Package") -Recurse -Force New-Item -ItemType Directory -Path $localPackagesDirectory -Force | Out-Null $entryPointDirectory = Join-Path $smokeRoot "EntryPointApp" $packageDirectory = Join-Path $smokeRoot "Package" $entryPointProjectFile = Join-Path $entryPointDirectory "EntryPointApp.csproj" Expand-TemplateFile ` -TemplatePath (Join-Path $entryPointDirectory "EntryPointApp.csproj.template") ` -DestinationPath $entryPointProjectFile ` -Tokens @{ "__PACKAGE_VERSION__" = $PackageVersion "__PACKAGES_PATH__" = $localPackagesDirectory } Remove-Item -Path (Join-Path $entryPointDirectory "EntryPointApp.csproj.template") -Force -ErrorAction SilentlyContinue $wapProjectFile = Join-Path $packageDirectory "Package.wapproj" Expand-TemplateFile ` -TemplatePath (Join-Path $packageDirectory "Package.wapproj.template") ` -DestinationPath $wapProjectFile ` -Tokens @{ "__PACKAGES_PATH__" = $localPackagesDirectory } Remove-Item -Path (Join-Path $packageDirectory "Package.wapproj.template") -Force -ErrorAction SilentlyContinue $nuGetConfigFile = Join-Path $smokeRoot "NuGet.config" $nuGetConfigContent = @' '@.Replace("__PACKAGES_DIRECTORY__", (Resolve-Path $PackagesDirectory).Path).Replace("__PACKAGES_PATH__", $localPackagesDirectory) Set-Content -Path $nuGetConfigFile -Value $nuGetConfigContent -Encoding UTF8 $restoreArguments = @( $wapProjectFile, "/t:Restore", "/p:RestoreConfigFile=$nuGetConfigFile", "/p:Platform=x64", "/p:Configuration=Release", "/p:RuntimeIdentifier=win-x64", "/p:SelfContained=true", "/p:RestorePackagesPath=$localPackagesDirectory", "/nologo" ) $restoreResult = Invoke-CommandText -FilePath $MsbuildPath -ArgumentList $restoreArguments -WorkingDirectory $packageDirectory if ($restoreResult.ExitCode -ne 0) { $diagnostics = Publish-RestoreFailure "WAP project restore failed" $resultRecord.DisplayName $restoreResult $resultRecord.Details = Get-FailureDetailText -Diagnostics $diagnostics -ProcessResult $restoreResult return $resultRecord } $buildArguments = @( $wapProjectFile, "/t:Build", "/p:Restore=false", "/p:RestoreConfigFile=$nuGetConfigFile", "/p:Platform=x64", "/p:Configuration=Release", "/p:RuntimeIdentifier=win-x64", "/p:SelfContained=true", "/p:RestorePackagesPath=$localPackagesDirectory", "/nologo" ) $buildResult = Invoke-CommandText -FilePath $MsbuildPath -ArgumentList $buildArguments -WorkingDirectory $packageDirectory $resultRecord.Executed = $true if ($buildResult.ExitCode -ne 0) { $diagnostics = Publish-RestoreFailure "WAP project build failed" $resultRecord.DisplayName $buildResult $resultRecord.Details = Get-FailureDetailText -Diagnostics $diagnostics -ProcessResult $buildResult return $resultRecord } Publish-RestoreSuccess "WAP project build succeeded" $resultRecord.DisplayName $buildResult | Out-Null $resultRecord.Success = $true return $resultRecord } function Get-PackageReferencesXml { param( [Parameter(Mandatory = $true)][string]$Scenario, [Parameter(Mandatory = $true)][string]$PackageVersion ) switch ($Scenario.ToLowerInvariant()) { 'meta' { return @" "@ } 'core-lang' { return @" "@ } default { throw "Unsupported package smoke scenario '$Scenario'" } } } function Expand-TemplateDirectory { param( [Parameter(Mandatory = $true)][string]$TemplateDirectory, [Parameter(Mandatory = $true)][string]$DestinationDirectory, [Parameter(Mandatory = $true)][hashtable]$Tokens ) New-Item -ItemType Directory -Path $DestinationDirectory -Force | Out-Null foreach ($item in Get-ChildItem -Path $TemplateDirectory -Recurse -Force) { $relativePath = $item.FullName.Substring($TemplateDirectory.Length).TrimStart('\', '/') if ([string]::IsNullOrWhiteSpace($relativePath)) { continue } if ($item.PSIsContainer) { New-Item -ItemType Directory -Path (Join-Path $DestinationDirectory $relativePath) -Force | Out-Null continue } $targetRelativePath = if ($relativePath.EndsWith('.template')) { $relativePath.Substring(0, $relativePath.Length - '.template'.Length) } else { $relativePath } $destinationPath = Join-Path $DestinationDirectory $targetRelativePath $destinationParent = Split-Path -Parent $destinationPath if (-not [string]::IsNullOrWhiteSpace($destinationParent)) { New-Item -ItemType Directory -Path $destinationParent -Force | Out-Null } if (-not $relativePath.EndsWith('.template')) { Copy-Item -Path $item.FullName -Destination $destinationPath -Force continue } $content = Get-Content -Raw $item.FullName foreach ($token in $Tokens.GetEnumerator()) { $content = $content.Replace($token.Key, [string]$token.Value) } Set-Content -Path $destinationPath -Value $content -Encoding UTF8 } } function New-SmokeProjectNuGetConfig { param( [Parameter(Mandatory = $true)][string]$ProjectDirectory, [Parameter(Mandatory = $true)][string]$PackagesDirectory ) $globalPackagesDirectory = Join-Path $ProjectDirectory ".nuget\packages" New-Item -ItemType Directory -Path $globalPackagesDirectory -Force | Out-Null $nuGetConfigPath = Join-Path $ProjectDirectory "NuGet.config" $nuGetConfigContent = @" "@ Set-Content -Path $nuGetConfigPath -Value $nuGetConfigContent -Encoding UTF8 return [PSCustomObject]@{ GlobalPackagesDirectory = $globalPackagesDirectory NuGetConfigPath = $nuGetConfigPath } } function Expand-TemplateFile { param( [Parameter(Mandatory = $true)][string]$TemplatePath, [Parameter(Mandatory = $true)][string]$DestinationPath, [Parameter(Mandatory = $true)][hashtable]$Tokens ) $content = Get-Content -Raw $TemplatePath foreach ($token in $Tokens.GetEnumerator()) { $content = $content.Replace($token.Key, [string]$token.Value) } $destinationParent = Split-Path -Parent $DestinationPath if (-not [string]::IsNullOrWhiteSpace($destinationParent)) { New-Item -ItemType Directory -Path $destinationParent -Force | Out-Null } Set-Content -Path $DestinationPath -Value $content -Encoding UTF8 } function Invoke-SmokeProject { param( [Parameter(Mandatory = $true)][string]$TemplateDirectory, [Parameter(Mandatory = $true)][string]$DisplayName, [Parameter(Mandatory = $true)][string]$TargetFramework, [Parameter(Mandatory = $true)][string]$Scenario, [Parameter(Mandatory = $true)][string]$PackageVersion, [Parameter(Mandatory = $true)][string]$PackagesDirectory, [Parameter(Mandatory = $true)][string]$TempDir, [switch]$ExpectAnalyzerDiagnostic ) $resultRecord = [PSCustomObject]@{ DisplayName = $DisplayName Success = $false Details = $null } $templateName = Split-Path -Leaf $TemplateDirectory $workingDirectory = Join-Path $TempDir ("smoke-{0}-{1}-{2}" -f $templateName, $Scenario, ($TargetFramework -replace '[^A-Za-z0-9]', '')) if (Test-Path $workingDirectory) { Remove-Item -Path $workingDirectory -Recurse -Force -ErrorAction SilentlyContinue } Expand-TemplateDirectory ` -TemplateDirectory $TemplateDirectory ` -DestinationDirectory $workingDirectory ` -Tokens @{ "__PACKAGE_REFERENCES__" = Get-PackageReferencesXml -Scenario $Scenario -PackageVersion $PackageVersion "__TARGET_FRAMEWORK__" = $TargetFramework } if ($ExpectAnalyzerDiagnostic) { Copy-Item -Path (Join-Path $PSScriptRoot "fixtures\PackageSmoke\AnalyzerProbe.cs") -Destination (Join-Path $workingDirectory "AnalyzerProbe.cs") -Force } $projectContext = New-SmokeProjectNuGetConfig -ProjectDirectory $workingDirectory -PackagesDirectory $PackagesDirectory $projectFile = Join-Path $workingDirectory "Consumer.csproj" $restoreResult = Invoke-CommandText ` -FilePath "dotnet" ` -ArgumentList @("restore", $projectFile, "--configfile", $projectContext.NuGetConfigPath, "--packages", $projectContext.GlobalPackagesDirectory) ` -WorkingDirectory $workingDirectory if ($restoreResult.ExitCode -ne 0) { $diagnostics = Publish-RestoreFailure "Smoke project restore failed: $DisplayName" $DisplayName $restoreResult $resultRecord.Details = Get-FailureDetailText -Diagnostics $diagnostics -ProcessResult $restoreResult return $resultRecord } $buildResult = Invoke-CommandText -FilePath "dotnet" -ArgumentList @("build", $projectFile, "--no-restore") -WorkingDirectory $workingDirectory if ($ExpectAnalyzerDiagnostic) { if ($buildResult.ExitCode -eq 0 -or ($buildResult.Output -notmatch 'HUMANIZER001')) { $resultRecord.Details = "Expected HUMANIZER001 analyzer diagnostic for $DisplayName." return $resultRecord } $resultRecord.Success = $true return $resultRecord } if ($buildResult.ExitCode -ne 0) { $diagnostics = Publish-RestoreFailure "Smoke project build failed: $DisplayName" $DisplayName $buildResult $resultRecord.Details = Get-FailureDetailText -Diagnostics $diagnostics -ProcessResult $buildResult return $resultRecord } $resultRecord.Success = $true return $resultRecord } function Invoke-PackageSmokeTests { param( [Parameter(Mandatory = $true)][string]$PackageVersion, [Parameter(Mandatory = $true)][string]$PackagesDirectory, [Parameter(Mandatory = $true)][string[]]$TargetFrameworks, [Parameter(Mandatory = $true)][string[]]$Hosts, [Parameter(Mandatory = $true)][string[]]$Scenarios ) $resultRecord = [PSCustomObject]@{ DisplayName = "Package smoke tests" Success = $false Executed = $false Details = $null Hosts = @($Hosts) TargetFrameworks = @($TargetFrameworks) Scenarios = @($Scenarios) } if ($TargetFrameworks.Count -eq 0 -or $Hosts.Count -eq 0 -or $Scenarios.Count -eq 0) { $resultRecord.Success = $true $resultRecord.Details = "Package smoke tests skipped (no frameworks, hosts, or scenarios configured)" return $resultRecord } $packageSmokeFixtureRoot = Join-Path $PSScriptRoot "fixtures\PackageSmoke" if (-not (Test-Path $packageSmokeFixtureRoot)) { $resultRecord.Details = "Package smoke fixture root not found: $packageSmokeFixtureRoot" return $resultRecord } $resolvedPackagesDirectory = (Resolve-Path $PackagesDirectory).Path $smokeResults = @() foreach ($scenario in $Scenarios) { foreach ($targetFramework in $TargetFrameworks) { foreach ($hostName in $Hosts) { switch ($hostName) { 'console' { $smokeResults += Invoke-SmokeProject ` -TemplateDirectory (Join-Path $packageSmokeFixtureRoot 'ConsoleConsumer') ` -DisplayName "Console $scenario $targetFramework" ` -TargetFramework $targetFramework ` -Scenario $scenario ` -PackageVersion $PackageVersion ` -PackagesDirectory $resolvedPackagesDirectory ` -TempDir $TempDir } 'webapi' { if ($targetFramework -eq 'net48') { continue } $smokeResults += Invoke-SmokeProject ` -TemplateDirectory (Join-Path $packageSmokeFixtureRoot 'WebApiConsumer') ` -DisplayName "Web API $scenario $targetFramework" ` -TargetFramework $targetFramework ` -Scenario $scenario ` -PackageVersion $PackageVersion ` -PackagesDirectory $resolvedPackagesDirectory ` -TempDir $TempDir } 'blazor' { if ($targetFramework -eq 'net48') { continue } $smokeResults += Invoke-SmokeProject ` -TemplateDirectory (Join-Path $packageSmokeFixtureRoot 'BlazorConsumer') ` -DisplayName "Blazor $scenario $targetFramework" ` -TargetFramework $targetFramework ` -Scenario $scenario ` -PackageVersion $PackageVersion ` -PackagesDirectory $resolvedPackagesDirectory ` -TempDir $TempDir } } } } } $smokeResults += Invoke-SmokeProject ` -TemplateDirectory (Join-Path $packageSmokeFixtureRoot 'ConsoleConsumer') ` -DisplayName 'Console analyzer net48' ` -TargetFramework 'net48' ` -Scenario 'meta' ` -PackageVersion $PackageVersion ` -PackagesDirectory $resolvedPackagesDirectory ` -TempDir $TempDir ` -ExpectAnalyzerDiagnostic $smokeResults += Invoke-SmokeProject ` -TemplateDirectory (Join-Path $packageSmokeFixtureRoot 'BlazorConsumer') ` -DisplayName 'Blazor analyzer net8.0' ` -TargetFramework 'net8.0' ` -Scenario 'meta' ` -PackageVersion $PackageVersion ` -PackagesDirectory $resolvedPackagesDirectory ` -TempDir $TempDir ` -ExpectAnalyzerDiagnostic $resultRecord.Executed = ($smokeResults.Count -gt 0) $failedSmokeResult = $smokeResults | Where-Object { -not $_.Success } | Select-Object -First 1 if ($null -ne $failedSmokeResult) { $resultRecord.Details = $failedSmokeResult.Details return $resultRecord } $resultRecord.Success = $true return $resultRecord } Write-AzureDevOpsSection "Humanizer Package Verification" Write-Host "Package Version: $PackageVersion" Write-Host "Packages Directory: $PackagesDirectory" Write-Host "" # Verify the packages directory exists if (-not (Test-Path $PackagesDirectory)) { Write-AzureDevOpsError "Packages directory not found: $PackagesDirectory" throw "Packages directory not found: $PackagesDirectory" } # Find all packages $mainPackage = Get-ChildItem -Path $PackagesDirectory -Filter "Humanizer.$PackageVersion.nupkg" -File $corePackage = Get-ChildItem -Path $PackagesDirectory -Filter "Humanizer.Core.$PackageVersion.nupkg" -File $satellitePackages = Get-ChildItem -Path $PackagesDirectory -Filter "Humanizer.Core.*.$PackageVersion.nupkg" -File | Where-Object { $_.Name -ne "Humanizer.Core.$PackageVersion.nupkg" } if (-not $mainPackage) { Write-AzureDevOpsError "Main Humanizer metapackage not found: Humanizer.$PackageVersion.nupkg" throw "Main Humanizer metapackage not found" } Write-Host "##[command]Found main metapackage: $($mainPackage.Name)" if (-not $corePackage) { Write-AzureDevOpsError "Humanizer.Core package not found: Humanizer.Core.$PackageVersion.nupkg" throw "Humanizer.Core package not found" } Write-Host "##[command]Found core package: $($corePackage.Name)" Write-Host "##[command]Found $($satellitePackages.Count) satellite (localized) packages" $satellitePackages | ForEach-Object { Write-Host " - $($_.Name)" } Write-Host "" # Create a temporary test directory $tempPath = if ($env:TEMP) { $env:TEMP } elseif ($env:TMP) { $env:TMP } else { "/tmp" } $tempDir = Join-Path $tempPath "HumanizerPackageTest_$(New-Guid)" New-Item -ItemType Directory -Path $tempDir -Force | Out-Null try { # Create NuGet.config pointing to local packages $nugetConfig = Join-Path $tempDir "NuGet.config" $absolutePackagesDir = (Resolve-Path $PackagesDirectory).Path $nugetConfigContent = @" "@ Set-Content -Path $nugetConfig -Value $nugetConfigContent # Discover restore targets $restoreTestResults = @() $verificationFailures = @() $runningOnWindows = $false try { $runningOnWindows = [System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform([System.Runtime.InteropServices.OSPlatform]::Windows) } catch { $runningOnWindows = $false } $restoreTargets = Get-RestoreTargets -RunningOnWindows $runningOnWindows -MinimumPassingSdkVersion $MinimumPassingSdkVersion $smokeTestTargetFrameworkList = @('net8.0', 'net9.0', 'net10.0', 'net11.0') if ($runningOnWindows) { $smokeTestTargetFrameworkList += 'net48' } $smokeTestHostList = @('console', 'webapi', 'blazor') if ($runningOnWindows -and $IncludeWapProjSmokeTest) { $smokeTestHostList += 'wapproj' } $packageSmokeHostList = @($smokeTestHostList | Where-Object { $_ -ne 'wapproj' }) $smokeTestScenarioList = @('meta', 'core-lang') foreach ($target in $restoreTargets) { Write-AzureDevOpsSection "Testing package restoration with $($target.DisplayName)" if ($target.Kind -eq 'dotnet') { $testResult = Invoke-DotnetRestoreTarget -Target $target -TempDir $tempDir -NuGetConfig $nugetConfig -PackageVersion $PackageVersion } elseif ($target.Kind -eq 'msbuild') { $testResult = Invoke-MSBuildRestoreTarget -Target $target -TempDir $tempDir -NuGetConfig $nugetConfig -PackageVersion $PackageVersion } else { continue } if ($null -ne $testResult) { $restoreTestResults += $testResult } } Write-Host "" Write-AzureDevOpsSection "Restore Test Results" $validRestoreResults = @($restoreTestResults | Where-Object { $_ -and -not [string]::IsNullOrWhiteSpace($_.DisplayName) }) if ($validRestoreResults.Count -eq 0) { Write-AzureDevOpsWarning "No restore tests were executed" } else { foreach ($result in $validRestoreResults) { if ($result.Success) { Write-Host " ✓ $($result.DisplayName)" } else { Write-Host " ✗ $($result.DisplayName)" } } } # Verify main metapackage can be restored and pulls in satellites Write-Host "" Write-AzureDevOpsSection "Verifying Humanizer metapackage dependencies" Push-Location $tempDir $missingSatellites = @() $metapackageCheckCompleted = $false Write-Host "Creating test project..." $metaVerificationSucceeded = $true $metaProjectCreated = $false $metaProjectRoot = Join-Path (Get-Location).Path "MetaTest" try { New-Item -ItemType Directory -Path $metaProjectRoot -Force | Out-Null $metaProjectPath = New-RestoreProjectFile -Directory $metaProjectRoot -ProjectName "MetaTest" -TargetFramework "net8.0" -PackageVersion $PackageVersion $metaProjectCreated = $true } catch { $metaVerificationSucceeded = $false $metaProjectCreated = $false $creationDetails = ($_ | Out-String) Write-AzureDevOpsErrorDetail "Failed to create metapackage verification project" $creationDetails $verificationFailures += "Metapackage verification project creation failed" } if ($metaVerificationSucceeded -and $metaProjectCreated) { Set-Location $metaProjectRoot } if ($metaVerificationSucceeded -and $metaProjectCreated) { Write-Host "Restoring packages..." $globalRestoreResult = Invoke-CommandText -FilePath "dotnet" -ArgumentList @("restore", "--configfile", $nugetConfig) -WorkingDirectory (Get-Location).Path if ($globalRestoreResult.ExitCode -ne 0) { Publish-RestoreFailure "Failed to restore Humanizer metapackage" "Humanizer metapackage" $globalRestoreResult $verificationFailures += "Metapackage restore failed" $metaVerificationSucceeded = $false } else { Publish-RestoreSuccess "Humanizer metapackage restore succeeded" "Humanizer metapackage" $globalRestoreResult } if ($metaVerificationSucceeded) { $objPath = "obj/project.assets.json" if (-not (Test-Path $objPath)) { Write-AzureDevOpsError "project.assets.json not found after metapackage restore" $verificationFailures += "Metapackage restore assets missing" $metaVerificationSucceeded = $false } else { $assets = Get-Content $objPath | ConvertFrom-Json $restoredPackages = $assets.libraries.PSObject.Properties.Name | Where-Object { $_ -like "Humanizer*" } Write-Host "Restored packages:" $restoredPackages | ForEach-Object { Write-Host " - $_" } Write-Host "" $missingSatellites = @() foreach ($satellite in $satellitePackages) { $pkgName = $satellite.Name -replace "\.$PackageVersion\.nupkg$", "" $pkgEntry = "$pkgName/$PackageVersion" if ($restoredPackages -notcontains $pkgEntry) { $missingSatellites += $pkgName } } $metapackageCheckCompleted = $true if ($missingSatellites.Count -gt 0) { $missingMessage = "The following satellite packages are NOT dependencies of the Humanizer metapackage: $($missingSatellites -join ', ')" Write-AzureDevOpsError $missingMessage $verificationFailures += "Humanizer metapackage dependencies are incomplete" } else { Write-Host "##[command]✓ All $($satellitePackages.Count) satellite packages are dependencies of the Humanizer metapackage" } } } } if ($metaProjectCreated -and (Get-Location).Path -like "*MetaTest") { Set-Location .. } Pop-Location Write-Host "" Write-AzureDevOpsSection "Running package smoke tests" $packageSmokeTestResult = Invoke-PackageSmokeTests ` -PackageVersion $PackageVersion ` -PackagesDirectory $PackagesDirectory ` -TargetFrameworks $smokeTestTargetFrameworkList ` -Hosts $packageSmokeHostList ` -Scenarios $smokeTestScenarioList if (-not $packageSmokeTestResult.Success) { $verificationFailures += "Package smoke tests failed" } $wapProjSmokeTestResult = [PSCustomObject]@{ DisplayName = "WAP project smoke test" Success = $true Executed = $false Details = $null } if ($smokeTestHostList -contains 'wapproj') { $msbuildSmokeTarget = $restoreTargets | Where-Object { $_.Kind -eq 'msbuild' } | Select-Object -First 1 if ($null -eq $msbuildSmokeTarget) { $wapProjSmokeTestResult.Success = $false $wapProjSmokeTestResult.Details = "WAP project smoke test requested but no MSBuild installation was found." $verificationFailures += "WAP project smoke tests failed" } else { Write-AzureDevOpsSection "Running WAP project smoke test" $wapProjSmokeTestResult = Invoke-WapProjSmokeTest ` -PackageVersion $PackageVersion ` -PackagesDirectory $PackagesDirectory ` -MsbuildPath $msbuildSmokeTarget.Path ` -TempDir $tempDir if (-not $wapProjSmokeTestResult.Success) { $verificationFailures += "WAP project smoke tests failed" } } } Write-AzureDevOpsSection "Verification Summary" $restoreSuccesses = @($validRestoreResults | Where-Object { $_.Success }) $restoreFailures = @($validRestoreResults | Where-Object { -not $_.Success }) $restorePassedCount = $restoreSuccesses.Count $restoreTotalCount = $validRestoreResults.Count $summaryLines = @() $summaryLines += "Summary:" $summaryLines += " ✓ Humanizer" $summaryLines += " ✓ Humanizer.Core" $satelliteLine = " ✓ Satellite packages verified: $($satellitePackages.Count)" if ($satellitePackages.Count -eq 0) { $satelliteLine = " ✗ Satellite packages verified: 0" } $summaryLines += $satelliteLine if ($metapackageCheckCompleted -and $missingSatellites.Count -eq 0) { $summaryLines += " ✓ All satellites are dependencies of Humanizer" } elseif ($metapackageCheckCompleted) { $summaryLines += " ✗ All satellites are dependencies of Humanizer" } else { $summaryLines += " ✗ All satellites are dependencies of Humanizer (not verified)" } if ($packageSmokeTestResult.Success -and $packageSmokeTestResult.Executed) { $summaryLines += " ✓ Package smoke tests: $($packageSmokeTestResult.TargetFrameworks -join ', ') / $($packageSmokeTestResult.Hosts -join ', ') / $($packageSmokeTestResult.Scenarios -join ', ')" } elseif ($packageSmokeTestResult.Executed) { $summaryLines += " ✗ Package smoke tests: $($packageSmokeTestResult.TargetFrameworks -join ', ') / $($packageSmokeTestResult.Hosts -join ', ') / $($packageSmokeTestResult.Scenarios -join ', ')" } else { $summaryLines += " ✓ Package smoke tests skipped" } if ($smokeTestHostList -contains 'wapproj') { if ($wapProjSmokeTestResult.Success -and $wapProjSmokeTestResult.Executed) { $summaryLines += " ✓ WAP project smoke test" } elseif ($wapProjSmokeTestResult.Executed -or -not $wapProjSmokeTestResult.Success) { $summaryLines += " ✗ WAP project smoke test" } else { $summaryLines += " ✓ WAP project smoke test skipped" } } $summaryLines += "" $summaryLines += "Restore tests passed: $restorePassedCount/$restoreTotalCount" if ($restoreTotalCount -eq 0) { $summaryLines += " (no restore tests executed)" } else { foreach ($result in $restoreSuccesses) { $formatted = Format-RestoreSummaryLine -Result $result -PrefixSymbol "✓" if ($formatted) { $summaryLines += $formatted } } } if ($restoreFailures.Count -gt 0) { $summaryLines += "Restore tests failed:" foreach ($failure in $restoreFailures) { $formattedFailure = Format-RestoreSummaryLine -Result $failure -PrefixSymbol "✗" if ($formattedFailure) { $summaryLines += $formattedFailure } } } if ($verificationFailures.Count -gt 0) { $summaryLines += "" foreach ($failure in $verificationFailures) { $summaryLines += " ✗ $failure" } } foreach ($line in $summaryLines) { Write-Host $line } $summaryText = $summaryLines -join "`n" $hasFailures = ($restoreFailures.Count -gt 0) -or ($verificationFailures.Count -gt 0) if ($hasFailures) { Write-AzureDevOpsError $summaryText $completionMessage = ConvertTo-AzureDevOpsCommandValue $summaryText Write-Host "##vso[task.complete result=Failed;]$completionMessage" } else { if ($script:AzureDevOpsWarningLogged) { Write-AzureDevOpsWarning $summaryText } else { $completionMessage = ConvertTo-AzureDevOpsCommandValue $summaryText Write-Host "##vso[task.complete result=Succeeded;]$completionMessage" } } } catch { $catchText = ($_ | Out-String).Trim() Write-AzureDevOpsErrorDetail $_.Exception.Message $catchText throw } finally { # Cleanup if (Test-Path $tempDir) { Write-Host "" Write-Host "Cleaning up temporary directory..." Remove-Item -Path $tempDir -Recurse -Force -ErrorAction SilentlyContinue } } ================================================ FILE: version.json ================================================ { "version": "3.1.0-dev.{height}", "publicReleaseRefSpec": [ "^refs/heads/main$", // we release out of main "^refs/heads/rel/v\\d+\\.\\d+" // we also release branches starting with rel/vN.N ], "nugetPackageVersion":{ "semVer": 2 } }