packages feed

gettext-th 0.1.0.3 → 0.2.0.0

raw patch · 3 files changed

+59/−26 lines, 3 filesdep +containersPVP ok

version bump matches the API change (PVP)

Dependencies added: containers

API changes (from Hackage documentation)

Files

CHANGELOG.md view
@@ -1,5 +1,10 @@ # Revision history for gettext-th +## 0.2.0.0++* duplicates are filtered out+* utf8 support+ ## 0.1.0.0 -- YYYY-mm-dd  * First version. Released on an unsuspecting world.
gettext-th.cabal view
@@ -1,6 +1,6 @@ cabal-version:      2.4 name:               gettext-th-version:            0.1.0.3+version:            0.2.0.0  synopsis: gettext-th can internationalise a haskell program without runtime dependencies @@ -17,7 +17,7 @@  -- A copyright notice. -- copyright:-category: i18n Text+category: i18n, Text extra-source-files: CHANGELOG.md, README.md  library@@ -30,6 +30,7 @@     -- other-extensions:     build-depends:    base  >= 4 && < 5                     , bytestring+                    , containers                     , directory                     , filepath                     , haskell-gettext
src/I18N/Gettext/TH.hs view
@@ -4,6 +4,8 @@  import Language.Haskell.TH import Language.Haskell.TH.Quote+import Language.Haskell.TH.Syntax+ import Instances.TH.Lift() import System.IO.Unsafe import System.Directory@@ -12,6 +14,8 @@ import Data.Bifunctor import Data.Char (isSpace) import Data.List+import Data.Set (Set)+import qualified Data.Set as S  import qualified Data.ByteString as B import qualified Data.Text as T@@ -21,11 +25,11 @@ import qualified Data.Gettext as G import Data.Gettext (Catalog, loadCatalog) import System.FilePath.Posix-+import System.IO -{-# NOINLINE firstCall #-}-firstCall :: IORef Bool-firstCall = unsafePerformIO $ newIORef True+{-# NOINLINE knownMsgs #-}+knownMsgs :: IORef (Set String)+knownMsgs = unsafePerformIO $ newIORef S.empty  potFileName :: FilePath potFileName = "po/messages.pot"@@ -61,57 +65,80 @@   "\"Language-Team: LANGUAGE <LL@li.org>\\n\"",   "\"Language: \\n\"",   "\"MIME-Version: 1.0\\n\"",-  "\"Content-Type: text/plain; charset=CHARSET\\n\"",+  "\"Content-Type: text/plain; charset=utf-8\\n\"",   "\"Content-Transfer-Encoding: 8bit\\n\""   ] ++++writeFileUtf8 :: FilePath -> IOMode -> String -> IO ()+writeFileUtf8 f mode txt = withFile f mode (\ hdl -> do+                                               hSetEncoding hdl utf8+                                               hPutStr hdl txt)  + createPotFile :: Q () createPotFile = do-  runIO $ do-    f <- readIORef firstCall-    when f $ do-      writeIORef firstCall False+  fn <- runIO $ do       createDirectoryIfMissing True (takeDirectory potFileName)       potE <- doesFileExist potFileName           when potE $         renameFile potFileName (potFileName ++ ".bak") -      writeFile potFileName header-    --addDependentFile poFileName+      writeFileUtf8 potFileName WriteMode header+      makeAbsolute moFileName+  addDependentFile fn   packStr :: String -> B.ByteString packStr = encodeUtf8 . T.pack - gettextQ  :: String -> Q Exp gettextQ str = do-  createPotFile-  loc <- location-  runIO $ appendFile potFileName $ unlines $ poEntry loc str+  kmsgs <- runIO $ do+     kmsgs <- readIORef knownMsgs+     writeIORef knownMsgs (S.insert str kmsgs)+     return kmsgs++  when (S.null kmsgs) createPotFile+  when (str `S.notMember` kmsgs) $ do+    loc <- location+    runIO $ writeFileUtf8 potFileName AppendMode $ unlines $ poEntry loc str   let trans = TL.toStrict $ G.gettext catalog (packStr str)   [| trans |] +quote :: String -> String+quote s =  '"':escape s+  where escape [] = "\""+        escape ('"':s') = '\\':'"':escape s'+        escape ('\n':s') = '\\':'n':escape s'+        escape ('\r':s') = escape s'+        escape (c:s') = c:escape s'+          poEntry :: Loc -> String -> [String] poEntry loc msg = [       "",       "#: " ++ (loc_filename loc) ++ ":0", -- TODO line nr or char pos-      "msgid " ++ show msg,-      "msgstr " ++ show msg +      "msgid " ++ quote msg,+      "msgstr " ++ quote msg        ]  gettextsDecs  :: String -> Q [Dec] gettextsDecs str = do-  createPotFile-  loc <- location   let msgs = map splitKeyMsg $ parseLines str  -  runIO $ appendFile potFileName $ unlines $ concat [ poEntry loc msg | (_, msg) <- msgs ]    +  kmsgs <- runIO $ do+     kmsgs <- readIORef knownMsgs+     writeIORef knownMsgs (foldl' (\ acc (_, msg) -> msg `S.insert` acc) kmsgs msgs)+     return kmsgs+  when (S.null kmsgs) createPotFile+  loc <- location +  runIO $ writeFileUtf8 potFileName AppendMode $ unlines $ concat [ poEntry loc msg | (_, msg) <- msgs, msg `S.notMember` kmsgs ]    +   forM msgs $ \ (key, msg) ->               let trans = TL.toStrict $ G.gettext catalog (packStr msg) in do-                 e <-  [| trans |]-                 return $ FunD (mkName key) [Clause [] (NormalB e) []]+                 funD (mkName key) [clause [] (normalB [| trans |]) []]                             @@ -132,7 +159,7 @@          join acc cl = (intercalate "\n" $ reverse cl):acc  splitKeyMsg :: String -> (String, String)        -splitKeyMsg line =  bimap trim (trim . tail)$ span (/= ':') line +splitKeyMsg line =  bimap trim (trim . tail) $ span (/= ':') line      trim :: String -> String@@ -143,7 +170,7 @@ gettext :: QuasiQuoter gettext = QuasiQuoter   { quoteExp  = gettextQ-  , quotePat  = error "Usage as a parttern is not supported"+  , quotePat  = error "Usage as a pattern is not supported"   , quoteType = error "Usage as a type is not supported"   , quoteDec = gettextsDecs   }