
我想定義一些巨集來創建不同語言的文字;該命令會\newlang
建立一個不可見的巨集或變數來儲存特定語言的文字以及一個設定器來設定該變數。
例如:\newlang{ar}
將建立\@artxt
儲存文本,並\setartext{text}
設定\@artxt
.
當我想顯示這些變數的內容時(假設我們呼叫了\newlang
3次),使用\csname
juste最後一個顯示其內容。這是代碼:
\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
(看如何迭代逗號分隔的清單?更多細節)。