1

When \cref a theorem, in order to show the referencing name corresponding to the original appearance in its context (i.e., if you write a theorem in English context, and later refer to it in French context, then the English name Theorem shall be shown), I defined separate counters theorem-english and theorem-french and then alias them to theorem, and defined separate \crefname to these counters.

The problem is that \crefname is slow, so as the number of languages and theorem-like environments increase, this approach quite soon becomes unbearably slow.

An idea is to reduce the use of \crefname, only define it once for the counter theorem-\languagename (here \languagename is used as a place holder). However I don't know if this can actually work -- I tried to set it to the counter theorem- \exp_not:N \languagename, but this ended up with several errors.

Below is a MWE.

\documentclass{article}

\usepackage[french,english]{babel}

\usepackage{amsthm}
\usepackage{aliascnt}
\usepackage[french,english]{cleveref}

\makeatletter

\ExplSyntaxOn

\newtheorem{theorem}{ \tl_use:c { c_projlib_theorem_name_theorem_ \languagename _tl } }
\newtheorem{definition}[theorem]{ \tl_use:c { c_projlib_theorem_name_definition_ \languagename _tl } }

\newaliascnt{theorem-english}{theorem}
\newaliascnt{theorem-french}{theorem}

%% Too many crefnames thus too slow
\crefname{theorem-english}{\c_projlib_theorem_name_theorem_english_tl}{\c_projlib_theorem_name_theorem_plural_english_tl}
\crefname{theorem-french}{\c_projlib_theorem_name_theorem_french_tl}{\c_projlib_theorem_name_theorem_plural_french_tl}

%% Does not work
% \crefname{theorem- \exp_not:N \languagename}
%   { \tl_use:c { c_projlib_theorem_name_theorem_\languagename_tl } }
%   { \tl_use:c { c_projlib_theorem_name_theorem_plural_\languagename_tl } }


% Temporary names
\tl_set:Nn \c_projlib_theorem_name_theorem_english_tl { Theorem }
\tl_set:Nn \c_projlib_theorem_name_theorem_plural_english_tl { Theorems }
\tl_set:Nn \c_projlib_theorem_name_theorem_french_tl { Théorème }
\tl_set:Nn \c_projlib_theorem_name_theorem_plural_french_tl { Théorèmes }

\tl_set:Nn \c_projlib_theorem_name_definition_english_tl { Definition }
\tl_set:Nn \c_projlib_theorem_name_definition_plural_english_tl { Definitions }
\tl_set:Nn \c_projlib_theorem_name_definition_french_tl { Définition }
\tl_set:Nn \c_projlib_theorem_name_definition_plural_french_tl { Définitions }

\ExplSyntaxOff

\makeatother


\begin{document}

\begin{theorem}
  \addtocounter{theorem-english}{-1}
  \refstepcounter{theorem-english}
  \label{thm1}
  In english.
\end{theorem}
\begin{definition}\label{def1}
  In english.
\end{definition}

\cref{thm1,thm2,def1,def2}


\selectlanguage{french}
\begin{theorem}
  \addtocounter{theorem-french}{-1}
  \refstepcounter{theorem-french}
  \label{thm2}
  En français.
\end{theorem}
\begin{definition}\label{def2}
  En français.
\end{definition}

\cref{thm1,thm2,def1,def2}



% \makeatletter

% \meaning\cref@old@refstepcounter

% \meaning\refstepcounter@noarg

\end{document}

Below is a sophisticated version, contains the code that is supposed to be part of the in building projlib-theorem module. If you uncomment the To slow part, this is the behavior of the above MWE, but with a more complete configuration.

\begin{filecontents*}[overwrite]{projlib-language.sty}
\NeedsTeXFormat{LaTeX2e}[2020-10-01]
\RequirePackage{l3keys2e}
\ProvidesExplPackage
  {projlib-language}
  {2022/02/10} {}
  {Multi-language configuration}

\clist_new:N \c__projlib_language_supported_clist
\clist_new:N \g__projlib_language_babel_option_clist

\clist_set:Nn \c__projlib_language_supported_clist
  {
    english     ,
    french      ,
    ngerman     ,
    italian     ,
    portuguese  ,
    brazilian   ,
    spanish     ,
    schinese    ,
    tchinese    ,
    japanese    ,
    russian     ,
  }

\str_new:N   \g__projlib_language_main_str

\bool_new:N        \g__projlib_language_enabled_all_bool
\bool_gset_true:N  \g__projlib_language_enabled_all_bool

\clist_map_inline:Nn \c__projlib_language_supported_clist
  {
    \bool_new:c        { g__projlib_language_enabled_ #1 _bool }
    \bool_gset_false:c { g__projlib_language_enabled_ #1 _bool }
  }

\cs_new:Nn \projlib_language_set_option_no_babel:n
  {
    \bool_gset_false:N \g__projlib_language_enabled_all_bool
    \bool_gset_true:c { g__projlib_language_enabled_ #1 _bool }
    \str_if_empty:NT \g__projlib_language_main_str
      {
        \str_gset:Nn \g__projlib_language_main_str { #1 }
      }
  }
\cs_new:Nn \projlib_language_set_option:n
  {
    \projlib_language_set_option_no_babel:n { #1 }
    \clist_gput_left:Nn \g__projlib_language_babel_option_clist { #1 }
  }

\keys_define:nn { projlib-language }
  {
    , EN                  .code:n       = { \projlib_language_set_option:n { english } }
    , english             .code:n       = { \projlib_language_set_option:n { english } }
    , English             .code:n       = { \projlib_language_set_option:n { english } }
    , FR                  .code:n       = { \projlib_language_set_option:n { french } }
    , french              .code:n       = { \projlib_language_set_option:n { french } }
    , French              .code:n       = { \projlib_language_set_option:n { french } }
    , DE                  .code:n       = { \projlib_language_set_option:n { ngerman } }
    , german              .code:n       = { \projlib_language_set_option:n { ngerman } }
    , ngerman             .code:n       = { \projlib_language_set_option:n { ngerman } }
    , German              .code:n       = { \projlib_language_set_option:n { ngerman } }
    , IT                  .code:n       = { \projlib_language_set_option:n { italian } }
    , italian             .code:n       = { \projlib_language_set_option:n { italian } }
    , Italian             .code:n       = { \projlib_language_set_option:n { italian } }
    , PT                  .code:n       = { \projlib_language_set_option:n { portuguese } }
    , portuguese          .code:n       = { \projlib_language_set_option:n { portuguese } }
    , Portuguese          .code:n       = { \projlib_language_set_option:n { portuguese } }
    , BR                  .code:n       = { \projlib_language_set_option:n { brazilian } }
    , brazilian           .code:n       = { \projlib_language_set_option:n { brazilian } }
    , Brazilian           .code:n       = { \projlib_language_set_option:n { brazilian } }
    , ES                  .code:n       = { \clist_gput_left:Nn \g__projlib_language_babel_option_clist { es-notilde, es-noquoting } \projlib_language_set_option:n { spanish } }
    , spanish             .code:n       = { \clist_gput_left:Nn \g__projlib_language_babel_option_clist { es-notilde, es-noquoting } \projlib_language_set_option:n { spanish } }
    , Spanish             .code:n       = { \clist_gput_left:Nn \g__projlib_language_babel_option_clist { es-notilde, es-noquoting } \projlib_language_set_option:n { spanish } }
    , CN                  .code:n       = { \projlib_language_set_option_no_babel:n { schinese } }
    , chinese             .code:n       = { \projlib_language_set_option_no_babel:n { schinese } }
    , schinese            .code:n       = { \projlib_language_set_option_no_babel:n { schinese } }
    , simplifiedchinese   .code:n       = { \projlib_language_set_option_no_babel:n { schinese } }
    , Chinese             .code:n       = { \projlib_language_set_option_no_babel:n { schinese } }
    , SChinese            .code:n       = { \projlib_language_set_option_no_babel:n { schinese } }
    , SimplifiedChinese   .code:n       = { \projlib_language_set_option_no_babel:n { schinese } }
    , TC                  .code:n       = { \projlib_language_set_option_no_babel:n { tchinese } }
    , tchinese            .code:n       = { \projlib_language_set_option_no_babel:n { tchinese } }
    , traditionalchinese  .code:n       = { \projlib_language_set_option_no_babel:n { tchinese } }
    , TChinese            .code:n       = { \projlib_language_set_option_no_babel:n { tchinese } }
    , TraditionalChinese  .code:n       = { \projlib_language_set_option_no_babel:n { tchinese } }
    , JP                  .code:n       = { \projlib_language_set_option:n { japanese } }
    , japanese            .code:n       = { \projlib_language_set_option:n { japanese } }
    , Japanese            .code:n       = { \projlib_language_set_option:n { japanese } }
    , RU                  .code:n       = { \projlib_language_set_option:n { russian } }
    , russian             .code:n       = { \projlib_language_set_option:n { russian } }
    , Russian             .code:n       = { \projlib_language_set_option:n { russian } }
    , unknown             .code:n       = {}
  }
\ProcessKeysOptions { projlib-language }

\cs_new_protected:Nn \projlib_language_clear_global_option:n
  {
    \clist_remove_all:cn { @classoptionslist } { #1 }
  }

\projlib_language_clear_global_option:n { chinese }
\projlib_language_clear_global_option:n { Chinese }

\clist_gput_right:Nn \g__projlib_language_babel_option_clist { shorthands = off }

\str_if_empty:NT \g__projlib_language_main_str
  {
    \str_gset:Nn \g__projlib_language_main_str { english }
  }

\bool_if:NT \g__projlib_language_enabled_all_bool
  {
    \clist_map_inline:Nn \c__projlib_language_supported_clist
      {
        \bool_gset_true:c { g__projlib_language_enabled_ #1 _bool }
      }
  }

\cs_new:Nn \projlib_language_str_to_languagename:n
  {
    \str_case_e:nnF { \str_foldcase:n { #1 } }
      {
        {all}                   {common}
        {common}                {common}
        {cn}                    {schinese}
        {chinese}               {schinese}
        {schinese}              {schinese}
        {simplifiedchinese}     {schinese}
        {tc}                    {tchinese}
        {tchinese}              {tchinese}
        {traditionalchinese}    {tchinese}
        {jp}                    {japanese}
        {japanese}              {japanese}
        {en}                    {english}
        {english}               {english}
        {fr}                    {french}
        {french}                {french}
        {de}                    {ngerman}
        {german}                {ngerman}
        {ngerman}               {ngerman}
        {it}                    {italian}
        {italian}               {italian}
        {pt}                    {portuguese}
        {portuguese}            {portuguese}
        {br}                    {brazilian}
        {brazilian}             {brazilian}
        {es}                    {spanish}
        {spanish}               {spanish}
        {ru}                    {russian}
        {russian}               {russian}
      }
      { #1 }
  }

\cs_new:Nn \projlib_language_str_to_languagetype:n
  {
    \str_case_e:nn { \str_foldcase:n { #1 } }
      {
        {cn}                    {cjk}
        {chinese}               {cjk}
        {schinese}              {cjk}
        {simplifiedchinese}     {cjk}
        {tc}                    {cjk}
        {tchinese}              {cjk}
        {traditionalchinese}    {cjk}
        {jp}                    {cjk}
        {japanese}              {cjk}
        {en}                    {latin}
        {english}               {latin}
        {fr}                    {latin}
        {french}                {latin}
        {de}                    {latin}
        {german}                {latin}
        {ngerman}               {latin}
        {it}                    {latin}
        {italian}               {latin}
        {pt}                    {latin}
        {portuguese}            {latin}
        {br}                    {latin}
        {brazilian}             {latin}
        {es}                    {latin}
        {spanish}               {latin}
        {ru}                    {latin}
        {russian}               {latin}
      }
  }

\sys_if_engine_pdftex:T
  {
    \RequirePackage [T1] { fontenc }
    \RequirePackage { inputenc }
  }

\bool_if:NTF \g__projlib_language_enabled_all_bool
  {
    \sys_if_engine_pdftex:F
      {
        \PassOptionsToPackage { japanese, russian } { babel }
      }
    \PassOptionsToPackage { italian, portuguese, brazilian, spanish, es-notilde, es-noquoting, ngerman, french, english, shorthands = off } { babel }
  }
  {
    \PassOptionsToPackage { \g__projlib_language_babel_option_clist } { babel }
  }

\PassOptionsToPackage { italian, brazilian, spanish, ngerman, french, english } { cleveref }
\RequirePackage { babel }

\bool_if:NT \g__projlib_language_enabled_french_bool
  {
    \frenchsetup { PartNameFull = false }
  }

\bool_if:NT \g__projlib_language_enabled_portuguese_bool
  {
    \cs_set_eq:NN \__projlib_language_babel_ord: \ord
    \cs_undefine:N \ord
    \hook_gput_code:nnn { begindocument } { projlib-language }
      {
        \cs_if_exist:NT \ord
          {
            \cs_set_eq:NN \__projlib_language_user_ord: \ord
            \cs_set_protected:Npn \ord
              {
                \mode_if_math:TF
                  { \__projlib_language_user_ord:  }
                  { \__projlib_language_babel_ord: }
              }
          }
      }
  }

\babelprovide { schinese }
\babelprovide { tchinese }

\NewCommandCopy \projlib_language_backup_today:n \today

\tl_new:N \g_projlib_language_settings_common_tl
\clist_map_inline:Nn \c__projlib_language_supported_clist
  {
    \tl_new:c { g_projlib_language_settings_ #1 _tl }
  }

\tl_gput_right:Nn \g_projlib_language_settings_common_tl
  {
    \cs_if_exist:NT \ProjLibToday
      {
        \RenewCommandCopy \today \ProjLibToday
      }
  }

\tl_gput_right:Nn \g_projlib_language_settings_schinese_tl
  {
    \g_projlib_language_settings_common_tl
    \tl_gset:Nn \languagename          { schinese }
    \tl_gset:cn { abstractname }       { 摘要 }
    \tl_gset:cn { proofname }          { 证明 }
    \tl_gset:cn { contentsname }       { 目录 }
    \tl_gset:cn { listfigurename }     { 插图 }
    \tl_gset:cn { listtablename }      { 表格 }
    \tl_gset:cn { figurename }         { 图 }
    \tl_gset:cn { tablename }          { 表 }
    \tl_gset:cn { indexname }          { 索引 }
    \tl_gset:cn { appendixname }       { 附录 }
    \tl_gset:cn { refname }            { 参考文献 }
    \tl_gset:cn { bibname }            { 参考文献 }
  }

\tl_gput_right:Nn \g_projlib_language_settings_tchinese_tl
  {
    \g_projlib_language_settings_common_tl
    \tl_gset:Nn \languagename          { tchinese }
    \tl_gset:cn { abstractname }       { 摘要 }
    \tl_gset:cn { proofname }          { 證明 }
    \tl_gset:cn { contentsname }       { 目錄 }
    \tl_gset:cn { listfigurename }     { 插圖 }
    \tl_gset:cn { listtablename }      { 表格 }
    \tl_gset:cn { figurename }         { 圖 }
    \tl_gset:cn { tablename }          { 表 }
    \tl_gset:cn { indexname }          { 索引 }
    \tl_gset:cn { appendixname }       { 附錄 }
    \tl_gset:cn { refname }            { 參考文獻 }
    \tl_gset:cn { bibname }            { 參考文獻 }
  }

\tl_gput_right:Nn \g_projlib_language_settings_japanese_tl
  {
    \selectlanguage { japanese }
    \g_projlib_language_settings_common_tl
  }

\tl_gput_right:Nn \g_projlib_language_settings_english_tl
  {
    \selectlanguage { english }
    \g_projlib_language_settings_common_tl
  }

\tl_gput_right:Nn \g_projlib_language_settings_french_tl
  {
    \selectlanguage { french }
    \g_projlib_language_settings_common_tl
    \tl_gset:cn { frenchpartname } { Partie }
  }

\tl_gput_right:Nn \g_projlib_language_settings_ngerman_tl
  {
    \selectlanguage { ngerman }
    \g_projlib_language_settings_common_tl
  }

\tl_gput_right:Nn \g_projlib_language_settings_italian_tl
  {
    \selectlanguage { italian }
    \g_projlib_language_settings_common_tl
  }

\tl_gput_right:Nn \g_projlib_language_settings_portuguese_tl
  {
    \selectlanguage { portuguese }
    \g_projlib_language_settings_common_tl
  }

\tl_gput_right:Nn \g_projlib_language_settings_brazilian_tl
  {
    \selectlanguage { brazilian }
    \g_projlib_language_settings_common_tl
  }

\tl_gput_right:Nn \g_projlib_language_settings_spanish_tl
  {
    \selectlanguage { spanish }
    \g_projlib_language_settings_common_tl
  }

\tl_gput_right:Nn \g_projlib_language_settings_russian_tl
  {
    \selectlanguage { russian }
    \g_projlib_language_settings_common_tl
  }

\NewDocumentCommand \AddLanguageSetting { O{} m }
  {
    \IfNoValueTF { #1 }
      {
        \tl_gput_right:Nn \g_projlib_language_settings_common_tl { #2 }
      }
      {
        \tl_gput_right:cn { g_projlib_language_settings_ \projlib_language_str_to_languagename:n { #1 } _tl } { #2 }
      }
  }

\RequirePackage { setspace }

\tl_new:N  \g_projlib_language_linespacing_latin_tl
\tl_new:N  \g_projlib_language_linespacing_cjk_tl

\tl_gset:Nn \g_projlib_language_linespacing_latin_tl
  {
    \setstretch { 1.00 }
  }
\tl_gset:Nn \g_projlib_language_linespacing_cjk_tl
  {
    \onehalfspacing
  }

\cs_new:Nn \projlib_language_set_linespacing_latin:n
  {
    \tl_gset:Nn \g_projlib_language_linespacing_latin_tl { #1 }
  }
\cs_new:Nn \projlib_language_set_linespacing_cjk:n
  {
    \tl_gset:Nn \g_projlib_language_linespacing_cjk_tl { #1 }
  }

\tl_new:N  \g_projlib_language_parindent_latin_tl
\tl_new:N  \g_projlib_language_parindent_cjk_tl

\@ifclassloaded{beamer}
  {
    \tl_gset:Nn \g_projlib_language_parindent_latin_tl
      {
        \dim_set:Nn \parindent { 0em }
      }
    \tl_gset:Nn \g_projlib_language_parindent_cjk_tl
      {
        \dim_set:Nn \parindent { 0em }
      }
  }
  {
    \tl_gset:Nn \g_projlib_language_parindent_latin_tl
      {
        \dim_set:Nn \parindent { 1.5em }
      }
    \tl_gset:Nn \g_projlib_language_parindent_cjk_tl
      {
        \dim_set:Nn \parindent { 2em }
      }
  }

\cs_new:Nn \projlib_language_set_parindent_latin:n
  {
    \tl_gset:Nn \g_projlib_language_parindent_latin_tl { #1 }
  }
\cs_new:Nn \projlib_language_set_parindent_cjk:n
  {
    \tl_gset:Nn \g_projlib_language_parindent_cjk_tl { #1 }
  }

\cs_new:Nn \projlib_language_use_language_pure:n
  {
    \tl_use:c { g_projlib_language_settings_ \projlib_language_str_to_languagename:n { #1 } _tl }
  }

\cs_new:Nn \projlib_language_use_language:n
  {
    \projlib_language_use_language_pure:n { #1 }
    \tl_use:c { g_projlib_language_linespacing_ \projlib_language_str_to_languagetype:n { #1 } _tl }
    \tl_use:c { g_projlib_language_parindent_ \projlib_language_str_to_languagetype:n { #1 } _tl }
  }
\cs_generate_variant:Nn \projlib_language_use_language:n { e }

\NewDocumentCommand \UseLanguage { m }
  {
    \hook_gput_code:nnn { begindocument } { projlib-language }
      {
        \projlib_language_use_language:e { #1 }
      }
  }

\NewDocumentCommand \UseOtherLanguage { m m }
  {
    \group_begin: \group_begin:
      \projlib_language_use_language_pure:e { #1 }
      #2
    \group_end: \group_end:
  }

\UseLanguage { \g__projlib_language_main_str }

\cs_new:Nn \projlib_langauge_define_multilingual_text:Nn
  { % #1 = command name
    % #2 = key-value name configuration
    \keyval_parse:nnn
      {}
      {
        \__projlib_langauge_define_multilingual_text_do:nnn
          { \cs_to_str:N #1 }
      }
      { #2 }
    \tl_gset:Nn #1
      {
        \tl_use:c { \cs_to_str:N #1 _projlib_language_text_ \languagename }
      }
  }
\cs_generate_variant:Nn \projlib_langauge_define_multilingual_text:Nn { cn }

\cs_new:Nn \__projlib_langauge_define_multilingual_text_do:nnn
  { % #1 = command name
    % #2 = language name
    % #3 = the text
    \exp_args:Ne \tl_gset:cn { #1 _projlib_language_text_ \projlib_language_str_to_languagename:n { #2 } } { #3 }
  }

\endinput
%%
%% End of file `projlib-language.sty'.
\end{filecontents*}
\documentclass{article}

\usepackage{projlib-language}

\usepackage{amsthm}
\usepackage{aliascnt}
\usepackage{cleveref}

\makeatletter

\ExplSyntaxOn

\bool_new:N \l__projlib_theorem_regionalref_bool
\bool_new:N \l__projlib_theorem_originalref_bool

\bool_set_true:N \l__projlib_theorem_originalref_bool
% \bool_set_false:N \l__projlib_theorem_originalref_bool


\clist_set:Nn \c__projlib_theorem_supported_clist
  {
    theorem                   ,
    lemma                     ,
    proposition               ,
    corollary                 ,
    property                  ,
    fact                      ,
    conjecture                ,
    definition                ,
    axiom                     ,
    assumption                ,
    convention                ,
    hypothesis                ,
    notation                  ,
    exemple                   ,
    problem                   ,
    question                  ,
    exercise                  ,
    remark                    ,
    observation               ,
    definition-proposition    ,
    definition-theorem        ,
  }

\clist_map_inline:Nn \c__projlib_theorem_supported_clist
  {
    \clist_map_inline:Nn \c__projlib_language_supported_clist
      {
        \tl_new:c { c_projlib_theorem_name_ #1 _ ##1 _tl }
        \tl_new:c { c_projlib_theorem_name_ #1 _plural_ ##1 _tl }
        \tl_new:c { c_projlib_theorem_name_uppercase_ #1 _ ##1 _tl }
        \tl_new:c { c_projlib_theorem_name_uppercase_ #1 _plural_ ##1 _tl }
      }
  }

\clist_map_inline:Nn \c__projlib_theorem_supported_clist
  {
    \newtheorem { #1 _projlib_regional } { \tl_use:c { c_projlib_theorem_name_ #1 _ \languagename _tl } }
    \NewDocumentEnvironment { #1 } { O{} }
      {
        \begin{ #1 _projlib_regional }[##1]
          \bool_if:NT \l__projlib_theorem_originalref_bool
            {
              \addtocounter   { #1 _projlib_original_\languagename } { -1 }
              \refstepcounter { #1 _projlib_original_\languagename }
            }
      }
      {
        \end{ #1 _projlib_regional }
      }
  }

\bool_if:NTF \l__projlib_theorem_originalref_bool
  {% "originalref" mode
    \clist_map_inline:Nn \c__projlib_theorem_supported_clist
      {
        \clist_map_inline:Nn \c__projlib_language_supported_clist
          {
            \newaliascnt { #1 _projlib_original_ ##1 } { #1 _projlib_regional }
            %% Too slow
            % \crefname { #1 _projlib_original_ ##1 }
            %   { \tl_use:c { c_projlib_theorem_name_ #1 _ ##1 _tl } }
            %   { \tl_use:c { c_projlib_theorem_name_ #1 _plural_ ##1 _tl } }
            % \Crefname { #1 _projlib_original_ ##1 }
            %   { \tl_use:c { c_projlib_theorem_name_uppercase_ #1 _ ##1 _tl } }
            %   { \tl_use:c { c_projlib_theorem_name_uppercase_ #1 _plural_ ##1 _tl } }
          }
        %% Does not work
        % \crefname { #1 _projlib_original_ \exp_not:N \languagename }
        %   { \tl_use:c { c_projlib_theorem_name_ #1 _ \languagename _tl } }
        %   { \tl_use:c { c_projlib_theorem_name_ #1 _plural_ \languagename _tl } }
      }
  }
  {% "regionalref" mode
    \clist_map_inline:Nn \c__projlib_theorem_supported_clist
      {
        \crefname { #1 _projlib_regional }
          { \tl_use:c { c_projlib_theorem_name_ #1 _ \languagename _tl } }
          { \tl_use:c { c_projlib_theorem_name_ #1 _plural_ \languagename _tl } }
        \Crefname { #1 _projlib_regional }
          { \tl_use:c { c_projlib_theorem_name_uppercase_ #1 _ \languagename _tl } }
          { \tl_use:c { c_projlib_theorem_name_uppercase_ #1 _plural_ \languagename _tl } }
      }
  }


% Temporary names
\tl_set:Nn \c_projlib_theorem_name_theorem_english_tl { Theorem }
\tl_set:Nn \c_projlib_theorem_name_theorem_plural_english_tl { Theorems }
\tl_set:Nn \c_projlib_theorem_name_theorem_french_tl { Théorème }
\tl_set:Nn \c_projlib_theorem_name_theorem_plural_french_tl { Théorèmes }

\tl_set:Nn \c_projlib_theorem_name_definition_english_tl { Definition }
\tl_set:Nn \c_projlib_theorem_name_definition_plural_english_tl { Definitions }
\tl_set:Nn \c_projlib_theorem_name_definition_french_tl { Définition }
\tl_set:Nn \c_projlib_theorem_name_definition_plural_french_tl { Définitions }

\ExplSyntaxOff

\makeatother


\begin{document}

\UseLanguage{English}

\begin{theorem}\label{thm1}
  In english.
\end{theorem}
\begin{definition}\label{def1}
  In english.
\end{definition}

\cref{thm1,thm2,def1,def2}


\UseLanguage{French}
\begin{theorem}\label{thm2}
  En français.
\end{theorem}
\begin{definition}\label{def2}
  En français.
\end{definition}

\cref{thm1,thm2,def1,def2}


\end{document}
7
  • \crefname/\Crefname internally use \csname..\endcsname for defining some macros. In the course of defining the \csname..\endcsname-expressions are evaluated fully to yield the corresponding control-word-token. Seems basically you ask whether the name of a control-word-token can have a place-holder. This is not possible. You can use place-holders with \csname..\endcsname-expressions but you cannot have place-holders in the names of already created control-word-tokens. ... Feb 11 at 10:33
  • ... If instead of c_projlib_theorem_name_theorem_\languagename_tl and the like you could use macro-names that match the naming-pattern of the macros defined via \crefname/\Crefname, then you would be done without needing to use \crefname/\Crefname. But I think this is not an option for you. Feb 11 at 10:35
  • @UlrichDiez The thing is I am not familiar with the internal of cleveref. Clearly \crefname does much more that just set some name macros, otherwise it won't take so much time. That said, I'm not sure which macros should be set if not using \crefname to accomplish the goal.
    – Jinwen
    Feb 11 at 10:39
  • Neither am I all too familiar with cleveref's internals. I just downloaded cleveref.dtx and searched for \crefname. Definitions can be found in lines 4164 ff. Basically both \crefname and \Crefnamre internally use \@crefname (defined in line 4245) for doing some \csname..\endcsname-trickery. Seems the time-consuming part with \crefname and \Crefname is the attempts of defining the other case-variants as well. Feb 11 at 10:45
  • @UlrichDiez Actually I owe you a huge "Thank you" :) The current approach I'm using is inspired by your answer tex.stackexchange.com/a/610207 , thus the use of \newtheorem is reduced to only once per theorem-like environment, and is instead using only counters for recording the language name in the context, so the code is more compact. The sad thing is \newtheorem is not the most time-consuming item, so one still has to deal with the \crefname/\Crefname issue.
    – Jinwen
    Feb 11 at 10:53

1 Answer 1

1

After more than half an year since the question Seeking a faster implementation of \CreateTheorem, I think I finally realize what is really consuming so much time in the "originalref" mode.

The \crefname calls \@crefname internally, which, despite creating name macros \cref@...@name and \cref@...@name@plural, adds the current counter name to \cref@label@types. It is really from then that so much time is taken. In cleveref.dtx, one can find the following code processing names, formats, etc. to each item in \cref@label@types:

% Define any undefined formats listed in \cmd{\cref@label@types} using
% the components.
%    \begin{macrocode}
  \let\@tempstack\cref@label@types%
  \cref@isstackfull{\@tempstack}%
  \@whilesw\if@cref@stackfull\fi{%
    \edef\@tempa{\cref@stack@top{\@tempstack}}%
    \@ifundefined{cref@\@tempa @name}{%
      \expandafter\def\expandafter\@tempb\expandafter{%
        \csname cref@\@tempa @name\endcsname}%
      \expandafter\def\expandafter\@tempc\expandafter{%
        \csname cref@\@tempa @name@preamble\endcsname}%
      \expandafter\expandafter\expandafter%
        \let\expandafter\@tempb\@tempc%
      \expandafter\def\expandafter\@tempb\expandafter{%
        \csname cref@\@tempa @name@plural\endcsname}%
      \expandafter\def\expandafter\@tempc\expandafter{%
        \csname cref@\@tempa @name@plural@preamble\endcsname}%
      \expandafter\expandafter\expandafter%
        \let\expandafter\@tempb\@tempc%
    }{%
      \edef\@tempb{%
        \expandafter\noexpand\csname extras\cref@language\endcsname}%
      \expandafter\def\expandafter\@tempc\expandafter{%
        \expandafter\crefname\expandafter{\@tempa}}%
      \expandafter\expandafter\expandafter\cref@addto%
      \expandafter\expandafter\expandafter\@tempc%
      \expandafter\expandafter\expandafter{%
        \expandafter\expandafter\expandafter{%
          \csname cref@\@tempa @name\endcsname}}%
      \expandafter\expandafter\expandafter\cref@addto%
      \expandafter\expandafter\expandafter\@tempc%
      \expandafter\expandafter\expandafter{%
        \expandafter\expandafter\expandafter{%
          \csname cref@\@tempa @name@plural\endcsname}}%
      \expandafter\expandafter\expandafter\cref@addto%
        \expandafter\@tempb\expandafter{\@tempc}%
    }%
    \@ifundefined{Cref@\@tempa @name}{%
      \expandafter\def\expandafter\@tempb\expandafter{%
        \csname Cref@\@tempa @name\endcsname}%
      \expandafter\def\expandafter\@tempc\expandafter{%
        \csname Cref@\@tempa @name@preamble\endcsname}%
      \expandafter\expandafter\expandafter%
        \let\expandafter\@tempb\@tempc%
      \expandafter\def\expandafter\@tempb\expandafter{%
        \csname Cref@\@tempa @name@plural\endcsname}%
      \expandafter\def\expandafter\@tempc\expandafter{%
        \csname Cref@\@tempa @name@plural@preamble\endcsname}%
      \expandafter\expandafter\expandafter%
        \let\expandafter\@tempb\@tempc%
    }{%
      \edef\@tempb{%
        \expandafter\noexpand\csname extras\cref@language\endcsname}%
      \expandafter\def\expandafter\@tempc\expandafter{%
        \expandafter\Crefname\expandafter{\@tempa}}%
      \expandafter\expandafter\expandafter\cref@addto%
      \expandafter\expandafter\expandafter\@tempc%
      \expandafter\expandafter\expandafter{%
        \expandafter\expandafter\expandafter{%
          \csname Cref@\@tempa @name\endcsname}}%
      \expandafter\expandafter\expandafter\cref@addto%
      \expandafter\expandafter\expandafter\@tempc%
      \expandafter\expandafter\expandafter{%
        \expandafter\expandafter\expandafter{%
          \csname Cref@\@tempa @name@plural\endcsname}}%
      \expandafter\expandafter\expandafter\cref@addto%
        \expandafter\@tempb\expandafter{\@tempc}%
    }%
%    \end{macrocode}
% We only define the reference-range and multi-reference formats if the
% plural form of the name is defined in the corresponding
% \cmd{\cref\meta{type}@name@plural}. Though \cmd{\crefname} and
% \cmd{\Crefname} always define both the singular and plural forms
% together, cross-reference names can also be defined automatically by
% \cmd{\newtheorem}, which can only define the singular form. For
% symmetry, we apply the same logic to the normal cross-reference format
% definition (only defining it if the singular form of the name is
% defined in \cmd{\cref\meta{type}@name}), though this should always be
% the case.
%    \begin{macrocode}
    \@ifundefined{cref@\@tempa @format}{%
      \@ifundefined{cref@\@tempa @name}{}{%
        \expandafter\@crefdefineformat\expandafter{\@tempa}}}{}%
    \@ifundefined{crefrange@\@tempa @format}{%
      \@ifundefined{cref@\@tempa @name@plural}{}{%
        \expandafter\@crefrangedefineformat\expandafter{\@tempa}}}{}%
    \@ifundefined{cref@\@tempa @format@first}{%
      \@ifundefined{cref@\@tempa @name@plural}{}{%
        \expandafter\@crefdefinemultiformat\expandafter{\@tempa}}}{}%
    \@ifundefined{crefrange@\@tempa @format@first}{%
      \@ifundefined{cref@\@tempa @name@plural}{}{%
        \expandafter\@crefrangedefinemultiformat%
        \expandafter{\@tempa}}}{}%
    \cref@stack@pop{\@tempstack}%
    \cref@isstackfull{\@tempstack}}%
%    \end{macrocode}
%
% If formats for subsections are undefined, define them to be identical
% to the formats for sections. Similarly for subsections within
% appendices, subfigures, subtables, subequations and enums.
%    \begin{macrocode}
  \@crefcopyformats{section}{subsection}%
  \@crefcopyformats{subsection}{subsubsection}%
  \@crefcopyformats{appendix}{subappendix}%
  \@crefcopyformats{subappendix}{subsubappendix}%
  \@crefcopyformats{figure}{subfigure}%
  \@crefcopyformats{table}{subtable}%
  \@crefcopyformats{equation}{subequation}%
%
  \@crefcopyformats{enumi}{enumii}%
  \@crefcopyformats{enumii}{enumiii}%
  \@crefcopyformats{enumiii}{enumiv}%
  \@crefcopyformats{enumiv}{enumv}%
%    \end{macrocode}

Since all these separate counters for theorems shares the same format, one can simply use \@crefcopyformats. That said, instead of \crefname, one can do:

\tl_gset:cn { cref@ ... @name } { ... }
\tl_gset:cn { cref@ ... @name@plural } { ... }
\@crefcopyformats { <the main counter> } { <the separate counter> }

For originalref mode, this would save plenty of time, making it almost as fast as the regionalref mode (finally).

A complete example is:

\documentclass{article}

\usepackage{projlib-language}

\usepackage{amsthm}
\usepackage{aliascnt}
\usepackage{hyperref}
\usepackage[nameinlink]{cleveref}

\makeatletter

\ExplSyntaxOn

\bool_new:N \l__projlib_theorem_regionalref_bool
\bool_new:N \l__projlib_theorem_originalref_bool

\bool_set_true:N \l__projlib_theorem_originalref_bool
% \bool_set_false:N \l__projlib_theorem_originalref_bool


\clist_const:Nn \c__projlib_theorem_supported_clist
  {
    theorem                   ,
    lemma                     ,
    proposition               ,
    corollary                 ,
    property                  ,
    fact                      ,
    conjecture                ,
    definition                ,
    axiom                     ,
    assumption                ,
    convention                ,
    hypothesis                ,
    notation                  ,
    example                   ,
    problem                   ,
    question                  ,
    exercise                  ,
    remark                    ,
    observation               ,
    definition-proposition    ,
    definition-theorem        ,
  }

\clist_map_inline:Nn \c__projlib_theorem_supported_clist
  {
    \clist_map_inline:Nn \c__projlib_language_supported_clist
      {
        \tl_new:c { c_projlib_theorem_name_ #1 _ ##1 _tl }
        \tl_new:c { c_projlib_theorem_name_ #1 _plural_ ##1 _tl }
        \tl_new:c { c_projlib_theorem_name_uppercase_ #1 _ ##1 _tl }
        \tl_new:c { c_projlib_theorem_name_uppercase_ #1 _plural_ ##1 _tl }
      }
  }

\clist_map_inline:Nn \c__projlib_theorem_supported_clist
  {
    \newtheorem { #1 _projlib_regional } { \tl_use:c { c_projlib_theorem_name_ #1 _ \languagename _tl } }
    \NewDocumentEnvironment { #1 } { O{} }
      {
        \begin{ #1 _projlib_regional }[##1]
          \bool_if:NT \l__projlib_theorem_originalref_bool
            {
              \addtocounter   { #1 _projlib_original_\languagename } { -1 }
              \refstepcounter { #1 _projlib_original_\languagename }
            }
      }
      {
        \end{ #1 _projlib_regional }
      }
  }

\bool_if:NTF \l__projlib_theorem_originalref_bool
  {% "originalref" mode
    \clist_map_inline:Nn \c__projlib_theorem_supported_clist
      {
        \clist_map_inline:Nn \c__projlib_language_supported_clist
          {
            \newaliascnt { #1 _projlib_original_ ##1 } { #1 _projlib_regional }
            %% Too slow
            % \crefname { #1 _projlib_original_ ##1 }
            %   { \tl_use:c { c_projlib_theorem_name_ #1 _ ##1 _tl } }
            %   { \tl_use:c { c_projlib_theorem_name_plural_ #1 _ ##1 _tl } }
            % \Crefname { #1 _projlib_original_ ##1 }
            %   { \tl_use:c { c_projlib_theorem_name_uppercase_ #1 _ ##1 _tl } }
            %   { \tl_use:c { c_projlib_theorem_name_plural_uppercase_ #1 _ ##1 _tl } }
            \tl_gset:cn { cref@ #1 _projlib_original_ ##1 @name } { \tl_use:c { c_projlib_theorem_name_ #1 _ ##1 _tl } }
            \tl_gset:cn { cref@ #1 _projlib_original_ ##1 @name@plural } { \tl_use:c { c_projlib_theorem_name_plural_ #1 _ ##1 _tl } }
            % Two ways to add items in \cref@label@types, just for testing
            % \cref@stack@push{ #1 _projlib_original_ ##1 }{\cref@label@types}
            % \regex_replace_once:nnN { \c{@nil} } { #1 _projlib_original_ ##1 , \c{@nil} } \cref@label@types
            \@crefcopyformats { #1_projlib_regional } { #1 _projlib_original_ ##1 }
          }
      }
  }
  {% "regionalref" mode
    \clist_map_inline:Nn \c__projlib_theorem_supported_clist
      {
        \crefname { #1 _projlib_regional }
          { \tl_use:c { c_projlib_theorem_name_ #1 _ \languagename _tl } }
          { \tl_use:c { c_projlib_theorem_name_plural_ #1 _ \languagename _tl } }
        \Crefname { #1 _projlib_regional }
          { \tl_use:c { c_projlib_theorem_name_uppercase_ #1 _ \languagename _tl } }
          { \tl_use:c { c_projlib_theorem_name_plural_uppercase_ #1 _ \languagename _tl } }
      }
  }


% Temporary names
\tl_set:Nn \c_projlib_theorem_name_theorem_english_tl { Theorem }
\tl_set:Nn \c_projlib_theorem_name_plural_theorem_english_tl { Theorems }
\tl_set:Nn \c_projlib_theorem_name_theorem_french_tl { Théorème }
\tl_set:Nn \c_projlib_theorem_name_plural_theorem_french_tl { Théorèmes }

\tl_set:Nn \c_projlib_theorem_name_definition_english_tl { Definition }
\tl_set:Nn \c_projlib_theorem_name_plural_definition_english_tl { Definitions }
\tl_set:Nn \c_projlib_theorem_name_definition_french_tl { Définition }
\tl_set:Nn \c_projlib_theorem_name_plural_definition_french_tl { Définitions }

\ExplSyntaxOff

\makeatother


\begin{document}

\UseLanguage{English}

Current language: \languagename

\begin{theorem}\label{thm1}
  In english.
\end{theorem}
\begin{theorem}\label{thm2}
  In english.
\end{theorem}
\begin{definition}\label{def1}
  In english.
\end{definition}

\cref{thm1,thm2,thm3,def1,def2}


\vspace{1cm}

\UseLanguage{French}

Current language: \languagename

\begin{theorem}\label{thm3}
  En français.
\end{theorem}
\begin{definition}\label{def2}
  En français.
\end{definition}

\cref{thm1,thm2,thm3,def1,def2}

\end{document}

enter image description here

If you uncomment the \bool_set_false:N \l__projlib_theorem_originalref_bool to enable the regionalref mode, the result would be:

enter image description here

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.