3

Based on this answer, I wrote a macro \CreateTheorem, which can be used in the following five ways:

  1. \CreateTheorem*{env}, which creates an unnumbered theorem-like environment env;
  2. \CreateTheorem{env}, which creates a numbered theorem-like environment env, numbered in order 1,2,3,...
  3. \CreateTheorem{env}[numberlike], which creates a numbered theorem-like environment env, shares the counter numberlike;
  4. \CreateTheorem{env}<numberwithin>, which creates a numbered theorem-like environment env, numbered within the counter numberwithin;
  5. \CreateTheorem*{env}(existedenv) or \CreateTheorem{env}(existedenv), which identifies the environment env with an existed environment existedenv;

    here \CreateTheorem*{env}(existedenv) has the same effect with \CreateTheorem{env}(existedenv*)

And to support multi-language, \CreateTheorem reads the macro \envnameEN, \envnameFR, \envnameDE etc. to get the label of the theorem-like environment env. It will then create environments envEN, envFR, envDE etc., and set the crefname accordingly, and finally define the environment env to select the appropriate environment based on the name of the current language.

Note that, if one writes \CreateTheorem*{env*}, then the language-specified environments will be named envEN*, envFR*, envDE* etc, not env*EN.

This macro is now part of the ProjLib toolkit: https://ctan.org/pkg/projlib. Since many commonly used theorem-like environments have been pre-defined, one can use it as in the following MWE:

\documentclass{article}

\usepackage{PJLthm}

\def\ideanameFR{Idée}
\CreateTheorem{idea}[theorem]

\UseLanguage{French}

\begin{document}

\begin{theorem}\label{thm}
    Un théorème en français.
\end{theorem}
\begin{idea}\label{idea}
    Une idée en français.
\end{idea}

\cref{thm,idea}

\end{document}

which resulted in:

enter image description here

However, the performance of the current implementation is relatively low. On my PC, the above MWE takes about 8s. The reason I believe this can be heavily improved is that if one removes those lines setting \crefname, the time would be reduced to 2s. Thus, I'm seeking a way to achieve the same result as the current \CreateTheorem, but only takes about 3s. Any suggestion is welcomed. Thanks in advance!


The current implementation of \CreateTheorem is:

\RequirePackage{PJLlang}
\RequirePackage{amsmath,amsthm}
\RequirePackage{aliascnt}
\PassOptionsToPackage{nameinlink}{cleveref}
\RequirePackage{cleveref}

