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
  • 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
  • 3
    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
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. – 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
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} 
  • 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
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).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.