{-# LANGUAGE FlexibleInstances, TypeSynonymInstances #-} ----------------------------------------------------------------------------- -- | -- Module : Text.I18n -- Copyright : (c) Eugene Grigoriev, 2008 -- License : BSD3 -- -- Maintainer : eugene.grigoriev@gmail.com -- Stability : experimental -- Portability : portable -- -- Internationalization support for Haskell. -- Use Text.I18n.Po module. -- -- Plural forms are not yet implemented. -- ----------------------------------------------------------------------------- module Text.I18n ( -- * Type Declarations Msgid(..), Msgstr, Locale(..), Context, I18n, L10n, -- * Internationalization Monad Functions gettext, localize, withContext, withLocale ) where import Control.Monad.Reader import Control.Monad.Trans import Control.Monad.Identity import Data.Maybe import Text.I18n.Printf import qualified Data.Map as Map ------------------------------------------------------------------------------- -- Type declarations ------------------------------------------------------------------------------- newtype Msgid = Msgid String deriving (Show,Eq,Ord) type Msgstr = String newtype Locale = Locale String deriving (Show,Eq,Ord) type Context = String -- | The Internationalization monad built using monad transformers. type I18n a = ReaderT (Locale, L10n, Maybe Context) Identity a -- | The Localization structure. type L10n = Map.Map Locale (Map.Map (Maybe Context) (Map.Map Msgid [Msgstr])) instance PrintfType (I18n String) where spr fmts args = return (uprintf fmts (reverse args)) ------------------------------------------------------------------------------- -- I18N Monad functions ------------------------------------------------------------------------------- {-| The top level localization function. > import Text.I18n.Po > import Prelude hiding (putStr,putStrLn) > > main = do > (l10n,errors) <- getL10n "dir/to/po" -- directory containing PO files > putStrLn $ localize l10n (Locale "en") (example "Joe") -} localize :: L10n -- ^ Structure containing localization data -> Locale -- ^ Locale to use -> I18n a -- ^ Inernationalized expression -> a -- ^ Localized expression localize l10n loc expression = runIdentity $ runReaderT expression (loc,l10n,Nothing) {-| The heart of I18n monad. Based on 'Text.Printf.printf'. > example :: String -> I18n String > example name = do > hello <- gettext "Hello, %s!" > return (hello name) -} gettext :: PrintfType a => String -> I18n a gettext msgid = do (loc, l10n, ctxt) <- ask case localizeMsgid l10n loc ctxt (Msgid msgid) of Just msgstr -> return (printf msgstr) Nothing -> case ctxt of Just _ -> withContext Nothing (gettext msgid) Nothing -> return (printf msgid) {-| Sets a local 'Context' for an internationalized expression. If there is no translation, then no context version is tried. > example2 :: String -> I18n String > example2 = withContext (Just "test") . example -} withContext :: Maybe Context -- ^ Context to use -> I18n a -- ^ Internationalized expression -> I18n a -- ^ New internationalized expression withContext ctxt expression = do (lang, l10n, _) <- ask local (const (lang, l10n, ctxt)) expression {-| Sets a local 'Locale' for an internationalized expression. > example3 :: String -> I18n String > example3 = withLocale (Locale "ru") . example2 -} withLocale :: Locale -- ^ Locale to use -> I18n a -- ^ Internationalized expression -> I18n a -- ^ New internationalized expression. -- Note: while this expression is localy localized already, it is to be a -- part of another internationalized expression. -- Therefore the final type is internationalized. withLocale loc expression = do (_, l10n, ctxt) <- ask local (const (loc, l10n, ctxt)) expression localizeMsgid :: L10n -> Locale -> Maybe Context -> Msgid -> Maybe String localizeMsgid l10n loc ctxt msgid = do local <- Map.lookup loc l10n contextual <- Map.lookup ctxt local msgstrs <- Map.lookup msgid contextual listToMaybe msgstrs