{-# LANGUAGE TypeSynonymInstances, FlexibleInstances, ExistentialQuantification, DeriveDataTypeable #-}
-- | This is the main module of the @localize@ package.
-- It contains definitions of general use and reexport generally required internal modules.
module Text.Localize
  (
   -- $description
   --
   -- * Most used functions
   __, __n, __f,
   -- * Basic functions
   translate, translateN, translateNFormat, 
   lookup, withTranslation,
   -- * Reexports
   module Text.Localize.Types,
   module Text.Localize.Load,
   module Text.Localize.Locale
  ) where

import Prelude hiding (lookup)
import Control.Applicative
import Control.Monad
import qualified Data.Map as M
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L
import qualified Data.Text.Lazy as T
import qualified Data.Text.Lazy.Encoding as TLE
import qualified Data.Text.Encoding as TE
import Data.String
import Data.List hiding (lookup)
import Data.Monoid
import Data.Typeable
import qualified Data.Gettext as Gettext
import qualified Data.Text.Format.Heavy as F
import Data.Text.Format.Heavy.Parse (parseFormat)

import Text.Localize.Types
import Text.Localize.Load
import Text.Localize.Locale

-- $description
--
-- This is the main module of the @localize@ package. In most cases, you have to import only
-- this module. In specific cases, you may also want to import Text.Localize.IO or Text.Localize.State.
--
-- All functions exported by @localize@ package work with any instance of the
-- @Localized@ type class. There are two simple examples of this type class
-- implementation provided in separate modules (IO and State); however, in
-- complex applications it may be more convinient to implement @Localized@
-- instance for the monadic stack you already have.
--
-- Example of usage is:
--
-- @
-- import qualified Data.Text as T
-- import qualified Data.Text.Lazy.IO as TLIO
-- import Text.Localize
-- 
-- newtype MyMonad a = MyMonad {unMyMonad :: ... }
--   deriving (Monad)
-- 
-- instance Localized MyMonad where
--   ...
--
-- runMyMonad :: Translations -> MyMonad a -> IO a
-- runMyMonad = ...
-- 
-- hello :: T.Text -> MyMonad ()
-- hello name = do
--   liftIO $ TLIO.putStrLn =<< __ "Your name: "
--   liftIO $ hFlush stdout
--   name <- liftIO $ TLIO.getLine
--   greeting <- __f "Hello, {}!" (Single name)
--   liftIO $ TLIO.putStrLn greeting
--
-- main :: IO ()
-- main = do
--   translations <- locateTranslations $ linuxLocation "hello"
--   runMyMonad translations hello
--
-- @
--
-- See also working examples under @examples/@ directory.
--

-- | Look up for translation. Returns source string if translation not found.
lookup :: Translations -> LanguageId -> TranslationSource -> T.Text
lookup :: Translations -> LanguageId -> TranslationSource -> Text
lookup Translations
t LanguageId
lang TranslationSource
bstr =
  case LanguageId -> Map LanguageId Catalog -> Maybe Catalog
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup LanguageId
lang (Translations -> Map LanguageId Catalog
tMap Translations
t) of
    Maybe Catalog
Nothing -> TranslationSource -> Text
toText TranslationSource
bstr
    Just Catalog
gmo -> Catalog -> TranslationSource -> Text
Gettext.gettext Catalog
gmo TranslationSource
bstr

-- | Execute function depending on current translation catalog and context.
withTranslation :: Localized m
                => (b -> r)    -- ^ Function to be executed if there is no
                               --   translation for current language loaded.
                -> (Gettext.Catalog -> Maybe Context -> b -> r) -- ^ Function to be executed on current catalog.
                -> (b -> m r)  -- ^ Function lifted into @Localized@ monad.
withTranslation :: (b -> r)
-> (Catalog -> Maybe TranslationSource -> b -> r) -> b -> m r
withTranslation b -> r
dflt Catalog -> Maybe TranslationSource -> b -> r
fn b
b = do
  Translations
t <- m Translations
forall (m :: * -> *). Localized m => m Translations
getTranslations
  LanguageId
lang <- m LanguageId
forall (m :: * -> *). Localized m => m LanguageId
getLanguage
  Maybe TranslationSource
ctxt <- m (Maybe TranslationSource)
forall (m :: * -> *). Localized m => m (Maybe TranslationSource)
getContext
  case LanguageId -> Map LanguageId Catalog -> Maybe Catalog
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup LanguageId
lang (Translations -> Map LanguageId Catalog
tMap Translations
t) of
    Maybe Catalog
Nothing -> r -> m r
forall (m :: * -> *) a. Monad m => a -> m a
return (r -> m r) -> r -> m r
forall a b. (a -> b) -> a -> b
$ b -> r
dflt b
b
    Just Catalog
gmo -> r -> m r
forall (m :: * -> *) a. Monad m => a -> m a
return (r -> m r) -> r -> m r
forall a b. (a -> b) -> a -> b
$ Catalog -> Maybe TranslationSource -> b -> r
fn Catalog
gmo Maybe TranslationSource
ctxt b
b

-- | Translate a string.
translate :: (Localized m) => TranslationSource -> m T.Text
translate :: TranslationSource -> m Text
translate TranslationSource
orig = do
  Translations
t <- m Translations
forall (m :: * -> *). Localized m => m Translations
getTranslations
  LanguageId
lang <- m LanguageId
forall (m :: * -> *). Localized m => m LanguageId
getLanguage
  Maybe TranslationSource
mbContext <- m (Maybe TranslationSource)
forall (m :: * -> *). Localized m => m (Maybe TranslationSource)
getContext
  case LanguageId -> Map LanguageId Catalog -> Maybe Catalog
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup LanguageId
lang (Translations -> Map LanguageId Catalog
tMap Translations
t) of
    Maybe Catalog
Nothing -> Text -> m Text
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> m Text) -> Text -> m Text
forall a b. (a -> b) -> a -> b
$ TranslationSource -> Text
toText TranslationSource
orig
    Just Catalog
