-- | This module provides a small English locale.
--
-- The locale is intended for tests and experimentation, not for production use.
--
-- == Supported
--
-- * Cardinal and ordinal plural rules.
-- * Decimal, percent, currency and unit numbers.
-- * Dates and times in UTC.
--
-- == Limitations
--
-- * No regional differences are supported.
--   Every language code with language @en@, such as @en-US@ and @en-GB@, gives the same output.
-- * With the currency display @symbol@, only currencies in 'currencies' have a symbol.
--   Any other currency is shown by its ISO 4217 code.
-- * The currency display @name@ is not supported. It shows the ISO 4217 code like @code@, so
--   @EUR@ gives @EUR 12.50@, not @12.50 euros@.
-- * Only units in 'units' are supported. Any other unit fails.
-- * The unit displays @narrow@ and @long@ are not supported. They show the same abbreviation as
--   @short@, so @long@ gives @3 s@, not @3 seconds@.
-- * Significant digits have no effect.
-- * Era and time zone name fields are left out of dates.
-- * Time zones other than UTC fail.
module Language.Fluent.Locale.English where

import Data.Char qualified as Char
import Data.HashMap.Strict (HashMap)
import Data.HashMap.Strict qualified as HashMap
import Data.List qualified as List
import Data.Maybe qualified as Maybe
import Data.Scientific qualified as Scientific
import Data.Text (Text)
import Data.Text qualified as Text
import Data.Time qualified as Time
import Language.Fluent.Locale (Locale (..))
import Language.Fluent.Number (NumberOptions (..))
import Language.Fluent.Number qualified as NumberOptions
import Language.Fluent.Plural qualified as Plural
import Language.Fluent.Time (TimeOptions (..))
import Language.Fluent.Time qualified as TimeOptions
import Language.Fluent.Width (Width (..))
import Prelude

-- | A small English locale.
--
-- See [the module documentation]("Language.Fluent.Locale.English") for the full list of limitations.
data English = English

-- |
-- ['fromCode']: Accepts any code with language "en", ignoring case:
--
--       * "en", \"EN\", "en-US", and "en_AU" all yield 'English'.
--       * "english" is rejected.
--
-- ['toCode']: Always yields "en".
--
-- ['displayLanguage']: Always yields \"English\".
--
-- ['pluralCategory']:
--
--       * Cardinal: 'Plural.One' for an absolute value of exactly 1 with zero fraction digits;
--                   'Plural.Other' for all other numbers.
--       * Ordinal: 'Plural.One' for numbers ending in 1;
--                  'Plural.Two' for numbers ending in 2;
--                  'Plural.Few' for numbers ending in 3;
--                  'Plural.Other' for all other integers, fractions, and values beyond 'Int'.
--
-- ['formatNumber']: Uses sign, prefix, digits, and suffix layout.
--
--       * Grouping uses commas by default unless disabled.
--       * Percent multiplies by 100 and appends a no-break space and "%".
--       * Currency defaults to ISO 4217 fractional digits, e.g., 0 for JPY.
--       * Units append a no-break space and abbreviation, pluralizing day, week, month, and year
--         with an "s" unless the category is "one".
--
-- ['formatTime']: Renders UTC date and time layouts:
--
--       * Fails if the time zone is anything other than UTC.
--       * Joins weekday, date, and time fields with ", ".
--       * Numeric months, e.g. "21\/08\/2026"
--       * Full month names, e.g. "21 August 2026"
instance Locale English where
    fromCode :: Text -> Maybe English
fromCode Text
code
        | Text -> Text
Text.toLower ((Char -> Bool) -> Text -> Text
Text.takeWhile Char -> Bool
Char.isAlpha Text
code) Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
"en" = English -> Maybe English
forall a. a -> Maybe a
Just English
English
        | Bool
otherwise = Maybe English
forall a. Maybe a
Nothing

    toCode :: English -> Text
toCode English
English = Text
"en"

    displayLanguage :: English -> English -> Maybe Text
displayLanguage English
English English
English = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"English"

    capitalise :: English -> Text -> Text
