-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.


{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE NoRebindableSyntax #-}
module Duckling.Locale
  ( Lang(..)
  , Locale(..)
  , Region
      ( AU
      , BE
      , BZ
      , CL
      , CN
      , CO
      , EG
      , GB
      , HK
      , IE
      , IN
      , JM
      , MO
      , MX
      , NZ
      , PE
      , PH
      , TT
      , TW
      , US
      , VE
      , ZA
      )
  , allLocales
  , makeLocale
  ) where

import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.HashSet (HashSet)
import qualified Data.HashSet as HashSet
import Data.Hashable
import GHC.Generics
import Prelude
import TextShow (TextShow)
import qualified TextShow as TS

import Duckling.Region hiding
  ( AR
  , CA
  , ES
  , NL
  )
import qualified Duckling.Region as R
  ( Region
      ( AR
      , CA
      , ES
      , NL
      )
  )

-- | ISO 639-1 Language.
-- See https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
data Lang
  = AF
  | AR
  | BG
  | BN
  | CA
  | CS
  | DA
  | DE
  | EL
  | EN
  | ES
  | ET
  | FA
  | FI
  | FR
  | GA
  | HE
  | HI
  | HR
  | HU
  | ID
  | IS
  | IT
  | JA
  | KA
  | KN
  | KM
  | KO
  | LO
  | ML
  | MN
  | MY
  | NB
  | NE
  | NL
  | PL
  | PT
  | RO
  | RU
  | SK
  | SV
  | SW
  | TA
  | TE
  | TH
  | TR
  | UK
  | VI
  | ZH
  deriving (Lang
Lang -> Lang -> Bounded Lang
forall a. a -> a -> Bounded a
maxBound :: Lang
$cmaxBound :: Lang
minBound :: Lang
$cminBound :: Lang
Bounded, Int -> Lang
Lang -> Int
Lang -> [Lang]
Lang -> Lang
Lang -> Lang -> [Lang]
Lang -> Lang -> Lang -> [Lang]
(Lang -> Lang)
-> (Lang -> Lang)
-> (Int -> Lang)
-> (Lang -> Int)
-> (Lang -> [Lang])
-> (Lang -> Lang -> [Lang])
-> (Lang -> Lang -> [Lang])
-> (Lang -> Lang -> Lang -> [Lang])
-> Enum Lang
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: Lang -> Lang -> Lang -> [Lang]
$cenumFromThenTo :: Lang -> Lang -> Lang -> [Lang]
enumFromTo :: Lang -> Lang -> [Lang]
$cenumFromTo :: Lang -> Lang -> [Lang]
enumFromThen :: Lang -> Lang -> [Lang]
$cenumFromThen :: Lang -> Lang -> [Lang]
enumFrom :: Lang -> [Lang]
$cenumFrom :: Lang -> [Lang]
fromEnum :: Lang -> Int
$cfromEnum :: Lang -> Int
toEnum :: Int -> Lang
$ctoEnum :: Int -> Lang
pred :: Lang -> Lang
$cpred :: Lang -> Lang
succ :: Lang -> Lang
$csucc :: Lang -> Lang
Enum, Lang -> Lang -> Bool
(Lang -> Lang -> Bool) -> (Lang -> Lang -> Bool) -> Eq Lang
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Lang -> Lang -> Bool
$c/= :: Lang -> Lang -> Bool
== :: Lang -> Lang -> Bool
$c== :: Lang -> Lang -> Bool
Eq, (forall x. Lang -> Rep Lang x)
-> (forall x. Rep Lang x -> Lang) -> Generic Lang
forall x. Rep Lang x -> Lang
forall x. Lang -> Rep Lang x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Lang x -> Lang
$cfrom :: forall x. Lang -> Rep Lang x
Generic, Int -> Lang -> Int
Lang -> Int
(Int -> Lang -> Int) -> (Lang -> Int) -> Hashable Lang
forall a. (Int -> a -> Int) -> (a -> Int) -> Hashable a
hash :: Lang -> Int
$chash :: Lang -> Int
hashWithSalt :: Int -> Lang -> Int
$chashWithSalt :: Int -> Lang -> Int
Hashable, Eq Lang
Eq Lang
-> (Lang -> Lang -> Ordering)
-> (Lang -> Lang -> Bool)
-> (Lang -> Lang -> Bool)
-> (Lang -> Lang -> Bool)
-> (Lang -> Lang -> Bool)
-> (Lang -> Lang -> Lang)
-> (Lang -> Lang -> Lang)
-> Ord Lang
Lang -> Lang -> Bool
Lang -> Lang -> Ordering
Lang -> Lang -> Lang
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Lang -> Lang -> Lang
$cmin :: Lang -> Lang -> Lang
max :: Lang -> Lang -> Lang
$cmax :: Lang -> Lang -> Lang
>= :: Lang -> Lang -> Bool
$c>= :: Lang -> Lang -> Bool
> :: Lang -> Lang -> Bool
$c> :: Lang -> Lang -> Bool
<= :: Lang -> Lang -> Bool
$c<= :: Lang -> Lang -> Bool
< :: Lang -> Lang -> Bool
$c< :: Lang -> Lang -> Bool
compare :: Lang -> Lang -> Ordering
$ccompare :: Lang -> Lang -> Ordering
$cp1Ord :: Eq Lang
Ord, ReadPrec [Lang]
ReadPrec Lang
Int -> ReadS Lang
ReadS [Lang]
(Int -> ReadS Lang)
-> ReadS [Lang] -> ReadPrec Lang -> ReadPrec [Lang] -> Read Lang
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [Lang]
$creadListPrec :: ReadPrec [Lang]
readPrec :: ReadPrec Lang
$creadPrec :: ReadPrec Lang
readList :: ReadS [Lang]
$creadList :: ReadS [Lang]
readsPrec :: Int -> ReadS Lang
$creadsPrec :: Int -> ReadS Lang
Read, Int -> Lang -> ShowS
[Lang] -> ShowS
Lang -> String
(Int -> Lang -> ShowS)
-> (Lang -> String) -> ([Lang] -> ShowS) -> Show Lang
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Lang] -> ShowS
$cshowList :: [Lang] -> ShowS
show :: Lang -> String
$cshow :: Lang -> String
showsPrec :: Int -> Lang -> ShowS
$cshowsPrec :: Int -> Lang -> ShowS
Show)