gmo ->
      case Maybe TranslationSource
mbContext of
        Maybe TranslationSource
Nothing -> Text -> m Text
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> m Text) -> Text -> m Text
forall a b. (a -> b) -> a -> b
$ Catalog -> TranslationSource -> Text
Gettext.gettext Catalog
gmo TranslationSource
orig
        Just TranslationSource
ctxt -> Text -> m Text
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> m Text) -> Text -> m Text
forall a b. (a -> b) -> a -> b
$ Catalog -> TranslationSource -> TranslationSource -> Text
Gettext.cgettext Catalog
gmo TranslationSource
ctxt TranslationSource
orig

-- | Short alias for @translate@.
__ ::  (Localized m) => TranslationSource -> m T.Text
__ :: TranslationSource -> m Text
__ = TranslationSource -> m Text
forall (m :: * -> *). Localized m => TranslationSource -> m Text
translate

-- | Translate a string, taking plural forms into account.
translateN :: (Localized m)
           => TranslationSource -- ^ Single form in original language
           -> TranslationSource -- ^ Plural form in original language
           -> Int               -- ^ Number
           -> m T.Text
translateN :: TranslationSource -> TranslationSource -> Int -> m Text
translateN TranslationSource
orig TranslationSource
plural Int
n = do
  Translations
t <- m Translations
forall (m :: * -> *). Localized m => m Translations
getTranslations
  LanguageId
lang <- m LanguageId
forall (m :: * -> *). Localized m => m LanguageId
getLanguage
  Maybe TranslationSource
mbContext <- m (Maybe TranslationSource)
forall (m :: * -> *). Localized m => m (Maybe TranslationSource)
getContext
  case LanguageId -> Map LanguageId Catalog -> Maybe Catalog
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup LanguageId
lang (Translations -> Map LanguageId Catalog
tMap Translations
t) of
    Maybe Catalog
Nothing -> Text -> m Text
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> m Text) -> Text -> m Text
forall a b. (a -> b) -> a -> b
$ TranslationSource -> Text
toText TranslationSource
orig
    Just Catalog
gmo ->
      case Maybe TranslationSource
mbContext of
        Maybe TranslationSource
Nothing -> Text -> m Text
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> m Text) -> Text -> m Text
forall a b. (a -> b) -> a -> b
$ Catalog -> TranslationSource -> TranslationSource -> Int -> Text
Gettext.ngettext Catalog
gmo TranslationSource
orig TranslationSource
plural Int
n
        Just TranslationSource
