CTeX-org / ctex-kit

Macro Packages and Scripts for Chinese TeX users
974 stars 124 forks source link

ctex: 初步支持 biblatex #350

Open leo-liu opened 6 years ago

leo-liu commented 6 years ago

与许多宏包一样,biblatex 基于 babel 做本地化。默认语言用的是 english,然后会在 \begin{document} 之后修改 \refname\bibname 的值,造成问题。

biblatex 自己的本地化文献是 .lbx 文件,会语言保存相关的串。

对于中文文档,ctex 包对 \refname\bibname 的修改早于 biblatex 的重定义,会造成无效。

简单的处理方式是让 \ctexset 设置 bibname 延迟(利用 \AtBeginDocument)。

目前已有的 biblatex 格式,如 biblatex-gb7714-2015biblatex-caspervector,则是直接在 .bbx 文件定义中类似这样设置:

\DefineBibliographyStrings{english}{
  bibliography = {参考文献},
  references   = {参考文献},
}

这种设置也有一些风险。

需要考虑一下怎么设置比较好。

lrtfm commented 6 years ago

利用 \AtBeginDocument 延迟设置比较好,简单易行,并可定义设置开关,使用户可以控制显示结果。

leo-liu commented 6 years ago

使用 \AtBeginDocument 这种方式也可能一些细节问题,比如与现有部分中文 biblatex 模板冲突需要与作者沟通之类。 这个问题和 beamer 当时汉化有点像,ctexbeamer 的作法还是通过 beamer 的接口定义了 translator。 我再想想。目前只是写东西遇到这个问题,暂时没有时间仔细看代码去改。

hushidong commented 6 years ago

从实践看,中文文档不需要使用babel或者polyglossia。 因此默认本地化语言是英文,反正中文处理是另一套体系,所以并没有多大影响。

现在的关键问题是biblatex功能过多,导致问题复杂化,如果简单的借用原来bibtex的思路,那么是可以给出一定的设定的。

目前biblatex参考文献标题的修改主要有三种方式:

  1. 重定义标题,biblatex本身就是这么做的。 在biblatex打印参考文献命令\printbibliography中有一个选项是heading, 默认情况下值为bibliography,使用bibliography标题,该标题有一个可选参数\bibname,一种简单定义如下:
