# Why does \captiondelim cause error with babel-french?

The MWE below causes the error:

./caption-err.tex:9: Argument of \reserved@a has an extra }.
<inserted text>
\par
l.9 \begin{document}

? q
OK, entering \batchmode...
Runaway argument?
{.\ }\ifx \reserved@a \@empty \let \check@icl \@empty \let \check@icr \ETC.
./caption-err.tex:9: Paragraph ended before \reserved@a was complete.
\par
l.9 \begin{document}

I suspect you've forgotten a }', causing me to apply this
control sequence to too much text....


How can it be fixed?

The error does not occur if french is not used as a babel option.

\documentclass{memoir}
\usepackage[T1]{fontenc}
\usepackage[french,ngerman,main=english]{babel}

\captionnamefont{\sffamily}
\captiondelim{\textsf{.\ }}
\begin{document}

\begin{figure}
\centering
\framebox[15in][c]{\rule{0pt}{1in}}
\caption{A figure.}
\end{figure}

\end{document}


Related:

Change caption label delimiter with babel french in memoir but without caption package?

The new version of french.ldf contains a \edef\FB@capsep{\@contdelim}. This is not a good idea as it as no control over the content of \@contdelim and so can't be sure that it is expandable. This should be at least \protected@edef\FB@capsep{\@contdelim}. Report this to the author.

With the \edef the \textsf in your definition breaks. So a way to avoid the error is to use \captiondelim{.\ } instead.

• I have reported this to the babel-french author. – murray Jul 2 at 14:18

Until french.ldf is updated to fix the glitch, you can make \@contdelim robust under \edef.

\documentclass{memoir}
\usepackage[T1]{fontenc}
\usepackage[french,ngerman,main=english]{babel}

\captionnamefont{\sffamily}
\captiondelim{\textsf{.\ }}
\makeatletter
\protected\edef\@contdelim{\unexpanded\expandafter{\@contdelim}}
\makeatother

\begin{document}

\begin{figure}
\centering
\framebox[5in][c]{\rule{0pt}{1in}}
\caption{A figure.}
\end{figure}

\end{document}


The previous version of french.ldf, 2020/04/18 v3.5h, had

1541      \ifFBCustomiseFigTabCaptions
1542        \ifFB@koma
1543          \renewcommand*{\captionformat}{\CaptionSeparator}%
1544        \fi
1546           {\captiondelim{\CaptionSeparator}}{}%
1548           {\defbeamertemplate{caption label separator}{FBcustom}{%
1549                \CaptionSeparator}%
1550            \setbeamertemplate{caption label separator}[FBcustom]}{}%
1551      \else
1552        \ifFB@koma
1553          \renewcommand*{\captionformat}{{\autospace@beforeFDP : }}%
1554        \fi
1556           {\captiondelim{{\autospace@beforeFDP : }}%
1557           }{}%
1559           {\defbeamertemplate{caption label separator}{FBcolon}{%
1560                 {\autospace@beforeFDP : }}%
1561            \setbeamertemplate{caption label separator}[FBcolon]%
1562           }{}%
1563      \fi


The new one, 2020/06/30 v3.5i, has reworked the code above

1551      \@ifclassloaded{memoir}%
1552         {\edef\FB@capsep{\@contdelim}\edef\FB@std@capsep{: }%
1553          \ifx\FB@capsep\FB@std@capsep
1554            \ifFBCustomiseFigTabCaptions
1555              \captiondelim{\CaptionSeparator}%
1556            \else
1557              \captiondelim{{\autospace@beforeFDP : }}%
1558            \fi
1559          \fi}{}%


This is disputable under many respects. There is no reason for doing

\edef\FB@std@capsep{: }


when \def is more than sufficient. But the main error is in the previous declaration that should be

\let\FB@capsep\@contdelim


as the code wants to compare the meaning of \@contdelim with a standard. Well, the user might do

\newcommand{\mycaptiondelim}{: }
\captiondelim{\mycaptiondelim}


and the test performed by french.ldf would return false (with the proposed fix). But it should return false, because the user surely has a reason for the indirection (for instance, they want to avoid french.ldf taking precedence over their preferences).

As Ulrike Fischer states in her answer, the \edef is conceptually wrong, because nothing makes certain that \@contdelim will only contain \edef-safe tokens.

• I disagree with your statement "There is no reason for doing \edef\FB@std@capsep{: } when \def is more than sufficient". Doing what you suggest \let\FB@capsep\@contdelim and \def\FB@std@capsep{: } would make the test \ifx\FB@capsep\FB@std@capsep /always/ FALSE as it occurs AtBeginDocument : the colon's catcode has changed in between! My concern is to get a proper space before the colon in French with the standard definition of \@contdelim. – Daniel Flipo Jul 2 at 16:22
• @DanielFlipo Maybe you have some reasons to, I can't see one. Anyway, \edef is the wrong tool. What has the category code of the colon to do? It's frozen at definition time and \edef doesn't change this. – egreg Jul 2 at 16:22
• Indeed \edef is wrong but Ulrike's suggestion looks fine for me. – Daniel Flipo Jul 2 at 16:27
• I know that the category code is frozen at definition time. That's precisely my point: the colon has catcode 13 when I define \FB@std@capsep (AtBeginDocument) but 12 in memoir's original definition of \@contdelim, thus the test \ifx\FB@capsep\FB@std@capsep returns FALSE anytime, even if \@contdelim is unchanged. Defining \FB@std@capsep /before/ babel-french activates the colon would work and avoid using \protected@edef, that's probably what i will do. – Daniel Flipo Jul 2 at 17:50
• @DanielFlipo No, the definition of \FB@std@capsep uses a token list that has already been absorbed when french.ldf` is loaded, so it will have the catcode it had at that time, which I presume is 12. – egreg Jul 2 at 19:27