This is my code :
 testSplice :: C.Splice Handler
 testSplice = return $ C.yieldRuntimeText $ do
    return "中文"
And I bind it to a tag:
  splices :: Splices (C.Splice Handler)
  splices =
      "testSplice" ## testSplice
And used it on layout.tpl:
   <meta charset="UTF-8"> 
   <testSplice/>
And the output on the browser is
    -�
What have I done wrong?
Sorry for the delay, I have been busy for a while, and now I come back and I think I may not make the question specific enough @mightybyte Here is the code where the problem occurs, I hope it would make the question more specifier:
test.hs:
{-# LANGUAGE OverloadedStrings #-}
import Snap
import Heist
import qualified Heist.Compiled as C
import Data.Monoid
import Control.Monad.Trans.Either
import Data.Maybe
main :: IO ()
main = quickHttpServe site
site :: Snap ()
site = 
    route [("/", testSnap)]
testSnap :: Snap ()
testSnap = do
    hs <- liftIO $ load "template" splices
    let runtime = fromJust $ C.renderTemplate hs "test"
    builder <-liftIO  (fst runtime)
    writeBuilder builder
  where
    splices :: Splices (C.Splice IO)
    splices = 
        "testSplice" ## testSplice
load :: MonadIO n
    => FilePath
    -> Splices (C.Splice n)
    -> IO (HeistState n)
load baseDir splices = do
    tmap <- runEitherT $ do
        let t = loadTemplates baseDir
            hc = HeistConfig
                    defaultInterpretedSplices
                    defaultLoadTimeSplices
                    splices
                    mempty
                    [t]
        initHeist hc
    either (error . concat) return tmap
testSplice :: C.Splice IO
testSplice = return $ C.yieldRuntimeText $ do return "中文" 
template/test.tpl
<html>
  <head>
    <meta charset="UTF-8">
  </head>
 <body>
     <testSplice/>
 </body>
 </html>
Now I tried heist-0.13.0.2 and it works fine now, great work Daniel!