ctxt -> Text -> m Text
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> m Text) -> Text -> m Text
forall a b. (a -> b) -> a -> b
$ Catalog
-> TranslationSource
-> TranslationSource
-> TranslationSource
-> Int
-> Text
Gettext.cngettext Catalog
gmo TranslationSource
ctxt TranslationSource
orig TranslationSource
plural Int
n

-- | Translate a string and substitute variables into it.
-- Data.Text.Format.Heavy.format syntax is used.
translateFormat :: (Localized m, MonadFail m, F.VarContainer vars)
                => TranslationSource -- ^ Original formatting string
                -> vars              -- ^ Substitution variables
                -> m T.Text
translateFormat :: TranslationSource -> vars -> m Text
translateFormat TranslationSource
orig vars
vars = do
  Text
fmtStr <- TranslationSource -> m Text
forall (m :: * -> *). Localized m => TranslationSource -> m Text
translate TranslationSource
orig
  case Text -> Either ParseError Format
parseFormat Text
fmtStr of
    Left ParseError
err -> LanguageId -> m Text
forall (m :: * -> *) a. MonadFail m => LanguageId -> m a
fail (LanguageId -> m Text) -> LanguageId -> m Text
forall a b. (a -> b) -> a -> b
$ ParseError -> LanguageId
forall a. Show a => a -> LanguageId
show ParseError
err
    Right Format
fmt -> Text -> m Text
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> m Text) -> Text -> m Text
forall a b. (a -> b) -> a -> b
$ Format -> vars -> Text
forall vars. VarContainer vars => Format -> vars -> Text
F.format Format
fmt vars
vars

-- | Short alias for @translateFormat@.
__f ::  (Localized m, MonadFail m, F.VarContainer c) => TranslationSource -> c -> m T.Text
__f :: TranslationSource -> c -> m Text
__f = TranslationSource -> c -> m Text
forall (m :: * -> *) vars.
(Localized m, MonadFail m, VarContainer vars) =>
TranslationSource -> vars -> m Text
translateFormat

-- | Translate a string, taking plural forms into account,
-- and substitute variables into it.
-- Data.Text.Format.Heavy.format syntax is used.
translateNFormat :: (Localized m, MonadFail m, F.VarContainer vars)
                 => TranslationSource -- ^ Single form of formatting string in original language
                 -> TranslationSource -- ^ Plural form of formatting string in original language
                 -> Int               -- ^ Number
                 -> vars              -- ^ Substitution variables
                 -> m T.Text
translateNFormat :: TranslationSource -> TranslationSource -> Int -> vars -> m Text
translateNFormat TranslationSource
orig TranslationSource
plural Int
n vars
vars = do
  Text
fmtStr <- TranslationSource -> TranslationSource -> Int -> m Text
forall (m :: * -> *).
Localized m =>
TranslationSource -> TranslationSource -> Int -> m Text
translateN TranslationSource
orig TranslationSource
plural Int
n
  case Text -> Either ParseError Format
parseFormat Text
fmtStr of
    Left ParseError
err -> LanguageId -> m Text
forall (m :: * -> *) a. MonadFail m => LanguageId -> m a
fail (LanguageId -> m Text) -> LanguageId -> m Text
forall a b. (a -> b) -> a -> b
$ ParseError -> LanguageId
forall a. Show a => a -> LanguageId
show ParseError
err
    Right Format
fmt -> Text -> m Text
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> m Text) -> Text -> m Text
forall a b. (a -> b) -> a -> b
$ Format -> vars -> Text
forall vars. VarContainer vars => Format -> vars -> Text
F.format Format
fmt vars
vars

-- | Short alias for @translateNFormat@.
__n :: (Localized m, MonadFail m, F.VarContainer c) => TranslationSource -> TranslationSource -> Int -> c -> m T.Text
__n :: TranslationSource -> TranslationSource -> Int -> c -> m Text
__n = TranslationSource -> TranslationSource -> Int -> c -> m Text
forall (m :: * -> *) vars.
(Localized m, MonadFail m, VarContainer vars) =>
TranslationSource -> TranslationSource -> Int -> vars -> m Text
translateNFormat