
Me gustaría generar un entorno que cambie un poco según un argumento dado para ello. El motivo es que el documento tiene diferentes configuraciones regionales. He definido un comando EmitLanguageStr
que determina el argumento de otherlanguage
acuerdo con el argumento que se pasó. Por ejemplo, \EmitLanguageStr[en] -> english
. Consulte estas preguntas para obtener más contexto: [1,2]. Aquí está el entorno simplificado.
\renewenvironment{abstract}[1][en]{%
\section*{\EmitAbstractStr[#1]}
\begin{otherlanguage}{\EmitLanguageStr[#1]}
\@author\par
\textbf{\EmitTitle[#1]}\par
}{%
\end{otherlanguage}
}
Resulta que otras personas han tenido el mismo problema (q), pero la solución no me funcionó del todo. La respuesta sugiere que envolver el entorno de una de dos maneras permitiría ampliar el argumento:
% Create a macro
\newcommand\testlang{english}
% Expand the argument once:
\newenvironment{Otherlanguage}[1]{%
\expandafter\otherlanguage\expandafter{#1}%
}{\endotherlanguage}
% Alternative: argument is fully expanded
\newenvironment{Otherlanguage}[1]{%
\begingroup
\edef\temp{\endgroup\noexpand\otherlanguage{#1}}%
\temp
}{\endotherlanguage}
% usage
\begin{Otherlanguage}{\testlang}
...
\end{Otherlangauge}
Primero, sin estos envoltorios, babel muestra un mensaje de error que indica que el idioma EmitLanguageStr[en]
no está definido. Eso se abordó en la pregunta vinculada. Sin embargo, las soluciones presentadas producen otro tipo de error: Use of \EmitLanguageStr doesn't match its definition
.
¿Cómo se puede ampliar adecuadamente el comando?
Aquí hay un ejemplo completo de la situación. Esto funciona, pero al cambiar el argumento de Otherlanguage
al del comentario se genera el error descrito.
\documentclass[a4paper,12pt]{article}
\usepackage{ifthen}
\usepackage{pgffor}
\makeatletter
\newcommand\SetDefaultValue[2]{%
\global\@namedef{#2:#1}{%
{\scriptsize (Use {\tt\textbackslash #2[#1]} to replace this text.)}%
}%
}
\newcommand\MakeLocaleVar[2][en,fi]{%
\foreach \n in {#1}{%
\expandafter\SetDefaultValue\expandafter{\n}{#2}
}%
\expandafter\newcommand\csname #2\endcsname[2][]{%
\ifthenelse{\equal{##1}{}}{%
\foreach \n in {#1}{%
\global\@namedef{#2:\n}{##2}%
}%
}{%
\global\@namedef{#2:##1}{##2}%
}%
}%
\expandafter\newcommand\csname Emit#2\endcsname[1][en]{\@nameuse{#2:##1}}%
}
% Variables set in document
\MakeLocaleVar{Title}
\MakeLocaleVar{Year}
%\newenvironment{Otherlanguage}[1]{%
% \expandafter\otherlanguage\expandafter{#1}%
%}{\endotherlanguage}
\newenvironment{Otherlanguage}[1]{%
\begingroup
\edef\temp{\endgroup\noexpand\otherlanguage{#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]
\@author\par
\textbf{\EmitTitle[#1]}\par
\EmitYear\par
\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}
Respuesta1
\MakeLocaleVar{LanguageStr}
causas \EmitLanguageStr
que se definen como:
\newcommand\EmitLanguageStr[1][en]{\@nameuse{LanguageStr:#1}}%
\EmitLanguageStr
procesa un argumento opcional.
Si miras a \EmitLanguageStr
través de \show\EmitLanguageStr
, encontrarás:
> \EmitLanguageStr=macro:
->\@protected@testopt \EmitLanguageStr \\EmitLanguageStr {en}.
Mirando \@protected@testopt
los rendimientos:
> \@protected@testopt=macro:
#1->\ifx \protect \@typeset@protect \expandafter \@testopt \else \@x@protect #1
\fi .
Mirando \@testopt
los rendimientos:
> \@testopt=\long macro:
#1#2->\kernel@ifnextchar [{#1}{#1[{#2}]}.
Mirando \kernel@ifnextchar
los rendimientos:
> \kernel@ifnextchar=\long macro:
#1#2#3->\let \reserved@d =#1\def \reserved@a {#2}\def \reserved@b {#3}\futurele
t \@let@token \@ifnch .
Mirando \@ifnch
los rendimientos:
> \@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 .
Mirando \@xifnch
los rendimientos:
> \@xifnch=macro:
->\futurelet \@let@token \@ifnch .
Como puede ver, hay que jugar mucho con asignaciones \let
y no expandibles \futurelet
para verificar la presencia del argumento opcional a través de \kernel@ifnextchar [
.
Por lo tanto \EmitLanguageStr
no sólo entrega aquellos tokens de caracteres que forman el nombre del idioma. También produce una gran cantidad de tokens de asignación no expandibles como \let
y \futurelet
para verificar la presencia del argumento opcional.
Estos tokens no desaparecerán dentro de un contexto de expansión pura, mientras que obtener el nombre del idioma para pasarlo como argumento a un entorno sería un contexto de expansión pura. Después de la expansión, estos tokens de asignación no expandibles permanecen en el flujo de tokens porque mientras la expansión tiene lugar en la "garganta" de (La)TeX, la realización de las asignaciones tiene lugar en el "estómago" de (La)TeX.
En resumen:
Siempre que \EmitLanguageStr
procese un argumento opcional mediante el cual las técnicas para detectar la presencia de un argumento opcional impliquen tokens de asignación no expandibles que no desaparecen durante la expansión, no se puede utilizar \EmitLanguageStr
en contextos de expansión pura para obtener solo esos tokens. que forman el nombre de la lengua.
Pero puede, por ejemplo, crear una variante de \EmitLanguageStr
con un argumento adicional que contenga tokens a los que se pasará la cadena emitida como argumento. Yo llamo a esa macro \PassLanguageStrTo
:
\documentclass[a4paper,12pt]{article}
\usepackage{ifthen}
\usepackage{pgffor}
\makeatletter
\newcommand\SetDefaultValue[2]{%
\global\@namedef{#2:#1}{%
{\scriptsize (Use {\tt\textbackslash #2[#1]} to replace this text.)}%
}%
}
\newcommand\PassFirstToSecond[2]{#2{#1}}%
\newcommand\MakeLocaleVar[2][en,fi]{%
\foreach \n in {#1}{%
\expandafter\SetDefaultValue\expandafter{\n}{#2}%%%%
}%
\expandafter\newcommand\csname #2\endcsname[2][]{%
\ifthenelse{\equal{##1}{}}{%
\foreach \n in {#1}{%
\global\@namedef{#2:\n}{##2}%
}%
}{%
\global\@namedef{#2:##1}{##2}%
}%
}%
\expandafter\newcommand\csname Emit#2\endcsname[1][en]{\@nameuse{#2:##1}}%
\expandafter\newcommand\csname Pass#2To\endcsname[2][en]{%
\expandafter\expandafter\expandafter\PassFirstToSecond
\expandafter\expandafter\expandafter{\csname#2:##1\endcsname}{##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}}%
\@author\par
\textbf{\EmitTitle[{#1}]}\par
\EmitYear\par
\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}