instance TextShow Lang where
  showb :: Lang -> Builder
showb = String -> Builder
TS.fromString (String -> Builder) -> (Lang -> String) -> Lang -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Lang -> String
forall a. Show a => a -> String
show

data Locale = Locale Lang (Maybe Region)
  deriving (Locale -> Locale -> Bool
(Locale -> Locale -> Bool)
-> (Locale -> Locale -> Bool) -> Eq Locale
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Locale -> Locale -> Bool
$c/= :: Locale -> Locale -> Bool
== :: Locale -> Locale -> Bool
$c== :: Locale -> Locale -> Bool
Eq, (forall x. Locale -> Rep Locale x)
-> (forall x. Rep Locale x -> Locale) -> Generic Locale
forall x. Rep Locale x -> Locale
forall x. Locale -> Rep Locale x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Locale x -> Locale
$cfrom :: forall x. Locale -> Rep Locale x
Generic, Int -> Locale -> Int
Locale -> Int
(Int -> Locale -> Int) -> (Locale -> Int) -> Hashable Locale
forall a. (Int -> a -> Int) -> (a -> Int) -> Hashable a
hash :: Locale -> Int
$chash :: Locale -> Int
hashWithSalt :: Int -> Locale -> Int
$chashWithSalt :: Int -> Locale -> Int
Hashable, Eq Locale
Eq Locale
-> (Locale -> Locale -> Ordering)
-> (Locale -> Locale -> Bool)
-> (Locale -> Locale -> Bool)
-> (Locale -> Locale -> Bool)
-> (Locale -> Locale -> Bool)
-> (Locale -> Locale -> Locale)
-> (Locale -> Locale -> Locale)
-> Ord Locale
Locale -> Locale -> Bool
Locale -> Locale -> Ordering
Locale -> Locale -> Locale
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Locale -> Locale -> Locale
$cmin :: Locale -> Locale -> Locale
max :: Locale -> Locale -> Locale
$cmax :: Locale -> Locale -> Locale
>= :: Locale -> Locale -> Bool
$c>= :: Locale -> Locale -> Bool
> :: Locale -> Locale -> Bool
$c> :: Locale -> Locale -> Bool
<= :: Locale -> Locale -> Bool
$c<= :: Locale -> Locale -> Bool
< :: Locale -> Locale -> Bool
$c< :: Locale -> Locale -> Bool
compare :: Locale -> Locale -> Ordering
$ccompare :: Locale -> Locale -> Ordering
$cp1Ord :: Eq Locale
Ord)

