Punctuations rules in multilingual bilbiography

babelbiblatex

I would like a (biblatex) bibliography where:

  • The language of the bibliography is always the same, regardless of the language of the entry. I do not want translation or localization of things like: page or volume number, translator or editor data, author's name layout…
  • The title of the entries follow the punctuation spacing rules of the language of the entry. Typically: no space before ? in english, unbreakable space before ? in french.

I've tested various combinations of language and autolang parameters for biblatex, whitout success so far.
For example in the MWE below:

  • autolang=other
    • correct punctuation spacing to switch punctuation rules, following the langid of each entry.
    • unwanted localization like: "Trans. by"/"Trad. par", "p."/"pp.", small capital or not for the name of the author…
  • autolang=hyphen
    • correct single language for the bibliography ("Trad. par" in both cases)
    • incorrect typography: the space before ? is missing in french.
\documentclass{article}
\usepackage[english,french]{babel}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{filecontents}

\begin{filecontents}{biblio.bib}
@book{compagnon,
  author     = {Compagnon, Antoine},
  translator = {Même, Moi},
  date       = {1998},
  title      = {Titre: aléatoire?},
  pages      = {306-723},
  langid     = {french},
}
@book{glashow,
  author       = {Glashow, Sheldon},
  title        = {Random: title?},
  translator   = {Self, My},
  date         = {1961},
  pages        = {579-588},
  langid       = {english},
}
\end{filecontents}

\usepackage[backend=biber,
    style=verbose-trad2,
    singletitle=true,
    autolang=other,
]{biblatex}  
\addbibresource{biblio.bib}

\begin{document}
\footcite{compagnon}
\footcite{glashow}
\printbibliography
\end{document}

Potential close questions:

  • Adding \foreignlanguage{...} in the title field is often suggested. I can't find again a very didactic post from user moewe explaining that biblatex does not have a per-field language options and presenting distinct strategies.
  • Correct punctuation, but with unwanted localisation at the entry level.
  • Correct hyphenation, but not the punctuation rules.
  • Potential solution in lualatex? Not sure to understand why it should be different.

Best Answer

As discussed in https://github.com/plk/biblatex/issues/757 and Change language on a per field basis, part 2: Fonts, case transformation and sorting this is pretty tricky and would ideally be addressed in the biblatex core. But that needs a lot of groundwork that still is being worked on.

Here is a babel version of the polyglossia-based answer to Change language on a per field basis, part 2: Fonts, case transformation and sorting that should get you a little further.

\documentclass{article}
\usepackage[english,french]{babel}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}

\usepackage[backend=biber,
    style=verbose-trad2,
    singletitle=true,
]{biblatex}

\makeatletter
\def\blx@thefakelangenv{otherlanguage}%

\def\blx@beglang@fake{%
  \blx@clearlang
  \begingroup
  \ifdef\abx@field@langid
    {\def\blx@endlang@fake{%
       \end{otherlanguage*}%
       \endgroup}%
     \begin{otherlanguage*}{\abx@field@langid}}
    {}}

\let\blx@endlang@fake\relax

