6

I'm trying to define a macro \CreateTheorem(*), the intention is to be able to define the theorem-like environments as easy as before, but can be traced correctly by cref in a multi-language document. For example,

\CreateTheorem{theorem}<section>
\CreateTheorem{definition}[theorem]

should create theorem and definition environments as usual. The result would be like (this is produced by the document in the last of this question, which manually does the work of \CreateTheorem):

result

Currently I have (below is a complete, but not yet working MWE):

\documentclass{article}

\usepackage[french,english]{babel}

\usepackage{xcolor}
\definecolor{paper}{RGB}{255,255,255}

\usepackage{mathtools}
\usepackage{amsthm}
\makeatletter
\newtheoremstyle{simple}%
    {}{}%
    {\normalfont}{}%
    {\normalfont}{}%
    {0pt}%
    {\thmname{\MakeUppercase{#1}}\thmnumber{ #2}\hspace{.4em}\textcolor{gray!55!paper}{$|$}\hspace{.4em}\color{gray}\thmnote{\ensuremath{(\text{#3})}~~}\pushQED{\qed}}
\def\@endtheorem{\popQED\endtrivlist\@endpefalse }
\makeatother

\renewcommand{\qedsymbol}{\makebox[1em]{\color{gray!55!paper}\rule[-0.1em]{.95em}{.95em}}}

\PassOptionsToPackage{hidelinks,linktoc=all}{hyperref}
\RequirePackage{hyperref}
\PassOptionsToPackage{nameinlink}{cleveref}
\RequirePackage{cleveref}
\crefdefaultlabelformat{#2#1#3~\aftergroup\ignorespaces}

\theoremstyle{simple}

\newcommand\englishABBR{EN}
\newcommand\frenchABBR{FR}

%% macro for creating theorems
\RequirePackage{xstring}
\NewDocumentCommand{\CreateTheorem}{smod<>}{%
    \IfBooleanTF{#1}
    {% Stared version
        \IfEndWith{#2}{*}
        {% \CreateTheorem*{theorem*}
            \StrGobbleRight{#2}{1}[\temp]%
            \newtheorem*{\temp EN*}{\csname\temp nameEN\endcsname}
            \newtheorem*{\temp FR*}{\csname\temp nameFR\endcsname}
            \NewDocumentEnvironment{\temp*}{O{}}{\begin{\temp \csname\languagename ABBR\endcsname*}[##1]}{\end{\temp \csname\languagename ABBR\endcsname*}}
        }
        {% \CreateTheorem*{theorem}
            \newtheorem*{#2EN}{\csname#2nameEN\endcsname}
            \newtheorem*{#2FR}{\csname#2nameFR\endcsname}
            \NewDocumentEnvironment{#2}{O{}}{\begin{#2\csname\languagename ABBR\endcsname}[##1]}{\end{#2\csname\languagename ABBR\endcsname}}
        }%
    }
    {% Non-stared version
        \IfEndWith{#2}{*}
        {% \CreateTheorem{theorem*}[...]<...>
            \StrGobbleRight{#2}{1}[\temp]%
            \newtheorem{\temp EN*}[#3]{\csname\temp nameEN\endcsname}[#4]
            \newtheorem{\temp FR*}[#3]{\csname\temp nameFR\endcsname}[#4]
            \crefname{\temp EN*}{\protect\MakeUppercase{\csname\temp nameEN\endcsname}}{\protect\MakeUppercase{\csname\temp nameEN\endcsname}}
            \crefname{\temp FR*}{\protect\MakeUppercase{\csname\temp nameFR\endcsname}}{\protect\MakeUppercase{\csname\temp nameFR\endcsname}}
            \NewDocumentEnvironment{\temp*}{O{}}{\begin{\temp \csname\languagename ABBR\endcsname*}[##1]}{\end{\temp \csname\languagename ABBR\endcsname*}}
        }
        {% \CreateTheorem{theorem}[...]<...>
            \newtheorem{#2EN}[#3]{\csname#2nameEN\endcsname}[#4]
            \newtheorem{#2FR}[#3]{\csname#2nameFR\endcsname}[#4]
            \crefname{#2EN}{\protect\MakeUppercase{\csname#2nameEN\endcsname}}{\protect\MakeUppercase{\csname#2nameEN\endcsname}}
            \crefname{#2FR}{\protect\MakeUppercase{\csname#2nameFR\endcsname}}{\protect\MakeUppercase{\csname#2nameFR\endcsname}}
            \NewDocumentEnvironment{#2}{O{}}{\begin{#2\csname\languagename ABBR\endcsname}[##1]}{\end{#2\csname\languagename ABBR\endcsname}}
        }%
    }%
}

\def\theoremnameEN{Theorem}
\def\theoremnameFR{Théorème}
\def\definitionnameEN{Definition}
\def\definitionnameFR{Définition}
\def\remarknameEN{Remark}
\def\remarknameFR{Remarque}
\def\notenameEN{Note}
\def\notenameFR{Note}

\CreateTheorem{theorem}<section>
\CreateTheorem{definition}[theorem]
\CreateTheorem*{theorem*}
\CreateTheorem*{definition*}
\CreateTheorem*{remark}
\CreateTheorem{note*} % This is strange, only for test

\begin{document}

\begin{theorem}
\end{theorem}

\begin{definition}
\end{definition}

\end{document}

There're two problems:

  1. As @Skillmon points out to me, one cannot use \newtheorem with two counters as optional arguments. (Using \newtheorem) So [#3] and [#4] should only appear when they are non-empty.
  2. The theorem* case uses \temp string, which is not static and may get changed. Something similar to this question should be considered.

Could anyone please help me building this macro?


This macro is intended to simplify to process for defining theorem-like environments in a multi-language document. Below is a document with manually defined theorem-like environments. As a comparison, when \CreateTheorem is finished, it should be able to produce the same result, but with a much easier process.

\documentclass{article}

\usepackage[french,english]{babel}

\usepackage{xcolor}
\definecolor{paper}{RGB}{255,255,255}

\usepackage{mathtools}
\usepackage{amsthm}
\makeatletter
\newtheoremstyle{simple}%
    {}{}%
    {\normalfont}{}%
    {\normalfont}{}%
    {0pt}%
    {\thmname{\MakeUppercase{#1}}\thmnumber{ #2}\hspace{.4em}\textcolor{gray!55!paper}{$|$}\hspace{.4em}\color{gray}\thmnote{\ensuremath{(\text{#3})}~~}\pushQED{\qed}}
\def\@endtheorem{\popQED\endtrivlist\@endpefalse }
\makeatother

\renewcommand{\qedsymbol}{\makebox[1em]{\color{gray!55!paper}\rule[-0.1em]{.95em}{.95em}}}

\PassOptionsToPackage{hidelinks,linktoc=all}{hyperref}
\RequirePackage{hyperref}
\PassOptionsToPackage{nameinlink}{cleveref}
\RequirePackage{cleveref}
\crefdefaultlabelformat{#2#1#3~\aftergroup\ignorespaces}

\theoremstyle{simple}

\newcounter{theorem}
\newcounter{conjecture}
\newcounter{example}
\newcounter{problem}
\newcounter{remark}
\numberwithin{theorem}{section}
\numberwithin{conjecture}{section}
\numberwithin{example}{section}
\numberwithin{problem}{section}
\numberwithin{remark}{section}

\newcommand\englishABBR{EN}
\newcommand\frenchABBR{FR}

%% English theorems
\newtheorem{theoremEN}[theorem]{\theoremnameEN}
\newtheorem{lemmaEN}[theorem]{\lemmanameEN}
\newtheorem{propositionEN}[theorem]{\propositionnameEN}
\newtheorem{corollaryEN}[theorem]{\corollarynameEN}
\newtheorem{factEN}[theorem]{\factnameEN}
\newtheorem{conjectureEN}[conjecture]{\conjecturenameEN}
\newtheorem*{theoremEN*}{\theoremnameEN}
\newtheorem*{lemmaEN*}{\lemmanameEN}
\newtheorem*{propositionEN*}{\propositionnameEN}
\newtheorem*{corollaryEN*}{\corollarynameEN}
\newtheorem*{factEN*}{\factnameEN}
\newtheorem*{conjectureEN*}{\conjecturenameEN}
\newtheorem{definitionEN}[theorem]{\definitionnameEN}
\newtheorem{exampleEN}[example]{\examplenameEN}
\newtheorem{problemEN}[problem]{\problemnameEN}
\newtheorem*{definitionEN*}{\definitionnameEN}
\newtheorem*{exampleEN*}{\examplenameEN}
\newtheorem*{problemEN*}{\problemnameEN}
\newtheorem{remarkEN}[remark]{\remarknameEN}
\newtheorem*{remarkEN*}{\remarknameEN}


\def\theoremnameEN{Theorem}
\def\lemmanameEN{Lemma}
\def\propositionnameEN{Proposition}
\def\corollarynameEN{Corollary}
\def\factnameEN{Fact}
\def\conjecturenameEN{Conjecture}
\def\definitionnameEN{Definition}
\def\examplenameEN{Example}
\def\problemnameEN{Problem}
\def\remarknameEN{Remark}

%% French theorems
\newtheorem{theoremFR}[theorem]{\theoremnameFR}
\newtheorem{lemmaFR}[theorem]{\lemmanameFR}
\newtheorem{propositionFR}[theorem]{\propositionnameFR}
\newtheorem{corollaryFR}[theorem]{\corollarynameFR}
\newtheorem{factFR}[theorem]{\factnameFR}
\newtheorem{conjectureFR}[conjecture]{\conjecturenameFR}
\newtheorem*{theoremFR*}{\theoremnameFR}
\newtheorem*{lemmaFR*}{\lemmanameFR}
\newtheorem*{propositionFR*}{\propositionnameFR}
\newtheorem*{corollaryFR*}{\corollarynameFR}
\newtheorem*{factFR*}{\factnameFR}
\newtheorem*{conjectureFR*}{\conjecturenameFR}
\newtheorem{definitionFR}[theorem]{\definitionnameFR}
\newtheorem{exampleFR}[example]{\examplenameFR}
\newtheorem{problemFR}[problem]{\problemnameFR}
\newtheorem*{definitionFR*}{\definitionnameFR}
\newtheorem*{exampleFR*}{\examplenameFR}
\newtheorem*{problemFR*}{\problemnameFR}
\newtheorem{remarkFR}[remark]{\remarknameFR}
\newtheorem*{remarkFR*}{\remarknameFR}

\def\theoremnameFR{Théorème}
\def\lemmanameFR{Lemme}
\def\propositionnameFR{Proposition}
\def\corollarynameFR{Corollaire}
\def\factnameFR{Fait}
\def\conjecturenameFR{Conjecture}
\def\definitionnameFR{Définition}
\def\examplenameFR{Exemple}
\def\problemnameFR{Problème}
\def\remarknameFR{Remarque}

%% cleveref configuration
\crefname{theoremEN}{\protect\MakeUppercase{\theoremnameEN}}{\protect\MakeUppercase{\theoremnameEN}}
\crefname{lemmaEN}{\protect\MakeUppercase{\lemmanameEN}}{\protect\MakeUppercase{\lemmanameEN}}
\crefname{propositionEN}{\protect\MakeUppercase{\propositionnameEN}}{\protect\MakeUppercase{\propositionnameEN}}
\crefname{corollaryEN}{\protect\MakeUppercase{\corollarynameEN}}{\protect\MakeUppercase{\corollarynameEN}}
\crefname{factEN}{\protect\MakeUppercase{\factnameEN}}{\protect\MakeUppercase{\factnameEN}}
\crefname{conjectureEN}{\protect\MakeUppercase{\conjecturenameEN}}{\protect\MakeUppercase{\conjecturenameEN}}
\crefname{definitionEN}{\protect\MakeUppercase{\definitionnameEN}}{\protect\MakeUppercase{\definitionnameEN}}
\crefname{exampleEN}{\protect\MakeUppercase{\examplenameEN}}{\protect\MakeUppercase{\examplenameEN}}
\crefname{problemEN}{\protect\MakeUppercase{\problemnameEN}}{\protect\MakeUppercase{\problemnameEN}}
\crefname{remarkEN}{\protect\MakeUppercase{\remarknameEN}}{\protect\MakeUppercase{\remarknameEN}}

\crefname{theoremFR}{\protect\MakeUppercase{\theoremnameFR}}{\protect\MakeUppercase{\theoremnameFR}}
\crefname{lemmaFR}{\protect\MakeUppercase{\lemmanameFR}}{\protect\MakeUppercase{\lemmanameFR}}
\crefname{propositionFR}{\protect\MakeUppercase{\propositionnameFR}}{\protect\MakeUppercase{\propositionnameFR}}
\crefname{corollaryFR}{\protect\MakeUppercase{\corollarynameFR}}{\protect\MakeUppercase{\corollarynameFR}}
\crefname{factFR}{\protect\MakeUppercase{\factnameFR}}{\protect\MakeUppercase{\factnameFR}}
\crefname{conjectureFR}{\protect\MakeUppercase{\conjecturenameFR}}{\protect\MakeUppercase{\conjecturenameFR}}
\crefname{definitionFR}{\protect\MakeUppercase{\definitionnameFR}}{\protect\MakeUppercase{\definitionnameFR}}
\crefname{exampleFR}{\protect\MakeUppercase{\examplenameFR}}{\protect\MakeUppercase{\examplenameFR}}
\crefname{problemFR}{\protect\MakeUppercase{\problemnameFR}}{\protect\MakeUppercase{\problemnameFR}}
\crefname{remarkFR}{\protect\MakeUppercase{\remarknameFR}}{\protect\MakeUppercase{\remarknameFR}}

%% Theorem environments
\NewDocumentEnvironment{theorem}{O{}}{\begin{theorem\csname\languagename ABBR\endcsname}[#1]}{\end{theorem\csname\languagename ABBR\endcsname}}
\NewDocumentEnvironment{theorem*}{O{}}{\begin{theorem\csname\languagename ABBR\endcsname*}[#1]}{\end{theorem\csname\languagename ABBR\endcsname*}}
\NewDocumentEnvironment{lemma}{O{}}{\begin{lemma\csname\languagename ABBR\endcsname}[#1]}{\end{lemma\csname\languagename ABBR\endcsname}}
\NewDocumentEnvironment{lemma*}{O{}}{\begin{lemma\csname\languagename ABBR\endcsname*}[#1]}{\end{lemma\csname\languagename ABBR\endcsname*}}
\NewDocumentEnvironment{proposition}{O{}}{\begin{proposition\csname\languagename ABBR\endcsname}[#1]}{\end{proposition\csname\languagename ABBR\endcsname}}
\NewDocumentEnvironment{proposition*}{O{}}{\begin{proposition\csname\languagename ABBR\endcsname*}[#1]}{\end{proposition\csname\languagename ABBR\endcsname*}}
\NewDocumentEnvironment{corollary}{O{}}{\begin{corollary\csname\languagename ABBR\endcsname}[#1]}{\end{corollary\csname\languagename ABBR\endcsname}}
\NewDocumentEnvironment{corollary*}{O{}}{\begin{corollary\csname\languagename ABBR\endcsname*}[#1]}{\end{corollary\csname\languagename ABBR\endcsname*}}
\NewDocumentEnvironment{fact}{O{}}{\begin{fact\csname\languagename ABBR\endcsname}[#1]}{\end{fact\csname\languagename ABBR\endcsname}}
\NewDocumentEnvironment{fact*}{O{}}{\begin{fact\csname\languagename ABBR\endcsname*}[#1]}{\end{fact\csname\languagename ABBR\endcsname*}}
\NewDocumentEnvironment{conjecture}{O{}}{\begin{conjecture\csname\languagename ABBR\endcsname}[#1]}{\end{conjecture\csname\languagename ABBR\endcsname}}
\NewDocumentEnvironment{conjecture*}{O{}}{\begin{conjecture\csname\languagename ABBR\endcsname*}[#1]}{\end{conjecture\csname\languagename ABBR\endcsname*}}
\NewDocumentEnvironment{definition}{O{}}{\begin{definition\csname\languagename ABBR\endcsname}[#1]}{\end{definition\csname\languagename ABBR\endcsname}}
\NewDocumentEnvironment{definition*}{O{}}{\begin{definition\csname\languagename ABBR\endcsname*}[#1]}{\end{definition\csname\languagename ABBR\endcsname*}}
\NewDocumentEnvironment{example}{O{}}{\begin{example\csname\languagename ABBR\endcsname}[#1]}{\end{example\csname\languagename ABBR\endcsname}}
\NewDocumentEnvironment{example*}{O{}}{\begin{example\csname\languagename ABBR\endcsname*}[#1]}{\end{example\csname\languagename ABBR\endcsname*}}
\NewDocumentEnvironment{problem}{O{}}{\begin{problem\csname\languagename ABBR\endcsname}[#1]}{\end{problem\csname\languagename ABBR\endcsname}}
\NewDocumentEnvironment{problem*}{O{}}{\begin{problem\csname\languagename ABBR\endcsname*}[#1]}{\end{problem\csname\languagename ABBR\endcsname*}}
\NewDocumentEnvironment{remark}{O{}}{\begin{remark\csname\languagename ABBR\endcsname}[#1]}{\end{remark\csname\languagename ABBR\endcsname}}
\NewDocumentEnvironment{remark*}{O{}}{\begin{remark\csname\languagename ABBR\endcsname*}[#1]}{\end{remark\csname\languagename ABBR\endcsname*}}


\def\sometext{Here's some text without a meaning. This text ...}

\begin{document}

In English:

\begin{theorem}\label{thm:1}
    \sometext
\end{theorem}

\begin{theorem*}
    \sometext
\end{theorem*}

\begin{definition}\label{def:1}
    \sometext
\end{definition}

\selectlanguage{french}

En français:

\begin{theorem}\label{thm:2}
    \sometext
\end{theorem}

\begin{theorem*}
    \sometext
\end{theorem*}

\begin{definition}\label{def:2}
    \sometext
\end{definition}

\selectlanguage{english}

See \cref{thm:1,thm:2,def:1,def:2}. % reference should be in their original language

\end{document}
2
  • It's not really clear what the difference between \CreateTheorem*{foo}, \CreateTheorem*{foo} and \CreateTheorem*{foo*} should be.
    – egreg
    Mar 7, 2021 at 13:21
  • @egreg \CreateTheorem creates numbered theorems, \CreateTheorem* creates unnumbered theorems. foo and foo* are just different choices of names, I chose to process them separately because I want fooEN*, not foo*EN.
    – Jinwen
    Mar 7, 2021 at 13:25

4 Answers 4

2

If you wish cleveref to work I suggest defining a counter ⟨name of environment⟩ and using the package aliascnt for defining alias-counters ⟨name of environment⟩EN and ⟨name of environment⟩FR.
(Splitting a trailing * from the ⟨name of environment⟩ is taken into account with the example below.)
Then you can define new theorems via
\newtheorem{⟨name of environment⟩EN}[⟨name of environment⟩EN]{⟨header⟩}
respective
\newtheorem{⟨name of environment⟩FR}[⟨name of environment⟩FR]{⟨header⟩}
and you run into problems

  • neither with cleveref or hyperref's \autoref choosing the right \..name-macro
  • nor with \newtheorem-directives where the counter to use is not specified with a trailing EN/FR.

 

\documentclass{article}

\usepackage[french,english]{babel}

\usepackage[T1]{fontenc} % <-- needed for French language !!!

\usepackage{xcolor}
\definecolor{paper}{RGB}{255,255,255}

\usepackage{mathtools}
\usepackage{amsthm}
\makeatletter
\newtheoremstyle{simple}%
    {}{}%
    {\normalfont}{}%
    {\normalfont}{}%
    {0pt}%
    {\thmname{\MakeUppercase{#1}}\thmnumber{ #2}\hspace{.4em}\textcolor{gray!55!paper}{$|$}\hspace{.4em}\color{gray}\thmnote{\ensuremath{(\text{#3})}~~}\pushQED{\qed}}
\def\@endtheorem{\popQED\endtrivlist\@endpefalse }
\makeatother

\renewcommand{\qedsymbol}{\makebox[1em]{\color{gray!55!paper}\rule[-0.1em]{.95em}{.95em}}}

\RequirePackage{aliascnt}
\PassOptionsToPackage{hidelinks,linktoc=all}{hyperref}
\RequirePackage{hyperref}
\PassOptionsToPackage{nameinlink}{cleveref}
\RequirePackage{cleveref}
\crefdefaultlabelformat{#2#1#3~\aftergroup\ignorespaces}

\theoremstyle{simple}

\newcommand\englishABBR{EN}
\newcommand\frenchABBR{FR}

%% macro for creating theorems
\RequirePackage{xstring}

\makeatletter
\newcommand\PassFirstToSecond[2]{#2{#1}}%
\NewDocumentCommand{\CreateTheorem}{sm}{%
  \begingroup
  \protected@edef\temp{#2}%
  \expandafter\IfEndWith\expandafter{\temp}{*}{%
    \expandafter\StrGobbleRight\expandafter{\temp}{1}[\temp]%
    \PassFirstToSecond{*}%
  }{%
    \PassFirstToSecond{}%
  }%
  {\expandafter\PassFirstToSecond\expandafter{\temp}{\endgroup\InnerCreateTheorem{#1}}}%
}%
\NewDocumentCommand{\InnerCreateTheorem}{mmmod<>}{%
   % #1 = Tokens denoting an xparse-boolean value;
   %      value "true" -> the call was \CreateTheorem*{...}...
   %      value "false" -> the call was \CreateTheorem{...}...
   %      This indicates whether the "starred" variant or the
   %      "unstarred" variant of \CreateTheorem was called.
   % #2 = Name of environment to define. One trailing
   %      star is removed from the environment-name provided 
   %      to \CreateTheorem if that environment-name has
   %      trailing stars.
   % #3 = If the environment-name provided to \CreateTheorem has
   %      trailing stars: A star (*).
   %      If the environment-name provided to \CreateTheorem has
   %      no trailing stars: Empty/no tokens at all.
   % #4 = numbered like=name of counter like which the environment
   %      shall be numbered.
   % #5 = numbered within=name of counter which is superordinate
   %      to the environment's counter and whose stepping resets
   %      the environment's counter.
   \IfBooleanTF{#1}{%
     \IfValueTF{#4}{\@firstoftwo}{\IfValueTF{#5}{\@firstoftwo}{\@secondoftwo}}%
   }{\IfValueTF{#4}{\IfValueTF{#5}{\@firstoftwo}{\@secondoftwo}}{\@secondoftwo}}%
   {%
    \GenericError{}%
                 {\string\CreateTheorem\space syntax error\on@line}%
                 {You cannot call the starred variant with optional arguments.\MessageBreak
                  You cannot call the unstarred variant with several optional arguments.}%
                 {%
                   Allowed usage:\MessageBreak\MessageBreak
                   \CreateTheorem*{(name of environment)}\MessageBreak
                   \CreateTheorem{(name of environment)}[(numbered like)]\MessageBreak
                   \CreateTheorem{(name of environment)}<(numbered within)>\MessageBreak
                   \CreateTheorem{(name of environment)}\MessageBreak
                   Captions come from macros \string\(name of environment)nameEN\MessageBreak
                   respective \string\(name of environment)nameFR.\MessageBreak
                   These macros must be defined separately.%
                 }%
   }{%
      \IfBooleanTF{#1}{%
        \expandafter\PassFirstToSecond\expandafter{\csname#2nameEN\endcsname}{\newtheorem*{#2EN#3}}%
        \expandafter\PassFirstToSecond\expandafter{\csname#2nameFR\endcsname}{\newtheorem*{#2FR#3}}%
      }{%
        \IfValueTF{#5}{%
          \newcounter{#2#3}[{#5}]%
          \expandafter\renewcommand\expandafter*\csname the#2#3\expandafter\endcsname\expandafter{\csname the#5\endcsname.\arabic{#2#3}}%
        }{%
          \IfValueTF{#4}{\newaliascnt{#2#3}{#4}}{\newcounter{#2#3}}%
        }%
        %-------------------------------------------------------------------------------------------------------------
        \CreateTheoremNumberedLikeAliasCounter{#2}{EN}{#3}%
        \CreateTheoremNumberedLikeAliasCounter{#2}{FR}{#3}%
        %-------------------------------------------------------------------------------------------------------------
      }%
      \NewDocumentEnvironment{#2#3}{}{\csname#2\csname\languagename ABBR\endcsname#3\endcsname}%
                                     {\csname end#2\csname\languagename ABBR\endcsname#3\endcsname}%
   }%
}%
\NewDocumentCommand{\CreateTheoremNumberedLikeAliasCounter}{mmm}{%
  \newaliascnt{#1#2#3}{#1#3}%
  \newtheorem{#1#2#3}[{#1#2#3}]{\csname#1name#2\endcsname}%
  \aliascntresetthe{#1#2#3}%
  \expandafter\PassFirstToSecond\expandafter{\expandafter\protect\expandafter\MakeUppercase\expandafter{\csname#1name#2\endcsname}}%
  {%
    \expandafter\PassFirstToSecond\expandafter{\expandafter\protect\expandafter\MakeUppercase\expandafter{\csname#1name#2\endcsname}}%
    {\crefname{#1#2#3}}%
  }%
}%
\makeatother

\def\theoremnameEN{Theorem}
\def\theoremnameFR{Théorème}
\def\definitionnameEN{Definition}
\def\definitionnameFR{Définition}
\def\remarknameEN{Remark}
\def\remarknameFR{Remarque}
\def\notenameEN{Note}
\def\notenameFR{Note}

\CreateTheorem{theorem}<section>
\CreateTheorem{definition}[theorem]
\CreateTheorem*{theorem*}
\CreateTheorem*{definition*}
\CreateTheorem*{remark}
\CreateTheorem{note*} % This is strange, only for test

\newcommand*\sometext{Here's some text without a meaning. This text ...}

\begin{document}

In English:

\begin{theorem}\label{thm:1}%
    \sometext
\end{theorem}

\begin{theorem*}
    \sometext
\end{theorem*}

\begin{definition}\label{def:1}%
    \sometext
\end{definition}

\selectlanguage{french}

En français:

\begin{theorem}\label{thm:2}%
    \sometext
\end{theorem}

\begin{theorem*}
    \sometext
\end{theorem*}

\begin{definition}\label{def:2}%
    \sometext
\end{definition}

\selectlanguage{english}

See \cref{thm:1,thm:2,def:1,def:2}. % reference should be in their original language

\end{document}

enter image description here

12
  • I have two questions: 1) Is the use of \PassFirstToSecond just to make the code look clearer, or is it because that it has some real propose? 2) How do \@firstoftwo, \@secondoftwo and \GenericError work here? That is, to whom \@firstoftwo and \@secondoftwo are pointing to?
    – Jinwen
    Mar 8, 2021 at 1:28
  • 1
    @Jinwen Ad 1:Think of \PassFirstToSecond as \PassFirstToSecond{<Argument-Tokens>}{<Argument-Processing-Tokens>} yielding <Argument-Processing-Tokens>{<Argument-Tokens>}. You can have TeX beforehand modify/change the <Argument-Tokens> by going at the <Argument-Tokens> via \expandafter or \romannumeral or some other expansion-trickery. Hereby you don't need to have TeX jump over an unknown amount of tokens but to jump over \PassFirstToSecond and { only. You can even use some forking for choosing which tokens to place behind <Argument-Processing-Tokens>. So there is a ... Mar 8, 2021 at 10:46
  • 1
    @Jinwen Ad 2: At the top of the definition of \InnerCreateTheorem you find a bunch of nested \IfBooleanTF- and \IfValueTF-directives which in the end either deliver \@firstoftwo or deliver \@secondoftwo. Behind that you find two macro-arguments which each holds a lot of tokens. These directives detect if star/optional arguments are provided in a combination not permitted with \newtheorem. If so, then \@firstoftwo is carried out which yields delivering the first argument without the surrounding curly braces and just removing the second argument. ... Mar 8, 2021 at 10:51
  • 1
    @Jinwen Ad 1: I often prefer \@firstoftwo/\@secondoftwo to \if<condition><A bunch of tokens>\else<Another bunch of tokens>\fi because with \@firstoftwo/\@secondoftwo tokens not carried out are removed from memory immediately instead of being accumulated until either being removed in some later stage of processing/expansion or causing TeX-capacity-exceeded-error-messages. Mar 8, 2021 at 10:53
  • 1
    @Jinwen You can do this and it will work out. But: Then the \csname..\endcsname-constructs are not evaluated only once, namely at the time of defining the theorem-environments but they get evaluated each time the environments are used. This way TeX has more work to do and needs more memory for storing the macro-definitions underlying the begin- and end-macros of the environments to define as these definitions will not consist of the single control-word-token formed from the evaluation of \csname..\endcsname but will consist of all tokens forming the \csname..\endcsname-expression. Mar 8, 2021 at 16:02
3

Not a direct answer to your question, but I believe your approach is not the best one.

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage[french,english]{babel}
\usepackage{xcolor}

\usepackage{amsthm}
\usepackage[hidelinks,linktoc=all]{hyperref}
\usepackage[nameinlink]{cleveref}

\definecolor{paper}{RGB}{255,255,255}

\newtheoremstyle{simple}%
  {}
  {}
  {\normalfont}
  {}
  {\normalfont}
  {}
  {0pt}
  {%
   \thmname{#1}%
   \thmnumber{ #2}%
   \hspace{.4em}%
   \textcolor{gray!55!paper}{$|$}%
   \hspace{.4em}\color{gray}%
   \thmnote{(#3)~~}\pushQED{\qed}%
  }
\makeatletter
\def\@endtheorem{\popQED\endtrivlist\@endpefalse}
\makeatother

\theoremstyle{simple}

\ExplSyntaxOn

\NewDocumentCommand{\CreateTheorem}{smm}
 {
  \IfBooleanTF{#1}
   {
    \jinwen_theorem_nonumber:nn { #2 } { #3 }
   }
   {
    \jinwen_theorem_number:nn { #2 } { #3 }
   }
 }

\keys_define:nn { jinwen/theorem }
 {
  within .tl_set:N = \l__jinwen_theorem_within_tl,
  like .tl_set:N = \l__jinwen_theorem_like_tl,
  name .tl_set:N = \l__jinwen_theorem_name_tl,
  unknown .code:n = 
   \prop_gput:cVn { g_jinwen_theorem_ \l__jinwen_theorem_main_tl _prop }
                  \l_keys_key_str { #1 },
 }
\tl_new:N \l__jinwen_theorem_main_tl
\str_new:N \l_jinwen_language_curr_str

\cs_new_protected:Nn \jinwen_theorem_nonumber:nn
 {
  \tl_set:Nn \l__jinwen_theorem_main_tl { #1 }
  \prop_new:c { g_jinwen_theorem_#1_prop }
  \keys_set:nn { jinwen/theorem }
   {
    #2, % set the given options
   }
  \newtheorem*{#1}{ \__jinwen_theorem_printname:n { #1 } }
 }
\cs_generate_variant:Nn \prop_item:Nn { cV }

\cs_new_protected:Nn \jinwen_theorem_number:nn
 {
  \tl_set:Nn \l__jinwen_theorem_main_tl { #1 }
  \prop_new:c { g_jinwen_theorem_#1_prop }
  \keys_set:nn { jinwen/theorem }
   {
    within = , % initialize to empty
    like =, % initialize to empty
    #2, % set the given options
   }
  \jinwen_theorem_new:nVV { #1 } \l__jinwen_theorem_within_tl \l__jinwen_theorem_like_tl
 }
\cs_new_protected:Nn \jinwen_theorem_new:nnn
 {
  \tl_if_blank:nTF { #2 }
   {% no within
    \tl_if_blank:nTF { #3 }
     {% no like
      \newtheorem{#1}{ \__jinwen_theorem_printname:n { #1 } }
     }
     {% numbered like
      \newtheorem{#1}[#3]{ \__jinwen_theorem_printname:n { #1 } }
     }
   }
   {% within
    \newtheorem{#1}{ \__jinwen_theorem_printname:n { #1 } }[#2]
   }
  \crefname{#1}{ \protect\__jinwen_theorem_printname:n { #1 } }
               { \protect\__jinwen_theorem_printname:n { #1 } }

 }
\cs_generate_variant:Nn \jinwen_theorem_new:nnn { nVV }

\cs_new:Nn \__jinwen_theorem_printname:n
 {
  \text_uppercase:n { \prop_item:cV { g_jinwen_theorem_#1_prop } \l_jinwen_language_curr_str }
 }

\addto\captionsenglish{\tl_set:Nn \l_jinwen_language_curr_str { EN } }
\addto\captionsfrench{\tl_set:Nn \l_jinwen_language_curr_str { FR } }

\ExplSyntaxOff

\CreateTheorem{theorem}{within=section,EN=Theorem,FR=Théorème}
\CreateTheorem{lemma}{EN=Lemma,FR=Lemme}
\CreateTheorem*{foo}{EN=abc,FR=xyz}

\CreateTheorem{theorem*}{like=theorem,EN=Easy Theorem,FR=Théorème facile}
\CreateTheorem*{foo*}{EN=foo,FR=xyz}

\begin{document}

\section{English}

\begin{lemma}\label{l}
This is a lemma.
\end{lemma}
\cref{l}

\begin{theorem}\label{a}
This is in English.
\end{theorem}
\cref{a}

\begin{theorem*}[Very easy]\label{b}
This is in English.
\end{theorem*}
\cref{b}

\begin{foo}
This is in English and is named abc.
\end{foo}

\begin{foo*}
This is in English and is named abc.
\end{foo*}

\selectlanguage{french}

\section{Français}

\begin{lemma}\label{m}
Ceci est un lemme.
\end{lemma}
\cref{m}

\begin{theorem}\label{c}
Ceci est en français.
\end{theorem}
\cref{c}

\begin{theorem*}[Très facile]\label{d}
Ceci est en français.
\end{theorem*}
\cref{d}

\begin{foo}
Ceci est en français et est nommé xyz.
\end{foo}

\begin{foo*}
Ceci est en français et est nommé xyz.
\end{foo*}

\end{document}

enter image description here

Of course there is too much uppercasing going on, but it's your document, not mine.

2

The following solves your \temp expansion issue by using two helper macros, one for the starred one for the unstarred case. The one in the unstarred case makes sure that only the correct optional arguments are forwarded, and throws an error if both were used.

You don't need \edef, this answer just expands your \temp macro using \expandafter. The general rule for \expandafter is that \expandafter<tokA><tokB> tries to expand <tokB> before <tokA> is expanded, so \expandafter\foo\expandafter{\stuff} will do the following (this lists four steps, but you can't really access these steps, TeX will do all these steps when it expands the first \expandafter once):

  1. \expandafter defers \foo:

    % to be reinserted
    \expandafter\foo
    % next things TeX will look at
    \expandafter{\stuff}
    
  2. the second \expandafter defers {:

    % to be reinserted
    \expandafter\foo\expandafter{%
    % next things TeX will look at
    \stuff}
    
  3. \stuff gets expanded and the deferred \expandafter{ gets put back (with \expandafter getting removed, <stuff> being the expansion of \stuff)

    % to be reinserted
    \expandafter\foo
    % next things TeX will look at
    {<stuff>}
    
  4. and finally \expandafter\foo gets reinserted and the \expandafter is removed

    % next things TeX will look at
    \foo{<stuff>}
    

Now \foo can do its thing and all it does see is the expansion of \stuff (expanded just once, which is fine in your use case).

All this applied to your code to create new theorem environments:

\documentclass{article}

\usepackage[french,english]{babel}

\usepackage{xcolor}
\definecolor{paper}{RGB}{255,255,255}

\usepackage{mathtools}
\usepackage{amsthm}
\makeatletter
\newtheoremstyle{simple}%
    {}{}%
    {\normalfont}{}%
    {\normalfont}{}%
    {0pt}%
    {\thmname{\MakeUppercase{#1}}\thmnumber{ #2}\hspace{.4em}\textcolor{gray!55!paper}{$|$}\hspace{.4em}\color{gray}\thmnote{\ensuremath{(\text{#3})}~~}\pushQED{\qed}}
\def\@endtheorem{\popQED\endtrivlist\@endpefalse }
\makeatother

\renewcommand{\qedsymbol}{\makebox[1em]{\color{gray!55!paper}\rule[-0.1em]{.95em}{.95em}}}

\PassOptionsToPackage{hidelinks,linktoc=all}{hyperref}
\RequirePackage{hyperref}
\PassOptionsToPackage{nameinlink}{cleveref}
\RequirePackage{cleveref}
\crefdefaultlabelformat{#2#1#3~\aftergroup\ignorespaces}

\theoremstyle{simple}

\newcommand\englishABBR{EN}
\newcommand\frenchABBR{FR}

%% macro for creating theorems
\RequirePackage{xstring}
\makeatletter
\newcommand\jinwen@createenvironment@starred[2]
  {%
    % #1: name
    % #2: star or empty
    \newtheorem*{#1EN#2}{\csname#1nameEN\endcsname}%
    \newtheorem*{#1FR#2}{\csname#1nameFR\endcsname}%
    \NewDocumentEnvironment{#1#2}{O{}}
      {\begin{#1\csname\languagename ABBR\endcsname#2}[{##1}]}
      {\end{#1\csname\languagename ABBR\endcsname#2}}%
  }
\newcommand\jinwen@createenvironment@nostar[4]
  {%
    % #1: name
    % #2: star or empty
    % #3: first optional argument to \newtheorem
    % #4: second optional argument to \newtheorem
    \IfNoValueTF{#3}
      {%
        \IfNoValueTF{#4}
          {%
            \newtheorem{#1EN#2}{\csname #1nameEN\endcsname}%
            \newtheorem{#1FR#2}{\csname #1nameFR\endcsname}%
          }%
          {%
            \newtheorem{#1EN#2}{\csname #1nameEN\endcsname}[{#4}]%
            \newtheorem{#1FR#2}{\csname #1nameFR\endcsname}[{#4}]%
          }%
      }%
      {%
        \IfNoValueTF{#4}
          {%
            \newtheorem{#1EN#2}[{#3}]{\csname #1nameEN\endcsname}%
            \newtheorem{#1FR#2}[{#3}]{\csname #1nameFR\endcsname}%
          }%
          {%
            \PackageError{jinwen}
              {%
                You can't use both optional arguments,\MessageBreak
                they are mutually exclusive!\@gobble%
              }
              {}%
          }%
      }%
    \crefname{#1EN#2}
      {\protect\MakeUppercase{\csname #1nameEN\endcsname}}
      {\protect\MakeUppercase{\csname #1nameEN\endcsname}}%
    \crefname{#1FR#2}
      {\protect\MakeUppercase{\csname #1nameFR\endcsname}}
      {\protect\MakeUppercase{\csname #1nameFR\endcsname}}%
    \NewDocumentEnvironment{#1#2}{O{}}
      {\begin{#1\csname\languagename ABBR\endcsname#2}[{##1}]}
      {\end{#1\csname\languagename ABBR\endcsname#2}}%
  }
\NewDocumentCommand{\CreateTheorem}{smod<>}
  {%
    \IfBooleanTF{#1}
      {% Stared version
        \IfEndWith{#2}{*}
          {% \CreateTheorem*{theorem*}
              \StrGobbleRight{#2}{1}[\temp]%
              \expandafter\jinwen@createenvironment@starred\expandafter{\temp}{*}%
          }
          {% \CreateTheorem*{theorem}
              \jinwen@createenvironment@starred{#2}{}%
          }%
      }
      {% Non-stared version
        \IfEndWith{#2}{*}
          {% \CreateTheorem{theorem*}[...]<...>
            \StrGobbleRight{#2}{1}[\temp]%
            \expandafter\jinwen@createenvironment@nostar\expandafter
              {\temp}{*}{#3}{#4}%
          }
          {% \CreateTheorem{theorem}[...]<...>
            \jinwen@createenvironment@nostar{#2}{}{#3}{#4}%
          }%
      }%
  }
\makeatother
\def\theoremnameEN{Theorem}
\def\theoremnameFR{Théorème}
\def\definitionnameEN{Definition}
\def\definitionnameFR{Définition}
\def\remarknameEN{Remark}
\def\remarknameFR{Remarque}
\def\notenameEN{Note}
\def\notenameFR{Note}

\newcounter{theorem}
\CreateTheorem{theorem}<section>
\CreateTheorem{definition}[theorem]
\CreateTheorem*{theorem*}
\CreateTheorem*{definition*}
\CreateTheorem*{remark}
\CreateTheorem{note*} % This is strange, only for test

\begin{document}

\begin{theorem}
\end{theorem}

\begin{definition}
\end{definition}

\end{document}
1

If I understand well what do you want:

\createtheorem *{definition*}[theorem] ->          
    \newtheorem *{definitionEN*}[theorem]{\definitionnameEN}
    \newtheorem *{definitionFR*}[theorem]{\definitionnameFR}    

\createtheorem *{definition}[theorem] ->          
    \newtheorem *{definitionEN}[theorem]{\definitionnameEN}
    \newtheorem *{definitionFR}[theorem]{\definitionnameFR}

\createtheorem {definition}[theorem] ->          
    \newtheorem {definitionEN}[theorem]{\definitionnameEN}
    \newtheorem {definitionFR}[theorem]{\definitionnameFR}

\createtheorem {definition} ->          
    \newtheorem {definitionEN}{\definitionnameEN}
    \newtheorem {definitionFR}{\definitionnameFR}

\createtheorem*{definition} ->          
    \newtheorem*{definitionEN}{\definitionnameEN}
    \newtheorem*{definitionFR}{\definitionnameFR}

\createtheorem*{definition*} ->          
    \newtheorem*{definitionEN*}{\definitionnameEN}
    \newtheorem*{definitionFR*}{\definitionnameFR}

I don't understand what these asterisks and paremeters in [..] exactly mean (because I don't use LaTeX), but it does not matter. If you want to do such macro \createtheroem, you can use this code:

\def\createtheorem#1#{\def\astA{#1}\createthmA}
\def\createthmA#1{\def\themname{#1}\futurelet\next\createthmB}
\def\createthmB{\ifx[\next\afterfi{\createthmC}\else\afterfi{\createthmC[]}\fi}
\def\createthmC[#1]{\def\astB{}\def\themopt{#1}%
   \expandafter\createthmD\themname*\end % \themname + *->\astB
   \createthmE{EN}\createthmE{FR}%
}
\def\createthmD#1*#2\end{\ifx^#2^\else\def\themname{#1}\def\astB{*}\fi}
\def\createthmE#1{%
    \edef\act{\noexpand\newtheorem\astA{\themname#1\astB}%
              \ifx\themopt\empty \else[\themopt]\fi
              {\expandafter\noexpand\csname\themname name#1\endcsname}}\act
}
\def\afterfi#1#2\fi{\fi#1}

You must log in to answer this question.

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