我使用带有软件包的 LaTeXbabel
并biblatex
经常处理我主要以德语为基础的文档。
最近,我为所有 BibTeX 条目添加了类似的注释,只要条目引用了 TeXLive 发行版提供的 PDF 文档即可。翻译成英文后,注释内容如下:
note={Part of the online documentation of TeXLive distribution, file
\url{<filename>.pdf}},
这是我使用的德语文本:
note={Bestandteil der Online"=Dokumentation von \TeXLive,
Datei \url{<filename>.pdf}},
我添加了在或语言"=
中启用的babel 简写 。但即使我用 来包装注释文本,我也无法像我预期的那样将简写替换为普通连字符。german
ngerman
\foreignlanguage{ngerman}{...}
如果我用普通连字符替换它,第二个单词“Dokumentation”就不会再被 LaTeX 破坏,因此通常会导致错误overfull hbox
。
这是一个 MWE(当然是德语)。
\documentclass[english,ngerman]{scrartcl}
\usepackage[style=numeric]{biblatex}
\usepackage{babel}
\usepackage{csquotes}
\usepackage{dtk-logos}
\addbibresource{\jobname.bib}
\begin{filecontents}{\jobname.bib}
@Manual{class:scrguide,
title = {KOMA-Script},
author = {Kohm, Markus},
month = May,
year = 2016,
url = {http://www.komascript.de/~mkohm/scrguide.pdf},
langid = {ngerman},
note = {Bestandteil der Online"=Dokumentation von
\TeXLive, Datei \url{scrguide.pdf}},
keywords = {manual},
}
\end{filecontents}
\begin{document}
Der Eintrag~\cite{class:scrguide} aus meiner
Literatur"=Datenbank erscheint im Quellen"=Verzeichnis leider mit
einem \verb|"=| in der Ausgabe.
\printbibliography%
\end{document}
"=
(亲爱的德国读者:请忽略上面例子中速记的愚蠢例子。它们被插入是为了证明它们被正常的连字符所取代。)
这是输出:
如何解决这一困境?
答案1
多年来,法语、德语、荷兰语等语言中广泛使用活动字符,并且不时会产生一些令人讨厌的副作用。使用 TeX 或 pdfTeX 引擎时,您必须忍受它们。
幸运的是,LuaTeX 提供了一些工具来摆脱它们,我为 babel-french 做了同样的事,并查看了你的报告,该报告遵循了 (丹尼斯·比图泽), 我决定检查德语 dblquote 是否也可以在 LuaTeX 中保持非活动状态。
我编写了以下“dblquote.sty”文件作为“概念证明”;它似乎可以工作,但由于我不是德语母语人士,我无法判断这个 Lua 代码(改进后)是否可以替换 (n)german.ldf 文件中的当前代码。
要尝试一下,只需在序言中添加 \usepackage{dblquote},并在 \begin{document} 之后添加一行 \shorthandoff{"}。
\ProvidesPackage{dblquote}
[2021/07/04 v.0.01 Daniel Flipo]
\NeedsTeXFormat{LaTeX2e}[2021/06/01]
\ifdefined\directlua
\RequirePackage{luatexbase,luacode}
\else
\PackageError{This package is meant for LuaTeX only! Aborting}
{No more information available, sorry!}
\fi
\newattribute\DQ \DQ=1 \relax
\newattribute\toss \toss=0 \relax
\ifluatex
\def\mdqon{\DQ=1\relax}
\def\mdqoff{\DQ=0\relax}
%\else
% \def\mdqon{\shorthandon{"}}
% \def\mdqoff{\shorthandoff{"}}
\fi
\begin{luacode}
dblquote = { }
local DQ = luatexbase.attributes['DQ']
local toss = luatexbase.attributes['toss']
local has_attribute = node.has_attribute
local traverse_id = node.traverse_id
local remove = node.remove
local insert_before = node.insert_before
local insert_after = node.insert_after
local current_attr = node.current_attr
local new_node = node.new
local copy_node = node.copy
local copy_list = node.copy_list
local node_id = node.id
local DISC = node_id("disc")
local HLIST = node_id("hlist")
local GLUE = node_id("glue")
local GLYPH = node_id("glyph")
local KERN = node_id("kern")
local PENALTY = node_id("penalty")
local nobreak = new_node(PENALTY,0)
nobreak.penalty = 10000
local hskip0 = new_node(GLUE,0)
-- Replace "a with ä etc.
dblquote.replace = function (head)
local t = { }
t[string.byte("'")] = 0x201C
t[0x2019] = 0x201C -- quoteright (Ligatures=TeX)
t[string.byte("`")] = 0x201E
t[0x2018] = 0x201E -- quoteleft (Ligatures=TeX)
t[string.byte("<")] = 0x00AB
t[string.byte(">")] = 0x00BB
t[string.byte("A")] = 0x00C4
t[string.byte("a")] = 0x00E4
t[string.byte("E")] = 0x00CB
t[string.byte("e")] = 0x00EB
t[string.byte("I")] = 0x00CF
t[string.byte("i")] = 0x00EF
t[string.byte("O")] = 0x00D6
t[string.byte("o")] = 0x00F6
t[string.byte("U")] = 0x00DC
t[string.byte("u")] = 0x00FC
t[string.byte("S")] = 0x0053
t[string.byte("Z")] = 0x005A
for item in traverse_id(GLYPH, head) do
local lang = item.lang
local char = item.char
local DQon = has_attribute(item, DQ)
DQon = DQon and DQon > 0
local tossON = has_attribute(item, toss)
tossON = tossON and tossON > 0
if (lang == DE or lang == DEn) and DQon and
(char == 0x201D or char == 0x22) then
local next = item.next
local nchar = next.char
if tossON then
t[string.byte("s")] = string.byte("s")
t[string.byte("z")] = string.byte("z")
else
t[string.byte("s")] = 0x00DF
t[string.byte("z")] = 0x00DF
end
if t[nchar] then
next.char = t[nchar]
if t[nchar] == string.byte("s") or t[nchar] == string.byte("z") then
item.char = string.byte("s")
elseif t[nchar] == string.byte("S") or t[nchar] == string.byte("Z") then
item.char = string.byte("S")
else
head = remove(head,item)
end
end
end
end
return head
end
-- Hyphenation and ligatures
dblquote.disc = function (head)
local to = { }
to[string.byte("f")] = true
to[string.byte("F")] = true
to[string.byte("l")] = true
to[string.byte("L")] = true
to[string.byte("m")] = true
to[string.byte("M")] = true
to[string.byte("n")] = true
to[string.byte("N")] = true
to[string.byte("p")] = true
to[string.byte("P")] = true
to[string.byte("r")] = true
to[string.byte("R")] = true
to[string.byte("t")] = true
to[string.byte("T")] = true
for item in node.traverse_id(GLYPH, head) do
local lang = item.lang
local char = item.char
local DQon = has_attribute(item, DQ)
DQon = DQon and DQon > 0
if DQon and (char == 0x201D or char == 0x22) then
-- traditionnal German only
if lang == DE then
local n = item.next
local nn = n.next
local nchar = n.char
local prev = item.prev
-- "ck and "CK
if nchar == string.byte("c") or nchar == string.byte("C") then
head = remove(head,n)
head = remove(head,item)
-- building d.pre looks clumsy, to be improved!
local pre = new_node(HLIST,0)
local hyph = copy_node(nn)
hyph.char = string.byte("-")
local first = copy_node(nn)
local second = copy_node(hyph)
pre.head = first
first.next = second
second.next = nil
----------------------------------------------
local d = new_node(DISC,0)
d.attr = current_attr()
d.penalty = tex.hyphenpenalty
d.pre = copy_list(first)
d.replace = copy_node(n)
insert_after(head,prev,copy_node(d))
insert_after(head,prev,copy_node(nobreak))
insert_before(head,nn,copy_node(nobreak))
insert_before(head,nn,copy_node(hskip0))
-- all others "ff, "FF, etc.
elseif to[nchar] and nn.char and nn.char == n.char then
head = remove(head,n)
head = remove(head,item)
local d = new_node(DISC,0)
d.attr = current_attr()
d.penalty = tex.hyphenpenalty
-- building d.pre looks clumsy, to be improved!
local pre = new_node(HLIST,0)
local hyph = copy_node(nn)
hyph.char = string.byte("-")
local first, second, third
-- "f is special
if nchar == string.byte("f") then
local ff = copy_node(n)
ff.char = 0xFB00 -- ligature "ff"
first = copy_node(ff)
second = copy_node(hyph)
second.next = nil
d.post = copy_node(n)
d.replace = copy_node(ff)
head = remove(head,nn)
else
first = copy_node(n)
second = copy_node(n)
third = copy_node(hyph)
third.next = nil
d.replace = copy_node(n)
end
pre.head = first
first.next = second
second.next = third
--
d.attr = current_attr()
d.pre = copy_list(first)
d.penalty = tex.hyphenpenalty
insert_after(head,prev,copy_node(hskip0))
insert_after(head,prev,copy_node(nobreak))
insert_after(head,prev,copy_node(d))
insert_after(head,prev,copy_node(nobreak))
end
end
-- modern and traditionnal German
if lang == DE or lang == DEn then
local n = item.next
local nchar
if n.id == GLYPH then
nchar = n.char
elseif n.id == PENALTY then -- n = node ~
nchar = 1
end
local prev = item.prev
if nchar == string.byte("-") then
local d = new_node(DISC,0)
d.attr = current_attr()
d.penalty = tex.hyphenpenalty
local hyph = copy_node(n)
hyph.char = string.byte("-")
d.pre = copy_node(hyph)
head = remove(head,n)
head = remove(head,item)
insert_after(head,prev,copy_node(hskip0))
insert_after(head,prev,copy_node(nobreak))
insert_after(head,prev,copy_node(d))
insert_after(head,prev,copy_node(nobreak))
elseif nchar == string.byte("|") then
local d = new_node(DISC,0)
d.attr = current_attr()
d.penalty = tex.hyphenpenalty
local hyph = copy_node(n)
hyph.char = string.byte("-")
d.pre = copy_node(hyph)
local k = new_node(KERN,1)
k.attr = current_attr()
k.kern = 20000
d.replace = copy_node(k)
head = remove(head,n)
head = remove(head,item)
insert_after(head,prev,copy_node(hskip0))
insert_after(head,prev,copy_node(nobreak))
insert_after(head,prev,copy_node(d))
insert_after(head,prev,copy_node(nobreak))
elseif nchar == string.byte('"') then
head = remove(head,n)
head = remove(head,item)
insert_after(head,prev,copy_node(hskip0))
elseif nchar == 1 then -- ("~)
local hyph = copy_node(item)
hyph.char = string.byte("-")
head = remove(head,n.next)
head = remove(head,n)
head = remove(head,item)
insert_after(head,prev,copy_node(nobreak))
insert_after(head,prev,copy_node(hyph))
elseif nchar == string.byte("=") then
local hyph = copy_node(n)
hyph.char = string.byte("-")
head = remove(head,n)
head = remove(head,item)
insert_after(head,prev,copy_node(hskip0))
insert_after(head,prev,copy_node(hyph))
insert_after(head,prev,copy_node(nobreak))
elseif nchar == string.byte("/") then
local d = new_node(DISC,0)
d.attr = current_attr()
d.penalty = tex.hyphenpenalty
local slash = copy_node(n)
slash.char = string.byte("/")
d.pre = copy_node(slash)
d.replace = copy_node(slash)
head = remove(head,n)
head = remove(head,item)
insert_after(head,prev,copy_node(hskip0))
insert_after(head,prev,copy_node(nobreak))
insert_after(head,prev,copy_node(d))
insert_after(head,prev,copy_node(hskip0))
insert_after(head,prev,copy_node(nobreak))
end
end
end
end
return head
end
return dblquote.replace, dblquote.disc
\end{luacode}
\directlua{%
DE = \the\l@german ;
DEn = \the\l@ngerman ;
luatexbase.add_to_callback
("pre_linebreak_filter",dblquote.disc,"discretionary",1)
luatexbase.add_to_callback
("pre_linebreak_filter",dblquote.replace,"replace",1)
luatexbase.add_to_callback
("hpack_filter",dblquote.replace,"replace")
}
\endinput`