capitalise English
English (Int -> Text -> (Text, Text)
Text.splitAt Int
1 -> (Text
initial, Text
rest)) = Text -> Text
Text.toTitle Text
initial Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
rest

    pluralCategory :: English -> Scientific -> NumberOptions -> Category
pluralCategory English
English Scientific
value NumberOptions
options = case NumberOptions
options.form of
        Form
Plural.Cardinal
            | Scientific -> Scientific
forall a. Num a => a -> a
abs Scientific
value Scientific -> Scientific -> Bool
forall a. Eq a => a -> a -> Bool
== Scientific
1 Bool -> Bool -> Bool
&& (Int, Int) -> Int
forall a b. (a, b) -> a
fst (NumberOptions -> (Int, Int)
NumberOptions.fractionDigits NumberOptions
options) Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 -> Category
Plural.One
            | Bool
otherwise -> Category
Plural.Other
        Form
Plural.Ordinal -> case forall i. (Integral i, Bounded i) => Scientific -> Maybe i
Scientific.toBoundedInteger @Int (Scientific -> Scientific
forall a. Num a => a -> a
abs Scientific
value) of
            Just Int
n | Int
n Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
100 Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Int
11 .. Int
13] -> case Int
n Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
10 of
                Int
1 -> Category
Plural.One
                Int
2 -> Category
Plural.Two
                Int
3 -> Category
Plural.Few
                Int
_ -> Category
Plural.Other
            Maybe Int
_ -> Category
Plural.Other

    formatNumber :: NonEmpty English
-> Scientific -> NumberOptions -> Either String Text
formatNumber NonEmpty English
_ Scientific
value NumberOptions
options = case NumberOptions
options.style of
        Style
NumberOptions.Decimal -> Text -> Text -> Either String Text
format Text
"" Text
""
        Style
NumberOptions.Percent -> Text -> Text -> Either String Text
format Text
"" Text
"\xA0%"
        NumberOptions.Currency (Text -> Text
Text.toUpper -> Text
code)
            | CurrencyDisplay
NumberOptions.Symbol <- NumberOptions
options.currencyDisplay
            , Just Text
symbol <- Text -> HashMap Text Text -> Maybe Text
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HashMap.lookup Text
code HashMap Text Text
currencies ->
                Text -> Text -> Either String Text
format Text
symbol Text
""
            | Bool
otherwise -> Text -> Text -> Either String Text
format (Text
code Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\xA0") Text
""
        NumberOptions.Unit (Text -> Text
NumberOptions.unitIdentifier -> Text
unit) ->
            case Text -> HashMap Text Text -> Maybe Text
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HashMap.lookup Text
unit HashMap Text Text
units of
                Maybe Text
Nothing -> String -> Either String Text
forall a b. a -> Either a b
Left (String -> Either String Text) -> String -> Either String Text
forall a b. (a -> b) -> a -> b
$ String
"NUMBER: unknown unit: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Text -> String
Text.unpack Text
unit
                Just Text
symbol
                    | Text
unit Text -> [Text] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Text
"day", Text
"week", Text
"month", Text
"year"]
                    , English -> Scientific -> NumberOptions -> Category
forall l. Locale l => l -> Scientific -> NumberOptions -> Category
pluralCategory English
English Scientific
value NumberOptions
options Category -> Category -> Bool
forall a. Eq a => a -> a -> Bool
/= Category
Plural.One ->
                        Text -> Text -> Either String Text
format Text
"" (Text
"\xA0" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
symbol Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"s")
                    | Bool
otherwise -> Text -> Text -> Either String Text
format Text
"" (Text
"\xA0" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
symbol)
      where
        format :: Text -> Text -> Either String Text
format Text
before Text
after = Text -> Either String Text
forall a b. b -> Either a b
Right (Text -> Either String Text) -> Text -> Either String Text
forall a b. (a -> b) -> a -> b
$ Text
sign Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
before Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
digits Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
after
        sign :: Text
sign = if Scientific
value Scientific -> Scientific -> Bool
forall a. Ord a => a -> a -> Bool
< Scientific
0 then Text
"-" else Text
""
        amount :: Scientific
amount
            | NumberOptions
