复数形式






4.69/5 (11投票s)
用任何语言正确拼写“找到 5 个文件”之类的消息。
引言
像 "%d 个文件找到" 这样的消息很难进行本地化。在英语中,只有两种形式:1 个文件(单数)和 2 个或更多文件(复数),但其他语言最多使用 4 种复数形式。例如,波兰语有 3 种形式
0 plików
1 plik
2-4 pliki
5-21 plików
22-24 pliki
25-31 plików
etc.
其他语言(法语、俄语、捷克语等)也使用与英语和彼此不同的规则。
gettext
库从本地化文件中提取 复数形式选择规则。该规则是一个 C 语言表达式,它为每个消息进行评估。这是一个通用的解决方案,但恕我直言,对于这项任务来说,表达式评估器有些过头了。
我的解决方案
我开发了一个更简单的解决方案,适用于 gettext
页面上提到的所有语言。它基于以下观察
- 所有额外的复数形式都用于某个数字范围,例如斯洛伐克语和捷克语中的 2 到 4。
- 这种模式通常会**为每 10 或 100 个项目重复**。在俄语中,它听起来像是“二十一个文件”,而不是“二十一个文件”,因为名词与最后一个数字“一”一致。相同的模式重复出现在 30、40 等数字中。
- 从 10 到 19 的数字(我简称为**“十几”**)通常是规则的例外。就像英语中 16 的拼写与 26、36、46 等不同一样:“sixteen”与“twenty-six”、“thirty-six”和“forty-six”不同。
- 在某些语言中,**零**的处理方式不同,例如罗马尼亚语。
因此,每个复数形式的规则将由这些组件组成
range_start range_end modulo_for_repetition skip_teens_flag
以下是一些示例
English
singular - range_start = 1, range_end = 1
plural - all other numbers
Polish
singular - range_start = 1, range_end = 1
plural1 - range_start = 2, range_end = 4, modulo = 10, skip_teens = true
plural2 - all other numbers
Irish
singular - range_start = 1, range_end = 1
plural1 - range_start = 2, range_end = 2
plural2 - all other numbers
Lithuanian
singular - range_start = 1, range_end = 1, modulo = 10, skip_teens = true
plural1 - range_start = 2, range_end = 9, modulo = 10, skip_teens = true
plural2 - all other numbers ("teens")
每种语言的规则可以写入一个简短的 string
,并存储在语言文件中(例如,对于立陶宛语,string
是 "1 1 10 t; 2 9 10 t
")。
Using the Code
要使用我的解决方案,请在您的项目中包含 plurals.h 和 plurals.c。**接口**由两个函数组成。首先,您调用 PluralsReadCfg
从 string
读取规则。接下来,您将一个数字传递给 PluralsGetForm
。它返回该数字的正确复数形式的索引,您可以使用该索引从语言文件中读取 string
PLURAL_INFO plurals;
PluralsReadCfg(&plurals, ReadFromLngFile("PluralRules"));
char lng_str_name[16], message[128];
sprintf(lng_str_name, "FilesFound%d", PluralsGetForm(&plurals, number));
sprintf(message, ReadFromLngFile(lng_str_name), number);
在语言文件中,您为每种复数形式都有 string
PluralRules = "1"
FilesFound0 = "%d file found"
FilesFound1 = "%d files found"
ReadFromLngFile
是您自己的函数。您可以将两个 sprintf
包装在一个更高级别的函数中(当然,使用安全的函数代替 sprintf
以保护您的程序免受缓冲区溢出)。
结论
使用 MSVC++ 编译时,两个函数 PluralsReadCfg
和 PluralsGetForm
在您的可执行文件中占用 500 字节。为了以任何语言正确地拼写您的消息,这很值得。
历史
- 2008 年 4 月 15 日:初始发布