@@ -39,12 +39,13 @@ import Control.Monad.State.Strict
3939import Data.Aeson (FromJSON, object, (.=))
4040import Data.Char (isAlphaNum, isAscii, isDigit, isLetter, isPunctuation, ord,
4141 toLower)
42−import Data.List (foldl', intercalate, intersperse, isInfixOf, nub, nubBy,
42+import Data.List (foldl', intercalate, intersperse, isInfixOf, nubBy,
4343 stripPrefix, (\\))
4444import Data.Maybe (catMaybes, fromMaybe, isJust)
4545import Data.Text (Text)
4646import qualified Data.Text as T
4747import Network.URI (unEscapeString)
48+import Text.Pandoc.BCP47 (Lang(..), toLang, getLang, renderLang)
4849import Text.Pandoc.Class (PandocMonad, report)
4950import Text.Pandoc.Definition
5051import Text.Pandoc.Highlighting (formatLaTeXBlock, formatLaTeXInline, highlight,
@@ -188,7 +189,8 @@ pandocToLaTeX options (Pandoc meta blocks) = do
188189 st <- get
189190 titleMeta <- stringToLaTeX TextString $ stringify $ docTitle meta
190191 authorsMeta <- mapM (stringToLaTeX TextString . stringify) $ docAuthors meta
191− let docLangs = nub $ query (extract "lang") blocks
192+ docLangs <- catMaybes <$>
193+ mapM (toLang . Just) (ordNub (query (extract "lang") blocks))
192194 let hasStringValue x = isJust (getField x metadata :: Maybe String)
193195 let geometryFromMargins = intercalate [','] $ catMaybes $
194196 map (\(x,y) ->
@@ -198,6 +200,18 @@ pandocToLaTeX options (Pandoc meta blocks) = do
198200 ,("tmargin","margin-top")
199201 ,("bmargin","margin-bottom")
200202 ]
203+ let toPolyObj lang = object [ "name" .= T.pack name
204+ , "options" .= T.pack opts ]
205+ where
206+ (name, opts) = toPolyglossia lang
207+ mblang <- toLang $ case getLang options meta of
208+ Just l -> Just l
209+ Nothing | null docLangs -> Nothing
210+ | otherwise -> Just "en"
211+ -- we need a default here since lang is used in template conditionals
212+
213+ let dirs = query (extract "dir") blocks
214+
201215 let context = defField "toc" (writerTableOfContents options) $
202216 defField "toc-depth" (show (writerTOCDepth options -
203217 if stBook st
@@ -235,26 +249,20 @@ pandocToLaTeX options (Pandoc meta blocks) = do
235249 Biblatex -> defField "biblio-title" biblioTitle .
236250 defField "biblatex" True
237251 _ -> id) $
238− -- set lang to something so polyglossia/babel is included
239− defField "lang" (if null docLangs then ""::String else "en") $
240− defField "otherlangs" docLangs $
241252 defField "colorlinks" (any hasStringValue
242253 ["citecolor", "urlcolor", "linkcolor", "toccolor"]) $
243− defField "dir" (if (null $ query (extract "dir") blocks)
244− then ""::String
245− else "ltr") $
254+ (if null dirs
255+ then id
256+ else defField "dir" ("ltr" :: String)) $
246257 defField "section-titles" True $
247258 defField "geometry" geometryFromMargins $
248259 metadata
249− let toPolyObj lang = object [ "name" .= T.pack name
250− , "options" .= T.pack opts ]
251− where
252− (name, opts) = toPolyglossia lang
253− let lang = maybe [] (splitBy (=='-')) $ getField "lang" context
254− otherlangs = maybe [] (map $ splitBy (=='-')) $ getField "otherlangs" context
255260 let context' =
256− defField "babel-lang" (toBabel lang)
257− $ defField "babel-otherlangs" (map toBabel otherlangs)
261+ -- note: lang is used in some conditionals in the template,
262+ -- so we need to set it if we have any babel/polyglossia:
263+ maybe id (defField "lang" . renderLang) mblang
264+ $ maybe id (defField "babel-lang" . toBabel) mblang
265+ $ defField "babel-otherlangs" (map toBabel docLangs)
258266 $ defField "babel-newcommands" (concatMap (\(poly, babel) ->
259267 -- \textspanish and \textgalician are already used by babel
260268 -- save them as \oritext... and let babel use that
@@ -274,16 +282,12 @@ pandocToLaTeX options (Pandoc meta blocks) = do
274282 -- eliminate duplicates that have same polyglossia name
275283 $ nubBy (\a b -> fst a == fst b)
276284 -- find polyglossia and babel names of languages used in the document
277− $ map (\l ->
278− let lng = splitBy (=='-') l
279− in (fst $ toPolyglossia lng, toBabel lng)
280− )
281− docLangs )
282− $ defField "polyglossia-lang" (toPolyObj lang)
283− $ defField "polyglossia-otherlangs" (map toPolyObj otherlangs)
284− $ defField "latex-dir-rtl" (case (getField "dir" context)::Maybe String of
285− Just "rtl" -> True
286− _ -> False)
285+ $ map (\l -> (fst $ toPolyglossia l, toBabel l)) docLangs
286+ )
287+ $ maybe id (defField "polyglossia-lang" . toPolyObj) mblang
288+ $ defField "polyglossia-otherlangs" (map toPolyObj docLangs)
289+ $ defField "latex-dir-rtl"
290+ (getField "dir" context == Just ("rtl" :: String))
287291 $ context
288292 case writerTemplate options of
289293 Nothing -> return main
@@ -443,11 +447,12 @@ blockToLaTeX (Div (identifier,classes,kvs) bs) = do
443447 -> "\\leavevmode" <> linkAnchor' <> "%"
444448 _ -> linkAnchor'
445449 let align dir txt = inCmd "begin" dir $$ txt $$ inCmd "end" dir
450+ lang <- toLang $ lookup "lang" kvs
446451 let wrapDir = case lookup "dir" kvs of
447452 Just "rtl" -> align "RTL"
448453 Just "ltr" -> align "LTR"
449454 _ -> id
450− wrapLang txt = case lookup "lang" kvs of
455+ wrapLang txt = case lang of
451456 Just lng -> let (l, o) = toPolyglossiaEnv lng
452457 ops = if null o
453458 then ""
@@ -918,13 +923,14 @@ inlineToLaTeX :: PandocMonad m
918923 -> LW m Doc
919924inlineToLaTeX (Span (id',classes,kvs) ils) = do
920925 linkAnchor <- hypertarget False id' empty
926+ lang <- toLang $ lookup "lang" kvs
921927 let cmds = ["textup" | "csl-no-emph" `elem` classes] ++
922928 ["textnormal" | "csl-no-strong" `elem` classes ||
923929 "csl-no-smallcaps" `elem` classes] ++
924930 ["RL" | ("dir", "rtl") `elem` kvs] ++
925931 ["LR" | ("dir", "ltr") `elem` kvs] ++
926− (case lookup "lang" kvs of
927− Just lng -> let (l, o) = toPolyglossia $ splitBy (=='-') lng
932+ (case lang of
933+ Just lng -> let (l, o) = toPolyglossia lng
928934 ops = if null o then "" else ("[" ++ o ++ "]")
929935 in ["text" ++ l ++ ops]
930936 Nothing -> [])
@@ -1254,85 +1260,95 @@ lookKey :: String -> Attr -> [String]
12541260lookKey key (_,_,kvs) = maybe [] words $ lookup key kvs
12551261
12561262-- In environments \Arabic instead of \arabic is used
1257−toPolyglossiaEnv :: String -> (String, String)
1263+toPolyglossiaEnv :: Lang -> (String, String)
12581264toPolyglossiaEnv l =
1259− case toPolyglossia $ (splitBy (=='-')) l of
1265+ case toPolyglossia l of
12601266 ("arabic", o) -> ("Arabic", o)
12611267 x -> x
12621268
12631269-- Takes a list of the constituents of a BCP 47 language code and
12641270-- converts it to a Polyglossia (language, options) tuple
12651271-- http://mirrors.ctan.org/macros/latex/contrib/polyglossia/polyglossia.pdf
1266−toPolyglossia :: [String] -> (String, String)
1267−toPolyglossia ("ar":"DZ":_) = ("arabic", "locale=algeria")
1268−toPolyglossia ("ar":"IQ":_) = ("arabic", "locale=mashriq")
1269−toPolyglossia ("ar":"JO":_) = ("arabic", "locale=mashriq")
1270−toPolyglossia ("ar":"LB":_) = ("arabic", "locale=mashriq")
1271−toPolyglossia ("ar":"LY":_) = ("arabic", "locale=libya")
1272−toPolyglossia ("ar":"MA":_) = ("arabic", "locale=morocco")
1273−toPolyglossia ("ar":"MR":_) = ("arabic", "locale=mauritania")
1274−toPolyglossia ("ar":"PS":_) = ("arabic", "locale=mashriq")
1275−toPolyglossia ("ar":"SY":_) = ("arabic", "locale=mashriq")
1276−toPolyglossia ("ar":"TN":_) = ("arabic", "locale=tunisia")
1277−toPolyglossia ("de":"1901":_) = ("german", "spelling=old")
1278−toPolyglossia ("de":"AT":"1901":_) = ("german", "variant=austrian, spelling=old")
1279−toPolyglossia ("de":"AT":_) = ("german", "variant=austrian")
1280−toPolyglossia ("de":"CH":"1901":_) = ("german", "variant=swiss, spelling=old")
1281−toPolyglossia ("de":"CH":_) = ("german", "variant=swiss")
1282−toPolyglossia ("de":_) = ("german", "")
1283−toPolyglossia ("dsb":_) = ("lsorbian", "")
1284−toPolyglossia ("el":"polyton":_) = ("greek", "variant=poly")
1285−toPolyglossia ("en":"AU":_) = ("english", "variant=australian")
1286−toPolyglossia ("en":"CA":_) = ("english", "variant=canadian")
1287−toPolyglossia ("en":"GB":_) = ("english", "variant=british")
1288−toPolyglossia ("en":"NZ":_) = ("english", "variant=newzealand")
1289−toPolyglossia ("en":"UK":_) = ("english", "variant=british")
1290−toPolyglossia ("en":"US":_) = ("english", "variant=american")
1291−toPolyglossia ("grc":_) = ("greek", "variant=ancient")
1292−toPolyglossia ("hsb":_) = ("usorbian", "")
1293−toPolyglossia ("la":"x":"classic":_) = ("latin", "variant=classic")
1294−toPolyglossia ("sl":_) = ("slovenian", "")
1295−toPolyglossia x = (commonFromBcp47 x, "")
1272+toPolyglossia :: Lang -> (String, String)
1273+toPolyglossia (Lang "ar" _ "DZ" _) = ("arabic", "locale=algeria")
1274+toPolyglossia (Lang "ar" _ "IQ" _) = ("arabic", "locale=mashriq")
1275+toPolyglossia (Lang "ar" _ "JO" _) = ("arabic", "locale=mashriq")
1276+toPolyglossia (Lang "ar" _ "LB" _) = ("arabic", "locale=mashriq")
1277+toPolyglossia (Lang "ar" _ "LY" _) = ("arabic", "locale=libya")
1278+toPolyglossia (Lang "ar" _ "MA" _) = ("arabic", "locale=morocco")
1279+toPolyglossia (Lang "ar" _ "MR" _) = ("arabic", "locale=mauritania")
1280+toPolyglossia (Lang "ar" _ "PS" _) = ("arabic", "locale=mashriq")
1281+toPolyglossia (Lang "ar" _ "SY" _) = ("arabic", "locale=mashriq")
1282+toPolyglossia (Lang "ar" _ "TN" _) = ("arabic", "locale=tunisia")
1283+toPolyglossia (Lang "de" _ _ vars)
1284+ | "1901" `elem` vars = ("german", "spelling=old")
1285+toPolyglossia (Lang "de" _ "AT" vars)
1286+ | "1901" `elem` vars = ("german", "variant=austrian, spelling=old")
1287+toPolyglossia (Lang "de" _ "AT" _) = ("german", "variant=austrian")
1288+toPolyglossia (Lang "de" _ "CH" vars)
1289+ | "1901" `elem` vars = ("german", "variant=swiss, spelling=old")
1290+toPolyglossia (Lang "de" _ "CH" _) = ("german", "variant=swiss")
1291+toPolyglossia (Lang "de" _ _ _) = ("german", "")
1292+toPolyglossia (Lang "dsb" _ _ _) = ("lsorbian", "")
1293+toPolyglossia (Lang "el" _ "polyton" _) = ("greek", "variant=poly")
1294+toPolyglossia (Lang "en" _ "AU" _) = ("english", "variant=australian")
1295+toPolyglossia (Lang "en" _ "CA" _) = ("english", "variant=canadian")
1296+toPolyglossia (Lang "en" _ "GB" _) = ("english", "variant=british")
1297+toPolyglossia (Lang "en" _ "NZ" _) = ("english", "variant=newzealand")
1298+toPolyglossia (Lang "en" _ "UK" _) = ("english", "variant=british")
1299+toPolyglossia (Lang "en" _ "US" _) = ("english", "variant=american")
1300+toPolyglossia (Lang "grc" _ _ _) = ("greek", "variant=ancient")
1301+toPolyglossia (Lang "hsb" _ _ _) = ("usorbian", "")
1302+toPolyglossia (Lang "la" _ _ vars)
1303+ | "x-classic" `elem` vars = ("latin", "variant=classic")
1304+toPolyglossia (Lang "sl" _ _ _) = ("slovenian", "")
1305+toPolyglossia x = (commonFromBcp47 x, "")
12961306
12971307-- Takes a list of the constituents of a BCP 47 language code and
12981308-- converts it to a Babel language string.
12991309-- http://mirrors.ctan.org/macros/latex/required/babel/base/babel.pdf
13001310-- List of supported languages (slightly outdated):
13011311-- http://tug.ctan.org/language/hyph-utf8/doc/generic/hyph-utf8/hyphenation.pdf
1302−toBabel :: [String] -> String
1303−toBabel ("de":"1901":_) = "german"
1304−toBabel ("de":"AT":"1901":_) = "austrian"
1305−toBabel ("de":"AT":_) = "naustrian"
1306−toBabel ("de":"CH":"1901":_) = "swissgerman"
1307−toBabel ("de":"CH":_) = "nswissgerman"
1308−toBabel ("de":_) = "ngerman"
1309−toBabel ("dsb":_) = "lowersorbian"
1310−toBabel ("el":"polyton":_) = "polutonikogreek"
1311−toBabel ("en":"AU":_) = "australian"
1312−toBabel ("en":"CA":_) = "canadian"
1313−toBabel ("en":"GB":_) = "british"
1314−toBabel ("en":"NZ":_) = "newzealand"
1315−toBabel ("en":"UK":_) = "british"
1316−toBabel ("en":"US":_) = "american"
1317−toBabel ("fr":"CA":_) = "canadien"
1318−toBabel ("fra":"aca":_) = "acadian"
1319−toBabel ("grc":_) = "polutonikogreek"
1320−toBabel ("hsb":_) = "uppersorbian"
1321−toBabel ("la":"x":"classic":_) = "classiclatin"
1322−toBabel ("sl":_) = "slovene"
1323−toBabel x = commonFromBcp47 x
1312+toBabel :: Lang -> String
1313+toBabel (Lang "de" _ "AT" vars)
1314+ | "1901" `elem` vars = "austrian"
1315+ | otherwise = "naustrian"
1316+toBabel (Lang "de" _ "CH" vars)
1317+ | "1901" `elem` vars = "swissgerman"
1318+ | otherwise = "nswissgerman"
1319+toBabel (Lang "de" _ _ vars)
1320+ | "1901" `elem` vars = "german"
1321+ | otherwise = "ngerman"
1322+toBabel (Lang "dsb" _ _ _) = "lowersorbian"
1323+toBabel (Lang "el" _ _ vars)
1324+ | "polyton" `elem` vars = "polutonikogreek"
1325+toBabel (Lang "en" _ "AU" _) = "australian"
1326+toBabel (Lang "en" _ "CA" _) = "canadian"
1327+toBabel (Lang "en" _ "GB" _) = "british"
1328+toBabel (Lang "en" _ "NZ" _) = "newzealand"
1329+toBabel (Lang "en" _ "UK" _) = "british"
1330+toBabel (Lang "en" _ "US" _) = "american"
1331+toBabel (Lang "fr" _ "CA" _) = "canadien"
1332+toBabel (Lang "fra" _ _ vars)
1333+ | "aca" `elem` vars = "acadian"
1334+toBabel (Lang "grc" _ _ _) = "polutonikogreek"
1335+toBabel (Lang "hsb" _ _ _) = "uppersorbian"
1336+toBabel (Lang "la" _ _ vars)
1337+ | "x-classic" `elem` vars = "classiclatin"
1338+toBabel (Lang "sl" _ _ _) = "slovene"
1339+toBabel x = commonFromBcp47 x
13241340
13251341-- Takes a list of the constituents of a BCP 47 language code
13261342-- and converts it to a string shared by Babel and Polyglossia.
13271343-- https://tools.ietf.org/html/bcp47#section-2.1
1328−commonFromBcp47 :: [String] -> String
1329−commonFromBcp47 [] = ""
1330−commonFromBcp47 ("pt":"BR":_) = "brazil"
1344+commonFromBcp47 :: Lang -> String
1345+commonFromBcp47 (Lang "pt" _ "BR" _) = "brazil"
13311346-- Note: documentation says "brazilian" works too, but it doesn't seem to work
13321347-- on some systems. See #2953.
1333−commonFromBcp47 ("sr":"Cyrl":_) = "serbianc"
1334−commonFromBcp47 ("zh":"Latn":"pinyin":_) = "pinyin"
1335−commonFromBcp47 x = fromIso $ head x
1348+commonFromBcp47 (Lang "sr" "Cyrl" _ _) = "serbianc"
1349+commonFromBcp47 (Lang "zh" "Latn" _ vars)
1350+ | "pinyin" `elem` vars = "pinyin"
1351+commonFromBcp47 (Lang l _ _ _) = fromIso l
13361352 where
13371353 fromIso "af" = "afrikaans"
13381354 fromIso "am" = "amharic"