%<*driver>
\def\packagename{langselect}

\def\nameofplainTeX{plain}
\ifx\fmtname\nameofplainTeX
\input l3docstrip.tex
\keepsilent
\askforoverwritefalse
\preamble

========================================================================
 Package langselect - generate documents in different languages
                      from a common source. This is a generated file.

 (C) 2022-2026 Matthias Werner
 E-mail: matthias.werner@informatik.tu-chemnitz.de

 Released under the LaTeX Project Public License v1.3c or later
 See http://www.latex-project.org/lppl.txt
======================================================================== 

\endpreamble
\postamble

This work is "maintained" (as per LPPL maintenance status) by
 Matthias Werner.
\endpostamble

\generate{
  \file{\packagename.sty}{\from{\packagename.dtx}{pkg}}
}
  \expandafter\endbatchfile
\fi

\iffalse
%</driver>
%<*pkg> 
\NeedsTeXFormat{LaTeX2e}[2022/06/01]
\def\packagename{langselect}
\ProvidesExplPackage{langselect}
{2026-09-18}
{v1.1.3}
{support for different languages versions from a common source}
\ExplSyntaxOff
%</pkg>
%<*driver>
\fi 
\documentclass[
load-preamble,
]{osgdoc}

\usepackage[
languages={de,en},
map={de=german,en=english},
targetlang={job=2},
load babel
]{langselect}
\usepackage{enumitem}

% --------------------------------------------------------------------
\makeindex
\def\packagename{langselect}
\def\thepkg{\pkg*{\packagename}}

\setcnltx{
  package  = langselect,
  version  = \UseVersionOf{\packagename.sty},
  date     = \UseDateOf{\packagename.sty},
  title    = {\ldeen{Das \pkg*{langselect}-Paket}{The \pkg*{langselect} Package}},
  info     = \ldeen{Generierung verschiedener Sprachversionen aus einer
    Quelle}{Generate different language versions from a common source}, 
  authors  = {Matthias Werner[matthias.werner@informatik.tu-chemnitz.de]},
  abstract={
    \ldeen{
      Dieses Paket unterstützt die Generierung von Dokumenten in zwei oder drei
      Sprachvarianten aus einem gemeinsamen 
      Quelldokument. Es wird ein entsprechendes Nutzermakro generiert und es
      gibt mehrere Methoden, die Zielsprache zu bestimmen.
      
      Das Paket gehört zum \bnd*{osglecture}-Bundle, wird in die \cls*{osglecture}-Klasse
      integriert und vom Buildscript \code{ollm} unterstützt, kann aber auch eigenständig
      genutzt werden.
    }{
      This package supports the generation of documents in two or three language
      versions from a common source document. A corresponding user macro is
      generated, and there are several methods for determining the target language.
      
      The package is part of the \bnd*{osglecture} bundle, is integrated into
      the \cls*{osglecture} class 
      and supported by the build script \code{ollm}, but can also be used independently.
    }
  },
  url      =https://github.com/werner-matthias/osglecture,
  build-title
}


\begin{document}
 
%\renewcommand{\packageformat}{\color{cnltxformalblue}\sffamily}
\section{\ldeen{Einleitung}{Introduction}}
\label{sec:intro}
\subsection{TL;DR}
\label{sec:tldr}
\ldeen{Angenommen Sie wollen von einen Text eine englische und ein
  deutsche Version erhalten, wobei Sie ein gemeinsames Quelldokument
  nutzen wollen.}{Assume, you have a text with an English and a German version whilst
  you want to use a common source}.
\begin{enumerate}
\item \ldeen*{Binden Sie @1 ein}{Include @1}{\cs{usepackage}\Oarg{languages=\Marg{en,de}}\Marg{langselect}}
\item \ldeen{Nutzen Sie im Quelldokument 
    \cs*{lende}\marg{Text$_{en}$}\marg{Text$_{de}$}. \meta{Text$_{en}$} wird in
    der englischen Version erscheinen, während \meta{Text$_{de}$} in der deutschen
    Version erscheinen wird.}{Use in the
  source \cs*{lende}\marg{text$_{en}$}\marg{text$_{de}$}. \meta{text$_{en}$} will
  appear in the Englisch version, whereas \meta{text$_{de}$} will appear in the German
  one.}
\begin{itemize}
\item \ldeen*{Text, der in beiden Versionen vorkommt, schreiben Sie außerhalb des
  Makros oder nutzen die Sternversion, um gemeinsame Daten im Fließtext nur
  einmal schreiben zu müssen, siehe Abschnitt~@1}{Write text that appears in
  both versions outside the macro or use the star version so that you only have
  to write common data in the body text once, see
  Section~@1}{\ref{sec:start-var}}.  
\end{itemize}
\item \ldeen*{Übersetzen Sie das Dokument mit @1, um die englische Version zu
    erhalten, und mit @2 für die deutsche.}{Translate the document with @1 to
    get the English version and with @2 for the German version.}{
    
    \centerline{\code{> latex
        "\cs*{def}\cs{olsTargetLanguage}\Marg{en}\cs{include}\marg{document}"}}
      
    }{

      \centerline{\code{> latex
          "\cs*{def}\cs{olsTargetLanguage}\Marg{de}\cs{include}\marg{document}"}}

    }
    
  \begin{itemize}
  \item \ldeen*{Es gibt noch einige andere Möglichkeiten,die Zielsprache zu
      bestimmen, u.\;a.\ über den Jobnamen und über @1}{There are several other
      ways to determine the target language, including via the job name and via
      @1}{\cs{DocumentMetadata}}. 
  \end{itemize}
\end{enumerate}
\subsection{Motivation}
\label{sec:motivation}
\ldeen{Mitunter werden mehrere Sprachversionen des gleichen Dokuments benötigt.
Im Anwendungsgebiet des \pkg*{osglecture}-Bündel sind dies beispielsweise die
Lehrskripte, Vorlesungsfolien und Handouts einer Lehrveranstaltung.
Es fällt häufig schwer, mehrere parallel existierende Sprachversionen konsistent zu halten.
Diese Aufgabe ist etwas einfacher, wenn alle Versionen in einem gemeinsamen
Quelldokument enthalten sind.

Dieses Paket unterstützt die Generierung solcher Sprachversionen aus einem
gemeinsamen \LaTeX-Quelldokument indem es Makros für Sprachvarianten und
Mechanismen zur Auswahl der Zielsprache bereitstellt.
}{
Sometimes, multiple language versions of the same document are required.
In the application area of the \pkg*{osglecture} bundle, these are, for example, the
lecture notes, lecture slides, and handouts for a course.
It is often difficult to keep multiple parallel language versions consistent.
This task is somewhat easier if all versions are contained in a common
source document.

This package supports the generation of such language versions from a
common \LaTeX\ source document by providing commands for language variants and
mechanisms for selecting the target language.
}

\subsection{\ldeen{Alternativen}{Alternatives}}
\label{sec:alternatives}
\ldeen{Es gibt eine Reihe von Alternativen zu \thepkg.}{The are a number of
  alternatives to \thepkg.}
\begin{description}
  \item [\ldeen{Adhoc-Makros}{Ad hoc commands}]\ldeen{Man kann relativ einfach adhoc Lösungen schaffen, wie z.\,B.}{It
      is relatively easy to create ad hoc solutions, such as the following}
    \begin{example}[code-only]
        \newif\ifenglish
        \englishtrue
        \ifenglish
            Welcome!
        \else
            ¡Bienvenido!
        \fi
    \end{example}
    \ldeen{
      Tatsächlich folgt \thepkg\ grundsätzlich diesem Ansatz, automatisiert aber die
      Erstellung der Sprachmakros, vereinfacht die gemeinsame Nutzung
      von nichtsprachabhängigen Elementen wie z.\,B. Formeln und ermöglicht die
      Auswahl der Sprachvariante über verschiedene Methoden.
    }{
      In fact, \thepkg\ basically follows this approach, but automates the
      creation of language commands, simplifies the sharing
      of non-language-dependent elements such as formulas, and enables the
      selection of the target language by different approaches.
    }
  \item[\pkg{multilang}]
    \ldeen{
      Das ausgeklügelte Paket \needpackage{multilang} von \name{Richard Grewe} erstellt
      Sprachversionen von gegebenen Makros, wobei die aktive Sprache direkt aus
      \pkg*{Babel} oder \pkg*{Polyglossia} übernommen wird.
      \thepkg\ hat ein ähnliches Ziel, aber ein anderes (aus Sicht des
      Paketautoren: praktischeres) Interface.
      Falls Sie aber den Ansatz von \thepkg\ nicht mögen, sollten Sie sich
      unbedingt \pkg*{multilang} anschauen.
    }{
      The sophisticated package \needpackage{multilang} by \name{Richard Grewe} creates
      language versions of given commands, whereby the active language is taken directly from
      \pkg*{Babel} or \pkg*{Polyglossia}.
      \thepkg\ has a similar goal, but a different (from the package author's
      point of view: more practical) interface. 
      However, if you don't like the approach of \thepkg\, you should definitely
      take a look at \pkg*{multilang}. 
    }
  \item[\pkg{comment}]
    \ldeen{
      \name{Victor Eijkhout} hat des Paket \needpackage{comment} geschrieben,
      das auf einfache Weise ermöglicht, nur bestimmte Abschnitte im Dokument
      auszugeben. Dies kann auch sehr gut für eine Sprachauswahl genutzt werden.
    }{
      \name{Victor Eijkhout} wrote the package \needpackage{comment},
      which makes it easy to output only certain sections of the document.
      This can also be used very well for language selection.
    }
  \item[\pkg{bicaption}/\allowbreak\pkg{translations}/\allowbreak\pkg{translator}/\allowbreak\pkg{xtcapts}]
    \ldeen*{
      Die Pakete @1      
      addressieren Programmierer von \LaTeX-Paketen, um fixe Textelemente wie
      die Überschriften von Verzeichnissen zu internationalisieren.
      Für Dokumentautoren sind diese Pakete nur bedingt geeignet.
    }{
      The packages @1 are intended for programmers of \LaTeX\ packages to internationalize fixed
      text elements such as the headings of tables of contents.
      These packages are only of limited use for document authors.
    }{\needpackage{bicaption}/\allowbreak\needpackage{translations}/\allowbreak%
    \needpackage{translator}/\allowbreak\needpackage{xtcapts}}
\end{description}
\subsection{\ldeen{Sprachen}{Languages}}
\label{sec:languages}
\ldeen{%
  Das Konzept von \thepkg\ beinhaltet die Nutzung von Sprachen auf verschiedenen
  Ebenen mit unterschiedlicher Wirkung. Um Verwechselungen zu vermeiden, wollen
  wir hier die Begriffe eindeutig definieren.
}{%
  The concept of \thepkg\ involves the use of languages at different
  levels with different effects. To avoid confusion, we want to
  clearly define the terms here.
}

