- 开发工具
【免费下载链接】Humanizer
Humanizer meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities
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 }三个成员的语义与底层数值如下:
| 成员 | 数值 | 语义 | 典型语言场景 |
|---|---|---|---|
Masculine | 0 | 阳性 | 俄语、希伯来语、西班牙语的阳性名词;作为多数性别感知转换器的默认性别 |
Feminine | 1 | 阴性 | 俄语одна、希伯来语אחת、西班牙语una/primera等阴性词形 |
Neuter | 2 | 中性 | 德语、俄语等拥有中性词形的语言;无中性词形的语言会自动退化为默认词形 |
注意,枚举数值是隐式赋值的(0、1、2),并非由源码显式声明——这是 C# 枚举的默认行为。测试中甚至通过(GrammaticalGender)999验证非法值会抛出ArgumentOutOfRangeException(见 CoverageGapTests.cs),说明底层实现是按数值做校验的,调用方不应依赖超出三个成员的取值。
三、性别参数如何流入转换器:调用链解析
GrammaticalGender本身只是一个"选项容器",真正的工作由各语言的INumberToWordsConverter实现完成。调用链如下:
- 扩展方法层:NumberToWordsExtension.cs 提供
ToWords(this int/long number, GrammaticalGender gender, CultureInfo? culture = null)等重载,内部调用Configurator.GetNumberToWordsConverter(culture).Convert(number, gender); - 接口层:INumberToWordsConverter.cs 声明
Convert(long number, GrammaticalGender gender, bool addAnd = true)与ConvertToOrdinal(int number, GrammaticalGender gender)等性别感知方法,文档注释明确"当语言区分性别词形时使用指定的语法性别"; - 基类层: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,证明性别参数在英语中完全不起作用。
七、最佳实践与注意事项
- 只对性别感知语言显式传性别:对
ru、he、es、pt-BR、pl、cs、sr等语言,务必根据实际名词性别传入Masculine/Feminine(必要时Neuter),否则会落到默认性别(多为阳性),产生语法错误的文案;对en、zh等语言可以不传,或统一传值以保持代码路径一致。 - 结合 WordForm 使用:西班牙语等语言中,性别与词形(正常形/缩写形)共同决定输出(如
tercerovstercer),两者需要同时指定,相关重载可见 NumberToWordsExtension.cs。 - 不要依赖底层数值:枚举的 0/1/2 数值是 C# 默认赋值,属于实现细节;测试用
(GrammaticalGender)999验证了未定义值会触发ArgumentOutOfRangeException,业务代码应始终使用具名成员。 - culture 参数可选:所有性别感知重载都支持
CultureInfo? culture = null,默认使用当前线程文化;跨语言输出时建议显式传入,避免受运行环境文化影响。 - 语义边界:
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
相关推荐
Humanizer 语法性别(GrammaticalGender)枚举深度解析:让多语言数字与序数输出更地道
Humanizer 语法性别(GrammaticalGender)枚举深度解析:让多语言数字与序数输出更地道 本篇技术指南围绕 Humanizer 的 Gram
开发工具Humanizer数字转文字:面向开发者的终极多语言解决方案
Humanizer数字转文字:面向开发者的终极多语言解决方案 在当今全球化的软件开发环境中,处理多语言数字和文字转换已成为每个开发者的必备技能。 Humaniz
开发工具Humanizer 中 GrammaticalGender 枚举详解:跨文化控制数字词性与序数词性形的机制
Humanizer 中 GrammaticalGender 枚举详解:跨文化控制数字词性与序数词性形的机制 本篇围绕 Humanizer 仓库文档 Humani
开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考