Variable de cadena con múltiples valores

Variable de cadena con múltiples valores

Busco una definición de un comando que pueda tener múltiples valores para usar en diferentes contextos. El caso de uso para esto sería una clase personalizada que use dos idiomas simultáneamente, o supongo que cualquier situación en la que una variable pueda tener valores diferentes según el entorno. Después de buscar información \newcommandy cosas relacionadas con él, todavía estoy un poco desconcertado.

Según tengo entendido, una implementación simple sería:

\newcommand\varname{text value}

Sin embargo, tener diferentes comandos para las mismas cosas me resulta feo. Por ejemplo, tengo frente a mí una clase antigua con comandos como Doctypey Doctypefinpara la versión finlandesa. En lugar de eso, me gustaría usar el comando como este:

% Definitions
\title{en}{Title Of The Document}
\title{fi}{Dokumentin otsikko}

% Use in class environments or tex files
\title{en} % -> "Title Of The Document"
\title{fi} % -> "Dokumentin otsikko"

¿Hay alguna manera de construir tal macro o definición?

Idealmente, especificar categorías invisibles (aquí idiomas) no sería un problema, pero veo que sería razonable exigir que se especifiquen los valores aceptados en el archivo de clase. Además, como en el ejemplo siguiente, creo que sería aceptable tener un comando separado para generar la variable, si eso es un problema.


Intenté tomar nota de la forma en que se construyen otros comandos de clase. Hay un MakeStringVarcomando útil que construye una variable y, si no se establece, muestra un texto predeterminado. Esa funcionalidad de texto predeterminada sería muy útil para el nuevo comando, porque muchos entornos en la clase usan las definiciones para generar texto en páginas de título, etc.