\begin{enumerate}
  \item \ldeen*{
      Die Menge \emph{möglicher} Zielsprachen des Dokuments. Ein Dokument, das
      \thepkg\ nutzt, enthält typischerweise Textteile in verschiedenen
      Zielsprachen. Die möglichen Zielsprachen werden über eine Paketoption
      gesetzt, siehe Abbschnitt~@1. Im weiteren Text dieser Dokumentation
      nennen wir die \emph{möglichen} Zielsprachen \emph{Auswahlsprachen}, da für die
      \LaTeX-Übersetzung eine dieser Sprachen ausgewählt wird.
    }{
      The set of \emph{possible} target languages for the document. A document that
      uses \thepkg\ typically contains text sections in different target
      languages. The possible target languages are set via a package option, see
      Section~@1. In the remaining part of this documentation,
      we refer to the \emph{possible} target languages as \emph{selectable languages},
      since one of these languages is selected for the \LaTeX\ translation.
    }{\ref{sec:options}}
  \item
    \ldeen{%
      Die tatsächliche bei einer \LaTeX-Übersetzung gebrauchte Zielsprache.
      Diese muss eine der Sprachen aus 1. sein. Typischerweise wird der
      Übersetzungsvorgang für jede der tatsächlichen Zielsprachen einzeln
      ausgeführt.
      Für die Auswahl der tatsächlichen Zielsprache gibt es mehrere Methoden,
      siehe Abschnitt}{%
      The actual target language used in a LaTeX translation.
      This must be one of the languages from 1. Typically, the  translation
      process is performed separately for each of the actual target languages. 
      There are several methods for selecting the actual target language;  see
      section}~\ref{sec:targetlang}.
  \item
    \ldeen{
      Die Sprache, in der Textteile oder einzelne Wörter tatsächlich geschrieben
      sind und die beispielsweise bei der Worttrennung berücksichtigt wird.
      Dies ist das Konzept von Sprache, das Pakete wie Babel oder
      Polyglossia haben.\footnote{Wobei auch in diesen Pakten "`Sprache"' ebenfalls
        für mehrere unterschiedliche und z.\,T. voneinander unabhängige Konzepte
        wie Trennungsmuster, zu nutzende Fonts etc. steht}
      Bitte beachten Sie, dass ein mehrsprachiges Dokument aus der Sicht von
      \thepkg\ ein monosprachiges Dokument aus der Sicht von Babel sein kann.
      Häufig ist es aber eher umgekehrt, so dann durchaus noch weitere Sprachen
      als die Auswahlsprechen hinzukommen:
      Beispielsweise kann ein Dokument mit den Auswahlsprachen Deutsch und
      Englisch im Text lateinische Wörter oder Sätze enthalten.
      Diese Auswahl wird über die üblichen Mechanismen wie in
      \cs{selectlanguage}, \cs{foreignlanguage} oder \cs*{text}\meta{sprache}
      vorgenommen.
      Wenn Babel oder Polyglossia geladen wird, was auf Wunsch auch direkt über
      \thepkg\ erfolgen kann, wird als aktive Sprache die Zielsprache ausgewählt.
    }{
       The language in which text fragments or individual words are actually
       written, what is considered, e.\,g. for hyphenation.
       This is the concept of language used by packages such as Babel or
       Polyglossia.\footnote{However, in these packages, "`language"' also refers to
        several different and, in some cases, independent concepts such as
        hyphenation patterns, fonts to be used, etc.}
      Please note that a multilingual document from the perspective of
      \thepkg\ can be a monolingual document from the perspective of Babel.
      Frequently, it is the other way around, and more languages than the
      selectable languages are used:
      For example, a document with the selectable languages German and
      English may contain Latin words or sentences in the text.
      This selection is made using the usual mechanisms such as
      \cs{selectlanguage}, \cs{foreignlanguage} or \cs*{text}\meta{language}.
      When Babel or Polyglossia is loaded, which can also be done directly via
      \thepkg\ if desired, the target language is selected as the active language.
    }
\end{enumerate}
\ldeen{
  Sprachen werden in \thepkg\ über ISO 639-1-Codes (z.\,B. "`en"', "`fr"',
  "`de"', \ldots) bezeichnet.
  Wenn für die Sprachbehandlung auf der Ebene von Babel/Polyglossia ein
  bestimmter Dialekt oder eine bestimmte Variante gewünscht ist, kann ein
  Mapping erfolgen.
}{
  Languages are designated in \thepkg\ using ISO 639-1 codes ("`en"', "`fr"',
  "`de"' \ldots).
  If a specific dialect or variant is desired for language processing at the Babel/Polyglossia level,
  mapping can be performed.
}
\section{\ldeen{Anwendung}{Usage}}
\label{sec:usage}
\ldeen{Das Paket wird auf die übliche Weise geladen}{The package is loaded in
  the usual way}:

\centerline{\cs{usepackage}\oarg{options}\Marg{langselect}}

\noindent
\ldeen*{%
  Da die Auswahl der Zielsprache sowohl über Optionen als auch auf anderem Weg
  erfolgen kann, werden hier zunächst diese verschiedenen Wege beschrieben.
  Weitere Optionen wie das Setzen der Auswahlsprachen werden in Abschnitt~@1 besprochen.%
}{%
  Since the target language can be selected both via options and in other ways,
  these different methods are described here first.
  Further options, such as setting the selectable languages, are discussed in
Section~@1.%
}{\ref{sec:options}}
\subsection{\ldeen{Auswahl der Zielsprache}{Selection of the Target Language}}
\label{sec:targetlang}

\ldeen{%
  Um eine Zielsprache für einen \LaTeX-Übersetzungslauf zu bestimmen, gibt es verschiedene
  Möglichkeiten. Die Reihenfolge in der folgenden Liste spiegelt auch die
  Reihenfolge der Auswertung. Sobald damit eine Zielsprache ermittelt wird, wird
  eine weitere Auswertung abgebrochen.
}{%
  There are various ways to determine a target language for a LaTeX translation run.
  The order in the following list also reflects the order of evaluation.
  Once a target language has been determined, further evaluation is canceled.
}
\begin{enumerate}
  \item \ldeen{Definition eines Makros \cs{olsTargetLanguage} \emph{vor} Laden des
    Pakets. Damit ist es beispielsweise möglich, über}{Definition of a macro
    \cs{olsTargetLanguage} \emph{before} loading the package. This makes it
    possible, for example, to use}  
\begin{verbatim}
> latexmk -usepretex="\def\olsTargetLanguage{fr}" document.tex
\end{verbatim}
    \ldeen{die Zielsprache Französisch für den Übersetzungslauf festzulegen}{to
      set the target language French for the translation run}.
  \item \ldeen*{Setzen der Paketoption @1. Verschiedene Werte sind hier möglich}{Setting of
      the packet option @1. Various values are
      possible here}{\option{targetlang}}:
    \begin{options}
      \keyval-{targetlang}{\ldeen{ISO-Code}{ISO code}}
        \ldeen{Die Zielsprache wird direkt durch den Code angegeben.}{The target
          language is specified directly by the code.}
        
       \keychoice{targetlang}{\Marg{job=\meta{n}}}
         \ldeen{Die Zielsprache wird aus dem $n.$ Element des Jobnamens bestimmt.
           Ein Element ist ein mit "`-"' (Minus) abgetrennter Teil des Jobnamens, siehe
           die Dokumentation zum Paket \needpackage{varsfromjobname}, das dafür geladen
           wird.}{
           The target language is determined from the $n$th element of the job name.
           An element is a part of the job name separated by "`-"' (minus), see
           the documentation for the package \needpackage{varsfromjobname}, which is loaded
           for this purpose.
         }
        \ldeen{%
          Beispielsweise kann bei \keyis*{targetlang}{job=2} über 
        }{%
          For example, with \keyis*{targetlang}{job=2} one can set Russian as target
          language using
        }
\begin{verbatim}
> latex -jobname doc-ru doc.tex
\end{verbatim}
        \ldeen{
          Russisch als Zielsprache eingestellt werden.
        }{}
        \keychoice{targetlang}{babel,polyglossia}
        \ldeen{Für die Nutzung dieses Schlüsselwerts muss Babel oder Polyglossia
          \emph{vor} \thepkg\ geladen sein. Die 
          Zielsprache wird dann auf die durch das Sprachpaket eingestellte
          (Haupt-)Sprache gesetzt.}{To use this key value,
          Babel or Polyglossia must be loaded \emph{before} \thepkg. The
          target language is then set to the (main) language set by the language
          packet.}\footnote{\ldeen{Beide Werte bewirken exakt das Gleiche: Da
            Babel und Polyglossia die gleiche Schnittstelle anbieten, ist es
            egal, welches von beiden Paketen geladen
            ist. \keyis*-{targetlang}{polyglossia} findet also auch 
            Babel.}{Both values have exactly the same effect: Since Babel and
            Polyglossia offer the same interface, it doesn't matter which of the
            two packages is loaded. Thus, \keyis*-{targetlang}{polyglossia} will also find Babel.}}  
        \keychoice{targetlang}{meta}
        \ldeen{Die in \cs{DocumentMetadata} angegebene Sprache als Zielsprache verwendet.
        }{Uses the language specified in \cs{DocumentMetadata}  as the target language. }
    \end{options}
  \item \ldeen{Wenn weder \cs{olsTargetLanguage} definiert noch die Option
      \option{targetlang} gesetzt wird, versucht \thepkg\ selbständig die
      Zielsprache zu bestimmen, indem es erst die Option
      \keyis*-{targetlang}{babel} und dann (wenn kein Sprachpaket gefunden
      wurde) die Option \keyis*-{targetlang}{meta} ausprobiert.}{If neither
      \cs{olsTargetLanguage} is defined nor the option 
      \option{targetlang} is set, \thepkg\ attempts to determine the target
      language on its own by first trying the option \keyis*-{targetlang}{babel}
      and then (if no language package was found) the option
      \keyis*-{targetlang}{meta}.}
  \item \ldeen{Wenn alles andere versagt, wird die erste Auswahlsprache als Zielsprache
      gesetzt.}{If everything else fails, the first selectable languages is set as the 
      target language.}
\end{enumerate}
\subsection{\ldeen{Optionen}{Options}}
\label{sec:options}
\ldeen{Folgende Optionen stehen zur Verfügung}{The following options are available}:
\begin{options}
    \keyval{languages}{\ldeen{Liste von Auswahlsprachen}{list of selectable
        languages}}\Default!{}
    \ldeen*{Gibt zwei oder drei Auswahlsprachen an. Die Reihenfolge ist relevant
      für die automatische Generierung der Sprachmakros (siehe Abschnitt~@1).
    }{%
      Provides two or three selectable languages.
      The order matters for the automatic generation of the language commands
    (cf.\ Section~@1).
  }{\ref{sec:usermacros}}

  \keychoice{targetlang}{\meta{\ldeen{Sprache}{language}},\{job=\meta{n}\},babel,polyglossia,meta}%\Default{}
  \ldeen{Siehe Abbschnitt}{See Section}~\ref{sec:targetlang}

  \keyval{prefix}{prefix}\Default{l}
  \ldeen{Setzt einen Prefix für die Multisprachmakros. Es kann auch ein leerer
    Prefix gesetzt werden.}{Sets a prefix for multilingual commands. An empty
    prefix can also be set.}

  \keybool{auto}\Default{true}\ldeen*{Die eigentlichen Sprachmakros werden
    automatisch angelegt, siehe Abschnitt~@1. Wird \keyis*-{auto}{false}
    gesetzt, werden nur die Makros zur Erzeugung der Sprachmakros zur Verfügung
    gestellt, nicht die Sprachmakros selbst.}{The actual language commands are
    created automatically, see Section~@1. If \keyis*-{auto}{false}
    is set, only the commands for generating the language commands are provided, not
    the language commands themselves.}{\ref{sec:usermacros}}
  \keybool{trim}\Default{true}\ldeen{Enfernt Whitespaces am Anfang und Ende der
    Argumente der Sprachmakros.}{Removes whitespace at the beginning and end of
    language macro arguments.}
  \keyval{load babel}{Babel \ldeen{Optionen}{options}}\default{}
  \keyval{load polyglossia}{Polyglossia \ldeen{Optionen}{options}}
  \ldeen{Lädt entweder Babel oder Polyglossia so, dass die Zielsprache von
    \thepkg\ als Hauptsprache gesetzt wird. Die hier übergebenen Optionen werden
    an das jeweilige Sprachpaket weitergeleitet.
    Wenn hier Optionen angegeben werden, darf kein Sprachpaket vor \thepkg\ geladen 
    sein.
  }{%
    Loads either Babel or Polyglossia so that the target language of \thepkg is
    set as the main language. The options passed here are forwarded to the
    respective language package.
    If any option is provided, no language package must be loaded before \thepkg.
  }
  \keychoice{map}{\Marg{\meta{\ldeen{Sprache}{language}}=\meta{\ldeen{Variante}{variant}},\ldots}}
  \ldeen{Legt ein Mapping von Sprachen zu einer Sprachvariante fest. Wenn
    \thepkg\ mit anderen Paketen interagiert, wird dann die spezifische
    Sprachvariante statt des ISO-Codes weitergegeben.

    Falls Sie beispielsweise Babel von \thepkg\ aus laden und Ihr Dokument explizit
    \emph{Britisches} Englisch und \emph{Schweizerdeutsch} nutzt, sichern Sie
    mit folgendem Code ab, dass Babel korrekte Optionen erhält.
  }{%
    Defines a mapping of languages to a language variant. When
    \thepkg\ interacts with other packages, the specific
    language variant is passed instead of the ISO code.

    For example, if you load Babel from \thepkg\ and your document explicitly
    uses  \emph{British} English and \emph{Swiss} German, use the following
    code to ensure that Babel receives the correct options.}
   \begin{example}[code-only]
       \documentclass{article}
       \usepackage[
         languages={en,de},
         load=babel,
         map={en=british,de=nswissgerman}
       ]
       \begin{document}
        \title{\lende{Hallo}{Grüezi}}
    \end{example}
    \keybool{unified shorthands}\Default{true}\ldeen{Definiert
      sprachenübergreifende Shorthands zur Unterstützung von \pkg{csquotes}.}{Defines
      cross-language shorthands to support \pkg{csquotes}}

    \keybool{bcp47}\Default{true}\ldeen{Wenn Babel aktiv ist, sorgt
      \thepkg\ dafür, dass die von \thepkg\ genutzten ISO-Codes als
      Selektornamen für \cs{selectlanguage} funktionieren. Mit \keyis-{bcp47}{false} 
      muss die Babelzielsprache über \option{map} oder von Hand ausgewählt werden.
      Diese Option ist hat keine Wirkung, wenn Babel nicht geladen wird.
      }{
      When Babel is active, \thepkg\ makes the ISO codes used by \thepkg\
      work as selector names for \cs{selectlanguage}. In case of \keyis-{bcp47}{false}, 
      Babel's target language must be selected through \option{map} or by hand.
      This option has no effect if Babel is not loaded.
      }
\end{options}
   
\section{\ldeen{Nutzermakros}{User Commands}}
\label{sec:usermacros}
\subsection{\ldeen{Automatisch Sprachmakros}{Automatic Language Commands}}
\label{sec:automatic}
\ldeen{Wenn Sie nicht die Option \keyis-{auto}{false} gesetzt haben, wird ein
  Multisprachmakro angelegt. Dessen Name wird durch die Liste der Auswahlsprachen
  festgelegt. Je nachdem, ob Sie zwei oder mehr Auswahlsprachen angegeben haben,
  ist ist der Name}{If you have not set the option \keyis-{auto}{false}, a multilanguage command will be created.
  Its names is determined by the list of selection languages.
  Depending on whether you have specified two or more selection languages,
  the name is}
\begin{itemize}[nosep]
  \item \cs*{\meta{\ldeen{Prefix}{prefix}}\meta{\ldeen{Sprache}{language}$_{1}$}%
      \meta{\ldeen{Sprache}{language}$_{2}$}\marg{\ldeen{Text}{text}$_{1}$}\marg{\ldeen{Text}{text}$_{2}$}}
\end{itemize}
\ldeen{oder}{or}
\begin{itemize}[nosep]
  \item \cs*{\meta{\ldeen{Prefix}{prefix}}\meta{\ldeen{Sprache}{language}$_{1}$}%
      \meta{\ldeen{Sprache}{language}$_{2}$}\meta{\ldeen{Sprache}{language}$_{3}$}%
      \marg{\ldeen{Text}{text}$_{1}$}\marg{\ldeen{Text}{text}$_{2}$}\marg{\ldeen{Text}{text}$_{3}$}
    }
\end{itemize}
\ldeen{Beispielsweise wurde für diese Dokumentation das Paket mit folgenden
  Optionen geladen:}{For example, for this documentation, the package was loaded with the following
  options:}
\begin{example}[code-only]
    \usepackage[
      languages={de,en},
      targetlang={job=2}
    ]{langselect}
\end{example}
\ldeen*{
  Damit steht das Makro \cs*{ldeen\marg{Text$_{1}$}\marg{Text$_{1}$}} zur Verfügung.
  Wenn jetzt die Zielsprache "`de"' ausgewählt wird (hier über den Jobnamen,
  aber es gibt auch andere Möglichkeiten, vgl.\ Abschnitt~@1), wird nur
  \meta{Text$_{1}$} in das PDF-Dokument übernommen und \meta{Text$_{2}$}
  verworfen.
  Bei der Zielsprache "`en"' ist es umgekehrt.
}{This makes the command \cs*{ldeen} available.

  If the target language "`de"' is now selected (here via the job name,
  but there are also other options, see Section~@1), only
  \meta{Text$_{1}$} is transferred to the PDF document and \meta{Text$_{2}$}
  is discarded.
  With the target language "`de"', it is the other way
  around.}{\ref{sec:targetlang}}