options.style Style -> Style -> Bool
forall a. Eq a => a -> a -> Bool
== Style
NumberOptions.Percent = Scientific -> Scientific
forall a. Num a => a -> a
abs Scientific
value Scientific -> Scientific -> Scientific
forall a. Num a => a -> a -> a
* Scientific
100
            | Bool
otherwise = Scientific -> Scientific
forall a. Num a => a -> a
abs Scientific
value
        (Int
atLeast, Int
atMost) = case NumberOptions
options.style of
            NumberOptions.Currency (Text -> Text
Text.toUpper -> Text
code)
                | NumberOptions
options.minimumFractionDigits Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0
                , Maybe Int
Nothing <- NumberOptions
options.maximumFractionDigits
                , let places :: Int
places = Text -> Int
currencyDigits Text
code ->
                    (Int
places, Int
places)
            Style
_ -> NumberOptions -> (Int, Int)
NumberOptions.fractionDigits NumberOptions
options
        (Integer
whole, Integer
fractional) =
            forall a b. (RealFrac a, Integral b) => a -> b
floor @_ @Integer (Scientific -> Rational
forall a. Real a => a -> Rational
toRational Scientific
amount Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
* Rational
10 Rational -> Int -> Rational
forall a b. (Num a, Integral b) => a -> b -> a
^ Int
atMost Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
+ Rational
1 Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/ Rational
2) Integer -> Integer -> (Integer, Integer)
forall a. Integral a => a -> a -> (a, a)
`divMod` (Integer
10 Integer -> Int -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ Int
atMost)
        padded :: Text
padded = Int -> Char -> Text -> Text
Text.justifyRight (NumberOptions -> Int
NumberOptions.integerDigits NumberOptions
options) Char
'0' (Text -> Text) -> (Integer -> Text) -> Integer -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Text
forall a. Show a => a -> Text
Text.show (Integer -> Text) -> Integer -> Text
forall a b. (a -> b) -> a -> b
$ Integer
whole
        integer :: Text
integer
            | NumberOptions
options.useGrouping =
                Text -> Text
Text.reverse (Text -> Text) -> (Text -> Text) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Text] -> Text
Text.intercalate Text
"," ([Text] -> Text) -> (Text -> [Text]) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Text -> [Text]
Text.chunksOf Int
3 (Text -> [Text]) -> (Text -> Text) -> Text -> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
Text.reverse (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ Text
padded
            | Bool
otherwise = Text
padded
        fraction :: Text
fraction =
            Int -> Char -> Text -> Text
Text.justifyLeft Int
atLeast Char
'0'
                (Text -> Text) -> (Integer -> Text) -> Integer -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> Text -> Text
Text.dropWhileEnd (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'0')
                (Text -> Text) -> (Integer -> Text) -> Integer -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Char -> Text -> Text
Text.justifyRight Int
atMost Char
'0'
                (Text -> Text) -> (Integer -> Text) -> Integer -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Text
forall a. Show a => a -> Text
Text.show
                (Integer -> Text) -> Integer -> Text
forall a b. (a -> b) -> a -> b
$ Integer
fractional
        digits :: Text
digits
            | Text -> Bool
Text.null Text
fraction = Text
integer
            | Bool
otherwise = Text
integer Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"." Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
fraction

    formatTime :: NonEmpty English -> UTCTime -> TimeOptions -> Either String Text
formatTime NonEmpty English
_ UTCTime
when TimeOptions
options
        | TimeOptions
options.timeZone Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
/= Text
"UTC" =
            String -> Either String Text
forall a b. a -> Either a b
Left (String -> Either String Text) -> String -> Either String Text
forall a b. (a -> b) -> a -> b
$ String
"DATETIME: unsupported time zone: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Text -> String
Text.unpack TimeOptions
options.timeZone
        | Bool
otherwise = Text -> Either String Text
forall a b. b -> Either a b
Right (Text -> Either String Text)
-> (String -> Text) -> String -> Either String Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
Text.pack (String -> Either String Text) -> String -> Either String Text
forall a b. (a -> b) -> a -> b
$ TimeLocale -> String -> UTCTime -> String
forall t. FormatTime t => TimeLocale -> String -> t -> String
Time.formatTime TimeLocale
Time.defaultTimeLocale String
layout UTCTime
when
      where
        fields :: [(Char, Either Digits Width)]
fields = TimeOptions -> [(Char, Either Digits Width)]
TimeOptions.fields TimeOptions
options
        textualMonth :: Bool
textualMonth = case Char
-> [(Char, Either Digits Width)] -> Maybe (Either Digits Width)
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Char
'M' [(Char, Either Digits Width)]
fields of
            Just (Right Width
_) -> Bool
True
            Maybe (Either Digits Width)
_ -> Bool
False
        layout :: String
layout =
            String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
List.intercalate String
", " ([String] -> String)
-> ([String] -> [String]) -> [String] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> Bool) -> [String] -> [String]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (String -> Bool) -> String -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null) ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$
                [ String -> String -> String
part String
"" String
"E"
                , String -> String -> String
part (if Bool
textualMonth then String
" " else String
"/") String
"dMy"
                , String -> String -> String
part String
":" String
"hHjms" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
meridiem
                ]
        meridiem :: String
