Generalising a second-order macro with loopsExpansion of macro in environment argumentLaTeX Loops in...
Which aircraft had such a luxurious-looking navigator's station?
Has the Isbell–Freyd criterion ever been used to check that a category is concretisable?
When should a commit not be version tagged?
How to speed up a process
Where is this triangular-shaped space station from?
How can I handle a player who pre-plans arguments about my rulings on RAW?
Can I become debt free or should I file for bankruptcy? How do I manage my debt and finances?
How to mitigate "bandwagon attacking" from players?
I am on the US no-fly list. What can I do in order to be allowed on flights which go through US airspace?
Logistics of a hovering watercraft in a fantasy setting
Is there any relevance to Thor getting his hair cut other than comedic value?
Must a tritone substitution use a dominant seventh chord?
Why does the author believe that the central mass that gas cloud HCN-0.009-0.044 orbits is smaller than our solar system?
Whom do I have to contact for a ticket refund in case of denied boarding (in the EU)?
Is my plan for fixing my water heater leak bad?
Why is working on the same position for more than 15 years not a red flag?
Auto Insert date into Notepad
Is divide-by-zero a security vulnerability?
What can I substitute for soda pop in a sweet pork recipe?
Is there a frame of reference in which I was born before I was conceived?
What to do when being responsible for data protection in your lab, yet advice is ignored?
How to avoid being sexist when trying to employ someone to function in a very sexist environment?
What if I store 10TB on azure servers and then keep the vm powered off?
How can atoms be electrically neutral when there is a difference in the positions of the charges?
Generalising a second-order macro with loops
Expansion of macro in environment argumentLaTeX Loops in newcommandDeclaring variables and writing loopsProblem using macro with TikZ foreachDefine macro for sequence/list/tuple macrosDefining newtheorems using loopsExpandable macro with loops and advanced string functions?Loops with Latex?For-loops with different iterationsDefine variable without newcommandDynamic Conditional Variables
I'd like to construct a macro that can be used to define commands. Those commands behave like variables or structs of variables, such that they can contain multiple values. The "member" is passed via an optional argument. I use it to define template environments and to have different strings for different languages, which need to be present in the document simultaneously.
Here's what I had and works.
newcommandMakeLocaleVar[1]{%
global@namedef{#1:en}{{scriptsize (Use {tttextbackslash #1[en]} to replace this text.)}}%
global@namedef{#1:fi}{{scriptsize (Use {tttextbackslash #1[fi]} to replace this text.)}}%
expandafternewcommandcsname #1endcsname[2][]{%
ifthenelse{equal{##1}{}}{%
global@namedef{#1:en}{##2}%
global@namedef{#1:fi}{##2}%
}{%
global@namedef{#1:##1}{##2}%
}%
}%
expandafternewcommandcsname Emit#1endcsname[1][en]{@nameuse{#1:##1}}%
}
First the default values are set. Then a command is created that sets the values according to the optional argument. If none, set value for all locales.
% In cls: define command
MakeLocaleVar{Faculty}
% In main tex: set values
Faculty{This faculty} % for all values
Faculty[fi]{Tämä tiedekunta} % for a specific one
% In cls environments: use values
EmitFaculty[en]
EmitFaculty[fi]
% Now in addition I'd like to be able to:
MakeLocaleVar[en,fi,de]{Faculty}
I tried to modify the command to accept arbitrary locales, but something's not working.
newcommandMakeLocaleVar[2][en,fi]{%
foreach n in {#1}{%
global@namedef{#2:n}{%
{scriptsize (Use {tttextbackslash #2[n]} to replace this text.)}%
}%
}%
expandafternewcommandcsname #2endcsname[2][]{%
ifthenelse{equal{##1}{}}{%
foreach n in {#1}{%
global@namedef{#2:n}{##2}%
}%
}{%
global@namedef{#2:##1}{##2}%
}%
}%
expandafternewcommandcsname Emit#2endcsname[1][en]{@nameuse{#2:##1}}%
}
If I set values that are used, everything is fine and dandy. It is when values are not set that my custom environments break and the default message shown is just Use Cmd[] to...
, so without the locale names.
Any idea as to what is going on?
macros loops pgffor variable
New contributor
|
show 1 more comment
I'd like to construct a macro that can be used to define commands. Those commands behave like variables or structs of variables, such that they can contain multiple values. The "member" is passed via an optional argument. I use it to define template environments and to have different strings for different languages, which need to be present in the document simultaneously.
Here's what I had and works.
newcommandMakeLocaleVar[1]{%
global@namedef{#1:en}{{scriptsize (Use {tttextbackslash #1[en]} to replace this text.)}}%
global@namedef{#1:fi}{{scriptsize (Use {tttextbackslash #1[fi]} to replace this text.)}}%
expandafternewcommandcsname #1endcsname[2][]{%
ifthenelse{equal{##1}{}}{%
global@namedef{#1:en}{##2}%
global@namedef{#1:fi}{##2}%
}{%
global@namedef{#1:##1}{##2}%
}%
}%
expandafternewcommandcsname Emit#1endcsname[1][en]{@nameuse{#1:##1}}%
}
First the default values are set. Then a command is created that sets the values according to the optional argument. If none, set value for all locales.
% In cls: define command
MakeLocaleVar{Faculty}
% In main tex: set values
Faculty{This faculty} % for all values
Faculty[fi]{Tämä tiedekunta} % for a specific one
% In cls environments: use values
EmitFaculty[en]
EmitFaculty[fi]
% Now in addition I'd like to be able to:
MakeLocaleVar[en,fi,de]{Faculty}
I tried to modify the command to accept arbitrary locales, but something's not working.
newcommandMakeLocaleVar[2][en,fi]{%
foreach n in {#1}{%
global@namedef{#2:n}{%
{scriptsize (Use {tttextbackslash #2[n]} to replace this text.)}%
}%
}%
expandafternewcommandcsname #2endcsname[2][]{%
ifthenelse{equal{##1}{}}{%
foreach n in {#1}{%
global@namedef{#2:n}{##2}%
}%
}{%
global@namedef{#2:##1}{##2}%
}%
}%
expandafternewcommandcsname Emit#2endcsname[1][en]{@nameuse{#2:##1}}%
}
If I set values that are used, everything is fine and dandy. It is when values are not set that my custom environments break and the default message shown is just Use Cmd[] to...
, so without the locale names.
Any idea as to what is going on?
macros loops pgffor variable
New contributor
Looks like an expansion issue. The way@namedef{#2:n}
is defined, its replacement text containsn
. So when you callFaculty:fi
lets, say it gets replaced by... Use {tttextbackslash #2[n]} ...
withn
and not with the value ofn
at the timeFaculty:fi
was defined, i.e.fi
. One way to get around this would be by moving theglobal@namedef{#2:n}
to a helper function and expanding the argument of the helper function before it is called.
– moewe
14 hours ago
@moewe I don't quite get it. Why wouldn't then
be expanded in the very loop it is ment to be used in? It is expanded in the namedef. Does something prevent that in the text after?
– Felix
14 hours ago
The@namedef
carries out a full expansion of its (first) argument, but the replacement text (second argument of@namedef
) is not expanded. I'm working an alternative withetoolbox
right now, if you are interested.
– moewe
14 hours ago
@moewe That could be interesting. But can the effect be achieved usingexpandafter
?
– Felix
14 hours ago
Yes and quite straightforward with a helper function. If you want to avoid the helper its more tricky, but probably doable (and I wouldn't be the one to ask).
– moewe
13 hours ago
|
show 1 more comment
I'd like to construct a macro that can be used to define commands. Those commands behave like variables or structs of variables, such that they can contain multiple values. The "member" is passed via an optional argument. I use it to define template environments and to have different strings for different languages, which need to be present in the document simultaneously.
Here's what I had and works.
newcommandMakeLocaleVar[1]{%
global@namedef{#1:en}{{scriptsize (Use {tttextbackslash #1[en]} to replace this text.)}}%
global@namedef{#1:fi}{{scriptsize (Use {tttextbackslash #1[fi]} to replace this text.)}}%
expandafternewcommandcsname #1endcsname[2][]{%
ifthenelse{equal{##1}{}}{%
global@namedef{#1:en}{##2}%
global@namedef{#1:fi}{##2}%
}{%
global@namedef{#1:##1}{##2}%
}%
}%
expandafternewcommandcsname Emit#1endcsname[1][en]{@nameuse{#1:##1}}%
}
First the default values are set. Then a command is created that sets the values according to the optional argument. If none, set value for all locales.
% In cls: define command
MakeLocaleVar{Faculty}
% In main tex: set values
Faculty{This faculty} % for all values
Faculty[fi]{Tämä tiedekunta} % for a specific one
% In cls environments: use values
EmitFaculty[en]
EmitFaculty[fi]
% Now in addition I'd like to be able to:
MakeLocaleVar[en,fi,de]{Faculty}
I tried to modify the command to accept arbitrary locales, but something's not working.
newcommandMakeLocaleVar[2][en,fi]{%
foreach n in {#1}{%
global@namedef{#2:n}{%
{scriptsize (Use {tttextbackslash #2[n]} to replace this text.)}%
}%
}%
expandafternewcommandcsname #2endcsname[2][]{%
ifthenelse{equal{##1}{}}{%
foreach n in {#1}{%
global@namedef{#2:n}{##2}%
}%
}{%
global@namedef{#2:##1}{##2}%
}%
}%
expandafternewcommandcsname Emit#2endcsname[1][en]{@nameuse{#2:##1}}%
}
If I set values that are used, everything is fine and dandy. It is when values are not set that my custom environments break and the default message shown is just Use Cmd[] to...
, so without the locale names.
Any idea as to what is going on?
macros loops pgffor variable
New contributor
I'd like to construct a macro that can be used to define commands. Those commands behave like variables or structs of variables, such that they can contain multiple values. The "member" is passed via an optional argument. I use it to define template environments and to have different strings for different languages, which need to be present in the document simultaneously.
Here's what I had and works.
newcommandMakeLocaleVar[1]{%
global@namedef{#1:en}{{scriptsize (Use {tttextbackslash #1[en]} to replace this text.)}}%
global@namedef{#1:fi}{{scriptsize (Use {tttextbackslash #1[fi]} to replace this text.)}}%
expandafternewcommandcsname #1endcsname[2][]{%
ifthenelse{equal{##1}{}}{%
global@namedef{#1:en}{##2}%
global@namedef{#1:fi}{##2}%
}{%
global@namedef{#1:##1}{##2}%
}%
}%
expandafternewcommandcsname Emit#1endcsname[1][en]{@nameuse{#1:##1}}%
}
First the default values are set. Then a command is created that sets the values according to the optional argument. If none, set value for all locales.
% In cls: define command
MakeLocaleVar{Faculty}
% In main tex: set values
Faculty{This faculty} % for all values
Faculty[fi]{Tämä tiedekunta} % for a specific one
% In cls environments: use values
EmitFaculty[en]
EmitFaculty[fi]
% Now in addition I'd like to be able to:
MakeLocaleVar[en,fi,de]{Faculty}
I tried to modify the command to accept arbitrary locales, but something's not working.
newcommandMakeLocaleVar[2][en,fi]{%
foreach n in {#1}{%
global@namedef{#2:n}{%
{scriptsize (Use {tttextbackslash #2[n]} to replace this text.)}%
}%
}%
expandafternewcommandcsname #2endcsname[2][]{%
ifthenelse{equal{##1}{}}{%
foreach n in {#1}{%
global@namedef{#2:n}{##2}%
}%
}{%
global@namedef{#2:##1}{##2}%
}%
}%
expandafternewcommandcsname Emit#2endcsname[1][en]{@nameuse{#2:##1}}%
}
If I set values that are used, everything is fine and dandy. It is when values are not set that my custom environments break and the default message shown is just Use Cmd[] to...
, so without the locale names.
Any idea as to what is going on?
macros loops pgffor variable
macros loops pgffor variable
New contributor
New contributor
edited 14 hours ago
Felix
New contributor
asked 14 hours ago
FelixFelix
1265
1265
New contributor
New contributor
Looks like an expansion issue. The way@namedef{#2:n}
is defined, its replacement text containsn
. So when you callFaculty:fi
lets, say it gets replaced by... Use {tttextbackslash #2[n]} ...
withn
and not with the value ofn
at the timeFaculty:fi
was defined, i.e.fi
. One way to get around this would be by moving theglobal@namedef{#2:n}
to a helper function and expanding the argument of the helper function before it is called.
– moewe
14 hours ago
@moewe I don't quite get it. Why wouldn't then
be expanded in the very loop it is ment to be used in? It is expanded in the namedef. Does something prevent that in the text after?
– Felix
14 hours ago
The@namedef
carries out a full expansion of its (first) argument, but the replacement text (second argument of@namedef
) is not expanded. I'm working an alternative withetoolbox
right now, if you are interested.
– moewe
14 hours ago
@moewe That could be interesting. But can the effect be achieved usingexpandafter
?
– Felix
14 hours ago
Yes and quite straightforward with a helper function. If you want to avoid the helper its more tricky, but probably doable (and I wouldn't be the one to ask).
– moewe
13 hours ago
|
show 1 more comment
Looks like an expansion issue. The way@namedef{#2:n}
is defined, its replacement text containsn
. So when you callFaculty:fi
lets, say it gets replaced by... Use {tttextbackslash #2[n]} ...
withn
and not with the value ofn
at the timeFaculty:fi
was defined, i.e.fi
. One way to get around this would be by moving theglobal@namedef{#2:n}
to a helper function and expanding the argument of the helper function before it is called.
– moewe
14 hours ago
@moewe I don't quite get it. Why wouldn't then
be expanded in the very loop it is ment to be used in? It is expanded in the namedef. Does something prevent that in the text after?
– Felix
14 hours ago
The@namedef
carries out a full expansion of its (first) argument, but the replacement text (second argument of@namedef
) is not expanded. I'm working an alternative withetoolbox
right now, if you are interested.
– moewe
14 hours ago
@moewe That could be interesting. But can the effect be achieved usingexpandafter
?
– Felix
14 hours ago
Yes and quite straightforward with a helper function. If you want to avoid the helper its more tricky, but probably doable (and I wouldn't be the one to ask).
– moewe
13 hours ago
Looks like an expansion issue. The way
@namedef{#2:n}
is defined, its replacement text contains n
. So when you call Faculty:fi
lets, say it gets replaced by ... Use {tttextbackslash #2[n]} ...
with n
and not with the value of n
at the time Faculty:fi
was defined, i.e. fi
. One way to get around this would be by moving the global@namedef{#2:n}
to a helper function and expanding the argument of the helper function before it is called.– moewe
14 hours ago
Looks like an expansion issue. The way
@namedef{#2:n}
is defined, its replacement text contains n
. So when you call Faculty:fi
lets, say it gets replaced by ... Use {tttextbackslash #2[n]} ...
with n
and not with the value of n
at the time Faculty:fi
was defined, i.e. fi
. One way to get around this would be by moving the global@namedef{#2:n}
to a helper function and expanding the argument of the helper function before it is called.– moewe
14 hours ago
@moewe I don't quite get it. Why wouldn't the
n
be expanded in the very loop it is ment to be used in? It is expanded in the namedef. Does something prevent that in the text after?– Felix
14 hours ago
@moewe I don't quite get it. Why wouldn't the
n
be expanded in the very loop it is ment to be used in? It is expanded in the namedef. Does something prevent that in the text after?– Felix
14 hours ago
The
@namedef
carries out a full expansion of its (first) argument, but the replacement text (second argument of @namedef
) is not expanded. I'm working an alternative with etoolbox
right now, if you are interested.– moewe
14 hours ago
The
@namedef
carries out a full expansion of its (first) argument, but the replacement text (second argument of @namedef
) is not expanded. I'm working an alternative with etoolbox
right now, if you are interested.– moewe
14 hours ago
@moewe That could be interesting. But can the effect be achieved using
expandafter
?– Felix
14 hours ago
@moewe That could be interesting. But can the effect be achieved using
expandafter
?– Felix
14 hours ago
Yes and quite straightforward with a helper function. If you want to avoid the helper its more tricky, but probably doable (and I wouldn't be the one to ask).
– moewe
13 hours ago
Yes and quite straightforward with a helper function. If you want to avoid the helper its more tricky, but probably doable (and I wouldn't be the one to ask).
– moewe
13 hours ago
|
show 1 more comment
1 Answer
1
active
oldest
votes
As mentioned in the comment, your main issue was that the n
in the replacement text of the @namedef
was not expanded to its value. The replacement text for Faculty:fi
for example thus remained literally
{scriptsize (Use {tttextbackslash #2[n]} to replace this text.)}%
with n
. In most contexts where the macro would be called n
would be undefined and you would get an error. You want the macro replacement text to be constructed so that n
becomes its expansion, i.e. fi
. The easiest way to get that done properly is probably a helper macro. This answer will show two approaches: One with etoolbox
and its list macros and one with your code that uses expandafter
and a helper macro. etoolbox
's loop work by passing the value of the loop variable directly as an argument to a helper macro.
In the first argument of @namedef
(i.e. the #2:n
), the n
would be expanded automatically so that it would really become fi
there.
Here is a solution using etoolbox
and its list macros. Some explanations are inline. The advantage of this approach is that there is no need for expansion of the loop variable (n
) as the loop is directly implemented as a macro.
documentclass[english,finnish]{article}
usepackage[T1]{fontenc}
usepackage[utf8]{inputenc}
usepackage{babel}
usepackage{etoolbox}
makeatletter
% {<name>}{<lang>}
newcommand*{mlv@defaultvalue}[2]{%
csdef{#1@#2}{%
{scriptsize (Use {ttfamilytextbackslash #1[#2]} to replace this text.)}}}
% {<repl. text>}{<name>}{<lang>}
% the unusual order instead of the more natural {<name>}{<lang>}{<repl. text>}
% makes for a more elegant call to forcsvlist
newcommand*{mlv@realvalue}[3]{%
csdef{#2@#3}{#1}}
% [<langs>]{<name>}
% forcsvlist{<macro>}{<item_1, item_2, ..., item_n>}
% calls <macro> once with each item_i as argument
% <macro>{<item_1>}, <macro>{<item_2>}
% since the items are the <lang> argument it must be the last
% argument to mlv@defaultvalue and mlv@realvalue
newcommandMakeLocaleVar[2][en,fi]{%
forcsvlist{mlv@defaultvalue{#2}}{#1}%
expandafternewcommandcsname #2endcsname[2][]{%
ifblank{##1}
{forcsvlist{mlv@realvalue{##2}{#2}}{#1}}%
{mlv@realvalue{##2}{#2}{##1}}}%
expandafternewcommandcsname Emit#2endcsname[1][en]{csuse{#2@##1}}%
}
makeatother
begin{document}
MakeLocaleVar{Faculty}
% In main tex: set values
Faculty{This faculty} % for all values
Faculty[fi]{Tämä tiedekunta} % for a specific one
% In cls environments: use values
EmitFaculty[en]
EmitFaculty[fi]
% Now in addition I'd like to be able to:
MakeLocaleVar[en,fi,de]{Gaculty}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
Gaculty{Foo}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
Gaculty[fi]{Föö}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
end{document}
If you want to stick to your version with foreach
and ifthenelse
, you can make use of a helper function.
The trick is that we need to expand n
so that we get its actual value. This is possible with expandafter
, but to avoid having to use it with surgical precision to jump over many tokens, a helper function is useful.
documentclass[english,finnish]{article}
usepackage[T1]{fontenc}
usepackage[utf8]{inputenc}
usepackage{babel}
usepackage{ifthen}
usepackage{tikz}
makeatletter
% helper for easier control of expansion
% {<lang>}{<name>}
newcommand*{mlv@helper}[2]{%
global@namedef{#2:#1}{%
{scriptsize (Use {ttfamilytextbackslash #2[#1]} to replace this text.)}%
}%
}
% n must be expanded to be useful.
% The first argument of @namedef automatically expands it,
% but the second does not.
% Here we use a helper function to expand n
% before it is processed.
newcommandMakeLocaleVar[2][en,fi]{%
foreach n in {#1}{%
expandaftermlv@helperexpandafter{n}{#2}%
}%
expandafternewcommandcsname #2endcsname[2][]{%
ifthenelse{equal{##1}{}}{%
foreach n in {#1}{%
global@namedef{#2:n}{##2}%
}%
}{%
global@namedef{#2:##1}{##2}%
}%
}%
expandafternewcommandcsname Emit#2endcsname[1][en]{@nameuse{#2:##1}}%
}
makeatother
begin{document}
MakeLocaleVar{Faculty}
% In main tex: set values
Faculty{This faculty} % for all values
Faculty[fi]{Tämä tiedekunta} % for a specific one
% In cls environments: use values
EmitFaculty[en]
EmitFaculty[fi]
% Now in addition I'd like to be able to:
MakeLocaleVar[en,fi,de]{Gaculty}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
Gaculty{Foo}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
Gaculty[fi]{Föö}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
end{document}
add a comment |
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "85"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Felix is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f477656%2fgeneralising-a-second-order-macro-with-loops%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
As mentioned in the comment, your main issue was that the n
in the replacement text of the @namedef
was not expanded to its value. The replacement text for Faculty:fi
for example thus remained literally
{scriptsize (Use {tttextbackslash #2[n]} to replace this text.)}%
with n
. In most contexts where the macro would be called n
would be undefined and you would get an error. You want the macro replacement text to be constructed so that n
becomes its expansion, i.e. fi
. The easiest way to get that done properly is probably a helper macro. This answer will show two approaches: One with etoolbox
and its list macros and one with your code that uses expandafter
and a helper macro. etoolbox
's loop work by passing the value of the loop variable directly as an argument to a helper macro.
In the first argument of @namedef
(i.e. the #2:n
), the n
would be expanded automatically so that it would really become fi
there.
Here is a solution using etoolbox
and its list macros. Some explanations are inline. The advantage of this approach is that there is no need for expansion of the loop variable (n
) as the loop is directly implemented as a macro.
documentclass[english,finnish]{article}
usepackage[T1]{fontenc}
usepackage[utf8]{inputenc}
usepackage{babel}
usepackage{etoolbox}
makeatletter
% {<name>}{<lang>}
newcommand*{mlv@defaultvalue}[2]{%
csdef{#1@#2}{%
{scriptsize (Use {ttfamilytextbackslash #1[#2]} to replace this text.)}}}
% {<repl. text>}{<name>}{<lang>}
% the unusual order instead of the more natural {<name>}{<lang>}{<repl. text>}
% makes for a more elegant call to forcsvlist
newcommand*{mlv@realvalue}[3]{%
csdef{#2@#3}{#1}}
% [<langs>]{<name>}
% forcsvlist{<macro>}{<item_1, item_2, ..., item_n>}
% calls <macro> once with each item_i as argument
% <macro>{<item_1>}, <macro>{<item_2>}
% since the items are the <lang> argument it must be the last
% argument to mlv@defaultvalue and mlv@realvalue
newcommandMakeLocaleVar[2][en,fi]{%
forcsvlist{mlv@defaultvalue{#2}}{#1}%
expandafternewcommandcsname #2endcsname[2][]{%
ifblank{##1}
{forcsvlist{mlv@realvalue{##2}{#2}}{#1}}%
{mlv@realvalue{##2}{#2}{##1}}}%
expandafternewcommandcsname Emit#2endcsname[1][en]{csuse{#2@##1}}%
}
makeatother
begin{document}
MakeLocaleVar{Faculty}
% In main tex: set values
Faculty{This faculty} % for all values
Faculty[fi]{Tämä tiedekunta} % for a specific one
% In cls environments: use values
EmitFaculty[en]
EmitFaculty[fi]
% Now in addition I'd like to be able to:
MakeLocaleVar[en,fi,de]{Gaculty}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
Gaculty{Foo}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
Gaculty[fi]{Föö}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
end{document}
If you want to stick to your version with foreach
and ifthenelse
, you can make use of a helper function.
The trick is that we need to expand n
so that we get its actual value. This is possible with expandafter
, but to avoid having to use it with surgical precision to jump over many tokens, a helper function is useful.
documentclass[english,finnish]{article}
usepackage[T1]{fontenc}
usepackage[utf8]{inputenc}
usepackage{babel}
usepackage{ifthen}
usepackage{tikz}
makeatletter
% helper for easier control of expansion
% {<lang>}{<name>}
newcommand*{mlv@helper}[2]{%
global@namedef{#2:#1}{%
{scriptsize (Use {ttfamilytextbackslash #2[#1]} to replace this text.)}%
}%
}
% n must be expanded to be useful.
% The first argument of @namedef automatically expands it,
% but the second does not.
% Here we use a helper function to expand n
% before it is processed.
newcommandMakeLocaleVar[2][en,fi]{%
foreach n in {#1}{%
expandaftermlv@helperexpandafter{n}{#2}%
}%
expandafternewcommandcsname #2endcsname[2][]{%
ifthenelse{equal{##1}{}}{%
foreach n in {#1}{%
global@namedef{#2:n}{##2}%
}%
}{%
global@namedef{#2:##1}{##2}%
}%
}%
expandafternewcommandcsname Emit#2endcsname[1][en]{@nameuse{#2:##1}}%
}
makeatother
begin{document}
MakeLocaleVar{Faculty}
% In main tex: set values
Faculty{This faculty} % for all values
Faculty[fi]{Tämä tiedekunta} % for a specific one
% In cls environments: use values
EmitFaculty[en]
EmitFaculty[fi]
% Now in addition I'd like to be able to:
MakeLocaleVar[en,fi,de]{Gaculty}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
Gaculty{Foo}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
Gaculty[fi]{Föö}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
end{document}
add a comment |
As mentioned in the comment, your main issue was that the n
in the replacement text of the @namedef
was not expanded to its value. The replacement text for Faculty:fi
for example thus remained literally
{scriptsize (Use {tttextbackslash #2[n]} to replace this text.)}%
with n
. In most contexts where the macro would be called n
would be undefined and you would get an error. You want the macro replacement text to be constructed so that n
becomes its expansion, i.e. fi
. The easiest way to get that done properly is probably a helper macro. This answer will show two approaches: One with etoolbox
and its list macros and one with your code that uses expandafter
and a helper macro. etoolbox
's loop work by passing the value of the loop variable directly as an argument to a helper macro.
In the first argument of @namedef
(i.e. the #2:n
), the n
would be expanded automatically so that it would really become fi
there.
Here is a solution using etoolbox
and its list macros. Some explanations are inline. The advantage of this approach is that there is no need for expansion of the loop variable (n
) as the loop is directly implemented as a macro.
documentclass[english,finnish]{article}
usepackage[T1]{fontenc}
usepackage[utf8]{inputenc}
usepackage{babel}
usepackage{etoolbox}
makeatletter
% {<name>}{<lang>}
newcommand*{mlv@defaultvalue}[2]{%
csdef{#1@#2}{%
{scriptsize (Use {ttfamilytextbackslash #1[#2]} to replace this text.)}}}
% {<repl. text>}{<name>}{<lang>}
% the unusual order instead of the more natural {<name>}{<lang>}{<repl. text>}
% makes for a more elegant call to forcsvlist
newcommand*{mlv@realvalue}[3]{%
csdef{#2@#3}{#1}}
% [<langs>]{<name>}
% forcsvlist{<macro>}{<item_1, item_2, ..., item_n>}
% calls <macro> once with each item_i as argument
% <macro>{<item_1>}, <macro>{<item_2>}
% since the items are the <lang> argument it must be the last
% argument to mlv@defaultvalue and mlv@realvalue
newcommandMakeLocaleVar[2][en,fi]{%
forcsvlist{mlv@defaultvalue{#2}}{#1}%
expandafternewcommandcsname #2endcsname[2][]{%
ifblank{##1}
{forcsvlist{mlv@realvalue{##2}{#2}}{#1}}%
{mlv@realvalue{##2}{#2}{##1}}}%
expandafternewcommandcsname Emit#2endcsname[1][en]{csuse{#2@##1}}%
}
makeatother
begin{document}
MakeLocaleVar{Faculty}
% In main tex: set values
Faculty{This faculty} % for all values
Faculty[fi]{Tämä tiedekunta} % for a specific one
% In cls environments: use values
EmitFaculty[en]
EmitFaculty[fi]
% Now in addition I'd like to be able to:
MakeLocaleVar[en,fi,de]{Gaculty}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
Gaculty{Foo}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
Gaculty[fi]{Föö}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
end{document}
If you want to stick to your version with foreach
and ifthenelse
, you can make use of a helper function.
The trick is that we need to expand n
so that we get its actual value. This is possible with expandafter
, but to avoid having to use it with surgical precision to jump over many tokens, a helper function is useful.
documentclass[english,finnish]{article}
usepackage[T1]{fontenc}
usepackage[utf8]{inputenc}
usepackage{babel}
usepackage{ifthen}
usepackage{tikz}
makeatletter
% helper for easier control of expansion
% {<lang>}{<name>}
newcommand*{mlv@helper}[2]{%
global@namedef{#2:#1}{%
{scriptsize (Use {ttfamilytextbackslash #2[#1]} to replace this text.)}%
}%
}
% n must be expanded to be useful.
% The first argument of @namedef automatically expands it,
% but the second does not.
% Here we use a helper function to expand n
% before it is processed.
newcommandMakeLocaleVar[2][en,fi]{%
foreach n in {#1}{%
expandaftermlv@helperexpandafter{n}{#2}%
}%
expandafternewcommandcsname #2endcsname[2][]{%
ifthenelse{equal{##1}{}}{%
foreach n in {#1}{%
global@namedef{#2:n}{##2}%
}%
}{%
global@namedef{#2:##1}{##2}%
}%
}%
expandafternewcommandcsname Emit#2endcsname[1][en]{@nameuse{#2:##1}}%
}
makeatother
begin{document}
MakeLocaleVar{Faculty}
% In main tex: set values
Faculty{This faculty} % for all values
Faculty[fi]{Tämä tiedekunta} % for a specific one
% In cls environments: use values
EmitFaculty[en]
EmitFaculty[fi]
% Now in addition I'd like to be able to:
MakeLocaleVar[en,fi,de]{Gaculty}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
Gaculty{Foo}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
Gaculty[fi]{Föö}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
end{document}
add a comment |
As mentioned in the comment, your main issue was that the n
in the replacement text of the @namedef
was not expanded to its value. The replacement text for Faculty:fi
for example thus remained literally
{scriptsize (Use {tttextbackslash #2[n]} to replace this text.)}%
with n
. In most contexts where the macro would be called n
would be undefined and you would get an error. You want the macro replacement text to be constructed so that n
becomes its expansion, i.e. fi
. The easiest way to get that done properly is probably a helper macro. This answer will show two approaches: One with etoolbox
and its list macros and one with your code that uses expandafter
and a helper macro. etoolbox
's loop work by passing the value of the loop variable directly as an argument to a helper macro.
In the first argument of @namedef
(i.e. the #2:n
), the n
would be expanded automatically so that it would really become fi
there.
Here is a solution using etoolbox
and its list macros. Some explanations are inline. The advantage of this approach is that there is no need for expansion of the loop variable (n
) as the loop is directly implemented as a macro.
documentclass[english,finnish]{article}
usepackage[T1]{fontenc}
usepackage[utf8]{inputenc}
usepackage{babel}
usepackage{etoolbox}
makeatletter
% {<name>}{<lang>}
newcommand*{mlv@defaultvalue}[2]{%
csdef{#1@#2}{%
{scriptsize (Use {ttfamilytextbackslash #1[#2]} to replace this text.)}}}
% {<repl. text>}{<name>}{<lang>}
% the unusual order instead of the more natural {<name>}{<lang>}{<repl. text>}
% makes for a more elegant call to forcsvlist
newcommand*{mlv@realvalue}[3]{%
csdef{#2@#3}{#1}}
% [<langs>]{<name>}
% forcsvlist{<macro>}{<item_1, item_2, ..., item_n>}
% calls <macro> once with each item_i as argument
% <macro>{<item_1>}, <macro>{<item_2>}
% since the items are the <lang> argument it must be the last
% argument to mlv@defaultvalue and mlv@realvalue
newcommandMakeLocaleVar[2][en,fi]{%
forcsvlist{mlv@defaultvalue{#2}}{#1}%
expandafternewcommandcsname #2endcsname[2][]{%
ifblank{##1}
{forcsvlist{mlv@realvalue{##2}{#2}}{#1}}%
{mlv@realvalue{##2}{#2}{##1}}}%
expandafternewcommandcsname Emit#2endcsname[1][en]{csuse{#2@##1}}%
}
makeatother
begin{document}
MakeLocaleVar{Faculty}
% In main tex: set values
Faculty{This faculty} % for all values
Faculty[fi]{Tämä tiedekunta} % for a specific one
% In cls environments: use values
EmitFaculty[en]
EmitFaculty[fi]
% Now in addition I'd like to be able to:
MakeLocaleVar[en,fi,de]{Gaculty}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
Gaculty{Foo}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
Gaculty[fi]{Föö}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
end{document}
If you want to stick to your version with foreach
and ifthenelse
, you can make use of a helper function.
The trick is that we need to expand n
so that we get its actual value. This is possible with expandafter
, but to avoid having to use it with surgical precision to jump over many tokens, a helper function is useful.
documentclass[english,finnish]{article}
usepackage[T1]{fontenc}
usepackage[utf8]{inputenc}
usepackage{babel}
usepackage{ifthen}
usepackage{tikz}
makeatletter
% helper for easier control of expansion
% {<lang>}{<name>}
newcommand*{mlv@helper}[2]{%
global@namedef{#2:#1}{%
{scriptsize (Use {ttfamilytextbackslash #2[#1]} to replace this text.)}%
}%
}
% n must be expanded to be useful.
% The first argument of @namedef automatically expands it,
% but the second does not.
% Here we use a helper function to expand n
% before it is processed.
newcommandMakeLocaleVar[2][en,fi]{%
foreach n in {#1}{%
expandaftermlv@helperexpandafter{n}{#2}%
}%
expandafternewcommandcsname #2endcsname[2][]{%
ifthenelse{equal{##1}{}}{%
foreach n in {#1}{%
global@namedef{#2:n}{##2}%
}%
}{%
global@namedef{#2:##1}{##2}%
}%
}%
expandafternewcommandcsname Emit#2endcsname[1][en]{@nameuse{#2:##1}}%
}
makeatother
begin{document}
MakeLocaleVar{Faculty}
% In main tex: set values
Faculty{This faculty} % for all values
Faculty[fi]{Tämä tiedekunta} % for a specific one
% In cls environments: use values
EmitFaculty[en]
EmitFaculty[fi]
% Now in addition I'd like to be able to:
MakeLocaleVar[en,fi,de]{Gaculty}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
Gaculty{Foo}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
Gaculty[fi]{Föö}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
end{document}
As mentioned in the comment, your main issue was that the n
in the replacement text of the @namedef
was not expanded to its value. The replacement text for Faculty:fi
for example thus remained literally
{scriptsize (Use {tttextbackslash #2[n]} to replace this text.)}%
with n
. In most contexts where the macro would be called n
would be undefined and you would get an error. You want the macro replacement text to be constructed so that n
becomes its expansion, i.e. fi
. The easiest way to get that done properly is probably a helper macro. This answer will show two approaches: One with etoolbox
and its list macros and one with your code that uses expandafter
and a helper macro. etoolbox
's loop work by passing the value of the loop variable directly as an argument to a helper macro.
In the first argument of @namedef
(i.e. the #2:n
), the n
would be expanded automatically so that it would really become fi
there.
Here is a solution using etoolbox
and its list macros. Some explanations are inline. The advantage of this approach is that there is no need for expansion of the loop variable (n
) as the loop is directly implemented as a macro.
documentclass[english,finnish]{article}
usepackage[T1]{fontenc}
usepackage[utf8]{inputenc}
usepackage{babel}
usepackage{etoolbox}
makeatletter
% {<name>}{<lang>}
newcommand*{mlv@defaultvalue}[2]{%
csdef{#1@#2}{%
{scriptsize (Use {ttfamilytextbackslash #1[#2]} to replace this text.)}}}
% {<repl. text>}{<name>}{<lang>}
% the unusual order instead of the more natural {<name>}{<lang>}{<repl. text>}
% makes for a more elegant call to forcsvlist
newcommand*{mlv@realvalue}[3]{%
csdef{#2@#3}{#1}}
% [<langs>]{<name>}
% forcsvlist{<macro>}{<item_1, item_2, ..., item_n>}
% calls <macro> once with each item_i as argument
% <macro>{<item_1>}, <macro>{<item_2>}
% since the items are the <lang> argument it must be the last
% argument to mlv@defaultvalue and mlv@realvalue
newcommandMakeLocaleVar[2][en,fi]{%
forcsvlist{mlv@defaultvalue{#2}}{#1}%
expandafternewcommandcsname #2endcsname[2][]{%
ifblank{##1}
{forcsvlist{mlv@realvalue{##2}{#2}}{#1}}%
{mlv@realvalue{##2}{#2}{##1}}}%
expandafternewcommandcsname Emit#2endcsname[1][en]{csuse{#2@##1}}%
}
makeatother
begin{document}
MakeLocaleVar{Faculty}
% In main tex: set values
Faculty{This faculty} % for all values
Faculty[fi]{Tämä tiedekunta} % for a specific one
% In cls environments: use values
EmitFaculty[en]
EmitFaculty[fi]
% Now in addition I'd like to be able to:
MakeLocaleVar[en,fi,de]{Gaculty}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
Gaculty{Foo}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
Gaculty[fi]{Föö}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
end{document}
If you want to stick to your version with foreach
and ifthenelse
, you can make use of a helper function.
The trick is that we need to expand n
so that we get its actual value. This is possible with expandafter
, but to avoid having to use it with surgical precision to jump over many tokens, a helper function is useful.
documentclass[english,finnish]{article}
usepackage[T1]{fontenc}
usepackage[utf8]{inputenc}
usepackage{babel}
usepackage{ifthen}
usepackage{tikz}
makeatletter
% helper for easier control of expansion
% {<lang>}{<name>}
newcommand*{mlv@helper}[2]{%
global@namedef{#2:#1}{%
{scriptsize (Use {ttfamilytextbackslash #2[#1]} to replace this text.)}%
}%
}
% n must be expanded to be useful.
% The first argument of @namedef automatically expands it,
% but the second does not.
% Here we use a helper function to expand n
% before it is processed.
newcommandMakeLocaleVar[2][en,fi]{%
foreach n in {#1}{%
expandaftermlv@helperexpandafter{n}{#2}%
}%
expandafternewcommandcsname #2endcsname[2][]{%
ifthenelse{equal{##1}{}}{%
foreach n in {#1}{%
global@namedef{#2:n}{##2}%
}%
}{%
global@namedef{#2:##1}{##2}%
}%
}%
expandafternewcommandcsname Emit#2endcsname[1][en]{@nameuse{#2:##1}}%
}
makeatother
begin{document}
MakeLocaleVar{Faculty}
% In main tex: set values
Faculty{This faculty} % for all values
Faculty[fi]{Tämä tiedekunta} % for a specific one
% In cls environments: use values
EmitFaculty[en]
EmitFaculty[fi]
% Now in addition I'd like to be able to:
MakeLocaleVar[en,fi,de]{Gaculty}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
Gaculty{Foo}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
Gaculty[fi]{Föö}
EmitGaculty[en]
EmitGaculty[fi]
EmitGaculty[de]
end{document}
edited 13 hours ago
answered 13 hours ago
moewemoewe
92.6k10115351
92.6k10115351
add a comment |
add a comment |
Felix is a new contributor. Be nice, and check out our Code of Conduct.
Felix is a new contributor. Be nice, and check out our Code of Conduct.
Felix is a new contributor. Be nice, and check out our Code of Conduct.
Felix is a new contributor. Be nice, and check out our Code of Conduct.
Thanks for contributing an answer to TeX - LaTeX Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f477656%2fgeneralising-a-second-order-macro-with-loops%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Looks like an expansion issue. The way
@namedef{#2:n}
is defined, its replacement text containsn
. So when you callFaculty:fi
lets, say it gets replaced by... Use {tttextbackslash #2[n]} ...
withn
and not with the value ofn
at the timeFaculty:fi
was defined, i.e.fi
. One way to get around this would be by moving theglobal@namedef{#2:n}
to a helper function and expanding the argument of the helper function before it is called.– moewe
14 hours ago
@moewe I don't quite get it. Why wouldn't the
n
be expanded in the very loop it is ment to be used in? It is expanded in the namedef. Does something prevent that in the text after?– Felix
14 hours ago
The
@namedef
carries out a full expansion of its (first) argument, but the replacement text (second argument of@namedef
) is not expanded. I'm working an alternative withetoolbox
right now, if you are interested.– moewe
14 hours ago
@moewe That could be interesting. But can the effect be achieved using
expandafter
?– Felix
14 hours ago
Yes and quite straightforward with a helper function. If you want to avoid the helper its more tricky, but probably doable (and I wouldn't be the one to ask).
– moewe
13 hours ago