寻求更快的 \CreateTheorem 实现

寻求更快的 \CreateTheorem 实现

基于这个答案,我写了一个宏\CreateTheorem,有以下五种使用方法:

  1. \CreateTheorem*{env},它创建了一个类似无编号定理的环境env
  2. \CreateTheorem{env},它创建了一个类似于编号定理的环境env,按顺序编号为 1,2,3,...
  3. \CreateTheorem{env}[numberlike],它创建了一个类似于编号定理的环境env,共享计数器numberlike
  4. \CreateTheorem{env}<numberwithin>,它创建了一个类似于编号定理的环境env,在计数器内编号numberwithin
  5. \CreateTheorem*{env}(existedenv)或者\CreateTheorem{env}(existedenv),将 该 环境env与 已 存在 的 环境进行 标识existedenv;

    此处\CreateTheorem*{env}(existedenv)的效果与\CreateTheorem{env}(existedenv*)

并且为了支持多语言,\CreateTheorem会读取宏\envnameEN、等\envnameFR\envnameDE获取类定理环境的标号env,然后创建环境envENenvFRenvDE,并进行相应的设置crefname,最后定义环境env,根据当前语言的名称选择合适的环境。

请注意,如果写\CreateTheorem*{env*},那么语言指定的环境将被命名为envEN*、等envFR*envDE*而不是env*EN

此宏现在是工具包的一部分ProjLibhttps://ctan.org/pkg/projlib由于许多常用的类定理环境已经预先定义,因此可以像以下 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}

结果是:

在此处输入图片描述

但是,当前实现的性能相对较低。在我的 PC 上,上述 MWE 大约需要8s。我相信这可以大大改善的原因是,如果删除那些设置 的行\crefname,时间将减少到2s。因此,我正在寻找一种方法来实现与当前 相同的结果\CreateTheorem,但只需要3s。欢迎任何建议。提前致谢!


目前的实现\CreateTheorem是:

\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}%
}%

答案1

在你最初的问题中关于宏 \CreateTheorem(*) 的帮助“我发现了以下初步情况:

  1. \CreateTheorem阿姆斯特丹和/或 cleveref 已加载。
  2. 底层宏的参数需要正确排列,包括\newtheorem,,,等等\crefname\Crefname

我目前的方法的问题是

  • \newtheorem速度很慢,而且经常进行。
  • 聪明人的宏很慢\Crefname并且\crefname经常执行。
  • 加载包聪明人需要一些时间

您可以通过推导where\newtheorem的损坏/残缺变体来查看 etc 的缓慢程度PJLthm.sty

  • \Crefname和的实例\crefname\newtheorem参数吞噬宏的实例所取代。
  • cleveref 的加载已被删除。
  • 软件包名称和版本已改变。

当使用受损/损坏的软件包进行基准测试时,请确保没有尝试使用应该定义的环境与残缺/损坏的变体一样,根据底层\newtheorem//进行的定义不会发生,因此\Crefname\crefname对于应该定义的包环境的残缺/损坏的变体,将不可用。


我刚刚下载项目库[2021/08/07]来自 CTAN 并编译 .ins 文件以获取 .sty 文件。

当我保存示例时

\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}

作为测试.tex在 Debian Linux 上也可以
time pdflatex test.tex

,然后我得到:

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

当我推导出PJLthmDamaged.sty普吉岛经过

  • 用参数吞噬宏的实例替换\Crefname\crefname和的实例,\newtheorem
  • 删除 cleveref 的加载,
  • 更改软件包名称和版本,

因此差异文件Patch.diff如下所示:

--- 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'.

并保存示例

\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}

作为测试.tex(与上面的例子相同,唯一的区别是PJLthmDamaged.sty已加载,而不是普吉岛)在 Debian Linux 上
time pdflatex test.tex

,然后我得到:

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

在我的计算机上,⟨未禁用,  , 
的编译时间 ⟩:⟨禁用 ,  , 的编译时间⟩ 的比例 约为 38:1!\newtheorem\crefname\Crefname\newtheorem\crefname\Crefname

您可以看到,采用我当前的方法,速度缓慢的原因并不是因为我围绕对\newtheoremetc 的调用编写了代码来正确安排 etc 的参数,而更多的是因为etc 实际执行的\newtheorem频率。\newtheorem

\newtheorem因此,除了减少要执行的等量之外,我看不出还有其他方法可以使编译速度更快。

然而,在这种情况下,也需要\CreateTheorem一边工作一边阿姆斯特丹正在使用中存在问题— 回想起以前 hyperref 软件包版本的注释源代码中关于 ams-things 的“快乐”评论:什么时候问题与 ams-math-stuff 无关?(-:

阿姆斯特丹重新定义内部结构,\newtheorem以便您不能使用占位符来表示要与要定义的定理一起使用的计数器。

否则你可以,例如,

  • 有一个宏\languagename,用于保存当前使用的语言的名称

  • 通过\newcountr定义一个计数器counter

  • 暂时定义\languagename为空

  • 做一些类似的事情

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

  • 恢复\languagename

  • 并且对于每一个⟨语言名称⟩维护一个别名计数器,其名称为模式,是“底层”真实计数器的别名,并定义名称为模式的宏。counter⟨languagename⟩counter\theorem⟨languagename⟩heading

    \languagename必须暂时将其定义为空,以防止\newtheorem在当前使用某种语言且尚未定义环境真实计数器的语言特定别名计数器时传递错误消息。)

