-- | This library provides basic internationalization capabilities module Text.I18N.GetText ( getText, nGetText, dGetText, dnGetText, dcGetText, dcnGetText, bindTextDomain, textDomain ) where import Foreign.C.Types import Foreign.C.String import Foreign.C.Error import Foreign.Ptr import Data.Maybe (fromMaybe) import System.Locale.SetLocale foreign import ccall unsafe "libintl.h gettext" c_gettext :: CString -> IO CString foreign import ccall unsafe "libintl.h dgettext" c_dgettext :: CString -> CString -> IO CString foreign import ccall unsafe "libintl.h dcgettext" c_dcgettext :: CString -> CString -> CInt -> IO CString foreign import ccall unsafe "libintl.h ngettext" c_ngettext :: CString -> CString -> CULong -> IO CString foreign import ccall unsafe "libintl.h dngettext" c_dngettext :: CString -> CString -> CString -> CULong -> IO CString foreign import ccall unsafe "libintl.h dcngettext" c_dcngettext :: CString -> CString -> CString -> CULong -> CInt -> IO CString foreign import ccall unsafe "libintl.h bindtextdomain" c_bindtextdomain :: CString -> CString -> IO CString foreign import ccall unsafe "libintl.h textdomain" c_textdomain :: CString -> IO CString fromCString :: CString -> IO (Maybe String) fromCString x | x == nullPtr = return Nothing | otherwise = peekCString x >>= return . Just fromCStringError :: String -> CString -> IO String fromCStringError err x | x == nullPtr = throwErrno err | otherwise = peekCString x fromCStringDefault :: String -> CString -> IO String fromCStringDefault d x = fromCString x >>= \r -> return (fromMaybe d r) fromCStringPluralDefault :: Num a => String -> String -> a -> CString -> IO String fromCStringPluralDefault def def_plural n s | n == 1 = fromCStringDefault def s | otherwise = fromCStringDefault def_plural s withCStringMaybe :: Maybe String -> (CString -> IO a) -> IO a withCStringMaybe Nothing f = f nullPtr withCStringMaybe (Just str) f = withCString str f -- |getText wraps GNU gettext function. It returns translated string for the -- input messages. If translated string not found the input string will be -- returned. -- -- The most common usage of this function is to declare function __: -- -- > __ = unsafePerformIO . getText -- -- and wrap all text strings into this function, e.g. -- -- > printHello = putStrLn (__ "Hello") -- getText :: String -> IO String getText s = withCString s $ \s' -> c_gettext s' >>= fromCStringDefault s -- |dGetText wraps GNU dgettext function. It works similar to 'getText' -- but also could take domain name. -- dGetText :: Maybe String -- ^ domain name, if 'Nothing' --- -- default domain will be used -> String -- ^ message id -> IO String -- ^ return value dGetText domainname msgid = withCStringMaybe domainname $ \dn' -> withCString msgid $ \msg' -> c_dgettext dn' msg' >>= fromCStringDefault msgid -- |dcGetText wraps GNU dcgettext function. It works similar to 'dGetText' -- but also takes category id dcGetText :: Maybe String -- ^ domain name, if 'Nothing' --- -- default domain will be used -> Category -- ^ locale facet -> String -- ^ message id -> IO String -- ^ return value dcGetText domainname cat msgid = withCStringMaybe domainname $ \dn' -> withCString msgid $ \msg' -> c_dcgettext dn' msg' (categoryToCInt cat) >>= fromCStringDefault msgid -- |nGetText wraps GNU ngettext function. It translates text string in the -- user's native language, by lookilng up the approppiate plural form of the -- message. -- nGetText :: String -- ^ msgid in singular form -> String -- ^ msgid in plural form -> Integer -- ^ number, used to choose appropriate form -> IO String -- ^ result string, by default if number is 1 than -- singular form of msgid is returned, otherwise --- -- plural nGetText msgid msgid_plural n = withCString msgid $ \msgid' -> withCString msgid_plural $ \msgid_plural' -> c_ngettext msgid' msgid_plural' (fromInteger n) >>= fromCStringPluralDefault msgid msgid_plural n -- |dnGetText wraps GNU dngettext function. It works similar to 'nGetText' but -- also takes domain name -- dnGetText :: Maybe String -- ^ domain name, if 'Nothing' --- -- default domain will be used -> String -- ^ msgid in singular form -> String -- ^ msgid in plural form -> Integer -- ^ number, used to choose appropriate form -> IO String -- ^ result string, by default if number is 1 than -- singular form of msgid is returned, otherwise --- -- plural dnGetText domainname msgid msgid_plural n = withCStringMaybe domainname $ \dn' -> withCString msgid $ \msgid' -> withCString msgid_plural $ \msgid_plural' -> c_dngettext dn' msgid' msgid_plural' (fromInteger n) >>= fromCStringPluralDefault msgid msgid_plural n -- |dcnGetText wraps GNU dcngettext function. It works similar to 'dnGetText' but -- also takes category id -- dcnGetText :: Maybe String -- ^ domain name, if 'Nothing' --- -- default domain will be used -> Category -- ^ locale facet -> String -- ^ msgid in singular form -> String -- ^ msgid in plural form -> Integer -- ^ number, used to choose appropriate form -> IO String -- ^ result string, by default if number is 1 than -- singular form of msgid is returned, otherwise --- -- plural dcnGetText domainname cat msgid msgid_plural n = withCStringMaybe domainname $ \dn' -> withCString msgid $ \msgid' -> withCString msgid_plural $ \msgid_plural' -> c_dcngettext dn' msgid' msgid_plural' (fromInteger n) (categoryToCInt cat) >>= fromCStringPluralDefault msgid msgid_plural n -- |bindTextDomain sets the base directory of the hierarchy -- containing message catalogs for a given message domain. -- -- Throws 'IOError' if fails -- bindTextDomain :: String -- ^ domain name -> Maybe String -- ^ path to the locale folder or 'Nothing' to return -- base directory for domain -> IO String -- ^ return value bindTextDomain domainname dirname = withCString domainname $ \domain -> withCStringMaybe dirname $ \dir -> c_bindtextdomain domain dir >>= fromCStringError "bindTextDomain fails" -- |textDomain sets domain for future 'getText' call -- -- Throws 'IOError' if fails -- textDomain :: Maybe String -- ^ domain name, if 'Nothing' than returns -- current domain name -> IO String -- ^ return value textDomain domainname = withCStringMaybe domainname $ \domain -> c_textdomain domain >>= fromCStringError "textDomain fails"