\newcommand\MakeStringVar[2][\relax]{%
  \ifx#1\relax%
    \expandafter\newcommand\csname Emit#2\endcsname{%
      {\scriptsize (Use {\tt\textbackslash #2} to replace this text.)}}%
  \else%
    \expandafter\newcommand\csname Emit#2\endcsname{#1}%
  \fi%
  \expandafter\newcommand\csname #2\endcsname[1]{%
     \expandafter\renewcommand\csname Emit#2\endcsname{##1}%
  }%
}

Se usa así:

\MakeStringVar{Major} % Definition in class
\Major{Major subject name} % Set value in pre-document
\EmitMajor % Used in environments in class -> "Major subject name"

Pero soy un novato en lo que respecta a LaTeX, así que no estoy seguro de por dónde empezar. Tengo la sensación de que el comando anterior podría ampliarse de alguna manera, pero realmente no conozco las limitaciones de las macros de LaTeX.

Respuesta1

Puede considerar este enfoque que utiliza \@namedef:

\documentclass{article}

\makeatletter
\newcommand\deftitle[2][en]{%
    \global\@namedef{title:#1}{#2}%
}
\newcommand\usetitle[1][en]{\@nameuse{title:#1}}
\makeatother

\begin{document}

\deftitle{Default Language (English) Title} % same as \deftitle[en]{...}
\deftitle[it]{Italian Title}
\deftitle[fr]{French Title}

\usetitle[it]
\usetitle % same as \usetitle[en]
\usetitle[fr]

\end{document}

Cuando el usuario llama \deftitle[en]{<content>}, se define una nueva macro title:eny se expande <content>cuando se llama a través de \@nameuse.

EDITAR: Aquí hay una forma general de construir tales macros:

\makeatletter
\newcommand\newconstructor[1]{%
    \expandafter\newcommand\csname def#1\endcsname[2][en]{%
        \global\@namedef{#1:##1}{##2}%
    }%
    \expandafter\newcommand\csname use#1\endcsname[1][en]{\@nameuse{#1:##1}}%
}
\makeatother

Ahora, por ejemplo, \newconstructor{title}define \deftitley \usetitle, como antes.

Respuesta2

En esta implementación, las distintas versiones se ingresan con una práctica interfaz clave-valor (entrelace el valor si va a contener una coma).

También se pueden definir alias para claves. Para los idiomas, creo que es preferible usar claves largas con el nombre completo del idioma, de modo que \languagenamepuedan usarse para obtener la cadena relacionada. Sin embargo, también se pueden utilizar alias para claves en el documento, siempre que estén definidos de antemano.

No está obligado a agregar todas las versiones en el momento de la definición de una variable, ya que podrá usarlas \addtovarstringmás adelante.

\documentclass{article}
\usepackage[english,finnish]{babel}

\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\definevarstring}{mO{}}
 {
  \prop_new:c { g_felix_varstring_#1_prop }
  \felix_varstring_add:nn { #1 } { #2 }
 }
\NewDocumentCommand{\addtovarstring}{mm}
 {
  \felix_varstring_add:nn { #1 } { #2 }
 }
\NewDocumentCommand{\definealias}{m}
 {
  \prop_gset_from_keyval:Nn \g_felix_varstring_alias_prop { #1 }
 }
\NewExpandableDocumentCommand{\getvarstring}{mm}
 {
  \prop_if_in:cfTF { g_felix_varstring_#1_prop } { #2 }
   {
    \prop_item:cf { g_felix_varstring_#1_prop } { #2 }
   }
   {
    \prop_if_in:NnT \g_felix_varstring_alias_prop { #2 }
     {
      \prop_item:cf { g_felix_varstring_#1_prop }
       {
        \prop_item:Nn \g_felix_varstring_alias_prop { #2 }
       }
     }
   }
 }

\cs_generate_variant:Nn \prop_item:Nn { cf }
\prg_generate_conditional_variant:Nnn \prop_if_in:Nn { cf } { T,F,TF,p }
\prop_new:N \g_felix_varstring_alias_prop

\cs_new_protected:Nn \felix_varstring_add:nn
 {
  \prop_gset_from_keyval:cn { g_felix_varstring_#1_prop } { #2 }
 }

\ExplSyntaxOff

\definealias{fi=finnish,en=english}

\definevarstring{title}[% long versions for languages
  english=Title of the document,
  finnish=Dokumentin otsikko,
]

\begin{document}

\author{A. Uthor}
\title{\getvarstring{title}{\languagename}}
\maketitle

\selectlanguage{english}

\getvarstring{title}{\languagename}

\getvarstring{title}{en}---\getvarstring{title}{english}

\getvarstring{title}{fi}---\getvarstring{title}{finnish}

\end{document}

ingrese la descripción de la imagen aquí

Respuesta3

Hace algún tiempo escribí una \SetProperty- \GetProperty-interfaz.

Probablemente te sea de utilidad.

%% This coding example was written by Ulrich Diez in November 16, 2018.
%% It was modified by Ulrich Diez in February 28, 2019.
%%
%% Copyright 2018, 2019 Ulrich Diez (e-mail: [email protected])
%%
%% This work may be distributed and/or modified under the conditions of
%% the LaTeX Project Public License, either version 1.3c of this license
%% or (at your option) any later version.
%%
%% The latest version of this license is in
%%
%%   <http://www.latex-project.org/lppl.txt>
%%
%% and version 1.3x or later is part of all distributions of LaTeX
%% version 2005/12/01 or later.
%%
%% This work has the LPPL maintenance status `unmaintained'.
%%
%% This work consists of this coding example.
%%
\errorcontextlines=10000
\documentclass[landscape]{article}

\makeatletter
%%==== Begin of code for the \SetProperty-\GetProperty-Interface =======
\RequirePackage{ifluatex, ifxetex}
%%======================================================================
%% Paraphernalia:
%%    \UD@firstoftwo, \UD@secondoftwo, \UD@PassFirstToSecond,
%%    \UD@exchange, \UD@removespace, \UD@name, \UD@CheckWhetherNull,
%%    \UD@loopcall,
%%......................................................................
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
\newcommand\UD@exchange[2]{#2#1}%
\newcommand\UD@removespace{}\UD@firstoftwo{\def\UD@removespace}{} {}%
%%----------------------------------------------------------------------
%% Put a control sequence token in place instead of the string denoting
%% its name.
%%......................................................................
%%  \UD@name<emptiness or tokens other than braces>{<Name of
%%                                                   Control Sequence>}
%%
%% yields:
%%
%%  <emptiness or tokens other than braces>\Controlsequence
%%
%% E.g.,
%%
%%   \UD@name foo{bar} -> foo\bar
%%   \UD@name{bar} -> \bar
%%   \UD@name\newcommand*{wEirdName}[1]{Arg 1: (#1)}
%%       -> \newcommand*\wEirdName[1]{Arg 1: (#1)}
%%
\newcommand\UD@name{}\long\def\UD@name#1#{\romannumeral\UD@@name{#1}}%
\newcommand\UD@@name[2]{%
  \expandafter\UD@exchange\expandafter{\csname#2\endcsname}{0 #1}%
}%
%%----------------------------------------------------------------------
%% Check whether argument is empty:
%%......................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is empty>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
%%
%% (\romannumeral expansion was introduced in order to overcome the
%%  concerns and worries about improperly balanced
%%  \if..\else..\fi constructs.)
%%
\newcommand\UD@CheckWhetherNull[1]{%
  \romannumeral0\expandafter\UD@secondoftwo\string{\expandafter
  \UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
  \UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
  \UD@secondoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}%
}%
%%----------------------------------------------------------------------
%% Expandable Loop:
%% \UD@loopcall{<action>}%
%%          {<action if list empty>}%
%%          {<preset>}%
%%          {{<e_k>}{<e_(k+1)>}..{e_n}}% <- this is the list
%%
%% If list is empty: <action if list empty>
%% Else:
%% <action>{<e_k>}<preset> \UD@loopcall{<action>}%
%%                                  {<action if list empty>}%
%%                                  {<preset>}{{<e_(k+1)>}..{e_n}}
%%
%% <action> can be defined to mesh into the iteration-process, e.g.,
%% (ex)changing arguments like the <action if list empty>-argument for
%% the next \UD@loopcall-iteration, e.g., terminating iteration
%% prematurely under some circumstances.
%%......................................................................
\newcommand\UD@RemoveTillUD@nil{}%
\long\def\UD@RemoveTillUD@nil#1#2\UD@nil{{#1}}%
\newcommand\UD@Extractfirstloop[1]{%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
  {\UD@exchange{#1}}%
  {%
    \expandafter\UD@Extractfirstloop
    \expandafter{\UD@RemoveTillUD@nil#1}%
  }%
}%
\newcommand\UD@loopcall[4]{%
  \UD@CheckWhetherNull{#4}{#2}{%
    \expandafter\UD@exchange
    \expandafter{\expandafter{\UD@firstoftwo{}#4}}%
    {\UD@Extractfirstloop{#4\UD@nil}{#1}#3\UD@loopcall{#1}{#2}{#3}}%
  }%
}%
%%======================================================================
%% Expandable comparison of two strings:
%%
%% Derived from David Kastrup's \ifstrequal-test from the
%% TeX Pearl Diving Site;
%% Pearls of 2005;
%% Title: David Kastrup - Comparing two strings known to consist
%% only of characters ;
%% Url: <http://www.gust.org.pl/projects/pearls/2005p/david-kastrup/bachotex2005-david-kastrup-pearl1.pdf>
%%......................................................................
%% \UD@ifstrequal{<String 1>}{<String 2>}%
%%               {%
%%                  <Tokens to be delivered in case strings are equal>
%%               }%
%%               {%
%%                  <Tokens to be delivered in case strings are
%%                   not equal>
%%               }%
%%
%% (<String 1> gets expanded during comparison.
%%  <String 2> gets not expanded during comparison.
%%
%% I bloated this thing up for ensuring it also takes spaces into
%% account.
%%
\@ifdefinable\UD@strchksp{%
  \long\def\UD@strchksp#1#2#3#4 #5\relax{%
    #1{\if\UD@strequal\UD@secondoftwo{}{#4}%
       \expandafter\UD@firstoftwo\else\expandafter\UD@secondoftwo\fi
       {\if\UD@strequal\UD@secondoftwo{}{#5}%
        \expandafter\UD@firstoftwo\else\expandafter\UD@secondoftwo\fi
        {\UD@strequalstart#1{#2}{#3} \relax}%
        {\UD@strequalstart#1{#2}{#3}{ }#5\relax}}}%
    {\UD@strequalstart#1{#2}{#3}#4 #5\relax}%
  }%
}
\newcommand\UD@strequal[2]{\number\UD@strchksp#1{}{}#2 \relax}
\newcommand\UD@strequalstart[4]{%
  \if#4\relax\UD@strequalstop\fi
  \UD@strchksp#1{\if#4#2}{#3\fi}%
}%
\@ifdefinable\UD@strequalstop{%
  \long\def\UD@strequalstop\fi\UD@strchksp#1#2#3#4{\fi#2#4\relax'#313 }%
}
\newcommand\UD@ifstrequal[2]{%
  \romannumeral0%
  \if\UD@strequal\@firstofone{#2.}{#1.}%
  \expandafter\UD@firstoftwo\else\expandafter\UD@secondoftwo\fi
  {\UD@exchange{ \UD@firstoftwo}}{\UD@exchange{ \UD@secondoftwo}}%
  {\expandafter\expandafter\expandafter}%
}%
%%======================================================================
%% Total expansion and stringification of argument:
%%......................................................................
%% \UD@stringify{<argument that expands to character tokens>}
%%
%% Does \csname..\endcsname with the argument, then \string,
%% then removal of \escapechar if that was added.
%%
\newcommand\UD@stringify[1]{%
  \romannumeral0%
  \expandafter\expandafter\expandafter\UD@exchange
  \expandafter\expandafter\expandafter{%
  \expandafter\string\csname#1\endcsname}%
  {%
    \ifnum\the\escapechar<0 %
    \expandafter\UD@secondoftwo\else\expandafter\UD@firstoftwo\fi
    {%
      \ifnum\the\escapechar>\ifxetex 1114111 %
      \else\ifluatex 1114111 \else 255 \fi\fi
      \expandafter\UD@secondoftwo\else\expandafter\UD@firstoftwo\fi
      {%
        \ifnum\the\escapechar=32 %
        \expandafter\UD@secondoftwo\else\expandafter\UD@firstoftwo\fi
        {\UD@firstoftwo{ }}{}%
      }{ }%
    }{ }%
  }%
}%
%%======================================================================
%% Property-Management:
%%......................................................................
%%
%% The concept is about maintaining macros that expand to lists of
%% 2-tuple-arguments.
%% The first component of the tuple holds the name of a property.
%% The second component holds the value of the property.
%%
%% E.g., the macro \macro could be defined to expand to:
%%
%%   {{property name 1}{property value 1}}%
%%   {{property name 2}{property value 2}}%
%%   ...
%%   {{property name K}{property value K}}%
%%
%%
%% \SetProperty{\macro}%
%%             {<name of property>}%
%%             {<new value of property>}
%%
%%   In case \macro is undefined, \macro will be defined empty.
%%
%%   In case a property <name of property> does not exist within the
%%   macro \macro, it will be added to the macro and it will get the
%%   value <new value of property>.
%%
%%   In case a property <name of property> does exist within the macro
%%   \macro, its value will get replaced by <new value of property>.
%%
%%   Before further evaluation <name of property> will be expanded via
%%   \csname..\endcsname-expansion and afterwards "stringified" by
%%   applying \string and removing a leading escapechar if one was
%%   added.
%%
%%   Example:
%%
%%     \SetProperty{\macro}{property name 2}{changed property value 2}
%%
%%        would make \macro to expand to
%%
%%     {{property name 1}{property value 1}}%
%%     {{property name 2}{changed property value 2}}%
%%     ...
%%     {{property name K}{property value K}}%
%%
%%       and
%%
%%     \SetProperty{\macro}{property name (K+1)}{property value (K+1)}
%%
%%        would make \macro to expand to
%%
%%     {{property name 1}{property value 1}}%
%%     {{property name 2}{changed property value 2}}%
%%     ...
%%     {{property name K}{property value K}}%
%%     {{property name (K+1)}{property value (K+1)}}%
%%
%%
%% \GetProperty{\macro}%
%%             {<name of property>}%
%%             {%
%%               <tokens to be delivered in case
%%                property is not available>
%%             }
%%
%%   In case \macro is undefined or property <name of property> does not
%%   exist within the macro \macro,
%%   <tokens to be delivered in case property is not available>
%%   will be delivered.
%%
%%   In case a property <name of property> does exist within the macro
%%   \macro, its value will be delivered.
%%
%%   Before further evaluation <name of property> will be expanded via
%%   \csname..\endcsname-expansion and afterwards "stringified" by
%%   applying \string and removing a leading escapechar if one was
%%   added.
%%
%%   \GetProperty is expandable and delivers the result after two
%%   expansion steps / after being hit "twice" by \expandafter.
%%
%%   E.g., with the macro \macro being defined to expand to
%%
%%     {{property name 1}{property value 1}}%
%%     {{property name 2}{property value 2}}%
%%     ...
%%     {{property name K}{property value K}}%
%%
%%   , the sequence
%%
%%     \GetProperty{\macro}{property name 2}{Huh?}
%%
%%   will expand to:
%%
%%     property value 2
%%
\newcommand\UD@ExpandProperties[3]{%
  \expandafter\UD@PassFirstToSecond\expandafter{#1}%
  {\expandafter\expandafter\expandafter\UD@PassFirstToSecond
  \expandafter\expandafter\expandafter{%
  \UD@stringify{#2}}{#3}}%
}%
\newcommand\UD@AtIfPropertyListUndefined[1]{%
  \@ifundefined{%
    \expandafter\UD@exchange\expandafter{\string#1}%
    {%
      \ifnum\the\escapechar<0 %
      \expandafter\UD@secondoftwo\else\expandafter\UD@firstoftwo\fi
      {%
        \ifnum\the\escapechar>\ifxetex 1114111 %
        \else\ifluatex 1114111 \else 255 \fi\fi
        \expandafter\UD@secondoftwo\else\expandafter\UD@firstoftwo\fi
        {%
          \ifnum\the\escapechar=32 %
          \expandafter\UD@secondoftwo\else\expandafter\UD@firstoftwo\fi
          {\UD@firstoftwo{}}{\UD@removespace}%
        }{}%
      }{}%
    }%
  }%
}%
\newcommand\SetProperty[2]{%
  \@bsphack
  \UD@AtIfPropertyListUndefined{#1}{\newcommand*#1{}}{}%
  \romannumeral0%
  \UD@ExpandProperties{#1}{#2}{\UD@@setproperty}{#1}%
}%
\newcommand\UD@@setproperty[4]{%
  \UD@loopcall{\UD@@@setproperty}%
              { \global\def#3{{{#1}{#4}}}\@esphack}%
              {{#1}{#4}{ \global\def#3}{}}%
              {#2}%
}%
\newcommand\UD@@@setproperty{}%
\long\def\UD@@@setproperty#1#2#3#4#5\UD@loopcall#6#7#8#9{%
  \UD@ifstrequal{\UD@firstoftwo#1}{#2}%
  {%
    #4{#5{{#2}{#3}}#9}\@esphack
  }{%
    \UD@loopcall{#6}%
                {#4{#5{#1}{{#2}{#3}}}\@esphack}%
                {{#2}{#3}{#4}{#5{#1}}}%
                {#9}%
  }%
}%
\newcommand\GetProperty[3]{%
  \romannumeral0%
  \UD@AtIfPropertyListUndefined{#1}{ #3}{%
    \UD@ExpandProperties{#1}{#2}{\UD@@getproperty}{ #3}%
  }%
}%
\newcommand\UD@@getproperty[3]{%
  \UD@loopcall{\UD@@@getproperty}%
              {#3}%
              {{#1}}%
              {#2}%
}%
\newcommand\UD@@@getproperty{}%
\long\def\UD@@@getproperty#1#2\UD@loopcall#3#4#5#6{%
  \UD@ifstrequal{\UD@firstoftwo#1}{#2}%
    {\UD@exchange{ }\expandafter\UD@secondoftwo#1}%
    {%
      \UD@loopcall{#3}%
                  {#4}%
                  {#5}%
                  {#6}%
    }%
}%
%%==== End of code for the \SetProperty-\GetProperty-Interface =========


%%==== Layout of this example ==========================================
%   - No headers / no footers
\pagestyle{empty}
%   - paragraph-breaking:
\parindent=0ex
\parskip=\medskipamount
%   - horizontal margins:
\setlength\textwidth{\paperwidth}
\addtolength\textwidth{-3cm}
\setlength\oddsidemargin{1.5cm}%
\addtolength\oddsidemargin{-1in}%
\addtolength\oddsidemargin{-\hoffset}%
\setlength\evensidemargin{\oddsidemargin}%
\setlength\marginparwidth{1.5cm}%
\addtolength\marginparwidth{-2\marginparsep}%
%   - vertical margins:
\setlength\topmargin{1.5cm}
\addtolength\topmargin{-1in}
\addtolength\topmargin{-\voffset}
%   - no headheight/headsep etc as there are no headers as
%     pagestyle=empty:
\setlength\headsep{0pt}
\setlength\headheight{0pt}
\setlength\footskip{0pt}
\setlength\textheight{\paperheight}
\addtolength\textheight{-3cm}%
\addtolength\textheight{-\footskip}%
\addtolength\textheight{-\headsep}%
\addtolength\textheight{-\headheight}%
%   - allow linebreaks after closing braces in typewriter font:
\DeclareFontFamily{\encodingdefault}{\ttdefault}{\hyphenchar\font=`\}}
%   - in case of pdftex also adjust the underlying paper
\@ifundefined{pdfpagewidth}{}{\pdfpagewidth=\paperwidth}%
\@ifundefined{pdfpageheight}{}{\pdfpageheight=\paperheight}%
\@ifundefined{pagewidth}{}{\pagewidth=\paperwidth}%
\@ifundefined{pageheight}{}{\pageheight=\paperheight}%
%%==== Layout-changes etc done.=========================================

\newcommand\Errortext[3]{%
  \nfss@text{\reset@font\bfseries#3}%
  \GenericError{\space\@spaces\@spaces}%
               {Error: \string#1: Translation into language #2 not available}%
               {Source for further information on this error is neither available nor needed.}%
               {You can use \string\SetProperty for specifying a translation.}%
}%

\SetProperty{\mymacro}{English}{This is a sentence in English.}
\SetProperty{\mymacro}{Francais}{Ceci est une phrase en fran\c cais.}
\SetProperty{\mymacro}{Italiano}{Questa \`e una frase in italiano.}
\SetProperty{\mymacro}{Deutsch}{Dies ist ein Satz in deutscher Sprache.}

\makeatother

\begin{document}
\verb|\SetProperty{\mymacro}{English}{This is a sentence in English.}|\\
\verb|\SetProperty{\mymacro}{Francais}{Ceci est une phrase en fran\c cais.}|\\
\verb|\SetProperty{\mymacro}{Italiano}{Questa \`e una frase in italiano.}|\\
\verb|\SetProperty{\mymacro}{Deutsch}{Dies ist ein Satz in deutscher Sprache.}|
\\\null\hrulefill\null

\verb|\GetProperty{\mymacro}{English}{\Errortext{\mymacro}{English}{No translation available.}}|\\
\GetProperty{\mymacro}{English}{\Errortext{\mymacro}{English}{No translation available.}}

\verb|\GetProperty{\mymacro}{Francais}{\Errortext{\mymacro}{Francais}{Aucune traduction disponible.}}|\\
\GetProperty{\mymacro}{Francais}{\Errortext{\mymacro}{Francais}{Aucune traduction disponible.}}

\verb|\GetProperty{\mymacro}{Italiano}{\Errortext{\mymacro}{Italiano}{Nessuna traduzione disponibile.}}|\\
\GetProperty{\mymacro}{Italiano}{\Errortext{\mymacro}{Italiano}{Nessuna traduzione disponibile.}}

\verb|\GetProperty{\mymacro}{Deutsch}{\Errortext{\mymacro}{Deutsch}{Keine Übersetzung vorhanden.}}|\\
\GetProperty{\mymacro}{Deutsch}{\Errortext{\mymacro}{Deutsch}{Keine Übersetzung vorhanden.}}

\verb|% This will raise an error:|\\    
\verb|\GetProperty{\mymacro}{Esperanto}{\Errortext{\mymacro}{Esperanto}{Neniu traduko havebla.}}|\\
% This will raise an error:
\GetProperty{\mymacro}{Esperanto}{\Errortext{\mymacro}{Esperanto}{Neniu traduko havebla.}}

\end{document}

ingrese la descripción de la imagen aquí

información relacionada