diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,22 +1,25 @@
-
 [![Build Status](https://secure.travis-ci.org/HaskellCNOrg/snaplet-i18n.png?branch=master)](http://travis-ci.org/HaskellCNOrg/snaplet-i18n)
 
 ## snaplet-i18n
 
-1. create config below into `data/message_en.cfg`
+  1. create config below into `data/message_en.cfg`
 
 ~~~
 hello = "Hello"
 shanghai = "ShangHai"
 ~~~
 
-2. use tag in heist template
+  2. use tag in heist template
 
 ~~~
 <i18n name="shanghai"></i18n>
+<i18nSpan name="shanghai"></i18n>
+<i18n name="shanghai">
+  <a><i18nValue /></a>
+</i18n>
 ~~~
 
-**see test at test/snap.hs***
+**see example at example dir**
 
 ## Snaplet
 
@@ -27,6 +30,5 @@
 ## TODO
 
 - maybe multiple locale support at run time.
-- build failed at Hakcage
-    - because heist does not specify version of `transformers`, which will conflick with `transformer` of `mtl`
-    - Upgrade heist would be fine.
+- use getDataDir to retrieve locale msg. [snaplet tutorial](http://snapframework.com/docs/tutorials/snaplets-tutorial)
+  
diff --git a/example/snap.hs b/example/snap.hs
new file mode 100644
--- /dev/null
+++ b/example/snap.hs
@@ -0,0 +1,120 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE CPP               #-}
+{-# LANGUAGE TemplateHaskell   #-}
+{-# LANGUAGE RankNTypes        #-}
+
+
+module Main where
+
+------------------------------------------------------------------------------
+import           Control.Category
+import           Control.Monad
+import           Control.Exception (SomeException, try)
+import           Data.ByteString (ByteString)
+import           Data.Maybe
+import           Prelude hiding ((.))
+import           Snap
+import qualified Data.Configurator as CF
+import qualified Data.Configurator.Types as CF
+import           Snap.Core
+import           Snap.Http.Server
+import           Snap.Snaplet.Heist
+import           Snap.Snaplet.Config
+import           Snap.Util.FileServe
+import           System.IO
+import qualified Data.ByteString.Char8 as BS
+import qualified Data.ByteString.Lazy as LBS
+import qualified Data.Text as T
+import qualified Data.Text.Encoding as T
+import qualified Text.XmlHtml as X
+import           Text.Templating.Heist
+import           Text.XmlHtml hiding (render)
+
+#ifdef DEVELOPMENT
+import           Snap.Loader.Dynamic
+#else
+import           Snap.Loader.Static
+#endif
+
+import Snap.Snaplet.I18N
+
+------------------------------------------------------------------------------
+
+data App = App
+    { _heist   :: Snaplet (Heist App)
+    , _i18n   :: Snaplet I18NSnaplet
+    }
+
+makeLens ''App
+
+instance HasHeist App where
+    heistLens = subSnaplet heist
+
+instance HasI18N App where
+   i18nLens = i18n
+
+type AppHandler = Handler App App
+
+------------------------------------------------------------------------------
+
+decodedParam :: MonadSnap m => ByteString -> m ByteString
+decodedParam p = fromMaybe "" <$> getParam p
+
+------------------------------------------------------------------------------
+
+
+testSplice :: Splice AppHandler
+testSplice = do
+    locale <- liftIO $ getDefaultLocale
+    --liftIO $ print locale
+    textSplice $ T.pack "test"
+
+index :: AppHandler ()
+index = do
+     heistLocal (bindSplice "testSplice" testSplice) $ render "index"
+
+-- | wrap to element span
+--       
+
+------------------------------------------------------------------------------
+
+-- | The application's routes.
+routes :: [(ByteString, Handler App App ())]
+routes  = [ ("/", index)
+          , ("", with heist heistServe)
+          ]
+
+-- | The application initializer.
+app :: SnapletInit App App
+app = makeSnaplet "app" "An snaplet example application." Nothing $ do
+    h <- nestSnaplet "heist" heist $ heistInit "templates"
+    locale <- liftIO $ getDefaultLocale
+    i <- nestSnaplet "i18n" i18n $ initI18NSnaplet (Just "zh_CN")
+    addRoutes routes
+    return $ App h i
+
+getDefaultLocale :: IO (Maybe String)
+--getDefaultLocale = return $ Just "zh_CN"
+getDefaultLocale = liftM getLocale getConf
+
+------------------------------------------------------------------------------
+
+main :: IO ()
+main = do
+    (conf, site, cleanup) <- $(loadSnapTH [| getConf |]
+                                          'getActions
+                                          ["heist/templates"])
+
+    _ <- try $ httpServe conf $ site :: IO (Either SomeException ())
+    cleanup
+
+getConf :: IO (Config Snap AppConfig)
+getConf = commandLineAppConfig defaultConfig
+
+getActions :: Config Snap AppConfig -> IO (Snap (), IO ())
+getActions conf = do
+    (msgs, site, cleanup) <- runSnaplet
+        (appEnvironment =<< getOther conf) app
+    hPutStrLn stderr $ T.unpack msgs
+    return (site, cleanup)
+
diff --git a/example/snaplets/heist/templates/index.tpl b/example/snaplets/heist/templates/index.tpl
new file mode 100644
--- /dev/null
+++ b/example/snaplets/heist/templates/index.tpl
@@ -0,0 +1,30 @@
+<!DOCTYPE html>    
+<html>
+<head>
+
+<style>
+  p > span { display: block; }
+</style>
+
+</head>
+
+<body>
+
+<h2>Test I18N</h2>
+
+<testSplice />
+
+<p>
+<i18n name="shanghai"></i18n>
+<i18nSpan name="hello" class="test"></i18nSpan>
+<i18n name="invalidekey"></i18n>
+</p>
+ 
+ <p>
+    <i18n name="shanghai">
+        <input type="submit" value="${i18nValue}" />
+    </i18n>
+</p>
+
+</body>
+</html>
diff --git a/example/snaplets/i18n/message-en_US.cfg b/example/snaplets/i18n/message-en_US.cfg
new file mode 100644
--- /dev/null
+++ b/example/snaplets/i18n/message-en_US.cfg
@@ -0,0 +1,2 @@
+hello = "Hello"
+shanghai = "ShangHai"
diff --git a/example/snaplets/i18n/message-zh_CN.cfg b/example/snaplets/i18n/message-zh_CN.cfg
new file mode 100644
--- /dev/null
+++ b/example/snaplets/i18n/message-zh_CN.cfg
@@ -0,0 +1,2 @@
+hello = "你好"
+shanghai = "上海"
diff --git a/snaplet-i18n.cabal b/snaplet-i18n.cabal
--- a/snaplet-i18n.cabal
+++ b/snaplet-i18n.cabal
@@ -3,7 +3,7 @@
 -- http://www.haskell.org/cabal/release/cabal-latest/doc/users-guide/authors.html#pkg-descr.
 -- The name of the package.
 Name:                snaplet-i18n
-Version:             0.0.3
+Version:             0.0.3.1
 Description:         A light weight i18n snaplet.
 Synopsis:            snaplet-i18n
 Homepage:            https://github.com/HaskellCNOrg/snaplet-i18n
@@ -19,13 +19,13 @@
 
 Extra-source-files:  
   README.md
-  test/snap.hs
-  test/snaplets/heist/templates/*.tpl
-  test/data/*.cfg
+  example/snap.hs
+  example/snaplets/heist/templates/*.tpl
+  example/snaplets/i18n/*.cfg
 
 Source-Repository head
   Type:     git
-  Location: https://github.com/HaskellCNOrg/snaplet-i18n
+  Location: git://github.com/HaskellCNOrg/snaplet-i18n.git
 
 
 Library
@@ -33,12 +33,16 @@
   Exposed-modules:     
       Snap.Snaplet.I18N
 
+  Other-modules: Paths_snaplet_i18n
+
   Build-Depends:    
       base               >= 4     && < 5,
-      snap               >= 0.9.1 && < 0.10,
-      snap-core          == 0.9.0,
-      xmlhtml            == 0.2.0,
-      heist              == 0.8.1,
+      snap               == 0.9.*,
+      snap-core          == 0.9.*,
+      snap-loader-dynamic == 0.9.*,
+      snap-loader-static == 0.9.*,
+      xmlhtml            >= 0.2,
+      heist              >= 0.8.1 && < 0.9,
       bytestring         >= 0.9   && < 1.0,
       data-lens-template >= 2.1   && < 2.2,
       data-lens          >= 2.0   && < 2.1,
diff --git a/src/Snap/Snaplet/I18N.hs b/src/Snap/Snaplet/I18N.hs
--- a/src/Snap/Snaplet/I18N.hs
+++ b/src/Snap/Snaplet/I18N.hs
@@ -1,8 +1,7 @@
-{-# LANGUAGE OverloadedStrings, FlexibleInstances, MultiParamTypeClasses #-}
-{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE OverloadedStrings #-}
 
 
-module Snap.Snaplet.I18N 
+module Snap.Snaplet.I18N
   ( I18NSnaplet
   , HasI18N (..)
   , I18NMessage (..)
@@ -12,22 +11,24 @@
   ) where
 
 import           Control.Monad
+import qualified Data.Configurator       as Config
+import qualified Data.Configurator.Types as Config
 import           Data.Lens.Common
 import           Data.Maybe
-import           System.Directory
+import qualified Data.Text               as T
 import           System.FilePath.Posix
 import           Text.Templating.Heist
-import           Text.XmlHtml hiding (render)
-import qualified Data.Configurator as Config
-import qualified Data.Configurator.Types as Config
-import qualified Data.Text as T
-import qualified Text.XmlHtml as X
+import           Text.XmlHtml            hiding (render)
+import qualified Text.XmlHtml            as X
 
-import Snap
-import Snap.Snaplet.Heist
+import Paths_snaplet_i18n
+import           Snap
+import           Snap.Snaplet.Heist
 
 
--------------------------------------------------------
+----------------------------------------------------------------------
+--    Types
+----------------------------------------------------------------------
 
 type Locale      = String
 type MessageFile = String
@@ -36,87 +37,95 @@
 defaultLocale = "en_US"
 
 -- | ?? could be multiple message files
--- 
+--
 defaultMessageFilePrefix :: MessageFile
-defaultMessageFilePrefix = "data/message"
+defaultMessageFilePrefix = "message"
 
-data I18NConfig  = I18NConfig { _getLocale      :: Locale       -- ^ locale, default "en"
-                              , _getMessageFile :: MessageFile  -- ^ message file name, default to "message"
+data I18NConfig  = I18NConfig { _getLocale      :: Locale
+                                -- ^ locale, default "en"
+                              , _getMessageFile :: MessageFile
+                                -- ^ message file name, default to "message"
                               } deriving (Show)
 
--- | A simple mapping to hold i18n messages
--- 
-data I18NMessage = I18NMessage Config.Config
+-- | Message content.
+--
+newtype I18NMessage = I18NMessage Config.Config
 
 -- | data type
--- 
+--
 data I18NSnaplet = I18NSnaplet
                     { _getI18NConfig  :: I18NConfig
                     , _getI18NMessage :: I18NMessage
-                    } 
+                    }
 
 
 -- | Compose App with a I18N Snaplet.
--- 
+--
 class HasI18N b where
   i18nLens :: Lens b (Snaplet I18NSnaplet)
-  
+
 -- | Util functions
--- 
+--
 getI18NSnaplet :: HasI18N b => Handler b b I18NSnaplet
 getI18NSnaplet = with i18nLens Snap.get
 
 -- | Get the @I18NMessage@
--- 
+--
 getI18NMessages :: HasI18N b => Handler b b I18NMessage
 getI18NMessages = liftM _getI18NMessage getI18NSnaplet
 
 -- | Look up a value in, usuallly Handler Monad
--- 
+--
 lookupI18NValue :: HasI18N b => T.Text -> Handler b b T.Text
 lookupI18NValue key = do
                       (I18NMessage msg) <- getI18NMessages
                       liftIO $ Config.lookupDefault "Error: no value found." msg key
 
--------------------------------------------------------
+----------------------------------------------------------------------
+--    Init Snaplet
+----------------------------------------------------------------------
 
 -- | Init this I18NSnaplet snaplet.
--- 
+--
 initI18NSnaplet :: (HasHeist b, HasI18N b)
                 => Maybe Locale              -- ^ Locale, default to @defaultLocale@
                 -> SnapletInit b I18NSnaplet
-initI18NSnaplet l = makeSnaplet "I18NSnaplet" "" Nothing $ do
+initI18NSnaplet l = makeSnaplet "i18n" description datadir $ do
     let i18nConfig = I18NConfig (fromMaybe defaultLocale l) defaultMessageFilePrefix
-    config <- liftIO $ readMessageFile i18nConfig
+    fp <- getSnapletFilePath
+    msg <- liftIO $ readMessageFile fp i18nConfig
     addDefaultSplices
-    return $ I18NSnaplet i18nConfig $ I18NMessage config
+    return $ I18NSnaplet i18nConfig msg
   where addDefaultSplices = addSplices [ ("i18n", liftHeist i18nSplice)
                                        , ("i18nSpan", liftHeist i18nSpanSplice)]
+        -- config dir for snaplet
+        datadir = Just $ liftM (++ "/resources") getDataDir
+        description = "light weight i18n snaplet"
 
 -------------------------------------------------------
--- 
+--
 
 -- | Load file
 --   server will not be able to start up if dir doesnt exists.
 --   Thus, no additional validation check so far.
--- 
-readMessageFile :: I18NConfig -> IO Config.Config
-readMessageFile config = do
-    base     <- getCurrentDirectory
+--
+readMessageFile :: FilePath -> I18NConfig -> IO I18NMessage
+readMessageFile base config = do
     let fullname = base </> file config
-    Config.load [Config.Required fullname]
-  where 
+    fmap I18NMessage (Config.load [Config.Required fullname])
+  where
     -- file fullname will be like message-en_US.cfg
-    -- FIXME: Maybe replace "-" with "_" in locale for typo
+    -- FIXME: Maybe replace "-" with "_" in locale in case typo
     file c = _getMessageFile c ++ "-" ++ _getLocale c ++ ".cfg"
 
 
--------------------------------------------------------
-
+----------------------------------------------------------------------
+--    Splices
+----------------------------------------------------------------------
 
 -- | element attribute used for looking up i18n value.
 --   e.g. <i18n name="hello" />
--- 
+--
 i18nSpliceAttr :: T.Text
 i18nSpliceAttr = "name"
 
@@ -124,8 +133,11 @@
 -- | Splices just wrap value fonud at l10n message.
 --   When it is used for wrap around other elements, a.k.a children is not empty,
 --   binding `i18nValue`.
+--   e.g.
+--       <i18n name="hello" />
+--       <i18n name="hello"><p><i18nValue/></p></i18n>
 --
--- FIXME: Turns out that it is not possible to fail at compilation if value is Nothing but runtime. 
+-- FIXME: Turns out that it is not possible to fail at compilation if value is Nothing but runtime.
 i18nSplice :: HasI18N b => Splice (Handler b b)
 i18nSplice = do
     input <- getParamNode
@@ -135,7 +147,7 @@
       _  -> runChildrenWithText [("i18nValue", value)]
 
 -- | Splices. use 'span' html element wrap result.
--- 
+--
 i18nSpanSplice :: HasI18N b => Splice (Handler b b)
 i18nSpanSplice = do
     input <- getParamNode
@@ -143,8 +155,10 @@
     return [X.Element "span" (elementAttrs input) [X.TextNode value]]
 
 -- | Look up 'name' attribute value.
--- 
+--
 getNameAttr :: Node -> T.Text
 getNameAttr n = case getAttribute i18nSpliceAttr n of
                   Just x -> x
-                  _      -> "" 
+                  _      -> ""
+
+----------------------------------------------------------------------
diff --git a/test/data/message-en_US.cfg b/test/data/message-en_US.cfg
deleted file mode 100644
--- a/test/data/message-en_US.cfg
+++ /dev/null
@@ -1,2 +0,0 @@
-hello = "Hello"
-shanghai = "ShangHai"
diff --git a/test/data/message-zh_CN.cfg b/test/data/message-zh_CN.cfg
deleted file mode 100644
--- a/test/data/message-zh_CN.cfg
+++ /dev/null
@@ -1,2 +0,0 @@
-hello = "你好"
-shanghai = "上海"
diff --git a/test/snap.hs b/test/snap.hs
deleted file mode 100644
--- a/test/snap.hs
+++ /dev/null
@@ -1,121 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE CPP               #-}
-{-# LANGUAGE TemplateHaskell   #-}
-{-# LANGUAGE RankNTypes        #-}
-
-
-module Main where
-
-------------------------------------------------------------------------------
-import           Control.Category
-import           Control.Monad
-import           Control.Exception (SomeException, try)
-import           Data.ByteString (ByteString)
-import           Data.Maybe
-import           Network.HTTP.Conduit (responseBody)
-import           Network.HTTP.Types (renderSimpleQuery)
-import           Prelude hiding ((.))
-import           Snap
-import qualified Data.Configurator as CF
-import qualified Data.Configurator.Types as CF
-import           Snap.Core
-import           Snap.Http.Server
-import           Snap.Snaplet.Heist
-import           Snap.Snaplet.OAuth
-import           Snap.Util.FileServe
-import           System.IO
-import qualified Data.ByteString.Char8 as BS
-import qualified Data.ByteString.Lazy as LBS
-import qualified Data.Text as T
-import qualified Data.Text.Encoding as T
-import qualified Text.XmlHtml as X
-import           Text.Templating.Heist
-import           Text.XmlHtml hiding (render)
-
-#ifdef DEVELOPMENT
-import           Snap.Loader.Devel
-#else
-import           Snap.Loader.Prod
-#endif
-
-import Snap.Snaplet.I18N
-
-------------------------------------------------------------------------------
-
-data App = App
-    { _heist   :: Snaplet (Heist App)
-    , _i18n   :: Snaplet I18NSnaplet
-    }
-
-makeLens ''App
-
-instance HasHeist App where
-    heistLens = subSnaplet heist
-
-instance HasI18N App where
-   i18nLens = i18n
-
-type AppHandler = Handler App App
-
-------------------------------------------------------------------------------
-
-decodedParam :: MonadSnap m => ByteString -> m ByteString
-decodedParam p = fromMaybe "" <$> getParam p
-
-------------------------------------------------------------------------------
-
-
-testSplice :: Splice AppHandler
-testSplice = do
-    locale <- liftIO $ getDefaultLocale
-    liftIO $ print locale
-    textSplice $ T.pack "test"
-
-index :: AppHandler ()
-index = do
-     heistLocal (bindSplice "testSplice" testSplice) $ render "index"
-
--- | wrap to element span
---       
-
-------------------------------------------------------------------------------
-
--- | The application's routes.
-routes :: [(ByteString, Handler App App ())]
-routes  = [ ("/", index)
-          , ("", with heist heistServe)
-          ]
-
--- | The application initializer.
-app :: SnapletInit App App
-app = makeSnaplet "app" "An snaplet example application." Nothing $ do
-    h <- nestSnaplet "heist" heist $ heistInit "templates"
-    locale <- liftIO $ getDefaultLocale
-    i <- nestSnaplet "i18n" i18n $ initI18NSnaplet (Just "zh_CN")
-    addRoutes routes
-    return $ App h i
-
-getDefaultLocale :: IO (Maybe String)
---getDefaultLocale = return $ Just "zh_CN"
-getDefaultLocale = liftM getLocale getConf
-
-------------------------------------------------------------------------------
-
-main :: IO ()
-main = do
-    (conf, site, cleanup) <- $(loadSnapTH [| getConf |]
-                                          'getActions
-                                          ["heist/templates"])
-
-    _ <- try $ httpServe conf $ site :: IO (Either SomeException ())
-    cleanup
-
-getConf :: IO (Config Snap ())
-getConf = commandLineConfig defaultConfig
-
-getActions :: Config Snap () -> IO (Snap (), IO ())
-getActions _ = do
-    (msgs, site, cleanup) <- runSnaplet app
-    hPutStrLn stderr $ T.unpack msgs
-    return (site, cleanup)
-
diff --git a/test/snaplets/heist/templates/index.tpl b/test/snaplets/heist/templates/index.tpl
deleted file mode 100644
--- a/test/snaplets/heist/templates/index.tpl
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html>    
-<html>
-<head>
-
-<style>
-  p > span { display: block; }
-</style>
-
-</head>
-
-<body>
-
-<h2>Test I18N</h2>
-
-<testSplice />
-
-<p>
-<i18n name="shanghai"></i18n>
-<i18nSpan name="hello" class="test"></i18nSpan>
-<i18n name="invalidekey"></i18n>
-</p>
- 
- <p>
-    <i18n name="shanghai">
-        <input type="submit" value="${i18nValue}" />
-    </i18n>
-</p>
-
-</body>
-</html>
