Abstraction for working with pluralization rules.
Check Unicode Language Plural Rules for more information and examples for various languages.
Rules are a dictionary with various plural forms of words in your given language.
Elsewhere you can supply a function giving the default pluralization (in English
that's adding a -s
suffix), but here in Rules
you'll have to supply the
"exceptions" (like words that add an -es
suffix instead).
For an example see fromList
.
Note Rules
don't do anything about case at all! If they contain "query"
but
you then try to pluralize 5 "Query"
, the query
rule won't get used!
empty : Rules
Initialize empty Rules.
fromList : List ( String, List ( Cardinal, String ) ) -> Rules
Create Rules from a list of given exceptions to the general rule.
fromList
[ ( "Query"
, [ ( One, "Query" )
, ( Other, "Queries" )
]
)
]
You can imagine more complicated rules in other languages:
-- Czech rules
fromList
[ ( "muž"
, [ ( One, "muž" ) -- 1, no decimal digits
, ( Few, "muži" ) -- 2..4, no decimal digits
, ( Many, "muže" ) -- with decimal digits
, ( Other, "mužů" ) -- the rest
]
)
]
add : String -> List ( Cardinal, String ) -> Rules -> Rules
Add rules for a new word.
Behaves like Dict.insert
in case of collisions: replaces the previous value in
Rules
with the new value.
Each language will have its own rules for when to use which cardinal.
Check Unicode Language Plural Rules for more information and examples for various languages.
fromInt : { toCardinal : Basics.Float -> Cardinal, defaultPluralize : String -> String } -> Rules -> Basics.Int -> String -> String
Integer-specialized pluralization function. For more info see fromFloat
.
fromFloat : { toCardinal : Basics.Float -> Cardinal, defaultPluralize : String -> String } -> Rules -> Basics.Float -> String -> String
Pluralize a single word.
This is the most general case; the goal is to define and use a partially applied
"homegrown" variant that will apply the configuration and rules and end up with
a function of signature pluralize : Int -> String -> String
:
pluralize 5 "word"
--> "words"
pluralize 5 "query"
--> "queries" if you supplied the cases for "query" in the Rules dictionary
--> "querys" otherwise, as the default rule would fire!
The defaultPluralize
function is a helper for minimizing the amount of Rules
you'll have to write -- it is used when a word or its cardinal isn't found in
Rules
.
This is notably useful for English where most words have the -s
suffix in their plural form; you then have to supply just the "irregular" words
like query -> queries
, index -> indices
, etc.
It's admittedly less useful for some other languages like Czech where there is
no simple default case. In these cases you can supply
defaultPluralize = identity
and instead make sure that all the words you're
pluralizing are found in your Rules
dictionary.
The toCardinal
function implements the rules from Unicode Language Plural
Rules
for which quantities result in which cardinal. Your Rules
dictionary can then
just supply a word for each relevant cardinal, for cases where
defaultPluralize
isn't enough.
When implementing the toCardinal
function you'll likely reference the table of
Plural Rules
for your language.
The rules have conditions like i = 2..4 and v = 0
. See the
Plural Operand Meanings
table or below for
description of these.
{ absoluteValue : Basics.Float
, integerDigits : Basics.Int
, hasFractionDigits : Basics.Bool
}
Taken from Plural Operand Meanings.
Note that v,w,f,t
are quite problematic because of Float
behaviour, at least
when not dealing with simple != 0
. As we didn't need to deal with those
problematic rules, we're currently keeping only what we can guarantee: notably
hasFractionDigits == v != 0
.
If you, when implementing toCardinal
for your language, need those v,w,f,t
operands, shoot us a GitHub issue, we can likely create something working on
String
s which be able to work with trailing zeros etc.
operands : Basics.Float -> Operands
Compute Operands
from a Float
number.