news 2026/9/26 8:48:24

Humanizer 中的 GrammaticalGender:面向语法性别的多语言数字与序数本地化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Humanizer 中的 GrammaticalGender:面向语法性别的多语言数字与序数本地化
  • 开发工具

【免费下载链接】Humanizer

Humanizer meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities

项目地址:https://gitcode.com/gh_mirrors/hu/Humanizer
点击查看免费下载

GrammaticalGender 是 Humanizer 库中用于指定输出词语法性别的核心枚举,它让同一数字在不同语言(如俄语、西班牙语、德语、波兰语等)中能够生成符合名词性别的正确词形。本文围绕 GrammaticalGender.cs 的源码定义,结合 NumberToWordsExtension.cs、OrdinalizeExtensions.cs 等扩展方法及多语言测试用例,讲解枚举的三个成员、它在数字转词与序数化 API 中的传递链路,以及它在性别无关语言中的静默退化行为,帮助你写出真正"本地化"的 .NET 文案代码。

一、为什么需要"语法性别"枚举:从语言差异说起

英语几乎不需要语法性别:one、first无论修饰什么名词都是同一个词。但许多语言并非如此:

  • 俄语中1的阳性是один,阴性是одна(见 NumberToWordsExtension.cs 中的文档示例);
  • 希伯来语中1的阳性是אחד,阴性是אחת(同上);
  • 西班牙语中1的序数阳性为primero、阴性为primera,缩写阳性为primer(见 CoverageGapTests.cs 的测试断言);
  • 巴西葡萄牙语中1º(阳性)与1ª(阴性)是两种不同的序数写法(见 OrdinalizeExtensions.cs)。

当文案需要描述"一个人"(阳性)或"一本书"(阴性)时,单纯传入数字无法让库知道该用哪个词形。GrammaticalGender就是为此提供的显式选项,由调用方根据实际名词的性别传入。

二、枚举定义与三个成员

GrammaticalGender.cs 的完整定义如下:

namespace Humanizer; /// <summary> /// Options for specifying the desired grammatical gender for the output words /// </summary> public enum GrammaticalGender { /// <summary> /// Indicates masculine grammatical gender /// </summary> Masculine, /// <summary> /// Indicates feminine grammatical gender /// </summary> Feminine, /// <summary> /// Indicates neuter grammatical gender /// </summary> Neuter }

三个成员的语义与底层数值如下:

成员数值语义典型语言场景
Masculine0阳性俄语、希伯来语、西班牙语的阳性名词;作为多数性别感知转换器的默认性别
Feminine1阴性俄语одна、希伯来语אחת、西班牙语una/primera等阴性词形
Neuter2中性德语、俄语等拥有中性词形的语言;无中性词形的语言会自动退化为默认词形

注意,枚举数值是隐式赋值的(0、1、2),并非由源码显式声明——这是 C# 枚举的默认行为。测试中甚至通过(GrammaticalGender)999验证非法值会抛出ArgumentOutOfRangeException(见 CoverageGapTests.cs),说明底层实现是按数值做校验的,调用方不应依赖超出三个成员的取值。

三、性别参数如何流入转换器:调用链解析

GrammaticalGender本身只是一个"选项容器",真正的工作由各语言的INumberToWordsConverter实现完成。调用链如下:

  1. 扩展方法层:NumberToWordsExtension.cs 提供ToWords(this int/long number, GrammaticalGender gender, CultureInfo? culture = null)等重载,内部调用Configurator.GetNumberToWordsConverter(culture).Convert(number, gender);
  2. 接口层:INumberToWordsConverter.cs 声明Convert(long number, GrammaticalGender gender, bool addAnd = true)与ConvertToOrdinal(int number, GrammaticalGender gender)等性别感知方法,文档注释明确"当语言区分性别词形时使用指定的语法性别";
  3. 基类层:GenderedNumberToWordsConverter.cs 是性别感知语言的抽象基类,构造函数接受默认性别(默认GrammaticalGender.Masculine)。它把所有不传性别的重载都路由到"默认性别":
    • Convert(long number)等价于Convert(number, defaultGender);
    • ConvertToOrdinal(int number)等价于ConvertToOrdinal(number, defaultGender);
    • 派生类型只需覆写真正随性别变化的成员。

从源码结构看,Humanizer 采用的是"默认性别路由 + 子类覆写"策略:调用方不指定性别时,库使用该语言配置的默认性别(多为阳性),从而保证所有 API 重载对调用方而言是一致、可预测的。

四、实际用法:数字转词(ToWords)中的性别选择

最典型的用法是基数词。以俄语和西班牙语为例(示例来自 NumberToWordsExtension.cs 的文档注释):

