Expansion of macro in environment argumentExpansion of command for language in otherlanguage...

Is there a low-level alternative to Animate Objects?

What are these green text/line displays shown during the livestream of Crew Dragon's approach to dock with the ISS?

Understanding Kramnik's play in game 1 of Candidates 2018

If nine coins are tossed, what is the probability that the number of heads is even?

How to properly claim credit for peer review?

I encountered my boss during an on-site interview at another company. Should I bring it up when seeing him next time?

GeometricMean definition

How to avoid being sexist when trying to employ someone to function in a very sexist environment?

It took me a lot of time to make this, pls like. (YouTube Comments #1)

Can you use a beast's innate abilities while polymorphed?

What is a term for a function that when called repeatedly, has the same effect as calling once?

How can I be pwned if I'm not registered on that site?

How can atoms be electrically neutral when there is a difference in the positions of the charges?

Can you 'upgrade' leather armor to studded leather armor without purchasing the new armor directly?

What is the difference between ashamed and shamed?

If a druid in Wild Shape swallows a creature whole, then turns back to her normal form, what happens?

Skis versus snow shoes - when to choose which for travelling the backcountry?

When should a commit not be version tagged?

Multiplication via squaring and addition

Significance and timing of "mux scans"

What's the difference between a cart and a wagon?

Is there a frame of reference in which I was born before I was conceived?

Did 5.25" floppies undergo a change in magnetic coating?

How would we write a misogynistic character without offending people?



Expansion of macro in environment argument


Expansion of command for language in otherlanguage environmentString variable with multiple valuesGeneralising a second-order macro with loopsStrange expansion of a macro inside an environmentEnvironment with delayed expansionPreventing argument expansionCompiler Error when Creating a Macro/EnvironmentAbstract page of babel[magyar] undefinedTricky expansion in macroifnum and expansion of macro argumentForce macro expansionA way to “execute” only latex procedural code (def, let) in a sequence ignoring the rest?Macro Substitution/Expansion in Environment Names













0















I'd like to generate an environment that changes a bit according to an argument given for it. The reason is having different locales in the document. I have defined a command, EmitLanguageStr that determines the argument to otherlanguage according to the argument that was passed. For example, EmitLanguageStr[en] -> english. See these questions for further context: [ 1, 2 ]. Here's the environment stripped down.



renewenvironment{abstract}[1][en]{%
section*{EmitAbstractStr[#1]}
begin{otherlanguage}{EmitLanguageStr[#1]}
@authorpar
textbf{EmitTitle[#1]}par
}{%
end{otherlanguage}
}


Turns out other people have had the same problem (Q), but the solution did not quite work for me. The answer suggests that wrapping the environment in one of two ways would allow the argument to be expanded:



% Create a macro
newcommandtestlang{english}

% Expand the argument once:
newenvironment{Otherlanguage}[1]{%
expandafterotherlanguageexpandafter{#1}%
}{endotherlanguage}

% Alternative: argument is fully expanded
newenvironment{Otherlanguage}[1]{%
begingroup
edeftemp{endgroupnoexpandotherlanguage{#1}}%
temp
}{endotherlanguage}

% usage
begin{Otherlanguage}{testlang}
...
end{Otherlangauge}


First, without these wrappers, babel gives an error message that the language EmitLanguageStr[en] is not defined. That was addressed in the linked question. However, the solutions presented produce another kind of error: Use of EmitLanguageStr doesn't match its definition.



How can the command be properly expanded?





Here's a complete example of the situation. This works, but by switching the argument of Otherlanguage to the one in the comment the described error is thrown.



documentclass[a4paper,12pt]{article}

usepackage{ifthen}
usepackage{pgffor}

makeatletter

newcommandSetDefaultValue[2]{%
global@namedef{#2:#1}{%
{scriptsize (Use {tttextbackslash #2[#1]} to replace this text.)}%
}%
}

newcommandMakeLocaleVar[2][en,fi]{%
foreach n in {#1}{%
expandafterSetDefaultValueexpandafter{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}}%
}

% Variables set in document
MakeLocaleVar{Title}
MakeLocaleVar{Year}

%newenvironment{Otherlanguage}[1]{%
% expandafterotherlanguageexpandafter{#1}%
%}{endotherlanguage}

newenvironment{Otherlanguage}[1]{%
begingroup
edeftemp{endgroupnoexpandotherlanguage{#1}}%
temp
}{endotherlanguage}

MakeLocaleVar{AbstractStr}
AbstractStr[en]{ABSTRACT}
AbstractStr[fi]{TIIVISTELMÄ}

MakeLocaleVar{LanguageStr}
LanguageStr[en]{english}
LanguageStr[fi]{finnish}

renewenvironment{abstract}[1][en]{%
section*{EmitAbstractStr[#1]}
begin{Otherlanguage}{english}%EmitLanguageStr[#1]
@authorpar
textbf{EmitTitle[#1]}par
EmitYearpar
par
}{%
end{Otherlanguage}
}

makeatother

usepackage[utf8]{inputenc}
usepackage[T1]{fontenc}
usepackage[finnish, english]{babel}

author{Handsome Devil}
Year{2019}

Title[en]{Title in English}
Title[fi]{Otsikko suomeksi}

begin{document}
selectlanguage{english}

begin{abstract}
Abstract environment in English.
end{abstract}

begin{abstract}[fi]
Abstract environment in Finnish.
end{abstract}
end{document}









share|improve this question









New contributor




Felix is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
















  • 2





    As always on this site please provide a full minimal example instead of sniplets. That makes it a lot easier for others to test your code and provide suggestions

    – daleif
    14 hours ago











  • Seems EmitLanguageStr processes an optional argument. LaTeX-macros that process optional arguments usually are not fully expandable. This means EmitLanguageStr won't expand to tokens only that form the name of a language but it also delivers assignment-tokens like @ifnextchar/futurelet which are used for "looking ahead" at the next token for finding out whether that is a left-bracket. Such assignment-tokens won't vanish during expansion. Besides this for debugging a compilable example is needed which lets you reproduce the erroneous/problematic behavior exactly.

    – Ulrich Diez
    14 hours ago













  • @UlrichDiez Oh, that's good to know. Minimal example added.

    – Felix
    14 hours ago
















0















I'd like to generate an environment that changes a bit according to an argument given for it. The reason is having different locales in the document. I have defined a command, EmitLanguageStr that determines the argument to otherlanguage according to the argument that was passed. For example, EmitLanguageStr[en] -> english. See these questions for further context: [ 1, 2 ]. Here's the environment stripped down.



renewenvironment{abstract}[1][en]{%
section*{EmitAbstractStr[#1]}
begin{otherlanguage}{EmitLanguageStr[#1]}
@authorpar
textbf{EmitTitle[#1]}par
}{%
end{otherlanguage}
}


Turns out other people have had the same problem (Q), but the solution did not quite work for me. The answer suggests that wrapping the environment in one of two ways would allow the argument to be expanded:



% Create a macro
newcommandtestlang{english}

% Expand the argument once:
newenvironment{Otherlanguage}[1]{%
expandafterotherlanguageexpandafter{#1}%
}{endotherlanguage}

% Alternative: argument is fully expanded
newenvironment{Otherlanguage}[1]{%
begingroup
edeftemp{endgroupnoexpandotherlanguage{#1}}%
temp
}{endotherlanguage}

% usage
begin{Otherlanguage}{testlang}
...
end{Otherlangauge}


First, without these wrappers, babel gives an error message that the language EmitLanguageStr[en] is not defined. That was addressed in the linked question. However, the solutions presented produce another kind of error: Use of EmitLanguageStr doesn't match its definition.



How can the command be properly expanded?





Here's a complete example of the situation. This works, but by switching the argument of Otherlanguage to the one in the comment the described error is thrown.



documentclass[a4paper,12pt]{article}

usepackage{ifthen}
usepackage{pgffor}

makeatletter

newcommandSetDefaultValue[2]{%
global@namedef{#2:#1}{%
{scriptsize (Use {tttextbackslash #2[#1]} to replace this text.)}%
}%
}

newcommandMakeLocaleVar[2][en,fi]{%
foreach n in {#1}{%
expandafterSetDefaultValueexpandafter{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}}%
}

% Variables set in document
MakeLocaleVar{Title}
MakeLocaleVar{Year}

%newenvironment{Otherlanguage}[1]{%
% expandafterotherlanguageexpandafter{#1}%
%}{endotherlanguage}

newenvironment{Otherlanguage}[1]{%
begingroup
edeftemp{endgroupnoexpandotherlanguage{#1}}%
temp
}{endotherlanguage}

MakeLocaleVar{AbstractStr}
AbstractStr[en]{ABSTRACT}
AbstractStr[fi]{TIIVISTELMÄ}

MakeLocaleVar{LanguageStr}
LanguageStr[en]{english}
LanguageStr[fi]{finnish}

renewenvironment{abstract}[1][en]{%
section*{EmitAbstractStr[#1]}
begin{Otherlanguage}{english}%EmitLanguageStr[#1]
@authorpar
textbf{EmitTitle[#1]}par
EmitYearpar
par
}{%
end{Otherlanguage}
}

makeatother

usepackage[utf8]{inputenc}
usepackage[T1]{fontenc}
usepackage[finnish, english]{babel}

author{Handsome Devil}
Year{2019}

Title[en]{Title in English}
Title[fi]{Otsikko suomeksi}

begin{document}
selectlanguage{english}

begin{abstract}
Abstract environment in English.
end{abstract}

begin{abstract}[fi]
Abstract environment in Finnish.
end{abstract}
end{document}









share|improve this question









New contributor




Felix is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
















  • 2





    As always on this site please provide a full minimal example instead of sniplets. That makes it a lot easier for others to test your code and provide suggestions

    – daleif
    14 hours ago











  • Seems EmitLanguageStr processes an optional argument. LaTeX-macros that process optional arguments usually are not fully expandable. This means EmitLanguageStr won't expand to tokens only that form the name of a language but it also delivers assignment-tokens like @ifnextchar/futurelet which are used for "looking ahead" at the next token for finding out whether that is a left-bracket. Such assignment-tokens won't vanish during expansion. Besides this for debugging a compilable example is needed which lets you reproduce the erroneous/problematic behavior exactly.

    – Ulrich Diez
    14 hours ago













  • @UlrichDiez Oh, that's good to know. Minimal example added.

    – Felix
    14 hours ago














0












0








0








I'd like to generate an environment that changes a bit according to an argument given for it. The reason is having different locales in the document. I have defined a command, EmitLanguageStr that determines the argument to otherlanguage according to the argument that was passed. For example, EmitLanguageStr[en] -> english. See these questions for further context: [ 1, 2 ]. Here's the environment stripped down.



renewenvironment{abstract}[1][en]{%
section*{EmitAbstractStr[#1]}
begin{otherlanguage}{EmitLanguageStr[#1]}
@authorpar
textbf{EmitTitle[#1]}par
}{%
end{otherlanguage}
}


Turns out other people have had the same problem (Q), but the solution did not quite work for me. The answer suggests that wrapping the environment in one of two ways would allow the argument to be expanded:



% Create a macro
newcommandtestlang{english}

% Expand the argument once:
newenvironment{Otherlanguage}[1]{%
expandafterotherlanguageexpandafter{#1}%
}{endotherlanguage}

% Alternative: argument is fully expanded
newenvironment{Otherlanguage}[1]{%
begingroup
edeftemp{endgroupnoexpandotherlanguage{#1}}%
temp
}{endotherlanguage}

% usage
begin{Otherlanguage}{testlang}
...
end{Otherlangauge}


First, without these wrappers, babel gives an error message that the language EmitLanguageStr[en] is not defined. That was addressed in the linked question. However, the solutions presented produce another kind of error: Use of EmitLanguageStr doesn't match its definition.



How can the command be properly expanded?





Here's a complete example of the situation. This works, but by switching the argument of Otherlanguage to the one in the comment the described error is thrown.



documentclass[a4paper,12pt]{article}

usepackage{ifthen}
usepackage{pgffor}

makeatletter

newcommandSetDefaultValue[2]{%
global@namedef{#2:#1}{%
{scriptsize (Use {tttextbackslash #2[#1]} to replace this text.)}%
}%
}

newcommandMakeLocaleVar[2][en,fi]{%
foreach n in {#1}{%
expandafterSetDefaultValueexpandafter{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}}%
}

% Variables set in document
MakeLocaleVar{Title}
MakeLocaleVar{Year}

%newenvironment{Otherlanguage}[1]{%
% expandafterotherlanguageexpandafter{#1}%
%}{endotherlanguage}

newenvironment{Otherlanguage}[1]{%
begingroup
edeftemp{endgroupnoexpandotherlanguage{#1}}%
temp
}{endotherlanguage}

MakeLocaleVar{AbstractStr}
AbstractStr[en]{ABSTRACT}
AbstractStr[fi]{TIIVISTELMÄ}

MakeLocaleVar{LanguageStr}
LanguageStr[en]{english}
LanguageStr[fi]{finnish}

renewenvironment{abstract}[1][en]{%
section*{EmitAbstractStr[#1]}
begin{Otherlanguage}{english}%EmitLanguageStr[#1]
@authorpar
textbf{EmitTitle[#1]}par
EmitYearpar
par
}{%
end{Otherlanguage}
}

makeatother

usepackage[utf8]{inputenc}
usepackage[T1]{fontenc}
usepackage[finnish, english]{babel}

author{Handsome Devil}
Year{2019}

Title[en]{Title in English}
Title[fi]{Otsikko suomeksi}

begin{document}
selectlanguage{english}

begin{abstract}
Abstract environment in English.
end{abstract}

begin{abstract}[fi]
Abstract environment in Finnish.
end{abstract}
end{document}









share|improve this question









New contributor




Felix is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.












I'd like to generate an environment that changes a bit according to an argument given for it. The reason is having different locales in the document. I have defined a command, EmitLanguageStr that determines the argument to otherlanguage according to the argument that was passed. For example, EmitLanguageStr[en] -> english. See these questions for further context: [ 1, 2 ]. Here's the environment stripped down.



renewenvironment{abstract}[1][en]{%
section*{EmitAbstractStr[#1]}
begin{otherlanguage}{EmitLanguageStr[#1]}
@authorpar
textbf{EmitTitle[#1]}par
}{%
end{otherlanguage}
}


Turns out other people have had the same problem (Q), but the solution did not quite work for me. The answer suggests that wrapping the environment in one of two ways would allow the argument to be expanded:



% Create a macro
newcommandtestlang{english}

% Expand the argument once:
newenvironment{Otherlanguage}[1]{%
expandafterotherlanguageexpandafter{#1}%
}{endotherlanguage}

% Alternative: argument is fully expanded
newenvironment{Otherlanguage}[1]{%
begingroup
edeftemp{endgroupnoexpandotherlanguage{#1}}%
temp
}{endotherlanguage}

% usage
begin{Otherlanguage}{testlang}
...
end{Otherlangauge}


First, without these wrappers, babel gives an error message that the language EmitLanguageStr[en] is not defined. That was addressed in the linked question. However, the solutions presented produce another kind of error: Use of EmitLanguageStr doesn't match its definition.



How can the command be properly expanded?





Here's a complete example of the situation. This works, but by switching the argument of Otherlanguage to the one in the comment the described error is thrown.



documentclass[a4paper,12pt]{article}

usepackage{ifthen}
usepackage{pgffor}

makeatletter

newcommandSetDefaultValue[2]{%
global@namedef{#2:#1}{%
{scriptsize (Use {tttextbackslash #2[#1]} to replace this text.)}%
}%
}

newcommandMakeLocaleVar[2][en,fi]{%
foreach n in {#1}{%
expandafterSetDefaultValueexpandafter{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}}%
}

% Variables set in document
MakeLocaleVar{Title}
MakeLocaleVar{Year}

%newenvironment{Otherlanguage}[1]{%
% expandafterotherlanguageexpandafter{#1}%
%}{endotherlanguage}

newenvironment{Otherlanguage}[1]{%
begingroup
edeftemp{endgroupnoexpandotherlanguage{#1}}%
temp
}{endotherlanguage}

MakeLocaleVar{AbstractStr}
AbstractStr[en]{ABSTRACT}
AbstractStr[fi]{TIIVISTELMÄ}

MakeLocaleVar{LanguageStr}
LanguageStr[en]{english}
LanguageStr[fi]{finnish}

renewenvironment{abstract}[1][en]{%
section*{EmitAbstractStr[#1]}
begin{Otherlanguage}{english}%EmitLanguageStr[#1]
@authorpar
textbf{EmitTitle[#1]}par
EmitYearpar
par
}{%
end{Otherlanguage}
}

makeatother

usepackage[utf8]{inputenc}
usepackage[T1]{fontenc}
usepackage[finnish, english]{babel}

author{Handsome Devil}
Year{2019}

Title[en]{Title in English}
Title[fi]{Otsikko suomeksi}

begin{document}
selectlanguage{english}

begin{abstract}
Abstract environment in English.
end{abstract}

begin{abstract}[fi]
Abstract environment in Finnish.
end{abstract}
end{document}






macros environments expansion






share|improve this question









New contributor




Felix is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question









New contributor




Felix is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question








edited 14 hours ago







Felix













New contributor




Felix is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked 15 hours ago









FelixFelix

1265




1265




New contributor




Felix is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





Felix is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






Felix is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.








  • 2





    As always on this site please provide a full minimal example instead of sniplets. That makes it a lot easier for others to test your code and provide suggestions

    – daleif
    14 hours ago











  • Seems EmitLanguageStr processes an optional argument. LaTeX-macros that process optional arguments usually are not fully expandable. This means EmitLanguageStr won't expand to tokens only that form the name of a language but it also delivers assignment-tokens like @ifnextchar/futurelet which are used for "looking ahead" at the next token for finding out whether that is a left-bracket. Such assignment-tokens won't vanish during expansion. Besides this for debugging a compilable example is needed which lets you reproduce the erroneous/problematic behavior exactly.

    – Ulrich Diez
    14 hours ago













  • @UlrichDiez Oh, that's good to know. Minimal example added.

    – Felix
    14 hours ago














  • 2





    As always on this site please provide a full minimal example instead of sniplets. That makes it a lot easier for others to test your code and provide suggestions

    – daleif
    14 hours ago











  • Seems EmitLanguageStr processes an optional argument. LaTeX-macros that process optional arguments usually are not fully expandable. This means EmitLanguageStr won't expand to tokens only that form the name of a language but it also delivers assignment-tokens like @ifnextchar/futurelet which are used for "looking ahead" at the next token for finding out whether that is a left-bracket. Such assignment-tokens won't vanish during expansion. Besides this for debugging a compilable example is needed which lets you reproduce the erroneous/problematic behavior exactly.

    – Ulrich Diez
    14 hours ago













  • @UlrichDiez Oh, that's good to know. Minimal example added.

    – Felix
    14 hours ago








2




2





As always on this site please provide a full minimal example instead of sniplets. That makes it a lot easier for others to test your code and provide suggestions

– daleif
14 hours ago





As always on this site please provide a full minimal example instead of sniplets. That makes it a lot easier for others to test your code and provide suggestions

– daleif
14 hours ago













Seems EmitLanguageStr processes an optional argument. LaTeX-macros that process optional arguments usually are not fully expandable. This means EmitLanguageStr won't expand to tokens only that form the name of a language but it also delivers assignment-tokens like @ifnextchar/futurelet which are used for "looking ahead" at the next token for finding out whether that is a left-bracket. Such assignment-tokens won't vanish during expansion. Besides this for debugging a compilable example is needed which lets you reproduce the erroneous/problematic behavior exactly.

– Ulrich Diez
14 hours ago







Seems EmitLanguageStr processes an optional argument. LaTeX-macros that process optional arguments usually are not fully expandable. This means EmitLanguageStr won't expand to tokens only that form the name of a language but it also delivers assignment-tokens like @ifnextchar/futurelet which are used for "looking ahead" at the next token for finding out whether that is a left-bracket. Such assignment-tokens won't vanish during expansion. Besides this for debugging a compilable example is needed which lets you reproduce the erroneous/problematic behavior exactly.

– Ulrich Diez
14 hours ago















@UlrichDiez Oh, that's good to know. Minimal example added.

– Felix
14 hours ago





@UlrichDiez Oh, that's good to know. Minimal example added.

– Felix
14 hours ago










1 Answer
1






active

oldest

votes


















0














MakeLocaleVar{LanguageStr} causes EmitLanguageStr to be defined as:



newcommandEmitLanguageStr[1][en]{@nameuse{LanguageStr:#1}}%


EmitLanguageStr processes an optional argument.



If you look at EmitLanguageStr via showEmitLanguageStr, you'll find:



> EmitLanguageStr=macro:
->@protected@testopt EmitLanguageStr \EmitLanguageStr {en}.


Looking at @protected@testopt yields:



> @protected@testopt=macro:
#1->ifx protect @typeset@protect expandafter @testopt else @x@protect #1
fi .


Looking at @testopt yields:



> @testopt=long macro:
#1#2->kernel@ifnextchar [{#1}{#1[{#2}]}.


Looking at kernel@ifnextchar yields:



> kernel@ifnextchar=long macro:
#1#2#3->let reserved@d =#1def reserved@a {#2}def reserved@b {#3}futurele
t @let@token @ifnch .


Looking at @ifnch yields:



> @ifnch=macro:
->ifx @let@token @sptoken let reserved@c @xifnch else ifx @let@token
reserved@d let reserved@c reserved@a else let reserved@c reserved@b fi
fi reserved@c .


Looking at @xifnch yields:



> @xifnch=macro:
->futurelet @let@token @ifnch .


As you can see a lot of playing around with non-expandable let- and futurelet-assignments is involved into the checking for the presence of the optional argument via kernel@ifnextchar [.



Therefore EmitLanguageStr does not only deliver those character tokens that form the name of the language. It also yields a lot of unexpandable assignment-tokens like let and futurelet for checking for the presence of the optional argument.

These tokens won't vanish within a pure-expansion-context while obtaining the name of the language for passing it as argument to an environment would be a pure expansion context.
After expansion these unexpandable assignment-tokens remain in the token-stream because while expansion takes place in (La)TeX's "gullet",
the carrying out of assignments takes place in (La)TeX's "stomach".



So in short:



As long as EmitLanguageStr processes an optional argument whereby the techniques for detecting the presence of an optional argument themselves involve non-expandable assignment-tokens which don't vanish during expansion, you can't use EmitLanguageStr in pure-expansion-contexts for obtaining only those tokens that form the name of the language.



But you can, e.g., create a variant of EmitLanguageStr with an additional argument holding tokens to which the emitted string is to be passed as argument. I call that macro PassLanguageStrTo:



documentclass[a4paper,12pt]{article}

usepackage{ifthen}
usepackage{pgffor}

makeatletter

newcommandSetDefaultValue[2]{%
global@namedef{#2:#1}{%
{scriptsize (Use {tttextbackslash #2[#1]} to replace this text.)}%
}%
}

newcommandPassFirstToSecond[2]{#2{#1}}%

newcommandMakeLocaleVar[2][en,fi]{%
foreach n in {#1}{%
expandafterSetDefaultValueexpandafter{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}}%
expandafternewcommandcsname Pass#2Toendcsname[2][en]{%
expandafterexpandafterexpandafterPassFirstToSecond
expandafterexpandafterexpandafter{csname#2:##1endcsname}{##2}%
}%
}

% Variables set in document
MakeLocaleVar{Title}
MakeLocaleVar{Year}


MakeLocaleVar{AbstractStr}
AbstractStr[en]{ABSTRACT}
AbstractStr[fi]{TIIVISTELMÄ}

MakeLocaleVar{LanguageStr}
LanguageStr[en]{english}
LanguageStr[fi]{finnish}

renewenvironment{abstract}[1][en]{%
section*{EmitAbstractStr[{#1}]}%%%%
PassLanguageStrTo[{#1}]{begin{otherlanguage}}%
@authorpar
textbf{EmitTitle[{#1}]}par
EmitYearpar
par
}{%
end{otherlanguage}%%%%
}

makeatother

usepackage[utf8]{inputenc}
usepackage[T1]{fontenc}
usepackage[finnish, english]{babel}

author{Handsome Devil}
Year{2019}

Title[en]{Title in English}
Title[fi]{Otsikko suomeksi}

begin{document}
selectlanguage{english}

begin{abstract}
Abstract environment in English.
end{abstract}

begin{abstract}[fi]
Abstract environment in Finnish.
end{abstract}
end{document}





share|improve this answer

























    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.










    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f477681%2fexpansion-of-macro-in-environment-argument%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









    0














    MakeLocaleVar{LanguageStr} causes EmitLanguageStr to be defined as:



    newcommandEmitLanguageStr[1][en]{@nameuse{LanguageStr:#1}}%


    EmitLanguageStr processes an optional argument.



    If you look at EmitLanguageStr via showEmitLanguageStr, you'll find:



    > EmitLanguageStr=macro:
    ->@protected@testopt EmitLanguageStr \EmitLanguageStr {en}.


    Looking at @protected@testopt yields:



    > @protected@testopt=macro:
    #1->ifx protect @typeset@protect expandafter @testopt else @x@protect #1
    fi .


    Looking at @testopt yields:



    > @testopt=long macro:
    #1#2->kernel@ifnextchar [{#1}{#1[{#2}]}.


    Looking at kernel@ifnextchar yields:



    > kernel@ifnextchar=long macro:
    #1#2#3->let reserved@d =#1def reserved@a {#2}def reserved@b {#3}futurele
    t @let@token @ifnch .


    Looking at @ifnch yields:



    > @ifnch=macro:
    ->ifx @let@token @sptoken let reserved@c @xifnch else ifx @let@token
    reserved@d let reserved@c reserved@a else let reserved@c reserved@b fi
    fi reserved@c .


    Looking at @xifnch yields:



    > @xifnch=macro:
    ->futurelet @let@token @ifnch .


    As you can see a lot of playing around with non-expandable let- and futurelet-assignments is involved into the checking for the presence of the optional argument via kernel@ifnextchar [.



    Therefore EmitLanguageStr does not only deliver those character tokens that form the name of the language. It also yields a lot of unexpandable assignment-tokens like let and futurelet for checking for the presence of the optional argument.

    These tokens won't vanish within a pure-expansion-context while obtaining the name of the language for passing it as argument to an environment would be a pure expansion context.
    After expansion these unexpandable assignment-tokens remain in the token-stream because while expansion takes place in (La)TeX's "gullet",
    the carrying out of assignments takes place in (La)TeX's "stomach".



    So in short:



    As long as EmitLanguageStr processes an optional argument whereby the techniques for detecting the presence of an optional argument themselves involve non-expandable assignment-tokens which don't vanish during expansion, you can't use EmitLanguageStr in pure-expansion-contexts for obtaining only those tokens that form the name of the language.



    But you can, e.g., create a variant of EmitLanguageStr with an additional argument holding tokens to which the emitted string is to be passed as argument. I call that macro PassLanguageStrTo:



    documentclass[a4paper,12pt]{article}

    usepackage{ifthen}
    usepackage{pgffor}

    makeatletter

    newcommandSetDefaultValue[2]{%
    global@namedef{#2:#1}{%
    {scriptsize (Use {tttextbackslash #2[#1]} to replace this text.)}%
    }%
    }

    newcommandPassFirstToSecond[2]{#2{#1}}%

    newcommandMakeLocaleVar[2][en,fi]{%
    foreach n in {#1}{%
    expandafterSetDefaultValueexpandafter{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}}%
    expandafternewcommandcsname Pass#2Toendcsname[2][en]{%
    expandafterexpandafterexpandafterPassFirstToSecond
    expandafterexpandafterexpandafter{csname#2:##1endcsname}{##2}%
    }%
    }

    % Variables set in document
    MakeLocaleVar{Title}
    MakeLocaleVar{Year}


    MakeLocaleVar{AbstractStr}
    AbstractStr[en]{ABSTRACT}
    AbstractStr[fi]{TIIVISTELMÄ}

    MakeLocaleVar{LanguageStr}
    LanguageStr[en]{english}
    LanguageStr[fi]{finnish}

    renewenvironment{abstract}[1][en]{%
    section*{EmitAbstractStr[{#1}]}%%%%
    PassLanguageStrTo[{#1}]{begin{otherlanguage}}%
    @authorpar
    textbf{EmitTitle[{#1}]}par
    EmitYearpar
    par
    }{%
    end{otherlanguage}%%%%
    }

    makeatother

    usepackage[utf8]{inputenc}
    usepackage[T1]{fontenc}
    usepackage[finnish, english]{babel}

    author{Handsome Devil}
    Year{2019}

    Title[en]{Title in English}
    Title[fi]{Otsikko suomeksi}

    begin{document}
    selectlanguage{english}

    begin{abstract}
    Abstract environment in English.
    end{abstract}

    begin{abstract}[fi]
    Abstract environment in Finnish.
    end{abstract}
    end{document}





    share|improve this answer






























      0














      MakeLocaleVar{LanguageStr} causes EmitLanguageStr to be defined as:



      newcommandEmitLanguageStr[1][en]{@nameuse{LanguageStr:#1}}%


      EmitLanguageStr processes an optional argument.



      If you look at EmitLanguageStr via showEmitLanguageStr, you'll find:



      > EmitLanguageStr=macro:
      ->@protected@testopt EmitLanguageStr \EmitLanguageStr {en}.


      Looking at @protected@testopt yields:



      > @protected@testopt=macro:
      #1->ifx protect @typeset@protect expandafter @testopt else @x@protect #1
      fi .


      Looking at @testopt yields:



      > @testopt=long macro:
      #1#2->kernel@ifnextchar [{#1}{#1[{#2}]}.


      Looking at kernel@ifnextchar yields:



      > kernel@ifnextchar=long macro:
      #1#2#3->let reserved@d =#1def reserved@a {#2}def reserved@b {#3}futurele
      t @let@token @ifnch .


      Looking at @ifnch yields:



      > @ifnch=macro:
      ->ifx @let@token @sptoken let reserved@c @xifnch else ifx @let@token
      reserved@d let reserved@c reserved@a else let reserved@c reserved@b fi
      fi reserved@c .


      Looking at @xifnch yields:



      > @xifnch=macro:
      ->futurelet @let@token @ifnch .


      As you can see a lot of playing around with non-expandable let- and futurelet-assignments is involved into the checking for the presence of the optional argument via kernel@ifnextchar [.



      Therefore EmitLanguageStr does not only deliver those character tokens that form the name of the language. It also yields a lot of unexpandable assignment-tokens like let and futurelet for checking for the presence of the optional argument.

      These tokens won't vanish within a pure-expansion-context while obtaining the name of the language for passing it as argument to an environment would be a pure expansion context.
      After expansion these unexpandable assignment-tokens remain in the token-stream because while expansion takes place in (La)TeX's "gullet",
      the carrying out of assignments takes place in (La)TeX's "stomach".



      So in short:



      As long as EmitLanguageStr processes an optional argument whereby the techniques for detecting the presence of an optional argument themselves involve non-expandable assignment-tokens which don't vanish during expansion, you can't use EmitLanguageStr in pure-expansion-contexts for obtaining only those tokens that form the name of the language.



      But you can, e.g., create a variant of EmitLanguageStr with an additional argument holding tokens to which the emitted string is to be passed as argument. I call that macro PassLanguageStrTo:



      documentclass[a4paper,12pt]{article}

      usepackage{ifthen}
      usepackage{pgffor}

      makeatletter

      newcommandSetDefaultValue[2]{%
      global@namedef{#2:#1}{%
      {scriptsize (Use {tttextbackslash #2[#1]} to replace this text.)}%
      }%
      }

      newcommandPassFirstToSecond[2]{#2{#1}}%

      newcommandMakeLocaleVar[2][en,fi]{%
      foreach n in {#1}{%
      expandafterSetDefaultValueexpandafter{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}}%
      expandafternewcommandcsname Pass#2Toendcsname[2][en]{%
      expandafterexpandafterexpandafterPassFirstToSecond
      expandafterexpandafterexpandafter{csname#2:##1endcsname}{##2}%
      }%
      }

      % Variables set in document
      MakeLocaleVar{Title}
      MakeLocaleVar{Year}


      MakeLocaleVar{AbstractStr}
      AbstractStr[en]{ABSTRACT}
      AbstractStr[fi]{TIIVISTELMÄ}

      MakeLocaleVar{LanguageStr}
      LanguageStr[en]{english}
      LanguageStr[fi]{finnish}

      renewenvironment{abstract}[1][en]{%
      section*{EmitAbstractStr[{#1}]}%%%%
      PassLanguageStrTo[{#1}]{begin{otherlanguage}}%
      @authorpar
      textbf{EmitTitle[{#1}]}par
      EmitYearpar
      par
      }{%
      end{otherlanguage}%%%%
      }

      makeatother

      usepackage[utf8]{inputenc}
      usepackage[T1]{fontenc}
      usepackage[finnish, english]{babel}

      author{Handsome Devil}
      Year{2019}

      Title[en]{Title in English}
      Title[fi]{Otsikko suomeksi}

      begin{document}
      selectlanguage{english}

      begin{abstract}
      Abstract environment in English.
      end{abstract}

      begin{abstract}[fi]
      Abstract environment in Finnish.
      end{abstract}
      end{document}





      share|improve this answer




























        0












        0








        0







        MakeLocaleVar{LanguageStr} causes EmitLanguageStr to be defined as:



        newcommandEmitLanguageStr[1][en]{@nameuse{LanguageStr:#1}}%


        EmitLanguageStr processes an optional argument.



        If you look at EmitLanguageStr via showEmitLanguageStr, you'll find:



        > EmitLanguageStr=macro:
        ->@protected@testopt EmitLanguageStr \EmitLanguageStr {en}.


        Looking at @protected@testopt yields:



        > @protected@testopt=macro:
        #1->ifx protect @typeset@protect expandafter @testopt else @x@protect #1
        fi .


        Looking at @testopt yields:



        > @testopt=long macro:
        #1#2->kernel@ifnextchar [{#1}{#1[{#2}]}.


        Looking at kernel@ifnextchar yields:



        > kernel@ifnextchar=long macro:
        #1#2#3->let reserved@d =#1def reserved@a {#2}def reserved@b {#3}futurele
        t @let@token @ifnch .


        Looking at @ifnch yields:



        > @ifnch=macro:
        ->ifx @let@token @sptoken let reserved@c @xifnch else ifx @let@token
        reserved@d let reserved@c reserved@a else let reserved@c reserved@b fi
        fi reserved@c .


        Looking at @xifnch yields:



        > @xifnch=macro:
        ->futurelet @let@token @ifnch .


        As you can see a lot of playing around with non-expandable let- and futurelet-assignments is involved into the checking for the presence of the optional argument via kernel@ifnextchar [.



        Therefore EmitLanguageStr does not only deliver those character tokens that form the name of the language. It also yields a lot of unexpandable assignment-tokens like let and futurelet for checking for the presence of the optional argument.

        These tokens won't vanish within a pure-expansion-context while obtaining the name of the language for passing it as argument to an environment would be a pure expansion context.
        After expansion these unexpandable assignment-tokens remain in the token-stream because while expansion takes place in (La)TeX's "gullet",
        the carrying out of assignments takes place in (La)TeX's "stomach".



        So in short:



        As long as EmitLanguageStr processes an optional argument whereby the techniques for detecting the presence of an optional argument themselves involve non-expandable assignment-tokens which don't vanish during expansion, you can't use EmitLanguageStr in pure-expansion-contexts for obtaining only those tokens that form the name of the language.



        But you can, e.g., create a variant of EmitLanguageStr with an additional argument holding tokens to which the emitted string is to be passed as argument. I call that macro PassLanguageStrTo:



        documentclass[a4paper,12pt]{article}

        usepackage{ifthen}
        usepackage{pgffor}

        makeatletter

        newcommandSetDefaultValue[2]{%
        global@namedef{#2:#1}{%
        {scriptsize (Use {tttextbackslash #2[#1]} to replace this text.)}%
        }%
        }

        newcommandPassFirstToSecond[2]{#2{#1}}%

        newcommandMakeLocaleVar[2][en,fi]{%
        foreach n in {#1}{%
        expandafterSetDefaultValueexpandafter{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}}%
        expandafternewcommandcsname Pass#2Toendcsname[2][en]{%
        expandafterexpandafterexpandafterPassFirstToSecond
        expandafterexpandafterexpandafter{csname#2:##1endcsname}{##2}%
        }%
        }

        % Variables set in document
        MakeLocaleVar{Title}
        MakeLocaleVar{Year}


        MakeLocaleVar{AbstractStr}
        AbstractStr[en]{ABSTRACT}
        AbstractStr[fi]{TIIVISTELMÄ}

        MakeLocaleVar{LanguageStr}
        LanguageStr[en]{english}
        LanguageStr[fi]{finnish}

        renewenvironment{abstract}[1][en]{%
        section*{EmitAbstractStr[{#1}]}%%%%
        PassLanguageStrTo[{#1}]{begin{otherlanguage}}%
        @authorpar
        textbf{EmitTitle[{#1}]}par
        EmitYearpar
        par
        }{%
        end{otherlanguage}%%%%
        }

        makeatother

        usepackage[utf8]{inputenc}
        usepackage[T1]{fontenc}
        usepackage[finnish, english]{babel}

        author{Handsome Devil}
        Year{2019}

        Title[en]{Title in English}
        Title[fi]{Otsikko suomeksi}

        begin{document}
        selectlanguage{english}

        begin{abstract}
        Abstract environment in English.
        end{abstract}

        begin{abstract}[fi]
        Abstract environment in Finnish.
        end{abstract}
        end{document}





        share|improve this answer















        MakeLocaleVar{LanguageStr} causes EmitLanguageStr to be defined as:



        newcommandEmitLanguageStr[1][en]{@nameuse{LanguageStr:#1}}%


        EmitLanguageStr processes an optional argument.



        If you look at EmitLanguageStr via showEmitLanguageStr, you'll find:



        > EmitLanguageStr=macro:
        ->@protected@testopt EmitLanguageStr \EmitLanguageStr {en}.


        Looking at @protected@testopt yields:



        > @protected@testopt=macro:
        #1->ifx protect @typeset@protect expandafter @testopt else @x@protect #1
        fi .


        Looking at @testopt yields:



        > @testopt=long macro:
        #1#2->kernel@ifnextchar [{#1}{#1[{#2}]}.


        Looking at kernel@ifnextchar yields:



        > kernel@ifnextchar=long macro:
        #1#2#3->let reserved@d =#1def reserved@a {#2}def reserved@b {#3}futurele
        t @let@token @ifnch .


        Looking at @ifnch yields:



        > @ifnch=macro:
        ->ifx @let@token @sptoken let reserved@c @xifnch else ifx @let@token
        reserved@d let reserved@c reserved@a else let reserved@c reserved@b fi
        fi reserved@c .


        Looking at @xifnch yields:



        > @xifnch=macro:
        ->futurelet @let@token @ifnch .


        As you can see a lot of playing around with non-expandable let- and futurelet-assignments is involved into the checking for the presence of the optional argument via kernel@ifnextchar [.



        Therefore EmitLanguageStr does not only deliver those character tokens that form the name of the language. It also yields a lot of unexpandable assignment-tokens like let and futurelet for checking for the presence of the optional argument.

        These tokens won't vanish within a pure-expansion-context while obtaining the name of the language for passing it as argument to an environment would be a pure expansion context.
        After expansion these unexpandable assignment-tokens remain in the token-stream because while expansion takes place in (La)TeX's "gullet",
        the carrying out of assignments takes place in (La)TeX's "stomach".



        So in short:



        As long as EmitLanguageStr processes an optional argument whereby the techniques for detecting the presence of an optional argument themselves involve non-expandable assignment-tokens which don't vanish during expansion, you can't use EmitLanguageStr in pure-expansion-contexts for obtaining only those tokens that form the name of the language.



        But you can, e.g., create a variant of EmitLanguageStr with an additional argument holding tokens to which the emitted string is to be passed as argument. I call that macro PassLanguageStrTo:



        documentclass[a4paper,12pt]{article}

        usepackage{ifthen}
        usepackage{pgffor}

        makeatletter

        newcommandSetDefaultValue[2]{%
        global@namedef{#2:#1}{%
        {scriptsize (Use {tttextbackslash #2[#1]} to replace this text.)}%
        }%
        }

        newcommandPassFirstToSecond[2]{#2{#1}}%

        newcommandMakeLocaleVar[2][en,fi]{%
        foreach n in {#1}{%
        expandafterSetDefaultValueexpandafter{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}}%
        expandafternewcommandcsname Pass#2Toendcsname[2][en]{%
        expandafterexpandafterexpandafterPassFirstToSecond
        expandafterexpandafterexpandafter{csname#2:##1endcsname}{##2}%
        }%
        }

        % Variables set in document
        MakeLocaleVar{Title}
        MakeLocaleVar{Year}


        MakeLocaleVar{AbstractStr}
        AbstractStr[en]{ABSTRACT}
        AbstractStr[fi]{TIIVISTELMÄ}

        MakeLocaleVar{LanguageStr}
        LanguageStr[en]{english}
        LanguageStr[fi]{finnish}

        renewenvironment{abstract}[1][en]{%
        section*{EmitAbstractStr[{#1}]}%%%%
        PassLanguageStrTo[{#1}]{begin{otherlanguage}}%
        @authorpar
        textbf{EmitTitle[{#1}]}par
        EmitYearpar
        par
        }{%
        end{otherlanguage}%%%%
        }

        makeatother

        usepackage[utf8]{inputenc}
        usepackage[T1]{fontenc}
        usepackage[finnish, english]{babel}

        author{Handsome Devil}
        Year{2019}

        Title[en]{Title in English}
        Title[fi]{Otsikko suomeksi}

        begin{document}
        selectlanguage{english}

        begin{abstract}
        Abstract environment in English.
        end{abstract}

        begin{abstract}[fi]
        Abstract environment in Finnish.
        end{abstract}
        end{document}






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 13 hours ago

























        answered 13 hours ago









        Ulrich DiezUlrich Diez

        5,155619




        5,155619






















            Felix is a new contributor. Be nice, and check out our Code of Conduct.










            draft saved

            draft discarded


















            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.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f477681%2fexpansion-of-macro-in-environment-argument%23new-answer', 'question_page');
            }
            );

            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







            Popular posts from this blog

            El tren de la libertad Índice Antecedentes "Porque yo decido" Desarrollo de la...

            Puerta de Hutt Referencias Enlaces externos Menú de navegación15°58′00″S 5°42′00″O /...

            Castillo d'Acher Características Menú de navegación