In your original question "Help on a macro \CreateTheorem(*)" I found the following preliminaries:
- The
\CreateTheorem-mechanism is to work also when package(s) amsthm and/or cleveref are/is loaded.
- 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}
@@ -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%
%---------------------------------------------------------------
}%
@@ -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}%
{\@gobblethree{#1#2#3}}%
}%
\expandafter\PassFirstToSecond\expandafter{\csname#1name#2\endcsname}%
{%
\expandafter\PassFirstToSecond\expandafter{\csname#1name#2\endcsname}%
{\@gobblethree{#1#2#3}}%
}%
}%
\fi
@@ -702,4 +696,4 @@
\endinput
%%
-%% End of file PJLthm.sty'. +%% End of filePJLthmDamaged.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}

I have some questions regarding the "user interface":
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.
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}

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.)
regionalrefversion, now as the default choice byPJLthm, also uses cleveref and\newtheorem, only calls them fewer times, but is considerably faster than theoriginalrefversion. 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 '21 at 01:02\CreateTheorem, only faster because there were only three languages supported at that time.\@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\StrToABBRthat converts string like\languagenameto 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 '21 at 23:50\CreateTheoremSetKeysas an answer below (its length does not fit in a comment), unfortunately no MWE is given due to the length constraints. The code is a little mess, mixing LaTeX2e and expl3 (I'm not yet familiar with expl3 so currently I'm not able to rewrite the rest codes with it). What's your opinion of this? – Jinwen Aug 14 '21 at 04:00\prop_gput:Nnn \g_msg_module_type_prop...and\prop_gput:Nnn \g_msg_module_name_prop...should be sufficient. ... – Ulrich Diez Aug 14 '21 at 10:26\ExplSyntaxOnand\ExplSyntaxOffand for this code no\makeatletterwould be necessary even if it would not be in a .sty file. If it were otherwise, it might be an indication of some kind of interweaving not intended by the developers. interface3.pdf takes some time getting used to at first, in my opinion, but it does a good job of explaining the ... – Ulrich Diez Aug 14 '21 at 10:26