// 俄语:阳性与阴性词形不同 1.ToWords(GrammaticalGender.Masculine, new CultureInfo("ru")) // -> "один" 1.ToWords(GrammaticalGender.Feminine, new CultureInfo("ru")) // -> "одна" // 希伯来语 1.ToWords(GrammaticalGender.Masculine, new CultureInfo("he")) // -> "אחד" 1.ToWords(GrammaticalGender.Feminine, new CultureInfo("he")) // -> "אחת" // 西班牙语(结合 WordForm 使用) 21.ToWords(WordForm.Normal, GrammaticalGender.Masculine, new CultureInfo("es")) // -> "veintiuno" 21.ToWords(WordForm.Abbreviation, GrammaticalGender.Masculine, new CultureInfo("es")) // -> "veintiún" 21.ToWords(WordForm.Normal, GrammaticalGender.Feminine, new CultureInfo("es")) // -> "veintiuna"

测试侧同样印证了这些行为:NumberWordOverloadTests.cs 对多个 locale 逐一断言number.ToWords(GrammaticalGender.Feminine, culture)的输出;CoverageGapTests.cs 断言西班牙语1.ToWords(WordForm.Abbreviation, GrammaticalGender.Masculine)为un、1.ToWords(GrammaticalGender.Feminine)为una。

五、实际用法:序数词(ToOrdinalWords / Ordinalize)中的性别选择

序数词是性别区分最明显的一类输出。Humanizer 在两条 API 路径上都支持性别参数:

5.1 数字转序数词:ToOrdinalWords

// 巴西葡萄牙语(见 NumberToWordsExtension.cs 文档注释) 1.ToOrdinalWords(GrammaticalGender.Masculine, new CultureInfo("pt-BR")) // -> "primeiro" 1.ToOrdinalWords(GrammaticalGender.Feminine, new CultureInfo("pt-BR")) // -> "primeira" // 西班牙语:结合 WordForm 区分完整形与缩写形 3.ToOrdinalWords(GrammaticalGender.Masculine, WordForm.Normal, new CultureInfo("es")) // -> "tercero" 3.ToOrdinalWords(GrammaticalGender.Masculine, WordForm.Abbreviation, new CultureInfo("es")) // -> "tercer" 3.ToOrdinalWords(GrammaticalGender.Feminine, WordForm.Normal, new CultureInfo("es")) // -> "tercera"

CoverageGapTests.cs 用理论数据验证了西班牙语序数的性别行为:1.ToOrdinalWords(Masculine, Abbreviation, es)为primer,而1.ToOrdinalWords(Feminine, es)为primera。

5.2 字符串序数化:Ordinalize

对int、long或数字字符串,可以使用Ordinalize重载。以巴西葡萄牙语和西班牙语为例(见 OrdinalizeExtensions.cs 的文档注释):

"1".Ordinalize(GrammaticalGender.Masculine) // -> "1º" "1".Ordinalize(GrammaticalGender.Feminine) // -> "1ª" // 西班牙语(正常形/缩写形 × 性别) "1".Ordinalize(GrammaticalGender.Masculine, WordForm.Abbreviation) // -> "1.er"(如 "Vivo en el 1.er piso") "1".Ordinalize(GrammaticalGender.Masculine, WordForm.Normal) // -> "1.º" "1".Ordinalize(GrammaticalGender.Feminine, WordForm.Normal) // -> "1.ª"

另外,从 OrdinalizeExtensions.cs 和 OrdinalizeTests.cs 可以看到,对于超出int范围的long数字,库会回退到"数字转词 + 语言后缀"的策略,此时同样需要传入性别:例如印地语2_147_483_648L.Ordinalize(GrammaticalGender.Masculine, hi-IN)等于number.ToWords(GrammaticalGender.Masculine, hi-IN) + "वाँ"。

六、性别无关语言的静默退化

并非所有语言都区分语法性别。对于英语、中文等性别无关语言,传入GrammaticalGender不会报错,而是被静默忽略、始终输出同一个词形。这类语言对应的转换器通常继承自 GenderlessNumberToWordsConverter.cs,其性别感知重载与无性别重载产出相同结果。

测试用例明确覆盖了这种退化行为:

  • GermanGenderedOrdinalTests.cs:德语序数1.、2.、23.在三种性别下输出完全一致,并用Ordinalize_GenderInvariant_AllGendersMatch断言三种性别与阳性结果相同;
  • PolishGenderedOrdinalTests.cs:波兰语序数同样是1.风格,性别不影响结果。

值得注意的是德语本身拥有中性名词,其序数后缀统一为1.是语言惯例使然——"有中性词形"与"序数随性别变化"是两回事,具体行为取决于各语言转换器的实现。同理,OrdinalizeTests.cs 显示en-US下2147483651L.Ordinalize(GrammaticalGender.Masculine)与不带性别参数的调用输出均为2147483651st,证明性别参数在英语中完全不起作用。

