1- -- (C) vasylp https://github.com/vasylp/hgettext/blob/master/src/hgettext.hs
2-
3- import qualified Language.Haskell.Exts as H
4-
5- import System.Environment
6- import System.Console.GetOpt
7- import Data.Time
8- import System.Locale hiding (defaultTimeLocale )
9-
10- import Data.Generics.Uniplate.Data
11-
12- -- import Distribution.Simple.PreProcess.Unlit
13-
14- import Data.List
15- import Data.Char
16- import Data.Ord
17- import Data.Function (on )
18- import System.FilePath
19-
20- import Data.Version (showVersion )
21- version = undefined
22- -- import Paths_haskell_gettext (version)
23-
24- data Options = Options {
25- outputFile :: String ,
26- keywords :: [String ],
27- printVersion :: Bool
28- } deriving Show
29-
30- options :: [OptDescr (Options -> Options )]
31- options =
32- [
33- Option [' o' ] [" output" ]
34- (ReqArg (\ o opts -> opts {outputFile = o}) " FILE" )
35- " write output to specified file" ,
36- Option [' d' ] [" default-domain" ]
37- (ReqArg (\ d opts -> opts {outputFile = d ++ " .po" }) " NAME" )
38- " use NAME.po instead of messages.po" ,
39- Option [' k' ] [" keyword" ]
40- (ReqArg (\ d opts -> opts {keywords = d: keywords opts}) " WORD" )
41- " function names, in which searched words are wrapped. Can be used multiple times, for multiple funcitons" ,
42- Option [] [" version" ]
43- (NoArg (\ opts -> opts {printVersion = True }))
44- " print version of hgettexts"
45- ]
46-
47-
48- defaultOptions = Options " messages.po" [" __" , " lprintf" ] False
49-
50- parseArgs :: [String ] -> IO (Options , [String ])
51- parseArgs args =
52- case getOpt Permute options args of
53- (o, n, [] ) -> return (foldl (flip id ) defaultOptions o, n)
54- (_, _, errs) -> ioError (userError (concat errs ++ usageInfo header options))
55- where header = " Usage: hgettext [OPTION] [INPUTFILE] ..."
56-
57-
58- toTranslate :: [String ] -> H. ParseResult (H. Module H. SrcSpanInfo ) -> [(H. SrcSpanInfo , String )]
59- toTranslate f (H. ParseOk z) = nub [ (loc, s) | H. App _ (H. Var _ (H. UnQual _ (H. Ident _ x))) (H. Lit _ (H. String loc s _)) <- universeBi z, x `elem` f]
60- toTranslate _ _ = []
61-
62- -- Create list of messages from a single file
63- formatMessages :: String -> [(H. SrcSpanInfo , String )] -> String
64- formatMessages path l = concat $ map potEntry $ nubBy ((==) `on` snd ) $ sortBy (comparing snd ) l
65- where potEntry (l, s) = unlines [
66- " #: " ++ showSrc l,
67- " msgid " ++ (show s),
68- " msgstr \"\" " ,
69- " "
70- ]
71- showSrc l = path ++ " :" ++ show (H. srcSpanStartLine (H. srcInfoSpan l)) ++ " :" ++ show (H. srcSpanStartColumn (H. srcInfoSpan l))
1+ -- Originally copied from https://github.com/vasylp/hgettext/
2+ -- © 2009 Vasyl Pasternak, BSD-3-Clause.
3+
4+ import Options
5+ import Paths_haskell_gettext (version )
6+
7+ import qualified Data.Generics.Uniplate.Data as G
8+ import qualified Data.Function as F
9+ import qualified Data.List as L
10+ import qualified Data.Ord as O
11+ import qualified Data.Text as T
12+ import qualified Data.Time as TM
13+ import qualified Data.Text.IO.Utf8 as Utf8
14+ import qualified Data.Version as V
15+ import qualified Language.Haskell.Exts as H
16+
17+
18+ main :: IO ()
19+ main = do
20+ opts <- parseOptions
21+ process opts
22+
23+ process :: Options -> IO ()
24+ process Options {printVersion = True } =
25+ putStrLn $ " hgettext (from haskell-gettext), version " ++
26+ (V. showVersion version)
27+ process opts
28+ | null (inputFiles opts) = do
29+ putStrLn " hgettext: missing arguments"
30+ | otherwise = do
31+ t <- mapM read' (inputFiles opts)
32+ pot <- formatPotFile $
33+ map (\ (n,c) -> formatMessages n $
34+ toTranslate (keywords opts) c) t
35+ Utf8. writeFile (outputFile opts) (T. pack pot)
36+ where
37+ read' :: FilePath ->
38+ IO (String , H. ParseResult (H. Module H. SrcSpanInfo ))
39+ read' " -" = getContents >>= \ c -> return (" -" , H. parseFileContents c)
40+ read' f = H. parseFile f >>= \ m -> return (f, m)
41+
42+ -------------------------------------------------------------------------------
43+ -- Write
7244
7345
7446formatPotFile :: [String ] -> IO String
75- formatPotFile lines = do
76- time <- getZonedTime
77- let timeStr = formatTime defaultTimeLocale " %F %R%z" time
47+ formatPotFile ls = do
48+ time <- TM. getZonedTime
49+ let timeStr = TM. formatTime TM. defaultTimeLocale " %F %R%z" time
7850 let header = formatPotHeader timeStr
79- return $ concat $ header: lines
51+ return $ concat ( header: ls)
8052 where
53+ formatPotHeader :: String -> String
8154 formatPotHeader timeStr =
8255 unlines [" # Translation file" ,
8356 " " ,
@@ -95,18 +68,40 @@ formatPotFile lines = do
9568 " \" Content-Transfer-Encoding: 8bit\\ n\" " ,
9669 " " ]
9770
98- process :: Options -> [String ] -> IO ()
99- process Options {printVersion = True } _ =
100- putStrLn $ " hgettext, version " ++ (showVersion version)
101-
102- process opts fl = do
103- t <- mapM read' fl
104- pot <- formatPotFile $ map (\ (n,c) -> formatMessages n $ toTranslate (keywords opts) c) t
105- writeFile (outputFile opts) pot
106- where read' " -" = getContents >>= \ c -> return (" -" , H. parseFileContents c)
107- read' f = H. parseFile f >>= \ m -> return (f, m)
108-
109- main =
110- getArgs >>= parseArgs >>= uncurry process
111-
71+ -- Create list of messages from a single file.
72+ formatMessages :: String -> [(H. SrcSpanInfo , String )] -> String
73+ formatMessages path l =
74+ let sorted = L. sortBy (O. comparing snd ) l
75+ nubbed = L. nubBy ((==) `F.on` snd ) sorted
76+ in concatMap potEntry nubbed
77+ where
78+ potEntry :: (H. SrcSpanInfo , String ) -> String
79+ potEntry (wl, s) = unlines
80+ [" #: " ++ showSrc wl,
81+ " msgid " ++ (showStringC s),
82+ " msgstr \"\" " ,
83+ " " ]
84+
85+ showSrc :: H. SrcSpanInfo -> String
86+ showSrc wl = path ++ " :" ++
87+ show (H. srcSpanStartLine (H. srcInfoSpan wl)) ++ " :" ++
88+ show (H. srcSpanStartColumn (H. srcInfoSpan wl))
89+
90+ toTranslate :: [String ] -> H. ParseResult (H. Module H. SrcSpanInfo ) ->
91+ [(H. SrcSpanInfo , String )]
92+ toTranslate f (H. ParseOk z) =
93+ L. nub [(loc, s) |
94+ H. App _ (H. Var _ (H. UnQual _ (H. Ident _ x)))
95+ (H. Lit _ (H. String loc s _)) <- G. universeBi z,
96+ x `elem` f]
97+ toTranslate _ _ = []
11298
99+ -- Escape a string in a C-like fashion,
100+ -- see https://www.ibm.com/docs/en/i/7.4?topic=literals-string
101+ showStringC :: String -> String
102+ showStringC s0 = ' "' : concatMap showCharC s0 ++ " \" "
103+ where
104+ showCharC ' "' = " \\\" "
105+ showCharC ' \\ ' = " \\\\ "
106+ showCharC ' \n ' = " \\ n"
107+ showCharC c = return c
0 commit comments