%20e%20seus%20setters.png)
Quero definir algumas macros para criar textos em diferentes idiomas; o comando \newlang
cria uma macro ou variável invisível para armazenar o texto do idioma específico e um setter para definir esta variável.
Por exemplo: \newlang{ar}
criaria \@artxt
para armazenar o texto e \setartext{text}
definiria \@artxt
.
Quando quero mostrar o conteúdo dessas variáveis (suponha que chamamos \newlang
3 vezes), usando \csname
juste a última mostra seu conteúdo. Este é o código:
\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}
Deve imprimir isto:
—–ar—-
arabic2
*****
arabic2
french
—–fr—-
french
*****
arabic2
french
—–en—-
english
*****
arabic2
french
Another text
Mas, em vez disso, imprima isto:
—–ar—-
No ar csname here
*****
arabic2
french
—–fr—-
No fr csname here
*****
arabic2
french
—–en—-
english
*****
arabic2
french
Another text
Responder1
O erro é \@langs{}
adicionar {}
um token explícito à lista de idiomas para cada entrada, deixando ar{}
e não o esperado ar
, etc.
Desta forma o \ifcsname ....
teste deverá falhar, ou seja, retornará o branch falso já que @ar{}text
não está definido.
\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}
Responder2
O erro está aqui:
\expandafter\def\expandafter\@langs\expandafter{\@langs{},#1} %
porque quando você liga \@splitcomma
, a lista é
ar{},fr{},en
então \tmp
se torna ar{}
e \csname @ar{}txt\endcsname
é muito diferente de \csname @artxt\endcsname
.
Uma versão polida, com %
final de linha correto:
\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}
Uma implementação diferente usando 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}
Uma versão mais simples de suas macros:
\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}
Responder3
O código a seguir é um pouco mais agradável aos olhos:
\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}
Os idiomas são armazenados em uma lista que é processada usandoetoolbox
(verComo iterar em uma lista separada por vírgula?para mais detalhes).