\defbibheading{bibliography}[\bibname]{%
\chapter*{#1}%
\markboth{#1}{#1}}

一般情况下这个标题会读取一个参数作为标题内容,该参数缺省时就把\bibname作为标题内容这可以从下面代码中看出:

% {<name>}[<default>]{<code>}
\newrobustcmd*{\defbibheading}[1]{%
  \@ifnextchar[%]
    {\blx@defbibheading{blx@head@#1}}
    {\blx@defbibheading{blx@head@#1}[\bibname]}}

\def\blx@defbibheading#1[#2]{%
  \csundef{#1}%
  \expandafter\newcommand\csname#1\endcsname[1][#2]}

理论上似乎我们重定义\bibname就可以得到需要的标题内容,但实际上biblatex对\bibname做了特殊的处理:

% {<language>}{<strings>}
\newrobustcmd*{\DefineBibliographyStrings}[2]{%
  \blx@lbxcheck{#1}%
  \csgappto{blx@hook@strings@#1}{%
    \begingroup
    \let\blx@defstring\blx@cfg@defstring
    \blx@defbibstrings{#1}{#2}%
    \endgroup}}
\@onlypreamble\DefineBibliographyStrings

\def\blx@defbibstrings#1#2{%
  \def\do##1{\csundef{abx@lstr@##1}\csundef{abx@sstr@##1}}%
  \abx@dostrings
  \csuse{abx@strings@#1}%
  \setkeys{blx@lbx}{#2}%
  \let\do\blx@defbibstrings@i
  \csxdef{abx@strings@#1}{\abx@dostrings}%
  \csgappto{abx@strings@#1}{%
    \ifcsdef{\abx@str @bibliography}
      {\letcs\bibname{\abx@str @bibliography}}
      {\let\bibname\@empty}%
    \ifcsdef{\abx@str @references}
      {\letcs\refname{\abx@str @references}}
      {\let\refname\@empty}%
    \ifcsdef{\abx@str @shorthands}
      {\letcs\biblistname{\abx@str @shorthands}}
      {\let\biblistname\@empty}}}

biblatex把\bibname与本地化字符串做了关联,这个处理是在文档开始处完成的,看如下例子:

\documentclass[twoside]{ctexbook}%article
    \usepackage{xcolor}
    \usepackage{hyperref}
    \usepackage{lipsum}
    \usepackage[top=10pt,bottom=10pt,left=10pt,right=10pt]{geometry}

\usepackage[backend=biber,style=gb7714-2015]{biblatex}

\DefineBibliographyStrings{english}{
  bibliography = {ckwx},
  references   = {ckwx},
}

    \usepackage{filecontents}
    \begin{filecontents}{\jobname.bib}
   @REPORT{calvo2006phoenix,
  AUTHOR = {Calvo, Guillermo A and Izquierdo, Alejandro and Talvi, Ernesto},
  INSTITUTION = {National Bureau of Economic Research},
  DATE = {2006},
  KEYWORDS = {calvo2006phoenix},
  TITLE = {Phoenix miracles in emerging markets: recovering without credit from systemic financial crises},
}
    \end{filecontents}
    \addbibresource{\jobname.bib}
    %

%\ctexset{
%bibname ={文\quad 献}
%}
%

\show\bibname
\newcommand{\bibname}{文\quad 献}
\show\bibname

    \begin{document}

    %\meaning\bibname
    \show\bibname
    文献\nocite{*}
    \meaning\bibname
    \renewcommand{\bibname}{文\quad 献}
    \meaning\bibname
    \show\bibname

    \printbibliography%[title=参考文献]

    \end{document} 

因此说在导言区中做bibname重定义时没有效果的。

此外,还有其他的一些问题。假设用户仅使用这种默认设置,那么重定义参考文献标题是可以考虑的。比如:

\defbibheading{bibliography}{%
\chapter*{参考文献}%
\markboth{参考文献}{参考文献}}

这种方式直接避开了bibname宏处理问题,注意:对于article类(区别于book和report)是\refname宏。

但如果用户有其它选择,比如要用\printshorthands打印一个缩略表,那么就要重定义一个shorthands的标题。 如果用户还要用\printbiblist打印一些参考文献信息的缩略表,那么还要定义对应的标题。 而且如果用户还要使用heading=subbibliography等对应不同层级标题格式的设置,那么还要定义subbibliography。

当然通常情况下,一般用户用不了这么多功能,因此只需要重定义bibliography就行了。

当然如果仅需要修改标题的内容,那么还有如下两种方式:

  1. 直接在\printbibliography命令中给出标题的内容,比如:
\printbibliography[title=参考文献]

那么该标题‘参考文献’会作为上述bibname定义宏中的#1传递给它,进而自动成为参考标题内容。如果不给出该选项,那么就会使用本地化字符串来做#1,即前面说过的 ,将本地化字符串处理为\bibname,因此修改标题内容就是要修改本地化字符串的值:

  1. 修改本地化字符串就是第三种方式:
\DefineBibliographyStrings{english}{
  bibliography = {参考文献},
  references   = {参考文献},
}

从一般用户的角度看可能使用一个\printbibliography命令就够了,那么这时可以修改本地化字符串,也可以重定义bibliography标题。 直接重定义bibliography标题避开bibname宏处理是比较简单的方法。

另外因为biblatex的特殊性,其实可以考虑不在沿用以前bibtex的模式,非要定义一个bibname来设置参考文献标题。 因为biblatex定义标题内容的方式是很灵活的。

供探讨。

hushidong commented 6 years ago

当然,如果要用bibname的话,可以做一个简单的反处理,即重定义

\def\blx@defbibstrings#1#2{%
  \def\do##1{\csundef{abx@lstr@##1}\csundef{abx@sstr@##1}}%
  \abx@dostrings
  \csuse{abx@strings@#1}%
  \setkeys{blx@lbx}{#2}%
  \let\do\blx@defbibstrings@i
  \csxdef{abx@strings@#1}{\abx@dostrings}%
  }

这样直接使用ctexset就没有问题了。

比如

\ctexset{
bibname={文献}
}

\printbibliography
hushidong commented 6 years ago

示例为:

\documentclass[twoside]{ctexbook}%article
    \usepackage{xcolor}
    \usepackage{hyperref}
    \usepackage{etoolbox}
    \usepackage{lipsum}
    \usepackage[top=10pt,bottom=10pt,left=10pt,right=10pt]{geometry}

\usepackage[backend=biber,style=gb7714-2015]{biblatex}

\makeatletter
\def\blx@defbibstrings#1#2{%
  \def\do##1{\csundef{abx@lstr@##1}\csundef{abx@sstr@##1}}%
  \abx@dostrings
  \csuse{abx@strings@#1}%
  \setkeys{blx@lbx}{#2}%
  \let\do\blx@defbibstrings@i
  \csxdef{abx@strings@#1}{\abx@dostrings}%
}
\makeatother

\defbibheading{bibliography}[\bibname]{%
\section*{#1}}

\DefineBibliographyStrings{english}{
  bibliography = {ckwx},
  references   = {ckwx},
}

    \usepackage{filecontents}
    \begin{filecontents}{\jobname.bib}
   @REPORT{calvo2006phoenix,
  AUTHOR = {Calvo, Guillermo A and Izquierdo, Alejandro and Talvi, Ernesto},
  INSTITUTION = {National Bureau of Economic Research},
  DATE = {2006},
  KEYWORDS = {calvo2006phoenix},
  TITLE = {Phoenix miracles in emerging markets: recovering without credit from systemic financial crises},
}
    \end{filecontents}
    \addbibresource{\jobname.bib}
    %

    \begin{document}
    cite:\nocite{*}
    ctexbook类的默认设置:\meaning\bibname
    \printbibliography

    \renewcommand{\bibname}{文\quad 献}
    重定义bibname设置:\meaning\bibname
    \printbibliography

    \ctexset{
    bibname ={ctexckwx}
    }
    ctexset对bibname设置:\meaning\bibname
    \printbibliography

    \csgdef{bibname}{refs}
    \meaning\bibname
    \csgdef{bibnamea}{refa}
    \cslet{bibname}{\bibnamea}
    \meaning\bibname
    \csgdef{bibnameb}{refb}
    \letcs\bibname{bibnameb}
    \meaning\bibname
    \renewrobustcmd*{\bibname}{references}

    etoolbox的命令对bibname设置:\meaning\bibname
    \printbibliography

    \end{document} 

这种方式保留了使用printbibliography的title选项设置标题内容的方式, 去除了使用本地化字符串设置的方式, 但获得了利用ctexset设置的途径,有得有失,但对中文用户来说也不失为更好的选择。