在许多语言中,语法形式取决于所描述的元素数量。在英语中,它是单数和复数形式(复数通常但并非总是通过添加后缀“s”来生成,但例如参见 mouse/mice),在其他语言中,它可能更复杂,按照 gettext 手册中所述。
我想要的是一个根据数字选择语法形式的宏,例如\nn{\nmice}{mouse}{mice}
对于英语,它将输出1 只小鼠但2 只老鼠。
对于波兰语,我还必须使用一些涉及条件和模数的整数计算包
Plural-Forms: nplurals=3; \
plural=n==1 ? 0 : \
n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;
以及例如\nn{\nmice}{mysz}{mysze}{myszy}
。
上述公式(取自上述gettext 文档)意味着在波兰语中你有一 米斯(单数,第 0 种形式),2, 3, 4, 22, 23, 24 五月(保留旧双数形式、第一种复数形式),但5, 6, 7, 11, 12, 13, 14, 25 梅西(复数形式,第二种复数形式)。注意:斯洛文尼亚语有 4 种复数形式。
答案1
LuaTeX 非常适合此类宏。例如,这是 ConTeXt 中的实现(可以轻松转换为 LaTeX):
\startluacode
-- Function to choose amoung n alternatives
function commands.ngettext(n, f, t)
-- The function f should return an integer 1, 2, etc.
-- The table t contains the corresponding list of plurals
context("%d %s", n, t[f(n)])
end
\stopluacode
\define[1]\Mice
{\ctxcommand{
ngettext(#1,
function(n) if n == 1 then return 1 else return 2 end; end,
{"mouse", "mice"})}}
\define[1]\Mysz
{\ctxcommand{
ngettext(#1,
function(n)
if n == 1 then
return 1
elseif n \letterpercent 10 >= 2 and n \letterpercent 10<=4 and (n \letterpercent 100<10 or n \letterpercent 100 >= 20) then
return 2
else
return 3
end
end,
{"mysz", "mysze", "myszy"})}}
\starttext
Mouse: \Mice{1} \Mice{11} \Mice{22}
Mysz: \Mysz{1} \Mysz{11} \Mysz{22}
\stoptext
这使
答案2
从您所指出的方法来看ngettext
,似乎复数方案的数量有限,因此应该独立于给定单词的复数列表来定义这些方案。
以下是复数方案的一些示例。为了提高性能,复数方案是expl3
直接使用命令定义的,而不是解析您建议的语法。可以\plural_new_scheme:nn
用
\cs_new_protected:Npn \plural_new_scheme:nn #1#2 % <scheme> <code>
{ \cs_new:cpn { __plural_scheme_#1:n } ##1 { \fp_to_int:n { #2 + 1 } } }
然后简单地将复数方案定义中的所有n
内容替换为#1
(例如#1==1?0:1
或#1>1
,使用您在 C 中习惯使用的运算符)。
\documentclass{article}
\usepackage{expl3,xparse}
%%%%%%%%%%%%% Definitions first
\ExplSyntaxOn
% Defining and using a plural scheme
\cs_new_protected:Npn \plural_new_scheme:nn #1#2 % <scheme> <code>
{ \cs_new:cpn { __plural_scheme_#1:n } ##1 {#2} }
\cs_new:Npn \plural_scheme:nn #1#2 % <scheme> <value>
{ \use:c { __plural_scheme_#1:n } {#2} }
\cs_generate_variant:Nn \plural_scheme:nn { v }
% Defining and using a new word
\cs_new_protected:Npn \plural_new_word:nnn #1#2#3
{
\tl_const:cn { c__plural_word_#1_scheme_tl } {#2}
\clist_const:cn { c__plural_word_#1_clist } {#3}
}
\cs_new:Npn \plural_word:nn #1#2
{
\clist_item:cn { c__plural_word_#1_clist }
{ \plural_scheme:vn { c__plural_word_#1_scheme_tl } {#2} }
}
%
\NewDocumentCommand \NW { mmm } % <new word> <plural scheme> <plural forms>
{ \plural_new_word:nnn {#1} {#2} {#3} }
\NewDocumentCommand \UW { mm } % 'use word' <word> <number>
{ \plural_word:nn {#1} {#2} }
\ExplSyntaxOff
%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%% Some pluralization schemes:
% 'n' comes as '#1', return values must start at 1.
\ExplSyntaxOn
\plural_new_scheme:nn { en } % English
{ \int_compare:nTF { #1 = 1 } { 1 } { 2 } }
\plural_new_scheme:nn { ro } % Romanian
{
\int_case:nnF {#1}
{
{ 1 } { 1 } % if #1 is 1, then return 1
{ 0 } { 2 } % if #1 is 0, then return 2
}
{ \int_compare:nTF { 0 < \int_mod:nn {#1} { 100 } < 20 } { 2 } { 3 } }
}
\plural_new_scheme:nn { ru } % Russian
{
\bool_if:nTF
{
\int_compare_p:n { \int_mod:nn {#1} {10} = 1 }
&& \int_compare_p:n { \int_mod:nn {#1} {100} != 11 }
}
{ 1 }
{
\bool_if:nTF
{
\int_compare_p:n { 2 <= \int_mod:nn {#1} {10} <= 4 }
&& ! \int_compare_p:n { 10 <= \int_mod:nn {#1} {100} < 20 }
}
{ 2 }
{ 3 }
}
}
\ExplSyntaxOff
%%%%%%%%%%%%%%%%
\NW{mouse}{en}{mouse,mice}
\NW{mysz}{ru}{mysz,mysze,myszy}
\begin{document}
\UW{mouse}{0}, \UW{mouse}{1}, \UW{mouse}{2}, \UW{mouse}{36}!\
\UW{mysz}{0}, \UW{mysz}{1}, \UW{mysz}{2}, \UW{mysz}{104}!
\end{document}
答案3
针对每个单词单独进行强力解决,这里是 mysz。 (嘿,哈哈)
\documentclass{article}
\usepackage{polski}
\usepackage[cp1250]{inputenc}
\begin{document}
\def\mysz#1{\ifcase#1 myszy\or mysz \or mysze (naprawdę istnieje liczba podwójna?) \or myszy \else myszy \fi}
\mysz0
\mysz1
\mysz2
\mysz{126}
\end{document}
当mysz
被 替换时pani
,就变得复杂了。0 pań, 4 panie, 14 pań, 24 panie, 25 pań 等。并且człowiek
只有两种形式。如果你计划的字数有限,那没问题,但通常这可能是一项艰巨的工作。
答案4
下面是波兰语的纯 TeX 解决方案(基于模数计算这个答案)。为其他斯拉夫语言开发类似的宏留给读者作为练习。
\newcount\moduloResult
\def\modulo#1#2{%
\moduloResult=#1
\divide\moduloResult by #2
\multiply\moduloResult by -#2
\advance\moduloResult by #1\relax}
\def\pluralizePOL#1#2#3#4{%
\def\many{#4}%
\def\few{#3}%
\ifnum#1=1\def\one{#2}\else\let\one\many\fi
\modulo{#1}{100}%
\ifnum\moduloResult>10\ifnum\moduloResult<20\let\few\many\fi\fi
\modulo{#1}{10}%
#1~\ifcase\moduloResult\many\or\one\or\few\or\few\or\few\else\many\fi}
\def\test#1{\pluralizePOL{#1}{jajo}{jaja}{jaj}, }
\test{0}\test{1}\test{2}\test{3}\test{4}\test{5}\par
\test{10}\test{11}\test{12}\test{15}\par
\test{20}\test{21}\test{22}\test{25}\par
\test{100}\test{101}\test{102}\test{105}\par
\test{110}\test{111}\test{112}\test{115}\par
\test{120}\test{121}\test{122}\test{125}\par
\bye