TransWikia.com

A mode to produce a document in one language or the other

TeX - LaTeX Asked by Desiderius Severus on February 5, 2021

He is my issue: I need to keep many documents (CV, research statement, research projects, list of abstracts, etc.) updated and ready to be sent for applications, sometimes in quite a rush. However, depending on the place I send them to, the language change, and I keep translating again and again in one way or the other. I want to avoid it, and to stop juggling between many basically copies of the same content.

Is there a way to define a "mode" (say "English" or "German" or "French"), to write in a single file the content in both languages, e.g.

english{2020-2023: PhD student}
german{2020-2023: Doktorand}
french{2020-2023: Étudiant doctoral}

and to define at the top of the document the mode, e.g.

mode{english}

so that the printed pdf will consider only the required language entries (here, English)?

Basically, I will of course need to keep doing the translations and writing them, but it will be much more convenient to do for each bit of content that needs to be updated rather than rechecking the whole document to see if it is indeed the last version every time.

I would like it to be robust enough to e.g. keep working with beamers, moderncv, or any class or environment already existing.

3 Answers

The iflang package can do this.

documentclass[french,ngerman,english]{article}
usepackage{libertinus}
usepackage[main=french]{babel}
usepackage{iflang}

newcommandIfEnglish[1]{%
  IfLanguageName{english}%
                 {#1}%
                 {}%
  ignorespaces}

newcommandIfFrench[1]{%
  IfLanguageName{french}%
                 {#1}%
                 {}%
  ignorespaces}

newcommandIfGerman[1]{%
  IfLanguageName{german}%
                 {#1}%
                 {IfLanguageName{ngerman}%
                                 {#1}%
                                 {}}%
  ignorespaces}

begin{document}
section*{Curriculum Vitae}

noindentIfEnglish{2020--2023: PhD student}
IfFrench{2020--2023: Étudiant doctoral}
IfGerman{2020--2023: Doktorand}
end{document}

You can now switch by changing the main= option of babel, or by changing the options to the document class.

An alternative would be to provide translations in each language with the translator package. This has the advantage that it will always show the translated string once and only once, in either the current language or English, even if you leave a translation out by mistake or give one in the same language twice.

documentclass[french,ngerman,english]{article}
usepackage{libertinus}
usepackage[main=ngerman]{babel}
usepackage{translator}

providetranslation[to=English]{PHD student}{Ph.D. student}
providetranslation[to=French]{PHD student}{Étudiant doctoral}
providetranslation[to=German]{PHD student}{Doktorand}

begin{document}
section*{Curriculum Vitae}

noindent2020--2023: translate{PHD student}
end{document}

Answered by Davislor on February 5, 2021

If you are willing to use expl3's facilities for iterating keyval-lists, I can offer macros with keyval-syntax:


SelectLanguageString{⟨comma-separated ⟨language⟩=⟨string⟩-list⟩}

All those ⟨strings⟩ will be delivered whose ⟨language⟩ is currently selected.

If a ⟨string⟩ itself is to contain commas it can be nested in curly braces.

You can also specify the key other language=....
Strings belonging to that key will be delivered in case none of the ⟨languages⟩ where strings are specified is currently selected.


DefineLanguageSpecificMacro{⟨macro⟩}[⟨amount of parameters⟩][⟨1st optional argument's default-value⟩]{⟨comma-separated ⟨language⟩=⟨string⟩-list containing language-specific definition-texts⟩}

or

DefineLanguageSpecificMacro{⟨macro⟩}[][⟨parameter-text in plain-TeX-syntax⟩]{⟨comma-separated ⟨language⟩=⟨string⟩-list containing language-specific definition-texts⟩}

or

DefineLanguageSpecificMacro{⟨macro⟩}{⟨comma-separated ⟨language⟩=⟨string⟩-list containing language-specific definition-texts⟩}

⟨macro⟩ (with ⟨parameters⟩ if provided) will be defined from the ⟨definition-text⟩ whose ⟨language⟩ is currently selected.

Like above you can also specify the key other language=....

If you provide more than one ⟨definition-text⟩ for the currently selected ⟨language⟩ you will get an error-message.


documentclass[french,ngerman,english,spanish]{article}
usepackage{xparse}
usepackage{libertinus}
usepackage[main=french]{babel} % <- You get "french=..."-strings with SelectLanguageString and DefineLanguageSpecificMacro.
%usepackage[main=english]{babel} % <- You get "english=..."-strings with SelectLanguageString and DefineLanguageSpecificMacro.
%usepackage[main=german]{babel} % <- You get "german=..."-strings with SelectLanguageString and DefineLanguageSpecificMacro.
%usepackage[main=spanish]{babel} % <- As no "spanish=..."-strings are specified you get "other language=..."-strings with SelectLanguageString and DefineLanguageSpecificMacro.
usepackage{iflang}

ExplSyntaxOn
%-------------------------------------------------------------------------------------------------------------------
bool_new:N __SelectLanguageString_LanguageFound_bool
msg_new:nnnn {SelectLanguageString}{unknown-language}
              {No language  specified  for  string  `#1'}
              {You  need  to  specify  both  a  language  and  a  string  in  that  language}
msg_new:nnnn {DefineLanguageSpecificMacro}{unknown-language}
              {No language  specified  for  string  `#1'}
              {You  need  to  specify  both  a  language  and  a  string  in  that  language}
msg_new:nnnn {DefineLanguageSpecificMacro}{IncorrectParameterText}
              {Parameter-text-specification is incorrect}
              {Parameter-text can be specified as follows:
               LaTeX-Syntax:
              - first optional argument: amount of arguments
              - second optional argument: default in case 1st arg is optional
               plain-TeX-Syntax:
              - first optional argument: empty
              - second optional argument: plain-TeX parameter-text}
msg_new:nnnn {DefineLanguageSpecificMacro}{command-already-defined}
              { Command '#1' already defined! }
              {
                 You have used #2 
                 with a command that already has a definition.
                 The existing definition of '#1' will not be altered.
              }
msg_new:nnnn {DefineLanguageSpecificMacro}{string-already-specified}
              { String for language '#1' already specified! }
              {
                 You have used #2 with more than one definition text  for language '#1'.
                 Specify only one definition text per language.
                 '#3' will be defined from the first definition text specified.
              }
cs_new:Nn __SelectLanguageString_LanguageDetect:n {
  group_begin:
  cs_set:Nn  msg_error_text:n {Macro~exp_args:Nc token_to_str:N {##1}~Error}
  msg_error:nnx {SelectLanguageString}{unknown-language}{ exp_not:n {#1} }
  group_end:
}
cs_new:Nn __SelectLanguageString_Define_LanguageDetect:n {
  group_begin:
  cs_set:Nn  msg_error_text:n {Macro~exp_args:Nc token_to_str:N {##1}~Error}
  msg_error:nnx {DefineLanguageSpecificMacro}{unknown-language}{ exp_not:n {#1} }
  group_end:
}
cs_new:Nn __SelectLanguageString_LanguageDetect:nn { IfLanguageName{#1}{bool_set_true:N __SelectLanguageString_LanguageFound_bool}{} }
cs_new:Nn __SelectLanguageString_SelectLanguage:n {}
cs_new:Nn __SelectLanguageString_SelectLanguage:nn { IfLanguageName{#1}{__SelectLanguageString_MacroDefiner:nn{#1}{#2}}{} }
cs_new:Nn __SelectLanguageString_SelectOtherLanguage:n {}
cs_new:Nn __SelectLanguageString_SelectOtherLanguage:nn { str_if_eq:nnTF{#1}{other~language}{__SelectLanguageString_MacroDefiner:nn{#1}{#2}}{} }
cs_new:Nn__SelectLanguageString_MacroDefiner:nn { #2 }
cs_new:Nn__SelectLanguageString_DefineMacroDefiner:Nnn { 
  cs_set:Nx__SelectLanguageString_MacroDefiner:nn { 
     exp_not:n{tl_put_right:Nn l_tmpa_tl}{exp_not:n{__SelectLanguageString_CheckDefined:nnnnn}{##1}exp_not:n{{#3}{#1}{#2}}{##2}}  
  } 
}
cs_new:Nn __SelectLanguageString_CheckDefined:nnnnn{
  cs_if_exist:NTF{#3}{
    group_begin:
    cs_set:Nn  msg_error_text:n {Macro~exp_args:Nc token_to_str:N {##1}~Error}
    msg_error:nnxxx {DefineLanguageSpecificMacro}{string-already-specified}%
                     {tl_to_str:n{#1}}{token_to_str:N DefineLanguageSpecificMacro}{token_to_str:N #3}
    group_end:
  }{
    #2 #3 #4 {#5}
  }
}
cs_new:Nn __SelectLanguageString_SwapArgs:nn {#2#1}
%-------------------------------------------------------------------------------------------------------------------
% SelectLanguageString{%
%    key-val-list with texts for each language
% }%
NewDocumentCommand SelectLanguageString {m} {
  group_begin:
  bool_set_false:N __SelectLanguageString_LanguageFound_bool
  keyval_parse:NNn __SelectLanguageString_LanguageDetect:n __SelectLanguageString_LanguageDetect:nn {#1}
  bool_if:NTF __SelectLanguageString_LanguageFound_bool {
     group_end:
     keyval_parse:NNn __SelectLanguageString_SelectLanguage:n __SelectLanguageString_SelectLanguage:nn {#1}
  }{
     group_end:
     keyval_parse:NNn __SelectLanguageString_SelectOtherLanguage:n __SelectLanguageString_SelectOtherLanguage:nn {#1}
  }
}
%-------------------------------------------------------------------------------------------------------------------
% DefineLanguageDependentMacro{<macro>}{<parameters>}{%
%    key-val-list with definition-text for each language
% }%
NewDocumentCommand DefineLanguageSpecificMacro {mO{}om}{
  cs_if_exist:NTF{#1}{%
    group_begin:
    cs_set:Nn  msg_error_text:n {Macro~exp_args:Nc token_to_str:N {##1}~Error}
    msg_error:nnxx {DefineLanguageSpecificMacro}{command-already-defined}{token_to_str:N #1 }{ token_to_str:N DefineLanguageSpecificMacro }
    group_end:
  }{
    group_begin:
    bool_set_false:N __SelectLanguageString_LanguageFound_bool
    keyval_parse:NNn __SelectLanguageString_Define_LanguageDetect:n __SelectLanguageString_LanguageDetect:nn {#4}
    bool_if:NTF __SelectLanguageString_LanguageFound_bool {
       group_end:
       group_begin:
       tl_set:Nn l_tmpa_tl {group_end:}
       __SelectLanguageString_SwapArgs:nn{
         keyval_parse:NNn __SelectLanguageString_SelectLanguage:n __SelectLanguageString_SelectLanguage:nn {#4}
       }
    }{
       group_end:
       group_begin:
       tl_set:Nn l_tmpa_tl {group_end:}
       __SelectLanguageString_SwapArgs:nn{
         keyval_parse:NNn __SelectLanguageString_SelectOtherLanguage:n __SelectLanguageString_SelectOtherLanguage:nn {#4}
       }
    }
    {
      IfNoValueTF{#3}{
        str_case:nnTF{#2}{
          {0} {__SelectLanguageString_DefineMacroDefiner:Nnn #1 {} { cs_set_protected:Npn }}
          {1} {__SelectLanguageString_DefineMacroDefiner:Nnn #1 {##1} { cs_set_protected:Npn }}
          {2} {__SelectLanguageString_DefineMacroDefiner:Nnn #1 {##1##2} { cs_set_protected:Npn }}
          {3} {__SelectLanguageString_DefineMacroDefiner:Nnn #1 {##1##2##3} { cs_set_protected:Npn }}
          {4} {__SelectLanguageString_DefineMacroDefiner:Nnn #1 {##1##2##3##4} { cs_set_protected:Npn }}
          {5} {__SelectLanguageString_DefineMacroDefiner:Nnn #1 {##1##2##3##4##5} { cs_set_protected:Npn }}
          {6} {__SelectLanguageString_DefineMacroDefiner:Nnn #1 {##1##2##3##4##5##6} { cs_set_protected:Npn }}
          {7} {__SelectLanguageString_DefineMacroDefiner:Nnn #1 {##1##2##3##4##5##6##7} { cs_set_protected:Npn }}
          {8} {__SelectLanguageString_DefineMacroDefiner:Nnn #1 {##1##2##3##4##5##6##7##8} { cs_set_protected:Npn }}
          {9} {__SelectLanguageString_DefineMacroDefiner:Nnn #1 {##1##2##3##4##5##6##7##8##9} { cs_set_protected:Npn }}
          {} {__SelectLanguageString_DefineMacroDefiner:Nnn #1 {} { cs_set_protected:Npn }}
          {~} {__SelectLanguageString_DefineMacroDefiner:Nnn #1 {} { cs_set_protected:Npn }}
        }
      }{
        str_case:nnTF{#2}{
          {0} {__SelectLanguageString_DefineMacroDefiner:Nnn #1 {{+O{#3}}} {NewDocumentCommand}}
          {1} {__SelectLanguageString_DefineMacroDefiner:Nnn #1 {{+O{#3}}} {NewDocumentCommand}}
          {2} {__SelectLanguageString_DefineMacroDefiner:Nnn #1 {{+O{#3}+m}} {NewDocumentCommand}}
          {3} {__SelectLanguageString_DefineMacroDefiner:Nnn #1 {{+O{#3}+m+m}} {NewDocumentCommand}}
          {4} {__SelectLanguageString_DefineMacroDefiner:Nnn #1 {{+O{#3}+m+m+m}} {NewDocumentCommand}}
          {5} {__SelectLanguageString_DefineMacroDefiner:Nnn #1 {{+O{#3}+m+m+m+m}} {NewDocumentCommand}}
          {6} {__SelectLanguageString_DefineMacroDefiner:Nnn #1 {{+O{#3}+m+m+m+m+m}} {NewDocumentCommand}}
          {7} {__SelectLanguageString_DefineMacroDefiner:Nnn #1 {{+O{#3}+m+m+m+m+m+m}} {NewDocumentCommand}}
          {8} {__SelectLanguageString_DefineMacroDefiner:Nnn #1 {{+O{#3}+m+m+m+m+m+m+m}} {NewDocumentCommand}}
          {9} {__SelectLanguageString_DefineMacroDefiner:Nnn #1 {{+O{#3}+m+m+m+m+m+m+m+m}} {NewDocumentCommand}}
          {} {__SelectLanguageString_DefineMacroDefiner:Nnn #1 {#3} { cs_set_protected:Npn }}
          {~} {__SelectLanguageString_DefineMacroDefiner:Nnn #1 {#3} { cs_set_protected:Npn }}
        }
      }
      {}{
        cs_set:Nn  msg_error_text:n {Macro~exp_args:Nc token_to_str:N {##1}~Error}
        msg_error:nn {DefineLanguageSpecificMacro}{IncorrectParameterText}
      }
    }
    tl_use:N l_tmpa_tl
  }
}
ExplSyntaxOff

DefineLanguageSpecificMacro{SomeLanguageSpecificMacro}[1]{%
  english={This is in English and this is the argument: textbf{#1}},
  french={Ceci est en français et voici l'argument: textbf{#1}},
  german={Dies ist auf deutsch und das ist das Argument: textbf{#1}},
  other language={Ĉi tio estas en Esperanto kaj jen la argumento: textbf{#1}},
}%

begin{document}
section*{Curriculum Vitae}

noindent
texttt{stringSomeLanguageSpecificMacro: meaningSomeLanguageSpecificMacro}

bigskipnoindent
SomeLanguageSpecificMacro{Argument}

bigskipnoindent
2020--2023: SelectLanguageString{%
  english=PhD student,
  french=Étudiant doctoral,
  german=Doktorand,
  other language=Doktoriĝanto,
}%

end{document}

enter image description here

Answered by Ulrich Diez on February 5, 2021

Because the question is not explicitly concerned to LaTeX, I show what to do in another TeX format: OpTeX.

First alternative: you can map the language-dependent phrases to an identifier (phdstudent in the example below) and the you can run _mtext{identifier}. It expands to the language phrase depending on the current language:

sdef{_mt:phdstudent:en}{2020-2023: PhD student}
sdef{_mt:phdstudent:de}{2020-2023: Doktorand}
sdef{_mt:phdstudent:fr}{2020-2023: Étudiant doctoral}

enlang % default
_mtext{phdstudent}  % expands to 2020-2023: PhD student
frlang % another language
_mtext{phdstudent}  % expands to 2020-2023: Étudiant doctoral

Second alternative. You can swith between languages simply by ifnum:

longdefthreelangs#1#2#3{%
   ifnumlanguage=_enPatt #1fi
   ifnumlanguage=_dePatt #2fi
   ifnumlanguage=_frPatt #3fi
}

threelangs
   {2020-2023: PhD student}
   {2020-2023: Doktorand}
   {2020-2023: Étudiant doctoral}
% expands to the first or second or third parameter depending on
% the current language.

Answered by wipet on February 5, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP