    {-# LANGUAGE CPP                        #-}
    {-# LANGUAGE DeriveGeneric              #-}
    {-# LANGUAGE GeneralizedNewtypeDeriving #-}
    {-# LANGUAGE OverloadedStrings          #-}
    {- |
       Module      : Text.Pandoc.Translations.Types
       Copyright   : Copyright (C) 2017-2024 John MacFarlane
       License     : GNU GPL, version 2 or above

       Maintainer  : John MacFarlane <jgm@berkeley.edu>
       Stability   : alpha
       Portability : portable

    Data types for localization.

    Translations are stored in @data/translations/langname.trans@,
    where langname can be the full BCP47 language specifier, or
    just the language part.  File format is:

    > # A comment, ignored
    > Figure: Figura
    > Index: Indeksi

    -}
    module Text.Pandoc.Translations.Types (
                               Term(..)
                             , Translations
                             , lookupTerm
                             )
    where
    import Data.Aeson.Types (Value(..), FromJSON(..))
    import qualified Data.Aeson.Types as Aeson
    import qualified Data.Map as M
    import qualified Data.Text as T
    import GHC.Generics (Generic)
    import Text.Pandoc.Shared (safeRead)

    data Term =
        Abstract
      | Appendix
      | Bibliography
      | Cc
      | Chapter
      | Contents
      | Encl
      | Figure
      | Glossary
      | Index
      | Listing
      | ListOfFigures
      | ListOfTables
      | Page
      | Part
      | Preface
      | Proof
      | References
      | See
      | SeeAlso
      | Table
      | To
      deriving (Int -> Term -> ShowS
    [Term] -> ShowS
    Term -> String
    (Int -> Term -> ShowS)
    -> (Term -> String) -> ([Term] -> ShowS) -> Show Term
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> Term -> ShowS
    showsPrec :: Int -> Term -> ShowS
    $cshow :: Term -> String
    show :: Term -> String
    $cshowList :: [Term] -> ShowS
    showList :: [Term] -> ShowS
    Show, Term -> Term -> Bool
    (Term -> Term -> Bool) -> (Term -> Term -> Bool) -> Eq Term
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Term -> Term -> Bool
    == :: Term -> Term -> Bool
    $c/= :: Term -> Term -> Bool
    /= :: Term -> Term -> Bool
    Eq, Eq Term
    Eq Term =>
    (Term -> Term -> Ordering)
    -> (Term -> Term -> Bool)
    -> (Term -> Term -> Bool)
    -> (Term -> Term -> Bool)
    -> (Term -> Term -> Bool)
    -> (Term -> Term -> Term)
    -> (Term -> Term -> Term)
    -> Ord Term
    Term -> Term -> Bool
    Term -> Term -> Ordering
    Term -> Term -> Term
    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
    $ccompare :: Term -> Term -> Ordering
    compare :: Term -> Term -> Ordering
    $c< :: Term -> Term -> Bool
    < :: Term -> Term -> Bool
    $c<= :: Term -> Term -> Bool
    <= :: Term -> Term -> Bool
    $c> :: Term -> Term -> Bool
    > :: Term -> Term -> Bool
    $c>= :: Term -> Term -> Bool
    >= :: Term -> Term -> Bool
    $cmax :: Term -> Term -> Term
    max :: Term -> Term -> Term
    $cmin :: Term -> Term -> Term
    min :: Term -> Term -> Term
    Ord, (forall x. Term -> Rep Term x)
    -> (forall x. Rep Term x -> Term) -> Generic Term
    forall x. Rep Term x -> Term
    forall x. Term -> Rep Term x
    forall a.
    (forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
    $cfrom :: forall x. Term -> Rep Term x
    from :: forall x. Term -> Rep Term x
    $cto :: forall x. Rep Term x -> Term
    to :: forall x. Rep Term x -> Term
    Generic, Int -> Term
    Term -> Int
    Term -> [Term]
    Term -> Term
    Term -> Term -> [Term]
    Term -> Term -> Term -> [Term]
    (Term -> Term)
    -> (Term -> Term)
    -> (Int -> Term)
    -> (Term -> Int)
    -> (Term -> [Term])
    -> (Term -> Term -> [Term])
    -> (Term -> Term -> [Term])
    -> (Term -> Term -> Term -> [Term])
    -> Enum Term
    forall a.
    (a -> a)
    -> (a -> a)
    -> (Int -> a)
    -> (a -> Int)
    -> (a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> a -> [a])
    -> Enum a
    $csucc :: Term -> Term
    succ :: Term -> Term
    $cpred :: Term -> Term
    pred :: Term -> Term
    $ctoEnum :: Int -> Term
    toEnum :: Int -> Term
    $cfromEnum :: Term -> Int
    fromEnum :: Term -> Int
    $cenumFrom :: Term -> [Term]
    enumFrom :: Term -> [Term]
    $cenumFromThen :: Term -> Term -> [Term]
    enumFromThen :: Term -> Term -> [Term]
    $cenumFromTo :: Term -> Term -> [Term]
    enumFromTo :: Term -> Term -> [Term]
    $cenumFromThenTo :: Term -> Term -> Term -> [Term]
    enumFromThenTo :: Term -> Term -> Term -> [Term]
    Enum, ReadPrec [Term]
    ReadPrec Term
    Int -> ReadS Term
    ReadS [Term]
    (Int -> ReadS Term)
    -> ReadS [Term] -> ReadPrec Term -> ReadPrec [Term] -> Read Term
    forall a.
    (Int -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    $creadsPrec :: Int -> ReadS Term
    readsPrec :: Int -> ReadS Term
    $creadList :: ReadS [Term]
    readList :: ReadS [Term]
    $creadPrec :: ReadPrec Term
    readPrec :: ReadPrec Term
    $creadListPrec :: ReadPrec [Term]
    readListPrec :: ReadPrec [Term]
    Read)

    newtype Translations = Translations (M.Map Term T.Text)
            deriving (Int -> Translations -> ShowS
    [Translations] -> ShowS
    Translations -> String
    (Int -> Translations -> ShowS)
    -> (Translations -> String)
    -> ([Translations] -> ShowS)
    -> Show Translations
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> Translations -> ShowS
    showsPrec :: Int -> Translations -> ShowS
    $cshow :: Translations -> String
    show :: Translations -> String
    $cshowList :: [Translations] -> ShowS
    showList :: [Translations] -> ShowS
    Show, (forall x. Translations -> Rep Translations x)
    -> (forall x. Rep Translations x -> Translations)
    -> Generic Translations
    forall x. Rep Translations x -> Translations
    forall x. Translations -> Rep Translations x
    forall a.
    (forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
    $cfrom :: forall x. Translations -> Rep Translations x
    from :: forall x. Translations -> Rep Translations x
    $cto :: forall x. Rep Translations x -> Translations
    to :: forall x. Rep Translations x -> Translations
    Generic, NonEmpty Translations -> Translations
    Translations -> Translations -> Translations
    (Translations -> Translations -> Translations)
    -> (NonEmpty Translations -> Translations)
    -> (forall b. Integral b => b -> Translations -> Translations)
    -> Semigroup Translations
    forall b. Integral b => b -> Translations -> Translations
    forall a.
    (a -> a -> a)
    -> (NonEmpty a -> a)
    -> (forall b. Integral b => b -> a -> a)
    -> Semigroup a
    $c<> :: Translations -> Translations -> Translations
    <> :: Translations -> Translations -> Translations
    $csconcat :: NonEmpty Translations -> Translations
    sconcat :: NonEmpty Translations -> Translations
    $cstimes :: forall b. Integral b => b -> Translations -> Translations
    stimes :: forall b. Integral b => b -> Translations -> Translations
    Semigroup, Semigroup Translations
    Translations
    Semigroup Translations =>
    Translations
    -> (Translations -> Translations -> Translations)
    -> ([Translations] -> Translations)
    -> Monoid Translations
    [Translations] -> Translations
    Translations -> Translations -> Translations
    forall a.
    Semigroup a =>
    a -> (a -> a -> a) -> ([a] -> a) -> Monoid a
    $cmempty :: Translations
    mempty :: Translations
    $cmappend :: Translations -> Translations -> Translations
    mappend :: Translations -> Translations -> Translations
    $cmconcat :: [Translations] -> Translations
    mconcat :: [Translations] -> Translations
    Monoid)

    instance FromJSON Term where
      parseJSON :: Value -> Parser Term
    parseJSON (String Text
    t) = case Text -> Maybe Term
    forall (m :: * -> *) a. (MonadPlus m, Read a) => Text -> m a
    safeRead Text
    t of
                                   Just Term
    t' -> Term -> Parser Term
    forall a. a -> Parser a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure Term
    t'
                                   Maybe Term
    Nothing -> String -> Parser Term
    forall a. String -> Parser a
    forall (m :: * -> *) a. MonadFail m => String -> m a
    Prelude.fail (String -> Parser Term) -> String -> Parser Term
    forall a b. (a -> b) -> a -> b
    $ String
    "Invalid Term name " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++
                                                     Text -> String
    forall a. Show a => a -> String
    show Text
    t
      parseJSON Value
    invalid = String -> Value -> Parser Term
    forall a. String -> Value -> Parser a
    Aeson.typeMismatch String
    "Term" Value
    invalid

    instance FromJSON Translations where
      parseJSON :: Value -> Parser Translations
    parseJSON o :: Value
    o@(Object{}) = do
        xs <- Value -> Parser (Map Text Value)
    forall a. FromJSON a => Value -> Parser a
    parseJSON Value
    o Parser (Map Text Value)
    -> (Map Text Value -> Parser [(Term, Text)])
    -> Parser [(Term, Text)]
    forall a b. Parser a -> (a -> Parser b) -> Parser b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= ((Text, Value) -> Parser (Term, Text))
    -> [(Text, Value)] -> Parser [(Term, Text)]
    forall (t :: * -> *) (m :: * -> *) a b.
    (Traversable t, Monad m) =>
    (a -> m b) -> t a -> m (t b)
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
    mapM (Text, Value) -> Parser (Term, Text)
    forall {a}. Read a => (Text, Value) -> Parser (a, Text)
    addItem ([(Text, Value)] -> Parser [(Term, Text)])
    -> (Map Text Value -> [(Text, Value)])
    -> Map Text Value
    -> Parser [(Term, Text)]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Map Text Value -> [(Text, Value)]
    forall k a. Map k a -> [(k, a)]
    M.toList
        return $ Translations (M.fromList xs)
        where addItem :: (Text, Value) -> Parser (a, Text)
    addItem (Text
    k,Value
    v) =
                case Text -> Maybe a
    forall (m :: * -> *) a. (MonadPlus m, Read a) => Text -> m a
    safeRead Text
    k of
                     Maybe a
    Nothing -> String -> Parser (a, Text)
    forall a. String -> Parser a
    forall (m :: * -> *) a. MonadFail m => String -> m a
    Prelude.fail (String -> Parser (a, Text)) -> String -> Parser (a, Text)
    forall a b. (a -> b) -> a -> b
    $ String
    "Invalid Term name " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ Text -> String
    forall a. Show a => a -> String
    show Text
    k
                     Just a
    t  ->
                       case Value
    v of
                            (String Text
    s) -> (a, Text) -> Parser (a, Text)
    forall a. a -> Parser a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (a
    t, Text -> Text
    T.strip Text
    s)
                            Value
    inv        -> String -> Value -> Parser (a, Text)
    forall a. String -> Value -> Parser a
    Aeson.typeMismatch String
    "String" Value
    inv
      parseJSON Value
    invalid = String -> Value -> Parser Translations
    forall a. String -> Value -> Parser a
    Aeson.typeMismatch String
    "Translations" Value
    invalid

    -- | Lookup a term in a 'Translations'.
    lookupTerm :: Term -> Translations -> Maybe T.Text
    lookupTerm :: Term -> Translations -> Maybe Text
    lookupTerm Term
    t (Translations Map Term Text
    tm) = Term -> Map Term Text -> Maybe Text
    forall k a. Ord k => k -> Map k a -> Maybe a
    M.lookup Term
    t Map Term Text
    tm