# using csname to define intern commands(variables) and their setters

I want to define some macros to create texts in different languages; the command is \newlang which creates an invisible macro or variable to store the text of the specific language and a setter to set this variable.

For example: \newlang{ar} would create \@artxt to store the text, and \setartext{text} to set \@artxt.

When I want to show the content of these variables (suppose we called \newlang 3 times), using \csname juste the last one shows its content. This is the code:

\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}

It should print this:

—–ar—-
arabic2
*****
arabic2
french
—–fr—-
french
*****
arabic2
french
—–en—-
english
*****
arabic2
french
Another text

But, it print this instead:

—–ar—-
No ar csname here
*****
arabic2
french
—–fr—-
No fr csname here
*****
arabic2
french
—–en—-
english
*****
arabic2
french
Another text
• Your suggested output seems incorrect. – Werner Mar 21 '16 at 21:53
• You have \@langs{} but it should be \@langs – egreg Mar 21 '16 at 21:54
• Note that all the % at ends of lines are mis-placed you should have no space before the % or it does nothing useful. – David Carlisle Mar 21 '16 at 22:08
• Changing \@langs{} to \@langs solved the problem. As for the %, when I add them TexStudio adds spaces automatically, I will fix this. Thank you all for your help. – Karim Mar 21 '16 at 22:14

The error is \@langs{} which adds and explicit {} token to the language list for each entry, leaving ar{} and not the expected ar, etc.

This way the \ifcsname .... test must fail, i.e. it will return the false branch since @ar{}text is not defined.

\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}
• I tried to accept both answers, because I found them both useful. Apparently I can choose just one (why can't you choose 2 or 3?). – Karim Mar 22 '16 at 11:15
• @Karim: You 'have' to choose the best one. And I did not mean that you should change again. If egreg's solution is better for you than use it. – user31729 Mar 22 '16 at 11:16
• They are both good answers, I really can't choose. So let's decide with FIFO, since you are the first I feel like I must choose yours. By the way, I need this function to add more flexibility to my imgBook.cls. It accepts 4 languages: Ar, Fr, En and Ja. I want to give more freedom to add other languages link to the project – Karim Mar 22 '16 at 11:31

The error is here:

\expandafter\def\expandafter\@langs\expandafter{\@langs{},#1} %

because when you call \@splitcomma, the list is

ar{},fr{},en

so \tmp becomes ar{} and \csname @ar{}txt\endcsname is very different from \csname @artxt\endcsname.

A polished up version, with correct % at end of lines:

\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}

A different implementation using 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}

A simpler version of your 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}
• The second one using expl3 generated some errors: Undefined control sequence \print and also same error for \gettext{fr}. I used pdflatex to compile it. – Karim Mar 21 '16 at 22:30
• @Karim I suspect you don't have an up-to-date TeX distribution – egreg Mar 21 '16 at 22:33
• May be it's the reason. I use texlive package on ubuntu and its derivatives. I tried to download the package xparse and extract it besides the tex file but it still generates the error. I'll stick with the first solution for now. – Karim Mar 21 '16 at 22:45
• @Karim I added a simplified version of your macros (including a \gettext macro). – egreg Mar 21 '16 at 23:05

The follow code is a little easier on the eyes:

\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}

The languages are stored in a list that is process using etoolbox (see How to iterate over a comma separated list? for more details).