{-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedLists #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-} -- | -- Module : Text.Numerals.Languages.Dutch -- Description : A module to convert numbers to words in the /Dutch/ language. -- Maintainer : hapytexeu+gh@gmail.com -- Stability : experimental -- Portability : POSIX -- -- This module contains logic to convert numbers to words in the /Dutch/ language. module Text.Numerals.Languages.Dutch ( -- * Num to word algorithm dutch, -- * 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 #if __GLASGOW_HASKELL__ < 803 import Data.Semigroup((<>)) #endif import Data.Text (Text, pack, snoc) import Data.Vector (Vector) import Text.Numerals.Algorithm (HighNumberAlgorithm (LongScale), NumeralsAlgorithm, numeralsAlgorithm) import Text.Numerals.Algorithm.Template (ordinizeFromDict) import Text.Numerals.Class (ClockSegment (Half, OClock, Past, PastHalf, QuarterPast, QuarterTo, To, ToHalf), ClockText, DayPart (Afternoon, Evening, Morning, Night), DaySegment (dayHour, dayPart), hourCorrection, toCardinal, valueSplit) import Text.Numerals.Internal (_mergeWithSpace, _million, _pluralize', _showIntegral) $( pure ( ordinizeFromDict "_ordinize'" [ ("nul", "nuld"), ("één", "eerst"), ("twee", "tweed"), ("drie", "derd"), ("vier", "vierd"), ("vijf", "vijfd"), ("zes", "zesd"), ("zeven", "zevend"), ("acht", "achtst"), ("negen", "negend"), ("tien", "tiend"), ("elf", "elfd"), ("twaalf", "twaalfd"), ("ig", "igst"), ("erd", "erdst"), ("end", "endst"), ("joen", "joenst"), ("rd", "rdst") ] 'id ) ) -- | A function that converts a number in words in /cardinal/ form to /ordinal/ -- form according to the /Dutch/ language rules. ordinize' :: Text -> Text ordinize' = (`snoc` 'e') . _ordinize' -- | A 'NumeralsAlgorithm' to convert numbers to words in the /Dutch/ language. dutch :: -- | A 'NumeralsAlgorithm' that can be used to convert numbers to different formats. NumeralsAlgorithm dutch = numeralsAlgorithm negativeWord' zeroWord' oneWord' lowWords' midWords' (valueSplit highWords') merge' ordinize' shortOrdinal' clockText' -- | Convert numers to their cardinal counterpart in /Dutch/. toCardinal' :: Integral i => -- | The number to convert to text. i -> -- | The cardinal counterpart in /Dutch/. Text toCardinal' = toCardinal dutch -- | The words used to mark a negative number in the /Dutch/ language. negativeWord' :: Text negativeWord' = "min" -- | The word used for the number /zero/ in the /Dutch/ language. zeroWord' :: Text zeroWord' = "nul" -- | The word used for the number /one/ in the /Dutch/ language. oneWord' :: Text oneWord' = "één" -- | A 'Vector' that contains the word used for the numbers /two/ to /twenty/ in the /Dutch/ language. lowWords' :: Vector Text lowWords' = [ "twee", "drie", "vier", "vijf", "zes", "zeven", "acht", "negen", "tien", "elf", "twaalf", "dertien", "veertien", "vijftien", "zestien", "zeventien", "achttien", "negentien", "twintig" ] -- | A list of 2-tuples that contains the names of values between /thirty/ and -- /thousand/ in the /Dutch/ language. midWords' :: [(Integer, Text)] midWords' = [ (1000, "duizend"), (100, "honderd"), (90, "negentig"), (80, "tachtig"), (70, "zeventig"), (60, "zestig"), (50, "vijftig"), (40, "veertig"), (30, "dertig") ] _rightAnd :: Integral i => i -> Text -> Text _rightAnd 1 = const "een" _rightAnd _ = id _leftAnd :: Integral i => i -> Text -> Text _leftAnd 1 = const "eenen" _leftAnd n | 2 <- n = addE | 3 <- n = addE | otherwise = (<> "en") where addE = (<> "ën") -- | A merge function that is used to combine the names of words together to -- larger words, according to the /Dutch/ grammar rules. merge' :: Integral i => i -> i -> Text -> Text -> Text merge' 1 r | r < _million = const id | otherwise = const (_merge' 1 r "een") merge' l r = _merge' l r _merge' :: Integral i => i -> i -> Text -> Text -> Text _merge' l r | r > l && r >= _million = _mergeWithSpace | r > l = (<>) | r < 10 && 10 < l && l < 100 = go | l >= _million = _mergeWithSpace | otherwise = (<>) where go tl tr = _leftAnd r tr <> _rightAnd l tl -- | An algorithm to obtain the names of /large/ numbers (one million or larger) -- in /Dutch/. Dutch uses a /long scale/ with the @iljoen@ and @iljard@ -- suffixes. highWords' :: HighNumberAlgorithm highWords' = LongScale "iljoen" "iljard" -- | A function to convert a number to its /short ordinal/ form in /Dutch/. 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` "e") _dayPartText :: DayPart -> Text _dayPartText Night = "'s nachts" _dayPartText Morning = "'s ochtends" _dayPartText Afternoon = "'s middags" _dayPartText Evening = "'s avonds" _dayComponent :: Text -> Int -> DaySegment -> Text _dayComponent sep dh h = toCardinal' (hourCorrection (dayHour h + dh)) <> sep <> _dayPartText (dayPart h) _dayComponent' :: Int -> DaySegment -> Text _dayComponent' = _dayComponent " " _mins :: Int -> Text _mins = _pluralize' " minuut " " minuten " -- | Converting the time to a text that describes that time in /Dutch/. clockText' :: ClockText clockText' OClock ds _ _ = _dayComponent " uur " 0 ds clockText' (Past m) ds _ _ = toCardinal' m <> _mins m <> "na " <> _dayComponent' 0 ds clockText' QuarterPast ds _ _ = "kwart na " <> _dayComponent' 0 ds clockText' (ToHalf m) ds _ _ = toCardinal' m <> _mins m <> "voor half " <> _dayComponent' 1 ds clockText' Half ds _ _ = "half " <> _dayComponent' 1 ds clockText' (PastHalf m) ds _ _ = toCardinal' m <> _mins m <> "na half " <> _dayComponent' 1 ds clockText' QuarterTo ds _ _ = "kwart voor " <> _dayComponent' 1 ds clockText' (To m) ds _ _ = toCardinal' m <> _mins m <> "voor " <> _dayComponent' 1 ds