instance Show Locale where
  show :: Locale -> String
show (Locale Lang
lang Maybe Region
Nothing) = Lang -> String
forall a. Show a => a -> String
show Lang
lang String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"_XX"
  show (Locale Lang
lang (Just Region
region)) = Lang -> String
forall a. Show a => a -> String
show Lang
lang String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"_" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Region -> String
forall a. Show a => a -> String
show Region
region

instance TextShow Locale where
  showb :: Locale -> Builder
showb = String -> Builder
TS.fromString (String -> Builder) -> (Locale -> String) -> Locale -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Locale -> String
forall a. Show a => a -> String
show

makeLocale :: Lang -> Maybe Region -> Locale
makeLocale :: Lang -> Maybe Region -> Locale
makeLocale Lang
lang Maybe Region
Nothing = Lang -> Maybe Region -> Locale
Locale Lang
lang Maybe Region
forall a. Maybe a
Nothing
makeLocale Lang
lang (Just Region
region)
  | Region -> HashSet Region -> Bool
forall a. (Eq a, Hashable a) => a -> HashSet a -> Bool
HashSet.member Region
region HashSet Region
locales = Lang -> Maybe Region -> Locale
Locale Lang
lang (Maybe Region -> Locale) -> Maybe Region -> Locale
forall a b. (a -> b) -> a -> b
$ Region -> Maybe Region
forall a. a -> Maybe a
Just Region
region
  | Bool
otherwise = Lang -> Maybe Region -> Locale
Locale Lang
lang Maybe Region
forall a. Maybe a
Nothing
  where
    locales :: HashSet Region
locales = HashSet Region
-> Lang -> HashMap Lang (HashSet Region) -> HashSet Region
forall k v. (Eq k, Hashable k) => v -> k -> HashMap k v -> v
HashMap.lookupDefault HashSet Region
forall a. HashSet a
HashSet.empty Lang
lang HashMap Lang (HashSet Region)
allLocales

allLocales :: HashMap Lang (HashSet Region)
allLocales :: HashMap Lang (HashSet Region)
allLocales =
  [(Lang, HashSet Region)] -> HashMap Lang (HashSet Region)
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HashMap.fromList
    [ (Lang
AR, [Region] -> HashSet Region
forall a. (Eq a, Hashable a) => [a] -> HashSet a
HashSet.fromList [Region
EG])
    , (Lang
EN, [Region] -> HashSet Region
forall a. (Eq a, Hashable a) => [a] -> HashSet a
HashSet.fromList [Region
AU, Region
BZ, Region
R.CA, Region
GB, Region
IN, Region
IE, Region
JM, Region
NZ, Region
PH, Region
ZA, Region
TT, Region
US])
    , (Lang
ES, [Region] -> HashSet Region
forall a. (Eq a, Hashable a) => [a] -> HashSet a
HashSet.fromList [Region
R.AR, Region
CL, Region
CO, Region
R.ES, Region
MX, Region
PE, Region
VE])
    , (Lang
NL, [Region] -> HashSet Region
forall a. (Eq a, Hashable a) => [a] -> HashSet a
HashSet.fromList [Region
BE, Region
R.NL])
    , (Lang
ZH, [Region] -> HashSet Region
forall a. (Eq a, Hashable a) => [a] -> HashSet a
HashSet.fromList [Region
CN, Region
HK, Region
MO, Region
TW])
    ]