ordinal-0.6.0.0: src/Text/Numerals/Languages/German.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedLists #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
-- |
-- Module : Text.Numerals.Languages.German
-- Description : A module to convert numbers to words in the /German/ language.
-- Maintainer : hapytexeu+gh@gmail.com
-- Stability : experimental
-- Portability : POSIX
--
-- This module contains logic to convert numbers to words in the /German/ language.
module Text.Numerals.Languages.German
( -- * Num to word algorithm
german,
-- * Convert a cardinal number to text
toCardinal',
-- * Convert to ordinal
ordinize',
-- * Constant words
negativeWord',
zeroWord',
oneWord',
-- * Names for numbers
lowWords',
midWords',
highWords',
-- * Merge function
merge',
)
where
import Data.Bool (bool)
#if __GLASGOW_HASKELL__ < 803
import Data.Semigroup((<>))
#endif
import Data.Text (Text, isSuffixOf, pack, toLower, toTitle)
import Data.Vector (Vector)
import Text.Numerals.Algorithm (HighNumberAlgorithm (LongScale), NumeralsAlgorithm, numeralsAlgorithm, valueSplit')
import Text.Numerals.Algorithm.Template (ordinizeFromDict)
import Text.Numerals.Class (ClockText, FreeMergerFunction, toCardinal)
import Text.Numerals.Internal (_mergeWith, _mergeWithSpace, _million, _showIntegral)
import Text.RE.TDFA.Text (RE, SearchReplace, ed, (*=~/))
$( pure
( ordinizeFromDict
"_ordinize'"
[ ("eins", "ers"),
("drei", "drit"),
("acht", "ach"),
("sieben", "sieb"),
("ig", "igs"),
("ert", "erts"),
("end", "ends"),
("ion", "ions"),
("nen", "ns"),
("rde", "rds"),
("rden", "rds")
]
'id
)
)
-- | A 'NumeralsAlgorithm' to convert numbers to words in the /German/ language.
german ::
-- | A 'NumeralsAlgorithm' that can be used to convert numbers to different formats.
NumeralsAlgorithm
german = numeralsAlgorithm negativeWord' zeroWord' oneWord' lowWords' midWords' (valueSplit' toTitle highWords') merge' ordinize' shortOrdinal' clockText'
-- | Convert numers to their cardinal counterpart in /German/.
toCardinal' ::
Integral i =>
-- | The number to convert to text.
i ->
-- | The cardinal counterpart in /German/.
Text
toCardinal' = toCardinal german
-- | The words used to mark a negative number in the /German/ language.
negativeWord' :: Text
negativeWord' = "minus"
-- | The word used for the number /zero/ in the /German/ language.
zeroWord' :: Text
zeroWord' = "null"
-- | The word used for the number /one/ in the /German/ language.
oneWord' :: Text
oneWord' = "eins"
-- | A 'Vector' that contains the word used for the numbers /two/ to /twenty/ in the /German/ language.
lowWords' :: Vector Text
lowWords' =
[ "zwei",
"drei",
"vier",
"fünf",
"sechs",
"sieben",
"acht",
"neun",
"zehn",
"elf",
"zwölf",
"dreizehn",
"vierzehn",
"fünfzehn",
"sechzehn",
"siebzehn",
"achtzehn",
"neunzehn",
"zwanzig"
]
-- | A list of 2-tuples that contains the names of values between /thirty/ and
-- /thousand/ in the /German/ language.
midWords' :: [(Integer, Text)]
midWords' =
[ (1000, "tausend"),
(100, "hundert"),
(90, "neunzig"),
(80, "achtzig"),
(70, "siebzig"),
(60, "sechzig"),
(50, "fünfzig"),
(40, "vierzig"),
(30, "dreißig")
]
-- | A merge function that is used to combine the names of words together to
-- larger words, according to the /German/ grammar rules.
merge' :: FreeMergerFunction
merge' 1 100 = const ("ein" <>)
merge' 1 1000 = const ("ein" <>)
merge' 1 r | r < _million = const id
merge' 1 r = const (_merge' 1 r "eine")
merge' l r = _merge' l r
_pluralize :: Text -> Text
_pluralize t
| "e" `isSuffixOf` t = t <> "n"
| otherwise = t <> "en"
_merge' :: FreeMergerFunction
_merge' l r
| r > l && r >= _million = (. bool id _pluralize (l > 1)) . _mergeWithSpace
| r > l = (<>)
_merge' l 1 | 10 < l && l < 100 = const . ("einund" <>)
_merge' l r
| r < 10 && 10 < l && l < 100 = flip (_mergeWith "und")
| l >= _million = _mergeWithSpace
| otherwise = (<>)
_ordinalSuffixRe :: SearchReplace RE Text
_ordinalSuffixRe = [ed|(eine)? ([a-z]+(illion|illiard)ste)$///${2}|]
-- | A function that converts a number in words in /cardinal/ form to /ordinal/
-- form according to the /German/ language rules.
ordinize' :: Text -> Text
ordinize' = postprocess . (<> "te") . _ordinize' . toLower
where
postprocess "eintausendste" = "tausendste"
postprocess "einhundertste" = "hundertste"
postprocess t = t *=~/ _ordinalSuffixRe
-- | An algorithm to obtain the names of /large/ numbers (one million or larger)
-- in /German/. German uses a /long scale/ with the @illion@ and @illiard@
-- suffixes.
highWords' :: HighNumberAlgorithm
highWords' = LongScale "illion" "illiarde"
-- | A function to convert a number to its /short ordinal/ form in /German/.
shortOrdinal' ::
Integral i =>
-- | The number to convert to /short ordinal/ form.
i ->
-- | The equivalent 'Text' specifying the number in /short ordinal/ form.
Text
shortOrdinal' = pack . (`_showIntegral` ".")
-- | Converting the time to a text that describes that time in /German/.
clockText' :: ClockText
clockText' _ _ h 0 = toCardinal' h <> " Uhr"
clockText' _ _ h m = toCardinal' h <> " Uhr " <> toCardinal' m