meridiem = case Char
-> [(Char, Either Digits Width)] -> Maybe (Either Digits Width)
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Char
'h' [(Char, Either Digits Width)]
fields of
            Just Either Digits Width
_ -> String
" %p"
            Maybe (Either Digits Width)
Nothing -> String
""

        part :: String -> String -> String
part String
separator String
symbols =
            String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
List.intercalate String
separator ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$
                (Char -> Maybe String) -> String -> [String]
forall a b. (a -> Maybe b) -> [a] -> [b]
Maybe.mapMaybe (\Char
symbol -> Char -> Either Digits Width -> String
render Char
symbol (Either Digits Width -> String)
-> Maybe (Either Digits Width) -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Char
-> [(Char, Either Digits Width)] -> Maybe (Either Digits Width)
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Char
symbol [(Char, Either Digits Width)]
fields) String
symbols

        render :: Char -> Either Digits Width -> String
render Char
'E' (Right Width
Long) = String
"%A"
        render Char
'E' (Right Width
_) = String
"%a"
        render Char
'M' (Right Width
Long) = String
"%B"
        render Char
'M' (Right Width
_) = String
"%b"
        render Char
'M' (Left Digits
_) = String
"%m"
        render Char
'd' Either Digits Width
_ = if Bool
textualMonth then String
"%-d" else String
"%d"
        render Char
'y' Either Digits Width
_ = String
"%Y"
        render Char
'h' Either Digits Width
_ = String
"%-I"
        render Char
'H' Either Digits Width
_ = String
"%H"
        render Char
'j' Either Digits Width
_ = String
"%H"
        render Char
'm' Either Digits Width
_ = String
"%M"
        render Char
's' Either Digits Width
_ = String
"%S"
        render Char
_ Either Digits Width
_ = String
""

-- | The abbreviations of units of measurement, in the singular, by their CLDR identifier.
units :: HashMap Text Text
units :: HashMap Text Text
units =
    [(Text, Text)] -> HashMap Text Text
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HashMap.fromList ([(Text, Text)] -> HashMap Text Text)
-> (Text -> [(Text, Text)]) -> Text -> HashMap Text Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> (Text, Text)) -> [Text] -> [(Text, Text)]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Text -> Text) -> (Text, Text) -> (Text, Text)
forall a b. (a -> b) -> (Text, a) -> (Text, b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Int -> Text -> Text
Text.drop Int
1) ((Text, Text) -> (Text, Text))
-> (Text -> (Text, Text)) -> Text -> (Text, Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HasCallStack => Text -> Text -> (Text, Text)
Text -> Text -> (Text, Text)
Text.breakOn Text
",") ([Text] -> [(Text, Text)])
-> (Text -> [Text]) -> Text -> [(Text, Text)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Text]
Text.lines (Text -> HashMap Text Text) -> Text -> HashMap Text Text
forall a b. (a -> b) -> a -> b
$
        Text
