module Handler.Utils.I18n ( i18nWidgetFile , i18nWidgetFiles , i18nMessage , authorizedI18n, authenticationRequiredI18n, unauthorizedI18n , _AuthorizedI18n, _AuthenticationRequiredI18n, _UnauthorizedI18n , pattern UnauthorizedI18n, pattern AuthorizedI18n, pattern AuthenticationRequiredI18n , module Utils.I18n ) where import Import.NoFoundation import Foundation.Type import Utils.I18n import Language.Haskell.TH import Language.Haskell.TH.Syntax (qRunIO) import qualified Data.List as List import qualified Data.List.NonEmpty as NonEmpty import qualified Data.Map as Map import System.Directory (listDirectory) -- | Add language dependent template files -- -- For large files which are translated as a whole. -- -- Argument musst be a directory under @/templates@, -- which contains a file for each language, -- eg. @imprint@ for choosing between -- @/templates/imprint/de.hamlet@, @/templates/imprint/de-at.hamlet@, -- and @/templates/imprint/en.hamlet@ -- -- Dependency detection cannot work properly (no `addDependentFile`-equivalent -- for directories) -- @$ stack clean@ is required so new translations show up i18nWidgetFile :: FilePath -> Q Exp i18nWidgetFile basename = do -- Construct list of available translations (@de@, @en@, ...) at compile time let i18nDirectory = "templates" "i18n" basename availableFiles <- qRunIO $ listDirectory i18nDirectory let availableTranslations = sortWith (NTop . flip List.elemIndex (NonEmpty.toList appLanguages)) . List.nub $ pack . takeBaseName <$> availableFiles availableTranslations' <- maybe (fail $ "‘" <> i18nDirectory <> "’ is empty") return $ NonEmpty.nonEmpty availableTranslations -- Dispatch to correct language (depending on user settings via `selectLanguage`) at run time ws <- newName "ws" -- Name for dispatch function letE [ funD ws $ [ clause [litP $ stringL l] (normalB . widgetFile $ "i18n" basename l) [] | l <- unpack <$> NonEmpty.toList availableTranslations' -- One function definition for every available language ] ++ [ clause [wildP] (normalB [e| error "selectLanguage returned an invalid translation" |]) [] ] -- Fallback mostly there so compiler does not complain about non-exhaustive pattern match ] [e|selectLanguage availableTranslations' >>= $(varE ws)|] i18nWidgetFiles :: FilePath -> Q Exp i18nWidgetFiles basename = do availableTranslations' <- i18nWidgetFilesAvailable' basename -- Dispatch to correct language (depending on user settings via `selectLanguage`) at run time ws <- newName "ws" -- Name for dispatch function letE [ funD ws $ [ clause [litP $ stringL kind, litP $ stringL l] (normalB [e|$(widgetFile $ "i18n" basename kind <.> l) :: WidgetFor UniWorX ()|]) [] | (unpack -> kind, ls) <- Map.toList availableTranslations' , l <- unpack <$> NonEmpty.toList ls ] ++ [ clause [wildP, wildP] (normalB [e| error "selectLanguage returned an invalid translation" |]) [] ] -- Fallback mostly there so compiler does not complain about non-exhaustive pattern match ] [e|imap (\kind ls -> selectLanguage ls >>= $(varE ws) kind) availableTranslations'|] i18nMessage :: ( MonadHandler m , HandlerSite m ~ UniWorX , RenderMessage UniWorX msg ) => msg -> m I18nText i18nMessage = i18nMessageFor $ toList appLanguages unauthorizedI18n :: ( MonadHandler m , HandlerSite m ~ UniWorX , RenderMessage UniWorX msg ) => msg -> m I18nAuthResult unauthorizedI18n = fmap (fmap Unauthorized) . i18nMessage _UnauthorizedI18n :: Prism' I18nAuthResult I18nText _UnauthorizedI18n = prism' (fmap Unauthorized) . traverse $ preview _Unauthorized _AuthorizedI18n :: Prism' I18nAuthResult () _AuthorizedI18n = prism' (\() -> authorizedI18n) . traverse_ $ preview _Authorized _AuthenticationRequiredI18n :: Prism' I18nAuthResult () _AuthenticationRequiredI18n = prism' (\() -> authenticationRequiredI18n) . traverse_ $ preview _AuthenticationRequired authorizedI18n, authenticationRequiredI18n :: I18nAuthResult authorizedI18n = opoint Authorized authenticationRequiredI18n = opoint Authorized pattern UnauthorizedI18n :: I18nText -> I18nAuthResult pattern UnauthorizedI18n x <- (preview _UnauthorizedI18n -> Just x) where UnauthorizedI18n = review _UnauthorizedI18n pattern AuthorizedI18n :: I18nAuthResult pattern AuthorizedI18n <- (preview _AuthorizedI18n -> Just ()) where AuthorizedI18n = authorizedI18n pattern AuthenticationRequiredI18n :: I18nAuthResult pattern AuthenticationRequiredI18n <- (preview _AuthenticationRequiredI18n -> Just ()) where AuthenticationRequiredI18n = authenticationRequiredI18n