# Selecting grammatical form depending on programatically defined cardinal number (a la ngettext)

There are many languages where grammatical form depends on number of elements described. In English it is singular and plural form (plural usually but not always is generated by adding suffix 's', but see e.g. mouse / mice), in other languages it can be more complicated, as described in gettext manual.

What I'd like to have is a macro which choses grammatical form depending on number, e.g. \nn{\nmice}{mouse}{mice} for English, which would output 1 mouse but 2 mice.

For Polish I would also have to employ some package for integer calculations involving conditionals and modulo

Plural-Forms: nplurals=3; \
plural=n==1 ? 0 : \
n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;


and e.g. \nn{\nmice}{mysz}{mysze}{myszy}.

The above formula (taken from mentioned above gettext documentation) means that in Polish you have 1 mysz (singular, 0th form), 2, 3, 4, 22, 23, 24 mysze (remains of old dual form, 1st plural form), but 5, 6, 7, 11, 12, 13, 14, 25 myszy (plural form, 2nd plural form). Nb. Slovenian has 4 plural forms.

-
I guess I could adapt the solution used in nth package. –  Jakub Narębski Jun 15 '13 at 16:19

LuaTeX is ideally suited for such macros. For example, here is an implementation in ConTeXt (which can be easily translated to 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


which gives

-

Looking at the ngettext approach you pointed to, it seems that there are a limited number of pluralization schemes, so one should define those schemes independently of the list of plurals for a given word.

Here are some examples for pluralizing schemes. For performance, pluralizing schemes are defined using expl3 commands directly instead of parsing the syntax you suggest. It would be possible to replace \plural_new_scheme:nn by

\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 } } }


and then simply replace all n by #1 in your pluralizing scheme definitions (so for instance #1==1?0:1 or #1>1, with operators you are used to in 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}

-

A brutal-force solution for every word separately, here mysz. (Dwie mysze, hihi)

\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}


When mysz is replaced by pani, it becomes more complicated. 0 pań, 4 panie, 14 pań, 24 panie, 25 pań, etc. And człowiek has only two forms. If you are planning a limited number of words, it is no problem, but generally it might be a huge work.

-
What is the rule for pani? How many different forms exist, and what sets of integers (or non-integers) do they correspond to? –  Bruno Le Floch Jun 15 '13 at 15:14
@BrunoLeFloch 0 pań, 1 pani, 2-4 panie, 5-21 pań, and then forms of number modulo 10. –  Przemysław Scherwentke Jun 15 '13 at 15:20
Nothing special mod 100 or 1000? I could expect that (cf, 103rd vs 113th in English). –  Bruno Le Floch Jun 15 '13 at 15:37
@BrunoLeFloch Not for pani. But for ordinal numbers (and the other forms) in Polish it is also more complicated than in case of nouns. Hence I wish to know, what OP really needs. –  Przemysław Scherwentke Jun 15 '13 at 15:42
@BrunoLeFloch: Thanks for pointing the similarity between multiple plural forms and ordinal numbering style, 1st 2nd 3rd 4th 5th... 12th... 101st 102nd... in English. This lead me to considering adapting nth package for this. –  Jakub Narębski Jun 15 '13 at 16:21