@@ -39,7 +39,7 @@ import Text.Pandoc.Templates
39import Text.Printf ( printf )
39import Text.Printf ( printf )
40import Network.URI ( isURI, unEscapeString )
40import Network.URI ( isURI, unEscapeString )
41import Data.Aeson (object, (.=))
41import Data.Aeson (object, (.=))
42−import Data.List ( (\\), isInfixOf, stripPrefix, intercalate, intersperse )
42+import Data.List ( (\\), isInfixOf, stripPrefix, intercalate, intersperse, nub, nubBy )
43import Data.Char ( toLower, isPunctuation, isAscii, isLetter, isDigit, ord )
43import Data.Char ( toLower, isPunctuation, isAscii, isLetter, isDigit, ord )
44import Data.Maybe ( fromMaybe )
44import Data.Maybe ( fromMaybe )
45import qualified Data.Text as T
45import qualified Data.Text as T
@@ -145,6 +145,7 @@ pandocToLaTeX options (Pandoc meta blocks) = do
145 st <- get
145 st <- get
146 titleMeta <- stringToLaTeX TextString $ stringify $ docTitle meta
146 titleMeta <- stringToLaTeX TextString $ stringify $ docTitle meta
147 authorsMeta <- mapM (stringToLaTeX TextString . stringify) $ docAuthors meta
147 authorsMeta <- mapM (stringToLaTeX TextString . stringify) $ docAuthors meta
148+ let docLangs = nub $ query (extract "lang") blocks
148 let context = defField "toc" (writerTableOfContents options) $
149 let context = defField "toc" (writerTableOfContents options) $
149 defField "toc-depth" (show (writerTOCDepth options -
150 defField "toc-depth" (show (writerTOCDepth options -
150 if stBook st
151 if stBook st
@@ -179,18 +180,48 @@ pandocToLaTeX options (Pandoc meta blocks) = do
179 Biblatex -> defField "biblio-title" biblioTitle .
180 Biblatex -> defField "biblio-title" biblioTitle .
180 defField "biblatex" True
181 defField "biblatex" True
181 _ -> id) $
182 _ -> id) $
183+ -- set lang to something so polyglossia/babel is included
184+ defField "lang" (if null docLangs then ""::String else "en") $
185+ defField "otherlangs" docLangs $
186+ defField "dir" (if (null $ query (extract "dir") blocks)
183 let toPolyObj lang = object [ "name" .= T.pack name
190 let toPolyObj lang = object [ "name" .= T.pack name
184 , "options" .= T.pack opts ]
191 , "options" .= T.pack opts ]
186 (name, opts) = toPolyglossia lang
193 (name, opts) = toPolyglossia lang
187 let lang = maybe [] (splitBy (=='-')) $ getField "lang" context
194 let lang = maybe [] (splitBy (=='-')) $ getField "lang" context
195+ otherlangs = maybe [] (map $ splitBy (=='-')) $ getField "otherlangs" context
188 let context' =
196 let context' =
189 defField "babel-lang" (toBabel lang)
197 defField "babel-lang" (toBabel lang)
198+ $ defField "babel-otherlangs" (map toBabel otherlangs)
199+ $ defField "babel-newcommands" (concatMap (\(poly, babel) ->
200+ -- \textspanish and \textgalician are already used by babel
201+ -- save them as \oritext... and let babel use that
202+ if poly `elem` ["spanish", "galician"]
203+ then "\\let\\oritext" ++ poly ++ "\\text" ++ poly ++ "\n" ++
204+ "\\AddBabelHook{" ++ poly ++ "}{beforeextras}" ++
205+ "{\\renewcommand{\\text" ++ poly ++ "}{\\oritext"
206+ ++ poly ++ "}}\n" ++
207+ "\\AddBabelHook{" ++ poly ++ "}{afterextras}" ++
208+ "{\\renewcommand{\\text" ++ poly ++ "}[2][]{\\foreignlanguage{"
209+ ++ poly ++ "}{##2}}}\n"
210+ else "\\newcommand{\\text" ++ poly ++ "}[2][]{\\foreignlanguage{"
211+ ++ babel ++ "}{#2}}\n" ++
212+ "\\newenvironment{" ++ poly ++ "}[1]{\\begin{otherlanguage}{"
213+ ++ babel ++ "}}{\\end{otherlanguage}}\n"
215+ -- eliminate duplicates that have same polyglossia name
216+ $ nubBy (\a b -> fst a == fst b)
217+ -- find polyglossia and babel names of languages used in the document
219+ let lng = splitBy (=='-') l
220+ in (fst $ toPolyglossia lng, toBabel lng)
190 $ defField "polyglossia-lang" (toPolyObj lang)
223 $ defField "polyglossia-lang" (toPolyObj lang)
191− $ defField "polyglossia-otherlangs"
224+ $ defField "polyglossia-otherlangs" (map toPolyObj otherlangs)
192− (maybe [] (map $ toPolyObj . splitBy (=='-')) $
193− getField "otherlangs" context)
194 $ defField "latex-dir-rtl" (case (getField "dir" context)::Maybe String of
225 $ defField "latex-dir-rtl" (case (getField "dir" context)::Maybe String of
195 Just "rtl" -> True
226 Just "rtl" -> True
196 _ -> False)
227 _ -> False)
@@ -340,15 +371,24 @@ blockToLaTeX (Div (identifier,classes,kvs) bs) = do
340 then empty
371 then empty
341 else "\\hyperdef{}" <> braces (text ref) <>
372 else "\\hyperdef{}" <> braces (text ref) <>
342 braces ("\\label" <> braces (text ref))
373 braces ("\\label" <> braces (text ref))
343− contents' <- blockListToLaTeX bs
344− let align dir = inCmd "begin" dir $$ contents' $$ inCmd "end" dir
374+ let align dir txt = inCmd "begin" dir $$ txt $$ inCmd "end" dir
345− let contents = case lookup "dir" kvs of
375+ let wrapDir = case lookup "dir" kvs of
346− Just "rtl" -> align "RTL"
376+ Just "rtl" -> align "RTL"
347− Just "ltr" -> align "LTR"
377+ Just "ltr" -> align "LTR"
348− _ -> contents'
378+ _ -> id
379+ wrapLang txt = case lookup "lang" kvs of
380+ Just lng -> let (l, o) = toPolyglossiaEnv lng
383+ else brackets $ text o
384+ in inCmd "begin" (text l) <> ops
385+ $$ blankline <> txt <> blankline
386+ $$ inCmd "end" (text l)
349− if beamer && "notes" `elem` classes -- speaker notes
388+ wrapNotes txt = if beamer && "notes" `elem` classes
350− then return $ "\\note" <> braces contents
389+ then "\\note" <> braces txt -- speaker notes
351− else return (linkAnchor $$ contents)
390+ else linkAnchor $$ txt
391+ fmap (wrapDir . wrapLang . wrapNotes) $ blockListToLaTeX bs
352blockToLaTeX (Plain lst) =
392blockToLaTeX (Plain lst) =
353 inlineListToLaTeX $ dropWhile isLineBreakOrSpace lst
393 inlineListToLaTeX $ dropWhile isLineBreakOrSpace lst
354-- title beginning with fig: indicates that the image is a figure
394-- title beginning with fig: indicates that the image is a figure
@@ -759,9 +799,12 @@ inlineToLaTeX (Span (id',classes,kvs) ils) = do
759 (if noSmallCaps then inCmd "textnormal" else id) .
799 (if noSmallCaps then inCmd "textnormal" else id) .
760 (if rtl then inCmd "RL" else id) .
800 (if rtl then inCmd "RL" else id) .
761 (if ltr then inCmd "LR" else id) .
801 (if ltr then inCmd "LR" else id) .
762− (if not (noEmph || noStrong || noSmallCaps || rtl || ltr)
802+ (case lookup "lang" kvs of
763− then braces
803+ Just lng -> let (l, o) = toPolyglossiaEnv lng
804+ ops = if null o then "" else brackets (text o)
805+ in \c -> char '\\' <> "text" <> text l <> ops <> braces c
764− else id)) `fmap` inlineListToLaTeX ils
807+ ) `fmap` inlineListToLaTeX ils
765inlineToLaTeX (Emph lst) =
808inlineToLaTeX (Emph lst) =
766 inlineListToLaTeX lst >>= return . inCmd "emph"
809 inlineListToLaTeX lst >>= return . inCmd "emph"
767inlineToLaTeX (Strong lst) =
810inlineToLaTeX (Strong lst) =
@@ -1002,6 +1045,30 @@ getListingsLanguage :: [String] -> Maybe String
1002getListingsLanguage [] = Nothing
1045getListingsLanguage [] = Nothing
1003getListingsLanguage (x:xs) = toListingsLanguage x <|> getListingsLanguage xs
1046getListingsLanguage (x:xs) = toListingsLanguage x <|> getListingsLanguage xs
1048+-- Extract a key from divs and spans
1049+extract :: String -> Block -> [String]
1050+extract key (Div attr _) = lookKey key attr
1051+extract key (Plain ils) = concatMap (extractInline key) ils
1052+extract key (Para ils) = concatMap (extractInline key) ils
1053+extract key (Header _ _ ils) = concatMap (extractInline key) ils
1056+-- Extract a key from spans
1057+extractInline :: String -> Inline -> [String]
1058+extractInline key (Span attr _) = lookKey key attr
1059+extractInline _ _ = []
1061+-- Look up a key in an attribute and give a list of its values
1062+lookKey :: String -> Attr -> [String]
1063+lookKey key (_,_,kvs) = maybe [] words $ lookup key kvs
1065+-- In environments \Arabic instead of \arabic is used
1066+toPolyglossiaEnv :: String -> (String, String)
1067+toPolyglossiaEnv l =
1068+ case toPolyglossia $ (splitBy (=='-')) l of
1069+ ("arabic", o) -> ("Arabic", o)
1005-- Takes a list of the constituents of a BCP 47 language code and
1072-- Takes a list of the constituents of a BCP 47 language code and
1006-- converts it to a Polyglossia (language, options) tuple
1073-- converts it to a Polyglossia (language, options) tuple
1007-- http://mirrors.concertpass.com/tex-archive/macros/latex/contrib/polyglossia/polyglossia.pdf
1074-- http://mirrors.concertpass.com/tex-archive/macros/latex/contrib/polyglossia/polyglossia.pdf