\begin{warnbox}{\ldeen{Achtung}{Attention}!}
    \ldeen{Die automatische Generierung der Sprachmakros kann manchmal zu
      Problemen führen. Beispielsweise ergibt Abchasisch (Code: "`ab"' ) als Erst- und
      Griechisch (Code: "`el"') als Zweisprache den automatischen Namen \cs*{label}, was zu
      Fehlermeldungen führt. Nutzen Sie in solchen Fällen die im Abschnitt~\ref{sec:own-names}
      beschriebenen Möglichkeiten.}{The automatic generation of language commands can sometimes cause
      problems. For example, Abkhaz (code: "`ab"')  as the first language and
      Greek (Code: "`el"') as the second language results in the automatic name \cs*{label}, which leads to
      error messages. In such cases, use the features described in section~\ref{sec:own-names}.}
\end{warnbox}
\subsection{\ldeen{Sternvariante}{Starred Variant}}
\label{sec:start-var}
\ldeen{Ein häufiges Problem bei mehreren Sprachversionen ist die Konsistenz
  nichtsprachabhängiger Daten, insbesondere wenn diese Daten sich öfter
  ändern. (Denken Sie \zB\ an Stundenpläne.)
  
  Für solche Fälle stellt \thepkg\ eine Sternvariante der Sprachmakros bereit.
  In dieser Sternvariante können die Textargumente Platzhalter der Form
  "`@\meta{n}"' enthalten, wobei \meta{n} einen Wert zwischen $1$ und $9$
  darstellt.
  Hinter dem Makro müssen dann weitere Argumente angegeben werden, und zwar so
  viele, wie es dem höchsten verwendeten \meta{n} entspricht. Die Sternvariante
  ersetzt die Platzhalter mit den entsprechenden Argumenten.
}{A common problem with multiple language versions is the consistency of
  non-language-dependent data, especially if this data changes frequently
  (think, for example, of timetables).
  
  For such cases, \thepkg\ provides a starred variant of the language commands.
  In this starred variant, the text arguments can contain placeholders of the form
  "`@\meta{n}"' can be used, where \meta{n} represents a value between $1$ and $9$.

  Additional arguments must then be specified after the command, namely as many
  as correspond to the highest \meta{n} used. The starred variant
  replaces the placeholders with the corresponding arguments.
}
\begin{example}[
  compile,
  pages=1,
  graphics={trim=3cm 22cm 3cm 4cm,clip}]
      \documentclass{article}
      \usepackage[languages={en,fr},targetlang=fr]{langselect}
      \begin{document}
      \lenfr*{
        The formula @1 generally refers to the Pythagorean theorem.
      }{
        La formule @1 fait généralement référence au théorème de
      Pythagore.
      }{$a^{2}+b^{2}=c^{2}$}
    
      \lenfr*{
        Calculate the length of the third side if one side is @1 units long
        and the hypotenuse is @2 units long.
      }{
        Calculez la longueur du troisième
        côté si un côté mesure @1 unités et l'hypoténuse @2 unités.
      }{$4$}{$5$}  
      \end{document}
\end{example}
\ldeen{Die Sternvariante der Sprachmakros ist nicht vollständig expandierbar und sollte
  daher nicht in Kontexten verwendet werden, in denen vollständige Expandierbarkeit
  erforderlich ist. 
  Dies gilt insbesondere für PDF-Strings, wie sie \pkg{hyperref} für die Metadaten
  eines PDF-Dokuments benötigt. 
  Dort wählt \pkg{langselect} zwar die aktive Sprachfassung aus, Platzhalter wie 
  "`@\meta{n}"' werden jedoch nicht ersetzt, und die zugehörigen Ersetzungsargumente 
  bleiben im Eingabestrom erhalten. 
  Verwenden Sie in PDF-Strings daher nur die sternlose Form.
}{The starred variant of the language macros is not fully expandable and should
  therefore not be used in contexts where full expandability
  is required.
  This applies in particular to PDF strings, such as those required by \pkg{hyperref} 
  for the metadata of a PDF document.
  Although \pkg{langselect} selects the active language version there, placeholders such as
  “`@\meta{n}”' are not replaced, and the corresponding replacement arguments
  remain in the input stream.
  Therefore, use only the unstarred form in PDF strings.}
\subsection{\ldeen{Individuelle Sprachmakros}{Individual Language Commands}}
\label{sec:own-names}
\ldeen{Wenn Ihnen die generierten Namen der Sprachmakros nicht gefallen oder
  diese sogar zu Kollisionen führen, können Sie sie ändern. Am einfachsten ist
  es, die Paketoption \option{prefix} zu ändern, so dass beispielsweise mit
  \keyis-{prefix}{mv} das Sprachmakro für die Deutsch/Englisch-Kombination
  \cs*{mvdeen} heisst.}{If you do not like the generated names of the language
  commands or if they even lead to collisions, you can change them. The easiest
  way is to change the package option \option{prefix} so that, for example, with
  \keyis-{prefix}{mv}, the language command for the German/English combination
  is called \cs*{mvdeen}.}

\ldeen{Wenn dies nicht ausreichend ist, geben Ihnen die folgenden zwei Makros die
  vollständige Kontrolle über die Namensbildung.}{If this is not sufficient, the
  following two commands give you complete control over the naming.}
\begin{commands}
    \command{olsMakeBilangualMacro}[\oarg{\ldeen{P}{p}refix}\marg{\ldeen{Sprache}{lang}$_{1}$}\marg{\ldeen{Sprache}{lang}$_{2}$}\oarg{\ldeen{Basisname}{base
        name}}]\default{}% Missuse to eat additional newline
    \command{olsMakeTrilangualMacro}[\oarg{\ldeen{P}{p}refix}\marg{\ldeen{Sprache}{lang}$_{1}$}\marg{\ldeen{Sprache}{lang}$_{2}$}\marg{\ldeen{Sprache}{lang}$_{3}$}\oarg{\ldeen{Basisname}{base
        name}}]
    \ldeen{Diese Makros legen ein bilinguales bzw.\ trilinguales Sprachmakro für
    die angegbenen Sprachen an. Wenn \meta{Basisname} angegeben wird, ist der
    Name des Sprachmakros \cs*{\meta{Prefix}\meta{Basisname}}. Wenn das
    \meta{Prefix}-Argument benutzt wird, bestimmt dieses den Prefix, sonst
    gelten die Paketoptionen.}{These commands create a bilingual or trilingual language command for
    the specified languages. If \meta{base name} is specified, the
    name of the language command is \cs*{\meta{prefix}\meta{base name}}. If the
    \meta{prefix} argument is used, it determines the prefix; otherwise,
    the package options apply.}
\end{commands}
\section{\ldeen{Interaktion mit anderen Paketen}{Interaction with  Other Packages}}
\label{sec:other-pkg}
\subsection{Babel/Polyglossia}
\label{sec:babel}
\ldeen{Das Paket \thepkg\ ist zunächst einmal unabhängig von Sprachpaketen wie
  Babel oder Polyglossia. Es kann ohne oder neben diesen Paketen eingesetzt werden.
  Wenn man sich jedoch die Mühe eines mehrsprachigen Dokuments macht, will man
  in der Regel auch, dass für die jeweilige Sprache die richtigen
  Trennungsregeln, Fonteinstellungen, Datumsformate etc.\ benutzt werden.%
}{%
  The \thepkg\ package is initially independent of language packages such as Babel
  or Polyglossia. It can be used without or together with these
  packages. However, if you take the trouble to create a multilingual document,
  you will usually also want the correct hyphenation rules, font settings, date
  formats, etc.\ to be used for the respective language.}\footnote{\ldeen{Im
    Folgenden werde ich mich ausschließlich auf Babel beziehen. Das Gesagte gilt
    jedoch entsprechend auch für Polyglossia.}{In the following, I will refer
    exclusively to Babel. However, what has been said also applies accordingly
    to Polyglossia.}} 

\ldeen{Bitte beachten Sie, dass, solange Sie nicht \emph{innerhalb} eines Textes
  eine andere Sprache (vielleicht ja die Sprache der anderen Sprachversion)
  nutzen, ihr Dokument aus der Sicht von Babel ein
  \emph{einsprachiges} Dokument ist. Wenn Sie Babel auf die gewohnte Weise mit
  allen Sprachen ihrer Sprachversion laden, würde Babel als aktive Sprache aber
  die zuletzt genannte (oder die per \option{main} gesetzte) wählen, was nicht
  unbedingt die Zielsprache von \thepkg\ ist. Ohne spezielle Maßnahmen könnten Sie
  so falsche Trennungen und ähnliche Fehler erhalten.
}{%
  Please note that as long as you do not use a different language \emph{within} a text
  (perhaps the language of the other language version), your document is, from
  the perspective of Babel, a \emph{monolingual} document. If you load Babel in
  the usual way with all the languages of your language version, Babel would
  pick the last one listed (or the one set via \option{main}) as its active
  language -- not necessarily the target language of \thepkg. Without a
  countermeasure you could end up with incorrect hyphenation and similar
  errors.
}

\ldeen{Um dies zu vermeiden, bieten \thepkg\ verschiedene
  Möglichkeiten}{To avoid this, \thepkg\ offers several options}:
\begin{enumerate}
  \item \ldeen{Sofern die Zielsprache nicht ohnehin aus Babel abgeleitet wird,
      wählt \thepkg\ sie zu Dokumentbeginn selbst als aktive Sprache aus. Bei
      aktivem Babel wird dafür dessen BCP-47-Zuordnung eingeschaltet (Option
      \option{bcp47}), so dass die von \thepkg\ genutzten ISO-Codes als
      Selektornamen genügen und die Auswahlsprachen einfach mit ihren
      Babel-Namen geladen werden können. 
      Wenn sie spezielle Sprachvarianten möchten, können sie diese über die \option{map}-Option 
      wählen, die aber für den Standardfall nicht notwendig ist.}{Unless the target language is derived from
      Babel anyway, \thepkg\ selects it as the active language itself at the
      start of the document. When Babel is active it enables Babel's BCP~47
      mapping for this (option \option{bcp47}), so that the ISO codes used by
      \thepkg\ suffice as selector names and the selectable languages can simply
      be loaded under their Babel names. 
      A \option{map} entry is then only needed for named variants.}
  \item \ldeen{Wie oben erwähnt, kann man die Paketoption
      \keyis-{targetlang}{babel} nutzen. Dann wird die Zielsprache durch die
      Hauptsprache von Babel bestimmt. Allerdings muss man dann auf die
      Möglichkeit verzichten, die Zielsprache "`von außen"' (also über 
      den Jobnamen oder mit \cs{olsTargetLanguage}) zu steuern.
      }{
      As mentioned above, you can use the package option \keyis-{targetlang}{babel}.
      Then the target language is determined by the main language of Babel.
      However, you then have to forego the option of controlling the target language
      "`from outside"' (i.e., via the job
      name or with \cs{olsTargetLanguage}).} 
  \item \ldeen{Umgekehrt lädt \thepkg\ Babel oder Polyglossia mit Hilfe der
      Optionen \option{load babel}"/\option{load polyglossia} und setzt
      die Zielsprache als Hauptsprache. Weitere Optionen an die Sprachpakete
      werden als Optionsargument übergeben.}{In turn, \thepkg\ loads Babel or
      Polyglossia using the options \option{load babel}"/\option{load polyglossia} and sets
      the target language as the main language. Additional options for the
      language packages are passed as option arguments.}
  \item \ldeen{Schließlich kann mit den beiden Hooks \code{langselect}/"\code{language}/"\code{before}
      und \code{langselect}"/\code{language}"/\code{after} beliebiger Code
    vor bzw.\ nach Ausgabe der Argumente des Sprachmakros eingefügt werden. 
    Hier kann z.\,B.\ \cs{foreignlanguage} genutzt werden.
    Der \code{before}-Hook hat als Parameter die Zielsprachenvariante.}{Finally, the hooks
    \code{langselect}"/\code{language}"/\code{before} and \code{langselect}"/\code{language}"/\code{after}
    can be used to insert any code before or after the arguments of the language macro. E.g.,
    \cs{foreignlanguage} may be used here.
    The \code{before} hook has the (mapped) target language as a parameter.}
\end{enumerate}
\subsection{Csquotes}
\label{sec:csquote}
\ldeen{Unterschiedliche Sprachen haben unterschiedliche Konventionen zur Setzung
  von Satzzeichen. Besonders stört dies bei Anführungszeichen, da diese der
  Zielsprache folgen sollen, aber durchaus auch außerhalb der Sprachmakros oder
  in Argumenten der Sternvariante stehen können.
  Das Paket \needpackage{csquotes} bietet dafür eine Lösung, indem es \cs{enquote}
  und andere Makros anbietet, die der Zitatkonvention der aktuellen Sprache folgen.

  Zur Erhöhung der Bequemlichkeit unterstützt \thepkg\ die Nutzung korrekter
  Anführungszeichen mit sprachunabhängigen Shorthands:
  Wenn die Option \option{unified shorthands} wahr ist, wird \pkg{csquotes}
  geladen und die Shorthands \code{"{}`} und \code{"{}'} auf \cs{openautoquote}
  bzw.\ \cs{closeautoquote} gesetzt.

  Damit werden diese Shorthands in Sprachen wie Deutsch, wo sie bereits definiert
  sind, überschrieben.
}{Different languages have different conventions for punctuation.
  This is particularly problematic with quotation marks, as these should follow the
  target language, but may also appear outside language macros or
  in arguments of the asterisk variant.
  The \needpackage{csquotes} package offers a solution for this by providing \cs{enquote}
  and other macros that follow the quotation convention of the current language.

  For added convenience, \thepkg\ supports the use of correct
  quotation marks with language-independent shorthands: If the option
  \option{unified shorthands} is true, \pkg{csquotes} is loaded and the
  shorthands \code{"{}`} and \code{"{}'} are set to \cs{openautoquote} and
  \cs{closeautoquote}, respectively.}  
\section{FAQ}
\label{sec:faq}
\begin{itemize}
  \item \textbf{\ldeen{Ist \thepkg\ stabil?}{Is \thepkg\ stable?}}
  
    \ldeen*{Obwohl das Paket mittlerweile die Versionsnummer 1 erreicht 
      hat\footnote{Übrigens als einziges Paket im \bnd{osglecture}-Bundle}
      und zumindest beim Autor intensiv im Einsatz ist, kann ich nicht versprechen, 
      dass es soweit fehlerfrei ist, dass es das Attribut "`stabil"' verdient.
      Ich bitte darum, gefundene Fehler über @1 zu melden.
    }{ 
      Although the package has now reached version 1 
      \footnote{Incidentally, it is the only package in the \bnd{osglecture} bundle}
      and is in heavy use—at least by the author—I cannot promise 
      that it is bug-free enough to deserve the "`stable"' label.
      Please report any bugs you find via @1.     
    }{\url{https://github.com/werner-matthias/osglecture/issues}}
  \item \textbf{\ldeen{Wofür steht das "`o"' im \cs*{ols}-Prefix?}{What does the
        "`o"' in the \cs*{ols} prefix stand for?}}
    
    \ldeen{Das Paket gehört zu Bundle \bnd{osglecture}, von dort ist das
      "`o"' geerbt.}{The package belongs to the \bnd{osglecture} bundle,
      from which the "`o"' is inherited.}
  \item \textbf{\ldeen{Gibt es Anwendungsbeispiele, die über ein Toy-Hello-World
        hinausgehen?}{Are there any application examples that go beyond a toy
        Hello World?}}
    
    \ldeen{Ja, einige. Gucken Sie doch mal zum Beispiel in den Quelltext dieser
      Dokumentation.}{Yes, a few. Take a look at the source code of this
      documentation, for example.} 
    
  \item \textbf{\ldeen{Ich habe ein @1 in der Ausgabe, wo doch eine
        Argumentersetzung stattfinden sollte.}{I have an @1 in the output where an
        argument substitution should take place.}}

    \ldeen*{Das hat in der Regel eine der beiden folgenden Ursache:
      \begin{enumerate}[nosep]
        \item Sie nutzen alte Version (@1) von \pkg{langselect}. 
        Dort konnten unterschiedliche Catcodes z.\;B.\ durch \cs{makeatletter} zu Problemen führen.
        \item Sie haben den Stern im Sprachmakro vergessen.
      \end{enumerate}
    }{This usually has one of the following two causes:
      \begin{enumerate}[nosep]
        \item You are using an old version (@1) of \pkg{langselect}. In that version, different catcodes-—for example, those generated by \cs{makeatletter}-—could cause problems.
        \item You forgot the asterisk in the language macro.
      \end{enumerate}}{$\leq$ v0.6.0}
    
  \item \textbf{\ldeen{Kann ich in der Sternversion einen @$n$-Parameter in
        einer Sprachversion
        auslassen?}{Can I omit an @$n$ parameter in the starred version for one language?}}

    \ldeen{Nein. Außerdem wäre dann das Argument ja auch offensichtlich nicht
      mehr gemeinsam.}{No. Besides, then the argument would obviously no longer be
      shared.}
    
  \item \textbf{\ldeen{Kann ich @$n$-Parameter in gemischter Reihenfolge oder mehr als
        einmal verwenden?}{Can I use @$n$ parameters in mixed order or more than
        once?}}

    \ldeen{Ja}{Yes}.

  \item \textbf{\ldeen{Ich möchte @ in einer Sternvariante des Sprachmacros
        verwenden, aber nicht als Parameter.}{I want to use @, but not as a parameter, in a
        star variant of the language macro.}} 

    \ldeen{Dann machen Sie es.}{Just do it.}

  \item  \textbf{\ldeen{Aber ich brauche @{}42.}{But I need @{42}.}}

    \ldeen*{Nutzen Sie @1}{Use @1}{\code{@\{\}42}}.
   
  \item \textbf{\ldeen{Ich nutze Russisch, aber der Font ist nicht richtig.}{I
        use Russian, but the font is incorrect.}}

    \ldeen*{Das ist keine Problem von \thepkg\ (das kümmert sich gar nicht um den
      Font), sondern wahrscheinlich von Babel, \pkg{fontenc}, \pkg{fontspec},
      etc. Aber vielleicht können die Hooks für Sie nützlich sein, siehe Abschnitt~@1}{This is not a problem with \thepkg\ (which does not deal with the 
      font at all), but probably with Babel, \pkg{fontenc}, \pkg{fontspec},
      etc. But maybe you find the hooks useful, cf.\ section~@1}{\ref{sec:babel}}.

    
  \item \textbf{\ldeen{Meine Frage erscheint hier nicht.}{My question does not
        appear here.}}

    \ldeen*{Sie können Sie unter @1 stellen.}{You may ask at @1.}
      {\url{https://github.com/werner-matthias/osglecture/issues}}

    
\end{itemize}
\section{Implementation}
\AutoDocInput{langselect.dtx}{pkg}

\printindex

\end{document}
%</driver>
%<*pkg>
\ExplSyntaxOn
% \ldeen{\cs{olsIsoTags} enthält alle gültigen ISO
% 639-1-Codestags.}{\cs{olsIsoTags} contains all valid ISO 639-1 code tags.}
\seq_const_from_clist:cn{olsIsoTags}{aa,ab,ae,af,ak,am,an,ar,as,av,ay,az,ba,be,
  bg,bh,bi,bm,bn,bo,br,bs,ca,ce,ch,co,cr,cs,cu,cv,cy,da,de,dv,dz,ee,el,en,eo,es,
  et,eu,fa,ff,fi,fj,fo,fr,fy,ga,gd,gl,gn,gu,gv,ha,he,hi,ho,hr,ht,hu,hy,hz,ia,id,
  ie,ig,ii,ik,io,is,it,iu,ja,jv,ka,kg,ki,kj,kk,kl,km,kn,ko,kr,ks,ku,kv,kw,ky,la,
  lb,lg,li,ln,lo,lt,lu,lv,mg,mh,mi,mk,ml,mn,mr,ms,mt,my,na,nb,nd,ne,ng,nl,nn,no,
  nr,nv,ny,oc,oj,om,or,os,pa,pi,pl,ps,pt,qu,rm,rn,ro,ru,rw,sa,sc,sd,se,sg,si,sk,
  sl,sm,sn,so,sq,sr,ss,st,su,sv,sw,ta,te,tg,th,ti,tk,tl,tn,to,tr,ts,tt,tw,ty,ug,
  uk,ur,uz,ve,vi,vo,wa,wo,xh,yi,yo,za,zh,zu} 

\newcommand\IfTagIsValidF[2]{%
  \seq_if_in:ceF{olsIsoTags}{#1}{#2}
}
\RequirePackage{varsfromjobname}[2025/08/03]
% \ldeen{Das Ergebnisse von \cs{varsfromjobname}\ und \cs*{str\_range:Nnn} haben
% Catcode 12, aber ISO-Tags und Optionen haben Catcode 11. Wir vereinheitlichen
% durch einen Wrapper auf Catcode 11.}{The results of \cs{varsfromjobname}\
% and \cs*{str\_range:Nnn} have catcode 12, but ISO tags and options have catcode
% 11. We standardize using a wrapper on catcode 11.} 
\newcommand\olsChangeCatEleven[1]{
  \def\tmpa{#1} 
  \edef\tmpb{
    \noexpand\scantokens{
      \noexpand\edef\noexpand\olsCatElven{\tmpa}
    }
  }
  \tmpb
}
% \ldeen{Bei Bedarf bilden wir Spachcode auf Sprachvarianten ab. Bei
% Interaktionen mit externen Code wird dann die Sprachvariante weitergegeben.}{If
% necessary, we map language codes to language variants. When interacting with 
% external code, the language variant is then passed on.} 
\cs_new:Npn \ols_use_map:n #1 {
  \cs_if_exist_use:cF { olslangmap / #1 }{ #1 }
}
% \ldeen*{\cs{ols\_babel\_name\_from\_ini:nN} liest das Feld @1
% aus @2, das mehrere Babel-Namen für dieselbe Sprache
% enthalten kann. Häufig sind das nur alternative Bezeichnungen für das Gleiche. 
% Für Deutsch gibt es aber zwei tatsächlich verschiedene Rechtschreibungen
% (\code{german} = alte, \code{ngerman} = reformierte Orthographie). Ist 
% \code{ngerman} unter den Kandidaten, wird es deshalb bevorzugt (heutiger Standard 
% für Deutsch). Ansonsten wird der letzte Eintrag verwendet.
% Falls jemand, der sich mit den Sprachen besser auskennt als ich, eine weitere
% notwendigen SOnderfall entdeckt: Bitte ein entsprechendes Issue aufmachen.  }{%
% \cs{ols\_babel\_name\_from\_ini:nN} reads the field @1 from @2, which may
% contain multiple Babel names for the same language.
% Often, these are simply alternative names for the same thing.
% For German, however, there are two distinct orthographies
% (\code{german} = old, \code{ngerman} = reformed orthography). If \code{ngerman}
% is among the candidates, it is therefore preferred (today’s standard for German).
% Otherwise, the last entry is used. If anyone who is more familiar with languages 
% than I am discovers another necessary special case: Please open a corresponding issue.
% }{\code{name.babel}}{\File{babel-\meta{Code}.ini}}
\ior_new:N \g_ols_ini_ior
\seq_new:N \ols_ini_seq
\seq_new:N \ols_ini_names_seq
\cs_new_protected:Npn \ols_babel_name_from_ini:nN #1 #2
  {
    \tl_clear:N #2
    \ior_open:NnT \g_ols_ini_ior { babel- #1 .ini }
      {
        \ior_str_map_inline:Nn \g_ols_ini_ior
          {
            \str_if_eq:eeT { \str_range:nnn {##1} {1} {10} } { name.babel }
              {
                \seq_set_split:Nnn \ols_ini_seq { = } { ##1 }
                \seq_set_split:Nne \ols_ini_names_seq { ~ }
                  { \tl_trim_spaces:e { \seq_item:Nn \ols_ini_seq {2} } }
                \seq_if_empty:NF \ols_ini_names_seq
                  {
                    \seq_if_in:NeTF \ols_ini_names_seq { \tl_to_str:n {ngerman} }
                      { \tl_set:Nn #2 { ngerman } }
                      { \tl_set:Ne #2 { \seq_item:Nn \ols_ini_names_seq {-1} } }
                  }
                \ior_map_break:
              }
          }
        \ior_close:N \g_ols_ini_ior
      }
% \ldeen{Zeilen aus \cs*{ior\_str\_map\_inline} haben Catcode~12. Babel
% vergleicht Sprachoptionen mit \cs*{ifx} (catcode-empfindlich), daher machen wir
% aus dem Namen wieder Buchstaben mit Standard-Catcodes.}{Lines from
% \cs*{ior\_str\_map\_inline} have catcode~12. Babel compares language options
% with \cs*{ifx} (catcode sensitive), so we turn the name back into letters with
% standard catcodes.}
    \tl_if_empty:NF #2 { \tl_set_rescan:NnV #2 { } #2 }
  }
% \ldeen{Babel hat eine (in den verschiedenen Versionen unterschiedlich sortierte)
% Liste von Sprachennamen. Deshalb gehen wir zur "`Konkurrenz"' und nutzen in
% \cs{ols\_babel\_name\_from\_polyglossia:nN} \pkg*{polyglossia}s 
% \file{gloss-\meta{Code}.ldf}-Dateien als Datenquelle: diese
% enthalten für die Sprachen mit mehreren Babel-Namen (wie Deutsch) ein
% explizites \code{babelname}-Feld mit einem einzigen, eindeutigen Wert.
% \pkg*{polyglossia} selbst wird dabei nicht geladen, nur seine Textdateien
% werden wie schon bei \cs{ols\_babel\_name\_from\_ini:nN} zeilenweise
% eingelesen.}{%
% Babel has a list of language names (sorted differently in the various versions).
% That is why we turn to the “`competition”' and use 
% \cs{ols\_babel\_name\_from\_polyglossia:nN} \pkg*{polyglossia}s
% \File{gloss-\meta{Code}.ldf} files as our data source: for
% languages with multiple Babel names (such as German), these
% contain an explicit \code{babelname} field with a single, unique value.
% \pkg*{polyglossia} itself is not loaded for this; its text files are just
% read line by line, the same way \cs{ols\_babel\_name\_from\_ini:nN} already
% does.}
\tl_new:N \ols_ini_module_tl
\seq_new:N \ols_ini_regex_seq
\cs_new_protected:Npn \ols_babel_name_from_polyglossia:nN #1 #2
  {
    \tl_clear:N #2
    \tl_clear:N \ols_ini_module_tl
    \ior_open:NnT \g_ols_ini_ior { gloss- #1 .ldf }
      {
        \ior_str_map_inline:Nn \g_ols_ini_ior
          {
            \regex_extract_once:nnN { InheritGlossFile\{([a-zA-Z]+)\} } {##1} \ols_ini_regex_seq
            \seq_if_empty:NF \ols_ini_regex_seq
              {
                \tl_set:Ne \ols_ini_module_tl { \seq_item:Nn \ols_ini_regex_seq {2} }
                \ior_map_break:
              }
          }
        \ior_close:N \g_ols_ini_ior
      }
% \ldeen{Der Modulname selbst ist der Babel-Name, sofern die Zieldatei kein
% eigenes \code{babelname} definiert -- das betrifft die meisten Sprachen,
% bei denen Polyglossia- und Babel-Name ohnehin identisch sind.}{The module
% name itself is the Babel name unless the target file defines its own
% \code{babelname} -- true for most languages, where the Polyglossia and
% Babel names coincide anyway.}
    \tl_if_empty:NF \ols_ini_module_tl
      {
        \ior_open:NnT \g_ols_ini_ior { gloss- \ols_ini_module_tl .ldf }
          {
            \ior_str_map_inline:Nn \g_ols_ini_ior
              {
                \regex_extract_once:nnN { babelname\s*=\s*([a-zA-Z]+) } {##1} \ols_ini_regex_seq
                \seq_if_empty:NF \ols_ini_regex_seq
                  {
                    \tl_set:Ne #2 { \seq_item:Nn \ols_ini_regex_seq {2} }
                    \ior_map_break:
                  }
              }
            \ior_close:N \g_ols_ini_ior
          }
        \tl_if_empty:NT #2 { \tl_set_eq:NN #2 \ols_ini_module_tl }
      }
    \tl_if_empty:NF #2 { \tl_set_rescan:NnV #2 { } #2 }
  }
% \ldeen{\cs{ols\_babel\_name:nN} versucht zuerst \pkg*{polyglossia}s
% eindeutige Angabe und fällt nur, wenn diese fehlt (etwa weil
% \pkg*{polyglossia} in der genutzten Installation gar nicht vorhanden ist,
% oder für eine Sprache ohne eigene \file{gloss}-Datei), auf Babels eigene,
% mitunter mehrdeutige \file{.ini}-Liste zurück.}{%
% \cs{ols\_babel\_name:nN} tries \pkg*{polyglossia}'s unambiguous entry
% first, and only falls back -- e.g.\ because \pkg*{polyglossia} isn't
% installed at all, or a language has no \file{gloss} file of its own -- to
% Babel's own, sometimes ambiguous \file{.ini} list.}
\cs_new_protected:Npn \ols_babel_name:nN #1 #2
  {
    \ols_babel_name_from_polyglossia:nN {#1} #2
    \tl_if_empty:NT #2 { \ols_babel_name_from_ini:nN {#1} #2 }
  }
% \ldeen{Wir definieren einige Optionen. Alle außer \option{languages} sind
% optional. Einige Ergebnisse werden wir in Variablen spreichern, die wir zuerst
% anlegen.}{We define some options. All except \option{languages} are
% optional. We will store some results in variables that we first create.}
\bool_new:N\ols_load_babel
\bool_new:N\ols_load_polyglossia
% \ldeen{Wahr, wenn die Zielsprache aus dem aktiven Sprachpaket abgeleitet
% wurde. Dann ist dessen Hauptsprache bereits die Zielsprache und darf nicht
% erneut (womöglich mit einem Code statt eines Sprachnamens) ausgewählt
% werden.}{True when the target language was derived from the active language
% package. Its main language then already is the target language and must not be
% selected again (possibly with a code instead of a language name).}
\bool_new:N\ols_target_from_langpkg
\DeclareKeys{
  languages.clist_gset:N = \ols_langs,
  languages.usage=load,
  targetlang.code = {
% \ldeen*{Die Option @1 wird nur ausgewertet, wenn die Zielsprache nicht bereits
% durch Definition von @2 gesetzt wurde.}{The option @1 will be only evaluated
% in case, the target language isn't already set by definiton of
% @2}{\option{targetlang}}{\cs{olsTargetLanguage}}.     
      \cs_if_exist:NF\olsTargetLanguage{
% \ldeen{Wird ein Element des Jobnames angegeben}{Is an element of the jobname given}?  
      \bool_if:nT{                     
        \str_if_eq_p:ee{\str_range:nnn{#1}{1}{3}}{job}
      }{%
        \olsChangeCatEleven{\getfromjobname{\str_range:Nnn{#1}{-1}{-1}}}
        \xdef\olsTargetLanguage{\olsCatElven}
      }
% \ldeen*{Soll die Zielsprache von @1 oder @2 abgeleitet werden}{Should the
% target language be derived from @1 or @2}{\pkg{babel}}{\pkg{polyglossia}}?      
      \bool_if:nT{
        \str_if_eq_p:nn{#1}{babel} || \str_if_eq_p:nn{#1}{polyglossia}
      }{
        \str_if_eq:eeF{\BCPdata{main.language}}{}{
          \edef\olsTargetLanguage{\BCPdata{main.language}}
          \bool_set_true:N\ols_target_from_langpkg
        }
      }
% \ldeen{Soll die Sprache aus dem Metadaten genutzt werden}{Should the language
% of the meta data be used}?      
      \str_if_eq:nnTF{#1}{meta}{
        \IfDocumentMetadataTF{
          \edef\tmpa{\GetDocumentProperty{document/lang}}
          \edef\tmpb{\str_range:Nnn\tmpa{1}{2}}
          \olsChangeCatEleven{\tmpb}
          \edef\olsTargetLanguage{\olsCatElven}
        }{
          \PackageWarningNoLine{\packagename}{No~meta~data~provided}
        }
      }
    }
% \ldeen{Wenn bisher noch keine Sprache zugewiesen wurde, wird das Argument als
% Sprache angenommen. Es wird später überprüft, ob es gültig ist}{If no language
% is assigned by now, the argument is assumed to be the language. We check
% later, whether it is valid}.    
    \cs_if_exist:NF \olsTargetLanguage {
      \edef\olsTargetLanguage{#1}
    }
  },
% \ldeen{Prefix für die Nutzer-Sprachbefehle}{Prefix of the user language commands}.
  targetlang.usage=load,
  prefix.store=\ols_sprefix,
  prefix.initial:n=l,
  prefix.usage=load,
% \ldeen{Automatische Erzeugung der Sprachbefehle}{Automatic generation of the
% language commands}?  
  auto.bool_set:N=\ols_generate,
  auto.usage=load,
  auto.initial:n=true,
% \ldeen{Automatische Entfernung von Randleerzeichen}{Automatic removal of
% heading and trailing spaces}?  
  trim.bool_set:N=\ols_trim,
  trim.usage=load,
  trim.initial:n=true,
% \ldeen{Abbildung auf Sprachvarianten}{Mapping to language variants}.
  map.code:n = {
    \prop_new:N \ols_lang_pl
    \prop_clear:N \ols_lang_pl
    \prop_set_from_keyval:Nn \ols_lang_pl {#1}
% \ldeen{Da Property-Listen nicht expandierbar sind, setzen wir die Einträge auf
% gewöhnlich Makros um.}{Since property lists cannot be expanded, we convert the
% entries to ordinary macros.} 
    \prop_map_inline:Nn \ols_lang_pl
      { \cs_gset:cpn { olslangmap / \tl_to_str:n {##1} } {##2} }
    },
% \ldeen*{Laden von @1 oder @2 mit Optionen. Ein leerer Wert (\code{load~babel}
% ohne \code{=}) \textbf{darf nicht} als leere Option weitergereicht werden.}{Load @1 or
% @2 with options. An empty value (\code{load~babel} without \code{=}) \textbf{must not}
% be forwarded as an empty option.}{\pkg{babel}}{\pkg{polyglossia}}
  load~babel .code:n = {
    \bool_set_true:N \ols_load_babel
    \tl_if_empty:nF {#1} { \PassOptionsToPackage{#1}{babel} }
  },
  load~polyglossia .code:n = {
    \bool_set_true:N \ols_load_polyglossia
    \tl_if_empty:nF {#1} { \PassOptionsToPackage{#1}{polyglossia} }
  },
  load.usage = load,
  unified~shorthands.bool_set:N=\ols_shorthands,
  unified~shorthands.initial:n=true,
  unified~shorthands.usage=load,
% \ldeen{Sollen die von \thepkg\ genutzten ISO-Codes bei einem aktiven
% \pkg{babel} als BCP-47-Selektornamen zugelassen werden}{Should the ISO codes
% used by \thepkg\ be accepted as BCP~47 selector names by an active
% \pkg{babel}}?
  bcp47.bool_set:N=\ols_bcptags,
  bcp47.initial:n=true,
  bcp47.usage=load
}%
\ProcessKeyOptions\relax
% \ldeen{Wenn über \cs{olsTargetLanguage} oder die \option{targetlang} keine
% Zielsprache zugewiesen wurde, untersuchen wir noch einmal, ob über
% Sprachpakete oder \cs{DocumentMetadata} eine Sprache identifiziert werden kann.
% }{If no target language has been assigned via \cs{olsTargetLanguage} or \option{targetlang},
% we check again whether a language can be identified via
% language packages or \cs{DocumentMetadata}.}
\cs_if_exist:NF \olsTargetLanguage {
  \str_if_eq:eeF{\BCPdata{main.language}}{}{
    \edef\olsTargetLanguage{\BCPdata{main.language}}
    \bool_set_true:N\ols_target_from_langpkg
  }
}
\cs_if_exist:NF \olsTargetLanguage {
  \IfDocumentMetadataT{
    \edef\tmpa{\GetDocumentProperty{document/lang}}
    \edef\tmpb{\str_range:Nnn\tmpa{1}{2}}
    \olsChangeCatEleven{\tmpb}
    \edef\olsTargetLanguage{\olsCatElven}
  }
}
% \ldeen{
% Wir führen verschiedene Checks durch.}{We are doing some checks.}
% \ldeen{Sind mindestes zwei Auswahlsprachen angegeben?}{Are at least two
% selectable languages specified?}
\int_compare:nNnT{\clist_count:N{\ols_langs}} < {2}{
  \PackageError{\packagename}{No~sufficient~number~of~selectable
    \MessageBreak~languages~provided}{
    You~have~to~provide~a~list~of~two~or~three\MessageBreak
    languages~via~'language'~option.}
  \aftergroup\endinput      
}
% \ldeen{%
% Im Moment kann \thepkg\ nicht mehr als drei Auswahlsprachen verarbeiten. Wir
% warnen daher, wenn mehr als drei Sprachen angegeben werden.}{%
% Currently, \thepkg\ can't process more than three languages. Thus, we issue a
% warning if the list of selectable languages contrains more than three languages.
%}
\int_compare:nNnT{\clist_count:N\ols_langs} > {3}{
  \PackageWarningNoLine{\packagename}{Too~many~selectable~languages~provided.
    \MessageBreak I~will~ignore~the~superflous~languages}
}
% \ldeen{Als nächstes überprüfen wir, ob alle Auswahlsprachen gültige ISO
% 639~1 Codes sind.}{Next, we test the validity of the selectable
% languages. They should form ISO~693-1 codes.} 
\clist_map_inline:Nn\ols_langs {
  \IfTagIsValidF{#1}{
    \PackageError{\packagename}{Couldn't~resolve~selectable~language~'#1'}{
      Use~valid~ISO-639-1~code~in~option~'languages'.}
    \aftergroup\endinput
  }
}
% \ldeen{Nun prüfen wir, ob eine valide Zielsprache ermittelt werden konnte.
% }{Now we check whether a valid target language could be determined.}
\cs_if_exist:NF \olsTargetLanguage {
  \PackageWarningNoLine{\packagename}{Can't~identify~any~target~language.
    \MessageBreak Falling~back~to~'\clist_item:Nn \ols_langs {1}'}
  \edef\olsTargetLanguage{\clist_item:Nn \ols_langs {1}}}
\IfTagIsValidF{\olsTargetLanguage}{
  \PackageWarningNoLine{\packagename}{Do~not~recognize~language~'\olsTargetLanguage'.
    \MessageBreak Take~'\clist_item:Nn \ols_langs {1}'~as~replacement}
  \edef\olsTargetLanguage{\clist_item:Nn \ols_langs {1}}
}
% \ldeen{Die Zielsprache sollte in der Liste von Auswahlsprachen enthalten
% sein.}{The list of selectable languages should include the target language.}
\clist_if_in:NVF\ols_langs{\olsTargetLanguage}{
  \PackageError{\packagename}{Target~language~'\olsTargetLanguage'~is~not\MessageBreak
    in~the~list~of~selectable~languages}{
    Check~option~'language'~and~'targetlang'.}
}
% \ldeen{Babel und Polyglossia können nicht beiden geladen werden.}{Babel and
% Polyglossia cannot both be loaded.} 
\bool_if:nT{
  \ols_load_babel && \ols_load_polyglossia
}{
  \bool_set_false:N \ols_load_babel
  \bool_set_false:N \ols_load_polyglossia
  \PackageError{\packagename}{The~options~'load~babel'~and~'load~polyglossia'
    \MessageBreak are~mutual~exclusive,~you~can't~use~both}{Use~one~load~option,~only.}
}
% \ldeen*{Wenn bereits ein Sprachpaket aktiv ist, wird @1/@2 nicht selbst geladen.
% Die Zielsprache wird später aktiviert.}{If a language package is already active, 
% we don't load @1/@2 ourselves. The target language is activated 
% later.}{\pkg{babel}}{\pkg{polyglossia}}
\bool_if:nT{
  ( \cs_if_exist_p:c{ver@babel.sty} || \cs_if_exist_p:c{ver@polyglossia.sty} )
  &&
  ( \ols_load_babel || \ols_load_polyglossia )
}{
  \bool_set_false:N \ols_load_babel
  \bool_set_false:N \ols_load_polyglossia
  \PackageWarningNoLine{\packagename}{Can't~load~babel/polyglossia~for
    ~you,since\MessageBreak
    a~language~package~is~already~loaded.\MessageBreak
    I'll~ignore~that~option}
}
% \ldeen*{@1 ist die Bezeichnung der Zielsprache, wie sie ggf.\ an
% externen Code weitergegeben wird, d.,h. \cs{DocumentMetadata}, Sprachpakete
% und Hooks.}{@1 is the name of the target language as it is
% passed on to external code, if applicable, i.e. \cs{DocumentMetadata},
% language packs, and hooks.}{\cs{ols\_mapped\_target\_lang}}
\edef\ols_mapped_target_lang{\ols_use_map:n{\olsTargetLanguage}}
% \ldeen{Jetzt sollte die Zielsprache feststehen. Wir geben die Informationen
% ins Log.}{The target language should now be determined. We write the
% information into the log.}
\PackageNoteNoLine{\packagename}{Target~language~is~'\olsTargetLanguage'~(\ols_mapped_target_lang)}
% \ldeen{Wir korrigieren noch ggf.\ die über \cs{DocumentMetadata} gesetzen
% Metadaten auf die der Zielsprache, so dass beispielsweise Babel
% keine falsche Hauptsprache ableitet.
% }{%
% If needed, we correct the language metadata set by \cs{DocumentMetadata}.
% Now, Babel (for example) does not derive a wrong main language.
% }
\IfDocumentMetadataT{
  \edef\olsDocLang{\exp_args:Ne\str_range:nnn{\GetDocumentProperty{document/lang}}{1}{2}}
  \bool_if:nF{
    \str_if_eq_p:ee{\olsDocLang}{\olsTargetLanguage} 
  }{
    \PackageWarningNoLine{\packagename}{Target~language~'\olsTargetLanguage'~
      doesn't~comply~with\MessageBreak \c_backslash_str
      DocumentMetadata~'\GetDocumentProperty{document/lang}'.\MessageBreak
      I'll~try~to~overwrite~the~meta~data}
    \AddToDocumentProperties[document]{lang}{\olsTargetLanguage} 
  }
}
% \ldeen{Da der Name des Sprachmakros nicht bekannt ist, sind das Patchen oder
% generische Hooks komplizierter. Wir stellen deshalb eigene Hooks zur
% Verfügung.}{Since the name of the language macro is unknown, patching or
% generic hooks are more complicated. We therefore provide our own hooks.} 
\NewHookWithArguments{langselect/language/before}{1}
\NewReversedHook{langselect/language/after}
\NewHookWithArguments{langselect/argument}{2}
% \ldeen{Ein Boolean zur Markierung, ob mehr als zwei Auswahlsprachen angegeben
% wurden.}{A Boolean to indicate whether more than two selectable languages have
% been specified.} 
\bool_new:c{ols_trilang}
\int_compare:nNnTF{\clist_count:N{\ols_langs}} > {2}{
  \bool_set_true:c{ols_trilang}
}{
  \bool_set_false:c{ols_trilang}
}
\def\olsFrstLanguage{\clist_item:Nn \ols_langs{1}}
\def\olsScndLanguage{\clist_item:Nn \ols_langs{2}}
\bool_if:cT{ols_trilang}{
  \def\olsThrdLanguage{\clist_item:Nn \ols_langs{3}}
}
\bool_if:NTF\ols_trim{
  \let\ols_trim:n=\tl_trim_spaces:n
}{
  \let\ols_trim:n=\relax
}
% \ldeen*{Wenn @1 existiert (also die @2-Umgebung definiert ist), wird das Sprachmakro
%  dafür registriert.}{If @1 exists (i.e., the @2 environment is defined), the language macro
%  is registered for it.}{\cs{DeclarePresInitialBranchingCommand}}{\env{presitemize}}
\cs_new_protected:Npn \ols_register_pres_initial_branching:cn #1#2
  {
    \cs_if_exist:NTF \DeclarePresInitialBranchingCommand
      {
        \exp_args:Nc \DeclarePresInitialBranchingCommand {#1} {#2}
      }
      {
        \AddToHook { package/osglecture-presitemize/after }
          {
            \exp_args:Nc \DeclarePresInitialBranchingCommand {#1} {#2}
          }
      }
  }

% \ldeen{Für PDF-Strings registrieren wir eine vereinfachte Fassung jedes
% Sprachmakros bei \pkg{hyperref}. Sie konsumiert auch einen Stern, wählt aber
% lediglich den aktiven Sprachzweig und führt weder Hooks noch Ersetzungen aus.}
% {For PDF strings, we register a simplified version of every language macro
% with \pkg{hyperref}. It also consumes a star, but only selects the active
% language branch and runs neither hooks nor replacements.}
\cs_new_protected:Npn \ols_register_pdfstring_bilingual:cn #1#2
  {
    \AddToHook { package/hyperref/after }
      {
        \pdfstringdefDisableCommands
          {
            \int_compare:nNnTF {#2} = {1}
              {
                \ExpandArgs{c}\RenewExpandableDocumentCommand {#1}
                  {s +m +m} {##2}
              }
              {
                \ExpandArgs{c}\RenewExpandableDocumentCommand {#1}
                  {s +m +m} {##3}
              }
          }
      }
  }
\cs_new_protected:Npn \ols_register_pdfstring_trilingual:cn #1#2
  {
    \AddToHook { package/hyperref/after }
      {
        \pdfstringdefDisableCommands
          {
            \int_case:nn {#2}
              {
                {1}
                  {
                    \ExpandArgs{c}\RenewExpandableDocumentCommand {#1}
                      {s +m +m +m} {##2}
                  }
                {2}
                  {
                    \ExpandArgs{c}\RenewExpandableDocumentCommand {#1}
                      {s +m +m +m} {##3}
                  }
                {3}
                  {
                    \ExpandArgs{c}\RenewExpandableDocumentCommand {#1}
                      {s +m +m +m} {##4}
                  }
              }
          }
      }
  }
% \ldeen{Die Makros \cs{olsMakeBilangualMacro} bzw.\ \cs{olsMakeTrilangualMacro}
% dienen zur Generierung der eigentlichen Sprachmakros.}{The commands
% \cs{olsMakeBilangualMacro} and \cs{olsMakeTrilangualMacro}, resp., 
% are used to generate the actual language commands.}\par
% \#1: prefix, \#2,\#3: selectable languages, \#4: base name
\NewDocumentCommand{\olsMakeBilangualMacro}{O{\ols_sprefix} m m o}{
  \str_if_eq:eeT{\olsTargetLanguage}{#2} {
    \IfValueTF{#4}{
      \ExpandArgs{c}\NewExpandableDocumentCommand{#1#4}{s +m +m}{
        \UseHook{langselect/language/before}{\ols_mapped_target_lang}
        \IfBooleanTF{##1}{
          \ols_trim:n{\olsProcessArgs{##2}}
        }{
          \ols_trim:n{##2}
          \UseHook{langselect/language/after}
        }
        
      }
    }{
      \ExpandArgs{c}\NewExpandableDocumentCommand{#1#2#3}{s +m +m}{
        \UseHook{langselect/language/before}{\ols_mapped_target_lang}
        \IfBooleanTF{##1}{
          \ols_trim:n{\olsProcessArgs{##2}}
        }{
          \ols_trim:n{##2}
          \UseHook{langselect/language/after}
        }
      }
    }
  }
  \str_if_eq:eeT{\olsTargetLanguage}{#3}{
    \IfValueTF{#4}{
      \ExpandArgs{c}\NewExpandableDocumentCommand{#1#4}{s +m +m}{
        \UseHook{langselect/language/before}{\ols_mapped_target_lang}
        \IfBooleanTF{##1}{
          \ols_trim:n{\olsProcessArgs{##3}}
        }{
          \ols_trim:n{##3}
          \UseHook{langselect/language/after}
        }
      }
    }{
      \ExpandArgs{c}\NewExpandableDocumentCommand{#1#2#3}{s +m +m}{
        \UseHook{langselect/language/before}{\ols_mapped_target_lang}
        \IfBooleanTF{##1}{
          \ols_trim:n{\olsProcessArgs{##3}}
        }{
          \ols_trim:n{##3}\UseHook{langselect/language/after}
        }
      }
    }
  }
  \IfValueTF{#4}
    {
      \ols_register_pres_initial_branching:cn {#1#4} {2}
      \str_if_eq:eeTF {\olsTargetLanguage} {#2}
        { \ols_register_pdfstring_bilingual:cn {#1#4} {1} }
        { \ols_register_pdfstring_bilingual:cn {#1#4} {2} }
    }
    {
      \ols_register_pres_initial_branching:cn {#1#2#3} {2}
      \str_if_eq:eeTF {\olsTargetLanguage} {#2}
        { \ols_register_pdfstring_bilingual:cn {#1#2#3} {1} }
        { \ols_register_pdfstring_bilingual:cn {#1#2#3} {2} }
    }
}
% \ldeen{Nun das Gleiche nochmal für \emph{drei} Sprachen.}{Now do the same
% thing again for \emph{three} languages.}\\ 
% \#1: prefix, \#2...\#4: selectable languages, \#5: base name
\NewDocumentCommand{\olsMakeTrilangualMacro}{O{\ols_sprefix} m m m o}{
  \str_if_eq:eeT{\olsTargetLanguage}{#2} {
    \IfValueTF{#5}{
      \ExpandArgs{c}\NewExpandableDocumentCommand{#1#5}{s +m +m +m}{
        \UseHook{langselect/language/before}{\ols_mapped_target_lang}
        \IfBooleanTF{##1}{
          \ols_trim:n{\olsProcessArgs{##2}}
        }{
          \ols_trim:n{##2}
          \UseHook{langselect/language/after}
        }
      }
    }{
      \ExpandArgs{c}\NewExpandableDocumentCommand{#1#2#3#4}{s +m +m +m}{
        \UseHook{langselect/language/before}{\ols_mapped_target_lang}
        \IfBooleanTF{##1}{
          \ols_trim:n{\olsProcessArgs{##2}}
        }{
          \ols_trim:n{##2}
          \UseHook{langselect/language/after}
        }
      }
    }
  }
  \str_if_eq:eeT{\olsTargetLanguage}{#3} {
    \IfValueTF{#5}{
      \ExpandArgs{c}\NewExpandableDocumentCommand{#1#5}{s +m +m +m}{
        \UseHook{langselect/language/before}{\ols_mapped_target_lang}
        \IfBooleanTF{##1}{
          \ols_trim:n{\olsProcessArgs{##3}}
        }{
          \ols_trim:n{##3}
          \UseHook{langselect/language/after}
        }
      }
    }{
      \ExpandArgs{c}\NewExpandableDocumentCommand{#1#2#3#4}{s +m +m +m}{
        \UseHook{langselect/language/before}{\ols_mapped_target_lang}
        \IfBooleanTF{##1}{
          \ols_trim:n{\olsProcessArgs{##3}}
        }{
          \ols_trim:n{##3}
          \UseHook{langselect/language/after}
        }
      }
    }
  }
  \str_if_eq:eeT{\olsTargetLanguage}{#4} {
    \IfValueTF{#5}{
      \ExpandArgs{c}\NewExpandableDocumentCommand{#1#5}{s +m +m +m}{
        \UseHook{langselect/language/before}{\ols_mapped_target_lang}
        \IfBooleanTF{##1}{
          \ols_trim:n{\olsProcessArgs{##4}}
        }{
          \ols_trim:n{##4}
          \UseHook{langselect/language/after}
        }
      }
    }{
      \ExpandArgs{c}\NewExpandableDocumentCommand{#1#2#3#4}{s +m +m +m}{
        \UseHook{langselect/language/before}{\ols_mapped_target_lang}
        \IfBooleanTF{##1}{
          \ols_trim:n{\olsProcessArgs{##4}}
        }{
          \ols_trim:n{##4}
          \UseHook{langselect/language/after}
        }
      }
    }
  }
  \IfValueTF{#5}
    {
      \ols_register_pres_initial_branching:cn {#1#5} {3}
      \str_if_eq:eeTF {\olsTargetLanguage} {#2}
        { \ols_register_pdfstring_trilingual:cn {#1#5} {1} }
        {
          \str_if_eq:eeTF {\olsTargetLanguage} {#3}
            { \ols_register_pdfstring_trilingual:cn {#1#5} {2} }
            { \ols_register_pdfstring_trilingual:cn {#1#5} {3} }
        }
    }
    {
      \ols_register_pres_initial_branching:cn {#1#2#3#4} {3}
      \str_if_eq:eeTF {\olsTargetLanguage} {#2}
        { \ols_register_pdfstring_trilingual:cn {#1#2#3#4} {1} }
        {
          \str_if_eq:eeTF {\olsTargetLanguage} {#3}
            { \ols_register_pdfstring_trilingual:cn {#1#2#3#4} {2} }
            { \ols_register_pdfstring_trilingual:cn {#1#2#3#4} {3} }
        }
    }
}
% \ldeen{Falls die automatische Erzeugung nicht deaktivert ist, werden die
% konkreten Sprachmakros angelegt. Die Namen sind
% \cs*{\meta{Prefix}\meta{Sprache$_{1}$}\meta{Sprache$_{2}$}}
% bzw. \cs*{\meta{Prefix}\meta{Sprache$_{1}$}\meta{Sprache$_{2}$}\meta{Sprache$_{3}$}}.}{%
% If automatic generation is not disabled, the
% specific language commands are created. The names are
% \cs*{\meta{prefix}\meta{language$_{1}$}\meta{language$_{2}$}}
% or \cs*{\meta{prefix}\meta{language$_{1}$}\meta{language$_{2}$}\meta{language$_{3}$}}.
% }
\bool_if:cTF{ols_generate}{
  \bool_if:cTF{ols_trilang}{
    \olsMakeTrilangualMacro{\olsFrstLanguage}{\olsScndLanguage}{\olsThrdLanguage}
  }{
    \olsMakeBilangualMacro{\olsFrstLanguage}{\olsScndLanguage}
  }
}{
  \PackageInfoNoLine{\packagename}{No~language~macros~generated.\MessageBreak
  Use~\string\olsMakeBilangualMacro~or~\string\olsMakeTrilangualMacro~to~generate.}
}
% \ldeen{Für die Sternvarianten der Sprachmakros legen wir uns ein Makro an,
% das die folgenden Argumente verarbeitet.}{For the starred variants of the
% language commands, we create a command that processes the subsequent
% arguments.}
\seq_new:N \ols_args_seq 
\int_new:N \ols_num_of_args
\tl_new:N \ols_format_str_tl
\NewDocumentCommand \olsProcessArgs { +m } {
  \tl_gset:Nn \ols_format_str_tl{#1\UseHook{langselect/language/after}}
  \int_zero:N \ols_num_of_args
% \ldeen*{Suche den höchsten Wert @1, für den @@1 im Formatstring vorkommt.}{Find
% the highest value @1, where @@1 is contained in the format string.}{$n$}  
  \int_step_inline:nnnn { 9 } { -1 } { 1 }
  {
    \regex_if_match:nnT {@##1}{ #1 }
    {
      \int_set:Nn \ols_num_of_args { ##1 } \prg_break:
    }
  }
% \ldeen{Wenn kein Platzhalterzeichen gefunden wurde, gib den Text in
% Originalform aus. Ansonsten wird das Ersetzungmakro gerufen.}{If no
% placeholder character is found, output the text in 
% original form. Otherwise, the replacement command is called.}  
  \int_compare:nNnTF {\ols_num_of_args} = { 0 }
  { #1 }{
    \seq_clear:N \ols_args_seq
    \ols_collect_replace:n \ols_num_of_args
  }
}
% \ldeen*{@1 erhält \emph{ein} Argument übergeben, nämlich die Anzahl der
% verbleibenden Ersetzungstexte. Es konsumiert aber \emph{zwei}
% Argumente. Dieses zweite holt es sich aus dem nach dem Makro liegenden
% Tokenstrom, wo es den jeweilig nächsten Ersetzungstext findet.
% Dieser wird in einer Tokensequenz gespeichert und @1 erneut aufgerufen.
% }{
% @1 receives \emph{one} argument, namely the number of remaining replacement
% texts. However, it consumes \emph{two} arguments. It obtains the second one
% from the token stream following the command, where it finds the next replacement
% text. This is stored in a token sequence and @1 is called again.}{\cs{ols\_collect\_replace}}
\cs_new_protected:Npn \ols_collect_replace:n #1 #2{
  \IfHookEmptyTF{langselect/argument}{
    \seq_put_right:Nn \ols_args_seq { #2 }
  }{
    \seq_put_right:Nn \ols_args_seq {
      \UseHook{langselect/argument}{\ols_mapped_target_lang}{#2}
    }
  }
  \int_compare:nNnTF { #1 } = { 1 }
  {
% \ldeen{Wenn alle Ersetzungstexte eingelesen wurden, werden sie nacheinander
% auf die Platzhalterausdrücke angewendet.}{Once all replacement texts have been
% read in, they are applied one after the other 
% to the placeholder expressions.}
    \seq_map_indexed_inline:Nn \ols_args_seq
    {
      \tl_set:Nn \ols_replacement_tl { ##2 }

      \regex_replace_all:nnN
      { @##1 }
      { \u{ols_replacement_tl} }
      \ols_format_str_tl
    }
    \ols_format_str_tl
  }{
    \ols_collect_replace:n { \int_eval:n { #1 - 1 } }
  }
}
% \ldeen*{Wenn gewünscht, lädt \thepkg\ Babel und setzt die Zielsprache als
% Hauptsprache. Babel erwartet dafür Sprachnamen, keine ISO-Codes. Für jede
% Auswahlsprache ohne \option{map}-Eintrag wird der Name deshalb ermittelt
% und als impliziter Map-Eintrag hinterlegt -- auch wenn @1 selbst nicht
% gesetzt ist, aber @2 oder @3 aktiv sind, denn dann brauchen die
% BCP-47-Anbindung bzw.\ @4 weiter unten dieselben Einträge. Nur wenn @1 oder
% @3 gesetzt ist und kein Name ermittelt werden kann, gibt es einen Fehler;
% ist nur @2 gesetzt, bleibt eine unauflösbare Sprache einfach unangetastet,
% Babel entscheidet dann wie ohne \thepkg.
% }{If requested, \thepkg\ loads Babel and sets the target language as the
% main language. Babel expects language names, not ISO codes. For every
% selectable language without a \option{map} entry the name is therefore
% determined and stored as an implicit map entry -- even if @1 itself isn't
% set but @2 or @3 are active, since the BCP-47 hookup and @4 further below
% then need the same entries. Only if @1 or @3 is set and no name can be
% determined is there an error; if only @2 is set, an unresolvable language
% is simply left alone, and Babel decides as it would without \thepkg.}
% {\option{load babel}}{\option{bcp47}}{\option{load polyglossia}}
% {\cs{setdefaultlanguage}}
\tl_new:N \ols_babel_name_tl
\tl_new:N \ols_babel_opts_tl
\bool_if:nT { \ols_load_babel || \ols_load_polyglossia || \ols_bcptags } {
  \clist_map_inline:Nn \ols_langs {
    \cs_if_exist:cF{ olslangmap / \tl_to_str:n {#1} }{
      \ols_babel_name:nN {#1} \ols_babel_name_tl
      \tl_if_empty:NTF \ols_babel_name_tl {
        \bool_if:nT { \ols_load_babel || \ols_load_polyglossia } {
          \PackageError{\packagename}{Can't~find~a~language~name~for~'#1'}{
            Add~a~'map'~entry~such~as~map={#1=...}~to~the~package~options,
            \MessageBreak or~load~babel/polyglossia~yourself~before~\packagename.}
        }
      }{
        \cs_gset:cpe { olslangmap / \tl_to_str:n {#1} } { \ols_babel_name_tl }
      }
    }
  }
% \ldeen{\cs{ols\_mapped\_target\_lang} nach den neuen Map-Einträgen neu
% berechnen -- @1 und @2 unten brauchen beide den aktualisierten Wert.}
% {Recompute \cs{ols\_mapped\_target\_lang} after the new map entries -- @1
% and @2 below both need the updated value.}
% {\cs{selectlanguage}}{\cs{setdefaultlanguage}}
  \edef\ols_mapped_target_lang{\ols_use_map:n{\olsTargetLanguage}}
}
\bool_if:NT \ols_load_babel{
% \ldeen{Alle Auswahlsprachen unter ihren Babel-Namen laden, die Zielsprache als
% Hauptsprache.}{Load all selectable languages under their Babel names, the
% target as the main language.}
  \tl_clear:N \ols_babel_opts_tl
  \clist_map_inline:Nn \ols_langs
    { \tl_put_right:Ne \ols_babel_opts_tl { \ols_use_map:n {#1} , } }
  \tl_put_right:Ne \ols_babel_opts_tl { main = \ols_mapped_target_lang }
  \exp_args:NV \PassOptionsToPackage \ols_babel_opts_tl { babel }
  \RequirePackage { babel }
  \bool_if:nT{
    \ols_shorthands && !\str_if_eq_p:ee{\olsTargetLanguage}{de}}
  {
    \languageshorthands{ngerman}
  }
}
\bool_if:NT\ols_load_polyglossia{
  \RequirePackage{polyglossia}
}
% \ldeen*{Für die Shorthand-Logik brauchen wir @1.}{For the shorthand logic, we need @1.}{\pkg{csquotes}}
\bool_if:NT\ols_shorthands {
  \RequirePackage[autostyle=true]{csquotes}
}
% \ldeen*{Die folgende Initialisierung kann erst geschehen, wenn feststeht,
%   welches Sprachpaket (falls überhaupt eines) letztlich aktiv ist. Da andere
%   Pakete oder Klassen Sprachentscheidungen typischerweise nach hinten
%   verschieben, wird alles mit @1 bzw.\ @2 verschoben.}{The initialization
%   below can only happen once it is determined which language package (if any)
%   is ultimately active. Since other packages or classes typically defer
%   language decisions, everything is deferred using @1 and @2,
%   respectively.}{\cs*{AddToHook}[begindocument/before]}{\cs*{AddToHook}[begindocument]}
\AddToHook{begindocument/before}{%
% \ldeen{Aktiviere ISO-Codes vor der Sprachauswahl, damit \cs{selectlanguage} den
%   Code auflösen kann.}{Activate BCP~47 before language selection so
%   that \cs{selectlanguage} can resolve the code.}
  \bool_lazy_and:nnT{\ols_bcptags}{\cs_if_exist_p:N\babeladjust}{
% \ldeen*{@1 wird für jede Auswahlsprache mit ermitteltem Namen (oben)
%   vorbelegt, bevor @2 aktiviert wird. Dessen eigene Tag-Auflösung prüft @1
%   zuerst und nutzt es unverändert, wenn vorhanden (so hängt die
%   Sprachauswahl nicht von Babels eigener, je nach Release unterschiedlich
%   vollständiger BCP-47-Datenbank ab). Für Sprachen, die nicht ermittelt werden
%   konnten,  bleibt @2s eigenes Verhalten unverändert.}{@1 is pre-populated for every
%   selectable language with a name determined (above) before @2 is
%   enabled. Its own tag resolution checks @1 first and uses it unchanged if
%   present (in this way, language selection does not depend on Babel's own,
%   release-dependent BCP-47 database). For languages that could not be 
%   determined there, @2's own behavior is unchanged.}
%   {\cs{bbl@bcp@map@}\meta{Code}}{\code{autoload.bcp47}}
    \clist_map_inline:Nn \ols_langs {
      \cs_if_exist:cT{ olslangmap / \tl_to_str:n {#1} }{
        \cs_gset:cpe { bbl@bcp@map@ #1 } { \ols_use_map:n {#1} }
      }
    }
    \babeladjust{ bcp47.toname = on , autoload.bcp47 = on }
  }
  \bool_if:NT\ols_shorthands {
% \ldeen{Die Shorthand-Befehle benötigen ein aktives \code{@}.}{The shorthand macros
%   need an active \code{@}.
% }
    \makeatletter
% \ldeen{Die Babel-Shorthand-Infrastruktur ist bei Babel bereits vorhanden,
%   bei Polyglossia muss sie explizit initialisiert und ohne Sprachpaket direkt
%   geladen werden.}{Babel's shorthand infrastructure is already available with
%   Babel; with Polyglossia it has to be initialized explicitly, and without a
%   language package it has to be loaded directly.}
    \@ifpackageloaded{babel}{}{%
      \@ifpackageloaded{polyglossia}
        {\InitializeBabelShorthands}
        {\input{babelsh.def}}%
    }
    \@ifpackageloaded{babel}
      {\useshorthands*{"}}
      {\useshorthands{"}}
    \defineshorthand{"`}{\openautoquote}
    \defineshorthand{"'}{\closeautoquote}
    \defineshorthand{"/}{\textormath{\bbl@allowhyphens
        \discretionary{/}{}{/}\bbl@allowhyphens}{}}
    \makeatother
  }
}
% \ldeen{Die Sprachauswahl erfolgt im \code{begindocument}-Hook, also
%   \emph{nach} der Aktivierung der Hauptsprache durch das Sprachpaket.}{
%   Language selection happens in the
%   \code{begindocument} hook, i.e.\ \emph{after} the language package has
%   activated its main language.}
\AddToHook{begindocument}{%
  \bool_if:NF\ols_target_from_langpkg{
    \cs_if_exist:cT{ver@babel.sty}{
      \selectlanguage{\ols_mapped_target_lang}
    }
    \cs_if_exist:cT{ver@polyglossia.sty}{
      \setdefaultlanguage{\ols_mapped_target_lang}
    }
  }
}
%</pkg>
