diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,52 @@
+### shakesepare 2.0.2
+
+shakespeare-i18n supports message directories.
+
+### Hamlet 0.5.0 (August 29, 2010)
+
+* Use can use parantheses when referencing variables. This allows you to have
+functions applied to multiple arguments.
+
+* Added the hamlet' and xhamlet' quasiquoters for generating plain Html
+values.
+
+* Added runtime Hamlet support.
+
+* Added "file debug" support. This is a mode that is a drop-in replacement for
+external files compiled via template haskell. However, this mode also has a
+runtime component, in that is reads your templates at runtime, thus avoiding
+the need to a recompile for each template change. This takes a runtime hit
+obviously, so it's recommended that you switch back to the compile-time
+templates for production systems.
+
+* Added the Cassius and Julius template languages for CSS and Javascript,
+respectively. The former is white-space sensitive, whereas the latter is just
+a passthrough for raw Javascript code. The big feature in both of them is that
+they support variable interpolation just like Hamlet does.
+
+### New in Hamlet 0.4.0
+
+* Internal template parsing is now done via Parsec. This opened the doors for
+the other changes mentioned below, but also hopefully gives more meaningful
+error messages. There's absolutely no runtime performance hit for this change,
+since all parsing is done at compile time, and if there *is* any compile-time
+hit, it's too negligible to be noticed.
+
+* Attribute values can now be quoted. This allows you to embed spaces, periods
+and pounds in an attribute value. For example:
+[$hamlet|%input!type=submit!value="Add new value"|].
+
+* Space-delimited references in addition to period-delimited ones. This only
+applies to references in content, not in statements. For example, you could
+write [\$hamlet|\$foo bar baz\$|].
+
+* Dollar-sign interpolation is now polymorphic, based on the ToHtml typeclass.
+You can now do away with \$string.var\$ and simply type \$var\$. Currently, the
+ToHtml typeclass is not exposed, and it only provides instances for String and
+Html, though this is open for discussion.
+
+* Added hamletFile and xhamletFile which loads a Hamlet template from an
+external file. The file is parsed at compile time, just like a quasi-quoted
+template, and must be UTF-8 encoded. Additionally, be warned that the compiler
+won't automatically know to recompile a module if the template file gets
+changed.
diff --git a/Text/Shakespeare/I18N.hs b/Text/Shakespeare/I18N.hs
--- a/Text/Shakespeare/I18N.hs
+++ b/Text/Shakespeare/I18N.hs
@@ -62,10 +62,13 @@
     ) where
 
 import Language.Haskell.TH.Syntax
+import Control.Applicative ((<$>))
+import Control.Monad (filterM, forM)
 import Data.Text (Text, pack, unpack)
 import System.Directory
 import Data.Maybe (catMaybes)
 import Data.List (isSuffixOf, sortBy, foldl')
+import qualified Data.Map as Map
 import qualified Data.ByteString as S
 import Data.Text.Encoding (decodeUtf8)
 import Data.Char (isSpace, toLower, toUpper)
@@ -153,15 +156,16 @@
     files <- qRunIO $ getDirectoryContents folder
     (_files', contents) <- qRunIO $ fmap (unzip . catMaybes) $ mapM (loadLang folder) files
 #ifdef GHC_7_4
-    mapM_ qAddDependentFile _files'
+    mapM_ qAddDependentFile $ concat _files'
 #endif
+    let contents' = Map.toList $ Map.fromListWith (++) contents
     sdef <-
-        case lookup lang contents of
+        case lookup lang contents' of
             Nothing -> error $ "Did not find main language file: " ++ unpack lang
             Just def -> toSDefs def
-    mapM_ (checkDef sdef) $ map snd contents
+    mapM_ (checkDef sdef) $ map snd contents'
     let mname = mkName $ dt ++ postfix
-    c1 <- fmap concat $ mapM (toClauses prefix dt) contents
+    c1 <- fmap concat $ mapM (toClauses prefix dt) contents'
     c2 <- mapM (sToClause prefix dt) sdef
     c3 <- defClause
     return $
@@ -304,18 +308,50 @@
     , content :: [Content]
     }
 
-loadLang :: FilePath -> FilePath -> IO (Maybe (FilePath, (Lang, [Def])))
+(</>) :: FilePath -> FilePath -> FilePath
+path </> file = path ++ '/' : file
+
+loadLang :: FilePath -> FilePath -> IO (Maybe ([FilePath], (Lang, [Def])))
 loadLang folder file = do
-    let file' = folder ++ '/' : file
-    e <- doesFileExist file'
-    if e && ".msg" `isSuffixOf` file
+    let file' = folder </> file
+    isFile <- doesFileExist file'
+    if isFile && ".msg" `isSuffixOf` file
         then do
             let lang = pack $ reverse $ drop 4 $ reverse file
-            bs <- S.readFile file'
-            let s = unpack $ decodeUtf8 bs
-            defs <- fmap catMaybes $ mapM (parseDef . T.unpack . T.strip . T.pack) $ lines s
-            return $ Just (file', (lang, defs))
-        else return Nothing
+            defs <- loadLangFile file'
+            return $ Just ([file'], (lang, defs))
+        else do
+            isDir <- doesDirectoryExist file'
+            if isDir
+                then do
+                    let lang = pack file
+                    (files, defs) <- unzip <$> loadLangDir file'
+                    return $ Just (files, (lang, concat defs))
+                else
+                    return Nothing
+
+loadLangDir :: FilePath -> IO [(FilePath, [Def])]
+loadLangDir folder = do
+    paths <- map (folder </>) . filter (`notElem` [".", ".."]) <$> getDirectoryContents folder
+    files <- filterM doesFileExist paths
+    dirs  <- filterM doesDirectoryExist paths
+    langFiles <-
+        forM files $ \file -> do
+            if ".msg" `isSuffixOf` file
+                then do
+                  defs <- loadLangFile file
+                  return $ Just (file, defs)
+                else do
+                  return Nothing
+    langDirs <- mapM loadLangDir dirs
+    return $ catMaybes langFiles ++ concat langDirs
+
+loadLangFile :: FilePath -> IO [Def]
+loadLangFile file = do
+    bs <- S.readFile file
+    let s = unpack $ decodeUtf8 bs
+    defs <- fmap catMaybes $ mapM (parseDef . T.unpack . T.strip . T.pack) $ lines s
+    return defs
 
 parseDef :: String -> IO (Maybe Def)
 parseDef "" = return Nothing
diff --git a/shakespeare.cabal b/shakespeare.cabal
--- a/shakespeare.cabal
+++ b/shakespeare.cabal
@@ -1,5 +1,5 @@
 name:            shakespeare
-version:         2.0.1.2
+version:         2.0.2
 license:         MIT
 license-file:    LICENSE
 author:          Michael Snoyman <michael@snoyman.com>
@@ -31,6 +31,7 @@
   test/cassiuses/*.lucius
   test/hamlets/*.hamlet
   test/tmp.hs
+  ChangeLog.md
 
 library
     build-depends:   base             >= 4       && < 5
