From da65270cdbb449c68e6e9f06dd8089b64275a2d3 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Wed, 30 Aug 2017 23:02:13 +0000 Subject: multilang (30aug17) git-svn-id: svn://tug.org/texlive/trunk@45179 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/doc/latex/multilang/README.md | 90 + .../texmf-dist/doc/latex/multilang/multilang.pdf | Bin 0 -> 416564 bytes .../source/latex/multilang/multilang.dtx | 1748 ++++++++++++++++++++ .../source/latex/multilang/multilang.ins | 38 + .../tex/latex/multilang/multilang-sect.sty | 54 + .../tex/latex/multilang/multilang-tags.sty | 84 + .../texmf-dist/tex/latex/multilang/multilang.sty | 251 +++ 7 files changed, 2265 insertions(+) create mode 100644 Master/texmf-dist/doc/latex/multilang/README.md create mode 100644 Master/texmf-dist/doc/latex/multilang/multilang.pdf create mode 100644 Master/texmf-dist/source/latex/multilang/multilang.dtx create mode 100644 Master/texmf-dist/source/latex/multilang/multilang.ins create mode 100644 Master/texmf-dist/tex/latex/multilang/multilang-sect.sty create mode 100644 Master/texmf-dist/tex/latex/multilang/multilang-tags.sty create mode 100644 Master/texmf-dist/tex/latex/multilang/multilang.sty (limited to 'Master/texmf-dist') diff --git a/Master/texmf-dist/doc/latex/multilang/README.md b/Master/texmf-dist/doc/latex/multilang/README.md new file mode 100644 index 00000000000..95f7c52da46 --- /dev/null +++ b/Master/texmf-dist/doc/latex/multilang/README.md @@ -0,0 +1,90 @@ +The multilang Package +======================= + +Copyright (C) 2016-2017 Richard Gay + +Released under the [LaTeX Project Public License](http://www.latex-project.org/lppl/) version 1.2 or later + +## Abstract + +Maintaining a LaTeX document with translations for multiple languages +can be cumbersome and error-prone. +The `multilang` package provides a set of macros for defining macros and +environments as wrappers around existing macros and environments. +These wrappers allow one to clearly specify multiple translations for the +arguments to the wrapped macros and environments while only the +translation of the document's language is actually shown. +Choosing a translation then is as simple as choosing the document's +language via `babel` or `polyglossia`. + +## Availability + +The `multilang` package is on [CTAN](http://www.ctan.org/pkg/multilang), +where you can also find the [documentation](http://mirrors.ctan.org/macros/latex/contrib/multilang/multilang.pdf), +as well as on [github](https://github.com/Ri-Ga/multilang). + +## Manual Installation + +The `multilang` package comes with (at least) the following files +* multilang.ins +* multilang.dtx +* README.md + +and possibly also with +* Makefile +* multilang.pdf (generated from multilang.dtx) +* multilang.sty (generated from multilang.dtx) + +To install the `multilang` package, you additionally need +* docstrip.tex + +To build the package (`multilang.sty`), run one of the following +``` + latex multilang.ins + make package (needs Makefile) +``` + +Put the resulting `multilang.sty` somewhere where LaTeX can find it. +Read the documentation of your LaTeX system to find out where this +might be. + +## Building Documentation + +To build the documentation of the `multilang` package, you additionally +need the following classes and packages (including their dependencies) +* ltxdoc +* babel +* cleveref +* csquotes +* datetime2 +* enumitem +* environ +* etoolbox +* hypdoc +* idxlayout +* pbox +* pgfkeys +* pgfopts +* sectionbox +* showexpl +* translations +* xcolor +* xspace + +as well as +* pdflatex + +To build the documentation (`multilang.pdf`), either run +``` + make docs +``` +or the following sequence of commands +``` + pdflatex multilang.dtx + makeindex -s gind.ist -o multilang.ind multilang.idx + makeindex -s gglo.ist -o multilang.gls multilang.glo + pdflatex multilang.dtx + pdflatex multilang.dtx +``` + +Happy TeX'ing diff --git a/Master/texmf-dist/doc/latex/multilang/multilang.pdf b/Master/texmf-dist/doc/latex/multilang/multilang.pdf new file mode 100644 index 00000000000..456ef7bff89 Binary files /dev/null and b/Master/texmf-dist/doc/latex/multilang/multilang.pdf differ diff --git a/Master/texmf-dist/source/latex/multilang/multilang.dtx b/Master/texmf-dist/source/latex/multilang/multilang.dtx new file mode 100644 index 00000000000..3bf821a37dd --- /dev/null +++ b/Master/texmf-dist/source/latex/multilang/multilang.dtx @@ -0,0 +1,1748 @@ +% \iffalse meta-comment +% +% Copyright (C) 2016-2017 by Richard Gay +% ------------------------------------------------------- +% +% This file may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.2 +% of this license or (at your option) any later version. +% The latest version of this license is in: +% +% http://www.latex-project.org/lppl.txt +% +% and version 1.2 or later is part of all distributions of LaTeX +% version 1999/12/01 or later. +% +% \fi +% +% \iffalse +%<*driver> +\ProvidesFile{multilang.dtx} +% +%\NeedsTeXFormat{LaTeX2e}[1999/12/01] +%\NeedsTeXFormat{LaTeX2e}[1999/12/01] +%\NeedsTeXFormat{LaTeX2e}[1999/12/01] +%\ProvidesPackage{multilang} +%<*package> + [2017/08/30 v0.9 Tools for maintaining documents in multiple languages] +% +%\ProvidesPackage{multilang-tags}[2017/08/30 v0.9 Filtering of multilingual macros by tags] +%\ProvidesPackage{multilang-sect}[2017/08/30 v0.9 Multilingual sectioning environments] +% +%<*driver> +\documentclass{ltxdoc} +\usepackage[columns=2]{idxlayout} +\usepackage{xcolor} +\usepackage{xspace} +\usepackage[inline]{enumitem} +\usepackage{showexpl} +\lstset{gobble=2,frame=trbl,backgroundcolor=\color{black!5!white},width=0.475\textwidth} +\lstset{basicstyle=\footnotesize\fontfamily{pcr}\selectfont} +\lstset{explpreset={columns=fixed,numbers=none,language={}}} +\lstset{preset={\small\sffamily},overhang=2cm,pos=r,varwidth=false} +\usepackage{pbox} +\newcommand\NiceDescribeStuff[2]{% #1=margin text, #2=body text + \medskip\par\noindent\leavevmode% + \marginpar{\hfill\pbox[t]{2\marginparwidth}{\ttfamily #1}% + \hspace*{-\marginparsep}}% + \ifstrempty{#2}{}{#2\smallskip\\}} +\newcommand\NiceDescribeEnv[3][]{% #1=index list, #2=envname, #3=parameters + \NiceDescribeStuff{% + \textcolor{gray}{\cs{begin}}\string{#2\string}\\ + \textcolor{gray}{\cs{end}}\string{#2\string}}{#3}% + \ifstrempty{#1} + {\SpecialEnvIndex{#1}}% + {\forcsvlist{\SpecialEnvIndex}{#1}}% + \ignorespaces} +\newcommand\NiceDescribeMacro[2]{% #1=macro, #2=parameters + \NiceDescribeStuff{\hbox to 0pt{\hss\string#1}}{#2}% + \SpecialUsageIndex{#1}\ignorespaces} +\newcommand\NiceDescribeConstant[1]{% #1=constant + \NiceDescribeStuff{\hbox to 0pt{\hss #1\quad}}{}\ignorespaces} +\makeatletter +\newcommand\SaveSecs{% + \@for\SC:=section,subsection,subsubsection\do{% + \csedef{SC@\SC}{\the\value{\SC}}% + \setcounter{\SC}{0}}} +\newcommand\RestoreSecs{% + \@for\SC:=section,subsection,subsubsection\do{% + \setcounter{\SC}{\csuse{SC@\SC}}}} +\makeatother +\newcommand\ThisPackage{\textsf{multilang}\xspace} +\usepackage{hypdoc} +\usepackage[capitalise,nameinlink]{cleveref} +% the following packages are for the examples +\usepackage[german,english]{babel} +\usepackage[languages={english,german}]{multilang} +\usepackage[autostyle=true]{csquotes} +\usepackage[useregional]{datetime2} +\usepackage{sectionbox} +\usepackage{translations} +\usepackage{multilang-tags} +\usepackage{multilang-sect} +% end of examples packages +\EnableCrossrefs +\CodelineIndex +\RecordChanges +\begin{document} + \DocInput{multilang.dtx} + \PrintChanges + \PrintIndex +\end{document} +% +% \fi +% +% \CheckSum{0} +% +% \CharacterTable +% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z +% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z +% Digits \0\1\2\3\4\5\6\7\8\9 +% Exclamation \! Double quote \" Hash (number) \# +% Dollar \$ Percent \% Ampersand \& +% Acute accent \' Left paren \( Right paren \) +% Asterisk \* Plus \+ Comma \, +% Minus \- Point \. Solidus \/ +% Colon \: Semicolon \; Less than \< +% Equals \= Greater than \> Question mark \? +% Commercial at \@ Left bracket \[ Backslash \\ +% Right bracket \] Circumflex \^ Underscore \_ +% Grave accent \` Left brace \{ Vertical bar \| +% Right brace \} Tilde \~} +% +% \changes{v0.9}{2017/08/30}{Initial version} +% +% \GetFileInfo{multilang.dtx} +% +% \DoNotIndex{\newcommand,\newenvironment,\def,\gdef,\edef} +% +% +% \title{The \ThisPackage package\thanks{This document +% corresponds to \ThisPackage~\fileversion, dated \filedate. +% The package is available online at +% \url{http://www.ctan.org/pkg/multilang} and +% \url{https://github.com/Ri-Ga/multilang}.}} +% \author{Richard Gay \\ \texttt{richard.gay@t-online.de}} +% +% \maketitle +% +% \begin{abstract} +% Maintaining a \LaTeX{} document with translations for multiple languages +% can be cumbersome and error-prone. +% The \ThisPackage package provides a set of macros for defining macros and +% environments as wrappers around existing macros and environments. +% These wrappers allow one to clearly specify multiple translations for the +% arguments to the wrapped macros and environments while only the +% translation of the document's language is actually shown. +% Choosing a translation then is as simple as choosing the document's +% language via \textsf{babel} or \textsf{polyglossia}. +% \end{abstract} +% +% \section{Introduction} +% \label{sec:Introduction} +% +% The main goal of the \ThisPackage package is to facilitate the +% definition of macros and environments with which documents can be +% provisioned in multiple languages. +% To be more concrete, \ThisPackage facilitates +% \begin{enumerate} +% \item the specification of content translations: +% +% \begin{itemize}[noitemsep] +% \item Arguments to macros are specified by their name such that multiple +% translations do not clutter up the \LaTeX{} code that easily. +% \item If you forget to specify a mandatory argument in a language, +% \ThisPackage shows an error when you compile for that language. +% \end{itemize} +% +% \item the maintenance of translations:\smallskip +% +% Translations of content that is passed as an argument to a macro can be kept +% closely together such that you can keep track of which units belong together +% and can keep consistency among translations across content changes. +% +% \item the selection of a document language:\smallskip +% +% You simply specify the language with \textsf{babel} or \textsf{polyglossia} +% and \ThisPackage selects the translation you provided for the language. +% \end{enumerate} +% +% The motivating example that lead to the development of this package are CVs +% (curricula vitae). Suppose you want to maintain a CV document that contains +% the union of all your relevant personal data, education, achievements, etc. +% You update the CV from time to time with new achievements. Since you want to +% prepare for the possibility that you might apply nationally as well as +% internationally, you maintain the CV document in multiple languages (e.g., +% your mother language and English). +% When you use the CV in a concrete job application, you +% \begin{enumerate*}[label=(\arabic*)] +% \item filter out all details that are irrelevant for the position that you +% apply for +% and +% \item select a suitable language for the employer. +% \end{enumerate*} +% +% This package provides a set of basic macros for the definition of +% multilingual macros and multilingual environments. The following example +% illustrates such a macro and how it could be used. +% \SaveSecs +% +% \begin{LTXexample}[preset={\newcommand\Sec[1]{\section{Foobar}}}] +% % ... +% \usepackage[german,english]{babel} +% \usepackage[languages={english,german}] +% {multilang} +% % ... +% \begin{document} +% \Sec{ +% title/english={Foobar}, +% title/german ={Dingsda} +% } +% ... +% \end{document} +% \end{LTXexample} +% \RestoreSecs +% \Cref{sec:Usage} describes how a macro such as |\Sec| in the above +% example can be defined with \ThisPackage. The \lcnamecref{sec:Usage} also +% describes how analogous environments can be defined. +% \Cref{sec:Types} describes extensible argument types. +% \Cref{sec:Extensions} describes two extension packages, +% \textsf{multilang-sect} and \textsf{multilang-tags} for multilingual +% sectioning and, respectively, for filtering multilingual macros and +% environments. +% +% +% \section{Usage} +% \label{sec:Usage} +% +% \subsection{Package Options} +% +% \NiceDescribeConstant{languages} +% The \ThisPackage package has a single option: |languages|. This option +% expects a comma-separated list of language names. The ordering of the list +% does not make a difference. Through this option, one sets the languages for +% which translations can be provided. By default, the list is empty such that +% no translations can be specified. +% The example in \cref{sec:Introduction} demonstrates how this option can be +% used. +% +% +% \subsection{Multilingual Macros} +% \label{sec:Usage-Macros} +% +% \NiceDescribeMacro{\NewMultilangCmd}{\marg{command}\marg{options}} +% A multilingual macro can be defined via the |\NewMultilangCmd| macro. +% The macro defines \meta{command} as a macro that accepts a single argument. +% That is, the signature of \meta{command} is \meta{command}\marg{kvarg}. The +% argument, \meta{kvarg}, is a comma-separated key-value list. +% The \meta{options} argument takes the form of a comma-separated key-value +% list and specifies what \meta{command} does, including how \meta{kvarg} is +% interpreted. The following keys are defined for \meta{options}: +% \begin{description}[noitemsep] +% \item[|command|:] +% This key is to be used in the form ``|command=|\meta{c}'', where \meta{c} +% is an already existing command. +% The key specifies that \meta{command} is defined to invoke \meta{c} with +% some arguments. +% Example: see \cref{sec:Usage-margs}. +% \item[|margs|:] +% This key is to be used in the form ``|margs={|\meta{csvlist}|}|'', where +% \meta{csvlist} is a comma-separated list of names. +% The key specifies names for the mandatory arguments of \meta{c}, in the +% order specified. +% If \meta{c} is a macro that takes $n$ mandatory arguments, then +% \meta{csvlist} should be a list of $n$ names. If \meta{arg-i} is the +% $i$-th entry in \meta{csvlist}, then the $i$-th mandatory +% argument to \meta{c} can be specified as \meta{v} in the invocation of +% \meta{command} as follows: +% ``\meta{command}|{...,|\meta{arg-i}|=|\meta{v}|,...}|''. +% Example: see \cref{sec:Usage-margs}. +% \item[|oargs|:] +% This key is to be used in the form ``|oargs={|\meta{csvlist}|}|'', where +% \meta{csvlist} is a comma-separated list of names. +% This key is analogous to |margs|, but for optional arguments to \meta{c}. +% Example: see \cref{sec:Usage-oargs}. +% \item[|starred|:] +% This key is to be used simply as +% ``|starred=|\meta{bool}'', where \meta{bool} must be |true| or |false|, +% or just as ``|starred|'', which is equivalent to ``|starred=true|''. +% If \meta{bool} is |true|, then ``\meta{command}|*{...}|'' can be used to +% invoke ``\meta{c}|*...|''. +% Example: see \cref{sec:Usage-starred}. +% \item[|disablable|:] +% This key is to be used simply as +% ``|disablable=|\meta{bool}'', where \meta{bool} must be |true| or |false|, +% or just as ``|disablable|'', which is equivalent to ``|disablable=true|''. +% If \meta{bool} is |true|, then the invocation of \meta{c} in +% \meta{command} can be suppressed via +% ``\meta{command}|{...,disabled,...}|''. +% Example: see \cref{sec:Usage-disablable}. +% \item[|defaults|:] +% This key is to be used as +% ``|defaults={...,|\meta{arg}|=|\meta{value}|,...}|''. +% Each key \meta{arg} should be the name of an optional or mandatory +% argument and \meta{value} should be the intended default value for this +% argument. +% Example: see \cref{sec:Usage-defaults}. +% \item[|alias/...|:] +% This key is to be used as ``|alias/|\meta{name}|={|\meta{arglist}|}|'', +% where \meta{name} specifies the name of the alias and \meta{arglist} is a +% possibly empty comma-separated list of argument names (optional or +% mandatory arguments allowed). +% Example: see \cref{sec:Usage-alias}. +% \end{description} +% The remainder of \cref{sec:Usage-Macros} provides examples based on the +% |\section| macro. +% +% +% \subsubsection{Basic Usage} +% \label{sec:Usage-margs} +% The following example shows how the |\Section| macro used in the example of +% \cref{sec:Introduction} can be defined. We leave out the \textsf{babel} code +% in this \lcnamecref{sec:Usage} for more concise example code. +% +% \SaveSecs +% \begin{LTXexample}[morekeywords={NewMultilangCmd,command,margs}] +% \NewMultilangCmd{\Sec}{ +% command=\section, margs=title} +% \Sec{ +% title/english={Foobar}, +% title/german ={Dingsda} +% } +% \end{LTXexample} +% \RestoreSecs +% +% +% \paragraph{Language-independent arguments.} +% Sometimes, arguments to macros need no translation. For instance, if an +% argument is a technical term or a name, it can remain in the original +% language. To avoid redundancy, in such instances the language part of a +% mandatory or optional argument can be omitted to specify the argument for +% all languages. +% +% \SaveSecs +% \begin{LTXexample}[preset={\NewMultilangCmd{\Sec}{margs=title,oargs=short,command=\section}}] +% \Sec{title=multilang} +% \end{LTXexample} +% \RestoreSecs +% +% +% \paragraph{Forced foreign-language arguments.} +% \label{sec:Usage-forced-language} +% A particular instance of a language-independent argument is the case in which +% the argument shall explicitly be typeset in a particular language. For +% instance, the argument might use macros that internally determine the +% display based on the selected language. The following example shows the case +% of forcing German display of the |\enquote| macro. +% +% \SaveSecs +% \begin{LTXexample}[preset={\NewMultilangCmd{\Sec}{margs=title,oargs=short,command=\section}}] +% \usepackage[autostyle=true]{csquotes} +% %... +% \Sec{title/german!=\enquote{multilang}} +% \end{LTXexample} +% \RestoreSecs +% +% +% \subsubsection{Optional Arguments} +% \label{sec:Usage-oargs} +% Macros like |\section| don't just have a mandatory argument (the section +% title) but also an optional argument (a short title for the table of +% contents). We can make this optional argument accessible via the |oargs| +% option as follows. +% The displayed result does not show any difference as we don't have the table +% of contents here. +% +% \SaveSecs +% \begin{LTXexample}[morekeywords={oargs}] +% \NewMultilangCmd{\Sec}{ +% command=\section, margs=title, oargs=short} +% \Sec{ +% title/english={Foobar}, +% title/german ={Dingsda}, +% short/english={F}, +% short/german ={D}, +% } +% \end{LTXexample} +% \RestoreSecs +% +% +% \subsubsection{Starred Macros} +% \label{sec:Usage-starred} +% Some macros can be altered in their behavior with a star (``|*|'') after the +% macro. The |\section| command is an example of such a macro: |\section*| +% suppresses the display of the section number. The star can be transferred to +% the command defined via |\NewMultilangCmd| as the following example +% illustrates. Note the exclamation mark after ``|german|''. +% +% \SaveSecs +% \begin{LTXexample}[morekeywords={starred}] +% \NewMultilangCmd{\Sec}{starred, +% command=\section, margs=title, oargs=short} +% \Sec{title=Foo} +% \Sec*{title=Bar} +% \end{LTXexample} +% \RestoreSecs +% +% +% \subsubsection{Disabling Display} +% \label{sec:Usage-disablable} +% When a macro is defined with the |disablable| option, it can be passed the +% |disabled| argument which disables the display of the macro. One might +% consider this a nicer way to disable content than commenting out the macro. +% +% \SaveSecs +% \begin{LTXexample}[morekeywords={disablable}] +% \NewMultilangCmd{\Sec}{disablable, +% command=\section, margs=title, oargs=short} +% \Sec{title=Foo} +% \Sec{title=Bar,disabled} +% \end{LTXexample} +% \RestoreSecs +% +% +% \subsubsection{Default Arguments} +% \label{sec:Usage-defaults} +% When a mandatory or optional argument shall by default assume a particular +% value if no value is specified for the argument in the argument to +% \meta{command}, this can be specified via the |defaults| key as the +% following example demonstrates. +% +% \SaveSecs +% \begin{LTXexample}[morekeywords={defaults}] +% \NewMultilangCmd{\Sec}{ +% command=\section, margs=title, +% defaults={title={???}}} +% \Sec{} +% \end{LTXexample} +% \RestoreSecs +% Defaults can be particularly useful for mandatory arguments of commands +% that take multiple arguments and that can often be left empty. +% Essentially, argument defaults turn mandatory arguments of +% macros to optional arguments. +% +% +% \subsubsection{Argument Aliases} +% \label{sec:Usage-alias} +% Aliases allow one to specify argument names of three different kinds: +% \begin{description}[nosep] +% \item[direct aliases:] +% A direct alias declares an argument name that can then be used as a +% substitute for some mandatory or optional argument. +% The |heading| argument in the following example shows how direct aliases +% can be declared. +% \item[combiner aliases:] +% A combiner alias declares an argument name that acts as a substitute for a +% sequence of mandatory or optional arguments. +% Such aliases particularly help maintaining concise \LaTeX{} source code +% when argument values are rather short, as |both| in the following example +% shows. +% \item[comment aliases:] +% A comment alias declares an argument name that represents no mandatory or +% optional argument. That is, a value specified for a comment alias is not +% used as an argument to the |command| and can, hence, be used for capturing +% comments or values for future use. +% \end{description} +% +% \SaveSecs +% \begin{LTXexample}[morekeywords={alias}] +% \NewMultilangCmd{\Sec}{ +% command=\section, margs=title, oargs=short, +% alias/heading=title, +% alias/both={title,short}, +% alias/remark} +% \Sec{ +% both/english={Foobar}{Foo}, +% both/german ={Dingsda}{Dings}} +% \Sec{ +% heading=Baz, +% remark={select heading+translate}} +% \end{LTXexample} +% \RestoreSecs +% +% +% \subsection{Multilingual Environments} +% +% \NiceDescribeMacro{\NewMultilangEnv}{\marg{environment}\marg{options}} +% The usage of the |\NewMultilangEnv| macro is analogous to the usage of +% the macro |\NewMultilangCmd|, except for the following differences: +% \begin{itemize}[noitemsep] +% \item The first argument, \meta{environment}, expects the name of an +% environment that shall be defined. +% \item In the \meta{options}, the |environment| key substitutes the |command| +% key and expects an environment name. +% \item The |starred| key is not available. Following standard \LaTeX{} +% practices, if you want to define a starred environment, simply use the +% starred name for \meta{environment}. +% \end{itemize} +% Due to the similarity to |\NewMultilangCmd|, we don't provide separate +% examples for all the individual features. +% Continuing the line of examples started before, we again use an example +% about sections -- just now with an environment for section boxes, as +% provided by the \textsf{sectionbox} package. +% +% \SaveSecs +% \begin{LTXexample}[morekeywords={NewMultilangEnv}] +% \usepackage{sectionbox} +% \NewMultilangEnv{SecBox}{ +% environment=sectionbox, +% disablable, margs=title, oargs=width} +% +% \begin{SecBox}{title=Foo} +% content +% \end{SecBox} +% +% \begin{SecBox}{disabled,title=Bar} +% disabled content +% \end{SecBox} +% \end{LTXexample} +% \RestoreSecs +% +% +% \section{Extensible Argument Types} +% \label{sec:Types} +% +% By default, an argument |arg| in a multilingual macro can be specified in +% three ways: just ``|arg=...|'', ``|arg/|\meta{language}|=...|'', or +% ``|arg/|\meta{language}|!=...|''. +% The \ThisPackage package enables one to declare further so called `types'. +% These types can be used in place of \meta{language} in the argument syntax. +% They can be used for uniformly enabling a special formatting if an argument +% is of a particular type (rather than just being text). +% +% \NiceDescribeMacro{\NewMultilangType}{\oarg{argcount}\marg{typename}\marg{format}} +% The |\NewMultilangType| macro declares the \meta{typename} type. +% Values passed to arguments of this type must consist of \meta{argcount} +% arguments (default: 1). The value is then formatted with \meta{format} when +% displayed. The \meta{format} can (and should) contain positional parameters +% such as ``|#1|'' for the first argument. +% The remainder of this \lcnamecref{sec:Types} demonstrates the use of +% the macro by examples. +% +% +% \subsection{Dates via \textsf{datetime2}} +% +% The \textsf{datetime2} package supports regional (language-specific) +% formatting of dates. We can build on this feature such that we don't +% have to provide translations of dates. To keep the display +% smaller, we here use |\textbf| rather than |\section|. +% +% \begin{LTXexample}[morekeywords={NewMultilangType,date,daterange}] +% \usepackage[useregional]{datetime2} +% +% \NewMultilangType{date}{\DTMdate{#1}} +% \NewMultilangType[2]{daterange} +% {\DTMdate{#1}--\DTMdate{#2}} +% +% \NewMultilangCmd{\Bold} +% {margs=title, command=\textbf} +% +% Date: \Bold{title/date={2017-08-01}}\\ +% Range: \Bold{title/daterange= +% {2017-01-01}{2017-08-01}} +% \end{LTXexample} +% +% +% \subsection{Nesting Multilingual Macros} +% +% Multilingual macros can be used in arguments to multilingual macros. +% Coming back to the original motivation for developing \ThisPackage +% -- CVs -- you might want a translated two-column layout in which the +% right column might be filled with translated list items. The following +% example shows how this can be realized. +% +% \begin{LTXexample} +% \usepackage{enumitem}% for "nosep" +% +% \newcommand\entry[2]{% +% \begin{tabular}{p{1cm}p{4cm}}#1 +% \end{tabular}} +% +% \NewMultilangType{list}{% +% \begin{minipage}[t]{4cm} +% \begin{itemize}[nosep]#1 +% \end{itemize}\end{minipage}} +% \NewMultilangCmd{\Entry} +% {margs={head,text}, command=\entry} +% \NewMultilangCmd{\Item} +% {margs=name, command=\item} +% +% \Entry{head=2017, +% text/list={ +% \Item{name/english=foobar, +% name/german =Dingsda} +% \Item{name=multilang}}} +% \end{LTXexample} +% +% +% \section{Extension Packages} +% \label{sec:Extensions} +% +% The \ThisPackage package comes bundled with a few generic packages that build +% on \ThisPackage. These packages are described below. +% +% \subsection{Sectioning Environments} +% +% Sectioning environments are provided by the \textsf{multilang-sect} package. +% That package defines, for each of \LaTeX's sectioning macros (|\section|, +% \ldots, |\subparagraph|) an environment and a starred environment. +% +% \NiceDescribeEnv[Section,Section*]{Section(*)}{\marg{data}} +% This environment shows a section. +% It has a single, mandatory argument, named |title|. +% It is a disablable environment, i.e., the argument |disabled| can be used in +% \meta{data} to disable the display of the whole section. +% This environment acts as a proxy for the |\section| macro as it is used by +% \ThisPackage (i.e., without optional argument and without the star). + +% \NiceDescribeEnv[SubSection,SubSection*]{SubSection(*)}{\marg{data}} +% This environment is analogous to the |Section| environment, just for +% sub-sections. + +% \NiceDescribeEnv[SubSubSection,SubSubSection*]{SubSubSection(*)}{\marg{data}} +% This environment is analogous to the |Section| environment, just for +% sub-sub-sections. + +% \NiceDescribeEnv[Paragraph,Paragraph*]{Paragraph(*)}{\marg{data}} +% This environment is analogous to the |Section| environment, just for +% paragraphs. + +% \NiceDescribeEnv[SubParagraph,SubParagraph*]{SubParagraph(*)}{\marg{data}} +% This environment is analogous to the |Section| environment, just for +% sub-paragraphs. +% Examples: +% +% \SaveSecs +% \begin{LTXexample}[morekeywords={Section,SubSection}] +% \usepackage{multilang-sect} +% +% \begin{Section}{ +% title/english = Usage, +% title/german = Benutzung, +% } +% (section content) +% \begin{SubSection*}{ +% title/english = Package Options, +% title/german = Paketoptionen, +% } +% (subsection content) +% \end{SubSection*} +% \end{Section} +% \end{LTXexample} +% \RestoreSecs +% +% +% \subsection{Tags} +% +% Tags are an alternative to individually disabling macros or environments. +% They are provided by the \textsf{multilang-tags} package. +% A tag is just a word and sets of tags can be assigned to individual usages of +% multilingual macros and environments. +% As long as no tag filter policy is setup, specifying tags does not influence +% what is displayed. +% +% \NiceDescribeMacro{\SetTagFilter}{\oarg{default}\marg{policy}} +% The |\SetTagFilter|\oarg{default}\marg{policy} sets up a tag filter policy. +% The \meta{policy} is a comma-separated list of |accept|/|deny| rules. +% The \meta{default} argument is either |accept| (the default) or |deny| and +% specifies the default policy. +% The following toy example demonstrates tag filtering: +% +% \begin{LTXexample}[morekeywords={SetTagFilter,tags}] +% \usepackage{multilang-tags} +% \NewMultilangCmd{\Item}{disablable, +% command=\item,oargs=dd,margs=dt, +% alias/both={dd,dt}} +% \SetTagFilter{accept={A}, deny={D}} +% +% \begin{description} +% \Item{tags=A, both={1}{tagged A}} +% \Item{tags={A,D}, both={2}{tagged A,D}} +% \Item{tags=D, both={3}{tagged D}} +% \Item{tags={D,X}, both={4}{tagged D,X}} +% \Item{tags=!D, both={5}{tagged !D}} +% \Item{tags=X, both={6}{tagged X}} +% \end{description} +% \end{LTXexample} +% +% When a multilingual macro, such as |\BasicEntry| in the above example, is +% used, whether the macro content is displayed is determined as follows: +% \begin{itemize}[nosep] +% \item If no |tags| are specified or no tag policy is setup, then the macro +% content is displayed. +% \item Otherwise, the rules of the tag policy are processed in sequential order +% until the specified |tags| match a rule. +% A |tags| list matches a rule if at least one tag in the |tags| occurs in the +% rule (with or without ``|!|'' prefix). +% Let $t$ be the last tag in |tags| that occurs in the rule. +% \begin{itemize}[nosep] +% \item The macro content is displayed if the rule is an |accept| rule and $t$ +% is not prefixed with ``|!|'', or if the rule is a |deny| rule and $t$ is +% prefixed with ``|!|''. +% \item Otherwise the display of the macro content is disabled. +% \end{itemize} +% \item If the specified |tags| match no rule in the \meta{policy}, then the +% macro content is displayed if and only if the \meta{default} is |accept|. +% \end{itemize} +% +% Rather than directly setting up a filter policy, one can also use the +% following macros to first define filter policies and then select one for use. +% +% \NiceDescribeMacro{\DefineTagFilter}{\marg{name}\marg{default}\marg{policy}} +% This macro defines a tag filter policy with name \meta{name} to represent the +% given \meta{policy} and \meta{default}. +% +% \NiceDescribeMacro{\UseTagFilter}{\marg{name}} +% This macro uses the tag filter policy with name \meta{name}. +% +% Further examples: +% \begin{LTXexample}[morekeywords={DefineTagFilter,UseTagFilter,tags},preset={\NewMultilangCmd{\Item}{disablable,command=\item,oargs=dd,margs=dt,alias/both={dd,dt}}}] +% \DefineTagFilter{Show}{accept}{} +% \DefineTagFilter{Hide}{deny}{} +% \DefineTagFilter{OnlyA}{accept}{accept=A, +% deny={D,X}} +% \begin{description} +% \UseTagFilter{Hide} +% \Item{ both={1}{no tag}} +% \Item{tags=D, both={2}{tagged D}} +% \UseTagFilter{OnlyA} +% \Item{tags={D,!X},both={3}{tagged D,!X}} +% \Item{tags={!X,D},both={4}{tagged !X,D}} +% \end{description} +% \end{LTXexample} +% +% +% \section{Questions and Answers} +% +% \begin{description} +% \item[Can't I achieve the same thing simpler?] +% To some extent, you can. +% A variety of ad-hoc solutions to managing translations in \LaTeX{} +% documents exist.\footnote{see, e.g., +% \url{https://tex.stackexchange.com/q/5076}} +% An obvious approach is the following: +% \SaveSecs +% \begin{LTXexample} +% \newcommand\inEnglish[1]{#1} +% \newcommand\inGerman[1]{} +% +% \inEnglish{\section{Foobar}} +% \inGerman{\section{Dingsda}} +% % or +% \section{\inEnglish{Foobar} +% \inGerman{Dingsda}} +% \end{LTXexample} +% \RestoreSecs +% That is, for each translation language you define a macro with one +% argument; the macro for the ``selected'' language expands to the argument +% while all other macros have an empty expansion. +% An obvious advantage of this approach over \ThisPackage is that it does +% not require learning how to use \ThisPackage. +% However, in my opinion, the approach has the following disadvantages: +% \begin{itemize}[nosep] +% \item Both the first variant and the second variant in the example make +% the code more difficult to read due to the nesting of macros and the +% curly braces. +% \item The first variant even requires the |\section| macro to be repeated +% for each language. +% \item The second variant easily gets chaotic if instead of |\section| a +% macro with several arguments is used. +% \end{itemize} +% Solutions with conditionals (e.g., |\ifEnglish ...\else ...\fi|) share the +% disadvantages of above approach (except the curly braces) and additionally +% have an inherent asymmetry that becomes particularly apparent if more than +% two languages are involved. +% Similar arguments apply to other ad-hoc solutions I have seen. +% That is, I find documents based on such approaches cumbersome to maintain +% and, hence, requiring more careful checks for ensuring consistency. +% +% \item[Can I use \ThisPackage with \textsf{polyglossia} instead of \textsf{babel}?] +% Yes, you can use either one for selecting the language of your document. +% +% \item[Can I switch the language mid-document?] +% You can switch the language mid-document (e.g., using Babel's +% |selectlanguage| environment), but this does not effect what the +% multilingual macros or environments defined via \ThisPackage. +% The language that is displayed by a macro or environment is determined at +% the time of loading \ThisPackage. +% Future versions of \ThisPackage might add support for switching languages +% mid-document, though. +% +% \item[Are language dialects supported?] +% No, currently they are not supported. +% +% \item[Can I store the ``result'' of a multilingual macro in another macro?] +% No. +% You can store the macro itself (e.g., via |\newcommand|), but storing the +% result of the multilingual macro in a macro (e.g., via |\edef|) is not +% possible, as the multilingual macros are not expandable. +% \end{description} +% +% +% \section{Related Packages} +% +% I'm not aware of any \LaTeX{} packages that pursue similar goals or +% provide similar functionality. +% CTAN provides a list of many packages for supporting more than one +% language.\footnote{\url{https://www.ctan.org/topic/multilingual}} +% In the following, we compare against some of these packages. +% +% \begin{description} +% \item[\textsf{babel}, \textsf{polyglossia}:] +% These package provide support for selecting a document language and +% switching the document language within a document. The selected language +% is then used for hyphenation and other layouting aspects. +% Providing multiple translations of pieces of content is not particularly +% facilitated by the two packages. +% +% The \ThisPackage package builds on \textsf{babel} or \textsf{polyglossia} +% for determining the selected language and for forced foreign-language +% formatting (as illustrated in \cref{sec:Usage-margs}). +% +% \item[\textsf{translations}:] +% This package aims primarily aims at package authors, providing them an +% easy interface for providing translations of package-specific terms. +% Essentially, one declares translations for terms up-front and then later +% can use these translations. +% +% The separation of translations and the use of terms is beneficial +% for the maintenance of packages and documents in which individual terms +% occur multiple times. However, I assume that this separation would make it +% harder to maintain documents in which most translated units occur only +% once and at a particular location in the document. +% +% One could combine the virtues of \textsf{translations} and \ThisPackage as +% follows: +% \SaveSecs +% \begin{LTXexample}[morekeywords={DeclareTranslation,GetTranslation},preset={\let\DeclareTranslation=\addtranslation}] +% % in preamble +% \usepackage{translations} +% \DeclareTranslation{english}{foo}{Foobar} +% \DeclareTranslation{german}{foo}{Dingsda} +% \NewMultilangType{translate} +% {\GetTranslation{#1}} +% \NewMultilangCmd{\Sec}{ +% margs=title, command=\section} +% +% % in document +% \Sec{title/translate=foo} +% \end{LTXexample} +% \RestoreSecs +% +% \item[\textsf{xt\_capts}:] +% This package is similar to the \textsf{translations} package, even though +% the package's documentation does not explicitly refer to package authors +% as the target users. That is, it provides commands for declaring and using +% translations of terms. +% The main difference to \textsf{translations}, as far as I understand, is +% that the user interface of \textsf{translations} is larger and supports +% language dialects. +% Comparing with \ThisPackage, the same remarks as for \textsf{translations} +% apply. +% \end{description} +% +% +% \clearpage +% +% \StopEventually{} +%\iffalse +%<*package> +%\fi +% +% +% \section{Implementation} +% +% \subsection{Dependencies} +% +% We use \textsf{pgfkeys} for the options parsing, both for the macros defined +% by \ThisPackage and for the macro defined via the macros in \ThisPackage. +% We use \textsf{etoolbox} to simplify the internal code. +% \begin{macrocode} +\RequirePackage{pgfkeys,pgfopts} +\RequirePackage{etoolbox} +% \end{macrocode} +% We use the \textsf{environ} package for scanning and later forgetting the +% body of disabled multilingual environments. +% \begin{macrocode} +\RequirePackage{environ} +% \end{macrocode} +% +% +% \subsection{Package Options} +% +% The ``|languages|'' option selects the languages that \ThisPackage knows +% about. +% \begin{macrocode} +\newcommand\multilang@@langs{} +\pgfqkeys{/multilang/pkg}{ + languages/.code={\forcsvlist{\listadd\multilang@@langs}{#1}}, +} +\ProcessPgfOptions{/multilang/pkg} +% \end{macrocode} +% +% \subsection{Main Macros} +% +% \begin{macro}{\NewMultilangCmd} +% The |\NewMultilangCmd|\marg{command}\marg{options} macro defines +% \meta{command} to be a single-argument macro. The argument to \meta{command} +% specifies, in a key-value list style, the mandatory and optional arguments +% that are passed to a command specified in \meta{options}. +% \begin{macrocode} +\newcommand\NewMultilangCmd[2]{% + \bgroup +% \end{macrocode} +% The following line processes the \meta{options} given and, as its result, +% defines the macros +% |\multilang@@actuals|, |\multilang@@checks|, and |\multilang@@keys|. +% \begin{macrocode} + \multilang@processargs{#1}{/multilang/newcommand}{defaults={},#2}% +% \end{macrocode} +% To handle starred macros, we store the actual macro code into an auxiliary +% macro and define \meta{command} to be an interface to the auxiliary macro. +% The next line stores the name of the internal macro. +% \begin{macrocode} + \expandafter\def\expandafter\multilang@@intcmd\expandafter{% + \csname multilang@intcmd@\expandafter\@gobble\string#1\endcsname}% +% \end{macrocode} +% Finally, we create the \meta{command}. The |\edef| starting with the +% |\egroup| shall expand the three macros constructed above but nothing else +% such that none of the |\pgfqkeys| result for |#1| spills outside the +% |\NewMultilangCmd|. +% \begin{macrocode} + \edef\do{\egroup + \expandonce{\multilang@@keys}% + \ifbool{multilang@@starred}{% +% \end{macrocode} +% The following handles the case of a |starred| macro. We define the macro +% that scans for the star (\meta{command}) as well as the internal macro that +% does the actual work. +% \begin{macrocode} + \unexpanded{\newcommand#1}{% + \noexpand\@ifstar + {\expandonce{\multilang@@intcmd}{*}}% + {\expandonce{\multilang@@intcmd}{}}}% + }{% +% \end{macrocode} +% The following handles the case of a non-|starred| macro. Here we make +% \meta{command} directly resort to the internal macro. +% \begin{macrocode} + \unexpanded{\newcommand#1}{\expandonce{\multilang@@intcmd}{}}% + }% +% \end{macrocode} +% The remainder of the macro code defines the internal macro, with signature +% \meta{\cs{multilang@@keys}}\marg{decoration}\marg{kvarg}. +% The \meta{decoration} can assume any symbols that shall directly be put +% after the command encapsulated by |command|. A particular use for the +% \meta{decoration} argument is the ``|*|'' symbol for a |starred| macro. +% \begin{macrocode} + \noexpand\newcommand{\expandonce{\multilang@@intcmd}}[2]{% +% \end{macrocode} +% First, \meta{command} parses its argument using \textsf{pgfkeys}. +% \begin{macrocode} + \bgroup + \noexpand\boolfalse{multilang@cmd@@disabled}% + \noexpand\pgfqkeys{\multilang@keyof{#1}}{% + \expandonce{\multilang@@defaults},####2}% + \noexpand\ifbool{multilang@cmd@@disabled}% +% \end{macrocode} +% If the macro is disabled, simply use an empty invocation +% |\multilang@@invok|. +% \begin{macrocode} + {\unexpanded{\def\multilang@@invok{}}}% +% \end{macrocode} +% Otherwise, first check the arguments and afterwards define +% |\multilang@@invok| to contain \meta{command}, \meta{decoration} (in +% |####1|), and the actual arguments (in |\multilang@@actuals|). +% \begin{macrocode} + {\expandonce{\multilang@@checks}% + \unexpanded{\edef\multilang@@invok}{% + \noexpand\unexpanded{\expandonce{\multilang@@cmd}}####1% + \expandonce{\multilang@@actuals}}}% +% \end{macrocode} +% Finally, \meta{command} invokes the command specified via the |command| key. +% The invocation happens outside the local group, just for the case that makes +% a difference with the |command|. +% \begin{macrocode} + \unexpanded{\expandafter\egroup\multilang@@invok}% + }% + }\do} +% \end{macrocode} +% +% +% \begin{macro}{\NewMultilangEnv} +% The |\NewMultilangEnv|\marg{environment}\marg{options} macro defines +% \meta{environment} to be a single-argument environment. The argument to +% \meta{environment} specifies, in a key-value list style, the mandatory and +% optional arguments that are passed to an environment specified in +% \meta{options}. +% \begin{macrocode} +\newcommand\NewMultilangEnv[2]{% + \bgroup +% \end{macrocode} +% The following line processes the \meta{options} given and, as its result, +% defines the macros +% |\multilang@@actuals|, |\multilang@@checks|, and |\multilang@@keys|. +% \begin{macrocode} + \multilang@processargs{#1}{/multilang/newenvir}{defaults={},#2}% +% \end{macrocode} +% Finally, we create the \meta{environment}. The |\edef| starting with the +% |\egroup| shall expand the three macros constructed above but nothing else +% such that none of the |\pgfqkeys| result for |#1| spills outside the +% |\NewMultilangEnv|. We also pay attention that as few as possible internal +% macros spill into the environment or even the code that begins the +% environment. +% \begin{macrocode} + \edef\do{\egroup + \expandonce{\multilang@@keys}% + \unexpanded{\newenvironment{#1}}[1]{% +% \end{macrocode} +% First, \meta{command} parses its argument using \textsf{pgfkeys}. +% \begin{macrocode} + \bgroup + \noexpand\boolfalse{multilang@cmd@@disabled}% + \noexpand\pgfqkeys{\multilang@keyof{#1}}{####1}% + \noexpand\ifbool{multilang@cmd@@disabled}% +% \end{macrocode} +% If the body shall be disabled, then we don't perform checks on the +% arguments, don't open |environment| but rather collect the body of the +% environment and finally also ignore the code for closing |environment| (via +% |\multilang@noend|). Through this trick, we avoid defining an additional +% macro for switching in the end-block of the environment. +% \begin{macrocode} + {\unexpanded{% + \def\multilang@@invok{\Collect@Body{\multilang@noend}}}}% +% \end{macrocode} +% First check the arguments and afterwards define +% |\multilang@@invok| to contain the opening code for the environment, +% including the actual arguments (in |\multilang@@actuals|). +% \begin{macrocode} + {\expandonce{\multilang@@checks}% + \unexpanded{\edef\multilang@@invok}{% + \noexpand\noexpand\noexpand\begin{\multilang@@env}% + \expandonce{\multilang@@actuals}}}% +% \end{macrocode} +% Finally, \meta{environment} begins the environment specified via the +% |environment| key. This happens outside the local group, such that the +% internal macros set via |\pgfqkeys| are not visible anymore when the +% environment is started. +% \begin{macrocode} + \unexpanded{\expandafter\egroup\multilang@@invok}% + }{% +% \end{macrocode} +% The following implements the closing of the environment. +% \begin{macrocode} + \noexpand\end{\multilang@@env}% + }% + }\do} +% \end{macrocode} +% +% +% \subsubsection{Option Keys} +% +% We first setup the shared keys for the \meta{options} argument of +% |\NewMultilangCmd| and |\NewMultilangEnv|. +% \begin{macrocode} +\pgfqkeys{/multilang/cmd-or-env}{ + margs/.store in={\multilang@@margs}, + oargs/.store in={\multilang@@oargs}, + alias/.is family, + alias/.unknown/.code={% + \listeadd{\multilang@@aliases}{\pgfkeyscurrentname}% + \csdef{multilang@@alias@\pgfkeyscurrentname}{#1}}, + defaults/.store in={\multilang@@defaults}, + disablable/.is if={multilang@@disablable}, +} +\newbool{multilang@@disablable} +\newbool{multilang@cmd@@disabled} +% \end{macrocode} +% +% Next, we setup the specific keys for |\NewMultilangCmd|. +% \begin{macrocode} +\pgfqkeys{/multilang/newcommand}{ + .search also={/multilang/cmd-or-env}, + command/.store in={\multilang@@cmd}, + starred/.is if={multilang@@starred}, + alias/.search also={/multilang/cmd-or-env}, +} +\newbool{multilang@@starred} +% \end{macrocode} +% \end{macro} +% Finally, the specific keys for |\NewMultilangEnv|. +% \begin{macrocode} +\pgfqkeys{/multilang/newenvir}{ + .search also={/multilang/cmd-or-env}, + environment/.store in={\multilang@@env}, + alias/.search also={/multilang/cmd-or-env}, +} +% \end{macrocode} +% \end{macro} +% +% +% \subsection{Registration of Datatypes} +% +% \begin{macro}{\NewMultilangType} +% The |\NewMultilangType|\oarg{argcount}\marg{typename}\marg{format} macro +% registers the name \meta{typename} as a type that can be used for specifying +% \ThisPackage arguments. The type has \meta{argcount} arguments (default: 1) +% and is formatted according to code \meta{format}. +% Note that the definition of types is group-local. That is, if +% |\NewMultilangType| is used within a group, \meta{typename} is only +% available inside that group. +% \begin{macrocode} +\newcommand\NewMultilangType[3][1]{% +% \end{macrocode} +% We first record the new type's name (in |\multilang@@types|) and store both +% \meta{argcount} and \meta{format} in macros. +% \begin{macrocode} + \listadd\multilang@@types{#2}% + \expandafter\newcommand\csname multilang@@typecmd@#2\endcsname[#1]{#3}% + \csdef{multilang@@typeargc@#2}{#1}% +% \end{macrocode} +% Finally, we also store the invocation of the \meta{format} code macro. +% This is a bit cumbersome, as for all possible argument counts we provide the +% respective number of arguments. I did not yet find a more elegant way to +% achieve that the |style n args| code in |\multilang@regfieldtype| invokes +% \meta{format} properly with \meta{argcount} arguments. +% \meta{argcount} and \meta{format} in macros. +% \begin{macrocode} + \ifcase#1\relax + \csdef{multilang@@runcmd@#2}{\csuse{multilang@@typecmd@#2}}% +% \end{macrocode} +% For one argument, we check a special case: \meta{format} is the identity +% function. In this case, we directly expand to the argument itself, i.e., we +% unfold \meta{format}. We do this such that emptiness of optional arguments +% can be checked by a |command| or |environment| without having to expand the +% \meta{format} (which might not work out if \meta{format} is not expansible). +% For instance, KOMA's |\section| macro hides the TOC entry for +% |\section[]{...}| but not for |\section[\X]{...}| even if |\X| expands to an +% empty result. +% \begin{macrocode} + \or\ifcsequal{multilang@@typecmd@#2}{@firstofone}% + {\csdef{multilang@@runcmd@#2}{####1}}% + {\csdef{multilang@@runcmd@#2}{\csuse{multilang@@typecmd@#2}% + {####1}}}% + \or\csdef{multilang@@runcmd@#2}{\csuse{multilang@@typecmd@#2}% + {####1}{####2}}% + \or\csdef{multilang@@runcmd@#2}{\csuse{multilang@@typecmd@#2}% + {####1}{####2}{####3}}% + \or\csdef{multilang@@runcmd@#2}{\csuse{multilang@@typecmd@#2}% + {####1}{####2}{####3}{####4}}% + \or\csdef{multilang@@runcmd@#2}{\csuse{multilang@@typecmd@#2}% + {####1}{####2}{####3}{####4}{####5}}% + \or\csdef{multilang@@runcmd@#2}{\csuse{multilang@@typecmd@#2}% + {####1}{####2}{####3}{####4}{####5}{####6}}% + \or\csdef{multilang@@runcmd@#2}{\csuse{multilang@@typecmd@#2}% + {####1}{####2}{####3}{####4}{####5}{####6}{####7}}% + \or\csdef{multilang@@runcmd@#2}{\csuse{multilang@@typecmd@#2}% + {####1}{####2}{####3}{####4}{####5}{####6}{####7}{####8}}% + \or\csdef{multilang@@runcmd@#2}{\csuse{multilang@@typecmd@#2}% + {####1}{####2}{####3}{####4}{####5}{####6}{####7}{####8}{####9}}% + \else\multilang@error{Argument count expected to be between 0 and 9, % + but is '#1'}\fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\multilang@@types} +% The |\multilang@@types| macro collects and holds an \textsf{etoolbox} list +% of datatypes defined via |\NewMultilangType|. +% \begin{macrocode} +\newcommand\multilang@@types{} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\NewMultilangType@code} +% The |\NewMultilangType@code|\oarg{argcount}\marg{typename}\marg{format} +% macro is an internal counterpart to |\NewMultilangType| with which not +% not the |.style| but the |.code| property of the \meta{typename} key is +% defined. This is indicated by defining the +% |\multilang@@codetype@|\meta{typename} macro here and checking whether this +% macro is defined in |\multilang@regfieldtype|. +% \begin{macrocode} +\newcommand\NewMultilangType@code[3][1]{% + \csdef{multilang@@codetype@#2}{true}% + \NewMultilangType[#1]{#2}{#3}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\multilang@regfield} +% The |\multilang@regfield|\marg{cmd-or-env}\marg{fieldname} macro registers +% the respective \textsf{pgfkeys} keys for \meta{fieldname} for all registered datatypes. +% \begin{macrocode} +\newcommand\multilang@regfield[2]{% + \pgfqkeys{\multilang@keyof{#1}}{% + #2/.code={\csdef{multilang@@val@#2}{##1}}}% + \forlistloop{\multilang@regfieldtype{#1}{#2}}{\multilang@@types}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\multilang@regfieldtype} +% The |\multilang@regfieldtype|\marg{cmd-or-env}\marg{fieldname}\marg{typename} +% macro registers the \textsf{pgfkeys} key for \meta{typename} of +% \meta{fieldname}. +% \begin{macrocode} +\newcommand\multilang@regfieldtype[3]{% + \bgroup +% \end{macrocode} +% In the following, we check whether the number of arguments for the +% \meta{typename} macro is 1, because for some reason |style n args| seems not +% to work as we want it to work if $n=1$. +% \begin{macrocode} + \ifnumequal{\csuse{multilang@@typeargc@#3}}{1}{% + \ifcsdef{multilang@@codetype@#3}{% + \edef\do{\egroup\noexpand\pgfqkeys{\multilang@keyof{#1}}{% + #2/#3/.code={\csexpandonce{multilang@@runcmd@#3}}% + }}% + }{% + \edef\do{\egroup\noexpand\pgfqkeys{\multilang@keyof{#1}}{% + #2/#3/.style={#2={\csexpandonce{multilang@@runcmd@#3}}}% + }}% + }% + }{% + \ifcsdef{multilang@@codetype@#3}{% + \edef\do{\egroup\noexpand\pgfqkeys{\multilang@keyof{#1}}{% + #2/#3/.code n args={\csuse{multilang@@typeargc@#3}}% + {\csexpandonce{multilang@@runcmd@#3}}}}% + }{% + \edef\do{\egroup\noexpand\pgfqkeys{\multilang@keyof{#1}}{% + #2/#3/.style n args={\csuse{multilang@@typeargc@#3}}% + {#2={\csexpandonce{multilang@@runcmd@#3}}}}}% + }% + }\do} +% \end{macrocode} +% \end{macro} +% +% +% \subsubsection{Argument Aliases} +% +% \begin{macro}{\multilang@regcomb} +% The |\multilang@regcomb|\marg{cmd-or-env}\marg{alias}\marg{fields} +% macro registers an \meta{alias} argument for \meta{fields}. +% \begin{macrocode} +\newcommand\multilang@regcomb[3]{% + \multilang@regcombtype{#1}{#2}{#3}{}% + \forlistloop{\multilang@regcomb@i{#1}{#2}{#3}}{\multilang@@types}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\multilang@regcomb@i} +% The +% |\multilang@regcomb@i|\marg{cmd-or-env}\marg{alias}\marg{fields}\marg{type} +% macro is an auxiliary front-end to |\multilang@regcombtype| that transforms +% \meta{type} to a key \meta{suffix} (by prepending a ``|/|''). +% \begin{macrocode} +\newcommand\multilang@regcomb@i[4]{% + \multilang@regcombtype{#1}{#2}{#3}{/#4}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\multilang@regcombtype} +% The +% |\multilang@regcombtype|\marg{cmd-or-env}\marg{alias}\marg{fields}\marg{suffix} +% registers the \meta{alias} with the given type-\meta{suffix}. +% \begin{macrocode} +\newcommand\multilang@regcombtype[4]{% + \bgroup +% \end{macrocode} +% We count the number of field names in \meta{fields} (in |\@tempcnta|) and, +% in the same loop, gather the individual field assignments (in |\toks@|). +% \begin{macrocode} + \toks@{}\@tempcnta=0\relax + \forcsvlist{% + \advance\@tempcnta by1\relax + \expandafter\multilang@regcomb@set\expandafter{\the\@tempcnta}{#4}% + }{#3}% +% \end{macrocode} +% Finally, we set the style for the \meta{alias}\meta{suffix} key. Again we +% separately handle the case of a single field. Additionally, we treat also +% the case of \emph{no} field special: It gets a |style| (with 1 argument), +% but the argument is essentially ignored (as |\toks@| is empty). This makes +% \meta{alias} a ``comment'' field that is not passed to the |command| or +% |environment|. +% \begin{macrocode} + \ifnumgreater{\the\@tempcnta}{1}{% + \edef\do{\egroup\noexpand\pgfqkeys{\multilang@keyof{#1}}{% + #2#4/.style n args={\the\@tempcnta}{\the\toks@}}}% + }{% + \edef\do{\egroup\noexpand\pgfqkeys{\multilang@keyof{#1}}{% + #2#4/.style={\the\toks@}}}% + }% + \do} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\multilang@regcomb@set} +% The |\multilang@regcomb@set|\marg{index}\marg{suffix}\marg{field} macro +% appends the sequence ``\meta{field}\meta{suffix}|={#|\meta{index}|}|'' to +% the |toks@| register. When used in a |.style n args| key, this sets the +% ``\meta{field}\meta{suffix}'' key to the \meta{index}-th positional +% parameter. +% \begin{macrocode} +\newcommand\multilang@regcomb@set[3]{% + \toks@\expandafter{\the\toks@,#3#2={###1}}} +% \end{macrocode} +% \end{macro} +% +% +% \subsubsection{Language ``Types''} +% +% \begin{macro}{\multilang@addlanguage} +% The |\multilang@addlanguage|\marg{language} registers \meta{language}, +% essentially registering ``\meta{language}'' and ``\meta{language}|!|'' as +% argument datatypes. +% \begin{macrocode} +\newcommand\multilang@addlanguage[1]{% +% \end{macrocode} +% The following checks the current language (|\languagename|) against +% \meta{language}. In the following, +% |##1| is the argument to the key when the key is used. +% \begin{macrocode} + \ifdefstring{\languagename}{#1}% + {\NewMultilangType{#1}{##1}}% + {\NewMultilangType@code{#1}{}}% +% \end{macrocode} +% The following defines the ``\meta{language}|!|'' key for forcing an +% argument to be formatted in language \meta{language}. +% \begin{macrocode} + \NewMultilangType{#1!}{\foreignlanguage{#1}{##1}}} +% \end{macrocode} +% \end{macro} +% Register all languages passed as argument to the package. +% \begin{macrocode} +\forlistloop{\multilang@addlanguage}{\multilang@@langs} +% \end{macrocode} +% +% +% \subsection{Auxiliary Macros} +% +% \begin{macro}{\multilang@keyof} +% The |\multilang@keyof|\marg{cmd-or-env}, when fully expanded such as in the +% first argument of the |\pgfqkeys| macro, represents the key under which the +% parameter keys of the command or environment \meta{cmd-or-env} are stored. +% Note that the branching in the code below checks whether \meta{cmd-or-env} +% is a command sequence (|true| case) or not (|false| case). +% \begin{macrocode} +\newcommand\multilang@keyof[1]{% + \ifcat\relax\noexpand#1% + /multilang/cmd/\expandafter\@gobble\string#1% + \else + /multilang/env/#1% + \fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\multilang@error} +% The |\multilang@error|\marg{message} macro shows \meta{message} as an error +% message of the \ThisPackage package. +% \begin{macrocode} +\newcommand\multilang@error[1]{\PackageError{multilang}{#1}{}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\multilang@processargs} +% The |\multilang@processargs|\marg{cmd-or-env}\marg{opt-key}\marg{options} +% macro processes the \meta{options} in key \meta{opt-key}. Afterwards, it +% post-processes the arguments |margs|, |oargs|, |alias/...|, and +% |disablable|. +% It stores the result of the post-processing in the macros +% |\multilang@@actuals|, |\multilang@@checks|, and |\multilang@@keys|. +% \begin{macrocode} +\newcommand\multilang@processargs[3]{% + \let\multilang@@aliases=\empty + \pgfqkeys{#2}{#3}% +% \end{macrocode} +% In the following, we iteratively construct three macros: +% |\multilang@@actuals|, |\multilang@@checks|, and |\multilang@@keys|. +% \begin{itemize}[nosep] +% \item In |\multilang@@actuals|, we step by step construct the arguments that +% shall be passed to \meta{cmd-or-env}. +% \item In |\multilang@@checks|, we construct a list of preliminary checks +% that \meta{cmd-or-env} shall perform on its arguments. +% \item In |\multilang@@keys|, we construct a list of |\pgfqkeys| commands +% that set up the keys for \meta{cmd-or-env}'s one argument. +% \end{itemize} +% The following first initializes the three macros. +% \begin{macrocode} + \edef\multilang@@actuals{}% + \def\multilang@@checks{}% + \def\multilang@@keys{}% +% \end{macrocode} +% We first process the optional arguments. We process them before the +% mandatory arguments because they must come first in |\multilang@@actuals|. +% In the following |\do| macro, |##1| iterates over all optional argument +% names in the |margs| list. +% \begin{macrocode} + \ifdefvoid{\multilang@@oargs}{}{% + \def\do##1{% + \appto{\multilang@@actuals}{% + \ifcsmacro{multilang@@val@##1}% + {[\csexpandonce{multilang@@val@##1}]}% + {}% + }% + \appto{\multilang@@keys}{\multilang@regfield{#1}{##1}}% + }% + \expandafter\docsvlist\expandafter{\multilang@@oargs}}% +% \end{macrocode} +% Next, we append the mandatory arguments, specified by the |margs| list. +% In the following |\do| macro, |##1| iterates over all mandatory argument +% names in the |margs| list. +% \begin{macrocode} + \ifdefvoid{\multilang@@margs}{}{% + \def\do##1{% + \appto{\multilang@@actuals}{% + {\csexpandonce{multilang@@val@##1}}% + }% + \appto{\multilang@@checks}{% + \ifcsmacro{multilang@@val@##1}% + {}% + {\multilang@error{mandatory argument ##1 missing}}% + }% + \appto{\multilang@@keys}{\multilang@regfield{#1}{##1}}% + }% + \expandafter\docsvlist\expandafter{\multilang@@margs}}% +% \end{macrocode} +% Afterwards, we handle argument aliases. The list of aliases' names is in +% |\multilang@@aliases| and the list of arguments that a \meta{alias} +% combines is in |\multilang@@alias@|\meta{alias}. +% Note that aliases only modify |\multilang@@keys| -- i.e., not +% |\multilang@@actuals| or |\multilang@@checks|. +% \begin{macrocode} + \def\do##1{% + \eappto{\multilang@@keys}{% + \unexpanded{\multilang@regcomb{#1}{##1}}% + {\csuse{multilang@@alias@##1}}}}% + \expandafter\dolistloop\expandafter{\multilang@@aliases}% +% \end{macrocode} +% To handle |disablable| macros, we simply add the |disabled| key. This key is +% a Boolean key that just sets a conditional. +% \begin{macrocode} + \ifbool{multilang@@disablable}% + {\eappto{\multilang@@keys}{% + \noexpand\pgfqkeys{\multilang@keyof{#1}}{% + disabled/.is if={multilang@cmd@@disabled}}}}% + {}% +% \end{macrocode} +% Invoke the hook. To avoid macro arguments to the hook, we store the command or +% environment name in |\multilang@@cmdorenv| and store the \textsf{pgfkeys} key +% for the command or environment in |\multilang@@cekey|. +% \begin{macrocode} + \def\multilang@@cmdorenv{#1}% + \edef\multilang@@cekey{\multilang@keyof{#1}}% + \multilang@hook@processargs +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\multilang@hook@processargs} +% The |\multilang@hook@processargs| macro is a hook that enables extensions to +% the |\multilang@processargs|. +% \begin{macrocode} +\newcommand\multilang@hook@processargs{} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\multilang@noend} +% The |\multilang@noend|\marg{body} macro is intended to be used as the +% argument to |\Collect@Body| (or |\collect@body|) of the \textsf{environ} +% package. In this context, it performs the following: +% Firstly, it ignores the collected \meta{body} of the environment. +% Secondly, it temporarily disables the |\end|-code of the environment in +% which the |\Collect@Body| is expanded. +% \begin{macrocode} +\newcommand\multilang@noend[1]{\cslet{end\@currenvir}{\relax}} +% \end{macrocode} +% \end{macro} +% +%\iffalse +% +%<*pkgtags> +%\fi +% +% \section{Implementation of Tags} +% +% \begin{macro}{\SetTagFilter} +% The |\SetTagFilter|\oarg{default}\marg{policy} sets the tag filter policy +% based on accept/deny rules in \meta{policy}. +% \begin{macrocode} +\newcommand\SetTagFilter[2][accept]{% + \kcvml@parsepolicy{kcvml@@tagfilter}{#1}{#2}} +\newcommand\kcvml@@tagfilter{} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\DefineTagFilter} +% The |\DefineTagFilter|\marg{name}\marg{default}\marg{policy} macro defines a +% tag filter policy under name \meta{name}. +% \begin{macrocode} +\newcommand\DefineTagFilter[3]{% + \kcvml@parsepolicy{kcvml@filter@@#1}{#2}{#3}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\UseFilter} +% The |\UseTagFilter|\marg{name} macro uses the previously defined tag filter +% policy with name \meta{name}. +% \begin{macrocode} +\newcommand\UseTagFilter[1]{% + \letcs\kcvml@@tagfilter{kcvml@filter@@#1}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\kcvml@parsepolicy} +% The |\kcvml@parsepolicy|\marg{csname}\marg{default}\marg{policy} +% parses a tag filter policy, \meta{policy} with default \meta{default}, and +% stores the resulting filter in the control sequence \meta{csname}. +% \begin{macrocode} +\newcommand\kcvml@parsepolicy[3]{% +% \end{macrocode} +% We first reset the temporary filter variable |\kcvml@@tmptagfilter| then +% populate it via |\pgfqkeys|, first with the \meta{policy} list and +% subsequently with the \meta{default} policy. +% \begin{macrocode} + \bgroup + \def\kcvml@@tmptagfilter{}% + \pgfqkeys{kcvml/tagfilter}{#3,default/#2}% +% \end{macrocode} +% Now we export the temporary |\kcvml@@tmptagfilter| to outside the local group +% and into the control sequence \meta{csname}. +% \begin{macrocode} + \edef\do{\egroup + \unexpanded{\csdef{#1}}{\expandonce{\kcvml@@tmptagfilter}}}% + \do} +% \end{macrocode} +% The following lines specify how |\kcvml@@tmptagfilter| is modified when +% |accept| or |deny| filter rules are specified. +% \begin{macrocode} +\pgfqkeys{kcvml/tagfilter}{% + accept/.code={\kcvml@appendrule{#1}{\boolfalse}{\booltrue}}, + deny/.code ={\kcvml@appendrule{#1}{\booltrue}{\boolfalse}}, + default/accept/.code n args={0}{\appto\kcvml@@tmptagfilter{% + \kcvml@applydefault{\boolfalse}}}, + default/deny/.code n args={0}{\appto\kcvml@@tmptagfilter{% + \kcvml@applydefault{\booltrue}}}, +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\kcvml@appendrule} +% The |\kcvml@appendrule|\marg{ruletags}\marg{flagmacro}\marg{invmacro} macro +% appends a filter rule to the overall tag filter. The rule filters for the +% given comma-separated list \meta{ruletags}. +% The \meta{flagmacro} specifies whether a match shall be disabled (if +% |\booltrue|) or enabled (if |\boolfalse|). +% The \meta{invmacro} must be the inverse of \meta{flagmacro}. +% \begin{macrocode} +\newcommand\kcvml@appendrule[3]{% + \bgroup +% \end{macrocode} +% For simplified later processing, we turn \meta{ruletags} into an +% \textsf{etoolbox} list (in |\kcvml@@ruletags|) first. +% \begin{macrocode} + \def\kcvml@@ruletags{}% + \forcsvlist{\listadd{\kcvml@@ruletags}}{#1}% +% \end{macrocode} +% Now we append to the overall filter (in |\kcvml@@tmptagfilter|) outside the +% local group and use the cascade of |\expandafter|s to get |\cvmkl@@ruletags| +% out of the group without polluting the outer scope. +% \begin{macrocode} + \expandafter\egroup + \expandafter\listadd\expandafter\kcvml@@tmptagfilter\expandafter{% + \expandafter\kcvml@applyrule\expandafter{\kcvml@@ruletags}{#2}{#3}}} +% \end{macrocode} +% \end{macro} +% +% We add the additional |tags| key to every disablable multilingual macro and +% environment. For this, we use \textsf{multilang}'s +% |\multilang@hook@processargs| hook. +% \begin{macrocode} +\appto\multilang@hook@processargs{% + \ifbool{multilang@@disablable}% + {\eappto{\multilang@@keys}{% +% \end{macrocode} +% Note that in |\multilang@@cekey|, the parent key of the command or environment +% is stored. Whenever the |tags| argument is used, we make it invoke +% |\kcvml@applyfilter| with the given \meta{tags} (|##1|). +% \begin{macrocode} + \noexpand\pgfqkeys{\multilang@@cekey}{% + tags/.code={\noexpand\kcvml@applyfilter{##1}}}}} + {}} +% \end{macrocode} +% +% \begin{macro}{\kcvml@applyfilter} +% The |\kcvml@applyfilter|\marg{tags} macro applies the current filter, which is +% in the |\kcvml@@tagfilter| \textsf{etoolbox} list, to the comma-separated list +% \meta{tags} of tags to check whether the entity with the \meta{tags} should be +% disabled or not. The result of the check is stored in the Boolean flag +% |multilang@cmd@@disabled| for further use in with \textsf{multilang} code. +% \begin{macrocode} +\newcommand\kcvml@applyfilter[1]{% + \ifbool{multilang@cmd@@disabled}{}{% +% \end{macrocode} +% We check the filter only if the entry has not already explicitly been marked +% as disabled. I.e., explicit disabling takes precedence, no matter whether it +% is specified before or after a |tags| element. +% In the Boolean flag |kcvml@@match|, we store whether a tag in \meta{tags} +% matched one of the accept/deny filters already. After initializing this flag, +% we iterate through |\kcvml@@tagfilter| with |\do|\marg{rule}, and +% we stop iterating after a match has been found. +% \begin{macrocode} + \boolfalse{kcvml@@match}% + \def\do##1{% +% \end{macrocode} +% Note that \meta{rule} is a curried macro whose missing last argument, +% \meta{tags}, is added here. +% \begin{macrocode} + ##1{#1}% + \ifbool{kcvml@@match}{\listbreak}{}}% + \dolistloop{\kcvml@@tagfilter}}} +\newbool{kcvml@@match} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\kcvml@applyrule} +% The +% |\kcvml@applyrule|\marg{ruletags}\marg{flagmacro}\marg{invmacro}\marg{tags} +% macro applies a single filter rule to the given \meta{tags}. +% The \meta{flagmacro} must be either |\booltrue| or |\boolfalse|. +% If it is |\booltrue|, this specifies that a match of \meta{tags} against +% \meta{ruletags} disables the display of the respective entity; +% If it is |\boolfalse|, this specifies that a match enables the display. +% The \meta{invmacro} must be the inverse of \meta{flagmacro}. +% We just check each tag in \meta{tags} individually. +% \begin{macrocode} +\newcommand\kcvml@applyrule[4]{% + \forcsvlist{\kcvml@applyrule@i{#1}{#2}{#3}}{#4}} +% \end{macrocode} +% +% \begin{macro}{\kcvml@applyrule@i} +% The +% |\kcvml@applyrule@i|\marg{ruletags}\marg{flagmacro}\marg{invmacro}\marg{tag} +% macro applies a single filter rule to the given \meta{tag}. +% It checks whether the \meta{tag} is inverted (i.e., starting with ``|!|'') and +% hands over the actual check to |\kcvml@applyrule@ii|. +% \begin{macrocode} +\newcommand\kcvml@applyrule@i[4]{% + \if !\@car#4\@nil + \expandafter\kcvml@applyrule@ii\expandafter{\@cdr#4\@nil}{#1}{#3}% + \else + \kcvml@applyrule@ii{#4}{#1}{#2}\fi} +% \end{macrocode} +% \begin{macro}{\kcvml@applyrule@ii} +% The +% |\kcvml@applyrule@ii|\marg{tag}\marg{ruletags}\marg{flagmacro} +% macro applies a single filter rule to the given \meta{tag}. +% We check whether \meta{tag} in in the \textsf{etoolbox} list \meta{ruletags}. +% Since |\ifinlist| expects a list macro for its second argument (which it then +% expands once), we just give it |\empty| to eat (expand) and then use +% \meta{ruletags} as it is. +% \begin{macrocode} +\newcommand\kcvml@applyrule@ii[3]{% + \ifinlist{#1}{\empty #2}% +% \end{macrocode} +% If we have a match, we apply \meta{flagmacro} to |multilang@cmd@@disabled| and +% then record, in |kcvml@@match|, that we found a match. +% \begin{macrocode} + {#3{multilang@cmd@@disabled}\booltrue{kcvml@@match}}{}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\kcvml@applydefault} +% The |\kcvml@applydefault|\marg{flagmacro}\marg{tags} macro applies a default +% filter to \meta{tags}. A \meta{flagmacro} of |\booltrue| corresponds to a +% ``default deny''; |\boolfalse| corresponds to ``default accept''. +% \begin{macrocode} +\newcommand\kcvml@applydefault[2]{% + #1{multilang@cmd@@disabled}} +% \end{macrocode} +% \end{macro} +% +%\iffalse +% +%<*pkgsect> +%\fi +% +% \section{Implementation of Sectioning Environments} +% +% The sectioning environments are proxies for the corresponding sectioning +% macros. They are defined as environments such that the whole environments +% rather than just the headings can be disabled. +% Each of the environments has one optional argument, |short| (for a short +% title), and one mandatory argument, |title| (for the actual title). +% +% \begin{environment}{Section} +% \begin{environment}{Section*} +% The |Section| and |Section*| environments are +% multilingual proxies to |\section| and, respectively, |\section*|. +% \begin{macrocode} +\NewMultilangEnv{Section}{disablable, + environment=section, oargs=short, margs=title} +\NewMultilangEnv{Section*}{disablable, + environment=multilang@secstar, oargs=short, margs=title} +\newenvironment{multilang@secstar}{\section*}{} +% \end{macrocode} +% \end{environment} +% \end{environment} +% +% \begin{environment}{SubSection} +% \begin{environment}{SubSection*} +% The |SubSection| and |SubSection*| environments are +% multilingual proxies to |\subsection| and, respectively, |\subsection*|. +% \begin{macrocode} +\NewMultilangEnv{SubSection}{disablable, + environment=subsection, oargs=short, margs=title} +\NewMultilangEnv{SubSection*}{disablable, + environment=multilang@ssecstar, oargs=short, margs=title} +\newenvironment{multilang@ssecstar}{\subsection*}{} +% \end{macrocode} +% \end{environment} +% \end{environment} +% +% \begin{environment}{SubSubSection} +% \begin{environment}{SubSubSection*} +% The |SubSubSection| and |SubSubSection*| environments are +% multilingual proxies to |\subsubsection| and, respectively, |\subsubsection*|. +% \begin{macrocode} +\NewMultilangEnv{SubSubSection}{disablable, + environment=subsubsection, oargs=short, margs=title} +\NewMultilangEnv{SubSubSection*}{disablable, + environment=multilang@sssecstar, oargs=short, margs=title} +\newenvironment{multilang@sssecstar}{\subsubsection*}{} +% \end{macrocode} +% \end{environment} +% \end{environment} +% +% \begin{environment}{Paragraph} +% \begin{environment}{Paragraph*} +% The |Paragraph| and |Paragraph*| environments are +% multilingual proxies to |\paragraph| and, respectively, |\paragraph*|. +% \begin{macrocode} +\NewMultilangEnv{Paragraph}{disablable, + environment=paragraph, oargs=short, margs=title} +\NewMultilangEnv{Paragraph*}{disablable, + environment=multilang@parstar, oargs=short, margs=title} +\newenvironment{multilang@parstar}{\paragraph*}{} +% \end{macrocode} +% \end{environment} +% \end{environment} +% +% \begin{environment}{SubParagraph} +% \begin{environment}{SubParagraph*} +% The |SubParagraph| and |SubParagraph*| environments are +% multilingual proxies to |\subparagraph| and, respectively, |\subparagraph*|. +% \begin{macrocode} +\NewMultilangEnv{SubParagraph}{disablable, + environment=subparagraph, oargs=short, margs=title} +\NewMultilangEnv{SubParagraph*}{disablable, + environment=multilang@sparstar, oargs=short, margs=title} +\newenvironment{multilang@sparstar}{\subparagraph*}{} +% \end{macrocode} +% \end{environment} +% \end{environment} +% +% +%\iffalse +% +%\fi +% \Finale +\endinput diff --git a/Master/texmf-dist/source/latex/multilang/multilang.ins b/Master/texmf-dist/source/latex/multilang/multilang.ins new file mode 100644 index 00000000000..7d367b45927 --- /dev/null +++ b/Master/texmf-dist/source/latex/multilang/multilang.ins @@ -0,0 +1,38 @@ +%% +%% Copyright (C) 2016-2017 by Richard Gay +%% +%% This file may be distributed and/or modified under the conditions of +%% the LaTeX Project Public License, either version 1.2 of this license +%% or (at your option) any later version. The latest version of this +%% license is in: +%% +%% http://www.latex-project.org/lppl.txt +%% +%% and version 1.2 or later is part of all distributions of LaTeX version +%% 1999/12/01 or later. +%% +\input docstrip.tex +\keepsilent + +\usedir{tex/latex/multilang} +\preamble + +Copyright (C) 2016-2017 by Richard Gay + +This file may be distributed and/or modified under the conditions of +the LaTeX Project Public License, either version 1.2 of this license +or (at your option) any later version. The latest version of this +license is in: + + http://www.latex-project.org/lppl.txt + +and version 1.2 or later is part of all distributions of LaTeX version +1999/12/01 or later. + +\endpreamble + +\generate{\file{multilang.sty}{\from{multilang.dtx}{package}}} +\generate{\file{multilang-tags.sty}{\from{multilang.dtx}{pkgtags}}} +\generate{\file{multilang-sect.sty}{\from{multilang.dtx}{pkgsect}}} + +\endbatchfile diff --git a/Master/texmf-dist/tex/latex/multilang/multilang-sect.sty b/Master/texmf-dist/tex/latex/multilang/multilang-sect.sty new file mode 100644 index 00000000000..a143ff08bd8 --- /dev/null +++ b/Master/texmf-dist/tex/latex/multilang/multilang-sect.sty @@ -0,0 +1,54 @@ +%% +%% This is file `multilang-sect.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% multilang.dtx (with options: `pkgsect') +%% +%% Copyright (C) 2016-2017 by Richard Gay +%% +%% This file may be distributed and/or modified under the conditions of +%% the LaTeX Project Public License, either version 1.2 of this license +%% or (at your option) any later version. The latest version of this +%% license is in: +%% +%% http://www.latex-project.org/lppl.txt +%% +%% and version 1.2 or later is part of all distributions of LaTeX version +%% 1999/12/01 or later. +%% +\NeedsTeXFormat{LaTeX2e}[1999/12/01] +\ProvidesPackage{multilang-sect}[2017/08/30 v0.9 Multilingual sectioning environments] + + + + +\NewMultilangEnv{Section}{disablable, + environment=section, oargs=short, margs=title} +\NewMultilangEnv{Section*}{disablable, + environment=multilang@secstar, oargs=short, margs=title} +\newenvironment{multilang@secstar}{\section*}{} +\NewMultilangEnv{SubSection}{disablable, + environment=subsection, oargs=short, margs=title} +\NewMultilangEnv{SubSection*}{disablable, + environment=multilang@ssecstar, oargs=short, margs=title} +\newenvironment{multilang@ssecstar}{\subsection*}{} +\NewMultilangEnv{SubSubSection}{disablable, + environment=subsubsection, oargs=short, margs=title} +\NewMultilangEnv{SubSubSection*}{disablable, + environment=multilang@sssecstar, oargs=short, margs=title} +\newenvironment{multilang@sssecstar}{\subsubsection*}{} +\NewMultilangEnv{Paragraph}{disablable, + environment=paragraph, oargs=short, margs=title} +\NewMultilangEnv{Paragraph*}{disablable, + environment=multilang@parstar, oargs=short, margs=title} +\newenvironment{multilang@parstar}{\paragraph*}{} +\NewMultilangEnv{SubParagraph}{disablable, + environment=subparagraph, oargs=short, margs=title} +\NewMultilangEnv{SubParagraph*}{disablable, + environment=multilang@sparstar, oargs=short, margs=title} +\newenvironment{multilang@sparstar}{\subparagraph*}{} +\endinput +%% +%% End of file `multilang-sect.sty'. diff --git a/Master/texmf-dist/tex/latex/multilang/multilang-tags.sty b/Master/texmf-dist/tex/latex/multilang/multilang-tags.sty new file mode 100644 index 00000000000..66ab2a6133c --- /dev/null +++ b/Master/texmf-dist/tex/latex/multilang/multilang-tags.sty @@ -0,0 +1,84 @@ +%% +%% This is file `multilang-tags.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% multilang.dtx (with options: `pkgtags') +%% +%% Copyright (C) 2016-2017 by Richard Gay +%% +%% This file may be distributed and/or modified under the conditions of +%% the LaTeX Project Public License, either version 1.2 of this license +%% or (at your option) any later version. The latest version of this +%% license is in: +%% +%% http://www.latex-project.org/lppl.txt +%% +%% and version 1.2 or later is part of all distributions of LaTeX version +%% 1999/12/01 or later. +%% +\NeedsTeXFormat{LaTeX2e}[1999/12/01] +\ProvidesPackage{multilang-tags}[2017/08/30 v0.9 Filtering of multilingual macros by tags] + + + + +\newcommand\SetTagFilter[2][accept]{% + \kcvml@parsepolicy{kcvml@@tagfilter}{#1}{#2}} +\newcommand\kcvml@@tagfilter{} +\newcommand\DefineTagFilter[3]{% + \kcvml@parsepolicy{kcvml@filter@@#1}{#2}{#3}} +\newcommand\UseTagFilter[1]{% + \letcs\kcvml@@tagfilter{kcvml@filter@@#1}} +\newcommand\kcvml@parsepolicy[3]{% + \bgroup + \def\kcvml@@tmptagfilter{}% + \pgfqkeys{kcvml/tagfilter}{#3,default/#2}% + \edef\do{\egroup + \unexpanded{\csdef{#1}}{\expandonce{\kcvml@@tmptagfilter}}}% + \do} +\pgfqkeys{kcvml/tagfilter}{% + accept/.code={\kcvml@appendrule{#1}{\boolfalse}{\booltrue}}, + deny/.code ={\kcvml@appendrule{#1}{\booltrue}{\boolfalse}}, + default/accept/.code n args={0}{\appto\kcvml@@tmptagfilter{% + \kcvml@applydefault{\boolfalse}}}, + default/deny/.code n args={0}{\appto\kcvml@@tmptagfilter{% + \kcvml@applydefault{\booltrue}}}, +} +\newcommand\kcvml@appendrule[3]{% + \bgroup + \def\kcvml@@ruletags{}% + \forcsvlist{\listadd{\kcvml@@ruletags}}{#1}% + \expandafter\egroup + \expandafter\listadd\expandafter\kcvml@@tmptagfilter\expandafter{% + \expandafter\kcvml@applyrule\expandafter{\kcvml@@ruletags}{#2}{#3}}} +\appto\multilang@hook@processargs{% + \ifbool{multilang@@disablable}% + {\eappto{\multilang@@keys}{% + \noexpand\pgfqkeys{\multilang@@cekey}{% + tags/.code={\noexpand\kcvml@applyfilter{##1}}}}} + {}} +\newcommand\kcvml@applyfilter[1]{% + \ifbool{multilang@cmd@@disabled}{}{% + \boolfalse{kcvml@@match}% + \def\do##1{% + ##1{#1}% + \ifbool{kcvml@@match}{\listbreak}{}}% + \dolistloop{\kcvml@@tagfilter}}} +\newbool{kcvml@@match} +\newcommand\kcvml@applyrule[4]{% + \forcsvlist{\kcvml@applyrule@i{#1}{#2}{#3}}{#4}} +\newcommand\kcvml@applyrule@i[4]{% + \if !\@car#4\@nil + \expandafter\kcvml@applyrule@ii\expandafter{\@cdr#4\@nil}{#1}{#3}% + \else + \kcvml@applyrule@ii{#4}{#1}{#2}\fi} +\newcommand\kcvml@applyrule@ii[3]{% + \ifinlist{#1}{\empty #2}% + {#3{multilang@cmd@@disabled}\booltrue{kcvml@@match}}{}} +\newcommand\kcvml@applydefault[2]{% + #1{multilang@cmd@@disabled}} +\endinput +%% +%% End of file `multilang-tags.sty'. diff --git a/Master/texmf-dist/tex/latex/multilang/multilang.sty b/Master/texmf-dist/tex/latex/multilang/multilang.sty new file mode 100644 index 00000000000..41be4b0f48e --- /dev/null +++ b/Master/texmf-dist/tex/latex/multilang/multilang.sty @@ -0,0 +1,251 @@ +%% +%% This is file `multilang.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% multilang.dtx (with options: `package') +%% +%% Copyright (C) 2016-2017 by Richard Gay +%% +%% This file may be distributed and/or modified under the conditions of +%% the LaTeX Project Public License, either version 1.2 of this license +%% or (at your option) any later version. The latest version of this +%% license is in: +%% +%% http://www.latex-project.org/lppl.txt +%% +%% and version 1.2 or later is part of all distributions of LaTeX version +%% 1999/12/01 or later. +%% +\NeedsTeXFormat{LaTeX2e}[1999/12/01] +\ProvidesPackage{multilang} + [2017/08/30 v0.9 Tools for maintaining documents in multiple languages] + + + + +\RequirePackage{pgfkeys,pgfopts} +\RequirePackage{etoolbox} +\RequirePackage{environ} +\newcommand\multilang@@langs{} +\pgfqkeys{/multilang/pkg}{ + languages/.code={\forcsvlist{\listadd\multilang@@langs}{#1}}, +} +\ProcessPgfOptions{/multilang/pkg} +\newcommand\NewMultilangCmd[2]{% + \bgroup + \multilang@processargs{#1}{/multilang/newcommand}{defaults={},#2}% + \expandafter\def\expandafter\multilang@@intcmd\expandafter{% + \csname multilang@intcmd@\expandafter\@gobble\string#1\endcsname}% + \edef\do{\egroup + \expandonce{\multilang@@keys}% + \ifbool{multilang@@starred}{% + \unexpanded{\newcommand#1}{% + \noexpand\@ifstar + {\expandonce{\multilang@@intcmd}{*}}% + {\expandonce{\multilang@@intcmd}{}}}% + }{% + \unexpanded{\newcommand#1}{\expandonce{\multilang@@intcmd}{}}% + }% + \noexpand\newcommand{\expandonce{\multilang@@intcmd}}[2]{% + \bgroup + \noexpand\boolfalse{multilang@cmd@@disabled}% + \noexpand\pgfqkeys{\multilang@keyof{#1}}{% + \expandonce{\multilang@@defaults},####2}% + \noexpand\ifbool{multilang@cmd@@disabled}% + {\unexpanded{\def\multilang@@invok{}}}% + {\expandonce{\multilang@@checks}% + \unexpanded{\edef\multilang@@invok}{% + \noexpand\unexpanded{\expandonce{\multilang@@cmd}}####1% + \expandonce{\multilang@@actuals}}}% + \unexpanded{\expandafter\egroup\multilang@@invok}% + }% + }\do} +\newcommand\NewMultilangEnv[2]{% + \bgroup + \multilang@processargs{#1}{/multilang/newenvir}{defaults={},#2}% + \edef\do{\egroup + \expandonce{\multilang@@keys}% + \unexpanded{\newenvironment{#1}}[1]{% + \bgroup + \noexpand\boolfalse{multilang@cmd@@disabled}% + \noexpand\pgfqkeys{\multilang@keyof{#1}}{####1}% + \noexpand\ifbool{multilang@cmd@@disabled}% + {\unexpanded{% + \def\multilang@@invok{\Collect@Body{\multilang@noend}}}}% + {\expandonce{\multilang@@checks}% + \unexpanded{\edef\multilang@@invok}{% + \noexpand\noexpand\noexpand\begin{\multilang@@env}% + \expandonce{\multilang@@actuals}}}% + \unexpanded{\expandafter\egroup\multilang@@invok}% + }{% + \noexpand\end{\multilang@@env}% + }% + }\do} +\pgfqkeys{/multilang/cmd-or-env}{ + margs/.store in={\multilang@@margs}, + oargs/.store in={\multilang@@oargs}, + alias/.is family, + alias/.unknown/.code={% + \listeadd{\multilang@@aliases}{\pgfkeyscurrentname}% + \csdef{multilang@@alias@\pgfkeyscurrentname}{#1}}, + defaults/.store in={\multilang@@defaults}, + disablable/.is if={multilang@@disablable}, +} +\newbool{multilang@@disablable} +\newbool{multilang@cmd@@disabled} +\pgfqkeys{/multilang/newcommand}{ + .search also={/multilang/cmd-or-env}, + command/.store in={\multilang@@cmd}, + starred/.is if={multilang@@starred}, + alias/.search also={/multilang/cmd-or-env}, +} +\newbool{multilang@@starred} +\pgfqkeys{/multilang/newenvir}{ + .search also={/multilang/cmd-or-env}, + environment/.store in={\multilang@@env}, + alias/.search also={/multilang/cmd-or-env}, +} +\newcommand\NewMultilangType[3][1]{% + \listadd\multilang@@types{#2}% + \expandafter\newcommand\csname multilang@@typecmd@#2\endcsname[#1]{#3}% + \csdef{multilang@@typeargc@#2}{#1}% + \ifcase#1\relax + \csdef{multilang@@runcmd@#2}{\csuse{multilang@@typecmd@#2}}% + \or\ifcsequal{multilang@@typecmd@#2}{@firstofone}% + {\csdef{multilang@@runcmd@#2}{####1}}% + {\csdef{multilang@@runcmd@#2}{\csuse{multilang@@typecmd@#2}% + {####1}}}% + \or\csdef{multilang@@runcmd@#2}{\csuse{multilang@@typecmd@#2}% + {####1}{####2}}% + \or\csdef{multilang@@runcmd@#2}{\csuse{multilang@@typecmd@#2}% + {####1}{####2}{####3}}% + \or\csdef{multilang@@runcmd@#2}{\csuse{multilang@@typecmd@#2}% + {####1}{####2}{####3}{####4}}% + \or\csdef{multilang@@runcmd@#2}{\csuse{multilang@@typecmd@#2}% + {####1}{####2}{####3}{####4}{####5}}% + \or\csdef{multilang@@runcmd@#2}{\csuse{multilang@@typecmd@#2}% + {####1}{####2}{####3}{####4}{####5}{####6}}% + \or\csdef{multilang@@runcmd@#2}{\csuse{multilang@@typecmd@#2}% + {####1}{####2}{####3}{####4}{####5}{####6}{####7}}% + \or\csdef{multilang@@runcmd@#2}{\csuse{multilang@@typecmd@#2}% + {####1}{####2}{####3}{####4}{####5}{####6}{####7}{####8}}% + \or\csdef{multilang@@runcmd@#2}{\csuse{multilang@@typecmd@#2}% + {####1}{####2}{####3}{####4}{####5}{####6}{####7}{####8}{####9}}% + \else\multilang@error{Argument count expected to be between 0 and 9, % + but is '#1'}\fi} +\newcommand\multilang@@types{} +\newcommand\NewMultilangType@code[3][1]{% + \csdef{multilang@@codetype@#2}{true}% + \NewMultilangType[#1]{#2}{#3}} +\newcommand\multilang@regfield[2]{% + \pgfqkeys{\multilang@keyof{#1}}{% + #2/.code={\csdef{multilang@@val@#2}{##1}}}% + \forlistloop{\multilang@regfieldtype{#1}{#2}}{\multilang@@types}} +\newcommand\multilang@regfieldtype[3]{% + \bgroup + \ifnumequal{\csuse{multilang@@typeargc@#3}}{1}{% + \ifcsdef{multilang@@codetype@#3}{% + \edef\do{\egroup\noexpand\pgfqkeys{\multilang@keyof{#1}}{% + #2/#3/.code={\csexpandonce{multilang@@runcmd@#3}}% + }}% + }{% + \edef\do{\egroup\noexpand\pgfqkeys{\multilang@keyof{#1}}{% + #2/#3/.style={#2={\csexpandonce{multilang@@runcmd@#3}}}% + }}% + }% + }{% + \ifcsdef{multilang@@codetype@#3}{% + \edef\do{\egroup\noexpand\pgfqkeys{\multilang@keyof{#1}}{% + #2/#3/.code n args={\csuse{multilang@@typeargc@#3}}% + {\csexpandonce{multilang@@runcmd@#3}}}}% + }{% + \edef\do{\egroup\noexpand\pgfqkeys{\multilang@keyof{#1}}{% + #2/#3/.style n args={\csuse{multilang@@typeargc@#3}}% + {#2={\csexpandonce{multilang@@runcmd@#3}}}}}% + }% + }\do} +\newcommand\multilang@regcomb[3]{% + \multilang@regcombtype{#1}{#2}{#3}{}% + \forlistloop{\multilang@regcomb@i{#1}{#2}{#3}}{\multilang@@types}} +\newcommand\multilang@regcomb@i[4]{% + \multilang@regcombtype{#1}{#2}{#3}{/#4}} +\newcommand\multilang@regcombtype[4]{% + \bgroup + \toks@{}\@tempcnta=0\relax + \forcsvlist{% + \advance\@tempcnta by1\relax + \expandafter\multilang@regcomb@set\expandafter{\the\@tempcnta}{#4}% + }{#3}% + \ifnumgreater{\the\@tempcnta}{1}{% + \edef\do{\egroup\noexpand\pgfqkeys{\multilang@keyof{#1}}{% + #2#4/.style n args={\the\@tempcnta}{\the\toks@}}}% + }{% + \edef\do{\egroup\noexpand\pgfqkeys{\multilang@keyof{#1}}{% + #2#4/.style={\the\toks@}}}% + }% + \do} +\newcommand\multilang@regcomb@set[3]{% + \toks@\expandafter{\the\toks@,#3#2={###1}}} +\newcommand\multilang@addlanguage[1]{% + \ifdefstring{\languagename}{#1}% + {\NewMultilangType{#1}{##1}}% + {\NewMultilangType@code{#1}{}}% + \NewMultilangType{#1!}{\foreignlanguage{#1}{##1}}} +\forlistloop{\multilang@addlanguage}{\multilang@@langs} +\newcommand\multilang@keyof[1]{% + \ifcat\relax\noexpand#1% + /multilang/cmd/\expandafter\@gobble\string#1% + \else + /multilang/env/#1% + \fi} +\newcommand\multilang@error[1]{\PackageError{multilang}{#1}{}} +\newcommand\multilang@processargs[3]{% + \let\multilang@@aliases=\empty + \pgfqkeys{#2}{#3}% + \edef\multilang@@actuals{}% + \def\multilang@@checks{}% + \def\multilang@@keys{}% + \ifdefvoid{\multilang@@oargs}{}{% + \def\do##1{% + \appto{\multilang@@actuals}{% + \ifcsmacro{multilang@@val@##1}% + {[\csexpandonce{multilang@@val@##1}]}% + {}% + }% + \appto{\multilang@@keys}{\multilang@regfield{#1}{##1}}% + }% + \expandafter\docsvlist\expandafter{\multilang@@oargs}}% + \ifdefvoid{\multilang@@margs}{}{% + \def\do##1{% + \appto{\multilang@@actuals}{% + {\csexpandonce{multilang@@val@##1}}% + }% + \appto{\multilang@@checks}{% + \ifcsmacro{multilang@@val@##1}% + {}% + {\multilang@error{mandatory argument ##1 missing}}% + }% + \appto{\multilang@@keys}{\multilang@regfield{#1}{##1}}% + }% + \expandafter\docsvlist\expandafter{\multilang@@margs}}% + \def\do##1{% + \eappto{\multilang@@keys}{% + \unexpanded{\multilang@regcomb{#1}{##1}}% + {\csuse{multilang@@alias@##1}}}}% + \expandafter\dolistloop\expandafter{\multilang@@aliases}% + \ifbool{multilang@@disablable}% + {\eappto{\multilang@@keys}{% + \noexpand\pgfqkeys{\multilang@keyof{#1}}{% + disabled/.is if={multilang@cmd@@disabled}}}}% + {}% + \def\multilang@@cmdorenv{#1}% + \edef\multilang@@cekey{\multilang@keyof{#1}}% + \multilang@hook@processargs +} +\newcommand\multilang@hook@processargs{} +\newcommand\multilang@noend[1]{\cslet{end\@currenvir}{\relax}} +\endinput +%% +%% End of file `multilang.sty'. -- cgit v1.2.3