我想定义一些宏来创建不同语言的文本;该命令是\newlang
创建一个不可见的宏或变量来存储特定语言的文本和一个设置器来设置这个变量。
例如:\newlang{ar}
将创建\@artxt
来存储文本,并\setartext{text}
设置\@artxt
。
当我想显示这些变量的内容时(假设我们调用了\newlang
3 次),\csname
只使用最后一个变量来显示其内容。这是代码:
\documentclass{article}
\makeatletter
\newcommand\newlang[1]{ %
\ifdefined\@langs %
\expandafter\def\expandafter\@langs\expandafter{\@langs{},#1} %
\else %
\def\@langs{#1} %
\fi
\@namedef{@#1txt}{}%
%
\expandafter\newcommand\csname set#1text\endcsname[1]{ %
%
\expandafter\def\csname @#1txt\endcsname{##1} %
} %
}
\newcommand{\@processTexts}[1]{ %
-----#1----\\
\ifcsname @#1txt\endcsname
\csname @#1txt\endcsname
\else
No #1 csname here
\fi\\
******\\
\@artxt \\
\@frtxt \\
}
\newcommand\@splitcomma[1]{\@for\tmp:=#1\do{\@processTexts{\tmp}}}
\newcommand{\print}{ %
\ifdefined\@langs %
\@splitcomma{\@langs}%
\fi %
}
\makeatother
\begin{document}
\newlang{ar}
\newlang{fr}
\newlang{en}
\setartext{arabic}
\setfrtext{french}
\setentext{english}
\setartext{arabic2}
\print{}
Another text
\end{document}
它应该打印如下内容:
—–ar—-
arabic2
*****
arabic2
french
—–fr—-
french
*****
arabic2
french
—–en—-
english
*****
arabic2
french
Another text
但是,它打印的是这个:
—–ar—-
No ar csname here
*****
arabic2
french
—–fr—-
No fr csname here
*****
arabic2
french
—–en—-
english
*****
arabic2
french
Another text
答案1
错误在于为每个条目向语言列表\@langs{}
添加明确的标记,而留下的不是预期的,等等。{}
ar{}
ar
这样测试就必定失败,即由于未定义,\ifcsname ....
它将返回错误分支。@ar{}text
\documentclass{article}
\makeatletter
\newcommand\newlang[1]{%
\ifdefined\@langs%
\expandafter\def\expandafter\@langs\expandafter{\@langs,#1} %
\else %
\def\@langs{#1} %
\fi
\global\expandafter\newcommand\csname @#1txt\endcsname{foo}%
\expandafter\newcommand\csname set#1text\endcsname[1]{ %
%
\expandafter\gdef\csname @#1txt\endcsname{##1} %
}%
}
\newcommand{\@processTexts}[1]{ %
-----#1----\\
\@ifundefined{@#1txt}{%
No #1 csname here -- sorry%
}{%
\csname @#1txt\endcsname%
}
\\
******\\
}
\newcommand\@splitcomma[1]{\@for\tmp:=#1\do{\@processTexts{\tmp}}}
\newcommand{\print}{ %
\ifdefined\@langs %
\@splitcomma{\@langs}%
\fi %
}
\makeatother
\begin{document}
\newlang{ar}
\newlang{fr}
\newlang{en}
\setartext{arabic}
\setfrtext{french}
\setentext{english}
\setartext{arabic2}
\print{}
Another text
\end{document}
答案2
错误在这里:
\expandafter\def\expandafter\@langs\expandafter{\@langs{},#1} %
因为当你打电话的时候\@splitcomma
,列表是
ar{},fr{},en
所以\tmp
变得ar{}
与\csname @ar{}txt\endcsname
非常不同\csname @artxt\endcsname
。
经过完善的版本,%
行末有更正:
\documentclass{article}
\makeatletter
\newcommand\newlang[1]{%
\ifdefined\@langs
\expandafter\def\expandafter\@langs\expandafter{\@langs,#1}%
\else
\def\@langs{#1}%
\fi
\@namedef{@#1txt}{}%
\expandafter\newcommand\csname set#1text\endcsname[1]{%
\expandafter\def\csname @#1txt\endcsname{##1}%
}%
}
\newcommand{\@processTexts}[1]{%
-----#1----\\
\ifcsname @#1txt\endcsname
\csname @#1txt\endcsname
\else
No #1 csname here%
\fi
\\
******\\
\@artxt \\
\@frtxt \\
}
\newcommand\@splitcomma[1]{\@for\tmp:=#1\do{\@processTexts{\tmp}}}
\newcommand{\print}{%
\ifdefined\@langs
\@splitcomma{\@langs}%
\fi
}
\makeatother
\begin{document}
\newlang{ar}
\newlang{fr}
\newlang{en}
\setartext{arabic}
\setfrtext{french}
\setentext{english}
\setartext{arabic2}
\noindent\print{}
Another text
\end{document}
使用不同的实现expl3
:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
% User level commands
\NewDocumentCommand{\newlang}{m}
{
\karim_lang_newlang:n { #1 }
}
\DeclareExpandableDocumentCommand{\gettext}{m}
{
\karim_lang_gettext:n { #1 }
}
\NewDocumentCommand{\print}{}
{
\karim_lang_print:
}
% Variables
\seq_new:N \g_karim_lang_langs_seq
\prop_new:N \g_karim_lang_texts_prop
% Internal functions
\cs_new_protected:Nn \karim_lang_newlang:n
{
\seq_gput_right:Nn \g_karim_lang_langs_seq { #1 }
\cs_new:cpn { set#1text } ##1
{
\prop_gput:Nnn \g_karim_lang_texts_prop { #1 } { ##1 }
}
}
\cs_new:Nn \karim_lang_gettext:n
{
\prop_if_in:NnTF \g_karim_lang_texts_prop { #1 }
{
\prop_item:Nn \g_karim_lang_texts_prop { #1 }
}
{
No~text~for~#1~here
}
}
\cs_new_protected:Nn \karim_lang_print:
{
\seq_map_inline:Nn \g_karim_lang_langs_seq
{
\noindent
---##1---\\
\karim_lang_gettext:n { ##1 } \\
*****\par
}
}
\ExplSyntaxOff
\begin{document}
\newlang{ar}
\newlang{fr}
\newlang{en}
\setartext{arabic}
\setfrtext{french}
\setentext{english}
\setartext{arabic2}
\print
This is the text for French: \gettext{fr}
\end{document}
宏的更简单版本:
\documentclass{article}
\makeatletter
\let\karim@langs\@gobble
\newcommand\newlang[1]{%
\expandafter\def\expandafter\karim@langs\expandafter{\karim@langs,#1}%
\expandafter\newcommand\csname set#1text\endcsname[1]{%
\@namedef{karim@#1@text}{##1}%
}%
}
\newcommand{\gettext}[1]{%
\ifcsname karim@#1@text\endcsname
\@nameuse{karim@#1@text}%
\else
No text for #1!%
\fi
}
\newcommand{\print}{%
\ifx\karim@langs\@gobble
\else
\@for\next:=\karim@langs\do{%
\noindent
---\next---\\
\gettext{\next}\\
******\par
}%
\fi
}
\makeatother
\begin{document}
\newlang{ar}
\newlang{fr}
\newlang{en}
\setartext{arabic}
\setfrtext{french}
\setentext{english}
\setartext{arabic2}
\print
\end{document}
答案3
下面的代码看起来更简洁一些:
\documentclass{article}
\usepackage{etoolbox}
\makeatletter
\newcommand{\@langs}{}
\newcommand\newlang[1]{%
\xdef\@langs{\@langs,#1}%
\@namedef{set#1text}##1{\@namedef{@#1txt}{##1}}%
}
\newcommand{\printlangs}{%
\renewcommand{\do}[1]{%
\if$##1$\else
\par\noindent
\begin{tabular}{c}
\hline
-- ##1 -- \\
\hline
\ifcsname @##1txt\endcsname
\@nameuse{@##1txt}%
\else
No text specified%
\fi
\\
\hline
\end{tabular}
\par\bigskip
\fi
}
\expandafter\docsvlist\expandafter{\@langs}
}
\makeatother
\begin{document}
\newlang{ar}
\newlang{fr}
\newlang{en}
\setartext{arabic}
\setfrtext{french}
\setartext{arabic2}
\printlangs
Another text
\end{document}
语言存储在一个列表中,用于处理etoolbox
(看如何迭代以逗号分隔的列表?更多细节)。