没有 amsthm 你也可以这样做,因为没有 amsthm 的标记counter\languagename进入未评估/未扩展的环境定义,并且在执行相关环境实例时进行评估。

与 amsthm但是,你不能这样做,因为 amsthm 重新定义了事物,其中不是标记counter\languagename进入相关环境的定义,而是评估产生的控制字标记 \csname thecounter\languagename\endcsname进入相关环境的定义。

即,使用 amsthm 时,令牌\languagename在定义相关环境时进行评估,因此不会进入相关环境的定义。

当修补 amsthm 对内部的重新定义时\newtheorem,就像没有 amsthm 的情况一样,形成正在使用的计数器名称的标记会以未扩展/未评估的形式进入相关环境的定义,那么您不需要为每种语言中的每种定理定义一个内部定理环境,但对每组相同类型但语言不同的定理调用一次就足够了。theorem⟨languagename⟩\newtheorem

如果您不介意\@ynthm在加载 amsthm/cleveref 的情况下修补内部宏(该补丁可以被安排为仅在执行期间有效\CreateTheorem),那么根据刚刚概述的方法的解决方案可能是可行的。

到目前为止,我一直不愿意修补内部宏,顺便说一句,其他软件包也修补了该宏,原因如下:

  • 例如,软件包 cleveref 和 hyperref 反过来也修补了 amsthm 代码\@ynthm。我还没有深入研究 cleveref 的代码,以了解所有细节。
  • 我不知道这种修补会如何影响其他关于交叉引用或定理的软件包,例如 varioref 或 theorem 软件包。
  • 修补其他软件包的代码意味着需要跟踪您的软件包所修补代码的更改。这不会使软件包的维护变得更容易。
  • 修补其他软件包的代码意味着需要确保您的软件包在任何情况下都能被加载那些需要修补代码的软件包。这不会让软件包的使用变得更加容易。

如果您对这种方法感兴趣,尽管它有缺点,请告诉我,我可能会深入研究 cleveref 等的代码,并在完成后编辑这个答案。

最初的实验开始,但需要大量的修改、调试、调整、纠正和思考,可能是这样的:

\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}

在此处输入图片描述

我对“用户界面”有一些疑问:

  1. 如何遵循 babel 包中命名语言的惯例?然后,您可以从宏中获取当前使用的语言的名称\languagename。您可以简单地使用 babel 的基础结构(\selectlanguage\foreignlanguage)来更改语言。babel 的基础结构会自动设置/调整\languagename。特定于语言的定义结构将具有可以使用宏的扩展获取的名称\languagename。例如,不是“counterFR”,而是“counterfrench”或“counterenglish”,因此也可以泛泛地说“counter\languagename”。

  2. \CreateTheorem对于那些用于创建编号定理的情况,使用 expl3 添加带有逗号列表/键=值语法的参数怎么样?比如

    \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
      },
      %...
    }%
    

    最初的实验开始,但需要大量的修改、调试、调整、纠正和思考 :-) ,可能是这样的:

    \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}
    

    在此处输入图片描述

    我目前知道的陷阱:

    crefname使用和的键Crefname,目前尚未检查其值是否恰好由两个非可选参数组成,从而符合\crefname/的语法\Crefname




当你有普吉岛([2021/08/07a])和补丁差异在同一个目录中,然后在 Debian Linux 中,你可以获得残缺/损坏的PJLthmDamaged.sty, 在哪里

  • \Crefname和的实例\crefname\newtheorem参数吞噬宏的实例所取代,
  • cleveref 的加载被删除,
  • 软件包名称和版本已更改,

打开 shell,切换到该目录并执行命令
patch -o PJLthmDamaged.sty PJLthm.sty Patch.diff

(我无法将 PJLthmDamaged.sty 直接插入到这个答案中,因为这样做这个答案会超出 30000 个字符的限制。)

答案2

感谢 Ulrich Diez 的\CreateTheoremSetKeys回答,我添加了带星号的版本\NameTheorem和一个g-type 参数来\CreateTheorem调用此宏。以下是的当前版本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

为了清楚起见,我做了一些小调整:

  1. 首先\__MYMODULE_languageprefix:由 处理\StrToABBR,因此FrenchEnglish可以接受作为选项名称。
  2. 类定理环境的名称目前类似于:\***nameEN,而不是\***ENname。如果事实证明没有副作用,那么我肯定会考虑在未来版本中将它们更改为,以与等\***ENname保持一致。\***ENautorefname
  3. 按照 Ulrich Diez 在评论中所建议的那样,更改MYMODULE包名称并禁用“消息管理”部分中的两行。

\StrToABBR该文件(版本 2021/08/14)将与 CTAN 上的当前 2021/08/11 版本(已)一起使用PJLlang


目前有两种使用方式:

\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}

相关内容