2

I am currently trying to create new commands to add the correct French article in front of the cross-references when required (for example "la figure XX" or "le chapitre XX").

My initial idea was to create commands like \acref and \Acref somehow like that:

\newcommand{\acref}[1]{%
\def\rtype{\namecref{#1}}% namecref will produce something like "figure"
\def\article{{\bf error:[\rtype](#1)} }% default value to help debugging
\ifstrequal{\rtype}{figure}{\def\article{la }}{}%
\article\cref{#1}\xspace
}

I also tried adding \expandafter around \ifstrequal like that:

\expandafter\ifstrequal\expandafter{\rtype}{figure}{\def\article{la }}{}%

And I tried some other combinations of commands that I do not master, with bad results.

All my attempts produced an invalid output, either always using the article for figure (as it is currently the only one I try to test) because both branches of the conditional statement are executed (with too much \expandafter) or it never enters the true branch.

Minimal compiling and not working example:

\documentclass{paper}

\usepackage{cleveref}
\usepackage{etoolbox}
\usepackage{xspace}

\crefname{figure}{figure}{figures} % instead of fig.

\newcommand{\acref}[1]{%
\def\rtype{\namecref{#1}}% namecref will produce something like "figure"
\def\article{{\bf error:[\rtype](#1)} }% default value to help debugging
\ifstrequal{\rtype}{figure}{\def\article{la }}{}%
\article\cref{#1}\xspace
}

\begin{document}
  \section{Title}
  \label{sec:title}

  \begin{figure}
    \caption{Caption}
    \label{fig:caption}
  \end{figure}

  Test with figure: \acref{fig:caption}. % should print "la figure" but prints error:...

  Test with section: \acref{sec:title}. % should print error:...
\end{document}

I read that etoolbox does not expand its arguments in most of its tests, including \ifstrequal. I had the idea to create a list containing the result of \namecref as there is \listeadd which expands its item argument and then test if that list contains the text "figure". However, when I tried (\listeadd{\mylist}{\namecref{#1}}), pdflatex stopped compiling and returned (filtered):

! Argument of \@firstoftwo has an extra }
! Paragraph ended before \@firstoftwo was complete.
! TeX capacity exceeded, sorry [parameter stack size=10000].

So, is \namecref unexpandable?


Really close questions that I failed to make work in my case:

12
  • 1
    Welcome to TeX.SE. Is there something stopping you from simply writing \crefname{figure}{la figure}{les figures}?
    – Mico
    Commented Apr 17, 2020 at 13:25
  • 1
    I agree with@Mico's proposal. In the rare cases where the article wouldn't be used in French, you always can type the name of the environment and use a plain \ref.
    – Bernard
    Commented Apr 17, 2020 at 13:32
  • (perhaps I should edit my question?) No, this is not a solution in my case: first, the article would be included in the link (when using hyperref and because I like to have "figure" included in the link); then, and mostly, because I often use \cref like some text (\cref{fig:lbl}) which would be incorrectly expanded as "some text (la figure 2)". @Bernard and, I find using \ref defeats one advantage of \cref that allows to change easily all prefixes for a given label type.
    – Soko
    Commented Apr 17, 2020 at 13:45
  • 1
    Happily you do not write in Latin or Greek (I suppose) – you'd have to provide for the different possibilities of declensions and cases (albeit one rarely uses the vocative for a figure or a table, as far as I know).
    – Bernard
    Commented Apr 17, 2020 at 14:58
  • You might be interested in xcref. It's a proof of concept but works (see the examples in French and German). Some names had to be changed in the latest commit, which haven't propagated to the manual yet, but this only concerns one particular feature.
    – frougon
    Commented Apr 17, 2020 at 19:31

1 Answer 1

2

Welcome to TeX.SE. You can use \cref@gettype to get the type of a cleveref reference in a macro of your choice (\mycref@type in the code below), then execute special code depending on the result. \cref@gettype expects that the \r@〈reference〉@cref macro has already been defined, which is done when the \newlabel command present in the .aux file is executed after the first compilation run with the 〈reference〉 in question. Therefore, my code checks whether the \r@〈reference〉@cref macro is defined and if not, prints ?? in the document along with the usual message on the terminal and in the log file:

LaTeX Warning: Label(s) may have changed. Rerun to get cross-references right.

I removed the use of xspace in your code, because the original author of xspace nowadays advises against using it (moreover, as egreg pointed out, xspace wouldn't be useful here, since your macro takes an argument). I changed the fig:caption label to fig-caption, otherwise with cleveref and : as an active character,1 you'll encounter problems. Please also note that I use amsthm for the theorem in the example. Should you use theorem environments defined with \newtheorem from the LaTeX kernel, you'd find that the cleveref type for theorems using a shared counter is not necessarily what you expect (you'd get the name of the shared counter instead of the “specific” name; this doesn't happen with amsthm theorem environments).

Finally, don't forget to load cleveref last! :-)

\documentclass{article}
\usepackage{expl3}
\usepackage{amsthm}             % only for the demo
%\usepackage{hyperref}          % usually last, but before cleveref
\usepackage{cleveref}           % load this package last

\newtheorem{theorem}{Théorème}

\crefname{figure}{figure}{figures}    % instead of fig.
\crefname{theorem}{théorème}{théorèmes}

\makeatletter
\ExplSyntaxOn
% Let's borrow \str_case:onF from expl3 (\cs_new_eq:NN is like \let but checks
% that the “destination” command name doesn't already exist).
\cs_new_eq:NN \mycref@str@oswitch \str_case:onF
\ExplSyntaxOff

\newcommand*{\acref}[1]{%
  \ifcsname r@#1@cref\endcsname
    \cref@gettype{#1}{\mycref@type}%
    \mycref@str@oswitch{\mycref@type}
      {{figure}{la }%
       {theorem}{le }%
%      {...}{...}% you can add as many cases as you want!
      }
      {\errmessage{%
         My package: unknown reference type for label '#1':
         '\unexpanded\expandafter{\mycref@type}'}%
      }%
  \else
    \G@refundefinedtrue
    \nfss@text{\reset@font\bfseries ??}%
    \@latex@warning{Reference `#1' on page \thepage\space undefined}%
  \fi
  \cref{#1}%
}
\makeatother

\begin{document}

  \section{Title}\label{sec-title}

  \begin{theorem}\label{th-some-theorem}
    This is a theorem.
  \end{theorem}

  \begin{figure}
    \centering X
    \caption{Caption}
    \label{fig-caption}
  \end{figure}

  Test with figure: \acref{fig-caption}.

  Test with theorem: \acref{th-some-theorem}.

% Test with section: \acref{sec-title}. % prints an error, as expected

\end{document}

enter image description here

If you uncomment the \usepackage{hyperref} line and recompile until LaTeX is happy (because of the change in \newlabel syntax this implies), you'll get:

enter image description here


Footnote

  1. Which will normally be the case if you use \usepackage[french]{babel} with the pdfTeX engine.
7
  • By the way, \xspace is and has always been pretty useless in macros with arguments.
    – egreg
    Commented Apr 20, 2020 at 14:26
  • @egreg I believe the way the OP used xspace here was correct, wasn't it? Once the OP's \acref is expanded, \xspace would see a period, or a space, or... ?
    – frougon
    Commented Apr 20, 2020 at 14:31
  • @frougon ... well, I was reading and trying to adapt the link you gave to post something like you just did. I will accept the answer after some testing. I get ! Argument of \@fourthoffive has an extra }. if I use hyperref, however the second compilation works perfectly and produces the correct result. What I was trying to do produced the same but with \@firstoftwo and I was trying to get rid of that. Perhaps it is normal for first compilation? As for cleveref with babel, I did something probably ugly but working, I renewed to encapsulate inside otherlanguage to locally disable :.
    – Soko
    Commented Apr 20, 2020 at 14:43
  • hyperref and standard LaTeX use different syntaxes for \newlabel (and cleveref also its own!), so when adding or removing one of these packages, it's quite expected to have errors on the first run. In these cases, just recompile or remove the .aux file. There is no problem that I know of with \usepackage[french]{babel} if you don't use active characters in reference names (i.e., inside the argument of \label). I always use - instead of : in my label names for this reason (when writing in French). One more thing: hyperref must be loaded before cleveref!
    – frougon
    Commented Apr 20, 2020 at 14:47
  • 1
    @frougon The \xspace trick might only be useful for adding the space which would be gobbled by a macro with no argument. Since spaces after mandatory arguments are preserved, doing the check is simply a waste of time.
    – egreg
    Commented Apr 20, 2020 at 15:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .