This was the underlying motivation for a previous question of mine. However, after several hours of failure, I decide to ask this problem directly.
The goal
In order to support the four declensions of German in the package crefthe, I intended to define a new command \crefthevariantname, whose usage would be like:
\crefthevariantname{theorem}
{
{Satz}{Sätze}
, Nominativ = [der]{Satz}[die]{Sätze}
, Genitiv = [des]{Satzes}[der]{Sätze}
, Dativ = [dem]{Satz}[den]{Sätzen}
, Akkusativ = [den]{Satz}[die]{Sätze}
}
Ideally, it should internally convert this input into:
\crefthename{theorem}
[
\str_case:NnF \l__crefthe_variant_tl
{
{ Nominativ } { der }
{ Genitiv } { des }
{ Dativ } { dem }
{ Akkusativ } { den }
} { }
]
{
\str_case:NnF \l__crefthe_variant_tl
{
{ Nominativ } { Satz }
{ Genitiv } { Satzes }
{ Dativ } { Satz }
{ Akkusativ } { Satz }
} { Satz }
}
[
\str_case:Nn \l__crefthe_variant_tl
{
{ Nominativ } { die }
{ Genitiv } { der }
{ Dativ } { den }
{ Akkusativ } { die }
} { }
]
{
\str_case:Nn \l__crefthe_variant_tl
{
{ Nominativ } { Sätze }
{ Genitiv } { Sätze }
{ Dativ } { Sätzen }
{ Akkusativ } { Sätze }
} { Sätze }
}
I've tested the code above directly and it works, so the only thing remains to do is to achieve this transition.
What I have done
For now, I have successfully managed to parse the input, with the code below:
\keys_define:nn { crefthe-variant-parse }
{
, unknown .code:n = {
\seq_put_right:No \l__crefthe_variant_variant_seq { \l_keys_key_tl }
\__crefthe_variant_append_to_seq:w #1
}
}
\bool_new:N \l__crefthe_variant_dafault_given_bool
\cs_new:Nn \crefthe_parse_variant_string:n
% #1 = clist of configuration
{
\bool_set_false:N \l__crefthe_variant_dafault_given_bool
\clist_map_inline:nn { #1 }
{
\str_if_in:nnTF { ##1 } { = }
{
\keys_set:nn { crefthe-variant-parse } { ##1 }
}
{
\bool_set_true:N \l__crefthe_variant_dafault_given_bool
__crefthe_variant_set_default:w ##1
}
}
__crefthe_variant_create_prop_from_seq:n { article_singular }
__crefthe_variant_create_prop_from_seq:n { article_plural }
__crefthe_variant_create_prop_from_seq:n { singular }
__crefthe_variant_create_prop_from_seq:n { plural }
}
\tl_new:N \l__crefthe_variant_default_article_singular_tl
\tl_new:N \l__crefthe_variant_default_article_plural_tl
\tl_new:N \l__crefthe_variant_default_singular_tl
\tl_new:N \l__crefthe_variant_default_plural_tl
\NewDocumentCommand __crefthe_variant_set_default:w { O{} m O{} m }
{
\tl_set:Nn \l__crefthe_variant_default_article_singular_tl { #1 }
\tl_set:Nn \l__crefthe_variant_default_article_plural_tl { #3 }
\tl_set:Nn \l__crefthe_variant_default_singular_tl { #2 }
\tl_set:Nn \l__crefthe_variant_default_plural_tl { #4 }
}
\seq_new:N \l__crefthe_variant_variant_seq
\seq_new:N \l__crefthe_variant_article_singular_seq
\seq_new:N \l__crefthe_variant_article_plural_seq
\seq_new:N \l__crefthe_variant_singular_seq
\seq_new:N \l__crefthe_variant_plural_seq
\NewDocumentCommand __crefthe_variant_append_to_seq:w { O{} m O{} m }
{
\seq_put_right:Nn \l__crefthe_variant_article_singular_seq { #1 }
\seq_put_right:Nn \l__crefthe_variant_article_plural_seq { #3 }
\seq_put_right:Nn \l__crefthe_variant_singular_seq { #2 }
\seq_put_right:Nn \l__crefthe_variant_plural_seq { #4 }
}
\cs_new:Nn __crefthe_variant_create_prop_from_seq:n
{
\prop_clear_new:c { l__crefthe_variant_ #1 prop }
\int_step_inline:nn { \seq_count:c { l__crefthe_variant #1 seq } }
{
\prop_put:cxx { l__crefthe_variant #1 prop }
{ \seq_item:cn { l__crefthe_variant_variant_seq } { ##1 } }
{ \seq_item:cn { l__crefthe_variant #1 _seq } { ##1 } }
}
}
The main command is \crefthe_parse_variant_string:n. It shall parse the default line (the one without =, in the previous example it is {Satz}{Sätze}) and the other lines (like Nominativ = [der]{Satz}[die]{Sätze}) separately:
\__crefthe_variant_set_default:wparses the default line, saves the strings into the corresponding\l__crefthe_variant_default_<type>_tl;\__crefthe_variant_append_to_seq:wprocesses the other lines, at each time appends the string into the corresponding\l__crefthe_variant_<type>_seq.
Moreover, though I'm not sure if it would be helpful in the final solution, with the help of this @egreg's answer, there is a \__crefthe_variant_create_prop_from_seq:n to convert a pair of sequences into a property list.
What I don't know how to do
I would like then to achieve the [...] {...} [...] {...} part in \crefthe_pass_variant_string_to:n and then pass it to \crefthename{<name>} to get the desired result.
However, since all these variables, whether tl or seq, are reusable, when converting into the final result, they have to be properly expanded, i.e. to store their values instead of the macros themselves. However, since I am not experienced at controlling expansion, even with the powerful expl3 I feel hard to correctly achieve this.
My sole purpose is to achieve the main goal, i.e. the translation from the input into something that can be accepted by \crefthename, a command which receives m O{} m O{} m type arguments. Thus if you find my idea tedious or have alternative and maybe better approach, please kindly share your opinion with me.
MWE
Below is a MWE. Since the problem is really about macro calling and expanding, I did not include specific code about crefthe. In some commented part you may see my failed attempts trying to make use of Max Chernoff's and @egreg's code.
\documentclass{article}
\begin{document}
\ExplSyntaxOn
\NewDocumentCommand \crefthevariantname { m m }
{
\crefthe_parse_variant_string:n { #2 }
\crefthe_pass_variant_string_to:n { \crefthename {#1} }
}
\keys_define:nn { crefthe-variant-parse }
{
, unknown .code:n = {
\seq_put_right:No \l__crefthe_variant_variant_seq { \l_keys_key_tl }
__crefthe_variant_append_to_seq:w #1
}
}
\bool_new:N \l__crefthe_variant_dafault_given_bool
\cs_new:Nn \crefthe_parse_variant_string:n
% #1 = clist of configuration
{
\bool_set_false:N \l__crefthe_variant_dafault_given_bool
\clist_map_inline:nn { #1 }
{
\str_if_in:nnTF { ##1 } { = }
{
\keys_set:nn { crefthe-variant-parse } { ##1 }
}
{
\bool_set_true:N \l__crefthe_variant_dafault_given_bool
__crefthe_variant_set_default:w ##1
}
}
__crefthe_variant_create_prop_from_seq:n { article_singular }
__crefthe_variant_create_prop_from_seq:n { article_plural }
__crefthe_variant_create_prop_from_seq:n { singular }
__crefthe_variant_create_prop_from_seq:n { plural }
}
\tl_new:N \l__crefthe_variant_default_article_singular_tl
\tl_new:N \l__crefthe_variant_default_article_plural_tl
\tl_new:N \l__crefthe_variant_default_singular_tl
\tl_new:N \l__crefthe_variant_default_plural_tl
\NewDocumentCommand __crefthe_variant_set_default:w { O{} m O{} m }
{
\tl_set:Nn \l__crefthe_variant_default_article_singular_tl { #1 }
\tl_set:Nn \l__crefthe_variant_default_article_plural_tl { #3 }
\tl_set:Nn \l__crefthe_variant_default_singular_tl { #2 }
\tl_set:Nn \l__crefthe_variant_default_plural_tl { #4 }
}
\seq_new:N \l__crefthe_variant_variant_seq
\seq_new:N \l__crefthe_variant_article_singular_seq
\seq_new:N \l__crefthe_variant_article_plural_seq
\seq_new:N \l__crefthe_variant_singular_seq
\seq_new:N \l__crefthe_variant_plural_seq
\NewDocumentCommand __crefthe_variant_append_to_seq:w { O{} m O{} m }
{
\seq_put_right:Nn \l__crefthe_variant_article_singular_seq { #1 }
\seq_put_right:Nn \l__crefthe_variant_article_plural_seq { #3 }
\seq_put_right:Nn \l__crefthe_variant_singular_seq { #2 }
\seq_put_right:Nn \l__crefthe_variant_plural_seq { #4 }
}
\cs_new:Nn __crefthe_variant_create_prop_from_seq:n
{
\prop_clear_new:c { l__crefthe_variant_ #1 prop }
\int_step_inline:nn { \seq_count:c { l__crefthe_variant #1 seq } }
{
\prop_put:cxx { l__crefthe_variant #1 prop }
{ \seq_item:cn { l__crefthe_variant_variant_seq } { ##1 } }
{ \seq_item:cn { l__crefthe_variant #1 _seq } { ##1 } }
}
}
% \cs_new_protected:Nn __crefthe_variant_map_dafault:nn
% {
% \str_if_eq:onT { \l__crefthe_variant_tl } { #1 }
% {
% \prg_break:n { #2 \use_none:n }
% }
% }
% \cs_new_protected:Nn __crefthe_variant_map:nn
% {
% \str_if_eq:onT { \l__crefthe_variant_tl } { #1 }
% {
% \prg_break:n { #2 }
% }
% }
\cs_new:Nn \crefthe_pass_variant_string_to:n
{
\bool_if:NTF \l__crefthe_variant_dafault_given_bool
{
#1
% [
% \prop_if_in:coTF { l__crefthe_variant_article_singular_prop } { \l__crefthe_variant_tl }
% {
% \prop_get:coN { l__crefthe_variant_article_singular_prop } { \l__crefthe_variant_tl } \l_tmpa_tl
% \tl_use:N \l_tmpa_tl
% }
% { \l__crefthe_variant_default_article_singular_tl }
% ]
% {
% \prop_if_in:coTF { l__crefthe_variant_singular_prop } { \l__crefthe_variant_tl }
% {
% \prop_get:coN { l__crefthe_variant_singular_prop } { \l__crefthe_variant_tl } \l_tmpa_tl
% \tl_use:N \l_tmpa_tl
% }
% { \l__crefthe_variant_default_singular_tl }
% }
% [
% \prop_if_in:coTF { l__crefthe_variant_article_plural_prop } { \l__crefthe_variant_tl }
% {
% \prop_get:coN { l__crefthe_variant_article_plural_prop } { \l__crefthe_variant_tl } \l_tmpa_tl
% \tl_use:N \l_tmpa_tl
% }
% { \l__crefthe_variant_default_article_plural_tl }
% ]
% {
% \prop_if_in:coTF { l__crefthe_variant_plural_prop } { \l__crefthe_variant_tl }
% {
% \prop_get:coN { l__crefthe_variant_plural_prop } { \l__crefthe_variant_tl } \l_tmpa_tl
% \tl_use:N \l_tmpa_tl
% }
% { \l__crefthe_variant_default_plural_tl }
% }
}
{
#1
% [
% \seq_map_pairwise_function:NNN
% \l__crefthe_variant_variant_seq
% \l__crefthe_variant_article_singular_seq
% __crefthe_variant_map:nn
% ]
% {
% \seq_map_pairwise_function:NNN
% \l__crefthe_variant_variant_seq
% \l__crefthe_variant_singular_seq
% __crefthe_variant_map:nn
% }
% [
% \seq_map_pairwise_function:NNN
% \l__crefthe_variant_variant_seq
% \l__crefthe_variant_article_plural_seq
% __crefthe_variant_map:nn
% ]
% {
% \seq_map_pairwise_function:NNN
% \l__crefthe_variant_variant_seq
% \l__crefthe_variant_plural_seq
% __crefthe_variant_map:nn
% }
}
}
\ExplSyntaxOff
Text in case of empty.
\end{document}
Below is a MWE with specific example of crefthe (due to the character count limitation I can only omit some of the code as % ...; you may find the corresponding code in the MWE above, if needed).
\documentclass{article}
\usepackage{amsthm}
\usepackage{crefthe}
\newtheorem{testenv}{Testenv}
\begin{document}
\ExplSyntaxOn
\NewDocumentCommand \crefthevariantname { m m }
{
\crefthe_parse_variant_string:n { #2 }
\crefthe_pass_variant_string_to:n { \crefthename {#1} }
}
%...
\cs_new:Nn \crefthe_pass_variant_string_to:n
{
\bool_if:NTF \l__crefthe_variant_dafault_given_bool
{
#1
% ...
}
{
#1
% ...
}
}
\ExplSyntaxOff
\crefthevariantname{testenv}
{
[0]{Zero}[00]{Zero}
, Nominativ = [1]{One}[11]{Ones}
, Genitiv = [2]{Two}[22]{Twos}
, Dativ = [3]{Three}[33]{Threes}
, Akkusativ = [4]{Four}[44]{Fours}
}
\begin{testenv}\label{testenv:test}
Environment for testing...
\end{testenv}
\crefthe{testenv:test}
\crefthe[variant=Nominativ]{testenv:test}
\crefthe[variant=Genitiv]{testenv:test}
\crefthe[variant=Dativ]{testenv:test}
\crefthe[variant=Akkusativ]{testenv:test}
\end{document}
The expected result would be 0 Zero <number>, 1 One <number>, 2 Two <number> etc. I didn't include actual preposition or definite article for testing article contraction, but let's hope that the expansion works as expected.
Just in case needed, below is the current (as of 2023/07/20) version of crefthe. It contains the definition of the command option variant and the corresponding macro \l__crefthe_variant_tl.
\NeedsTeXFormat{LaTeX2e}[2022-06-01]
\ProvidesExplPackage
{crefthe}
{2023/07/20} {}
{Cross referencing with proper definite articles}
\keys_define:nn { crefthe }
{
, overwrite .bool_set:N = \l__crefthe_overwrite_bool
, overwrite .initial:n = { false }
, nameinlink .bool_set:N = \l__crefthe_nameinlink_bool
, nameinlink .initial:n = { false }
, unknown .code:n =
{ \PassOptionsToPackage { \CurrentOption } { cleveref } }
}
\ProcessKeyOptions [ crefthe ]
\bool_if:NT \l__crefthe_nameinlink_bool
{
\PassOptionsToPackage { nameinlink } { cleveref }
}
\RequirePackage { cleveref }
\RequirePackage { regexpatch }
\NewCommandCopy \crefthe_cref_original:w \cref
\NewCommandCopy \crefthe_Cref_original:w \Cref
\NewCommandCopy \crefthe_crefname_original:w \crefname
\NewCommandCopy \crefthe_Crefname_original:w \Crefname
\NewCommandCopy \crefthe_namecref_original:w \namecref
\NewCommandCopy \crefthe_nameCref_original:w \nameCref
\NewCommandCopy \crefthe_namecrefs_original:w \namecrefs
\NewCommandCopy \crefthe_nameCrefs_original:w \nameCrefs
\str_new:N \l__crefthe_tmpa_str
% \l__crefthe_prep_once_tl is for the "-" mode,
% that only passes the preposition to the first definite article;
% \l__crefthe_prep_each_tl is for the "+" mode,
% that passes the preposition to every definite article.
\tl_new:N \l__crefthe_prep_once_tl
\tl_new:N \l__crefthe_prep_each_tl
\bool_new:N \g__crefthe_uppercase_bool
\bool_new:N \g__crefthe_has_prep_bool
\NewDocumentCommand \crefthe { s t- t+ O{} m }
{
\bool_gset_false:N \g__crefthe_uppercase_bool
__crefthe_cref_general:NNNnnN #1 #2 #3 { #4 } { #5 } \crefthe_cref_original:w
}
\NewDocumentCommand \Crefthe { s t- t+ O{} m }
{
\bool_gset_true:N \g__crefthe_uppercase_bool
__crefthe_cref_general:NNNnnN #1 #2 #3 { #4 } { #5 } \crefthe_Cref_original:w
}
\NewDocumentCommand \namecrefthe { t- t+ O{} m }
{
\bool_gset_false:N \g__crefthe_uppercase_bool
__crefthe_cref_general:NNNnnN \c_false_bool #1 #2 { #3 } { #4 } \crefthe_namecref_original:w
}
\NewDocumentCommand \nameCrefthe { t- t+ O{} m }
{
\bool_gset_true:N \g__crefthe_uppercase_bool
__crefthe_cref_general:NNNnnN \c_false_bool #1 #2 { #3 } { #4 } \crefthe_nameCref_original:w
}
\NewDocumentCommand \namecrefsthe { t- t+ O{} m }
{
\bool_gset_false:N \g__crefthe_uppercase_bool
__crefthe_cref_general:NNNnnN \c_false_bool #1 #2 { #3 } { #4 } \crefthe_namecrefs_original:w
}
\NewDocumentCommand \nameCrefsthe { t- t+ O{} m }
{
\bool_gset_true:N \g__crefthe_uppercase_bool
__crefthe_cref_general:NNNnnN \c_false_bool #1 #2 { #3 } { #4 } \crefthe_nameCrefs_original:w
}
\keys_define:nn { crefthe-setting }
{
, variant .tl_set:N = \l__crefthe_variant_tl
, unknown .code:n = {
\bool_gset_true:N \g__crefthe_has_prep_bool
\tl_set:No \l__crefthe_prep_tl { \l_keys_key_tl }
}
}
\cs_new_protected:Nn __crefthe_cref_general:NNNnnN
% #1 = star or not
% #2 = -
% #3 = +
% #4 = key-value
% #5 = label
% #6 = original command, such as \crefthe_cref_original:w or \crefthe_Cref_original:w
{
\tl_set:Nn \l__crefthe_variant_tl {}
\bool_gset_false:N \g__crefthe_has_prep_bool
\tl_set:Nn \l__crefthe_prep_tl {}
\keys_set:nn { crefthe-setting } { #4 }
\bool_if:NTF #2
{ \tl_set:No \l__crefthe_prep_once_tl { \l__crefthe_prep_tl } }
{
\bool_if:NTF #3
{ \tl_set:No \l__crefthe_prep_each_tl { \l__crefthe_prep_tl } }
{
% \str_set:Nx fully expands \__crefthe_prep_mode: into a string,
% then \str_case:Vn compares the value of the resulting string:
\str_set:Nx \l__crefthe_tmpa_str { \__crefthe_prep_mode: }
\str_case:Vn \l__crefthe_tmpa_str
{
{ - } { \tl_set:No \l__crefthe_prep_once_tl { \l__crefthe_prep_tl } }
{ + } { \tl_set:No \l__crefthe_prep_each_tl { \l__crefthe_prep_tl } }
}
}
}
\group_begin:
\bool_if:NTF #1
{ #6 * { #5 } }
{ #6 { #5 } }
\group_end:
\tl_gclear:N \l__crefthe_prep_each_tl
}
% __crefthe_prep_mode: defines the default mode for supported languages
\cs_new:Nn __crefthe_prep_mode:
{
\str_case:Vn \languagename
{
{french} { + }
{italian} { + }
{spanish} { - }
{portuguese} { + }
{brazilian} { + }
}
}
\NewDocumentCommand \crefthename { m O{} m O{} m }
{
__crefthe_name_general:nnnnnn { #1 } { #2 } { #3 } { #4 } { #5 } { c }
}
\NewDocumentCommand \Crefthename { m O{} m O{} m }
{
__crefthe_name_general:nnnnnn { #1 } { #2 } { #3 } { #4 } { #5 } { C }
}
\cs_new:Npn \crefthe_retrieve_space: { \skip_horizontal:n { -\tex_fontdimen:D 2 \tex_font:D~plus -\tex_fontdimen:D 3 \tex_font:D~minus -\tex_fontdimen:D 4 \tex_font:D } }
\cs_new:Nn \crefthe_empty_adjust:n
{
\tl_if_blank:nTF { #1 }
{
\crefthe_retrieve_space:
}
{
#1
}
}
\cs_new_protected:Nn __crefthe_name_general:nnnnnn
% #1 = environment name
% #2 = singular definite article
% #3 = singular name
% #4 = plural definite article
% #5 = plural name
% #6 = c or C
{
__crefthe_name_general_do:nnnnnn
{ #1 }
{ \crefthemark { \crefthe_empty_adjust:n { #2 } } }
{ \crefthe_empty_adjust:n { #3 } }
{ \crefthemark { \crefthe_empty_adjust:n { #4 } } }
{ \crefthe_empty_adjust:n { #5 } }
{ #6 }
}
\cs_new_protected:Nn __crefthe_name_general_do:nnnnnn
{
\use:c { crefthe_#6refname_original:w } { #1 } { #2 #3 } { #4 #5 }
\bool_if:NT \l__crefthe_nameinlink_bool
{
\hook_gput_code:nnn { begindocument } { crefthe }
{
\crefthe_patch_format:nnnn { #6ref@#1@format } { #6ref@#1@name } { #2 } { #3 }
\crefthe_patch_format:nnnn { #6ref@#1@format@first } { #6ref@#1@name@plural } { #4 } { #5 }
\crefthe_patch_format:nnnn { #6refrange@#1@format } { #6ref@#1@name@plural } { #4 } { #5 }
\crefthe_patch_format:nnnn { #6refrange@#1@format@first } { #6ref@#1@name@plural } { #4 } { #5 }
}
}
}
\seq_new:N \g__crefthe_already_patched_seq
\cs_new_protected:Nn \crefthe_patch_format:nnnn
% #1 = name of the format command
% #2 = name of the command after the hyperlink beginning mark
% #3 = new content before the mark
% #4 = new content after the mark
{
\seq_if_in:NnF \g__crefthe_already_patched_seq { #1 - #2 }
{
\makeatletter
\tl_set:No \l_tmpa_tl { #3 }
\tl_set:No \l_tmpb_tl { #4 }
\exp_args:Nc \regexpatchcmd { #1 }
{ (\cP# .) \c{ #2 } }
{ \u{l_tmpa_tl} \1 \u{l_tmpb_tl} }
{ } { \msg_warning:nnn { crefthe } { format-patch-failed } { #1 } }
\makeatother
\seq_gput_right:Nn \g__crefthe_already_patched_seq { #1 - #2 }
}
}
\msg_new:nnn { crefthe }
{ format-patch-failed }
{ Failed~to~patch~the~format~"\iow_char:N \#1"! }
\cs_generate_variant:Nn \text_lowercase:n { V }
\NewDocumentCommand \crefthemark { m }
{
\crefthe_contraction:Ve \l__crefthe_prep_each_tl
{ \crefthe_contraction:Vn \l__crefthe_prep_once_tl { #1 } }
\tl_gclear:N \l__crefthe_prep_once_tl
\tl_gset:Nx \l__crefthe_prep_each_tl
{ \text_lowercase:V \l__crefthe_prep_each_tl }
\str_if_eq:eeF { \str_tail:n { #1 } } { ' } { ~ }
\bool_gset_false:N \g__crefthe_uppercase_bool
}
\prg_generate_conditional_variant:Nnn \str_case_e:nn { ev } { T, F, TF }
\cs_new:Nn \crefthe_contraction:nn
{
\exp_args:Ne __crefthe_contraction:nnn
{ \text_lowercase:n { #2 } } { #1 } { #2 }
}
\cs_generate_variant:Nn \crefthe_contraction:nn { V, Ve }
\cs_new:Nn __crefthe_contraction:nnn
{
% #1 is \text_lowercase:n { #3 }
% #2 is the preposition
\tl_if_blank:nTF { #2 }
{ #3 }
{
\tl_if_exist:cTF { c_crefthe_contraction_rule_ \languagename tl }
{
\exp_args:Ne __crefthe_conditional_uppercase:n
{
\str_case_e:evF { #2~#1 }
{ c_crefthe_contraction_rule \languagename _tl }
{ #2~#1 }
}
}
{ #2~#3 }
}
}
\cs_new:Nn __crefthe_conditional_uppercase:n
{
\bool_if:NTF \g__crefthe_uppercase_bool
{ \text_titlecase_first:n }
{ \use:n }
{ #1 }
}
\NewDocumentCommand \crefthepatchname { m }
{
\clist_map_inline:nn { #1 }
{
\crefthe_patch_name:n { ##1 }
}
}
\cs_new:Nn \crefthe_patch_name:n
{
\tl_gput_left:cn { cref@#1@name } { \crefthemark { \crefthe_empty_adjust:n {} } }
\tl_gput_left:cn { cref@#1@name@plural } { \crefthemark { \crefthe_empty_adjust:n {} } }
\tl_gput_left:cn { Cref@#1@name } { \crefthemark { \crefthe_empty_adjust:n {} } }
\tl_gput_left:cn { Cref@#1@name@plural } { \crefthemark { \crefthe_empty_adjust:n {} } }
}
\hook_gput_code:nnn { begindocument/end } { crefthe }
{
\bool_if:NT \l__crefthe_overwrite_bool
{
\RenewCommandCopy \cref \crefthe
\RenewCommandCopy \Cref \Crefthe
\RenewCommandCopy \crefname \crefthename
\RenewCommandCopy \Crefname \Crefthename
}
}
\tl_const:Nn \c_crefthe_contraction_rule_french_tl
{
{ à~le } { au }
{ à~les } { aux }
{ de~le } { du }
{ de~les } { des }
{ À~le } { Au }
{ À~les } { Aux }
{ De~le } { Du }
{ De~les } { Des }
}
\tl_const:Nn \c_crefthe_contraction_rule_ngerman_tl
{
{ an~dem } { am }
{ an~das } { ans }
{ bei~dem } { beim }
{ in~dem } { im }
{ in~das } { ins }
{ von~dem } { vom }
{ zu~dem } { zum }
{ zu~der } { zur }
{ An~dem } { Am }
{ An~das } { Ans }
{ Bei~dem } { Beim }
{ In~dem } { Im }
{ In~das } { Ins }
{ Von~dem } { Vom }
{ Zu~dem } { Zum }
{ Zu~der } { Zur }
}
\tl_const:Nn \c_crefthe_contraction_rule_italian_tl
{
{ a~il } { al }
{ a~lo } { allo }
{ a~l' } { all' }
{ a~la } { alla }
{ di~il } { del }
{ di~lo } { dello }
{ di~l' } { dell' }
{ di~la } { della }
{ da~il } { dal }
{ da~lo } { dallo }
{ da~l' } { dall' }
{ da~la } { dalla }
{ in~il } { nel }
{ in~lo } { nello }
{ in~l' } { nell' }
{ in~la } { nella }
{ su~il } { sul }
{ su~lo } { sullo }
{ su~l' } { sull' }
{ su~la } { sulla }
{ a~i } { ai }
{ a~gli } { agli }
{ a~le } { alle }
{ di~i } { dei }
{ di~gli } { degli }
{ di~le } { delle }
{ da~i } { dai }
{ da~gli } { dagli }
{ da~le } { dalle }
{ in~i } { nei }
{ in~gli } { negli }
{ in~le } { nelle }
{ su~i } { sui }
{ su~gli } { sugli }
{ su~le } { sulle }
{ A~il } { Al }
{ A~lo } { Allo }
{ A~l' } { All' }
{ A~la } { Alla }
{ Di~il } { Del }
{ Di~lo } { Dello }
{ Di~l' } { Dell' }
{ Di~la } { Della }
{ Da~il } { Dal }
{ Da~lo } { Dallo }
{ Da~l' } { Dall' }
{ Da~la } { Dalla }
{ In~il } { Nel }
{ In~lo } { Nello }
{ In~l' } { Nell' }
{ In~la } { Nella }
{ Su~il } { Sul }
{ Su~lo } { Sullo }
{ Su~l' } { Sull' }
{ Su~la } { Sulla }
{ A~i } { Ai }
{ A~gli } { Agli }
{ A~le } { Alle }
{ Di~i } { Dei }
{ Di~gli } { Degli }
{ Di~le } { Delle }
{ Da~i } { Dai }
{ Da~gli } { Dagli }
{ Da~le } { Dalle }
{ In~i } { Nei }
{ In~gli } { Negli }
{ In~le } { Nelle }
{ Su~i } { Sui }
{ Su~gli } { Sugli }
{ Su~le } { Sulle }
}
\tl_const:Nn \c_crefthe_contraction_rule_spanish_tl
{
{ a~el } { al }
{ de~el } { del }
{ A~el } { Al }
{ De~el } { Del }
}
\tl_const:Nn \c_crefthe_contraction_rule_portuguese_tl
{
{ a~o } { ao }
{ a~a } { à }
{ a~os } { aos }
{ a~as } { às }
{ de~o } { do }
{ de~a } { da }
{ de~os } { dos }
{ de~as } { das }
{ em~o } { no }
{ em~a } { na }
{ em~os } { nos }
{ em~as } { nas }
{ A~o } { Ao }
{ A~a } { À }
{ A~os } { Aos }
{ A~as } { Às }
{ De~o } { Do }
{ De~a } { Da }
{ De~os } { Dos }
{ De~as } { Das }
{ Em~o } { No }
{ Em~a } { Na }
{ Em~os } { Nos }
{ Em~as } { Nas }
}
\tl_const:Nx \c_crefthe_contraction_rule_brazilian_tl
{ \exp_not:V \c_crefthe_contraction_rule_portuguese_tl }
\endinput
%%
%% End of file `crefthe.sty'.

Nominativ,Genitiv,DativandAkkusativevaluated at use time or at define time? Your MWE doesn't show a usage of your macro only the definition. This way we can't really experiment with anything. – Skillmon Jul 20 '23 at 13:23Nominativ = [der]{Satz}[die]{Sätze}) into the format of the second code block. It is for this reason that I didn't put specific code about my package to make things complex. However, to make this conversion, some intermediate macros (like those produced by my code) might be needed, these macros need to be expanded before other commands receive them, that is, only their values are needed. – Jinwen Jul 20 '23 at 13:33\l__crefthe_variant_tlit seems. – Skillmon Jul 20 '23 at 14:44\text_lowercase:V, as\text_lowercase:nwill expand the argument using\text_expand:n. – Skillmon Jul 20 '23 at 15:56