plk / biblatex

biblatex is a sophisticated bibliography system for LaTeX users. It has considerably more features than traditional bibtex and supports UTF-8
507 stars 115 forks source link

BibLaTeX does not convert titles to sentence case #1008

Open RalfJung opened 4 years ago

RalfJung commented 4 years ago

I would like biblatex to translate the titles of the documents I cite to sentence case. In fact, the documentation says that that is the default behavior:

By default, converting to sentence case is enabled for the following language identifiers: american, british, canadian, english, australian, newzealand as well as the aliases USenglish and UKenglish. Use \DeclareCaseLangs to extend or change this list.

However, in my (english) document, conversion for some reason does not happen:

\documentclass[11pt,a4paper,english]{article}
\usepackage[english]{babel}
\usepackage{csquotes}
\usepackage[backend=biber,maxbibnames=10]{biblatex}

\addbibresource{../bib.bib}

% metadata
\title{Title}

\begin{document}

\maketitle

% {\input{intro}}
% {\input{iris}}
% {\input{rust}}
% {\input{stacked-borrows}}
% {\input{timeline}}

This is the text~\cite{hur+:popl12}.

\printbibliography

\end{document}

This is the relevant entry in the bib.bib:

@InProceedings{hur+:popl12,
  author =   {Chung-Kil Hur and Derek Dreyer and Georg Neis and Viktor Vafeiadis},
  title =    {The Marriage of Bisimulations and {Kripke} Logical Relations},
  booktitle = {{POPL}},
  year =     {2012},
}

I have now tried for almost an hour to make biblatex convert capitalization like bibtex did, with no success whatsoever. I tired biber and bibtex, and adding various versions of the following macro:

