我正在尝试将即将出版的“Play for Scala”一书的第2章中的教程代码从Scala转换为Haskell(使用Yesod)。我试图将defaultLayout
“国际化”时遇到错误。我(故意)不使用脚手架的Yesod网站,因为我试图理解内部。这是我的代码:
{-# LANGUAGE FlexibleInstances
, MultiParamTypeClasses
, OverloadedStrings
, QuasiQuotes
, TemplateHaskell
, TypeFamilies #-}
module Main where
import Text.Hamlet (ihamlet)
import Yesod
import Yesod.Static
staticFiles "static"
data PlayTutorial = PlayTutorial
{ getStatic :: Static
}
mkMessage "PlayTutorial" "messages" "en"
mkYesod "PlayTutorial" [parseRoutes|
/ RootR GET
/static StaticR Static getStatic
|]
instance Yesod PlayTutorial where
defaultLayout contents = do
PageContent title headTags bodyTags <- widgetToPageContent $ do
addStylesheet $ StaticR stylesheets_bootstrap_css
addStylesheet $ StaticR stylesheets_main_css
contents
ihamletToRepHtml [ihamlet|
$doctype 5
<html>
<head>
<title>#{title}
^{headTags}
<body>
<div ."screenshot">
<div ."navbar navbar-fixed-top">
<div ."container">
<a ."brand" href=@{RootR}>
_{MsgApplicationName}
<div ."container">
^{bodyTags}
|]
getRootR :: Handler RepHtml
getRootR = defaultLayout [whamlet|Hello, World!|]
main :: IO ()
main = do
static@(Static settings) <- static "static"
warp 8080 $ PlayTutorial static
我尝试使用runhaskell
构建或运行它的错误是
src/Main.hs:34:31:
Couldn't match type `Text.Blaze.Internal.MarkupM ()'
with `[(Data.Text.Internal.Text, Data.Text.Internal.Text)]
-> Data.Text.Internal.Text'
Expected type: Text.Hamlet.Render (Route PlayTutorial)
Actual type: Text.Hamlet.Translate (Route PlayTutorial)
In the first argument of `headTags', namely `_mrender_a7j2'
In a stmt of a 'do' block: headTags _mrender_a7j2 _urender_a7j1
In the expression:
do { id
((Text.Blaze.Internal.preEscapedText . Data.Text.pack)
"<!DOCTYPE html>\
\<html><head><title>");
id (toHtml title);
id
((Text.Blaze.Internal.preEscapedText . Data.Text.pack) "</title>");
headTags _mrender_a7j2 _urender_a7j1;
.... }
ihamlet
代码发生错误。
我认为headTags
是HtmlUrl
。我还认为我需要将其转换为HtmlUrlI18n
,但无法弄清楚如何。
我可以做同样的事情(定义{{1}})作为一个小部件(使用defaultLayout
)然后使用whamlet
将其转换为PageContent
,然后转换为{{{ 1}}(不确定如何),而不是使用widgetToPageContent
?这会解决i18n问题吗?
我已经尝试了谷歌搜索几个小时,但找不到任何广泛的例子,用i18n创建一个新的RepHtml
。
答案 0 :(得分:1)
在Google Groups与Michael Snoyman(Yesod框架的创始人和首席开发人员)进行简短讨论后,我相信我现在理解了这个问题,更重要的是解决了这个问题。
headTags
已
type HtmlUrl url = Render url -> Html
和^{}
中的ihamlet
插值需要
type HtmlUrlI18n msg url = Translate msg -> Render url -> Html
所以我们必须从一个转换为另一个。
Prelude中的函数const
定义为
const :: a -> b -> a
const x _ = x
因此,如果我们在const headTags
插值中嵌入^{}
,那就可以了。
表达式const headTags
是一个 currying 来自一个函数,该函数需要两个参数,这个参数需要一个参数。然后忽略第二个参数。插值调用单参数函数并传入Translate msg
,忽略该函数,留下类型为Render url -> Html
的函数,这正是我们传递给headTags
的函数。
同样的逻辑适用于bodyTags
。
谢谢,迈克尔。