"millimeter,mm\n\
        \centimeter,cm\n\
        \meter,m\n\
        \kilometer,km\n\
        \inch,in\n\
        \foot,ft\n\
        \yard,yd\n\
        \mile,mi\n\
        \square-meter,m²\n\
        \square-kilometer,km²\n\
        \square-foot,sq ft\n\
        \square-mile,sq mi\n\
        \hectare,ha\n\
        \acre,ac\n\
        \milliliter,mL\n\
        \liter,L\n\
        \gallon,gal\n\
        \fluid-ounce,fl oz\n\
        \pint,pt\n\
        \quart,qt\n\
        \tablespoon,tbsp\n\
        \teaspoon,tsp\n\
        \milligram,mg\n\
        \gram,g\n\
        \kilogram,kg\n\
        \ounce,oz\n\
        \pound,lb\n\
        \stone,st\n\
        \metric-ton,t\n\
        \ton,tn\n\
        \millisecond,ms\n\
        \second,s\n\
        \minute,min\n\
        \hour,hr\n\
        \day,day\n\
        \week,wk\n\
        \month,mth\n\
        \year,yr\n\
        \kilometer-per-hour,km/h\n\
        \mile-per-hour,mph\n\
        \meter-per-second,m/s\n\
        \bit,bit\n\
        \byte,byte\n\
        \kilobyte,kB\n\
        \megabyte,MB\n\
        \gigabyte,GB\n\
        \terabyte,TB\n\
        \petabyte,PB\n\
        \watt,W\n\
        \kilowatt,kW\n\
        \megawatt,MW\n\
        \kilowatt-hour,kWh\n\
        \celsius,°C\n\
        \fahrenheit,°F\n\
        \kelvin,K\n\
        \volt,V\n\
        \ampere,A\n\
        \hertz,Hz\n\
        \kilohertz,kHz\n\
        \megahertz,MHz\n\
        \gigahertz,GHz"

-- | The symbols of currencies by their ISO 4217 code.
currencies :: HashMap Text Text
currencies :: HashMap Text Text
currencies =
    [(Text, Text)] -> HashMap Text Text
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HashMap.fromList ([(Text, Text)] -> HashMap Text Text)
-> (Text -> [(Text, Text)]) -> Text -> HashMap Text Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> (Text, Text)) -> [Text] -> [(Text, Text)]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Text -> Text) -> (Text, Text) -> (Text, Text)
forall a b. (a -> b) -> (Text, a) -> (Text, b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Int -> Text -> Text
Text.drop Int
1) ((Text, Text) -> (Text, Text))
-> (Text -> (Text, Text)) -> Text -> (Text, Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HasCallStack => Text -> Text -> (Text, Text)
Text -> Text -> (Text, Text)
Text.breakOn Text
",") ([Text] -> [(Text, Text)])
-> (Text -> [Text]) -> Text -> [(Text, Text)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Text]
Text.lines (Text -> HashMap Text Text) -> Text -> HashMap Text Text
forall a b. (a -> b) -> a -> b
$
        Text
"GBP,£\n\
        \EUR,€\n\
        \USD,$\n\
        \AUD,A$\n\
        \CAD,CA$\n\
        \JPY,¥\n\
        \CNY,CN¥\n\
        \KRW,₩\n\
        \INR,₹\n\
        \HKD,HK$\n\
        \NZD,NZ$\n\
        \BRL,R$\n\
        \MXN,MX$"

-- | The number of digits after the decimal point of an amount of a currency by its ISO 4217 code.
currencyDigits :: Text -> Int
currencyDigits :: Text -> Int
currencyDigits Text
code
    | Text
code Text -> [Text] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` Text -> [Text]
Text.words Text
"BHD JOD KWD LYD OMR TND" = Int
3
    | Text
code Text -> [Text] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` Text -> [Text]
Text.words Text
"CLF UYW" = Int
4
    | Text
code Text -> [Text] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` Text -> [Text]
Text.words Text
zeroDigits = Int
0
    | Bool
otherwise = Int
2
  where
    zeroDigits :: Text
    zeroDigits :: Text
zeroDigits =
        Text
"ADP AFN ALL BIF BYR CLP COP DJF ESP GNF HUF IDR IQD IRR ISK ITL JPY KMF KPW KRW LAK LBP \
        \LUF MGA MGF MMK MRO PKR PYG RWF SLL SOS STD SYP TMM TRL UGX UYI VND VUV XAF XOF XPF YER \
        \ZMK ZWD"