5

Please consider the following MWE:

\documentclass{article} \usepackage[utf8]{inputenc} \usepackage{etoolbox} \newcommand*{\convertlang}[1]{% \ifstrequal{#1}{es}{spanish}{% \ifstrequal{#1}{lat}{latin}{% \ifstrequal{#1}{eng}{english}{% \ifstrequal{#1}{deu}{german}{% \ifstrequal{#1}{enm}{spanish}{% else % use English as foreign default english}}}}}}% \newcommand*{\langtest}[1]{% \def\temp{\convertlang{#1}}% \ifstrequal{\temp}{spanish}{True}{False}% } \begin{document} Testing: \convertlang{es} % yields: spanish \langtest{es} % should yield: True \end{document} 

The command \convertlang takes an ISO 8859 language code (es, eng, etc.) and converts it into a babel language name (spanish, english, etc.). This works fine.

The problem is with \langtest, which compares a string (spanish) with the result of transforming its argument (#1) using \convertlang.

There must be a problem in the expansion of \convertlang and/or of #1 there, buy I don't understand the fundamentals of TeX macro expansion.

I tried doing this:

\newcommand*{\langtest}[1]{% \edef\temp{\convertlang{#1}}% \ifstrequal{\temp}{spanish}{True}{False}% } 

expecting that \temp gets the expanded value of its argument. But this doesn't work either.

How can I fix this?

3 Answers 3

6

You can use the expandable and expanding string equality test \pdfstrcmp (for portability use \pdf@strcmp from pdftexcmds, see for example Are there any "if" commands like "\ifnum" in LaTeX?). That command expands its test arguments and is itself expandable. (The latter is always nice, the former is not always convenient [cf. https://tex.stackexchange.com/q/230878/35864], but is what we want here.)

\documentclass{article} \usepackage[utf8]{inputenc} \usepackage{etoolbox} \usepackage{pdftexcmds} \makeatletter \newcommand*{\IfStrEqualTF}[2]{% \ifnum\pdf@strcmp{#1}{#2}=\z@ \expandafter\@firstoftwo \else \expandafter\@secondoftwo \fi} \makeatother \newcommand*{\convertlang}[1]{% \IfStrEqualTF{#1}{es} {spanish} {\IfStrEqualTF{#1}{lat} {latin} {\IfStrEqualTF{#1}{eng} {english} {\IfStrEqualTF{#1}{deu} {german} {\IfStrEqualTF{#1}{enm} {spanish} {english}}}}}} \newcommand*{\langtest}[1]{% \IfStrEqualTF{\convertlang{#1}}{spanish} {True} {False}} \begin{document} Testing: \convertlang{es} % yields: spanish \langtest{es} % should yield: True \langtest{en} % should yield: False \end{document} 

Testing: spanish//True//False


Some more details about the MWE and why it doesn't do the desired thing.

First of all, etoolbox's \ifstrequal is defined with \newrobustcmd. It is therefore robust and not expandable. That means that

\edef\temp{\convertlang{#1}} 

does not actually save the long language name in \temp as we would have hoped. It just saves a cascade of \ifstrequal tests. This means that \temp does not contain a simple string.

\edef\temp{\convertlang{es}}% \show\temp 

gives

> \temp=macro: ->\ifstrequal {es}{es}{spanish}{\ifstrequal {es}{lat}{latin}{\ifstrequal {es}{eng}{english}{\ifstrequal {es}{deu}{german}{\ifstrequal {es}{enm}{spanish}{english}}}}}. 

You need a string equality test that is expandable to allow \convertlang{#1} to expand to the language name in an \edef.

\pdf@strcmp comes in handy here, since its string comparison is expandable, meaning that a command defined via this equality test can expand to the result of the comparisons in an \edef.

The second issue is that \ifstrequal doesn't expand its arguments, so even if \temp contained only a string, the test wouldn't quite work as intended

\def\temp{spanish}% \ifstrequal{\temp}{spanish}{True}{False}% 

still gives 'False', since \temp is not a string equal to spanish, it expands to a string equal to spanish, that is a small but significant difference.

There are several possible ways around that. Depending on what you can guarantee about \temp it would be enough to say

\expandafter\ifstrequal\expandafter{\temp}{spanish}{True}{False}% 

or

\ifdefstring{\temp}{spanish}{True}{False}% 

if you know that \temp expands to a string in one expansion step. If more steps are required or you want full expansion, other tricks are needed.

\pdf@strcmp helps here, because it just completely expands its argument. This means that as long as \temp does not contain anything that blows up in an expansion context, its 'ultimate expanded string value' can be compared. You need not worry about expanding it first for the test.

7
  • Thanks. But why does my code not work? Commented Aug 2, 2020 at 16:11
  • @NVaughan I'm just writing an edit explaining that in more detail. Commented Aug 2, 2020 at 16:12
  • Also, I read that pdftexcmds is aimed for LuaTex? Commented Aug 2, 2020 at 16:13
  • @NVaughan Yes and no. pdftexcmds provides primitives that are not defined in all engines by default in a way that it can be uniformly accessed by all engines. If you are only using pdfTeX you could use \pdfstrcmp but that would fail in LuaTeX. With pdftexcmds we can use \pdf@strcmp, which works everywhere. Commented Aug 2, 2020 at 16:14
  • Oh, good to know. Thanks. Commented Aug 2, 2020 at 16:17
8

I'd use the simpler interface of expl3 with \str_case:nnF

\documentclass{article} \usepackage{xparse} \ExplSyntaxOn \NewExpandableDocumentCommand{\convertlang}{m} { \nvaughan_convertlang:n { #1 } } \cs_new:Nn \nvaughan_convertlang:n { \str_case:nnF { #1 } { {es}{spanish} {lat}{latin} {eng}{english} {deu}{german} {enm}{spanish} } {english} } \NewExpandableDocumentCommand{\langtest}{m} { \str_if_eq:eeTF { \nvaughan_convertlang:n { #1 } } { spanish } { True } { False } } \ExplSyntaxOff \begin{document} Testing: \convertlang{es} % yields: spanish \langtest{es} should yield: True \langtest{lat} should yield: False \end{document} 

enter image description here

1
  • Oh gosh! There are so many options! Thanks @egreg. Commented Aug 2, 2020 at 19:37
7

I wouldn't use long nested if-tests. This is difficult to expand.

\documentclass{article} \ExplSyntaxOn \tl_const:Nn \c__nvaughan_convert_es_tl{spanish} \tl_const:Nn \c__nvaughan_convert_lat_tl{latin} \tl_const:Nn \c__nvaughan_convert_eng_tl{english} \tl_const:Nn \c__nvaughan_convert_deu_tl{german} \tl_const:Nn \c__nvaughan_convert_enm_tl{spanish} \newcommand*{\convertlang}[1] { \tl_if_exist:cTF {c__nvaughan_convert_#1_tl} { \tl_use:c {c__nvaughan_convert_#1_tl} } { english} } \newcommand*{\langtest}[1]{% \str_if_eq:eeTF {\convertlang{#1}}{spanish} {True}{False}} \ExplSyntaxOff \begin{document} Testing: \convertlang{es} % yields: spanish \convertlang{lat} \convertlang{blub} \langtest{es} % should yield: True \end{document} 

enter image description here

5
  • Thanks @Ulrike Fischer. Where can I find a guide to these LaTeX3 commands? Commented Aug 2, 2020 at 17:26
  • 1
    in interface3.pdf. Commented Aug 2, 2020 at 17:27
  • Thanks. I'll give it a look. When you said, "This is difficult to expand", did you mean that it take more processing resources, or that it is prone to faults. Commented Aug 2, 2020 at 17:30
  • 2
    I mean that it is difficult to add more languages as you would have to nest deeper and deeper, while when using commands like above a new language is simply on more line. (It is faster too, as tex doesn't have to do so many comparisions). Commented Aug 2, 2020 at 17:36
  • Great. Thanks for your help. Commented Aug 2, 2020 at 17:44

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.