
开发工具【免费下载链接】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点击查看免费下载导读本文围绕 Humanizer 中负责将DateTime转换为序数词日期文本的IDateToOrdinalWordConverter接口展开系统讲解其两个Convert方法的重载语义、默认实现的本地化行为、基于 YAML 语言配置的注册机制以及自定义转换器的注册方式。读完本文你将掌握ToOrdinalWords扩展方法的底层调用链理解英文与非英文文化下序数日期的不同渲染策略并能根据业务需要接入自己的日期序数词转换实现。接口定位本地化ToOrdinalWords的转换契约IDateToOrdinalWordConverter是 Humanizer 中“把日期转成序数词文本”这一能力的抽象契约其 XML 文档注释明确指出The interface used to localise the ToOrdinalWords method用于本地化ToOrdinalWords方法的接口。也就是说所有文化Culture相关的序数日期文本生成逻辑都收敛到这一个接口之下由它统一承载。接口定义位于 src/Humanizer/Localisation/DateToOrdinalWords/IDateToOrdinalWordConverter.cs完整签名如下namespace Humanizer; /// summary /// Converts dates into the localized text used by cToOrdinalWords/c. /// /summary public interface IDateToOrdinalWordConverter { /// summary /// Converts the given paramref namedate/ to ordinal words for the current culture. /// /summary string Convert(DateTime date); /// summary /// Converts the given paramref namedate/ to ordinal words using the specified grammatical case. /// /summary string Convert(DateTime date, GrammaticalCase grammaticalCase); }与DateOnly.NET 6对应的IDateOnlyToOrdinalWordConverter接口同位于 src/Humanizer/Localisation/DateToOrdinalWords/IDateOnlyToOrdinalWordConverter.cs二者结构对称本文以IDateToOrdinalWordConverter为主线展开。Convert(DateTime)按当前文化输出序数日期string Convert(System.DateTime date);参数date类型为System.DateTime即待转换的日期值。返回值System.String即本地化的序数日期文本。该方法不接收任何文化参数实际文化由实现内部决定——默认实现读取的是CultureInfo.CurrentCulture详见下文“默认实现”一节因此输出的语言与格式随线程当前文化而变化。Convert(DateTime, GrammaticalCase)按指定语法格输出序数日期string Convert(System.DateTime date, Humanizer.GrammaticalCase grammaticalCase);参数dateSystem.DateTime待转换日期grammaticalCaseHumanizer.GrammaticalCase希望应用于输出文本的语法格如主格 Nominative、属格 Genitive 等。返回值System.String本地化序数日期文本。该重载主要为拥有格位系统的语言如俄语、波兰语、乌克兰语等服务同一日期在不同语法格下需要不同的词形。GrammaticalCase枚举定义于 src/Humanizer/GrammaticalCase.cs对于没有语法格概念的语言如英语此参数不会产生任何效果——默认实现会直接忽略它并委托给无参重载。入口ToOrdinalWords 扩展方法与配置中枢IDateToOrdinalWordConverter并不直接暴露给调用方日常使用是通过 src/Humanizer/DateToOrdinalWordsExtensions.cs 中的ToOrdinalWords扩展方法触发例如new DateTime(2023, 1, 1).ToOrdinalWords() // en-US 下 1st of January, 2023 new DateTime(2020, 12, 22).ToOrdinalWords() // en-US 下 22nd of December, 2020其实现非常简洁直接委托给全局配置中枢public static string ToOrdinalWords(this DateTime input) Configurator.DateToOrdinalWordsConverter.Convert(input); public static string ToOrdinalWords(this DateTime input, GrammaticalCase grammaticalCase) Configurator.DateToOrdinalWordsConverter.Convert(input, grammaticalCase);这里的关键是Configurator。在 src/Humanizer/Configuration/Configurator.cs 中可以看到日期序数词转换器与其他本地化组件一样被组织在一个LocaliserRegistry注册表里public static LocaliserRegistryIDateToOrdinalWordConverter DateToOrdinalWordsConverters { get; } new DateToOrdinalWordsConverterRegistry(); internal static IDateToOrdinalWordConverter DateToOrdinalWordsConverter DateToOrdinalWordsConverters.ResolveForCulture(null);ResolveForCulture(null)表示按当前线程文化解析null即CultureInfo.CurrentCulture因此ToOrdinalWords的输出始终跟随运行线程的文化设置。整个调用链可概括为DateTime.ToOrdinalWords() - Configurator.DateToOrdinalWordsConverter按当前文化解析 - DateToOrdinalWordsConverterRegistry注册表 - IDateToOrdinalWordConverter.Convert(date[, grammaticalCase])注册表与默认实现注册表结构src/Humanizer/Configuration/DateToOrdinalWordsConverterRegistry.cs 定义了该接口的注册表class DateToOrdinalWordsConverterRegistry : LocaliserRegistryIDateToOrdinalWordConverter { public DateToOrdinalWordsConverterRegistry() : base(_ new DefaultDateToOrdinalWordConverter()) DateToOrdinalWordsConverterRegistryRegistrations.Register(this); }它继承自泛型基类LocaliserRegistryTLocaliser见 src/Humanizer/Configuration/LocaliserRegistry.cs并以DefaultDateToOrdinalWordConverter作为兜底默认实现——任何未显式注册的文化都会回落到它。而DateToOrdinalWordsConverterRegistryRegistrations.Register是 Humanizer 源生成器Source Generator根据语言 YAML 配置自动生成的一部分它把各文化的专用转换器按 locale 代码注册进注册表实现了“配置驱动”的本地化扩展。LocaliserRegistryTLocaliser提供了几个关键能力Register(string localeCode, TLocaliser localiser)注册指定 locale 的转换器实例Register(string localeCode, FuncCultureInfo, TLocaliser localiser)注册按文化工厂创建的转换器ResolveForCulture(CultureInfo? culture)解析指定文化对应的转换器null表示当前线程文化解析时先按精确文化名匹配再沿culture.Parent链向上回退最终落到默认实现。默认实现DefaultDateToOrdinalWordConvertersrc/Humanizer/Localisation/DateToOrdinalWords/DefaultDateToOrdinalWordConverter.cs 是默认转换器其行为可概括为两条规则class DefaultDateToOrdinalWordConverter : IDateToOrdinalWordConverter { const char LeftToRightMark (char)0x200E; const char RightToLeftMark (char)0x200F; const char ArabicLetterMark (char)0x061C; public virtual string Convert(DateTime date) { var culture CultureInfo.CurrentCulture; if (culture.TwoLetterISOLanguageName ! en) { // 非英语文化直接采用该文化自身的短日期模式d // 并剥离日历格式化时嵌入的方向性控制字符LRM/RLM/ALM // 使结果嵌入更大的序数短语时保持可读。 return SanitizeNonEnglishDate(date.ToString(d, culture)); } return date.Day.Ordinalize() date.ToString( MMMM yyyy); } public virtual string Convert(DateTime date, GrammaticalCase grammaticalCase) Convert(date); static string SanitizeNonEnglishDate(string value) value.Replace(LeftToRightMark.ToString(), string.Empty) .Replace(RightToLeftMark.ToString(), string.Empty) .Replace(ArabicLetterMark.ToString(), string.Empty); }要点拆解英语文化en输出形式为「序数日 空格 月份全名 空格 年份」例如22nd December 2020实际链接到ToOrdinalWords扩展方法后还带有 “of” 介词见下文示例。日部分由date.Day.Ordinalize()生成即复用 Humanizer 的序数化能力。非英语文化不做“翻译式”处理而是直接采用该文化自身的短日期格式字符串d例如ru-RU的dd.MM.yyyy随后做一次“清洗”——移除格式化输出中可能嵌入的 Unicode 方向性控制字符U200ELRM左至右标记、U200FRLM右至左标记与U061CALM阿拉伯字母标记。这是因为部分日历尤其阿拉伯、希伯来等 RTL 日历在短日期输出中会内嵌这些控制符剥离后文本在嵌入更大句子的场景下不会干扰阅读顺序。语法格重载默认实现中Convert(date, grammaticalCase)直接忽略语法格参数并调用无参版本注释明确说明这是因为回退转换器不随语法格变化词形——语法格支持由各语言的专用转换器提供。模式化转换器PatternDateToOrdinalWordsConverter除了默认实现还有基于预构建模式pattern的专用转换器 src/Humanizer/Localisation/DateToOrdinalWords/PatternDateToOrdinalWordsConverter.csclass PatternDateToOrdinalWordsConverter(OrdinalDatePattern pattern) : DefaultDateToOrdinalWordConverter { readonly OrdinalDatePattern pattern pattern; public override string Convert(DateTime date) pattern.Format(date); }它继承默认实现并重写Convert(DateTime)将格式化工作委托给 src/Humanizer/Localisation/DateToOrdinalWords/OrdinalDatePattern.cs 中定义的OrdinalDatePattern。这是源生成器按语言配置产出各文化转换器的核心载体详见下一节。语言配置驱动YAML 中的 ordinal.date 与源码生成Humanizer 的本地化数据以 YAML 形式存放于 src/Humanizer/Locales 目录如en.yml、ru.yml、zh-CN.yml等由Humanizer.SourceGenerators在编译期读取并生成注册代码DateToOrdinalWordsConverterRegistryRegistrations即由此产出。以 src/Humanizer/Locales/en.yml 为例英语的序数日期配置为ordinal: date: engine: pattern pattern: {day} MMMM yyyy dayMode: Ordinal dateOnly: engine: pattern pattern: {day} MMMM yyyy dayMode: Ordinal而以 src/Humanizer/Locales/ru.yml 为例俄语的配置则把日期渲染为纯数字模式ordinal: date: engine: pattern pattern: {day} MMMM yyyy dayMode: Numeric dateOnly: engine: pattern pattern: {day} MMMM yyyy dayMode: Numeric可以看到配置中有三个关键字段字段取值示例含义enginepattern指定转换器的生成引擎类型目前日期序数词走pattern模式即生成PatternDateToOrdinalWordsConverterpattern{day} MMMM yyyy日期格式模板其中{day}是日的占位符其余部分遵循 .NET 自定义日期格式说明符dayModeOrdinal/Numeric等日部分的渲染模式dayMode的完整取值定义在 src/Humanizer/Localisation/DateToOrdinalWords/OrdinalDatePattern.cs 的OrdinalDateDayMode枚举中enum OrdinalDateDayMode { /// summaryRenders the day as a culture-aware numeric value./summary Numeric, /// summaryRenders the day as an ordinal word./summary Ordinal, /// summaryRenders the day as a numeric value except for the first day of the month./summary OrdinalWhenDayIsOne, /// summaryRenders the first day of the month using the masculine ordinal form./summary MasculineOrdinalWhenDayIsOne, /// summaryRenders the day as a numeric value followed by a dot suffix./summary DotSuffix }各模式的渲染逻辑对应OrdinalDatePattern.FormatDay(int day)的 switch 分支Numeric输出本地化数字Ordinal调用day.Ordinalize()OrdinalWhenDayIsOne仅在日为 1 时输出序数词MasculineOrdinalWhenDayIsOne则在日为 1 时输出阳性序数形式day.Ordinalize(GrammaticalGender.Masculine)DotSuffix输出数字加英文句点如德语风格的1.。此外OrdinalDatePattern还承担了若干精细工作日历兼容OrdinalDateCalendarMode.Gregorian模式下会把文化日历强制切换为本地化公历GregorianCalendar保证年份输出一致Native模式则保留文化原生日历如泰历。属格月份对斯拉夫语系等存在属格genitive月份词形的语言当模式中“日与月相邻”如{day} MMMM时会替换为monthsGenitive数组中的属格月名参见SubstituteMonth与IsDayAdjacentToMonth的实现。Hijri 日历月份支持hijriMonths覆盖数组用于HijriCalendar/UmAlQuraCalendar下的月名替换ResolveMonthArray。方向性控制符剥离与默认实现一样最终输出会去除\u200E、\u200F、\u061C等控制字符StripDirectionalityControls。从源生成器一侧看src/Humanizer.SourceGenerators/Generators/ProfileCatalogs/OrdinalDateProfileCatalogInput.cs 负责读取上述 YAML 配置并生成对应的注册表达式engine为pattern时产出new PatternDateToOrdinalWordsConverter(new OrdinalDatePattern(...))形式的注册代码CreatePatternExpression并把pattern、dayMode、calendarMode与月份数组等参数逐一映射进OrdinalDatePattern构造器。自定义转换器注册与替换IDateToOrdinalWordConverter作为一个公开接口允许使用者注入自己的实现。标准做法是通过Configurator.DateToOrdinalWordsConverters注册表注册using Humanizer; public sealed class MyDateToOrdinalWordConverter : IDateToOrdinalWordConverter { public string Convert(DateTime date) $Day {date.Day} of month {date.ToString(MMMM, System.Globalization.CultureInfo.CurrentCulture)} in {date.Year}; public string Convert(DateTime date, GrammaticalCase grammaticalCase) Convert(date); } // 应用启动阶段如 Main 方法或 ModuleInitializer注册 Configurator.DateToOrdinalWordsConverters.Register(en-US, new MyDateToOrdinalWordConverter()); // 或使用工厂形式 Configurator.DateToOrdinalWordsConverters.Register(fr-FR, _ new MyDateToOrdinalWordConverter());注册后在对应文化下调用new DateTime(2023, 5, 17).ToOrdinalWords()就会走自定义实现。需要注意两点注册时机LocaliserRegistry.Register在注册表首次被解析即首次调用ToOrdinalWords之后会抛InvalidOperationException“Cannot register localisers after the registry has been used.”因为注册表在首次使用时会将字典“冻结”为FrozenDictionary以提升读取性能。因此自定义注册必须放在应用启动阶段、任何ToOrdinalWords调用之前。回退链未注册的文化会沿culture.Parent链逐级回退如en-US未注册可回退到en最终落到DefaultDateToOrdinalWordConverter。若需要全局替换所有文化的行为可参考LocaliserRegistry的默认实现构造函数把默认转换器替换为自定义类型。行为验证与测试参考仓库测试集Humanizer.Tests中与本主题相关的测试如 tests/Humanizer.Tests/DateToOrdinalWordsExtensions.cs 及本地化目录下的日期序数测试验证了以下行为英语文化下DateTime输出包含序数词st/nd/rd/th的日期短语非英语文化如ru、de、it等输出遵循其文化短日期格式GrammaticalCase重载在支持格位系统的语言上产生不同词形在英语上无差异剥离方向性控制字符后RTL 日历输出不携带干扰阅读的嵌入标记。如需扩充测试或本地化数据可对照 src/Humanizer/Locales 下的 YAML 配置与 src/Humanizer.SourceGenerators 的生成逻辑完整的 API 文档快照见 website/versioned_docs/version-3.0.1/api/Humanizer.IDateToOrdinalWordConverter.md。小结IDateToOrdinalWordConverter是 Humanizer 日期序数词本地化的核心抽象Convert(DateTime)负责按当前文化生成序数日期文本Convert(DateTime, GrammaticalCase)在支持格位系统的语言上提供语法格变体。其背后是由Configurator注册表、YAML 语言配置、源生成器与OrdinalDatePattern模式引擎构成的完整流水线——英语走“序数词 月份 年份”其余文化走“文化短日期 方向性控制符清洗”。理解这一接口与它的默认实现、注册机制既能帮助你正确使用ToOrdinalWords也为定制多语言日期呈现提供了明确的扩展点。赞分享开发工具【免费下载链接】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点击查看免费下载相关推荐Humanizer 本地化序数日期转换接口 IDateToOrdinalWordConverter 深入解析Humanizer 本地化序数日期转换接口 IDateToOrdinalWordConverter 深入解析 IDateToOrdinalWordConvert开发工具Humanizer 日期转序数词本地化接口深度解析IDateToOrdinalWordConverter 与 IDateOnlyToOrdinalWordConverterHumanizer 日期转序数词本地化接口深度解析IDateToOrdinalWordConverter 与 IDateOnlyToOrdinalWordCo开发工具Humanizer 的 IDateToOrdinalWordConverter日期转序数词文本的本地化转换接口解析Humanizer 的 IDateToOrdinalWordConverter日期转序数词文本的本地化转换接口解析 IDateToOrdinalWordCon开发工具上一篇CesiumJS能源地图发电设施与能源消费可视化完整指南下一篇从零开始编写你的第一个vis编辑器Lua插件完整开发指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考