\RequirePackage{xstring}
\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<>d()}{%
% #1 = star or no star
% #2 = name of environment
% #3 = emptiness or star to append to name of environment
% #4 = numbered like
% #5 = numbered within
% #6 = existed environment
    \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 argument,\MessageBreak
        nor call the unstarred variant with several optional arguments.}%
        {}%
    }{%
        \IfValueTF{#6}{%
            \IfBooleanTF{#1}{%
                \ifcsmacro{#2#3}%
                {\renewenvironment{#2#3}{\begin{#6*}}{\end{#6*}}}%
                {\newenvironment{#2#3}{\begin{#6*}}{\end{#6*}}}%
            }{%
                \ifcsmacro{#2#3}%
                {\renewenvironment{#2#3}{\begin{#6}}{\end{#6}}}%
                {\newenvironment{#2#3}{\begin{#6}}{\end{#6}}}%
            }
        }{%
            \IfBooleanTF{#1}{%
                \newtheorem*{#2EN#3}{\csname#2nameEN\endcsname}
                \newtheorem*{#2FR#3}{\csname#2nameFR\endcsname}
                \newtheorem*{#2DE#3}{\csname#2nameDE\endcsname}
                \newtheorem*{#2CN#3}{\csname#2nameCN\endcsname}
                \newtheorem*{#2TC#3}{\csname#2nameTC\endcsname}
                \newtheorem*{#2JP#3}{\csname#2nameJP\endcsname}
                \newtheorem*{#2RU#3}{\csname#2nameRU\endcsname}
            }{%
                \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}%
                \CreateTheoremNumberedLikeAliasCounter{#2}{DE}{#3}%
                \CreateTheoremNumberedLikeAliasCounter{#2}{CN}{#3}%
                \CreateTheoremNumberedLikeAliasCounter{#2}{TC}{#3}%
                \CreateTheoremNumberedLikeAliasCounter{#2}{JP}{#3}%
                \CreateTheoremNumberedLikeAliasCounter{#2}{RU}{#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}%
    \crefname{#1#2#3}%
        {\csname#1name#2\endcsname}%
        {\csname#1name#2\endcsname}%
    \Crefname{#1#2#3}%
        {\csname#1name#2\endcsname}%
        {\csname#1name#2\endcsname}%
}%
4

In your original question "Help on a macro \CreateTheorem(*)" I found the following preliminaries:

  1. The \CreateTheorem-mechanism is to work also when package(s) amsthm and/or cleveref are/is loaded.
  2. The underlying macros, whose arguments need to be arranged properly, are \newtheorem, \crefname, \Crefname, etc.

The problem with my current approach is that

  • \newtheorem is slow and is carried out often.
  • cleveref's macros \Crefname and \crefname are slow and are carried out often.
  • loading the package cleveref takes some time

You can see the slowness of \newtheorem etc by deriving a damaged/crippled variant of PJLthm.sty where

  • instances of \Crefname and \crefname and \newtheorem are replaced by instances of argument-gobbling-macros.
  • the loading of cleveref is removed.
  • package-name and version is changed.

When using the crippled/damaged variant of the package for benchmarking, make sure that no attempts take place at using the environments that should be defined as with the crippled/damaged variant defining in terms of underlying \newtheorem/\Crefname/\crefname does not take place and therefore with the crippled/damaged variant of the package environments that should be defined are not available.


I just downloaded ProjLib [2021/08/07a] from CTAN and compiled the .ins-files for obtaining the .sty-files.

When I save the example

\documentclass{article}

\makeatletter
\def\@gobblethree#1#2#3{}%
\def\@gobbleMandOptMand#1[#2]#3{}%
\makeatother

\usepackage[originalref]{PJLthm}

\UseLanguage{French}

% For some reason the package defines the theorem-environment
% via \AtEndPreamble.
% Therefore theorems based on that cannot be defined within the preamble
% unless via \AtEndPreamble or \AtBeginDocument or the like.

\AtEndPreamble{%
  \def\ideanameFR{Idée}%
  \CreateTheorem{idea}[theorem]%
}%


\begin{document}

%%%\begin{theorem}\label{thm}
%%%    Un théorème en français.
%%%\end{theorem}
%%%\begin{idea}\label{idea}
%%%    Une idée en français.
%%%\end{idea}

%%%\cref{thm,idea}

\end{document}

as test.tex and on Debian Linux do
time pdflatex test.tex

, then I get:

real    1m0,548s
user    1m0,284s
sys     0m0,134s

When I derive PJLthmDamaged.sty from PJLthm.sty by

  • replacing instances of \Crefname and \crefname and \newtheorem by instances of argument-gobbling-macros,
  • removing the loading of cleveref,
  • changing package-name and version,

so that the diff-file Patch.diff looks like this:

--- PJLthm.sty
+++ PJLthmDamaged.sty
@@ -1,23 +1,17 @@
 %%
-%% This is file `PJLthm.sty',
-%% generated with the docstrip utility.
-
-%% Copyright (C) 2021 by Jinwen XU
-%% 
-%% This is part of the ProjLib Toolkit.
-%% 
-%% This work may be distributed and/or modified under the conditions of the
-%% LaTeX Project Public License, either version 1.3c of this license or (at
-%% your option) any later version. The latest version of this license is in
-%% 
-%%     http://www.latex-project.org/lppl.txt
-%% 
-%% and version 1.3c or later is part of all distributions of LaTeX version
-%% 2005/12/01 or later.
+%% This is file `PJLthmDamaged.sty',
+%% generated by Ulrich Diez via manually editing
+%%
+%%   `PJLthm.sty',
+%%    Copyright (C) 2021 by Jinwen XU
 %% 
+%% in August 10, 2021, 18:24:37(UTC)
+%% in order to create a crippled/damaged variant which does not
+%% perform all the \Crefname/\crefname/\newtheorem.
+%%
 \NeedsTeXFormat{LaTeX2e}[2020-10-01]
-\ProvidesPackage{PJLthm}
-    [2021/08/07a Theorem setup and configuration]
+\ProvidesPackage{PJLthmDamaged}
+    [2021/08/10 Damaged!!!! theorem setup and configuration]
 \RequirePackage{kvoptions}
 \RequirePackage{etoolbox}
 \SetupKeyvalOptions{%
@@ -45,8 +39,8 @@
 \RequirePackage{PJLlang}
 \RequirePackage{amsmath,amsthm}
 \RequirePackage{aliascnt}
-\PassOptionsToPackage{nameinlink}{cleveref}
-\RequirePackage{cleveref}
+%%\PassOptionsToPackage{nameinlink}{cleveref}
+%%\RequirePackage{cleveref}
 
 \NewDocumentCommand{\NameTheorem}{omm}{%
     \protected@edef\PJLthm@temp{#2}%
@@ -176,8 +170,8 @@
             {\IfValueTF{#5}{\@firstoftwo}{\@secondoftwo}}%
     }{%
         \IfValueTF{#4}
-            {\IfValueTF{#5}{\@firstoftwo}{\@secondoftwo}}{
-            \@secondoftwo}
+            {\IfValueTF{#5}{\@firstoftwo}{\@secondoftwo}}{%%%%
+            \@secondoftwo}%%%%
     }%
     {%
         \GenericError{}%
@@ -205,17 +199,17 @@
             }
         }{%
             \IfBooleanTF{#1}{%
-                \if@PJLlang@enable@EN\expandafter\PassFirstToSecond\expandafter{\csname#2nameEN\endcsname}{\newtheorem*{#2EN#3}}\fi%
-                \if@PJLlang@enable@FR\expandafter\PassFirstToSecond\expandafter{\csname#2nameFR\endcsname}{\newtheorem*{#2FR#3}}\fi%
-                \if@PJLlang@enable@DE\expandafter\PassFirstToSecond\expandafter{\csname#2nameDE\endcsname}{\newtheorem*{#2DE#3}}\fi%
-                \if@PJLlang@enable@IT\expandafter\PassFirstToSecond\expandafter{\csname#2nameIT\endcsname}{\newtheorem*{#2IT#3}}\fi%
-                \if@PJLlang@enable@PT\expandafter\PassFirstToSecond\expandafter{\csname#2namePT\endcsname}{\newtheorem*{#2PT#3}}\fi%
-                \if@PJLlang@enable@BR\expandafter\PassFirstToSecond\expandafter{\csname#2nameBR\endcsname}{\newtheorem*{#2BR#3}}\fi%
-                \if@PJLlang@enable@ES\expandafter\PassFirstToSecond\expandafter{\csname#2nameES\endcsname}{\newtheorem*{#2ES#3}}\fi%
-                \if@PJLlang@enable@CN\expandafter\PassFirstToSecond\expandafter{\csname#2nameCN\endcsname}{\newtheorem*{#2CN#3}}\fi%
-                \if@PJLlang@enable@TC\expandafter\PassFirstToSecond\expandafter{\csname#2nameTC\endcsname}{\newtheorem*{#2TC#3}}\fi%
-                \if@PJLlang@enable@JP\expandafter\PassFirstToSecond\expandafter{\csname#2nameJP\endcsname}{\newtheorem*{#2JP#3}}\fi%
-                \if@PJLlang@enable@RU\expandafter\PassFirstToSecond\expandafter{\csname#2nameRU\endcsname}{\newtheorem*{#2RU#3}}\fi%
+                \if@PJLlang@enable@EN\expandafter\PassFirstToSecond\expandafter{\csname#2nameEN\endcsname}{\@gobbletwo{#2EN#3}}\fi
+                \if@PJLlang@enable@FR\expandafter\PassFirstToSecond\expandafter{\csname#2nameFR\endcsname}{\@gobbletwo{#2FR#3}}\fi
+                \if@PJLlang@enable@DE\expandafter\PassFirstToSecond\expandafter{\csname#2nameDE\endcsname}{\@gobbletwo{#2DE#3}}\fi
+                \if@PJLlang@enable@IT\expandafter\PassFirstToSecond\expandafter{\csname#2nameIT\endcsname}{\@gobbletwo{#2IT#3}}\fi
+                \if@PJLlang@enable@PT\expandafter\PassFirstToSecond\expandafter{\csname#2namePT\endcsname}{\@gobbletwo{#2PT#3}}\fi
+                \if@PJLlang@enable@BR\expandafter\PassFirstToSecond\expandafter{\csname#2nameBR\endcsname}{\@gobbletwo{#2BR#3}}\fi
+                \if@PJLlang@enable@ES\expandafter\PassFirstToSecond\expandafter{\csname#2nameES\endcsname}{\@gobbletwo{#2ES#3}}\fi
+                \if@PJLlang@enable@CN\expandafter\PassFirstToSecond\expandafter{\csname#2nameCN\endcsname}{\@gobbletwo{#2CN#3}}\fi
+                \if@PJLlang@enable@TC\expandafter\PassFirstToSecond\expandafter{\csname#2nameTC\endcsname}{\@gobbletwo{#2TC#3}}\fi
+                \if@PJLlang@enable@JP\expandafter\PassFirstToSecond\expandafter{\csname#2nameJP\endcsname}{\@gobbletwo{#2JP#3}}\fi
+                \if@PJLlang@enable@RU\expandafter\PassFirstToSecond\expandafter{\csname#2nameRU\endcsname}{\@gobbletwo{#2RU#3}}\fi
             }{%
                 \IfValueTF{#5}{%
                     \newcounter{#2#3}[{#5}]%
@@ -241,7 +235,7 @@
                 \if@PJLlang@enable@RU\CreateTheoremNumberedLikeAliasCounter{#2}{RU}{#3}\fi%
                 %---------------------------------------------------------------
             }%
-            \NewDocumentEnvironment{#2#3}{}
+            \NewDocumentEnvironment{#2#3}{}%%%
                 {\csname#2\csname\languagename ABBR\endcsname#3\endcsname}%
                 {\csname end#2\csname\languagename ABBR\endcsname#3\endcsname}%
         }%
@@ -249,17 +243,17 @@
 }%
 \NewDocumentCommand{\CreateTheoremNumberedLikeAliasCounter}{mmm}{%
     \newaliascnt{#1#2#3}{#1#3}%
-    \expandafter\PassFirstToSecond\expandafter{\csname#1name#2\endcsname}{\newtheorem{#1#2#3}[{#1#2#3}]}%
+    \expandafter\PassFirstToSecond\expandafter{\csname#1name#2\endcsname}{\@gobbleMandOptMand{#1#2#3}[{#1#2#3}]}%
     \aliascntresetthe{#1#2#3}%
     \expandafter\PassFirstToSecond\expandafter{\csname#1name#2\endcsname}%
     {%
         \expandafter\PassFirstToSecond\expandafter{\csname#1name#2\endcsname}%
-        {\crefname{#1#2#3}}%
+        {\@gobblethree{#1#2#3}}%
     }%
     \expandafter\PassFirstToSecond\expandafter{\csname#1name#2\endcsname}%
     {%
         \expandafter\PassFirstToSecond\expandafter{\csname#1name#2\endcsname}%
-        {\Crefname{#1#2#3}}%
+        {\@gobblethree{#1#2#3}}%
     }%
 }%
 \fi
@@ -702,4 +696,4 @@
 
 \endinput
 %%
-%% End of file `PJLthm.sty'.
+%% End of file `PJLthmDamaged.sty'.

and save the example

\documentclass{article}

\makeatletter
\def\@gobblethree#1#2#3{}%
\def\@gobbleMandOptMand#1[#2]#3{}%
\makeatother

\usepackage[originalref]{PJLthmDamaged}

\UseLanguage{French}

% For some reason the package defines the theorem-environment
% via \AtEndPreamble.
% Therefore theorems based on that cannot be defined within the preamble
% unless via \AtEndPreamble or \AtBeginDocument or the like.

\AtEndPreamble{%
  \def\ideanameFR{Idée}%
  \CreateTheorem{idea}[theorem]%
}%


\begin{document}

%%%\begin{theorem}\label{thm}
%%%    Un théorème en français.
%%%\end{theorem}
%%%\begin{idea}\label{idea}
%%%    Une idée en français.
%%%\end{idea}

%%%\cref{thm,idea}

\end{document}

as test.tex (same example as above, the only fifference is, that PJLthmDamaged.sty is loaded instead of PJLthm.sty) and on Debian Linux do
time pdflatex test.tex

, then I get:

real    0m1,614s
user    0m1,522s
sys     0m0,084s

The ratio
⟨compilation-time without disabling \newtheorem\crefname\Crefname⟩ : ⟨compilation-time with disabling \newtheorem\crefname\Crefname⟩ 
on my machine is about 38 : 1 !

You can see that with my current approach the slowness is not that much due to the code I wrote around the calls to \newtheorem etc for properly arranging the arguments of \newtheorem etc, but is more due to the frequency with which \newtheorem etc actually are carried out.

Thus I don't see ways of getting things compiled considerably faster other than reducing the amount of \newtheorem etc to carry out.

In this context, however, the requirement of \CreateTheorem also working while amsthm is in use is a problem—remembering the "joyful" comments about ams-things in the commented source code of previous hyperref package releases: When does a problem not have to do with ams-math-stuff? (-:

amsthm redefines internals of \newtheorem so that you cannot use a placeholder for the counter to use with the theorem to be defined.

Otherwise you could, e.g.,

  • have a macro \languagename which is to hold the name of the language currently in use

  • via \newcountr define a counter counter

  • temporarily define \languagename to be empty

  • do something like

    \newtheorem{theorem}[counter\languagename]{\csname theorem\languagename heading\endcsname}

  • restore \languagename

  • and for each ⟨languagename⟩ maintain an alias-counter whose name is of pattern counter⟨languagename⟩ and which is an alias of the "underlying" real counter counter and define macros whose names are of pattern \theorem⟨languagename⟩heading.

    (\languagename must temporarily be defined to be empty in order to prevent \newtheorem from delivering an error-message in case currently a language is in use where no language-specific alias-counter for the environment's real counter is defined yet.)

Without amsthm you can do this because without amsthm the tokens counter\languagename go into the definition of the environment in question unevaluated/unexpanded and are evaluated at the time of carrying out instances of the environment in question.

With amsthm, however, you can't do this because amsthm redefines things in a way where not the the tokens counter\languagename go into the definition of the environment in question but the control-word-token resulting from evaluating \csname thecounter\languagename\endcsname goes into the definition of the environment in question.

I.e., with amsthm the token \languagename is evaluated at the time of defining the environment in question and therefore doesn't make it into the definition of the environment in question.

When patching amsthm's redefinitions of the internals of \newtheorem so that—as is the case without amsthm—the tokens forming the name of the counter in use go into the definition of the environment in question unexpanded/unevaluated, then you would not need to define an internal theorem-environment theorem⟨languagename⟩ for each kind of theorem in each language, but one call to \newtheorem per group of theorems of same kind but differing in language would be sufficient.

If you don't mind patching the internal macro \@ynthm in case amsthm/cleveref is loaded—the patch could be arranged to be valid only during carrying out \CreateTheorem—, a solution according to the approach just outlined might be possible.

So far I have been reluctant to patch an internal macro, which, by the way, is also patched by other packages, for the following reasons:

  • E.g., the packages cleveref and hyperref in turn also patch the amsthm-code of \@ynthm. I did not yet delve into the code of cleveref deep enough to find out about all the details.
  • I don't know about the ways in which such patching would affect other packages about cross-referencing or theorems, e.g., the packages varioref or theorem.
  • Patching code of other packages implies the need of keeping track of changes to the code which your package is patching. This doesn't make maintenance of the package more easy.
  • Patching code of other packages implies the need of ensuring that your package in any case is loaded after those packages whose code it needs to patch. This doesn't make usage of the package more easy.

In case you are interested in such an approach despite its drawbacks, let me know and I might delve into the code of cleveref etc and edit this answer when I am done.

An initial experimental start, but one that needs intensive revision, debugging, adjusting, rectifying and thought, might be something like the following:

\documentclass[french,english,ngerman]{article}
\usepackage{babel}

\usepackage{xcolor}
  \definecolor{paper}{RGB}{255,255,255}
\PassOptionsToPackage{nameinlink}{cleveref}
\usepackage{hyperref}
\usepackage{mathtools}
\usepackage{amsthm}



\makeatletter
\RequirePackage{aliascnt}
\RequirePackage{cleveref}
\crefdefaultlabelformat{#2#1#3}
\RequirePackage{etoolbox}
\@ifdefinable\@ynthmcopyA{\let\@ynthmcopyA\@ynthm}
\@ifdefinable\@ynthmcopyB{\let\@ynthmcopyB\@ynthm}
\newcommand\languagenamecopy{}

\@ifpackageloaded{amsthm}{\iftrue}{\csname iffalse\endcsname}%
  \patchcmd{\@ynthmcopyA}%
           {\@xp\xdef\csname the#1\endcsname{\@xp\@nx\csname the#2\endcsname}}%
           {\@xp\gdef\csname the#1\endcsname{\csname the#2\endcsname}}%
           {\message{!!! Patching successful !!!}}%
           {\message{!!! Patching failed !!!}}%
  \patchcmd{\@ynthmcopyA}%
           {{#2}{\the\toks@}}%
           {{\unexpanded{#2}}{\the\toks@}}%
           {\message{!!! Patching successful !!!}}%
           {\message{!!! Patching failed !!!}}%
  \@ifpackageloaded{cleveref}{\iftrue}{\csname iffalse\endcsname}%
    % !!! Probably some more things need to be done.
    % !!! E.g., I did not yet grasp what all this preamble-stuff in
    % !!! cleveref's redefinition of \@ynthm is about.
    \patchcmd{\@ynthmcopyA}%
             {\@thm[#1]}%
             {\@thm[#1\@nx\languagename]}%
             {\message{!!! Patching successful !!!}}%
             {\message{!!! Patching failed !!!}}%
  \fi
\fi

\makeatother

\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}%
    }
% One needs to see if something can be done about this:
\def\@endtheorem{\popQED\endtrivlist\@endpefalse}%
% because the redifinition applies to all theorem-environments, not just 
% those defined with theoremstyle "simple". Probably the new 
% environment-hook-management of up-to-date LaTeX-kernels can be used.

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

\newcounter{theorem}

\newaliascnt{theoremenglish}{theorem}%
\aliascntresetthe{theoremenglish}%
\newcommand\theoremenglishheading{Theorem}%
\newcommand\theoremenglishname{Theorem}%
\crefname{theoremenglish}{theorem}{Theorem}%

\newaliascnt{theoremfrench}{theorem}%
\aliascntresetthe{theoremfrench}%
\newcommand\theoremfrenchheading{Théorème}%
\newcommand\theoremfrenchname{Théorème}%
\crefname{theoremfrench}{théorème}{Théorème}%

\newaliascnt{theoremngerman}{theorem}%
\aliascntresetthe{theoremngerman}%
\newcommand\theoremngermanheading{GTheorem}%
\newcommand\theoremngermanname{GTheorem}%
\crefname{theoremngerman}{gtheorem}{GTheorem}%

\theoremstyle{simple}

\makeatletter
\let\@ynthm\@ynthmcopyA
\let\languagenamecopy\languagename
\let\languagename\empty
\newtheorem{theorem}[theorem\languagename]{\csname theorem\languagename heading\endcsname}
\let\@ynthm\@ynthmcopyB
\let\languagename\languagenamecopy
\makeatother

\begin{document}

\begin{theorem}\label{theoremA}%
bla bla
\end{theorem}

\selectlanguage{french}

\begin{theorem}\label{theoremB}%
blu blu
\end{theorem}

\ref{theoremA}\\
\pageref{theoremA}\\
\autoref{theoremA}\\
% \nameref{theoremA}\\
\cref{theoremA,theoremB}

\ref{theoremB}\\
\pageref{theoremB}\\
\autoref{theoremB}\\
% \nameref{theoremB}\\
\cref{theoremA,theoremB}

\end{document}

enter image description here

I have some questions regarding the "user interface":

  1. How about following the convention of naming languages as they are named in the babel package? Then you could get the name of the language currently in use from the macro \languagename. And you could simply use babel's infrastructure (\selectlanguage, \foreignlanguage etc) to change the language. babel's infrastructure would automatically set/adjust \languagename. Language specific defined structures would have names that can be obtained using the expansion of the macro \languagename. E.g. not "counterFR" but "counterfrench or "counterenglish", so that one could also say "counter\languagename" in general.

  2. What about using expl3 for adding an argument with comma-list/key=value-syntax for those cases where \CreateTheorem is used for creating numbered theorems? Something like

    \CreateTheorem{MyTheorem}[superordinate counter]{%
      EN={%
         crefname={bla}{bla}{bla}, %<- for cleveref's \crefname with aliascounter MyTheoremEN
         Crefname={bla}{bla}{bla} %<- for cleveref's \Crefname with aliascounter MyTheoremEN
         name=bla, %<- for the macro \MyTheoremENname
         autoref=bla,%<- for the macro \MyTheoremENautorefname with aliascounter MyTheoremEN
         heading=Theorem heading in English %<- for the macro \MyTheoremENheading
      },
      FR={%
         crefname={bla}{bla}{bla}, %<- for cleveref's \crefname with aliascounter MyTheoremFR
         Crefname={bla}{bla}{bla} %<- for cleveref's \Crefname with aliascounter MyTheoremFR
         name=bla, %<- for the macro \MyTheoremFRname 
         autoref=bla,%<- for the macro \MyTheoremFRautorefname with aliascounter MyTheoremFR
         heading=Titre du théorème en français  %<- for the macro \MyTheoremFRheading
      },
      %...
    }%
    

    An initial experimental start, but one that needs intensive revision, debugging, adjusting, rectifying and thought :-) , might be something like the following:

    \documentclass{article}
    
    \RequirePackage{xparse}
    \RequirePackage{aliascnt}
    \RequirePackage{cleveref}
    
    \ExplSyntaxOn
    
    % Helper-macros/scratch-macros
    %-----------------------------
    \cs_new:Nn  \MYMODULE_exchange_i_iii_ii:nnn  { #1 {#3} {#2} }
    \cs_new:Nn  \__MYMODULE_languageprefix:  {}
    \cs_new:Nn  \__MYMODULE_countername:  {}
    
    % Message-management:
    %--------------------
    \msg_new:nnnn {MYMODULE}
                  {Undefined Language Dependent Specification Class}
                  {\token_to_str:N \CreateTheorem :\ Value\ `\tl_to_str:n{#2}'\ for\ invalid\ key\ `#1'.} 
                  {Providing\ Language-dependent\ specifications\ for\ element\ `#1'\ is\ currently\ not\ implemented.}
    % As long as MYMODULE is not a real package but just some preamble-code redirect
    % MYMODULE-related messages to denote to the preamble instead of a package/module:
    \prop_gput:Nnn \g_msg_module_type_prop { MYMODULE } {}
    \prop_gput:Nnn \g_msg_module_name_prop { MYMODULE } {Preamble-Code}
    
    % Nested key=value-interface by means of package l3keys:
    %-------------------------------------------------------
    % (l3keys is similar to pgfkeys.)
    % The outer level of key=value-specifications, i.e.,   <language-ID>={...},
    % is processed via  \keyval_parse:nnn  which was added tpo expl3 in 2020/12/19.
    % The inner level of key=value-specifications,
    %   i.e., the single keys whose values are to be specified dependant on the language,
    %   i.e., the "..."-content of the outer lever's {...},
    % is processed via  \keys_set:nn  .
    % The keys for the inner level are defined via  \keys_define:nn .
    
    \NewDocumentCommand \CreateTheoremSetKeys { mm } {
      % #1 = name of counter
      % #2 = keyval-list of language-specifications
      \cs_set:Nn \__MYMODULE_countername: {#1}
      \keyval_parse:nnn { \MYMODULE_exchange_i_iii_ii:nnn { \MYMODULE_setlanguagespecificparameters:nn } {} } 
                        { \MYMODULE_setlanguagespecificparameters:nn }
                        { #2 }
    }
    
    \cs_new_protected:Nn \MYMODULE_setlanguagespecificparameters:nn {
      % #1 = language-prefix
      % #2 = key-val-list for language whose prefix is language-prefix
      \cs_set:Nn \__MYMODULE_languageprefix: {#1}
      \newaliascnt {\__MYMODULE_countername: \__MYMODULE_languageprefix:} {\__MYMODULE_countername:}%
      \aliascntresetthe {\__MYMODULE_countername: \__MYMODULE_languageprefix:}%
      \keys_set:nn { MYMODULE } { #2 } 
    }%
    \keys_define:nn { MYMODULE } {
      crefname.code:n  = \cs_if_exist:NTF \crefname  {
                            \exp_args:Nx \crefname {\__MYMODULE_countername: \__MYMODULE_languageprefix: }#1
                         }{},
      crefname.value_required:n = true,
      Crefname.code:n  = \cs_if_exist:NTF \Crefname  { 
                            \exp_args:Nx \Crefname {\__MYMODULE_countername: \__MYMODULE_languageprefix: }#1
                         }{},
      Crefname.value_required:n = true,
      name.code:n  = \exp_args:Nx \cs_set:cpn {\__MYMODULE_countername: \__MYMODULE_languageprefix: name} {#1},
      name.value_required:n = true,
      autorefname.code:n  = \exp_args:Nx \cs_set:cpn  {\__MYMODULE_countername: \__MYMODULE_languageprefix: autorefname} {#1},
      autorefname.value_required:n = true,
      theoremheading.code:n= \exp_args:Nx \cs_set:cpn  {\__MYMODULE_countername: \__MYMODULE_languageprefix: heading} {#1},
      theoremheading.value_required:n = true,
      the.code:n= \exp_args:Nx \cs_set:cpn  {the \__MYMODULE_countername: \__MYMODULE_languageprefix: } {#1},
      the.value_required:n = true,
      %
      % Define keys for more Language Dependent Specification Classes.
      %
      unknown.code:n = \msg_error:nnxx {MYMODULE} 
                                       {Undefined Language Dependent Specification Class}
                                       {\exp_args:No \exp_not:n \l_keys_key_str}
                                       {\exp_not:n{#1}},
    }
    
    \ExplSyntaxOff
    
    \newcounter{oddity}%
    % By default \theoddity is now s.th. like \arabic{oddity}.
    %
    % Assume a \CreateTheorem-command is in progesss and has already defined
    % - a theroem-like environment "oddity", using the "oddity\languageplaceholder"-counter,
    %   and where the heading is to come from the macro \oddity<languageplaceholder>heading .
    % - a real counter "oddity" which is to be aliased to counters "oddity<languageplaceholder>"
    %   for language-specific output related to that counter.
    % - a macro "\theoddity".
    %
    % For defining language-specific alias-counter-related supplementary macros
    % which do not get defined by \newaliascnt, the macro \CreateTheorem could 
    % now internally do:
    %
    \CreateTheoremSetKeys{oddity}{%
      FR={%
        crefname={folie}{folies},
        Crefname={Folie}{Folies},
        name=folie,
        autorefname=folie,
        theoremheading=Folie,
      },
      EN={%
        crefname={oddity}{oddities},
        Crefname={Oddity}{Oddities},
        name=oddity,
        autorefname=oddity,
        theoremheading=Oddity,
        the=\roman{oddity}
      },
      DE={%
        crefname={Seltsamkeit}{Seltsamkeiten},
        Crefname={Seltsamkeit}{Seltsamkeiten},
        name=Seltsamkeit,
        autorefname=Seltsamkeit,
        theoremheading=Seltsamkeit,
        the=\alph{oddity},
      },
    }%
    
    \begin{document}
    
    \ttfamily
    
    \def\printmeaning#1{\string#1 = \meaning#1}
    \def\printmeanings#1#2{%
     \par{%
      \parskip=0ex \frenchspacing
      \hrule\hfill\par
      \noindent\strut Counter: #1\\
      \noindent Language: #2\\
      supplementary macros for alias-counter #1#2:\strut\par
      \hrule\hfill\par
      \noindent%
      \expandafter\printmeaning\csname cref@#1#2@name\endcsname \\
      \expandafter\printmeaning\csname Cref@#1#2@name\endcsname \\
      \expandafter\printmeaning\csname cref@#1#2@name@plural\endcsname \\
      \expandafter\printmeaning\csname Cref@#1#2@name@plural\endcsname \\
      \expandafter\printmeaning\csname #1#2name\endcsname \\
      \expandafter\printmeaning\csname #1#2autorefname\endcsname \\
      \expandafter\printmeaning\csname #1#2heading\endcsname \\
      \expandafter\printmeaning\csname the#1#2\endcsname\strut\par
      \hrule\hfill\par
     }%
    }%
    
    \printmeanings{oddity}{FR}
    
    \vfill
    
    \printmeanings{oddity}{EN}
    
    \vfill
    
    \printmeanings{oddity}{DE}
    
    \vfill\vfill
    
    \end{document}
    

    enter image description here

    Pitfalls I am currently aware of:

    With the keys of crefname and Crefname currently it is not checked whether the values consist of exactly two non-optional arguments and thus fit the syntax of \crefname/\Crefname.




When you have PJLthm.sty ([2021/08/07a]) and Patch.diff in the same directory, then in Debian Linux you can obtain the crippled/damaged PJLthmDamaged.sty, where

  • instances of \Crefname and \crefname and \newtheorem are replaced by instances of argument-gobbling-macros,
  • the loading of cleveref is removed,
  • package-name and version is changed,

by opening a shell, changing to that directory and performing the command
patch -o PJLthmDamaged.sty PJLthm.sty Patch.diff

(I could not insert PJLthmDamaged.sty into this answer directly as by doing so this answer would have exceeded the 30000-character limit.)

10
  • Thank you for your detailed analysis! There are still two problems that confuse me though: 1) The regionalref version, now as the default choice by PJLthm, also uses cleveref and \newtheorem, only calls them fewer times, but is considerably faster than the originalref version. Thus I've been supposing that is it possible that too many \crefnames or so somehow use too much memory and then cause a steep slow down?
    – Jinwen
    Aug 11 at 1:02
  • 2) You said that "The choice of underlying mechanisms, however, was made by you in your original question", what does this mean? I checked my old question, but it seems that I was just using the manually expanded version of \CreateTheorem, only faster because there were only three languages supported at that time.
    – Jinwen
    Aug 11 at 1:02
  • @Jinwen Thanks to whiplash, I am currently being kept awake at night by headaches, neck pain, dizziness, etc. I went to the computer to distract myself from it by dealing with LaTeX. Therefore, when I formulated my answer yesterday, my concentration was poor. Accordingly, I have formulated poorly. I ask you to accept my apologies. I have now edited and hope that the edits resolve the questions. Otherwise, please do not hesitate to follow up. :-) Aug 11 at 20:32
  • Thank you for the suggestion on patching \@ynthm, I didn’t tried this method but it seemed promising. Regarding the two suggestions you added in the last, I think the first is not necessary since there’s now (as of version 2021/08/11) a \StrToABBR that converts string like \languagename to the abbreviation. Your second suggestion is great, and I will try to achieve such an interface when I have the time. Hope you healthy, and many thanks for writing this wonderful answer!
    – Jinwen
    Aug 12 at 23:50
  • @Jinwen Thank you for the good wishes. :-) I wish you and those you love well-being and good health. I just thought a bit about the mentioned interface and edited my answer and, hoping it will be useful for you, added a bit of code based on expl3 / package l3keys. Aug 13 at 19:02
0

Thanks to Ulrich Diez's \CreateTheoremSetKeys in his answer, I added a starred version of \NameTheorem and a g-type argument to \CreateTheorem to call this macro. Below is the current version of PJLthm:

\NeedsTeXFormat{LaTeX2e}[2020-10-01]
\ProvidesPackage{PJLthm}
    [2021/08/14 Theorem setup and configuration]
\RequirePackage{kvoptions}
\RequirePackage{etoolbox}
\SetupKeyvalOptions{%
    family = @PJLthm,
    prefix = @PJLthm@
}
\DeclareBoolOption[false]{nothms}
\DeclareBoolOption[false]{delaythms}
\DeclareBoolOption[false]{nothmnum}
\DeclareStringOption{thmnum}[PJL@thmnum@default]
\DeclareBoolOption[false]{draft}
\DeclareBoolOption[false]{fast}
\DeclareBoolOption[true]{regionalref}
\DeclareBoolOption[false]{originalref}
\ProcessKeyvalOptions*\relax
\if@PJLthm@originalref
    \@PJLthm@regionalreffalse
\fi
\if@PJLthm@draft
    \@PJLthm@fasttrue
\fi
\if@PJLthm@fast
    \@PJLthm@regionalreftrue
\fi

\RequirePackage{PJLlang}
\RequirePackage{amsmath,amsthm}
\RequirePackage{aliascnt}
\PassOptionsToPackage{nameinlink}{cleveref}
\RequirePackage{cleveref}

\NewDocumentCommand{\NameTheorem}{somm}{%
    \protected@edef\PJLthm@temp{#3}%
    \expandafter\IfEndWith\expandafter{\PJLthm@temp}{*}{%
        \expandafter\StrGobbleRight\expandafter{\PJLthm@temp}{1}[\PJLthm@temp]%
    }{}%
    \IfBooleanTF{#1}{%
        \CreateTheoremSetKeys{\PJLthm@temp}{#4}%
    }{%
        \IfValueTF{#2}{%
            \expandafter\def\expandafter\PJL@temp@abbr\expandafter%
                {\expandafter\StrToABBR\expandafter{#2}}%
            \expandafter\def\csname\PJLthm@temp name\PJL@temp@abbr\endcsname{#4}%
        }{%
            \expandafter\def\csname\PJLthm@temp nameEN\endcsname{#4}%
            \expandafter\def\csname\PJLthm@temp nameFR\endcsname{#4}%
            \expandafter\def\csname\PJLthm@temp nameDE\endcsname{#4}%
            \expandafter\def\csname\PJLthm@temp nameIT\endcsname{#4}%
            \expandafter\def\csname\PJLthm@temp namePT\endcsname{#4}%
            \expandafter\def\csname\PJLthm@temp nameBR\endcsname{#4}%
            \expandafter\def\csname\PJLthm@temp nameES\endcsname{#4}%
            \expandafter\def\csname\PJLthm@temp nameCN\endcsname{#4}%
            \expandafter\def\csname\PJLthm@temp nameTC\endcsname{#4}%
            \expandafter\def\csname\PJLthm@temp nameJP\endcsname{#4}%
            \expandafter\def\csname\PJLthm@temp nameRU\endcsname{#4}%
        }%
    }%
}

\RequirePackage{xstring}
\newcommand\PassFirstToSecond[2]{#2{#1}}%
\NewDocumentCommand{\CreateTheorem}{sm}{%
    \begingroup
    \protected@edef\PJLthm@temp{#2}%
    \expandafter\IfEndWith\expandafter{\PJLthm@temp}{*}{%
        \expandafter\StrGobbleRight\expandafter{\PJLthm@temp}{1}[\PJLthm@temp]%
        \PassFirstToSecond{*}%
    }{%
        \PassFirstToSecond{}%
    }%
    {\expandafter\PassFirstToSecond%
        \expandafter{\PJLthm@temp}{\endgroup\InnerCreateTheorem{#1}}}%
}%
\if@PJLthm@regionalref
\NewDocumentCommand{\InnerCreateTheorem}{mmmod<>d()g}{%
    \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 argument,\MessageBreak
        nor call the unstarred variant with several optional arguments.}%
        {}%
    }{%
        \IfValueTF{#6}{%
            \IfBooleanTF{#1}{%
                \ifcsmacro{#2#3}%
                {\renewenvironment{#2#3}{\begin{#6*}}{\end{#6*}}}%
                {\newenvironment{#2#3}{\begin{#6*}}{\end{#6*}}}%
            }{%
                \ifcsmacro{#2#3}%
                {\renewenvironment{#2#3}{\begin{#6}}{\end{#6}}}%
                {\newenvironment{#2#3}{\begin{#6}}{\end{#6}}}%
            }
        }{%
            \IfBooleanTF{#1}{%
                \newtheorem*{#2#3}{\csname#2name\csname\languagename ABBR\endcsname\endcsname}
            }{%
                \IfValueTF{#5}{%
                    \newtheorem{PJL#2#3}{\csname#2name\csname\languagename ABBR\endcsname\endcsname}[#5]%
                    \newaliascnt{#2#3}{PJL#2#3}%
                }{%
                    \IfValueTF{#4}{%
                            \newtheorem{PJL#2#3}[#4]{\csname#2name\csname\languagename ABBR\endcsname\endcsname}
                        }{%
                            \newtheorem{PJL#2#3}{\csname#2name\csname\languagename ABBR\endcsname\endcsname}
                            \newaliascnt{#2#3}{PJL#2#3}%
                        }%
                }%
                \crefname{PJL#2#3}%
                    {\csname#2name\csname\languagename ABBR\endcsname\endcsname}%
                    {\csname#2name\csname\languagename ABBR\endcsname\endcsname}%
                \Crefname{PJL#2#3}%
                    {\csname#2name\csname\languagename ABBR\endcsname\endcsname}%
                    {\csname#2name\csname\languagename ABBR\endcsname\endcsname}%
                \NewDocumentEnvironment{#2#3}{}
                    {\begin{PJL#2#3}}
                    {\end{PJL#2#3}}
            }%
        }%
    }%
    \IfValueTF{#7}{%
        \CreateTheoremSetKeys{#2}{#7}%
    }{}%
}%
\else
\NewDocumentCommand{\InnerCreateTheorem}{mmmod<>d()g}{%
    \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 argument,\MessageBreak
        nor call the unstarred variant with several optional arguments.}%
        {%
            Allowed usage:\MessageBreak\MessageBreak
            \CreateTheorem*{(name of environment)}\MessageBreak
            \CreateTheorem{(name of environment)}\MessageBreak
            \CreateTheorem{(name of environment)}[(numbered like)]\MessageBreak
            \CreateTheorem{(name of environment)}<(numbered within)>\MessageBreak
            \CreateTheorem{(name of environment)}((existed environment))\MessageBreak
        }%
    }{%
        \IfValueTF{#6}{%
            \IfBooleanTF{#1}{%
                \ifcsmacro{#2#3}%
                {\renewenvironment{#2#3}{\begin{#6*}}{\end{#6*}}}%
                {\newenvironment{#2#3}{\begin{#6*}}{\end{#6*}}}%
            }{%
                \ifcsmacro{#2#3}%
                {\renewenvironment{#2#3}{\begin{#6}}{\end{#6}}}%
                {\newenvironment{#2#3}{\begin{#6}}{\end{#6}}}%
            }
        }{%
            \IfBooleanTF{#1}{%
                \if@PJLlang@enable@EN\expandafter\PassFirstToSecond\expandafter{\csname#2nameEN\endcsname}{\newtheorem*{#2EN#3}}\fi%
                \if@PJLlang@enable@FR\expandafter\PassFirstToSecond\expandafter{\csname#2nameFR\endcsname}{\newtheorem*{#2FR#3}}\fi%
                \if@PJLlang@enable@DE\expandafter\PassFirstToSecond\expandafter{\csname#2nameDE\endcsname}{\newtheorem*{#2DE#3}}\fi%
                \if@PJLlang@enable@IT\expandafter\PassFirstToSecond\expandafter{\csname#2nameIT\endcsname}{\newtheorem*{#2IT#3}}\fi%
                \if@PJLlang@enable@PT\expandafter\PassFirstToSecond\expandafter{\csname#2namePT\endcsname}{\newtheorem*{#2PT#3}}\fi%
                \if@PJLlang@enable@BR\expandafter\PassFirstToSecond\expandafter{\csname#2nameBR\endcsname}{\newtheorem*{#2BR#3}}\fi%
                \if@PJLlang@enable@ES\expandafter\PassFirstToSecond\expandafter{\csname#2nameES\endcsname}{\newtheorem*{#2ES#3}}\fi%
                \if@PJLlang@enable@CN\expandafter\PassFirstToSecond\expandafter{\csname#2nameCN\endcsname}{\newtheorem*{#2CN#3}}\fi%
                \if@PJLlang@enable@TC\expandafter\PassFirstToSecond\expandafter{\csname#2nameTC\endcsname}{\newtheorem*{#2TC#3}}\fi%
                \if@PJLlang@enable@JP\expandafter\PassFirstToSecond\expandafter{\csname#2nameJP\endcsname}{\newtheorem*{#2JP#3}}\fi%
                \if@PJLlang@enable@RU\expandafter\PassFirstToSecond\expandafter{\csname#2nameRU\endcsname}{\newtheorem*{#2RU#3}}\fi%
            }{%
                \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}}%
                }%
                %---------------------------------------------------------------
                \if@PJLlang@enable@EN\CreateTheoremNumberedLikeAliasCounter{#2}{EN}{#3}\fi%
                \if@PJLlang@enable@FR\CreateTheoremNumberedLikeAliasCounter{#2}{FR}{#3}\fi%
                \if@PJLlang@enable@DE\CreateTheoremNumberedLikeAliasCounter{#2}{DE}{#3}\fi%
                \if@PJLlang@enable@IT\CreateTheoremNumberedLikeAliasCounter{#2}{IT}{#3}\fi%
                \if@PJLlang@enable@PT\CreateTheoremNumberedLikeAliasCounter{#2}{PT}{#3}\fi%
                \if@PJLlang@enable@BR\CreateTheoremNumberedLikeAliasCounter{#2}{BR}{#3}\fi%
                \if@PJLlang@enable@ES\CreateTheoremNumberedLikeAliasCounter{#2}{ES}{#3}\fi%
                \if@PJLlang@enable@CN\CreateTheoremNumberedLikeAliasCounter{#2}{CN}{#3}\fi%
                \if@PJLlang@enable@TC\CreateTheoremNumberedLikeAliasCounter{#2}{TC}{#3}\fi%
                \if@PJLlang@enable@JP\CreateTheoremNumberedLikeAliasCounter{#2}{JP}{#3}\fi%
                \if@PJLlang@enable@RU\CreateTheoremNumberedLikeAliasCounter{#2}{RU}{#3}\fi%
                %---------------------------------------------------------------
            }%
            \NewDocumentEnvironment{#2#3}{}
                {\csname#2\csname\languagename ABBR\endcsname#3\endcsname}%
                {\csname end#2\csname\languagename ABBR\endcsname#3\endcsname}%
        }%
    }%
    \IfValueTF{#7}{%
        \CreateTheoremSetKeys{#2}{#7}%
    }{}%
}%
\NewDocumentCommand{\CreateTheoremNumberedLikeAliasCounter}{mmm}{%
    \newaliascnt{#1#2#3}{#1#3}%
    \expandafter\PassFirstToSecond\expandafter{\csname#1name#2\endcsname}{\newtheorem{#1#2#3}[{#1#2#3}]}%
    \aliascntresetthe{#1#2#3}%
    \expandafter\PassFirstToSecond\expandafter{\csname#1name#2\endcsname}%
    {%
        \expandafter\PassFirstToSecond\expandafter{\csname#1name#2\endcsname}%
        {\crefname{#1#2#3}}%
    }%
    \expandafter\PassFirstToSecond\expandafter{\csname#1name#2\endcsname}%
    {%
        \expandafter\PassFirstToSecond\expandafter{\csname#1name#2\endcsname}%
        {\Crefname{#1#2#3}}%
    }%
}%
\fi

\ExplSyntaxOn

% Helper-macros/scratch-macros
%-----------------------------
\cs_new:Nn  \PJLthm_exchange_i_iii_ii:nnn  { #1 {#3} {#2} }
\cs_new:Nn  \__PJLthm_languageprefix:  {}
\cs_new:Nn  \__PJLthm_countername:  {}

% Message-management:
%--------------------
\msg_new:nnnn {PJLthm}
              {Undefined Language Dependent Specification Class}
              {\token_to_str:N \CreateTheorem :\ Value\ `\tl_to_str:n{#2}'\ for\ invalid\ key\ `#1'.} 
              {Providing\ Language-dependent\ specifications\ for\ element\ `#1'\ is\ currently\ not\ implemented.}

% Nested key=value-interface by means of package l3keys:
%-------------------------------------------------------
% (l3keys is similar to pgfkeys.)
% The outer level of key=value-specifications, i.e.,   <language-ID>={...},
% is processed via  \keyval_parse:nnn  which was added tpo expl3 in 2020/12/19.
% The inner level of key=value-specifications,
%   i.e., the single keys whose values are to be specified dependant on the language,
%   i.e., the "..."-content of the outer lever's {...},
% is processed via  \keys_set:nn  .
% The keys for the inner level are defined via  \keys_define:nn .

\NewDocumentCommand \CreateTheoremSetKeys { mm } {
  % #1 = name of counter
  % #2 = keyval-list of language-specifications
  \cs_set:Nn \__PJLthm_countername: {#1}
  \keyval_parse:nnn { \PJLthm_exchange_i_iii_ii:nnn { \PJLthm_setlanguagespecificparameters:nn } {} } 
                    { \PJLthm_setlanguagespecificparameters:nn }
                    { #2 }
}

\cs_new_protected:Nn \PJLthm_setlanguagespecificparameters:nn {
  % #1 = language-prefix
  % #2 = key-val-list for language whose prefix is language-prefix
  \cs_set:Nx \__PJLthm_languageprefix: {\StrToABBR{#1}}
  \exp_args:No \tl_if_empty:nTF {\__PJLthm_languageprefix:} 
    { \msg_error:nn { PJLthm }
                    { No language \exp_not:n{#1} defined }
    }%
    {%
        \newaliascnt {\__PJLthm_countername: \__PJLthm_languageprefix:} {\__PJLthm_countername:}%
        \aliascntresetthe {\__PJLthm_countername: \__PJLthm_languageprefix:}%
        \keys_set:nn { PJLthm } { #2 } 
    }%
}%
\keys_define:nn { PJLthm } {
  crefname.code:n  = \cs_if_exist:NTF \crefname  {
                        \exp_args:Nx \crefname {\__PJLthm_countername: \__PJLthm_languageprefix: }#1
                     }{},
  crefname.value_required:n = true,
  Crefname.code:n  = \cs_if_exist:NTF \Crefname  { 
                        \exp_args:Nx \Crefname {\__PJLthm_countername: \__PJLthm_languageprefix: }#1
                     }{},
  Crefname.value_required:n = true,
  name.code:n  = \exp_args:Nx \cs_set:cpn {\__PJLthm_countername: name \__PJLthm_languageprefix:} {#1},
  name.value_required:n = true,
  autorefname.code:n  = \exp_args:Nx \cs_set:cpn  {\__PJLthm_countername: \__PJLthm_languageprefix: autorefname} {#1},
  autorefname.value_required:n = true,
  theoremheading.code:n= \exp_args:Nx \cs_set:cpn  {\__PJLthm_countername: \__PJLthm_languageprefix: heading} {#1},
  theoremheading.value_required:n = true,
  the.code:n= \exp_args:Nx \cs_set:cpn  {the \__PJLthm_countername: \__PJLthm_languageprefix: } {#1},
  the.value_required:n = true,
  %
  % Define keys for more Language Dependent Specification Classes.
  %
  unknown.code:n = \msg_error:nnxx {PJLthm} 
                                   {Undefined Language Dependent Specification Class}
                                   {\exp_args:No \exp_not:n \l_keys_key_str}
                                   {\exp_not:n{#1}},
}

\ExplSyntaxOff

\def\theoremnameEN{{Theorem}}
\def\lemmanameEN{{Lemma}}
\def\propositionnameEN{{Proposition}}
\def\corollarynameEN{{Corollary}}
\def\propertynameEN{{Property}}
\def\factnameEN{{Fact}}
\def\conjecturenameEN{{Conjecture}}
\def\definitionnameEN{{Definition}}
\def\axiomnameEN{{Axiom}}
\def\assumptionnameEN{{Assumption}}
\def\conventionnameEN{{Convention}}
\def\hypothesisnameEN{{Hypothesis}}
\def\notationnameEN{{Notation}}
\def\examplenameEN{{Example}}
\def\problemnameEN{{Problem}}
\def\questionnameEN{{Question}}
\def\exercisenameEN{{Exercise}}
\def\remarknameEN{{Remark}}
\def\observationnameEN{{Observation}}
\expandafter\def\csname definition-propositionnameEN\endcsname{\definitionnameEN-\propositionnameEN}
\expandafter\def\csname definition-theoremnameEN\endcsname{\definitionnameEN-\theoremnameEN}

\def\theoremnameFR{{Théorème}}
\def\lemmanameFR{{Lemme}}
\def\propositionnameFR{{Proposition}}
\def\corollarynameFR{{Corollaire}}
\def\propertynameFR{{Propriété}}
\def\factnameFR{{Fait}}
\def\conjecturenameFR{{Conjecture}}
\def\definitionnameFR{{Définition}}
\def\axiomnameFR{{Axiome}}
\def\assumptionnameFR{{Supposition}}
\def\conventionnameFR{{Convention}}
\def\hypothesisnameFR{{Hypothèse}}
\def\notationnameFR{{Notation}}
\def\examplenameFR{{Exemple}}
\def\problemnameFR{{Problème}}
\def\questionnameFR{{Question}}
\def\exercisenameFR{{Exercice}}
\def\remarknameFR{{Remarque}}
\def\observationnameFR{{Observation}}
\expandafter\def\csname definition-propositionnameFR\endcsname{\definitionnameFR-\propositionnameFR}
\expandafter\def\csname definition-theoremnameFR\endcsname{\definitionnameFR-\theoremnameFR}

\def\theoremnameDE{{Satz}}
\def\lemmanameDE{{Lemma}}
\def\propositionnameDE{{Proposition}}
\def\corollarynameDE{{Korollar}}
\def\propertynameDE{{Eigenschaft}}
\def\factnameDE{{Fakt}}
\def\conjecturenameDE{{Vermutung}}
\def\definitionnameDE{{Definition}}
\def\axiomnameDE{{Axiom}}
\def\assumptionnameDE{{Annahme}}
\def\conventionnameDE{{Konvention}}
\def\hypothesisnameDE{{Hypothese}}
\def\notationnameDE{{Notation}}
\def\examplenameDE{{Beispiel}}
\def\problemnameDE{{Problem}}
\def\questionnameDE{{Frage}}
\def\exercisenameDE{{Übung}}
\def\remarknameDE{{Bemerkung}}
\def\observationnameDE{{Beobachtung}}
\expandafter\def\csname definition-propositionnameDE\endcsname{\definitionnameDE-\propositionnameDE}
\expandafter\def\csname definition-theoremnameDE\endcsname{\definitionnameDE-\theoremnameDE}

\def\theoremnameIT{{Teorema}}
\def\lemmanameIT{{Lemma}}
\def\propositionnameIT{{Proposizione}}
\def\corollarynameIT{{Corollario}}
\def\propertynameIT{{Proprietà}}
\def\factnameIT{{Fatto}}
\def\conjecturenameIT{{Congettura}}
\def\definitionnameIT{{Definizione}}
\def\axiomnameIT{{Assioma}}
\def\assumptionnameIT{{Supposizione}}
\def\conventionnameIT{{Convenzione}}
\def\hypothesisnameIT{{Ipotesi}}
\def\notationnameIT{{Notazione}}
\def\examplenameIT{{Esempio}}
\def\problemnameIT{{Problema}}
\def\questionnameIT{{Domanda}}
\def\exercisenameIT{{Esercizio}}
\def\remarknameIT{{Nota}}
\def\observationnameIT{{Osservazione}}
\expandafter\def\csname definition-propositionnameIT\endcsname{\definitionnameIT-\propositionnameIT}
\expandafter\def\csname definition-theoremnameIT\endcsname{\definitionnameIT-\theoremnameIT}

\def\theoremnamePT{{Teorema}}
\def\lemmanamePT{{Lema}}
\def\propositionnamePT{{Proposição}}
\def\corollarynamePT{{Corolário}}
\def\propertynamePT{{Propriedade}}
\def\factnamePT{{Facto}}
\def\conjecturenamePT{{Conjetura}}
\def\definitionnamePT{{Definição}}
\def\axiomnamePT{{Axioma}}
\def\assumptionnamePT{{Suposição}}
\def\conventionnamePT{{Convenção}}
\def\hypothesisnamePT{{Hipótese}}
\def\notationnamePT{{Notação}}
\def\examplenamePT{{Exemplo}}
\def\problemnamePT{{Problema}}
\def\questionnamePT{{Pergunta}}
\def\exercisenamePT{{Exercício}}
\def\remarknamePT{{Comentário}}
\def\observationnamePT{{Observação}}
\expandafter\def\csname definition-propositionnamePT\endcsname{\definitionnamePT-\propositionnamePT}
\expandafter\def\csname definition-theoremnamePT\endcsname{\definitionnamePT-\theoremnamePT}

\def\theoremnameBR{{Teorema}}
\def\lemmanameBR{{Lema}}
\def\propositionnameBR{{Proposição}}
\def\corollarynameBR{{Corolário}}
\def\propertynameBR{{Propriedade}}
\def\factnameBR{{Facto}}
\def\conjecturenameBR{{Conjetura}}
\def\definitionnameBR{{Definição}}
\def\axiomnameBR{{Axioma}}
\def\assumptionnameBR{{Suposição}}
\def\conventionnameBR{{Convenção}}
\def\hypothesisnameBR{{Hipótese}}
\def\notationnameBR{{Notação}}
\def\examplenameBR{{Exemplo}}
\def\problemnameBR{{Problema}}
\def\questionnameBR{{Pergunta}}
\def\exercisenameBR{{Exercício}}
\def\remarknameBR{{Comentário}}
\def\observationnameBR{{Observação}}
\expandafter\def\csname definition-propositionnameBR\endcsname{\definitionnameBR-\propositionnameBR}
\expandafter\def\csname definition-theoremnameBR\endcsname{\definitionnameBR-\theoremnameBR}

\def\theoremnameES{{Teorema}}
\def\lemmanameES{{Lema}}
\def\propositionnameES{{Proposición}}
\def\corollarynameES{{Corolario}}
\def\propertynameES{{Propiedad}}
\def\factnameES{{Hecho}}
\def\conjecturenameES{{Conjetura}}
\def\definitionnameES{{Definición}}
\def\axiomnameES{{Axioma}}
\def\assumptionnameES{{Suposición}}
\def\conventionnameES{{Convención}}
\def\hypothesisnameES{{Hipótesis}}
\def\notationnameES{{Notación}}
\def\examplenameES{{Ejemplo}}
\def\problemnameES{{Problema}}
\def\questionnameES{{Pregunta}}
\def\exercisenameES{{Ejercicio}}
\def\remarknameES{{Comentario}}
\def\observationnameES{{Observación}}
\expandafter\def\csname definition-propositionnameES\endcsname{\definitionnameES-\propositionnameES}
\expandafter\def\csname definition-theoremnameES\endcsname{\definitionnameES-\theoremnameES}

\def\theoremnameCN{{定理}}
\def\lemmanameCN{{引理}}
\def\propositionnameCN{{命题}}
\def\corollarynameCN{{推论}}
\def\propertynameCN{{性质}}
\def\factnameCN{{事实}}
\def\conjecturenameCN{{猜想}}
\def\definitionnameCN{{定义}}
\def\axiomnameCN{{公理}}
\def\assumptionnameCN{{假设}}
\def\conventionnameCN{{约定}}
\def\hypothesisnameCN{{假设}}
\def\notationnameCN{{记号}}
\def\examplenameCN{{例}}
\def\problemnameCN{{问题}}
\def\questionnameCN{{问题}}
\def\exercisenameCN{{练习}}
\def\remarknameCN{{备注}}
\def\observationnameCN{{观察}}
\expandafter\def\csname definition-propositionnameCN\endcsname{\definitionnameCN-\propositionnameCN}
\expandafter\def\csname definition-theoremnameCN\endcsname{\definitionnameCN-\theoremnameCN}

\def\theoremnameTC{{定理}}
\def\lemmanameTC{{引理}}
\def\propositionnameTC{{命題}}
\def\corollarynameTC{{推論}}
\def\propertynameTC{{性質}}
\def\factnameTC{{事實}}
\def\conjecturenameTC{{猜想}}
\def\definitionnameTC{{定義}}
\def\axiomnameTC{{公理}}
\def\assumptionnameTC{{假設}}
\def\conventionnameTC{{約定}}
\def\hypothesisnameTC{{假設}}
\def\notationnameTC{{記號}}
\def\examplenameTC{{例}}
\def\problemnameTC{{問題}}
\def\questionnameTC{{問題}}
\def\exercisenameTC{{練習}}
\def\remarknameTC{{備註}}
\def\observationnameTC{{觀察}}
\expandafter\def\csname definition-propositionnameTC\endcsname{\definitionnameTC-\propositionnameTC}
\expandafter\def\csname definition-theoremnameTC\endcsname{\definitionnameTC-\theoremnameTC}

\def\theoremnameJP{{定理}}
\def\lemmanameJP{{補題}}
\def\propositionnameJP{{命題}}
\def\corollarynameJP{{系}}
\def\propertynameJP{{性質}}
\def\factnameJP{{事実}}
\def\conjecturenameJP{{予想}}
\def\definitionnameJP{{定義}}
\def\axiomnameJP{{公理}}
\def\assumptionnameJP{{仮定}}
\def\conventionnameJP{{慣例}}
\def\hypothesisnameJP{{仮設}}
\def\notationnameJP{{記法}}
\def\examplenameJP{{例}}
\def\problemnameJP{{問題}}
\def\questionnameJP{{問題}}
\def\exercisenameJP{{練習}}
\def\remarknameJP{{注釈}}
\def\observationnameJP{{観察}}
\expandafter\def\csname definition-propositionnameJP\endcsname{\definitionnameJP-\propositionnameJP}
\expandafter\def\csname definition-theoremnameJP\endcsname{\definitionnameJP-\theoremnameJP}

\def\theoremnameRU{{Теорема}} % Теоре́ма
\def\lemmanameRU{{Лемма}} % Ле́мма
\def\propositionnameRU{{Предложение}} % Предложе́ние
\def\corollarynameRU{{Следствие}} % Сле́дствие
\def\propertynameRU{{Имущество}} % Иму́щество
\def\factnameRU{{Факт}}
\def\conjecturenameRU{{Гипотеза}} % Гипо́теза
\def\definitionnameRU{{Определение}} % Определе́ние
\def\axiomnameRU{{Аксиома}} % Аксио́ма
\def\assumptionnameRU{{Предположение}} % Предположе́ние
\def\conventionnameRU{{Конвенция}} % Конве́нция
\def\hypothesisnameRU{{Гипотеза}} % Гипо́теза
\def\notationnameRU{{Нотация}} % Нота́ция
\def\examplenameRU{{Пример}} % Приме́р
\def\problemnameRU{{Проблема}} % Пробле́ма
\def\questionnameRU{{Вопрос}} % Вопро́с
\def\exercisenameRU{{Упражнение}} % Упражне́ние
\def\remarknameRU{{Замечание}} % Замеча́ние
\def\observationnameRU{{Наблюдение}} % Наблюде́ние
\expandafter\def\csname definition-propositionnameRU\endcsname{\definitionnameRU-\propositionnameRU}
\expandafter\def\csname definition-theoremnameRU\endcsname{\definitionnameRU-\theoremnameRU}

\newif\ifPJLthm@IsBook
\ifdefined\c@chapter\PJLthm@IsBooktrue\else\PJLthm@IsBookfalse\fi
\ifbool{PJLthm@IsBook}{
    \newaliascnt{PJLthm@highest}{chapter}
}{
    \newaliascnt{PJLthm@highest}{section}
}
\NewDocumentCommand{\CreateTheorem@thmnum}{m}{
    \expandafter\ifstrempty\expandafter{\@PJLthm@thmnum}{
        \CreateTheorem{#1}<PJLthm@highest>
    }{
        \expandafter\ifstrequal\expandafter{\@PJLthm@thmnum}{PJL@thmnum@default}{
            \CreateTheorem{#1}
        }{
            \CreateTheorem{#1}<\@PJLthm@thmnum>
        }
    }
}

\def\PJLthm@definethms{
\if@PJLthm@nothms\else
\if@PJLthm@nothmnum
\CreateTheorem*{theorem}
\CreateTheorem*{lemma}
\CreateTheorem*{proposition}
\CreateTheorem*{corollary}
\CreateTheorem*{definition-proposition}
\CreateTheorem*{definition-theorem}
\CreateTheorem*{property}
\CreateTheorem*{fact}
\CreateTheorem*{conjecture}
\else
\CreateTheorem@thmnum{theorem}
\CreateTheorem{lemma}[theorem]
\CreateTheorem{proposition}[theorem]
\CreateTheorem{corollary}[theorem]
\CreateTheorem{definition-proposition}[theorem]
\CreateTheorem{definition-theorem}[theorem]
\CreateTheorem{property}[theorem]
\CreateTheorem{fact}[theorem]
\CreateTheorem{conjecture}[theorem]
\fi
\CreateTheorem*{theorem*}
\CreateTheorem*{lemma*}
\CreateTheorem*{proposition*}
\CreateTheorem*{corollary*}
\CreateTheorem*{definition-proposition*}
\CreateTheorem*{definition-theorem*}
\CreateTheorem*{property*}
\CreateTheorem*{fact*}
\CreateTheorem*{conjecture*}

\theoremstyle{definition}
\if@PJLthm@nothmnum
\CreateTheorem*{definition}
\CreateTheorem*{axiom}
\CreateTheorem*{assumption}
\CreateTheorem*{convention}
\CreateTheorem*{hypothesis}
\CreateTheorem*{notation}
\CreateTheorem*{example}
\CreateTheorem*{problem}
\CreateTheorem*{question}
\CreateTheorem*{exercise}
\else
\CreateTheorem{definition}[theorem]
\CreateTheorem{axiom}[theorem]
\CreateTheorem{assumption}[theorem]
\CreateTheorem{convention}[theorem]
\CreateTheorem{hypothesis}[theorem]
\CreateTheorem{notation}[theorem]
\CreateTheorem{example}[theorem]
\CreateTheorem{problem}[theorem]
\CreateTheorem{question}[theorem]
\CreateTheorem{exercise}[theorem]
\fi
\CreateTheorem*{definition*}
\CreateTheorem*{axiom*}
\CreateTheorem*{assumption*}
\CreateTheorem*{convention*}
\CreateTheorem*{hypothesis*}
\CreateTheorem*{notation*}
\CreateTheorem*{example*}
\CreateTheorem*{problem*}
\CreateTheorem*{question*}
\CreateTheorem*{exercise*}

\theoremstyle{remark}
\if@PJLthm@nothmnum
\CreateTheorem*{remark}
\CreateTheorem*{observation}
\else
\CreateTheorem@thmnum{remark}
\CreateTheorem@thmnum{observation}
\fi
\CreateTheorem*{remark*}
\CreateTheorem*{observation*}
\fi

\expandafter\ifstrempty\expandafter{\@PJLthm@thmnum}{
    \numberwithin{equation}{PJLthm@highest}
}{
    \expandafter\ifstrequal\expandafter{\@PJLthm@thmnum}{PJL@thmnum@default}{
    }{
        \numberwithin{equation}{\@PJLthm@thmnum}
    }
}

} % End of \PJLthm@definethms

\if@PJLthm@delaythms
    \AtEndPreamble{\PJLthm@definethms}
\else
    \PJLthm@definethms
\fi

\endinput

To be clear, I made some minor adjustments:

  1. The \__MYMODULE_languageprefix: is at first processed by a \StrToABBR, so that French, English etc. are acceptable as option names.
  2. The names of theorem-like environments are currently like: \***nameEN, not \***ENname. If it turns out to have no side-effects, then I can surely consider changing them to be like \***ENname in the future versions, to be consistent with \***ENautorefname etc.
  3. Changing MYMODULE to the package name and disabling the two lines in "Message Management" part as Ulrich Diez suggested in his comments.

This file (version 2021/08/14) is to be used with the current 2021/08/11 release on CTAN (which has \StrToABBR in PJLlang).


Here are the two current ways of usage:

\CreateTheorem{oddity}{%
  French={%
    crefname={folie}{folies},
    Crefname={Folie}{Folies},
    name=Folie,
    autorefname=folie,
    theoremheading=Folie,
  },
  ...
}%
\NameTheorem*{oddity}{%
  French={%
    crefname={folie}{folies},
    Crefname={Folie}{Folies},
    name=Folie,
    autorefname=folie,
    theoremheading=Folie,
  },
  ...
}%
\CreateTheorem{oddity}
7
  • The macro \PJLthm_setlanguagespecificparameters:nn does some mapping via \cs_set:Nn \__PJLthm_languageprefix: {\StrToABBR{#1}}. This does not take into account the case of no mapping being provided. In that case \__PJLthm_languageprefix: yields emptiness and thus \newaliascnt aliases the counter denoted by \__PJLthm_countername: to itself, which is not a good thing. I suggest defining \__PJLthm_languageprefix: via \cs_set:Nx, i.e., \cs_set:Nx \__PJLthm_languageprefix: {\StrToABBR{#1}}. Then you can check... Aug 14 at 11:45
  • ... Then you can check whether the definition of \__PJLthm_languageprefix: is empty via \exp_args:No \tl_if_empty:nTF {\__PJLthm_languageprefix:} {<code if empty>} {<code if not empty>}. <code if not empty> could be the \newaliascnt/\resetaliascntthe/\keys_set:nn-thingie. <code if empty> could be an error-message about missing mapping. Aug 14 at 11:52
  • @UlrichDiez I've edited the \cs_new_protected:Nn \PJLthm_setlanguagespecificparameters:nn part, is this what you meant? Also I'm thinking of changing those ***.value_required:n = true to false, since one usually doesn't need all those names. Would it be safe to directly change them, or do I have to check if their values are empty and do some separate procedure?
    – Jinwen
    Aug 14 at 12:24
  • Sorry, it is not. Within the definition-text of \PJLthm_setlanguagespecificparameters:nn you use \cs_set:Nn for defining \__PJLthm_languageprefix:. If you use \cs_set:Nx instead, then it is like defining \__PJLthm_languageprefix: via \edef, i.e., \StrToABBR{#1} is done while performing the definition of \__PJLthm_languageprefix:. Then you can say: If \__PJLthm_languageprefix: is empty, there was/is no mapping available and have TeX perfoem actions according to this case. Aug 14 at 13:45
  • 1
    @UlrichDiez Oh I see, in this case I need x for exhaustive expansion. Thus I only need to change \cs_set:Nn to \cs_set:Nx, is that correct? And thank you for the explanation of <key>.value_required:n, I misunderstood its meaning.
    – Jinwen
    Aug 14 at 13:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.