\DeclareFieldFormat[article]{titlecase}{\MakeSentenceCase{#1}}

This is using TexLive 2020.20200417-1 as packaged in Debian.

moewew commented 4 years ago

With your example entry, which is an @inproceedings,

\DeclareFieldFormat[article]{titlecase}{\MakeSentenceCase{#1}}

won't do anything, since it only affects @articles.

Note that it is generally preferred to use the starred form \MakeSentenceCase*{#1} instead of \MakeSentenceCase{#1}.

The following affects all entry types whose titles are typeset in quotation marks.

\documentclass[11pt,a4paper,english]{article}
\usepackage[english]{babel}
\usepackage{csquotes}
\usepackage[backend=biber,maxbibnames=10]{biblatex}

\DeclareFieldFormat
  [article,inbook,incollection,inproceedings,patent,thesis,unpublished]
  {titlecase}{\MakeSentenceCase*{#1}}

\begin{filecontents}{\jobname.bib}
@InProceedings{hur+:popl12,
  author    = {Chung-Kil Hur and Derek Dreyer and Georg Neis and Viktor Vafeiadis},
  title     = {The Marriage of Bisimulations and {Kripke} Logical Relations},
  booktitle = {Principles of Programming Languages {(POPL)}},
  year      = {2012},
}
\end{filecontents}
\addbibresource{\jobname.bib}

\begin{document}
This is the text~\cite{hur+:popl12}.

\printbibliography
\end{document}

Note that this applies sentence casing to all title-like fields (that's why I added a little more text to the booktitle field).

For finer control you can use biblatex-ext's field formats

\documentclass[11pt,a4paper,english]{article}
\usepackage[english]{babel}
\usepackage{csquotes}
\usepackage[backend=biber,style=ext-numeric,maxbibnames=10]{biblatex}

\DeclareFieldFormat
  [article,inbook,incollection,inproceedings,patent,thesis,unpublished]
  {titlecase:title}{\MakeSentenceCase*{#1}}

\begin{filecontents}{\jobname.bib}
@InProceedings{hur+:popl12,
  author    = {Chung-Kil Hur and Derek Dreyer and Georg Neis and Viktor Vafeiadis},
  title     = {The Marriage of Bisimulations and {Kripke} Logical Relations},
  booktitle = {Principles of Programming Languages {(POPL)}},
  year      = {2012},
}
\end{filecontents}
\addbibresource{\jobname.bib}

\begin{document}
This is the text~\cite{hur+:popl12}.

\printbibliography
\end{document}
RalfJung commented 4 years ago

EDIT: you posted while I was still experimenting; will respond to that next.

Turns out this helps:

% "titlecase" applies not just to "title" fields but also "booktitle"
% and friends, so we need a clever macro to adjust capitalization.
\newrobustcmd{\MakeTitleCase}[1]{%
  \ifthenelse{\ifcurrentfield{title}}%
    {\MakeSentenceCase{#1}}%
    {#1}}
\DeclareFieldFormat{titlecase}{\MakeTitleCase{#1}}

However, it only helps for the blbliography as well. I am using "authortitle" citation style, and that one is still capitalized the wrong way.

moewew commented 4 years ago

Just an aside. The quoted passage from the documentation needs to be read in context. It means that if \MakeSentenceCase* is used, it will apply sentence casing to its input in case said input is in one of the languages from that list. Your style will still have to actually use \MakeSentenceCase* (ideally in the titlecase field) for any sentence case to be applied. The standard styles don't deploy \MakeSentenceCase*, so they don't use sentence casing by default.

moewew commented 4 years ago

Citations use a different field format for titles called citetitle. You'll have to redefine that as well. Again with biblatex-ext

\documentclass[11pt,a4paper,english]{article}
\usepackage[english]{babel}
\usepackage{csquotes}
\usepackage[backend=biber,style=ext-authortitle,maxbibnames=10]{biblatex}

\DeclareFieldFormat
  [article,inbook,incollection,inproceedings,patent,thesis,unpublished]
  {titlecase:title}{\MakeSentenceCase*{#1}}

\DeclareFieldFormat
  [article,inbook,incollection,inproceedings,patent,thesis,unpublished]
  {citetitle}{\mkbibquote{\MakeSentenceCase*{#1}\isdot}}

\begin{filecontents}{\jobname.bib}
@InProceedings{hur+:popl12,
  author    = {Chung-Kil Hur and Derek Dreyer and Georg Neis and Viktor Vafeiadis},
  title     = {The Marriage of Bisimulations and {Kripke} Logical Relations},
  booktitle = {Principles of Programming Languages {(POPL)}},
  year      = {2012},
}
\end{filecontents}
\addbibresource{\jobname.bib}

\begin{document}
This is the text~\autocite{hur+:popl12}.

\printbibliography
\end{document}

Or with your approach.

\documentclass[11pt,a4paper,english]{article}
\usepackage[english]{babel}
\usepackage{csquotes}
\usepackage[backend=biber,style=authortitle,maxbibnames=10]{biblatex}

% "titlecase" applies not just to "title" fields but also "booktitle"
% and friends, so we need a clever macro to adjust capitalization.
\newrobustcmd{\MakeTitleCase}[1]{%
  \ifthenelse{\ifcurrentfield{title}}%
    {\MakeSentenceCase{#1}}%
    {#1}}
\DeclareFieldFormat{titlecase}{\MakeTitleCase{#1}}

\DeclareFieldFormat{citetitle}{\mkbibemph{\MakeSentenceCase{#1}}}
\DeclareFieldFormat
  [article,inbook,incollection,inproceedings,patent,thesis,unpublished]
  {citetitle}{\mkbibquote{\MakeSentenceCase{#1}\isdot}}
\DeclareFieldFormat
  [suppbook,suppcollection,suppperiodical]
  {citetitle}{\MakeSentenceCase{#1}}

\begin{filecontents}{\jobname.bib}
@InProceedings{hur+:popl12,
  author    = {Chung-Kil Hur and Derek Dreyer and Georg Neis and Viktor Vafeiadis},
  title     = {The Marriage of Bisimulations and {Kripke} Logical Relations},
  booktitle = {Principles of Programming Languages {(POPL)}},
  year      = {2012},
}
\end{filecontents}
\addbibresource{\jobname.bib}

\begin{document}
This is the text~\autocite{hur+:popl12}.

\printbibliography
\end{document}

This is necessary for two reasons

  1. titlecase does not apply to citations, there only citetitle is used.
  2. In citations \currentfield would generally be labeltitle not title, so \MakeTitleCase wouldn't do the right thing.
RalfJung commented 4 years ago

@moewew thanks for the quick response!

The following affects all entry types whose titles are typeset in quotation marks.

This actually relates to another question I have, I am struggling to make titles for papers (in proceedings), books, and PhD thesis render consistently. Currently some are italic and some are in quotes, which does not look great.

Note that it is generally preferred to use the starred form \MakeSentenceCase*{#1} instead of \MakeSentenceCase{#1}.

I read that the starred form is smarter and since my recent experience with LaTeX smartness is to avoid it, I decided to experiment with the un-starred version first. ;)

For finer control you can use biblatex-ext's field formats

Interesting, I never heard of "biblatex-ext" before. My main document uses "alphabetic" bib style, so I switched to "ext-alphabetic" and added

\DeclareFieldFormat{titlecase:title}{\MakeSentenceCase*{#1}}

And that also seems to work. :) Those ext- style are not mentioned in the docs though, it seems?

Just an aside. The quoted passage from the documentation needs to be read in context. It means that if \MakeSentenceCase is used, it will apply sentence casing to its input in case said input is in one of the languages from that list. Your style will still have to actually use \MakeSentenceCase (ideally in the titlecase field) for any sentence case to be applied. The standard styles don't deploy \MakeSentenceCase*, so they don't use sentence casing by default.

Oh I see. I misinterpreted that footnote then, thanks for the clarification.

RalfJung commented 4 years ago

Citations use a different field format for titles called citetitle. You'll have to redefine that as well. Again with biblatex-ext

Ah, I see! Indeed this works with "ext-authortitle", thanks a lot. For my main document I have my own fork of the "authoryear" cite style, so I guess I'll need to figure out how to adjust that appropriately.

EDIT: ah the 2nd version you posted works with my custom style. :-)

RalfJung commented 4 years ago

After some more experimentation, I figured out how to also make all title fields consistently use quotes (instead of some being italic). This is what I ended up with:

% This requires using the "ext-" variant of the bib style.
\DeclareFieldFormat{titlecase:title}{\MakeSentenceCase*{#1}}
\DeclareFieldFormat{title}{\mkbibquote{#1\isdot}}
% Also use sentence case in citations.
\DeclareFieldFormat{citetitle}{\mkbibquote{\MakeSentenceCase{#1}\isdot}}
% Looks like setting it for all entry types is not enough, we need to
% specifically overwrite these to make it stick.
\DeclareFieldFormat
  [article,inbook,incollection,inproceedings,patent,thesis,unpublished]
  {citetitle}{\mkbibquote{\MakeSentenceCase{#1}\isdot}}
\DeclareFieldFormat
  [suppbook,suppcollection,suppperiodical]
  {citetitle}{\MakeSentenceCase{#1}}

I hope that's not too gross. ;) Thanks again for all your quick help!

(I feel I must be missing something as it seems like quite a lot of work to re-obtain what was the default behavior in bibtex -- but well, it works for me now. :D )

moewew commented 4 years ago

The following affects all entry types whose titles are typeset in quotation marks.

This actually relates to another question I have, I am struggling to make titles for papers (in proceedings), books, and PhD thesis render consistently. Currently some are italic and some are in quotes, which does not look great.

There is some method in the madness. Roughly speaking titles of stand-alone works (works that are not a direct - often physical - part of 'container' works) are typeset in italics, whereas works that are part of a stand-alone 'container' have their title set in quotation marks. A rule of thumb is that if you walk through a physical library and can see the title without opening the book, that title will probably end up being printed in italics, but if you have to open the book and go to the table of contents or somewhere else that is not the title page to find the title, it is probably going to be printed in quotation marks.

This is not something Philipp Lehman, the original author of biblatex, plucked out of thin air, it is found in prescriptive styles such as APA style (compare the guidance for books [stand-alone work, title italics] https://apastyle.apa.org/style-grammar-guidelines/references/examples/book-references with the guidance for articles and chapters in books [contained works, title without special formatting, but journal and book title are again in italics, because they are stand-alone] https://apastyle.apa.org/style-grammar-guidelines/references/examples/journal-article-references, https://apastyle.apa.org/style-grammar-guidelines/references/examples/edited-book-chapter-references) or Chicago Style (https://www.chicagomanualofstyle.org/tools_citationguide/citation-guide-1.html). And the standard BibTeX styles plain and friends also behave broadly like this.

Of course types such as @online, @unpublished, @misc, @patent are not that easy to force into this dichotomy, so there could be some disagreement about what to do with those. I'm not sure if I could find a justification for why biblatex's standard settings make sense for all of those.

But anyway, this is something you can change. If you want the title of all types to be formatted the same, just say

\DeclareFieldFormat*{title}{\mkbibemph{#1}}

See also https://tex.stackexchange.com/q/462133/35864 on TeX.SX with more code examples.

Note that it is generally preferred to use the starred form \MakeSentenceCase*{#1} instead of \MakeSentenceCase{#1}.

I read that the starred form is smarter and since my recent experience with LaTeX smartness is to avoid it, I decided to experiment with the un-starred version first. ;)

Of course here I have to point out that there is no reason to avoid biblatex's smartness :-)

For finer control you can use biblatex-ext's field formats

Interesting, I never heard of "biblatex-ext" before. My main document uses "alphabetic" bib style, so I switched to "ext-alphabetic" and added

\DeclareFieldFormat{titlecase:title}{\MakeSentenceCase*{#1}}

And that also seems to work. :) Those ext- style are not mentioned in the docs though, it seems?

Ah no, it's not mentioned in the docs. The biblatex-ext styles are my own pet project. They are drop-in replacements for the standard styles with a few added features that I found useful (either because I liked them myself or because they come in handy when answering style questions in various forums), but that for some reason or other didn't feel as though they should be included in the biblatex standard styles.

For the standard styles we need to be very careful when changing and adding stuff, because many contributed styles on CTAN and countless preambles are based on their code. Plus, the idea is that the standard styles should be easy to customise and be an example of biblatex coding, so we can't overload them with too much stuff. In biblatex-ext I have more freedom to just add stuff, because I don't have to worry about almost all contributed styles relying on my code base and about maintaining the 'example style'.


After some more experimentation, I figured out how to also make all title fields consistently use quotes (instead of some being italic). This is what I ended up with:

% This requires using the "ext-" variant of the bib style.
\DeclareFieldFormat{titlecase:title}{\MakeSentenceCase*{#1}}
\DeclareFieldFormat{title}{\mkbibquote{#1\isdot}}
% Also use sentence case in citations.
\DeclareFieldFormat{citetitle}{\mkbibquote{\MakeSentenceCase{#1}\isdot}}
% Looks like setting it for all entry types is not enough, we need to
% specifically overwrite these to make it stick.
\DeclareFieldFormat
  [article,inbook,incollection,inproceedings,patent,thesis,unpublished]
  {citetitle}{\mkbibquote{\MakeSentenceCase{#1}\isdot}}
\DeclareFieldFormat
  [suppbook,suppcollection,suppperiodical]
  {citetitle}{\MakeSentenceCase{#1}}

I hope that's not too gross. ;) Thanks again for all your quick help!

Looks good. But if you want all titles in quotes,

% This requires using the "ext-" variant of the bib style.
\DeclareFieldFormat{titlecase:title}{\MakeSentenceCase*{#1}}
\DeclareFieldFormat*{title}{\mkbibquote{#1\isdot}}
\DeclareFieldFormat*{citetitle}{\mkbibquote{\MakeSentenceCase{#1}\isdot}}

would be easier. As you found out type-specific field formats will prevail, so you will have to overwrite them separately or you have to use the starred version \DeclareFieldFormat* to clear out type-specific formatting beforehand (cf. also my comments above). (That actually requires knowing how the field formats are set up in biblatex.def. For the vast majority of fields there are no type-specific formats, but title is one example where different types have different formatting.)

(I feel I must be missing something as it seems like quite a lot of work to re-obtain what was the default behavior in bibtex -- but well, it works for me now. :D )

Well, biblatex is not BibTeX and some things just look different in the standard setup. So sometimes some work is required to make biblatex behave the same way standard BibTeX styles did. You may want to check out how much code you'd need to get plain.bst to stop

RalfJung commented 4 years ago

There is some method in the madness. Roughly speaking titles of stand-alone works (works that are not a direct - often physical - part of 'container' works) are typeset in italics, whereas works that are part of a stand-alone 'container' have their title set in quotation marks. A rule of thumb is that if you walk through a physical library and can see the title without opening the book, that title will probably end up being printed in italics, but if you have to open the book and go to the table of contents or somewhere else that is not the title page to find the title, it is probably going to be printed in quotation marks.

I am sure there were good reasons when this was introduced. :) But in my community (where no style guide mandates anything like that) and in a time where I am unlikely to be actually physically looking for citations in a library, the consequence is that my citations and bibliography are a seemingly-random mix of quoted and italic titles. That just does not look good.

DeclareFieldFormat*{title}{\mkbibemph{#1}}

Ah, the starred version to overwrite the field variants is the final piece that I missed! I will explore how to simplify my code with this, thanks for the pointer.

In biblatex-ext I have more freedom to just add stuff, because I don't have to worry about almost all contributed styles relying on my code base and about maintaining the 'example style'.

Now I am a bit worried that my document will stop compiling properly when I upgrade my TexLive...^^

You may want to check out how much code you'd need to get plain.bst to stop

("to stop applying sentence capitalization", I assume)

That's actually documented in the bst file, at least for the most common template in my community:

FUNCTION { format.articletitle }
{
  title empty.or.unknown
    { "" }
    % Use this to preserve lettercase in titles:
    { "\showarticletitle{" title * "}" * }
    % Use this for downcase title style:
    % { \showarticletitle{" title "t" change.case$ * "}" * }
  if$
}

source

moewew commented 4 years ago

In biblatex-ext I have more freedom to just add stuff, because I don't have to worry about almost all contributed styles relying on my code base and about maintaining the 'example style'.

Now I am a bit worried that my document will stop compiling properly when I upgrade my TexLive...^^

I knew I shouldn't have said that... I'm trying to be good about backwards compatibility also in biblatex-ext, but the stakes are not as high (and I can respond more quickly, because the release process is not as complex as with biblatex - it's not tied to Biber binary building etc.). As long as you are doing reasonably things with the usual interfaces, you should be fine. But if there is one thing I have learned playing around with LaTeX then that is that almost every change (however useful or well-meant) has the potential to break people's code.

You may want to check out how much code you'd need to get plain.bst to stop

("to stop applying sentence capitalization", I assume)

That's actually documented in the bst file, at least for the most common template in my community:

FUNCTION { format.articletitle }
{
  title empty.or.unknown
    { "" }
    % Use this to preserve lettercase in titles:
    { "\showarticletitle{" title * "}" * }
    % Use this for downcase title style:
    % { \showarticletitle{" title "t" change.case$ * "}" * }
  if$
}

source

Yeah, forget that last sentence. I wanted to mention that it can be tricky to modify BibTeX styles as well and that about 10 lines of code are not as bad. But then I decided not to (because in the example at hand, you'd not need a lot of changes to plain.bst once you understand how the BibTeX language works) and forget to remove the sentence fragment.

RalfJung commented 4 years ago

I knew I shouldn't have said that... I'm trying to be good about backwards compatibility also in biblatex-ext, but the stakes are not as high (and I can respond more quickly, because the release process is not as complex as with biblatex - it's not tied to Biber binary building etc.). As long as you are doing reasonably things with the usual interfaces, you should be fine. But if there is one thing I have learned playing around with LaTeX then that is that almost every change (however useful or well-meant) has the potential to break people's code.

Yeah, LaTeX is not exactly a language that lends itself to encapsulating effects inside an API and providing backwards compatibility. ;)

Speaking of which, looks like behavior is still a bit different from bibtex: bibtex knows how to apply proper title capitalization (well, "proper" in my community ;) and capitalize words after :. Is there a way to do the same with biblatex?

moewew commented 4 years ago

Joseph Wright's biblatex-ieee has something to deal with colons. https://github.com/josephwright/biblatex-ieee/blob/master/ieee.bbx

% {<process>} {<text>}
\newcommand*{\bbx@colon@search}[2]{%
  \bbx@colon@search@auxi\empty#2: \stop{#1}%
}
\long\def\bbx@colon@search@auxi#1: #2\stop#3{%
  \expandafter\bbx@colon@search@auxii\expandafter{#1}{#3}%
  \ifblank{#2}
    {}
    {%
      : %
      \bbx@colon@search@auxi\empty#2\stop{#3}%
    }%
}
\newcommand\bbx@colon@search@auxii[2]{#2{#1}}

Then use

\bbx@colon@search{\MakeSentenceCase*}{#1}

instead of

\MakeSentenceCase*{#1}

I should probably add that in some cases titles with colons significantly benefit from being split into title and subtitle. (You may need \renewcommand*{\subtitlepunct}{\addcolon\space} if you want to see a colon.)

https://github.com/plk/biblatex/blob/3ef5516cdb53bf06b0778edbcee0d2366f4bd354/bibtex/bib/biblatex/biblatex-examples.bib#L10-L24

RalfJung commented 4 years ago

Yes that does the trick, colons are handled like in bibtex now. :-) Thank you so much! My final LaTeX rune is

%% Adjust capitalization, and (while we are at it) also
%% formatting (quotes vs \emph) of titles.
\makeatletter%
\newcommand*{\bbx@colon@search}[2]{%% {<process>} {<text>}
  \bbx@colon@search@auxi\empty#2: \stop{#1}%
}
\long\def\bbx@colon@search@auxi#1: #2\stop#3{%
  \expandafter\bbx@colon@search@auxii\expandafter{#1}{#3}%
  \ifblank{#2}
    {}
    {%
      : %
      \bbx@colon@search@auxi\empty#2\stop{#3}%
    }%
}
\newcommand\bbx@colon@search@auxii[2]{#2{#1}}
% This requires using the "ext-" variant of the bib style.
% (Also see https://github.com/plk/biblatex/issues/1008.)
% The "*" overwrites previous more specific commands like
% \DeclareFieldFormat[article]{title}.
\DeclareFieldFormat*{titlecase:title}{\bbx@colon@search{\MakeSentenceCase}{#1}}
\DeclareFieldFormat*{title}{\mkbibquote{#1\isdot}}
% Also use sentence case in citations.
\DeclareFieldFormat*{citetitle}{\mkbibquote{\bbx@colon@search{\MakeSentenceCase}{#1}\isdot}}
\makeatother%

That seems to make biblatex mostly compatible with what bibtex did.

While trying many things I also found many people on the internet being more or less clueless about how to get the bibtex effect in biblatex. (My first attempt was based on one of the responses I found.) Would it make sense to document somewhere an "official"/"blessed" way of doing that?

moewew commented 4 years ago

Mhh, I guess we may want to think about adding \bbx@colon@search to the core (under a different name, naturally to avoid clashes) and can document that.