开发工具【免费下载链接】HumanizerHumanizer meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities项目地址https://gitcode.com/gh_mirrors/hu/Humanizer点击查看免费下载导读IGrammaticalCaseTimeSpanHumanizeStrategy是 Humanizer 中为时间跨度TimeSpan人文化Humanize能力提供语法格grammatical case感知的扩展接口。在许多屈折语如德语、匈牙利语、芬兰语、巴斯克语、马来语中名词与数字组合后的短语会因在句子中充当主语、宾语、属格、方位等不同句法角色而变化词形Humanizer 通过本接口与配套的HumanizeWithCase扩展方法允许你为时长短语显式指定语法格输出符合该语言格系统的本地化文本。读完本文你将掌握该接口的签名与职责、它与ITimeSpanHumanizeStrategy的关系、底层调用链从扩展方法到格式化器再到本地化词形表以及如何在实际项目中正确使用并规避异常。一、接口定位可选地扩展时长人文化策略在 src/Humanizer/TimeSpanHumanizeStrategy/IGrammaticalCaseTimeSpanHumanizeStrategy.cs 中接口定义如下public interface IGrammaticalCaseTimeSpanHumanizeStrategy : ITimeSpanHumanizeStrategy { string Humanize( TimeSpan timeSpan, int precision, bool countEmptyUnits, CultureInfo? culture, TimeUnit maxUnit, TimeUnit minUnit, string? collectionSeparator, bool toSymbols, GrammaticalCase grammaticalCase); }接口文档原文用 Optionally extends a time-span humanization strategy with grammatical-case support可选地为时长人文化策略扩展语法格支持来界定其性质它继承自ITimeSpanHumanizeStrategy因此实现它的策略天然兼容所有已有的时长 API如Humanize()、HumanizeToSymbols()它额外提供一个带GrammaticalCase参数的Humanize重载专门服务于HumanizeWithCase这一类按语法格输出的调用反过来只实现ITimeSpanHumanizeStrategy的旧策略依然有效但无法服务HumanizeWithCase——这正是接口注释中 cannot serviceHumanizeWithCase 的含义。从源码结构看当前仓库中该接口的直接实现是 DefaultTimeSpanHumanizeStrategy文档Derived ↳一节所指的实现类它显式实现了带格的Humanize并转发到内部TimeSpanHumanizeExtensions.DefaultHumanizeWithCase。为什么需要语法格TimeSpan.Humanize()默认输出的是孤立时长短语例如德语中的 1 Woche。但当这句话进入真实句子时作主语Eine Wocheist vergangen.一周过去了——主格Nominative作宾语/时间状语Wir warten seiteiner Woche.我们等了一周了——与格Dative。只有按目标语言的实际格系统选择词形输出才自然。GrammaticalCase枚举见 src/Humanizer/GrammaticalCase.cs定义了 30 个格值从常见的 Nominative/Genitive/Dative/Accusative/Instrumental/Prepositional到更专业的 Ablative、Ergative、Partitive、Vocative、Translative、Causal 等覆盖多种语言的格系统。二、Humanize方法详解参数、返回值与异常方法签名string Humanize( System.TimeSpan timeSpan, int precision, bool countEmptyUnits, System.Globalization.CultureInfo? culture, Humanizer.TimeUnit maxUnit, Humanizer.TimeUnit minUnit, string? collectionSeparator, bool toSymbols, Humanizer.GrammaticalCase grammaticalCase);参数说明参数类型说明timeSpanTimeSpan要被转成人化文本的时间跨度。precisionint最多返回多少个时间单位。例如precision: 3最多显示 3 个非空单位。countEmptyUnitsbool空的时间单位是否计入precision。注意前导空单位永远不计入源码注释明确 Leading empty time units never count。cultureCultureInfo?使用的区域文化为null时使用当前线程文化。maxUnitTimeUnit允许输出的最大时间单位如Week、Day。Month/Year对大于 30 天的跨度按一年 365.2425 天、一月约 30.4369 天做近似见 TimeSpanHumanizeExtensions.cs 的DaysInAYear/DaysInAMonth常量。minUnitTimeUnit允许输出的最小时间单位。collectionSeparatorstring?多个时间单位拼接用的分隔符为null时使用该文化的默认集合格式化器CollectionFormatters。toSymbolsbool时间单位是否渲染为符号如 2 d 而非 2 days。注意HumanizeWithCase路径固定传false且核心实现明确禁止符号 语法格组合见下文。grammaticalCaseGrammaticalCase用于为每个单位短语选择词形的语法格。返回值string——一段由区域文化编写的裸时长短语其数量可能显式写出也可能编码在单位词形中文档 Returns 原文。裸bare指不加介词例如HumanizeWithCase(GrammaticalCase.Dative, ...)输出 einer Woche而不是 seit einer Woche。异常契约接口文档明确声明两个异常ArgumentOutOfRangeExceptiongrammaticalCase超出其枚举定义范围时抛出。这与 TimeSpanHumanizeExtensions.cs 中的ValidateGrammaticalCase一致(uint)grammaticalCase (uint)GrammaticalCase.Causal即抛异常。NotSupportedException所选区域文化、格式化器或时长单位没有经过验证的语法格支持时抛出。这是格系统本地化的关键约束——并非所有语言、所有单位、所有格组合都可用。三、调用链从HumanizeWithCase到词形表整个流程的关键路径如下以 TimeSpanHumanizeExtensions.cs 为入口HumanizeWithCase(grammaticalCase, ...) → 校验 grammaticalCase 范围 → Configurator.TimeSpanHumanizeStrategy 是否实现 IGrammaticalCaseTimeSpanHumanizeStrategy → 否throw NotSupportedException旧策略无法服务 → strategy.Humanize(timeSpan, precision, countEmptyUnits, culture, maxUnit, minUnit, collectionSeparator, toSymbols:false, grammaticalCase) → DefaultTimeSpanHumanizeStrategy显式实现→ TimeSpanHumanizeExtensions.DefaultHumanizeWithCase → DefaultHumanizeCore(..., grammaticalCase) → 每个时间单位BuildFormatTimePart → cultureFormatter 是否为 IGrammaticalCaseTimeSpanFormatter → 是caseFormatter.TimeSpanHumanize(timeUnit, amount, grammaticalCase) → 否throw NotSupportedException → DefaultFormatter实现该接口→ 查询 LocaleDurationCaseTableCatalog 词形表 → 输出词形关键源码证据1. 策略必须是格感知的TimeSpanHumanizeExtensions.cs#L116-L131if (Configurator.TimeSpanHumanizeStrategy is not IGrammaticalCaseTimeSpanHumanizeStrategy strategy) { throw new NotSupportedException( $The configured {nameof(ITimeSpanHumanizeStrategy)} does not support grammatical-case-aware durations.); } return strategy.Humanize(..., toSymbols: false, grammaticalCase);2. 格式化器同样必须实现IGrammaticalCaseTimeSpanFormatterTimeSpanHumanizeExtensions.cs#L912-L917: cultureFormatter is IGrammaticalCaseTimeSpanFormatter caseFormatter ? caseFormatter.TimeSpanHumanize(timeUnit, amount, grammaticalCase.Value) : throw new NotSupportedException( $The formatter for {culture?.Name ?? CultureInfo.CurrentCulture.Name} does not support grammatical-case-aware durations.);3. 符号模式与语法格互斥TimeSpanHumanizeExtensions.cs#L650-L653if (toSymbols grammaticalCase is not null) { throw new NotSupportedException(Grammatical case is not supported for time-unit symbols.); }4. 词形由本地化词形表驱动DefaultFormatter.cs#L131-L186DefaultFormatter通过IGrammaticalCaseTimeSpanFormatter的显式实现先校验格值与时间单位范围再解析LocaleDurationCaseTableCatalog.Resolve(Culture)依据文化的格系统分类Unsupported/NotApplicable/ 支持的具体格选择词形对SameAsNominative的单位回退到主格形式对NotApplicable/Unsupported的单位抛出NotSupportedException。这意味着格支持是按文化、按单位、按格逐项验证的而非全局可用。四、扩展方法入口HumanizeWithCase普通用户通常不直接调用策略接口而是使用 TimeSpanHumanizeExtensions.cs 中的两个重载// 重载一使用默认参数precision1, countEmptyUnitsfalse, maxUnitWeek, minUnitMillisecond, separator, public static string HumanizeWithCase( this TimeSpan timeSpan, GrammaticalCase grammaticalCase, int precision 1, CultureInfo? culture null, TimeUnit maxUnit TimeUnit.Week, TimeUnit minUnit TimeUnit.Millisecond, string? collectionSeparator , ); // 重载二显式指定 precision 与 countEmptyUnits public static string HumanizeWithCase( this TimeSpan timeSpan, GrammaticalCase grammaticalCase, int precision, bool countEmptyUnits, CultureInfo? culture null, TimeUnit maxUnit TimeUnit.Week, TimeUnit minUnit TimeUnit.Millisecond, string? collectionSeparator , );注意与普通Humanize的两点差异没有toWords参数格感知路径不提供数字转单词选项数量可能以数字显式给出或编码在单位词形中由区域文化的词形表决定没有toSymbols参数固定以文字形式输出且核心实现禁止符号与语法格组合。配置前提HumanizeWithCase依赖Configurator.TimeSpanHumanizeStrategy默认即DefaultTimeSpanHumanizeStrategy。如果你通过Configurator替换了自定义策略必须让该策略显式实现IGrammaticalCaseTimeSpanHumanizeStrategy否则会抛出NotSupportedException。DefaultTimeSpanHumanizeStrategy的显式实现还包含一道装配检查DefaultTimeSpanHumanizeStrategy.cs#L75-L79如果自定义策略类型与程序集不符却未显式实现该接口会明确报错提示。五、实战示例不同语言与格的输出德语与格作用于每个单位来自 TimeSpanHumanizeTests.cs#L624-L633 的测试GrammaticalCaseAppliesToEveryPart验证了格作用于每一个时间单位var actual new TimeSpan(8, 2, 0, 0).HumanizeWithCase( GrammaticalCase.Dative, precision: 3, culture: new CultureInfo(de-DE)); Assert.Equal(einer Woche, einem Tag, 2 Stunden, actual);注意普通Humanize输出的是 1 Woche, 1 Tag, 2 Stunden主格/引文形式而指定与格后Woche变为einer Woche、Tag变为einem Tag而Stunden复数保持原形——体现了屈折语中单数名词随格变化、复数与格同形的语言事实。匈牙利语工具格/转化格等来自 HungarianDurationCaseTests.cs 的测试展示了TimeSpan.FromDays(1)在maxUnitminUnitDay时的格变[InlineData(GrammaticalCase.Translative, 1 nappá)] public void DurationAppliesTheRequestedCase(GrammaticalCase grammaticalCase, string expected) Assert.Equal( expected, TimeSpan.FromDays(1).HumanizeWithCase( grammaticalCase, maxUnit: TimeUnit.Day, minUnit: TimeUnit.Day));巴斯克语绝对格是引文格来自 TimeSpanHumanizeTests.cs#L635-L647 的测试揭示了一个重要语义不同语言引文形式对应的格不同。var culture new CultureInfo(eu); var duration TimeSpan.FromDays(1); // 普通 Humanize 默认使用该语言的引文格绝对格 Absolutive Assert.Equal(1 egun, duration.Humanize(culture: culture)); // 显式请求绝对格得到另一种词序/词形 Assert.Equal(egun bat, duration.HumanizeWithCase(GrammaticalCase.Absolutive, culture: culture)); // 巴斯克语没有主格形式的时长短语 Assert.ThrowsNotSupportedException( () duration.HumanizeWithCase(GrammaticalCase.Nominative, culture: culture));这个例子说明NotSupportedException不是 bug而是语言格系统的客观边界——使用前应针对目标文化探测其支持的格集合。六、异常处理与边界情况1.ArgumentOutOfRangeException非法的格值TimeSpan.FromDays(1).HumanizeWithCase((GrammaticalCase)int.MaxValue); // → ArgumentOutOfRangeException: Unsupported grammatical case.ValidateGrammaticalCase与DefaultFormatter双重校验确保格值必须落在GrammaticalCase.Causal枚举最后一个值之内。2.NotSupportedException的四种来源场景触发点配置的策略未实现格感知接口Configurator.TimeSpanHumanizeStrategy不是IGrammaticalCaseTimeSpanHumanizeStrategy文化的格式化器未实现格感知接口cultureFormatter不是IGrammaticalCaseTimeSpanFormatter文化没有适用的格系统或该格不可用LocaleDurationCaseTableCatalog分类为Unsupported/NotApplicable或TryGetCase未命中见 DefaultFormatter.cs#L152-L172特定单位不适用该格单位词形覆盖标记为NotApplicable/Unsupported从测试 TimeSpanHumanizeTests.cs 与各语言目录如tests/Humanizer.Tests/Localisation/de/、hu/、fi/、ml/、eu相关用例可以推断格支持是逐语言逐单位验证的仓库中已覆盖德语、匈牙利语、芬兰语、马来语、巴斯克语等语言场景而英语等非屈折语言则走不适用NotApplicable路径。3. 与ToAge、符号模式的交互ToAge()40 years old内部调用的是普通Humanize不涉及语法格若尝试在带格路径中混用toSymbols核心实现直接抛出NotSupportedException——格词形与单位符号属于两种互斥的渲染模式。七、设计要点与使用建议接口是可选能力而非破坏性变更IGrammaticalCaseTimeSpanHumanizeStrategy通过继承ITimeSpanHumanizeStrategy保持向后兼容旧策略在既有 API 中照常工作只是不能服务HumanizeWithCase。格支持具有文化特异性先确认目标语言是否属于格语言、其时长短语的引文格是什么如巴斯克语是绝对格再决定使用哪个GrammaticalCase不确定时用 try/catch 捕获NotSupportedException并回退到普通Humanize。词形数据由本地化系统驱动格词形来自LocaleDurationCaseTableCatalog等本地化词形表由Humanizer.SourceGenerators生成与Locales/*.yml中的区域文化数据体系一致新增语言支持属于数据与代码生成范畴而非仅改接口。参考实现与测试想深入理解可在仓库中查看 DefaultTimeSpanHumanizeStrategy.cs、DefaultFormatter.cs 以及 TimeSpanHumanizeTests.cs 中HumanizeWithCase相关用例如GrammaticalCaseAppliesToEveryPart、BasqueUsesAbsolutiveAsItsCitationCase它们同时是格式化器与词形表的契约测试。小结IGrammaticalCaseTimeSpanHumanizeStrategy是 Humanizer 时长人文化体系的格感知扩展层它以继承方式保持旧策略兼容以显式Humanize(timeSpan, ..., grammaticalCase)重载为HumanizeWithCase提供词形选择能力并将真正的词形解析委托给实现了IGrammaticalCaseTimeSpanFormatter的格式化器与本地化词形表。理解这条调用链与异常契约你就能在德语、匈牙利语、芬兰语等格语言场景中让时长短语精确贴合句子的句法角色。赞分享开发工具【免费下载链接】HumanizerHumanizer meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities项目地址https://gitcode.com/gh_mirrors/hu/Humanizer点击查看免费下载相关推荐抖音批量下载助手一键构建你的专属视频素材库抖音批量下载助手一键构建你的专属视频素材库 还在为手动保存抖音视频而烦恼吗想要批量获取心仪创作者的精彩内容却无从下手抖音批量下载助手正是你需要的终极解决方开发工具new-component终极指南如何快速创建React组件的10个技巧new component终极指南如何快速创建React组件的10个技巧 new component 是一款简单实用的 CLI 工具专为 React 开发者Humanizer ByteRate 全解析在 .NET 中用 ByteSize 与 TimeSpan 计算和格式化传输速率Humanizer ByteRate 全解析在 .NET 中用 ByteSize 与 TimeSpan 计算和格式化传输速率 ByteRate 是 Human开发工具上一篇高效代码高亮全攻略从命令行到专业文档的实战秘籍下一篇vgpu_unlock故障排除终极指南10个常见问题及解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考