plk / biblatex

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

Why is origlanguage a field while language is a list? #594

Closed equaeghe closed 7 years ago

equaeghe commented 7 years ago

In the manual, I see that origlanguage is a field, whereas language is a list. Is this also the case in the biblatex code? If so, is there a reason for this?

(I am just curious, but do not have a practical reason for asking. So feel free to treat this as low priority.)

moewew commented 7 years ago

We probably need to notify David Fussner of biblatex-chicago of the changes. But from a technical point of view, this can be closed. If problems arise we can re-open or open a new issue.

jspitz commented 5 years ago

I took me a while to notice that these changes broke some of my styles. I am on the way of fixing it, but there's one thing I am stuck at:

When printing my orig* fields, I attempt to switch the hyphenation patterns to the orig language to get proper hyphenation of those fields. This worked well when origlanguage was a field with this code:

\DeclareFieldFormat{origtitle}{%
  \iffieldundef{origlanguage}%
      {\emph{#1}}
      {\begin{hyphenrules}{\thefield{origlanguage}}%
       \emph{#1}%
       \end{hyphenrules}}%
}

I have now changed it like so:

\DeclareFieldFormat{origtitle}{%
   \iflistundef{origlanguage}%
      {\emph{#1}}
      {\begin{hyphenrules}{\strlist{origlanguage}}%
       \emph{#1}%
       \end{hyphenrules}}%
}

However, this yields: ! Package babel Error: You haven't defined the language {english} yet. (note the braces!)

I have also tried \thelist and some forms of \printlist, neither works.

How can I pass the plain language string to the environment (first one in the list is sufficient for me, since I never use more)?

plk commented 5 years ago

First thing - you'd have to use DeclareListFormat instead of DeclareFieldFormat I think.

jspitz commented 5 years ago

No, origtitle is not a list.

moewew commented 5 years ago

edit: See https://github.com/plk/biblatex/issues/594#issuecomment-464348870 below for a method using new commands.

This should work

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

\usepackage[style=authoryear, backend=biber]{biblatex}

\makeatletter
\newcommand*{\jsm@grabfirstlistitem}[1]{%
  \ifcsdef{abx@list@#1}
    {\expandafter\expandafter\expandafter
     \jsm@grabfirstlistitem@i
     \expandafter\expandafter\expandafter
     {\csname abx@list@#1\endcsname}}
    {}}
\def\jsm@grabfirstlistitem@i#1{\jsm@grabfirstlistitem@ii#1\jsm@grabfirstlistitem@ii@end}
\def\jsm@grabfirstlistitem@ii#1#2\jsm@grabfirstlistitem@ii@end{#1}

% idea by Martin Scharrer
% https://tex.stackexchange.com/users/2975/martin-scharrer
% https://tex.stackexchange.com/a/15014/35864
\newenvironment{jsm@eotherlanguage}[1]{%
  \begingroup
  \edef\jsm@temp{\endgroup\noexpand\otherlanguage{#1}}%
  \jsm@temp
}{\endotherlanguage}

\DeclareFieldFormat{origtitle}{%
  \iflistundef{origlanguage}%
    {\mkbibemph{#1}}
    {\begin{jsm@eotherlanguage}{\jsm@grabfirstlistitem{origlanguage}}
     \mkbibemph{#1}%
     \end{jsm@eotherlanguage}}}

\renewbibmacro*{title}{%
  \ifboolexpr{
    test {\iffieldundef{title}}
    and
    test {\iffieldundef{subtitle}}
  }
    {}
    {\printtext[title]{%
       \printfield[titlecase]{title}%
       \setunit{\subtitlepunct}%
       \printfield[titlecase]{subtitle}}%
     \newunit}%
  \printfield{titleaddon}%
  \newunit
  \printfield{origtitle}}
\makeatother

\usepackage{filecontents}
\begin{filecontents}{\jobname.bib}
@book{vangennep:my,
  author       = {van Gennep, Arnold},
  title        = {The Rites of Passage},
  year         = 1960,
  translator   = {Vizedom, Monika B. and Caffee, Gabrielle L.},
  origlanguage = {french and german},
  publisher    = {University of Chicago Press},
  origtitle    = {Les rites de passage: Just testing},
}
\end{filecontents}

\addbibresource{\jobname.bib}
\addbibresource{biblatex-examples.bib}

\begin{document}
\cite{maron,vangennep:my}
\printbibliography
\end{document}

\jsm@grabfirstlistitem can be used to grab the first item of a list, it relies on the fact that the internal representation of our lists looks like {item_1}{item_2}...{item_n}, which allows us to grab the first item with a delimited macro. One problem in this example was that otherlanguage does not expand its language argument (not sure about hyphenation, but the same structrual problem would have applied in the old days with \thefield{origlanguage}), so I used Martin Scharrer's fully expanding version from https://tex.stackexchange.com/a/15014/35864 (alternatively, a short test suggests 2*511 \expandafters would do it as well for nine expansion steps).

jspitz commented 5 years ago

Thank you so much. This works. For the record, since I wanted hyphenrules or rather otheranguage* (not otherlanguage), I had to tweak Martin's definition like this:

\newenvironment{jsm@eotherlanguage}[1]{%
  \begingroup%
  \edef\jsm@temp{\endgroup\noexpand\csname otherlanguage*\endcsname{#1}}%
  \jsm@temp%
}{\csname endotherlanguage*\endcsname}

The nice thing is that this also solves my second qualm: Sentence casing. For the records:

\xifinlist{\jsm@grabfirstlistitem{origlanguage}}\blx@cmksc@lang
            {\mkbibemph{\MakeSentenceCase{#1}}}
            {\mkbibemph{#1}}%
jspitz commented 5 years ago

I know this does not belong here, but maybe you can help me with this as well: Is it possible to generally cause \MakeSentenceCase to not lowercase the first word after \subtitlepunct? Since there is no origsubtitle, I separate title and subtitle by a \subtitlepunct in the bib file (and I want to avoid having to protect the word, as \subtitlepunct might change). I tired \bibsentence in the \subtitlepunct definition, to no avail.

moewew commented 5 years ago

I can't think of a good automatic way.

My preferred solution would be to define origsubtitle and use that field.

moewew commented 5 years ago

Mhhh, maybe biblatex-ieee's \bbx@colon@search can help you https://github.com/josephwright/biblatex-ieee/blob/master/ieee.bbx. But this is all quite tricky. I have come to the conclusion that it is wise to try and avoid string manipulation in LaTeX. Maybe things get better with LaTeX3. You could look into its RegExp capabilities.

jspitz commented 5 years ago

You are probably right about using origsubtitle. It is certainly the cleanest approach.

moewew commented 5 years ago

I think it makes sense to make the first item of a list easily accessible similar to \thefield, so the next version will include \thefirstlistitem. See https://github.com/plk/biblatex/commit/7b8ac94ff5a69218a80719bb58f40ff255dd374e. The example from above could then look like

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

\usepackage[style=authoryear, backend=biber]{biblatex}

\makeatletter
% idea by Martin Scharrer
% https://tex.stackexchange.com/users/2975/martin-scharrer
% https://tex.stackexchange.com/a/15014/35864
\newenvironment{jsm@eotherlanguage}[1]{%
  \begingroup
  \edef\jsm@temp{\endgroup\noexpand\otherlanguage{#1}}%
  \jsm@temp
}{\endotherlanguage}

\DeclareFieldFormat{origtitle}{%
  \iflistundef{origlanguage}%
    {\mkbibemph{#1}}
    {\begin{jsm@eotherlanguage}{\thefirstlistitem{origlanguage}}
     \mkbibemph{#1}%
     \end{jsm@eotherlanguage}}}

\renewbibmacro*{title}{%
  \ifboolexpr{
    test {\iffieldundef{title}}
    and
    test {\iffieldundef{subtitle}}
  }
    {}
    {\printtext[title]{%
       \printfield[titlecase]{title}%
       \setunit{\subtitlepunct}%
       \printfield[titlecase]{subtitle}}%
     \newunit}%
  \printfield{titleaddon}%
  \newunit
  \printfield{origtitle}}
\makeatother

\usepackage{filecontents}
\begin{filecontents}{\jobname.bib}
@book{vangennep:my,
  author       = {van Gennep, Arnold},
  title        = {The Rites of Passage},
  year         = 1960,
  translator   = {Vizedom, Monika B. and Caffee, Gabrielle L.},
  origlanguage = {french and german},
  publisher    = {University of Chicago Press},
  origtitle    = {Les rites de passage: Just testing \bibstring{and} lorem},
}
\end{filecontents}

\addbibresource{\jobname.bib}
\addbibresource{biblatex-examples.bib}

\begin{document}
\cite{maron,vangennep:my}
\printbibliography
\end{document}

edit Once this is released I should probably add a usage example to https://tex.stackexchange.com/q/474388/35864

jspitz commented 5 years ago

Thanks a lot. I also think this is useful in general.

jspitz commented 4 years ago

I just learned that \blx@cmksc@lang seems to have been removed along the way to 3.15, which breaks some of my styles that use

\xifinlist{\thefirstlistitem{origlanguage}}\blx@cmksc@lang
            {\mkbibemph{\MakeSentenceCase{#1}}}
            {\mkbibemph{#1}}%

(in origtitle macros).

What has this function been replaced with?

Edit: give full context

jspitz commented 4 years ago

Oh, I see:

\ifcaselang[\thefirstlistitem{origlanguage}]
            {\mkbibemph{\MakeSentenceCase{#1}}}
            {\mkbibemph{#1}}%

(with expl3). Sorry for the noise.

moewew commented 4 years ago

Just to avoid confusion: \ifcaselang is available with both the expl3 and legacy LaTeX2e case change code. The implementations differ (the LaTeX2e implementation basically does what you did manually with \xifinlist{<language>}\blx@cmksc@lang, the expl3 implementation is more LaTeX3-y), but the syntax and semantics are the same. I think \ifcaselang has been a part of core biblatex for a while (according to the docs since v3.4, which was released more than four years ago). In general it is much safer to rely on documented commands than on bits of their internal \blx@... implementation (though of course you sometimes have to resort to \blx@... macros).

jspitz commented 4 years ago

Yes, I learned this too, meanwhile. I just seem to have missed \ifcaselang completely :-/

moewew commented 4 years ago

@jspitz Turns it it was actually your idea ;-) https://github.com/plk/biblatex/issues/393#issuecomment-202346448, but I guess you needed the function before the v3.4 release and stuck with the internal implementation.

jspitz commented 4 years ago

Yes, probably. Sometimes you have to learn the hard way :-)