七、最佳实践与注意事项

  1. 只对性别感知语言显式传性别:对ru、he、es、pt-BR、pl、cs、sr等语言,务必根据实际名词性别传入Masculine/Feminine(必要时Neuter),否则会落到默认性别(多为阳性),产生语法错误的文案;对en、zh等语言可以不传,或统一传值以保持代码路径一致。
  2. 结合 WordForm 使用:西班牙语等语言中,性别与词形(正常形/缩写形)共同决定输出(如tercerovstercer),两者需要同时指定,相关重载可见 NumberToWordsExtension.cs。
  3. 不要依赖底层数值:枚举的 0/1/2 数值是 C# 默认赋值,属于实现细节;测试用(GrammaticalGender)999验证了未定义值会触发ArgumentOutOfRangeException,业务代码应始终使用具名成员。
  4. culture 参数可选:所有性别感知重载都支持CultureInfo? culture = null,默认使用当前线程文化;跨语言输出时建议显式传入,避免受运行环境文化影响。
  5. 语义边界:GrammaticalGender只负责输出词形(词法/形态层),与"性别中性文案"无关——Humanizer 不会做性别中立改写,它只是在既有语言规则内生成正确性别形式。

八、小结

GrammaticalGender是 Humanizer 多语言本地化能力中"词形正确性"的关键开关:通过 GrammaticalGender.cs 定义的三个成员,配合 INumberToWordsConverter.cs 的性别感知接口、GenderedNumberToWordsConverter.cs 的默认性别路由,以及 NumberToWordsExtension.cs 和 OrdinalizeExtensions.cs 提供的一组重载,开发者可以在俄语、希伯来语、西班牙语、巴西葡萄牙语等语言中生成与名词性别严格一致的数字和序数文案,而在英语等性别无关语言中无需任何额外处理。写多语言文案时,请根据实际名词性别显式传入该枚举,即可获得语法正确的本地化输出。

  • 开发工具

【免费下载链接】Humanizer

Humanizer meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities

项目地址:https://gitcode.com/gh_mirrors/hu/Humanizer
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/26 8:48:17

高集成电机驱动EMC整改:洗碗机水泵传导与辐射双超标的处理

做过电机驱动产品的人都知道&#xff0c;洗碗机水泵这种小功率无刷直流电机&#xff0c;本身功率不大、功能也不复杂&#xff0c;但EMC整改往往比大功率产品更让人头疼。空间狭小、结构固定、电源走线受限&#xff0c;一旦传导或辐射超标&#xff0c;能塞进去的滤波器件和能挪动…

作者头像 李华
网站建设 2026/9/26 8:46:56

基于YOLO的焊缝缺陷检测系统设计与工程实践全攻略

简介&#xff1a;基于YOLO的焊缝缺陷检测系统设计资源&#xff0c;面向深度学习课程设计、毕业设计及期末大作业等场景&#xff0c;提供一套可运行的完整工程方案。包内共26个文件&#xff0c;以C源码为主&#xff0c;含9个cpp与6个头文件&#xff0c;覆盖YOLO模型推理、点云生…

作者头像 李华
网站建设 2026/9/26 8:45:57

基于Neo4j的水浒人物关系问答系统实战

简介&#xff1a;这份资源围绕《水浒传》人物关系展开&#xff0c;基于Neo4j图数据库构建可视化与问答系统&#xff0c;面向计算机相关专业学生及企业员工&#xff0c;可用于课程设计、大作业、毕设或初期项目立项演示&#xff0c;也适合作为图数据库与知识图谱方向的实战练习素…

作者头像 李华
网站建设 2026/9/26 8:45:01

从水凝胶柔性传感器写到毕业论文:AI 写作工具到底怎么选?

如果你在工学 / 纺织科学与工程 / 柔性功能电子器件与系统专业学习&#xff0c;大概率会遇到这样一项任务&#xff1a;围绕一类柔性应变传感器完成研究或毕业论文。比如做一个导电水凝胶柔性应变传感器&#xff0c;要设计材料配方、制备试样、测试拉伸过程中的电阻变化&#xf…

作者头像 李华
网站建设 2026/9/26 8:44:43

分层强化学习实现四足机器人自适应步态控制

简介&#xff1a;本资源是一个面向机器人控制与强化学习研究者的四足机器人步态学习实战项目&#xff0c;聚焦于利用分层强化学习&#xff08;HRL&#xff09;实现多种动态步态&#xff08;如trot、pace、bound、爬楼梯等&#xff09;的自主习得&#xff0c;解决传统端到端强化…

作者头像 李华