
명령을 정의하는 데 사용할 수 있는 매크로를 만들고 싶습니다. 이러한 명령은 변수 또는 변수 구조체처럼 동작하므로 여러 값을 포함할 수 있습니다. "멤버"는 선택적 인수를 통해 전달됩니다. 저는 이를 사용하여 템플릿 환경을 정의하고 문서에 동시에 표시되어야 하는 다양한 언어에 대한 다양한 문자열을 보유합니다.
여기에 내가 가지고 있고 작동하는 것이 있습니다.
\newcommand\MakeLocaleVar[1]{%
\global\@namedef{#1:en}{{\scriptsize (Use {\tt\textbackslash #1[en]} to replace this text.)}}%
\global\@namedef{#1:fi}{{\scriptsize (Use {\tt\textbackslash #1[fi]} to replace this text.)}}%
\expandafter\newcommand\csname #1\endcsname[2][]{%
\ifthenelse{\equal{##1}{}}{%
\global\@namedef{#1:en}{##2}%
\global\@namedef{#1:fi}{##2}%
}{%
\global\@namedef{#1:##1}{##2}%
}%
}%
\expandafter\newcommand\csname Emit#1\endcsname[1][en]{\@nameuse{#1:##1}}%
}
먼저 기본값이 설정됩니다. 그런 다음 선택적 인수에 따라 값을 설정하는 명령이 생성됩니다. 없는 경우 모든 로캘에 대한 값을 설정합니다.
% 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}
임의의 로케일을 허용하도록 명령을 수정하려고 했지만 뭔가 작동하지 않습니다.
\newcommand\MakeLocaleVar[2][en,fi]{%
\foreach \n in {#1}{%
\global\@namedef{#2:\n}{%
{\scriptsize (Use {\tt\textbackslash #2[\n]} to replace this text.)}%
}%
}%
\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}}%
}
사용되는 값을 설정하면 모든 것이 괜찮고 멋집니다. 내 사용자 정의 환경이 중단되고 표시되는 기본 메시지가 Use \Cmd[] to...
로케일 이름이 없는 값이 설정되지 않은 경우입니다 .
무슨 일이 일어나고 있는지 아시나요?
답변1
의견에서 언급했듯이 주요 문제는 \n
대체 텍스트의 \@namedef
이 값으로 확장되지 않았다는 것입니다. Faculty:fi
예를 들어 대체 텍스트는 문자 그대로 유지되었습니다.
{\scriptsize (Use {\tt\textbackslash #2[\n]} to replace this text.)}%
와 함께 \n
. 매크로가 호출되는 대부분의 상황에서는 \n
정의되지 않고 오류가 발생합니다. 매크로 대체 텍스트를 구성하여 \n
확장(예: fi
또는 )이 되기를 원합니다 en
. 이를 올바르게 수행하는 가장 쉬운 방법은 아마도 도우미 매크로일 것입니다. 이 답변은 두 가지 접근 방식을 보여줍니다. 하나는 목록 매크로를 사용 하고 다른 하나는 도우미 매크로를 etoolbox
사용하는 코드를 사용합니다 . 의 루프는 루프 변수의 값을 도우미 매크로에 대한 인수로 직접 전달하여 작동합니다.\expandafter
etoolbox
\@namedef
(즉, #2:\n
) 의 첫 번째 인수에서 는 \n
실제로 거기에 도달하도록 자동으로 확장됩니다 fi
.
etoolbox
다음은 목록 매크로를 사용하는 솔루션입니다 . 일부 설명은 인라인입니다. 이 접근 방식의 장점은 \n
루프가 매크로(보통 도우미 매크로 필요)로 직접 구현되므로 루프 변수( )를 확장할 필요가 없다는 것입니다 .
\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 {\ttfamily\textbackslash #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 last argument
% <macro>{<item_1>}, <macro>{<item_2>}
% <macro> can already bring a few arguments of its own
% it could be <marco>{<fixed_1>}...{<fixed_n>} and then the invocations
% would become <marco>{<fixed_1>}...{<fixed_n>}{<item_1>} etc.
% Since the items are the <lang> argument it must be the last
% argument to \mlv@defaultvalue and \mlv@realvalue
\newcommand\MakeLocaleVar[2][en,fi]{%
\forcsvlist{\mlv@defaultvalue{#2}}{#1}%
\expandafter\newcommand\csname #2\endcsname[2][]{%
\ifblank{##1}
{\forcsvlist{\mlv@realvalue{##2}{#2}}{#1}}%
{\mlv@realvalue{##2}{#2}{##1}}}%
\expandafter\newcommand\csname Emit#2\endcsname[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}
\foreach
및 버전을 유지하려면 \ifthenelse
도우미 기능을 사용할 수 있습니다.
비결은 \n
실제 가치를 얻으려면 확장해야 한다는 것입니다. 이는 를 사용하여 가능 \expandafter
하지만 많은 토큰을 뛰어넘기 위해 정밀하게 사용하지 않으려면 도우미 기능이 유용합니다. 나중 인수 대신 s를 사용하여 매크로의 첫 번째 인수를 확장하는 것이 약간 더 쉽기 때문에 \expandafter
도우미 함수는 약간 예상치 못한 인수 순서를 사용합니다 {<lang>}{<name>}
.
\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 {\ttfamily\textbackslash #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.
\newcommand\MakeLocaleVar[2][en,fi]{%
\foreach \n in {#1}{%
\expandafter\mlv@helper\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}}%
}
\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}
참고: LaTeX2e에서는 두 글자로 된 글꼴 명령이 더 이상 사용되지 않기 때문에 \ttfamily
대신에 를 사용했습니다 (\tt
https://texfaq.org/FAQ-2letterfontcmd,LaTeX에서 두 글자 글꼴 스타일 명령(\bf, \it, …)이 부활할 예정입니까?).