\renewrobustcmd*{\blx@imc@printfield}[2][]{%
  \blx@imc@iffieldundef{#2}
    {\blx@nounit}
    {\blx@getformat\blx@theformat{ffd}{#1}{#2}%
     \ifdefvoid\blx@theformat
       {\blx@nounit}
       {\blx@begunit
        \let\blx@theformat@outer\blx@theformat
        \def\blx@theformat##1{\blx@theformat@outer{\blx@beglang@fake ##1\blx@endlang@fake}}%
        \edef\currentfield{#2}%
        \expandafter\expandafter
        \expandafter\blx@theformat
        \expandafter\expandafter
        \expandafter{\csname abx@field@#2\endcsname}%
        \blx@endunit}}}

\long\def\blx@nameparser@i#1#2{%
  \begingroup
  \ifblank{#1}
    {}
    {\setkeys{blx@opt@name}{#1}}%
  \setkeys{blx@opt@namepart}{#2}%
  \blx@beglang@fake\blx@theformat{#2}\blx@endlang@fake
  \endgroup}

\long\def\blx@listparser#1{%
  \ifblank{#1}
    {\blx@listbreak}
    {\ifnum\c@listcount<\c@liststart
     \else
       \blx@beglang@fake\blx@theformat{#1}\blx@endlang@fake
     \fi
     \advance\c@listcount\@ne
     \ifnum\c@listcount>\c@liststop
       \expandafter\blx@listbreak
     \fi
     \blx@listparser}}
\makeatother


\begin{filecontents}{\jobname.bib}
@book{compagnon,
  author     = {Compagnon, Antoine and Someone Else},
  translator = {Même, Moi},
  date       = {1998},
  title      = {Titre: aléatoire?},
  pages      = {306-723},
  langid     = {french},
}
@book{glashow,
  author       = {Glashow, Sheldon and Someone Else},
  title        = {Random: title?},
  translator   = {Self, My},
  date         = {1961},
  pages        = {579-588},
  langid       = {english},
}
\end{filecontents} 
\addbibresource{\jobname.bib}

\begin{document}
\footcite{compagnon}
\footcite{glashow}
\printbibliography
\end{document}

"Compagnon, Antoine et Someone Else. Titre : aléatoire ? Trad. par Moi Même. 1998, 306-723." (with space before colon and question mark)
"Glashow, Sheldon et Someone Else. Random: title? Trad. par My Self. 1961, 579-588." (without space before colon and question mark)


As discussed in the comments, this approach has some shortcomings, because it is not always desirable to have the language switching code applied to the field contents directly.

I cannot offer a good alternative approach, since changing the language after field formats etc. have been applied effects bibstrings (which are supposed to stay the same). What I can offer is an ad-hoc solution that allows you to exempt certain fields from the language switching (you can of course reverse the logic to have language switching only for certain fields if that works better for you).

\documentclass{article}
\usepackage[english,french]{babel}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}

\usepackage[backend=biber,
    style=verbose-trad2,
    singletitle=true,
]{biblatex}

\makeatletter
\newcommand*{\mblx@exemptfields}{}
\newrobustcmd*{\ExemptFromLanguageSwitching}{%
  \forcsvlist{\listgadd\mblx@exemptfields}}

\def\blx@thefakelangenv{otherlanguage}%

\def\blx@beglang@fake{%
  \blx@clearlang
  \begingroup
  \ifdef\abx@field@langid
    {\def\blx@endlang@fake{%
       \end{otherlanguage*}%
       \endgroup}%
     \begin{otherlanguage*}{\abx@field@langid}}
    {}}

\let\blx@endlang@fake\relax

\renewrobustcmd*{\blx@imc@printfield}[2][]{%
  \blx@imc@iffieldundef{#2}
    {\blx@nounit}
    {\blx@getformat\blx@theformat{ffd}{#1}{#2}%
     \ifdefvoid\blx@theformat
       {\blx@nounit}
       {\blx@begunit
        \ifinlist{#2}{\mblx@exemptfields}
          {}
          {\let\blx@theformat@outer\blx@theformat
           \def\blx@theformat##1{\blx@theformat@outer{\blx@beglang@fake ##1\blx@endlang@fake}}}%
        \edef\currentfield{#2}%
        \expandafter\expandafter
        \expandafter\blx@theformat
        \expandafter\expandafter
        \expandafter{\csname abx@field@#2\endcsname}%
        \blx@endunit}}}


\catcode`\&=3
\def\blx@printnames#1#2#3#4{%
  \blx@imc@ifnameundef{#4}
    {\blx@nounit}
    {\def\mblx@currentname{#4}%
     \blx@getformat\blx@thewrapperformat{nwd}{#1}{#4}%
     \ifdefvoid\blx@thewrapperformat
       {\blx@nounit}
       {\blx@getformat\blx@theformat{nfd}{#1}{#4}%
        \ifdefvoid\blx@theformat
          {\blx@nounit}
          {\blx@begunit
           \blx@namesetup{#2}{#3}{#4}%
           \blx@thewrapperformat{\expandafter\blx@nameparser\blx@thedata{}&}%
           \blx@endunit}}}}

\def\blx@indexnames#1#2#3#4{%
  \blx@imc@ifnameundef{#4}
    {}
    {\def\mblx@currentname{#4}%
     \blx@getformat\blx@theformat{nid}{#1}{#4}%
     \ifdefvoid\blx@theformat
       {}
       {\begingroup
        \blx@namesetup{#2}{#3}{#4}%
        \blx@indexnamesetup
        \expandafter\blx@nameparser\blx@thedata{}&%
        \endgroup}}}

\long\def\blx@nameparser@i#1#2{%
  \begingroup
  \ifblank{#1}
    {}
    {\setkeys{blx@opt@name}{#1}}%
  \setkeys{blx@opt@namepart}{#2}%
  \expandafter\ifinlist\expandafter{\mblx@currentname}{\mblx@exemptfields}
    {\blx@theformat{#2}}
    {\blx@beglang@fake\blx@theformat{#2}\blx@endlang@fake}%
  \endgroup}


\def\blx@printlist#1#2#3#4{%
  \blx@imc@iflistundef{#4}
    {\blx@nounit}
    {\def\mblx@currentlist{#4}%
     \blx@getformat\blx@thewrapperformat{lwd}{#1}{#4}%
     \ifdefvoid\blx@thewrapperformat
       {\blx@nounit}
       {\blx@getformat\blx@theformat{lfd}{#1}{#4}%
        \ifdefvoid\blx@theformat
          {\blx@nounit}
          {\blx@begunit
           \blx@listsetup{#2}{#3}{#4}%
           \blx@thewrapperformat{\expandafter\blx@listparser\blx@thedata{}&}%
           \blx@endunit}}}}

\def\blx@indexlist#1#2#3#4{%
  \blx@imc@iflistundef{#4}
    {}
    {\def\mblx@currentlist{#4}%
     \blx@getformat\blx@theformat{lid}{#1}{#4}%
     \ifdefvoid\blx@theformat
       {}
       {\begingroup
        \blx@listsetup{#2}{#3}{#4}%
        \expandafter\blx@listparser\blx@thedata{}&%
        \endgroup}}}

\long\def\blx@listparser#1{%
  \ifblank{#1}
    {\blx@listbreak}
    {\ifnum\c@listcount<\c@liststart
     \else
       \expandafter\ifinlist\expandafter{\mblx@currentlist}{\mblx@exemptfields}
         {\blx@theformat{#1}}
         {\blx@beglang@fake\blx@theformat{#1}\blx@endlang@fake}%
     \fi
     \advance\c@listcount\@ne
     \ifnum\c@listcount>\c@liststop
       \expandafter\blx@listbreak
     \fi
     \blx@listparser}}
\makeatother
\catcode`\&=4

\ExemptFromLanguageSwitching{url,doi,eprint,pages}


\begin{filecontents}[force]{\jobname.bib}
@book{compagnon,
  author     = {Compagnon, Antoine and Someone Else},
  translator = {Même, Moi},
  date       = {1998},
  title      = {Titre: aléatoire?},
  pages      = {306-723},
  langid     = {french},
  url        = {https://example.com/~stuff/more.pdf},
}
@book{glashow,
  author       = {Glashow, Sheldon and Someone Else},
  title        = {Random: title?},
  translator   = {Self, My},
  date         = {1961},
  pages        = {579-588},
  langid       = {english},
  url          = {https://example.com/~stuff/more.pdf},
}
\end{filecontents} 
\addbibresource{\jobname.bib}

\begin{document}
\footcite{compagnon}
\footcite{glashow}
\printbibliography
\end{document}
Related Question