5

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
Karim
  • 73

3 Answers3

6

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} 

enter image description here


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} 

enter image description here


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} 
egreg
  • 1,121,712
  • 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
2

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. –  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
1

The follow code is a little easier on the eyes:

enter image description here

\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).

Werner
  • 603,163