fradrive/src/Handler/Utils/I18n.hs
2020-12-11 19:56:05 +01:00

108 lines
4.7 KiB
Haskell
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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