% \iffalse meta-comment % % File: linguistix.dtx % % ---------------------------------------------------------- % The LaTeX bundle LinguisTiX v0.8 % Copyright © 2025, 2026 निरंजन % % This program is free software: you can redistribute it % and/or modify it under the terms of the GNU General Public % License as published by the Free Software Foundation, % either version 3 of the License, or (at your option) any % later version. % % This program is distributed in the hope that it will be % useful, but WITHOUT ANY WARRANTY; without even the implied % warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR % PURPOSE. See the GNU General Public License for more % details. % % You should have received a copy of the GNU General Public % License along with this program. If not, see % . % ---------------------------------------------------------- % % \fi % \iffalse %<*internal> \iffalse % %<*readme> ------------------------------------------------------------ Bundle: LinguisTiX Version: v0.8 Author: निरंजन Description: Enhanced support for linguistics. Repository: puszcza.gnu.org.ua/projects/linguistix License: GPLv3+ ------------------------------------------------------------ % %<*internal> \fi % %<*driver> \begin{filecontents}[overwrite]{\jobname.bib} @book{bringhurst, title = {The elements of typographic style}, author = {Bringhurst, Robert}, date = {2004}, publisher = {Point Roberts, WA: Hartley \& Marks, Publishers}, edition = {4} } @online{alan, author = {Munn, Alan and Gregorio, Enrico}, title = {{\textsf{ExPex} fails with \textsf{unicode-math}. How to avoid the clash?}}, url = {https://tex.stackexchange.com/q/703094}, date = {2023-12-05}, urldate = {2025-12-21} } \end{filecontents} \documentclass{l3doc} \usepackage{unicode-math} \usepackage{linguistix} \usepackage{xcolor} \usepackage{longtable} \usepackage{fontawesome5} \usepackage{hyperxmp} \usepackage[verbose=silent]{microtype} \usepackage{cleveref} \usepackage{hologo} \linguistix{old style one,languages={british,marathi}} \usepackage[style=authoryear,backend=biber]{biblatex} \addbibresource{\jobname.bib} \setlength{\LTpost}{0pt} \setlength{\LTcapwidth}{4.5in} \DeclareMicrotypeAlias{NewCMUncial10-Book.otf}{TU-basic} \setquotestyle{british} \colorlet{lngxredcolor}{red!50!black} \colorlet{lngxgreencolor}{green!50!black} \colorlet{lngxbluecolor}{blue!50!black} \setmathfont[% CharacterVariant = {1},% version = {emptyset}% ]{NewCMMath-Book.otf} \IfPackageLoadedT{lua-unicode-math}{% \DeclareMathVersion{emptyset}% } \urlstyle{tt} \hypersetup{% unicode,% colorlinks,% linkcolor = {lngxredcolor},% citecolor = {lngxgreencolor},% urlcolor = {lngxbluecolor},% pdftitle = {The LinguisTiX bundle},% pdfauthor = {निरंजन},% pdfsubject = {% Enhanced support for linguistics.% },% pdfcreator = {निरंजन},% pdfkeywords = {Linguistics, LaTeX},% pdfcopyright = {% The LaTeX bundle LinguisTiX\textLF Copyright © 2025, 2026 निरंजन\textLF This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.% },% pdflicenseurl = {gnu.org/licenses/gpl-3.0.html}% }% \newfontfamily\newcmnewone[% IgnoreFontspecFile,% Numbers = {OldStyle}% ]{NewCM10-Book.otf} \newfontfamily\newcmnewnum[% IgnoreFontspecFile% ]{NewCM10-Book.otf} \newfontfamily\mrfnt[% IgnoreFontspecFile,% Script = {Devanagari},% Language = {Marathi},% Renderer = {HarfBuzz}% ]{Mukta-Light.ttf} \newfontfamily\lngxcondensed[% IgnoreFontspecFile,% FakeStretch = {0.7},% BoldFont = {NewCMMono10-Bold.otf},% ItalicFont = {NewCMMono10-BookItalic.otf},% Renderer = {HarfBuzz}% ]{NewCMMono10-Book.otf} \makeatletter \setlength{\columnsep}{2pc} \setlength{\columnseprule}{0.2pt} \NewDocumentCommand \lngxtoc { } {% %% Courtesy: John Kormylo %% https://tex.stackexchange.com/a/606678 %% CC-BY-SA 4.0 International \setcounter{tocdepth}{1}% \section*{% \makebox[\linewidth][l]{\contentsname}% \@mkboth{% \MakeUppercase{\contentsname}% }{% \MakeUppercase{\contentsname}% }% }% \begin{multicols}{2}% \small \begingroup \hypersetup{hidelinks}% \@starttoc{toc}% \endgroup \end{multicols}% } \NewDocumentCommand \lngxdocumentation { m } {% \section[\csname lngx#1logo\endcsname]{% \csname lngx#1logo\endcsname\hfill \hyperref[lngx#1l3]{% \footnotesize\LaTeX3-interface% } \textbar{} \hyperref[lngx#1imp]{% \footnotesize Implementation% }% }% \label{lngx#1doc}% \addtocontents{toc}{% % Courtesy: samcarter % https://topanswers.xyz/tex?q=8120 % LPPL 1.3c+ \hspace*{0.5em}% \texorpdfstring{% \begingroup \scriptsize Interface\dots\ \hyperref[lngx#1l3]{% \color{lngxredcolor}% \textsf{% \pageref{lngx#1l3}% }% }; \scriptsize Implementation\dots\ \hyperref[lngx#1l3]{% \color{lngxredcolor}% \texttt{% \addfontfeatures{% Numbers=OldStyle,CharacterVariant={6}% }% \pageref{lngx#1imp}% }% }% \endgroup }{% \csname lngx#1logo\endcsname }% }% } \NewDocumentCommand \lngxinterface { m } {% \phantomsection \subsection*{% \csname lngx#1logo\endcsname\hfill \hyperref[lngx#1doc]{% \footnotesize Documentation% } \textbar{} \hyperref[lngx#1imp]{% \footnotesize Implementation% }% }% \label{lngx#1l3}% } \NewDocumentCommand \lngximplementation { m } {% \phantomsection \subsection*{% \csname lngx#1logo\endcsname\hfill \hyperref[lngx#1doc]{% \footnotesize Documentation% } \textbar{} \hyperref[lngx#1l3]{% \footnotesize\LaTeX3-interface% }% }% \label{lngx#1imp}% } \NewDocumentCommand \bLaTeX { } {% (\kern-0.035em\relax L\kern-.81ex\relax \raisebox{.6ex}{\textsc{a}}\kern-.23ex\relax )\kern-0.065em\relax \hbox{T}\kern-.4ex\relax \raisebox{-.5ex}{E}\kern-.3ex\relax X% } \makeatother \colorlet{lngxpurplecolor}{blue!50!red} \def\lngxtval{% \begingroup \color{lngxredcolor}% true% \endgroup \,|\,false% } \def\lngxfval{% true% \,|\,% \begingroup \color{lngxredcolor}% false% \endgroup } \ExplSyntaxOn \cs_new_protected:Npn \lngx_plain_logo:n #1 { \group_begin: \lngx_logo_font: LinguisTi \color_group_begin: \color_select:n { lngx_purple_color } X \color_group_end: - #1 \group_end: } \cs_gset_eq:NN \plainlngxlogo \lngx_plain_logo:n \msg_redirect_name:nnn { l3doc } { foreign-internal } { none } \RenewDocumentCommand \lngxlogo { O{} } {% \group_begin: \hypersetup { hidelinks } \hyperref [ lngx \IfBlankTF { #1 } { } { #1 doc } ] { \lngx_logo_font: LinguisTi \color_group_begin: \color_select:n { lngx_purple_color } X \color_group_end: \IfBlankF { #1 } { - #1 } } \group_end: } \NewDocumentCommand \fn { v }{ \phantomsection \__codedoc_function_index:n { #1 } \__codedoc_function_label:nN { #1 } \c_false_bool #1 } \RenewDocumentCommand \MacroLongFont { } { \lngxcondensed } \ExplSyntaxOff \makeatletter \NewDocumentCommand \supportfootnote { +m } {% \begingroup \def\thefootnote{}% \let\@makefnmark\relax \let\@makefntext\relax \let\hyper@makecurrent\@empty \footnotetext{% \hspace*{-\parindent}% #1% }% \endgroup } \renewenvironment{theindex}{% \index@prologue \medskip \let\item\@idxitem \ignorespaces }{} \makeatother \begin{document} \DocInput{\jobname.dtx} \end{document} % % \fi % \title{^^A % \phantomsection\label{lngx}^^A % The \lngxpkg\ bundle^^A % } % \author{निरंजन} % \date{^^A % \today\ (v0.8)\\[1ex]^^A % {^^A % \small\faIcon{home}\quad % \url{^^A % https://ctan.org/pkg/linguistix^^A % }\\[0.5ex]^^A % \small\faIcon{git-alt}\quad % \url{^^A % https://puszcza.gnu.org.ua/projects/linguistix^^A % }\\[0.5ex]^^A % \small\faIcon[regular]{comments}\quad % \url{^^A % https://matrix.to/\#/\#linguistix:matrix.org^^A % }^^A % }^^A % } % % \maketitle % % \supportfootnote{^^A % The \lngxpkg\ bundle % % \noindent % Copyright © 2025, 2026 निरंजन % % This program is free software: you can redistribute it % and/or modify it under the terms of the \textsc{gnu} % General Public License as published by the Free Software % Foundation, either version 3 of the License, or (at your % option) any later version. % % This program is distributed in the hope that it will be % useful, but \emph{\textbf{without any warranty}}; % without even the implied warranty of % \emph{\textbf{merchantability}} or \emph{\textbf{fitness % for a particular purpose}}. See the \textsc{gnu} General % Public License for more details. % % You should have received a copy of the GNU General % Public License along with this program. If not, see % \url{https://www.gnu.org/licenses/}.^^A % } % % \begin{documentation} % % \begin{abstract} % There are quite a few \LaTeX\ packages that support % typesetting in linguistics, but most of them lack a % modern \LaTeX-like users syntax as well as a programming % interface. The \lngxpkg\ bundle fills this gap. It % contains several packages enhancing the general support % for linguistics in \LaTeX. This is a comprehensive % documentation of the same comprising of three parts. The % first one is the general users manual, the second one % documents the programming interface of the bundle, % whereas the last one is the documented implementation of % all the packages. % \end{abstract} % % \lngxtoc ^^A Custom command defined in the preamble. % % \newpage % % ^^A Based on egreg’s answer: % ^^A https://tex.stackexchange.com/a/102849 % \begingroup % \thispagestyle{empty}^^A no header and footer. % \vspace*{\stretch{1}}^^A some space at the top. % \itshape ^^A to get the text in italics. % \raggedleft ^^A flush to the right margin. % Dedicated to Renuka who taught me rigour under the guise % of linguistics\dots % \par ^^A end the paragraph % \vspace{\stretch{3}} ^^A space at bottom is thrice that % \endgroup % \newpage % % \section{Introduction} % % Linguistics is a discipline that studies the phenomenon of % language and for this linguists analyse data from % languages across the globe. In order to be able to present % the data that is collected for this, linguists use several % representational methods that lead to a fiasco when their % typesetting is considered. In order to understand the % complexity of the task at hand, first, let’s have a look % at some of the problem cases. If you are an impatient % reader and are just willing to read the users manual, you % may skip reading the current section and start with % \cref{lngxbasedoc} and the ones following it. % % \subsection{Phonetic symbols} % % Speech sounds are the building blocks of many human % languages and the data collected from languages demands an % unambiguous method of representation which is served by % the International Phonetic Alphabet. For the longest time, % the \textsc{tipa} package % (\url{https://ctan.org/pkg/tipa}) was the one that % produced phonetic symbols in \bLaTeX. Visually, it matches % the default Computer Modern design of \bLaTeX, but % \textsc{tipa} is not Unicode. It is set in a legacy % encoding. With the recent developments, the New Computer % Modern family supports all the \textsc{ipa} characters % (even the ones that are missing in \textsc{tipa}). They % are created keeping in mind the principles of Knuth’s % Computer Modern. Additionally, the family also supports % sans serif (recommended in presentations) and mono % (recommended in coding context) families. It supports two % weights, i.e., book and regular respectively. The book % weight is slightly thicker than the regular weight, but % the regular one matches the thickness of the Computer % Modern design. Because of the increased thickness, the % former looks better. The current document, for example, is % typeset in the book weight of New Computer Modern. If you % are like me, you probably don’t like using % non-\LaTeX-fonts. The good news is that the requirements % of linguistics are very well fulfilled by the recent % developments in the New Computer modern family and it % \emph{does} belong to the fraternity of \LaTeX-fonts. % % Apart from this, there are some other advantages of the % New Computer Modern fonts. The \textsc{ipa} distinguishes % between \ipatext{a} and \ipatext{ɑ}, but unfortunately, in % Italic shape, the latter is a variant of the former. E.g., % |[a\textit{a}]| produces \enquote{[a\textit{a}]}. Whenever % an author uses Italic shape for their transcription and % use |a|, a wrong \textsc{ipa} symbol is printed with most % fonts. This problem was kindly acknowledged by Antonis % Tsolomitis, the developer of New Computer Modern. In the % stylistic set dedicated for linguistics, the correct shape % was added to the Italic shape by him. Thus, % |\ipatext{a\textit{a}}| (a command from \lngxipalogo) % renders \enquote{\ipatext{a\textit{a}}}. The package % enables New Computer Modern family with stylistic set 05 % dedicated for \textsc{ipa}. It also adds the brackets or % slashes around the argument as explained in % \cref{lngxipadoc}. % % A similar problem is with the character |g|. E.g., % |[g\textit{g}]| produces \enquote{[g\textit{g}]}. Here, % the situation is the other way round. The upright % \enquote{g} is not recognised by the \textsc{ipa}. The % \textsc{ipa} charts generally have the upright version of % the Italic shape. To see what this means, try % |\ipatext{g\textit{g}}|. It produces % \ipatext{g\textit{g}} and not [g\textit{g}]. % % In order to avail all of these features, I have set New % Computer Modern as the default font-family of \lngxpkg. % The bundle provides options to control these defaults. % Users can use their preferred text and \textsc{ipa} fonts. % There also is an option to use the regular weight of NewCM % instead of the book weight. % % \section{Planned} % % I plan to develop this bundle further in order to support % the typesetting of good quality examples with interlinear % glossing. My model is to imitate the output of the % \pkg{expex} package, but with a modern \LaTeX-like syntax. % % \section{Funding} % % I am a doctorate student without a fellowship (thanks to % our education policies!) currently sustaining only with a % full time job unrelated to linguistics that consumes most % of my working hours. At times, it becomes difficult to % continue the research, the job and the passion development % projects. \lngxpkg\ needs funding in order to sustain. If % you think you can support it, you can contact me on the % email \textsc{id} found on the front page. % % As of 2025-05-29, I have recieved funding from the \TeX\ % users group’s \TeX\ development fund. They have decided to % support the development of \enquote{linguistix-glossing} % (the logo will be available once the package is ready). % % An experimental version of \lngxglossinglogo\ is released % on 2026-01-19. This version is for testing and getting % feedback from the community. This marks the completion of % the first grant provided by the \TeX\ users group’s. The % project will still continue to develop further, so funding % initiatives will be highly appreciated. % % \section{Acknowledgements} % % This package relies the most on the New Computer Modern % font family. I would like to express my gratitude to % Antonis Tsolomitis who tirelessly worked on the set of % \textsc{ipa} symbols and brought back the good old charm % of \textsc{tipa}’s design in the modern Unicode world. I % would like to thank Renuka and Avinash who taught me % linguistics. They nourished my passion, helped me pursue % my love for the subject as well as the computation that % came along with it. I could have never imagined myself % working on a package written in \LaTeX3’s syntax. Not so % long ago, I used to find it very complicated. It’s mostly % Jonathan Spratte and Florent Rougon’s help (and, at times, % scolding :P) that helped me get used to it. I would also % like to mention C.V.\ Radhakrishnan for being an important % part of my journey in \LaTeX. Lastly, to all the free % software people who have created this friendly and % supportive world for people by investing their precious % time and resources! % % Hardly in a week after the initial release, the \TeX\ % users group decided to financially support the development % of a planned package in the bundle. I am grateful to them % for their support. % % \section*{Documentation} % % The bundle is comprised of several packages that are % developed for different purposes. In order to load all the % packages of the bundle, one can issue: % % \begin{verbatim} % \usepackage{linguistix} % \end{verbatim} % % This is the easiest method for getting all of % \lngxpkg\ in one go. But, if you don’t need all the % packages of the bundle, you may load the required packages % separately. We will start with the elementary package that % sets up things for other packages of the bundle. % % \lngxdocumentation{base} % % This package provides a single command that is used in all % the other packages of the bundle. The command is: % % \begin{function}{\linguistix} % \begin{syntax} % \marg{key-value-list} % \end{syntax} % We have a single set of keys for the entire bundle. Each % package appends keys to the same set. The argument of this % central processor command is the comma-separated % \meta{key-value-list}. So you can load any package of % \lngxpkg\ and use the \cs[no-index]{linguistix} command. % The only exception to this is \lngxnfsslogo. We will see % how it is different in its section. % \end{function} % % \lngxdocumentation{fixpex} % % This package offers a fix for the clash between % \pkg{expex} and \pkg{(lua)-unicode-math}. It provides a % single command. % % \begin{function}{\umgla} % This is a replica of the \pkg{(lua)-unicode-math}-|\gla|. % Since the \pkg{expex}-|\gla| is more relevant in % linguistics, I set it as the default. If one needs to use % \pkg{(lua)-unicode-math}-|\gla|, they can use this % command. % \end{function} % % \lngxdocumentation{fonts} % % This is a package that loads the New Computer Modern % family for the entire document. The package sets fonts for % both text and math. It has keys for customisation for % both. Note that just loading this package does \emph{not} % provide any support for \textsc{ipa}. For that one needs % \lngxipalogo\ separately. % % Antonis suggested a typographic enhancement for the logo % of \LaTeX. The default logo scales the \enquote{A} and % that affects the \enquote{colour} of the font. This is why % I renew the logo with the code given by Antonis. The % original logo is also available with an alternative % command. % % \begin{function}{\LaTeX,\ogLaTeX} % \begin{syntax} % {\normalfont\LaTeX} % {\normalfont\ogLaTeX} % \end{syntax} % \end{function} % % The package provides only these commands. Let’s now have a % look at the keys provided for the text. % % \subsection{Text} % % Most keys of this package are prefixed with the |text| in % order to distinguish them from the maths and \textsc{ipa} % ones. There aren’t any commands provided by the package. % Most of the important features of the \pkg{fontspec} % packakge are variablised with \pkg{l3keys}. % % The \enquote{old style numbers} have varying heights. Some % numbers have ascenders and some have descenders (e.g., % 6789). According to \cite{bringhurst}, this makes them % easier to read in running text. Lining numbers, on the % other hand have uniform heights. They go well with all % capital text (rare). Thus, for the general text, I enable % this setting by default in \lngxfontslogo. % % Apart from that, the New Computer Modern font family % provides an old-style shape for the number \enquote{1} % (this exact shape!), but it is provided as a character % variant. Different fonts may use these arbitrary slots for % any character’s alternation. Therefore this setting should % not be loaded blindly. Let’s have a look at the keys that % can be employed to change these behaviours. % % \begin{function}{old style numbers,old style one} % \begin{syntax} % = \marg{truth value}\hfill\lngxtval % = \marg{truth value}\hfill\lngxfval % \end{syntax} % If one wants to disable old style numbers, they may use % the |old style numbers| key with the |false| value % (default is |true|)\footnote{The possible and the default % values of keys are given at the right side in the % documentation and the defaults are highlighted in % red.}. Note that printing of old style numbers % also depends on whether the font you select has old style % numbers or not. The relevant settings are added by the % package to the font automatically, but while selecting the % font, make sure whether the old style table is present in % the font or not. % % Suppose one wants the alternative shape of number % \enquote{1} from the New Computer Modern family, they may % use the key |old style one| (default is false; adding % |true| is optional). % \end{function} % % Let’s have a look at the three way distinction we get % because of this. % % \begin{quote} % {\newcmnewone 0123456789}\hfill % \begingroup % \ttfamily\footnotesize\color{lngxredcolor}^^A % Old style with default 1^^A % \endgroup % % 0123456789\hfill % \texttt{\footnotesize Old style with the old 1}^^A % % {\newcmnewnum 0123456789}\hfill % \texttt{\footnotesize Lining}^^A % \end{quote} % % \begin{function}{^^A % newcm,newcm sans,newcm mono,^^A % newcm regular,newcm regular sans,newcm regular mono^^A % } % These are some keys that come in handy for setting New % Computer Modern defaults. All the necessary values are % stored in these. The keys that have |regular| in their % names refer to the \enquote{regular} variants of New % Computer Modern fonts. These variants match the colour and % widths of the Latin Modern fonts. One may use these keys % to override the defaults. % \end{function} % % \subsection{Maths} % % \lngxfontslogo\ sets maths fonts also. I have used % \pkg{lua-unicode-math} package which is faster and which % is said to be the future of maths in \LaTeX. But, as of % now it is highly experimental. If you want to stick to the % stable \pkg{unicode-math} package. The trick is simply to % load the same before loading \lngxpkg. That will suppress % the loading of \pkg{lua-unicode-math}. In order to control % the settings related to maths, the following keys can be % used. % % \begin{function}{^^A % math,math features,math bold,math bold features^^A % } % \begin{syntax} % = \marg{math font} % = \marg{math font features} % = \marg{bold math font} % = \marg{bold math font features} % \end{syntax} % The |math| and |math bold| keys set the respective fonts % (i.e., regular and bold fonts for mathematics % respectively). The keys suffixed with |features| set the % font features of the same. % \end{function} % % \begin{function}{bourbaki's empty set} % \begin{syntax} % = \marg{truth value}\hfill\lngxtval % \end{syntax} % In \bLaTeX, the default shape of the \enquote{empty set} % symbol is: \enquote{\mathversion{emptyset}$\emptyset$}, % but the symbol used by the Bourbaki group is still % considered more correct and preferred by many (including % me). New Computer Modern Math fonts provide it by default % and the slashed zero is provided as a character variant. % Since the Unicode-correct |$\emptyset$| is activated by % the package, it always renders: \enquote{$\emptyset$} and % not: \enquote{\mathversion{emptyset}$\emptyset$}. In order % to change this behaviour, one may use this key and set it % to false for getting the slashed-zero of original \bLaTeX. % Hail plumbers union, \emph{\textsc{iykyk}! ;-)} % \end{function} % % \newpage % % \lngxdocumentation{glossing} % % This package provides a suit for creating interlinear % glosses. It is supported by \TeX\ users group’s devfund. % The package attempts to be an all-in-one solution for % glossing. It doesn’t provide any particular glosses. It % only provides a method to create them. Using it, one may % easily create packages like \plainlngxlogo{leipzig} to % support a set of glosses. The glosses created by the % package use the new code of the \LaTeX\ project as they % are created in a tagging aware manner. Each gloss sets a % hyperlink to its position in the list of glosses. Let’s % take a look at its commands and options. % % \begin{function}{\glx,\glx*} % \begin{syntax} % \marg{comma separated list of glosses} % \marg{comma separated list of glosses} % \end{syntax} % These simple commands take a comma separated list as their % argument. All the items from the list are glosses (either % created by the user or provided by a package). Cases of % the items given in the list are ignored. Spaces around the % items are ignored. The regular unstarred command prints % the glosses related to each of the item in the comma % separated list, whereas the starred variant prints their % expansions. Have a look at the following example. % \end{function} % % \rule{0.7\linewidth}{0.5pt} % % \begin{verbatim} % \DocumentMetadata{tagging=on,lang={en-GB}} % \documentclass{article} % \usepackage{linguistix} % % \begin{document} % \glx{prs,pst}\par % \glx{ prs, pst }\par % \glx{ Prs,pSt} % % \glx*{prs,pst}\par % \glx*{ prs, pst }\par % \glx*{ Prs,pST} % \end{document} % \end{verbatim} % % \rule{0.7\linewidth}{0.5pt} % % \medskip % % The expansions of \glx{pst} and \glx{prs} (from % \plainlngxlogo{leipzig} package) are \glx*{pst} and % \glx*{prs} respectively. This example produces identical % output in three lines for glosses and the same for its % expansions. Notice that there is no format to the cases of % the glosses and similarly one level of spaces are trimmed. % % \begin{function}{\newgloss,\renewgloss} % \begin{syntax} % \marg{gloss} \marg{expansion} % \marg{gloss} \marg{expansion} % \end{syntax} % These commands create a new gloss or renew an existing % one. They can be accessed with the \cs{glx} command as % explained above. Using \cs{renewgloss} mid-document is not % recommended as it will erase the data of page numbers for % the previous (renewed) version of it. % \end{function} % % \begin{function}{\listofglosses} % \begin{syntax} % \oarg{setup keys} % \end{syntax} % This command prints the list of glosses using the default % settings. If the optional argument is used, the % adjustments are made locally only for a single run. E.g.: % \end{function} % % \listofglosses % % \begin{function}{\setupglossing} % \begin{syntax} % \marg{keys for formatting glosses} % \end{syntax} % This command takes one argument, i.e., the keys that % control everything regarding the use of glosses and their % expansions. The keys it takes are described in the section % that follows. % \end{function} % % \subsection{Setting up the glosses} % % The following keys can be passed to the command % \cs{setupglossing}. They control the printing along with a % lot of other things regarding glosses. All the % customisation offered by the package can be accessed via % this command. % % \begin{function}{format} % \begin{syntax} % = \marg{formatted element gloss/expansion}\hfill^^A % gloss\,\textbar\,expansion % \end{syntax} % The |format| key is used for setting the format of either % the gloss or the expansion. It’s a meta key that takes % other key-val pair in the argument. The nested keys % control the formatting of the respective elements. % \end{function} % % \begin{function}{gloss,expansion} % \begin{syntax} % = \marg{formatting commands for glosses}\hfill^^A % {\color{lngxredcolor}|\textsc{#1}|} % = \marg{formatting commands for glosses} % \end{syntax} % These keys only work inside the meta key |format|. They % set the commands that print either the gloss or the % expansion. |#1| refers to the printed text of them. No % special formatting is applied to expansions by default, % but glosses are by default printed in \cs{textsc}. % \end{function} % % \begin{function}{link color} % \begin{syntax} % = \marg{link color}\hfill{\color{lngxredcolor}black} % \end{syntax} % This option locally sets the colour for the hyperlinks. By % default they are set to the black colour. % \end{function} % % \begin{function}{sort} % \begin{syntax} % = \marg{sorting style}\hfill^^A % {\color{lngxredcolor}alphabetical}\,\textbar\,use % \end{syntax} % This key controls how the keys printed in the list of % glosses are ordered. They may be ordered alphabetically or % following the sequence in which they were used, the former % being the default. % \end{function} % % \begin{function}{expansion case} % \begin{syntax} % = \marg{case}\hfill{\color{lngxredcolor}lowercase}^^A %\,\textbar\,title case all\,\textbar\,title case first % \end{syntax} % The expansion can be printed in one of these three cases. % The default printing happens in lowercase. % \end{function} % % \begin{function}{style} % \begin{syntax} % = \marg{glossary style}\hfill^^A % {\color{lngxredcolor}block}\,\textbar\,inline % \end{syntax} % The package offers two styles. The |inline| style prints % the glosses and their expansions without page numbers in % the flowing text, whereas the |block| style, in default % settings prints them in a multicolumn block with an % unnumbered section with the glossary name. % \end{function} % % \begin{function}{columns} % \begin{syntax} % = \marg{number of columns}\hfill{\color{lngxredcolor}2} % \end{syntax} % The block style of glosses is printed in multicolumn % layout by default. If the number of columns has to be % adjusted, this key shall be used. The default value of it % is 2. It works with only one column too. % \end{function} % % \begin{function}{page numbers} % \begin{syntax} % = \marg{truth value}\hfill\lngxtval % \end{syntax} % By default, page numbers on which a particular gloss was % used are printed in the |block| style. This can be turned % off with this bool key. % \end{function} % % \begin{function}{sectioning} % \begin{syntax} % = \marg{section level}\hfill{\color{lngxredcolor}section} % \end{syntax} % In |block| style, a section heading is printed. In order % to choose the level of sectioning, this command can be % used. The default is |section| which can be changed to any % other desired level. In addition the key allows an option % |null| which suppresses the use of any section heading. % \end{function} % % \begin{function}{section number} % \begin{syntax} % = \marg{truth value}\hfill\lngxfval % \end{syntax} % By default, the section number for the glossary is turned % off, but if one wants to print it, this bool key can be % used with the |true| value. % \end{function} % % \begin{function}{no bold} % \begin{syntax} % = \marg{truth value}\hfill\lngxfval % \end{syntax} % Generally, the glosses are printed in bold inside % glossary. Some fonts don’t have bold small caps (e.g., % Latin Modern). If you need to stick to them, you can use % this inverse bool key with true value in order to obtain % non-bold glosses. % \end{function} % % \begin{function}{separator} % \begin{syntax} % = \marg{separator between glosses or expansions} % \end{syntax} % This is a context-sensitive key. If used with \cs{glx}, % then it sets the separator between the glosses (|,␣|~is % the default). If used with \cs{glx*}, it sets the % separator between the expansions (|,␣|~is the default) and % if used with the \cs{listofglosses}, it sets the separator % between glosses and their expansions (|:␣|~is the % default). % \end{function} % % \begin{function}{entry separator} % \begin{syntax} % = \marg{separator between pairs of glosses and expansions} % \end{syntax} % Each pair of gloss and its expansion is separated using a % token list controlled by this key. The default is |\par|. % \end{function} % % \newpage % % \lngxdocumentation{ipa} % % This package sets the fonts exclusively for the % \textsc{ipa}. The commands provided for switching to the % \textsc{ipa} control all serif, sans serif and typewriter % families. This package can be loaded standalone for % loading \textsc{ipa} fonts as well as some switch commands % useful in running text. New Computer Modern provides a % special stylistic set dedicated for linguistics. It is % enabled for \textsc{ipa} fonts automatically with this % package. Only the legally marked up \textsc{ipa} is % affected by the customisation provided by this package. % For switching to the \textsc{ipa}, \lngxipalogo\ provides % one command with a starred variant. % % \begin{function}{\ipatext,\ipatext*} % \begin{syntax} % \marg{phonetic transcription} % \marg{phonemic transcription} % \end{syntax} % This is a command that resembles with the % \pkg{\textsc{tipa}} command \cs[no-index]{textipa}. I have % deliberately kept it distinct from it so that just in case % somebody wants to use their old \textsc{tipa} code in a % Unicode document, the commands won’t clash (I highly % discourage doing this, though). The command comes with a % starred variant. The behaviour of the un-starred command % is to print the argument in brackets for phonetic % transcription, e.g.: |\ipatext{aɪ̯ pʰiː eɪ̯}|^^A % \,$\longrightarrow$\,\ipatext{aɪ̯ pʰiː eɪ̯} whereas the % starred version prints it in slashes for phonemic % transcription, e.g.: |\ipatext*{aɪ̯ pʰiː eɪ̯}|^^A % \,$\longrightarrow$\,\ipatext*{aɪ̯ pʰiː eɪ̯}. % \end{function} % % Suppose someone just wants to load the font without the % brackets or slashes, they can use the following command % for switching to the \textsc{ipa} without adding the % aforementioned. % % \begin{function}{\lngxipa} % This also is a command that switches to the % \textsc{ipa}-only features (default as well as user % added). This command, of course, leaks and that’s why % \emph{should} be delimited. E.g., the following code % lines produce {\lngxipa [aɪ̯ pʰiː eɪ̯]} and {\lngxipa /aɪ̯ % pʰiː eɪ̯/} respectively: % % \begin{verbatim} % {\lngxipa [aɪ̯ pʰiː eɪ̯]} % {\lngxipa /aɪ̯ pʰiː eɪ̯/} % \end{verbatim} % \end{function} % % \begin{function}{^^A % ipa newcm,ipa newcm sans,ipa newcm mono,^^A % ipa newcm regular,ipa newcm regular sans,^^A % ipa newcm regular mono^^A % } % These keys reset the \textsc{ipa}-only fonts to New % Computer Modern. They can be used even for resetting to % New Computer Modern from another \textsc{ipa} font. In % order to change or reset to the \textsc{ipa} defaults % these keys can be used. They store the names of the New % Computer Modern font family in the variables concerning % \textsc{ipa}. The keys that contain |regular| in their % name use the regular version of New Computer Modern that % matches the colour of Latin Modern. % \end{function} % % Let’s now see the combined table of font keys provided by % both \lngxfontslogo\ and \lngxipalogo. % % \begingroup % \begin{longtable}{% % l% % >{% % \lngxcondensed % \addfontfeature{FakeStretch=0.8}% % }l% % >{% % \lngxcondensed % \addfontfeature{FakeStretch=0.8}% % }l% % } % \toprule % Family % & \lngxfontslogo % & \lngxipalogo \\ % \midrule % \endfirsthead % \toprule % Family % & \lngxfontslogo % & \lngxipalogo \\ % \midrule % \endhead % \midrule % \multicolumn{3}{r}{^^A % \small % \emph{Continued on the next page\dots}^^A % } \\ % \bottomrule % \endfoot % \midrule % \multicolumn{3}{r}{^^A % \small % \emph{End of the table\dots}^^A % } \\ % \bottomrule % \addlinespace % \caption{^^A % Font keys provided by \lngxfontslogo\ and \lngxipalogo % }\label{lngxfontstable}\\ % \endlastfoot % Serif % & \fn{text main font} % & \fn{ipa main font} \\ % & \fn{text upright} % & \fn{ipa upright} \\ % & \fn{text upright features} % & \fn{ipa upright features} \\ % & \fn{text bold upright} % & \fn{ipa bold upright} \\ % & \fn{text bold upright features} % & \fn{ipa bold upright features} \\ % & \fn{text italic} % & \fn{ipa italic} \\ % & \fn{text italic features} % & \fn{ipa italic features} \\ % & \fn{text bold italic} % & \fn{ipa bold italic} \\ % & \fn{text bold italic features} % & \fn{ipa bold italic features} \\ % & \fn{text slanted} % & \fn{ipa slanted} \\ % & \fn{text slanted features} % & \fn{ipa slanted features} \\ % & \fn{text bold slanted} % & \fn{ipa bold slanted} \\ % & \fn{text bold slanted features} % & \fn{ipa bold slanted features} \\ % & \fn{text swash} % & \fn{ipa swash} \\ % & \fn{text swash features} % & \fn{ipa swash features} \\ % & \fn{text bold swash} % & \fn{ipa bold swash} \\ % & \fn{text bold swash features} % & \fn{ipa bold swash features} \\ % & \fn{text small caps} % & \fn{ipa small caps} \\ % & \fn{text small caps features} % & \fn{ipa small caps features} \\ % \midrule % Sans serif % & \fn{text sans font} % & \fn{ipa sans font} \\ % & \fn{text sans upright} % & \fn{ipa sans upright} \\ % & \fn{text sans upright features} % & \fn{ipa sans upright features} \\ % & \fn{text sans bold upright} % & \fn{ipa sans bold upright} \\ % & \fn{text sans bold upright features} % & \fn{ipa sans bold upright features} \\ % & \fn{text sans italic} % & \fn{ipa sans italic} \\ % & \fn{text sans italic features} % & \fn{ipa sans italic features} \\ % & \fn{text sans bold italic} % & \fn{ipa sans bold italic} \\ % & \fn{text sans bold italic features} % & \fn{ipa sans bold italic features} \\ % & \fn{text sans slanted} % & \fn{ipa sans slanted} \\ % & \fn{text sans slanted features} % & \fn{ipa sans slanted features} \\ % & \fn{text sans bold slanted} % & \fn{ipa sans bold slanted} \\ % & \fn{text sans bold slanted features} % & \fn{ipa sans bold slanted features} \\ % & \fn{text sans swash} % & \fn{ipa sans swash} \\ % & \fn{text sans swash features} % & \fn{ipa sans swash features} \\ % & \fn{text sans bold swash} % & \fn{ipa sans bold swash} \\ % & \fn{text sans bold swash features} % & \fn{ipa sans bold swash features} \\ % & \fn{text sans small caps} % & \fn{ipa sans small caps} \\ % & \fn{text sans small caps features} % & \fn{ipa sans small caps features} \\ % \midrule % Monospaced % & \fn{text mono font} % & \fn{ipa mono font} \\ % & \fn{text mono upright} % & \fn{ipa mono upright} \\ % & \fn{text mono upright features} % & \fn{ipa mono upright features} \\ % & \fn{text mono bold upright} % & \fn{ipa mono bold upright} \\ % & \fn{text mono bold upright features} % & \fn{ipa mono bold upright features} \\ % & \fn{text mono italic} % & \fn{ipa mono italic} \\ % & \fn{text mono italic features} % & \fn{ipa mono italic features} \\ % & \fn{text mono bold italic} % & \fn{ipa mono bold italic} \\ % & \fn{text mono bold italic features} % & \fn{ipa mono bold italic features} \\ % & \fn{text mono slanted} % & \fn{ipa mono slanted} \\ % & \fn{text mono slanted features} % & \fn{ipa mono slanted features} \\ % & \fn{text mono bold slanted} % & \fn{ipa mono bold slanted} \\ % & \fn{text mono bold slanted features} % & \fn{ipa mono bold slanted features} \\ % & \fn{text mono swash} % & \fn{ipa mono swash} \\ % & \fn{text mono swash features} % & \fn{ipa mono swash features} \\ % & \fn{text mono bold swash} % & \fn{ipa mono bold swash} \\ % & \fn{text mono bold swash features} % & \fn{ipa mono bold swash features} \\ % & \fn{text mono small caps} % & \fn{ipa mono small caps} \\ % & \fn{text mono small caps features} % & \fn{ipa mono small caps features} \\ % \end{longtable} % \endgroup % % Apart from these, both the packages provide the following % keys for appending to the extra features for the % respective fonts: % % \begin{itemize} % \ttfamily % \item \fn{text extra features} % \item \fn{text sans extra features} % \item \fn{text mono extra features} % \item \fn{ipa extra features} % \item \fn{ipa sans extra features} % \item \fn{ipa mono extra features} % \end{itemize} % % \newpage % % \lngxdocumentation{languages} % % This package is intended to provide support for loading % Unicode fonts as well as other necessary settings for % using languages. It is a wrapper around the \textsf{babel} % package, but it provides some other useful settings which % \textsf{babel} doesn’t agree to add. This package is a % little opinionated and pushes for \enquote{modern} % practices e.g., Unicode, Lua\LaTeX, no-markup multilingual % text etc. As of now, only a little support is available. % If you want your language to be supported, you can ask for % support at the bug tracker of the repository or you can % send an email in the public mailing list for the project. % You may subscribe to the mailing list at: % \url{mail.gnu.org.ua/mailman/listinfo/linguistix-languages}. % Here, I list down some \LaTeX-aspects that may demand some % modifications in the default settings. % % \begin{description} % \item[Fonts:] The package works with Unicode and does not % worry about legacy methods. If you want support for your % language, first and foremost, you should let me know % standard OpenType fonts suitable for your language. Note % that they should be freely licensed. I won’t support % proprietary software with \lngxpkg. % \item[\pkg{babel} support:] As mentioned before, the % package adds on to the support provided by package % \pkg{babel}. So check if the language files\,--\,^^A % specifically the modern |.ini| files\,--\,have the % correct settings. Sometimes they may need to undergo % native-speakers scrutiny. Whatever is wrong in % \pkg{babel}, may not get corrected in \lngxpkg. % \item[Numbers:] \LaTeX\ uses a lot of counters and all of % them, by default, print Latin numerals/characters. E.g., % |\arabic{page}| prints the page number in Latin, but % |\roman{page}| prints the same in Roman convention, % i.e., ‘i, ii, \dots’. Does your language allow them? % E.g., Greek doesn’t like Latin alphabets, but doesn’t % mind Roman numerals. Instead of Latin alphabets, Greek % prefers to use its own numeral system. Marathi doesn’t % like any of these, but it doesn’t have alternative forms % of numeration, so it changes certain cases drastically. % E.g., in nested |enumerate| environment, Marathi renews % the printing of nested |\item|s as 1, 1.1, 1.1.1 and % 1.1.1.1. This is reset to defaults when the language is % changed. Keeping this in mind, I am listing down some % places where I found non-native numbering (I might have % missed something in which case it deserves to be % reported as a bug, so feel free to do so!). % \begin{enumerate} % \item Page numbers (in front matter, main matter). % \item Part numbers. % \item Second, third and fourth levels of enumeration. % \end{enumerate} % \item[\pkg{ExPex}:] Labels provided by \pkg{ExPex} package % (see: \url{tex.stackexchange.com/a/548668}). % \item[Typography:] Language-specific conventions like % using Italic for emphasis. It is a Latin-script specific % convention (note that I don’t mean slanted when I say % Italic). Different languages have different conventions % of emphasising (e.g., Marathi uses bold font for % emphasis). % \item[Miscellaneous:] Anything other than these. % \end{description} % % I am very much willing to support multilingual typesetting % for multiple languages, but I need to know the things % mentioned in this list in order to provide the best suited % output. Please consider submitting a detailed feature % request. The documentation of supported languages is in % separate \textsc{pdf}s. This documentation only describes % the user-side commands provided by the package. % % \begin{function}{languages,\loadlanguages} % \begin{syntax} % \marg{list of languages} % \marg{list of languages} % \end{syntax} % This key works with the central key-parser of \lngxpkg, % i.e., |\linguistix|. It accepts one argument that is a % list of languages user wants to load. Unlike % \textsf{babel}, the first element of this list is set as % the main language for the document. The command % |\loadlanguages| has the identical behaviour. In fact, it % is a wrapper around the key. % \end{function} % \begin{function}{\providelanguage} % \begin{syntax} % \marg{language options} \marg{language name} % \end{syntax} % This is a wrapper command over |\babelprovide|. The first % argument is passed to the optional argument of % |\babelprovide| and the second one to the mandatory % argument of the same. For more information, please read % \textsf{babel}’s manual. % % Languages supported by \lngxlanguageslogo\ are loaded with % a package with that language’s name. If it is absent, the % package produces a warning. % \end{function} % % \begin{function}{native numbering} % \begin{syntax} % = \marg{strict/logical/off} % \end{syntax} % Many languages need native digits. Adding them in a % multilingual document is quite complicated. This key sets % the plugs provided for the socket of the same name. % Language packages already take care of them, but if you % want to change anything mid-document, you can use this % key. It has three choices available as its value as seen % below. % \end{function} % % \begin{function}{strict} % The ‘strict’ plug changes the \cs{lngx_counter:n} command % to the counter of the main language of the document. That % way all the counters are printed in the main language. % \end{function} % % \begin{function}{logical} % This plug changes the meaning of \cs{lngx_counter:n} to % the |\localecounter| command provided by \pkg{babel}. It % picks up the surrounding language and uses its native % digits. E.g., when Marathi is being typeset, it will print % counters in Marathi. When it is changed to English, it % will start printing the same in English. Note that this % will reflect in table of contents/tables/figures too. It % is called logical numbering because it obeys \TeX’s logic % more than what is generally considered the standard. E.g., % imagine you have an English section followed by a Marathi % section on the same page. Both of them will follow their % own numerals for default \TeX\ counters. Since both of % them are on the same page, while shipping out, the last % active language will be used for processing the page % number (Marathi in this case). This creates a table of % contents with Latin numeral as the section counter, but % Marathi numeral as the page number. Only experiments can % determine if an option like this can have valid use-cases, % so it is provided. If you use it, be aware that the % results might not be the most pleasant to your aesthetic % values. They are so because of the logic of \TeX. % \end{function} % % \begin{function}{off} % It is equivalent of the |noop| plug when the other two are % not used at all. It is only required when you want to go % back to \LaTeX\ defaults. E.g., if you have turned strict % native numbering in some language and you want it to go % back to \LaTeX\ defaults, you may use this. % \end{function} % % \newpage % % \lngxdocumentation{logos} % % This is a small package that provides commands for % printing logos of the \lngxpkg\ bundle. The logo is % printed in New Computer Modern Uncial font. It uses purple % colour for the \enquote{X} in it and it is defined using % \pkg{l3color} module. It provides one command that takes % an optional argument. Obviously it is ‘|protect|ed’. It is % as follows: % % \begin{function}{\lngxlogo} % \begin{syntax} % \oarg{package name} % \end{syntax} % The logo of the \meta{package name} from the \lngxpkg\ % bundle is printed with this command, e.g., % |\lngxlogo[fonts]|\,$\longrightarrow$\,\lngxfontslogo. % \end{function} % % Sometimes, the logos might be required to be used in an % expandable way, but optional arguments are not supported % in expandable commands. Thus we create separate commands % for separate packages. Even these ones have the |lngx| % prefix. It is followed by the package name, e.g., |fonts| % or |ipa| and finally the suffix |logo|. In the context of % \pkg{hyperref}, their behaviour is different than in the % context of normal text. % % \newpage % % \lngxdocumentation{nfss} % % This is an extension package to the existing \textsc{nfss} % scheme of \LaTeX. The \textsc{nfss} mainly works on the % four facets of the text, i.e., encoding, family, shape and % series. These facets are reset to default by the % |\normalfont| and |\selectfont| commands. These commands % work on some internals that are reset with every usage of % some commands that set them, e.g., |\rmfamily|, % |\bfseries|. There isn’t any way to control this unless % some internals are touched and there might be incidences % where one does want to control them, e.g., try compiling % the following code in Lua\LaTeX. % % \rule{0.7\linewidth}{0.5pt} % % \begin{verbatim} % \documentclass{article} % % \begin{document} % \makeatletter % \fontencoding{OT1}\sffamily\itshape\bfseries % \selectfont % \f@encoding\ | \f@family\ | \f@series\ | \f@shape\quad % \normalfont % \f@encoding\ | \f@family\ | \f@series\ | \f@shape % \end{document} % \end{verbatim} % % \rule{0.7\linewidth}{0.5pt} % % \medskip % % As can be seen in the output, the first line shows the % text in \textsc{ot}1 encoding, sans family, bold series % and Italic shape. After |\normalfont|, every aspect of the % text is reset to the default one. The default encoding is % \textsc{tu}. We can see \textsc{tu} instead of % \textsc{ot}1 after |\normalfont|. So is the case with % family (default: |\rmfamily|), series (default: % |\mdseries|) and shape (default: |\upshape|). This usually % is okay, but sometimes it doesn’t fit the requirement. % E.g., the following might be used with the intention of % switching from the \textsc{ipa} font to the text font, but % as can be seen, it doesn’t really change anything. % % \rule{0.7\linewidth}{0.5pt} % % \begin{verbatim} % \documentclass{article} % \usepackage{linguistix-fonts} % \usepackage{linguistix-ipa} % \linguistix{% % text upright = {KpRoman-Regular.otf},% % text upright features = {Color={green}},% % ipa upright = {KpSans-Regular.otf},% % ipa upright features = {Color={red}}% % } % % \begin{document} % test \lngxipa test \normalfont test % \end{document} % \end{verbatim} % % \rule{0.7\linewidth}{0.5pt} % % \medskip % % The reason for this is the way \cs{lngxipa} is defined. It % resets |\rmdefault|, |\sfdefault| and |\ttdefault| and % uses |\normalfont| to initialise this new super font % family (see: % \url{https://tex.stackexchange.com/a/729805}). Setting a % \enquote{super} font family effectively changes the % behaviour of |\normalfont| permanently. By the way, this % is not just something that \lngxpkg\ has to deal with. % This situation may arise whenever one wants to have a font % family command that sets all serif, sans serif and % monospaced font families. \lngxnfsslogo\ is useful in such % cases. It introduces the concept of \enquote{super} font % family. It shouldn’t be confused with % \hologo{LaTeX2e}’s \enquote{meta} font family. It refers % to |rm|, |sf| or |tt| in the kernel. This package provides % control over these facets. Let’s have a look at the macros % it provides. % % \begin{function}[EXP]{^^A % \IfEncodingTF,\IfEncodingT,\IfEncodingF,\CurrentEncoding % } % \begin{syntax} % \marg{encoding} \marg{true code} \marg{false code} % \marg{encoding} \marg{true code} % \marg{encoding} \marg{false code} % \end{syntax} % If the current encoding matches with the given % \meta{encoding}, it selects the true branch; false % otherwise. The \cs{CurrentEncoding} macro expands to the % current encoding. % \end{function} % % \begin{function}[EXP]{^^A % \IfMetaFamilyTF,\IfMetaFamilyT,\IfMetaFamilyF,^^A % \CurrentMetaFamily % } % \begin{syntax} % \marg{meta family} \marg{true code} \marg{false code} % \marg{meta family} \marg{true code} % \marg{meta family} \marg{false code} % \end{syntax} % If the current meta family matches with the given % \meta{meta family}, it selects the true branch; false % otherwise. The \cs{CurrentMetaFamily} macro expands to the % current meta family. % \end{function} % % \begin{function}[EXP]{^^A % \IfSuperFamilyTF,\IfSuperFamilyT,\IfSuperFamilyF,^^A % \CurrentSuperFamily % } % \begin{syntax} % \marg{super family} \marg{true code} \marg{false code} % \marg{super family} \marg{true code} % \marg{super family} \marg{false code} % \end{syntax} % If the current super family matches with the given % \meta{super family}, it selects the true branch; false % otherwise. The \cs{CurrentSuperFamily} macro expands to % the current super family. % \end{function} % % \begin{function}[EXP]{^^A % \IfSeriesTF,\IfSeriesT,\IfSeriesF,\CurrentSeries % } % \begin{syntax} % \marg{series} \marg{true code} \marg{false code} % \marg{series} \marg{true code} % \marg{series} \marg{false code} % \end{syntax} % If the current series matches with the given % \meta{series}, it selects the true branch and false % otherwise. The \cs{CurrentSeries} macro expands to the % current series. % \end{function} % % \begin{function}[EXP]{^^A % \IfShapeTF,\IfShapeT,\IfShapeF,\CurrentShape % } % \begin{syntax} % \marg{shape} \marg{true code} \marg{false code} % \marg{shape} \marg{true code} % \marg{shape} \marg{false code} % \end{syntax} % If the current series matches with the given \meta{shape}, % it selects the true branch and false otherwise. The % \cs{CurrentShape} macro expands to the current shape. % \end{function} % % \begin{function}{\superfontfamily} % \begin{syntax} % \marg{family \textsc{id}}^^A % \marg{rm=\marg{rm \textsc{nfss}},\ignorespaces^^A % sf=\marg{sf \textsc{nfss}},tt=\marg{tt \textsc{nfss}}} % \end{syntax} % Every super font family has a \meta{family \textsc{id}}, % even the default one (i.e., |default|). This command % creates a super family with the given \meta{family % \textsc{id}}s. The \meta{meta family keys} argument % accepts a list of specific keys, |rm|, |sf| and |tt|. They % take the \textsc{nfss} family names of these meta families % as arguments. One may define a font with, say, % |\newfontfamily|, pass the |NFSSkeys=|\marg{key} option to % it and use the \meta{key} in the suitable \meta{meta % family key}. Note that using all these keys is \emph{not} % mandatory. A super family may have $\leq 3$ keys. % \end{function} % % \begin{function}{^^A % \softsuperfontfamily,\softersuperfontfamily,^^A % \softestsuperfontfamily % } % \begin{syntax} % \marg{\textsc{id}}\ignorespaces^^A % \marg{encoding,family,series,shape} % \marg{\textsc{id}} % \marg{\textsc{id}} % \end{syntax} % These commands loads the super font family with the given % \meta{\textsc{id}}. The attributes listed in the second % argument are the only choices available. The required % super font family is loaded and the listed attributes are % reset to the ones that were active before. All the four % are not required. The number of attributes may be $\leq % 4$. The \cs{softernormalfont} command excludes encoding % and reactivates all the other attributes, whereas the % \cs{softestnormalfont} command reactivates all of them. % \end{function} % % \begin{function}{^^A % \softnormalfont,\softernormalfont,\softestnormalfont % } % \begin{syntax} % \marg{encoding,family,series,shape} % \end{syntax} % Similar to \cs{softsuperfontfamily} and friends, these % commands switch back to the default super font family, but % reactivate the previously active font attributes. The % argument to \cs{softnormalfont} takes the list of the % required font attributes. It can have $\leq 4$ values. Now % try the following example: % \end{function} % % \rule{0.7\linewidth}{0.5pt} % % \begin{verbatim} % \documentclass{article} % \usepackage{linguistix} % \linguistix{% % text upright features = {Color={green}},% % ipa upright features = {Color={red}}% % } % % \begin{document} % test \lngxipa test \softernormalfont test\par % \makeatletter % \sffamily\itshape\bfseries % \f@family\ | \f@series\ | \f@shape\quad % \softnormalfont{series} % \f@family\ | \f@series\ | \f@shape % \end{document} % \end{verbatim} % % \rule{0.7\linewidth}{0.5pt} % % \medskip % % Better? :-) % % \section*{^^A % \texorpdfstring{^^A % \LaTeX3 interface for programmers^^A % }{^^A % LaTeX3 interface for programmers^^A % }^^A % } % % In this section, we take a look at the public \LaTeX3 % commands of the bundle. These can be considered stable and % can be used in production code. % % \lngxinterface{base} % % \begin{function}{\lngx_set_keys:n} % \begin{syntax} % \meta{keyval list} % \end{syntax} % This is the base command for \cs{linguistix}. It takes a % comma separated list of \meta{keyval list} and parses it. % \end{function} % % \lngxinterface{fixpex} % % No \LaTeX3 function provided by this package. % % \lngxinterface{fonts} % % \begin{function}{^^A % \g_lngx_old_style_bool,\g_lngx_old_style_one_bool,^^A % \g_lngx_bourbaki_bool % } % These are the two booleans that are used to check if the % old style numbers, the old style one (i.e., \enquote{1}) % and Bourbaki’s emtpy set symbol (i.e., % \enquote{$\emptyset$}) is asked by the user. % \end{function} % % \begin{function}{^^A % \lngx_set_main_font:nn,\lngx_set_main_font:VV,^^A % \lngx_set_sans_font:nn,\lngx_set_sans_font:VV,^^A % \lngx_set_mono_font:nn,\lngx_set_mono_font:VV,^^A % \lngx_set_math_font:nn,\lngx_set_math_font:VV^^A % } % \begin{syntax} % \marg{features} \marg{font} % \marg{features} \marg{font} % \marg{features} \marg{font} % \marg{features} \marg{font} % \end{syntax} % These commands take two arguments, retrieve the values of % the data variables if |:VV| variants are used. These are % wrapper commands around the font-setting commands of % \pkg{fontspec} and \pkg{(lua)-unicode-math}, i.e., % |\setmainfont|, |\setsansfont|, |\setmonofont| and % |\setmathfont|. The \meta{features} are passed to the % optional argument and the \meta{font} is passed to the % mandatory argument of the respective command from the % aforementioned list. % \end{function} % % \begin{function}{^^A % \lngx_other_main_font:nnn,\lngx_other_main_font:nee,^^A % \lngx_other_sans_font:nnn,\lngx_other_sans_font:nee,^^A % \lngx_other_mono_font:nnn,\lngx_other_mono_font:nee^^A % } % \begin{syntax} % \marg{language} \marg{features} \marg{font} % \marg{language} \marg{features} \marg{font} % \marg{language} \marg{features} \marg{font} % \end{syntax} % These commands take three arguments. These are wrapper % commands around the font-setting commands of \pkg{babel}. % The \meta{features} are passed to the optional argument % and the \meta{font} is passed to the mandatory argument of % the respective command from the aforementioned list. % \end{function} % % \lngxinterface{glossing} % % \begin{function}{^^A % \lngx_gloss_format:n,\lngx_expansion_format:n % } % \begin{syntax} % \marg{gloss} % \marg{expansion} % \end{syntax} % This function is controlled by the key |format|. Its % argument is the gloss or the expansion itself. According % to the definition set in the key, the argument gets % printed. % \end{function} % % \begin{function}{\lngx_gloss_new:nn} % \begin{syntax} % \marg{gloss} \marg{expansion} % \end{syntax} % This function creates a new gloss. It is later equated % with the \cs{newgloss} command. % \end{function} % % \begin{function}{\lngx_gloss_list:} % This functions prints the list of glosses and is equated % with \cs{listofglosses}. % \end{function} % % \begin{function}{lngx_multicols} % \begin{syntax} % \marg{section title} % \end{syntax} % This environment reads an integer variable, i.e., % \cs{l__lngx_glossary_columns_int}. It is controlled by the % |columns| key. If its number is more than one (which, by % default \emph{is} more than one), the |multicols| % environment is used around the content that comes in % between, or else no action is taken. It takes one % compulsory argument, i.e., the content of the section % title material. This environment should not be used % outside this package. % \end{function} % % \lngxinterface{ipa} % % This package provides a few wrapper functions around % \pkg{fontspec}’s commands. % % \begin{function}{^^A % \lngx_set_main_ipa_font:nn,^^A % \lngx_set_main_ipa_font:VV,^^A % \lngx_main_ipa:,lngx_ipa_rm_nfss^^A % } % \begin{syntax} % \marg{features} \marg{font} % \end{syntax} % These functions set the \textsc{ipa} fonts for the serif % variants. The \meta{font} is set with \meta{features} for % the serif \textsc{ipa}. The command to switch to this % family is \cs{lngx_main_ipa:}. It can be accessed with the % \textsc{nfss} family |lngx_ipa_rm_nfss|. % \end{function} % % \begin{function}{^^A % \lngx_set_sans_ipa_font:nn,^^A % \lngx_set_sans_ipa_font:VV,^^A % \lngx_sans_ipa:,lngx_ipa_sf_nfss^^A % } % \begin{syntax} % \marg{features} \marg{font} % \end{syntax} % These functions set the \textsc{ipa} fonts for the sans % variants. The \meta{font} is set with \meta{features} for % the sans \textsc{ipa}. The command to switch to this % family is \cs{lngx_sans_ipa:}. It can be accessed with the % \textsc{nfss} family |lngx_ipa_sf_nfss|. % \end{function} % % \begin{function}{^^A % \lngx_set_mono_ipa_font:nn,^^A % \lngx_set_mono_ipa_font:VV,^^A % \lngx_mono_ipa:,lngx_ipa_tt_nfss^^A % } % \begin{syntax} % \marg{features} \marg{font} % \end{syntax} % These functions set the \textsc{ipa} fonts for the mono % variants. The \meta{font} is set with \meta{features} for % the mono \textsc{ipa}. The command to switch to this % family is \cs{lngx_mono_ipa:}. It can be accessed with the % \textsc{nfss} family |lngx_ipa_nfss_nfss|. % \end{function} % % \begin{function}{\lngx_ipa:,lngx_ipa} % The \cs{lngx_ipa:} command loads the super family % |lngx_ipa| (see the documentation of \lngxnfsslogo). The % \cs{lngx_ipa:} function has a user-side command % \cs{lngxipa} too. % \end{function} % % \lngxinterface{languages} % % Here are the L3 functions defined for \lngxlanguageslogo. % % \begin{function}{\g_lngx_main_language_tl} % A |tl| that globally stores the main language of the % document. % \end{function} % % \begin{function}{\g_lngx_languages_clist} % A |clist| that globally stores the languages that are % used. % \end{function} % % \begin{function}{\lngx_languages:nn,\lngx_languages:VV} % \begin{syntax} % \marg{language options} \marg{language name} % \meta{language options tl} \meta{language tl} % \end{syntax} % These functions read the |V|-type argument provided to % them and pass it to the |\babelprovide| command for % loading languages. % \end{function} % % \begin{function}{\lngx_load_languages:n} % \begin{syntax} % \marg{list of languages} % \end{syntax} % This function loads the languages in \lngxpkg\ sense. % \end{function} % % \begin{function}{\lngx_counter:n} % This is a developers function provided for printing the % counter based on the plug selected. It changes the meaning % according to the active value of |native-numbering| % socket. % \end{function} % % \begin{function}{\lngx_misc_reset:} % This function resets a lot of custom settings done by % some languages. It has to be used inside \cs{addto} macro % provided by the \pkg{babel} package. % \end{function} % % \lngxinterface{logos} % % There are only two \LaTeX3 functions provided by this % package. % % \begin{function}{\lngx_logo_font:} % This function switches to the New Computer Modern Uncial % font family. % \end{function} % % \begin{function}{lngx_purple_color} % I don’t like the default purple colour of the \pkg{xcolor} % package (i.e., \colorbox{purple}{\phantom{x}}\,). Thus I % have created a new colour using \pkg{l3color} module. It % can be accessed using this variable. The color looks like: % \colorbox{lngxpurplecolor}{\phantom{x}}. % \end{function} % % \lngxinterface{nfss} % % This subsection discusses the programming interface % \lngxnfsslogo\ provides. % % \begin{function}[EXP]{^^A % \c_lngx_default_rmdefault_tl,^^A % \c_lngx_default_sfdefault_tl,^^A % \c_lngx_default_ttdefault_tl % } % \begin{syntax} % \normalfont\normalsize^^A % These |tl|s expand to the default values of the fonts^^A % set at the |begindocument/end| hook. These are not^^A % supposed to be changed and hence they are set with^^A % the |c| prefix. % \end{syntax} % \end{function} % % \begin{function}[EXP]{^^A % \l_lngx_current_encoding_tl,^^A % \l_lngx_current_meta_family_tl,^^A % \l_lngx_current_super_family_tl,^^A % \l_lngx_current_series_tl,^^A % \l_lngx_current_shape_tl % } % \begin{syntax} % \normalfont\normalsize^^A % These |tl|s expand to the current values of encoding,^^A % meta family, super family, series and shape^^A % respectively. Note that these are updated time to time^^A % by the commands that change them (package-internal or^^A % \LaTeX-internal). % \end{syntax} % \end{function} % % \begin{function}[EXP,pTF]{^^A % \lngx_if_encoding:n,\lngx_if_meta_family:n,^^A % \lngx_if_super_family:n,\lngx_if_series:n,\lngx_if_shape:n % } % \begin{syntax} % \marg{encoding} % \marg{encoding}\marg{true code}\marg{false code} % \marg{meta font family} % \marg{meta font family}\marg{true code}\marg{false code} % \marg{super font family} % \marg{super font family}\marg{true code}\marg{false code} % \marg{series} % \marg{series}\marg{true code}\marg{false code} % \marg{shape} % \marg{shape}\marg{true code}\marg{false code} % \end{syntax} % \end{function} % % \begin{function}[EXP,pTF]{^^A % \lngx_if_meta_family_rm:,\lngx_if_meta_family_sf:,^^A % \lngx_if_meta_family_tt: % } % \begin{syntax} % \phantom{x} % \marg{true code}\marg{false code} % \phantom{x} % \marg{true code}\marg{false code} % \phantom{x} % \marg{true code}\marg{false code} % \end{syntax} % These conditionals select the true branch if the |rm|, % |sf|, |tt| families (respectively) are active, false % otherwise. % \end{function} % % \begin{function}[EXP,pTF]{^^A % \lngx_if_series_md:,\lngx_if_series_bf: % } % \begin{syntax} % \phantom{x} % \marg{true code}\marg{false code} % \phantom{x} % \marg{true code}\marg{false code} % \end{syntax} % These conditionals select the true branch if the |md|, % |bf| series (respectively) are active, false otherwise. % \end{function} % % \begin{function}[EXP,pTF]{^^A % \lngx_if_shape_up:,\lngx_if_shape_it:,^^A % \lngx_if_shape_sc:,\lngx_if_shape_ssc:,^^A % \lngx_if_shape_sl:,\lngx_if_shape_sw:,^^A % \lngx_if_shape_ulc: % } % \begin{syntax} % \phantom{x} % \marg{true code}\marg{false code} % \phantom{x} % \marg{true code}\marg{false code} % \phantom{x} % \marg{true code}\marg{false code} % \phantom{x} % \marg{true code}\marg{false code} % \phantom{x} % \marg{true code}\marg{false code} % \phantom{x} % \marg{true code}\marg{false code} % \phantom{x} % \marg{true code}\marg{false code} % \end{syntax} % These conditionals select the true branch if the |up|, % |it|, |sc|, |ssc|, |sl|, |sw|, |ulc| shapes (respectively) % are active, false otherwise. % \end{function} % % \begin{function}{\lngx_super_font_family:nn} % \begin{syntax} % \marg{family \textsc{id}}^^A % \marg{rm=\marg{rm \textsc{nfss}},\ignorespaces^^A % sf=\marg{sf \textsc{nfss}},tt=\marg{tt \textsc{nfss}}} % \end{syntax} % This function takes an \meta{\textsc{id}} and sets the % |rm|, |sf|, |tt| values as requested by the user and % creates a super font family. % \end{function} % % \begin{function}{^^A % \lngx_soft_super_font_family:nn,^^A % \lngx_softer_super_font_family:n,^^A % \lngx_softest_super_font_family:n % } % \begin{syntax} % \marg{\textsc{id}}\ignorespaces^^A % \marg{encoding,family,series,shape} % \marg{\textsc{id}} % \marg{\textsc{id}} % \end{syntax} % The \cs{lngx_soft_super_font_family:nn} sets super family % marked by the \meta{\textsc{id}} and reactivates the % currently active font attributes listed in the second % argument. The other two do the same, but without the list. % the |softer| one omits the encoding and the |softest| one % reactivate all of them. % \end{function} % % \begin{function}{^^A % \lngx_soft_normal_font:n,^^A % \lngx_softer_normal_font:,^^A % \lngx_softest_normal_font: % } % \begin{syntax} % \marg{\textsc{id}} % \end{syntax} % Quite similar to the soft super family functions, these % ones set the default font family and reactivate the font % attributes. The |soft| one sets the attributes listed in % the argument. The |softer| one omits encoding and % reactivates the rest and the |softest| one reactivates % all. % \end{function} % \end{documentation} % % \newpage % % \begin{implementation} % \section*{Implementation} % % In this section the code of this bundle is documented. % Each package in the bundle is documented in a separate % subsection. % % \subsection*{\lngxpkg} % % Provide the package with its basic information. % \begin{macrocode} %<*package> \ProvidesExplPackage{linguistix} {2026-02-02} {v0.8} {% The ‘LinguisTiX’ bundle: Enhanced support for linguistics.% } % \end{macrocode} % When one loads \lngxpkg, all the packages of the bundle % are loaded automatically. That’s the only content of the % umbrella package \lngxpkg. All the packages are loaded % conditionally (i.e., only if not loaded already). % \begin{macrocode} \IfPackageLoadedF { linguistix-base } { \RequirePackage { linguistix-base } } \IfPackageLoadedF { linguistix-fonts } { \RequirePackage { linguistix-fonts } } \IfPackageLoadedF { linguistix-glossing } { \RequirePackage { linguistix-glossing } } \IfPackageLoadedF { linguistix-ipa } { \RequirePackage { linguistix-ipa } } \IfPackageLoadedF { linguistix-languages } { \RequirePackage { linguistix-languages } } \IfPackageLoadedF { linguistix-leipzig } { \RequirePackage { linguistix-leipzig } } \IfPackageLoadedF { linguistix-logos } { \RequirePackage { linguistix-logos } } \IfPackageLoadedF { linguistix-nfss } { \RequirePackage { linguistix-nfss } } % % \end{macrocode} % \newpage % \lngximplementation{base} % Set the essentials of the package. % \begin{macrocode} %<*base> \ProvidesExplPackage{linguistix-base} {2026-02-02} {v0.8} {% The base package of the ‘LinguisTiX’ bundle.% } % \end{macrocode} % \begin{macro}{\lngx_set_keys:n} % I use the \pkg{l3keys} module of \LaTeX3 for creating the % key-values used in this bundle. In order to get a % singleton parser for all the packages of the bundle, I % have create this parsing command that is used throughout % the bundle. % \begin{macrocode} \cs_new_protected:Npn \lngx_set_keys:n #1 { \keys_set:nn { lngx_keys } { #1 } } % \end{macrocode} % \end{macro} % \begin{macro}{\linguistix} % I equate this command with a user-side macro here and end % the \lngxbaselogo\ package. % \begin{macrocode} \cs_gset_eq:NN \linguistix \lngx_set_keys:n % % \end{macrocode} % \end{macro} % \newpage % \lngximplementation{fixpex} % The \pkg{unicode-math} and \pkg{lua-unicode-math} packages % define |\gla| command which clashes with the same command % defined by the \pkg{expex} package. Of course, the % \pkg{expex}-|\gla| is more relevant in linguistics. Thus I % will save that and provide a new command for the % \pkg{(lua)-unicode-math}-|\gla|. This is not relevant to % people who are not using \pkg{expex}. Thus, the settings % are loaded only conditionally. % \begin{macrocode} %<*fixpex> \ProvidesExplPackage{linguistix-fixpex} {2026-02-02} {v0.8} {% To fix the clash between ‘expex’ and (lua-unicode-math).% } % \end{macrocode} % This package is useful only if either \pkg{expex} or % \pkg{(lua)-unicode-math} is loaded. Otherwise, it is of no % use. Thus, I create a message when either of them is not % loaded. % \begin{macrocode} \msg_new:nnn { fixpex } { pkg_not_loaded } { The~ ‘LinguisTiX-fixpex’~ package~ is~ a~ first-aid~ for~ resolving~ the~ clash~ between~ ‘(lua)-unicode-math’\\ and~ ‘expex’.~ It~ should~ only~ be~ used~ if~ at~ least\\ one~ of~ the~ two~ is~ loaded.~ Here~ ‘LinguisTiX-fixpex’\\ is~ not~ needed~ as~ you~ ‘#1’~ is~ not~ loaded. } % \end{macrocode} % I first start the hook |begindocument/before|. % \begin{macrocode} \hook_gput_code:nnn { begindocument / before } { . } { % \end{macrocode} % The \pkg{(lua)-unicode-math} package defines |\gla| after % |\begin{document}|, so the fix needs to be added after % that is done. For that, I start the |begindocument/end| % hook. % \begin{macrocode} \IfPackageLoadedTF { expex } { \exp_args:Ne \IfPackageLoadedTF { \sys_if_engine_luatex:TF { \IfPackageLoadedF { unicode-math } { unicode-math } { lua-unicode-math } } { unicode-math } } { \hook_gput_code:nnn { begindocument / end } { . } { % \end{macrocode} % \begin{macro}{\umgla} % This replicates the \pkg{(lua)-unicode-math}-|\gla| for % future use. % \begin{macrocode} \cs_gset_eq:NN \umgla \gla % \end{macrocode} % \end{macro} % The \pkg{expex}-|\gla| is then equated to the internal % function of the package that does the actual function % \parencite{alan}. % \begin{macrocode} \cs_gset_eq:NN \gla \glw@gla } % \end{macrocode} % In the false branch of \pkg{(lua)-unicode-math}, I issue % an info message that is not visible on the terminal, but % is printed in the log file. % \begin{macrocode} } { \msg_info:nnn { fixpex } { pkg_not_loaded } { (lua)-unicode-math } } % \end{macrocode} % Similarly, I do it for \pkg{expex}. % \begin{macrocode} } { \msg_info:nnn { fixpex } { pkg_not_loaded } { expex } } } % % \end{macrocode} % \newpage % \lngximplementation{fonts} % Package essentials first. % \begin{macrocode} %<*font> \ProvidesExplPackage{linguistix-fonts} {2026-02-02} {v0.8} {% The font-assistant package of the ‘LinguisTiX’ bundle.% } % \end{macrocode} % Then, I load \pkg{unicode-math} or \pkg{lua-unicode-math} % (depending on the engine used), \lngxnfsslogo\ and % \lngxbaselogo\ (if they are not already loaded). % \begin{macrocode} \IfPackageLoadedF { linguistix-base } { \RequirePackage { linguistix-base } } \sys_if_engine_luatex:TF { \IfPackageLoadedF { unicode-math } { \IfPackageLoadedF { lua-unicode-math } { \RequirePackage { fontspec, lua-unicode-math } } } } { \IfPackageLoadedF { unicode-math } { \RequirePackage { unicode-math } } } \IfPackageLoadedF { linguistix-fixpex } { \RequirePackage { linguistix-fixpex } } % \end{macrocode} % \begin{macro}{\LaTeX,\ogLaTeX} % We save the original code for the |\LaTeX| logo and then % renew the command. % \begin{macrocode} \NewCommandCopy \ogLaTeX \LaTeX \RenewDocumentCommand \LaTeX { } {% L\kern-.81ex\relax \raisebox{.6ex}{\textsc{a}}\kern-.23ex\relax \hbox{T}\kern-.4ex\relax \raisebox{-.5ex}{E}\kern-.3ex\relax X% } % \end{macrocode} % \end{macro} % \begin{macro}{^^A % old style numbers,\g_lngx_old_style_bool,^^A % old style one,\g_lngx_old_style_one_bool,^^A % bourbaki's empty set,\g_lngx_bourbaki_bool % } % I use the |.bool_gset:N| key-type of \pkg{l3keys} for % developing these boolean keys. % \begin{macrocode} \keys_define:nn { lngx_keys } { old~ style~ numbers .bool_gset:N = { \g_lngx_old_style_bool }, old~ style~ one .bool_gset:N = { \g_lngx_old_style_one_bool }, bourbaki's~ empty~ set .bool_gset:N = { \g_lngx_bourbaki_bool } } % \end{macrocode} % \end{macro} % \begin{macro}{^^A % \g__lngx_text_main_fonts_prop,^^A % \g__lngx_text_main_font_features_tl,^^A % text upright,text upright features,text bold upright,text % bold upright features,text italic,text italic % features,text bold italic,text bold italic features,text % slanted,text slanted features,text bold slanted,text bold % slanted features,text swash,text swash features,text bold % swash,text bold swash features,text small caps,text small % caps features^^A % } % In the first few versions of the package, I used to save % the font-names and their features in token lists, but I % found a better way to deal with this later which was using % |prop| lists. I had released the |tl|s publicly (with a % single |_| after the scope marker), which means ideally % they should be available forever, but for performance and % maintenance the newer approach is much preferred and hence % I decided to shift to |prop| lists from v0.6. This time, I % am correcting the mistake I made before. The |prop| lists % that save the keys is not public. It need not be. Only the % key-value pairs are public. They are unchanged anyway. % This section describes the implementation of serif text % fonts. All these keys have a common pattern of code. For % the convenience of maintenance, I have created a % comma-separated-list and used the elements of this list % inside the common code. % (See: \url{https://topanswers.xyz/tex?q=8074#a7689}.) % \begin{macrocode} \prop_gclear_new:N \g__lngx_text_main_fonts_prop \tl_gclear_new:N \g__lngx_text_main_font_features_tl \clist_map_inline:nn { upright, bold~ upright, italic, bold~ italic, slanted, bold~ slanted, swash, bold~ swash, small~ caps } { % \end{macrocode} % All the keys here are prefixed with the word |text| in % order to distinguish them from the keys provided by the % \lngxipalogo\ package. The argument of these keys should % be expanded for which I use |\prop_gput:Nne| function. % Each |#1| is replaced by the items from clist and the loop % is repeated, whereas |##1| is the argument passed to the % key by user. % \begin{macrocode} \keys_define:nn { lngx_keys } { text~ #1 .code:n = { % \end{macrocode} % I start a group first. Then clear and set a temporary % string variable. I make the text of the key titlecased as % required by \pkg{fontspec} and remove the spaces. Lastly, % the word |Font| is appended. So, |bold italic| becomes % |BoldItalicFont|. % \begin{macrocode} \group_begin: \str_clear:N \l_tmpa_str \str_set:Ne \l_tmpa_str { \text_titlecase_all:n { #1 } Font } \str_replace_all:Nnn \l_tmpa_str { ~ } { } % \end{macrocode} % The string is used inside the relevant |prop|-key and % group is ended. % \begin{macrocode} \prop_gput:Nne \g__lngx_text_main_fonts_prop { text~ #1 } { \str_use:N \l_tmpa_str = { ##1 } } \group_end: }, % \end{macrocode} % Same is repeated for features. % \begin{macrocode} text~ #1~ features .code:n = { \group_begin: \str_clear:N \l_tmpa_str \str_set:Ne \l_tmpa_str { \text_titlecase_all:n { #1 } Features } \str_replace_all:Nnn \l_tmpa_str { ~ } { } \prop_gput:Nne \g__lngx_text_main_fonts_prop { text~ #1~ features } { \str_use:N \l_tmpa_str = { ##1 } } \group_end: } } } % \end{macrocode} % \end{macro} % \begin{macro}{text extra features} % This key adds to the property that stores the extra % features for the serif fonts. % \begin{macrocode} \keys_define:nn { lngx_keys } { text~ extra~ features .prop_gput:N = \g__lngx_text_main_fonts_prop } % \end{macrocode} % \end{macro} % \newpage % \begin{macro}{^^A % \g__lngx_text_sans_fonts_prop,^^A % \g__lngx_text_sans_font_features_tl,^^A % \g__lngx_text_mono_fonts_prop,^^A % \g__lngx_text_mono_font_features_tl,^^A % text sans upright,text sans upright features,text sans % bold upright,text sans bold upright features,text sans % italic,text sans italic features,text sans bold % italic,text sans bold italic features,text sans % slanted,text sans slanted features,text sans bold % slanted,text sans bold slanted features,text sans % swash,text sans swash features,text sans bold swash,text % sans bold swash features,text sans small caps,text sans % small caps features,text mono upright,text mono upright % features,text mono bold upright,text mono bold upright % features,text mono italic,text mono italic features,text % mono bold italic,text mono bold italic features,text mono % slanted,text mono slanted features,text mono bold % slanted,text mono bold slanted features,text mono % swash,text mono swash features,text mono bold swash,text % mono bold swash features,text mono small caps,text mono % small caps features^^A % } % Since the only difference between the upcoming keys is % that of the word |sans| and |mono|, we combine them % together and use a nested |clist|. The rest of the % mechanism is identical. % \begin{macrocode} \prop_gclear_new:N \g__lngx_text_sans_fonts_prop \tl_gclear_new:N \g__lngx_text_sans_font_features_tl \prop_gclear_new:N \g__lngx_text_mono_fonts_prop \tl_gclear_new:N \g__lngx_text_mono_font_features_tl \clist_map_inline:nn { sans, mono } { \clist_map_inline:nn { upright, bold~ upright, italic, bold~ italic, slanted, bold~ slanted, swash, bold~ swash, small~ caps } { \keys_define:nn { lngx_keys } { text~ #1~ ##1 .code:n = { \group_begin: \str_clear:N \l_tmpa_str \str_set:Ne \l_tmpa_str { \text_titlecase_all:n { ##1 } Font } \str_replace_all:Nnn \l_tmpa_str { ~ } { } \prop_gput:cne { g__lngx_text_ #1 _fonts_prop } { text~ #1~ ##1 } { ####1 } \group_end: }, text~ #1~ ##1~ features .code:n = { \group_begin: \str_clear:N \l_tmpa_str \str_set:Ne \l_tmpa_str { \text_titlecase_all:n { #1 } Features } \str_replace_all:Nnn \l_tmpa_str { ~ } { } \prop_gput:cne { g__lngx_text_ #1 _fonts_prop } { text~ #1~ ##1~ features } { \str_use:N \l_tmpa_str = { ####1 } } \group_end: } } } \keys_define:nn { lngx_keys } { text~ #1~ extra~ features .prop_gput:c = { g__lngx_text_ #1 _fonts_prop } } } % \end{macrocode} % \end{macro} % \begin{macro}{^^A % \g__lngx_text_main_font_tl,\g__lngx_text_sans_font_tl,^^A % \g__lngx_text_mono_font_tl,^^A % text main font,text sans font,text mono font^^A % } % These keys add the parameter that sets the main font for % text. They set an internal token list which is retrieved % later by font setting command. % \begin{macrocode} \clist_map_inline:nn { main, sans, mono } { \keys_define:nn { lngx_keys } { text~ #1~ font .tl_gset:c = { g__lngx_text_ #1 _font_tl } } } % \end{macrocode} % \end{macro} % \begin{macro}{^^A % \g__lngx_math_fonts_prop,^^A % \g__lngx_math_features_tl,^^A % \g__lngx_math_bold_fonts_prop,^^A % \g__lngx_math_bold_features_tl,^^A % math,math features,math bold,math bold features^^A % } % The following are the keys set for math. They use the same % mechanism as before. % \begin{macrocode} \prop_gclear_new:N \g__lngx_math_fonts_prop \tl_gclear_new:N \g__lngx_math_features_tl \prop_gclear_new:N \g__lngx_math_bold_fonts_prop \tl_gclear_new:N \g__lngx_math_bold_features_tl \keys_define:nn { lngx_keys } { math .tl_gset:N = \g__lngx_math_font_tl, math~ bold .tl_gset:N = \g__lngx_math_bold_font_tl, math~ features .prop_gput:N = \g__lngx_math_fonts_prop, math~ bold~ features .prop_gput:N = \g__lngx_math_bold_fonts_prop } % \end{macrocode} % \end{macro} % \begin{macro}{newcm} % This key is of type |.meta:n|. It sets certain other keys % that enable the New Computer Modern fonts in book weight % and in all of the serif, sans serif and monospaced % families. % \begin{macrocode} \keys_define:nn { lngx_keys } { newcm .meta:n = { text~ main~ font = { NewCM10-Book.otf }, text~ sans~ font = { NewCMSans10-Book.otf }, text~ mono~ font = { NewCMMono10-Book.otf }, math = { NewCMMath-Book.otf }, math~ bold = { NewCMMath-Bold.otf } } } % \end{macrocode} % \end{macro} % \begin{macro}{newcm sans} % This is a |.meta:n| key that sets the default fonts to the % sans family. % \begin{macrocode} \keys_define:nn { lngx_keys } { newcm~ sans .meta:n = { main~ font = { NewCMSans10-Book.otf }, sans~ font = { NewCMSans10-Book.otf }, mono~ font = { NewCMMono10-Book.otf }, math = { NewCMSansMath-Regular.otf }, math~ bold = { NewCMSansMath-Regular.otf } } } % \end{macrocode} % \end{macro} % \begin{macro}{newcm mono} % This is a |.meta:n| key that sets the default fonts to the % monospaced family. % \begin{macrocode} \keys_define:nn { lngx_keys } { newcm~ mono .meta:n = { main~ font = { NewCMMono10-Book.otf }, sans~ font = { NewCMSans10-Book.otf }, mono~ font = { NewCMMono10-Book.otf }, math = { NewCMSansMath-Regular.otf }, math~ bold = { NewCMSansMath-Regular.otf } } } % \end{macrocode} % \end{macro} % \begin{macro}{newcm regular} % This is a |.meta:n| key that sets the default fonts to the % regular variant of the New Computer Modern family. % \begin{macrocode} \keys_define:nn { lngx_keys } { newcm~ regular .meta:n = { main~ font = { NewCM10-Regular.otf }, sans~ font = { NewCMSans10-Regular.otf }, mono~ font = { NewCMMono10-Regular.otf }, math = { NewCMMath-Regular.otf }, math~ bold = { NewCMMath-Bold.otf } } } % \end{macrocode} % \end{macro} % \begin{macro}{newcm regular sans} % This is a |.meta:n| key that sets the default fonts to the % regular sans variant of the New Computer Modern family. % \begin{macrocode} \keys_define:nn { lngx_keys } { newcm~ regular~ sans .meta:n = { main~ font = { NewCMSans10-Regular.otf }, sans~ font = { NewCMSans10-Regular.otf }, mono~ font = { NewCMMono10-Regular.otf }, math = { NewCMMath-Regular.otf }, math~ bold = { NewCMMath-Bold.otf } } } % \end{macrocode} % \end{macro} % \begin{macro}{newcm regular mono} % This is a |.meta:n| key that sets the default fonts to the % regular monospaced variant of the New Computer Modern % family. % \begin{macrocode} \keys_define:nn { lngx_keys } { newcm~ regular~ mono .meta:n = { main~ font = { NewCMMono10-Regular.otf }, sans~ font = { NewCMSans10-Regular.otf }, mono~ font = { NewCMMono10-Regular.otf }, math = { NewCMMath-Regular.otf }, math~ bold = { NewCMMath-Bold.otf }, } } % \end{macrocode} % \end{macro} % Then we load the |bourbaki's empty set| boolean. This gets % read later while setting the math font. % \begin{macrocode} \lngx_set_keys:n { bourbaki's~ empty~ set, % \end{macrocode} % Then we load the |old style numbers| boolean. % \begin{macrocode} old~ style~ numbers, newcm } % \end{macrocode} % \begin{macro}{^^A % \lngx_set_main_font:nn,\lngx_set_sans_font:nn,^^A % \lngx_set_mono_font:nn,\lngx_set_math_font:nn^^A % } % If \lngxlanguageslogo\ package is loaded, I load the fonts % with |\babelfont| command. In case it is not loaded, the % fonts are set with |\setxxxxcommand|-type commands % provided by \pkg{fontspec}. % \begin{macrocode} \IfPackageLoadedF { linguistix-languages } { \cs_new_protected:Npn \lngx_set_main_font:nn #1#2 { \setmainfont [ #1 ] { #2 } } \cs_new_protected:Npn \lngx_set_sans_font:nn #1#2 { \setsansfont [ #1 ] { #2 } } \cs_new_protected:Npn \lngx_set_mono_font:nn #1#2 { \setmonofont [ #1 ] { #2 } } } % \end{macrocode} % A wrapper command is provided for loading math fonts. % \begin{macrocode} \cs_new_protected:Npn \lngx_set_math_font:nn #1#2 { \setmathfont [ #1 ] { #2 } } % \end{macrocode} % \begin{macrocode} \cs_new_protected:Npn \lngx_set_math_bold_font:nn #1#2 { \IfPackageLoadedT { lua-unicode-math } { \DeclareMathVersion { bold } } \setmathfont [ #1, version = { bold } ] { #2 } } % \end{macrocode} % All of these commands should expand their arguments, so I % provide the appropriate variants. % \begin{macrocode} \cs_generate_variant:Nn \lngx_set_main_font:nn { VV } \cs_generate_variant:Nn \lngx_set_sans_font:nn { VV } \cs_generate_variant:Nn \lngx_set_mono_font:nn { VV } \cs_generate_variant:Nn \lngx_set_math_font:nn { VV } \cs_generate_variant:Nn \lngx_set_math_bold_font:nn { VV } % \end{macrocode} % \end{macro} % \begin{macro}{^^A % \__lngx_build_main_font_features:,^^A % \__lngx_build_sans_font_features:,^^A % \__lngx_build_mono_font_features:,^^A % \__lngx_build_math_font_features:,^^A % \__lngx_build_bold_math_font_features:,^^A % \g__lngx_text_main_font_features_tl,^^A % \g__lngx_text_sans_font_features_tl,^^A % \g__lngx_text_mono_font_features_tl,^^A % \g__lngx_math_font_features_tl,^^A % \g__lngx_bold_math_font_features_tl % } % These are some internal functions that basically iterate % on the |prop| list items and each of them is put to the % right of the respective token list. This way only the % functions that are added by the user are exported to the % font setting command. % \begin{macrocode} \clist_map_inline:nn { main, sans, mono } { \cs_new_protected:cpn { __lngx_build_ #1 _font_features: } { \prop_map_inline:cn { g__lngx_text_ #1 _fonts_prop } { \tl_gput_right:cn { g__lngx_text_ #1 _font_features_tl } { ####2 } } } } \cs_new_protected:Npn \__lngx_build_math_features: { \prop_map_inline:Nn \g__lngx_math_fonts_prop { \tl_gput_right:Nn \g__lngx_math_features_tl { { ##2 } } } } \cs_new_protected:Npn \__lngx_build_math_bold_features: { \prop_map_inline:Nn \g__lngx_math_bold_fonts_prop { \tl_gput_right:Nn \g__lngx_math_bold_features_tl { { ##2 } } } } % \end{macrocode} % \end{macro} % Now I start the pre-|begindocument| hook. % \begin{macrocode} \hook_gput_code:nnn { begindocument / before } { . } { % \end{macrocode} % If the boolean for old style numbers is true, I set the % |Numbers| key to |OldStyle|. Similarly, if the % NewCM-specific old one is requested, I turn the % character-variant on. % \begin{macrocode} \lngx_set_keys:n { text~ extra~ features = { \bool_if:NT \g_lngx_old_style_bool { Numbers = { OldStyle }, \bool_if:NT \g_lngx_old_style_one_bool { CharacterVariant = { 6 } } } }, text~ sans~ extra~ features = { \bool_if:NT \g_lngx_old_style_bool { Numbers = { OldStyle }, \bool_if:NT \g_lngx_old_style_one_bool { CharacterVariant = { 6 } } } } } % \end{macrocode} % All the font features are built using the internal % functions and then fonts are set. % \begin{macrocode} \__lngx_build_main_font_features: \lngx_set_main_font:VV \g__lngx_text_main_font_features_tl \g__lngx_text_main_font_tl \__lngx_build_sans_font_features: \lngx_set_sans_font:VV \g__lngx_text_sans_font_features_tl \g__lngx_text_sans_font_tl \__lngx_build_mono_font_features: \lngx_set_mono_font:VV \g__lngx_text_mono_font_features_tl \g__lngx_text_mono_font_tl \__lngx_build_math_features: \lngx_set_math_font:VV \g__lngx_math_features_tl \g__lngx_math_font_tl \IfPackageLoadedT { unicode-math } { \__lngx_build_math_bold_features: \lngx_set_math_bold_font:VV \g__lngx_math_bold_features_tl \g__lngx_math_bold_font_tl } } % % \end{macrocode} % \newpage % \lngximplementation{glossing} % \begin{macrocode} %<*glossing> \ProvidesExplPackage{linguistix-glossing} {2026-02-02} {v0.8} {% Accessible glossing with LinguisTiX% } % \end{macrocode} % In order to print the multi-column glossary, I load the % \cs{multicol} package. % \begin{macrocode} \IfPackageLoadedF { multicol } { \RequirePackage { multicol } } % \end{macrocode} % Then I declare some variables that will be used for % generating the glossing-auxiliary. % \begin{macrocode} \bool_new:N \l_lngx_expansion_bool \tl_clear_new:N \l_lngx_gloss_separator_tl \tl_clear_new:N \l_lngx_expansion_separator_tl \tl_clear_new:N \l_lngx_glossary_separator_tl \dim_zero_new:N \l_lngx_i_have_dim \dim_zero_new:N \l_lngx_i_need_dim \dim_zero_new:N \l_lngx_remain_dim \dim_zero_new:N \l_lngx_i_hack_dim \int_gzero_new:N \g__lngx_page_ref_int \str_clear_new:N \l_lngx_gls_language_str \str_clear_new:N \l__lngx_gls_sorting_order_str \str_clear_new:N \l__lngx_gls_expansion_case_str \str_clear_new:N \l__lngx_glossary_style_str \str_clear_new:N \l__lngx_separator_str \seq_gclear_new:N \g__lngx_gls_use_order_seq \str_set:Nn \l__lngx_separator_str { gloss } % \end{macrocode} % Glossaries are hyperlinked with complex and cryptic % labels. Some readers read the labels loudly when using % assistive technology. In order to dodge that, I add the % text to the Contents key. It uses Ulrike’s ideas: % \url{tex.stackexchange.com/a/758083/174620}. % \begin{macrocode} \IfPDFManagementActiveT { \socket_if_exist:nT { hyp / link / GoTo / Contents } { \socket_new_plug:nnn { hyp / link / GoTo / Contents } { text } { \pdfstringdef \__lngx_tmp_text: { #2 } \pdfannot_dict_put:nne { link / GoTo } { Contents } { ( \__lngx_tmp_text: ) } } } } % \end{macrocode} % After these initial declarations, I move to the socket % that controls the description of the gloss. The socket % itself has no arguments. % \begin{macrocode} \socket_new:nn { lngx / description / gloss } { 0 } % \end{macrocode} % \begin{macro}{\__lngx_gloss_description:} % When the socket is assigned the |on| plug, it defines the % expandable internal command for glossing description. It % is then used inside the tagging socket. The same command % is made inactive when the socket is assigned the |off| % plug. By default the |off| plug is assigned (this is % experimental and may change after reviews from the blind % people). The socket is activated by using it. % \begin{macrocode} \socket_new_plug:nnn { lngx / description / gloss } { on } { \cs_set:Npn \__lngx_gloss_description: { Gloss~ } } \socket_new_plug:nnn { lngx / description / gloss } { off } { \cs_set_eq:NN \__lngx_gloss_description: \prg_do_nothing: } \socket_assign_plug:nn { lngx / description / gloss } { off } \socket_use:n { lngx / description / gloss } % \end{macrocode} % \end{macro} % Then I declare the tagging socket for glossing which takes % two arguments. It should follow the default tagging which % is why I use the |default| plug (which is the only plug % the package does and will offer). The code is based on % suggestions by Ulrike Fischer % (\url{github.com/latex3/tagging-project/discussions/975}). % The |E| tag is used for ‘expansion’ which more or less % suits the nature of glosses. So it is used here. The % command \cs{__lngx_gloss_description:} is controlled by % the socket and is expandable. % \begin{macrocode} \NewTaggingSocket { lngx / gloss } { 2 } \NewTaggingSocketPlug { lngx / gloss } { default } { \mode_leave_vertical: \tag_mc_end: \exp_args:Ne \tag_struct_begin:n { tag = { Span }, E = { \__lngx_gloss_description: #2 } } \tag_mc_begin:n { tag = { Span } } % \end{macrocode} % The argument is printed with the package-controlled % formatting command. First I check if the \pkg{hyperref} % package is loaded. If it is loaded, the link colour is % changed to the one stored in the variable % \cs{g_lngx_gloss_link_color_str} (black, by default). % \begin{macrocode} \IfPackageLoadedTF { hyperref } { \group_begin: \str_clear:N \l_tmpa_str \str_set:Nn \l_tmpa_str { #1 } \exp_args:Ne \hypersetup { linkcolor = { \exp_not:V \g__lngx_gloss_link_color_str } } % \end{macrocode} % The socket for adding text into the Contents directory is % used here. % \begin{macrocode} \IfPDFManagementActiveT { \socket_if_exist:nT { hyp / link / GoTo / Contents } { \socket_assign_plug:nn { hyp / link / GoTo / Contents } { text } } } \lngx_gloss_format:n { \hyperlink { lngx_ #1 _glossary } { #1 } } \group_end: } { % \end{macrocode} % If \pkg{hyperref} is not loaded, the text is simply % printed with the formatting command. % \begin{macrocode} \lngx_gloss_format:n { #1 } } \tag_mc_end: \tag_struct_end: \tag_mc_begin:n { } } % \end{macrocode} % I assign the default tagging plug to the socket I just % defined. % \begin{macrocode} \AssignTaggingSocketPlug { lngx / gloss } { default } % \end{macrocode} % \begin{macro}{format} % Now I define the key for adjusting the formatting of the % glosses. It controls several keys contained in a separate % set. In short, this key will take another keys as % arguments. % \begin{macrocode} \keys_define:nn { lngx_glossing } { format .meta:nn = { lngx / gloss / format } { #1 }, % \end{macrocode} % \end{macro} % \begin{macro}{link color,\g__lngx_gloss_link_color_str} % This option sets the colour used for glossing links. It is % set to |black| by default. % \begin{macrocode} link~ color .str_gset:N = \g__lngx_gloss_link_color_str, link~ color .initial:n = { black }, % \end{macrocode} % \end{macro} % \begin{macro}{sort,\l__lngx_gls_sorting_order_str} % Glosses can be sorted alphabetically or as they are used. % The choice key for that is as follows. By default glosses % are sorted alphabetically. % \begin{macrocode} sort .choices:nn = { alphabetical, use } { \str_set_eq:NN \l__lngx_gls_sorting_order_str \l_keys_choice_str }, sort .initial:n = { alphabetical }, % \end{macrocode} % \end{macro} % \begin{macro}{^^A % expansion case,\l__lngx_gls_expansion_case_str % } % The expansion can be printed in lower case, title case % (with the first letter capitalised for all the words) or % title case (with the first letter capitalised only for the % first word). The default is lower case. % \begin{macrocode} expansion~ case .choices:nn = { lowercase, title~ case~ all, title~ case~ first } { \str_set_eq:NN \l__lngx_gls_expansion_case_str \l_keys_choice_str }, expansion~ case .initial:n = { lowercase }, % \end{macrocode} % \end{macro} % \begin{macro}{style,\l__lngx_glossary_style_str} % The glossary can be printed in two styles given below. % The default is |block|. % \begin{macrocode} style .choices:nn = { block, inline } { \str_set_eq:NN \l__lngx_glossary_style_str \l_keys_choice_str }, style .initial:n = { block }, % \end{macrocode} % \end{macro} % \begin{macro}{columns,\l__lngx_glossary_columns_int} % There is an option to change the number of columns used % for printing the glossary. It is controlled here. Default % is 2. % \begin{macrocode} columns .int_set:N = \l__lngx_glossary_columns_int, columns .initial:n = { 2 }, % \end{macrocode} % \end{macro} % \begin{macro}{^^A % page numbers,\l__lngx_glosses_page_number_bool % } % Page numbers can be turned off with the following boolean. % By default, they are active. % \begin{macrocode} page~ numbers .bool_set:N = \l__lngx_glosses_page_number_bool, page~ numbers .initial:n = { true }, % \end{macrocode} % \end{macro} % \begin{macro}{sectioning,\l__lngx_gls_sectioning_str} % The section used for printing the glossary title is % controlled by the following command. By default, I use % \cs{section} for printing the title. % \begin{macrocode} sectioning .str_set:N = \l__lngx_gls_sectioning_str, sectioning .initial:n = { section }, % \end{macrocode} % \end{macro} % \begin{macro}{^^A % section number,\l__lngx_gls_section_number_bool % } % This controls if the sectioning level should be numbered % or unnumbered. The default is false. % \begin{macrocode} section~ number .bool_set:N = \l__lngx_gls_section_number_bool, section~ number .initial:n = { false }, % \end{macrocode} % \end{macro} % \begin{macro}{no bold,\l__lngx_gls_bold_bool} % The |no bold| key is defined as an inverse boolean. By % default the key is set to false (resulting in the % controlled boolean being true). % \begin{macrocode} no~ bold .bool_set_inverse:N = \l__lngx_gls_bold_bool, no~ bold .initial:n = { false }, % \end{macrocode} % \end{macro} % \begin{macro}{separator,\l__lngx_separator_tl} % The separator between the glosses is controlled using this % key. It controls the separator for inline glosses, % expansion of glosses as well as glosses seen in the % glossary. Each of these functions set a string variable % which is expanded when this key is used. The default value % of the string variable is gloss and the default value for % this key is |,~|, which means by default the separator % between glosses is a comma followed by a space. % \begin{macrocode} separator .code:n = { \tl_set:cn { l_lngx_ \str_use:N \l__lngx_separator_str _separator_tl } { #1 } }, separator .initial:n = { ,~ }, % \end{macrocode} % \end{macro} % \begin{macro}{entry separator,\l__lngx_entry_separator_tl} % The separator between glossary entries is controlled using % this key. The default is a |\par| token. % \begin{macrocode} entry~ separator .tl_set:N = \l__lngx_entry_separator_tl, entry~ separator .initial:n = { \par } } % \end{macrocode} % \end{macro} % Sometimes language-specific settings are needed. I define % the language string variable with the information % retrieved from the lang key of the \textsc{pdf}. % \begin{macrocode} \IfPDFManagementActiveT { \str_set:Ne \l_lngx_gls_language_str { \GetDocumentProperties { document / lang } } } % \end{macrocode} % \begin{macro}{gloss,\lngx_gloss_format:n} % The formatting of glosses is defined here. By default they % are printed in small caps. % \begin{macrocode} \keys_define:nn { lngx / gloss / format } { gloss .cs_gset_protected:Np = \lngx_gloss_format:n #1, gloss .initial:n = { \textsc { #1 } }, % \end{macrocode} % \end{macro} % \begin{macro}{expansion,\lngx_expansion_format:n} % The formatting of expansions is defined here. There is no % change in the printing in the defaults. % \begin{macrocode} expansion .cs_gset_protected:Np = \lngx_expansion_format:n #1, expansion .initial:n = { #1 } } % \end{macrocode} % \end{macro} % \begin{macro}{\setupglossing} % A wrapper around these options is provided. % \begin{macrocode} \NewDocumentCommand \setupglossing { m } { \keys_set:nn { lngx_glossing } { #1 } } % \end{macrocode} % \end{macro} % \begin{macro}{\newgloss,\lngx_gloss_new:nn} % A function that creates new glosses starts here. It takes % 2 arguments. % \begin{macrocode} \cs_new_protected:Npn \lngx_gloss_new:nn #1#2 { % \end{macrocode} % First and foremost, the string received as the first % argument should change its case to lowercase. It is done % by \cs{str_lowercase:n}. I will use a temporary string % variable for storing the converted value. This needs to be % done locally so I start a group and clear the local |str| % variable. % \begin{macrocode} \group_begin: \str_clear:N \l_tmpa_str \str_set:Ne \l_tmpa_str { \str_lowercase:n { #1 } } % \end{macrocode} % Every gloss has its expansion stored in a token list % associated to it. The token list is declared here and it % is set to the expansion (i.e., |#2|). % \begin{macrocode} \tl_gclear_new:c { g_lngx_ \str_use:N \l_tmpa_str _expansion_tl } \seq_gclear_new:c { g_lngx_ \str_use:N \l_tmpa_str _pages_seq } \tl_gset:cn { g_lngx_ \str_use:N \l_tmpa_str _expansion_tl } { #2 } % \end{macrocode} % Whenever a gloss is defined, an internal protected command % is defined. It doesn’t take any argument. % \begin{macrocode} \cs_new_protected:cpn { __lngx_gloss_ \str_use:N \l_tmpa_str : } { % \end{macrocode} % The arguments are passed to the tagging socket. Since the % tagging socket doesn’t expand everything, an exhaustive % expansion is performed with the help of \cs{exp_args:Nee}. % This is done only if the \cs{DocumentMetadata} command is % used. % \begin{macrocode} \IfDocumentMetadataTF { \exp_args:Nee \UseTaggingSocket { lngx / gloss } { \str_use:N \l_tmpa_str } { #2 } } { \IfPackageLoadedTF { hyperref } { \group_begin: \exp_args:Ne \hypersetup { linkcolor = { \exp_not:V \g__lngx_gloss_link_color_str } } \IfPDFManagementActiveT { \socket_if_exist:nT { hyp / link / GoTo / Contents } { \socket_assign_plug:nn { hyp / link / GoTo / Contents } { text } } } \lngx_gloss_format:n { \hyperlink { lngx_ #1 _glossary } { #1 } } \group_end: } { \lngx_gloss_format:n { #1 } } } % \end{macrocode} % I use \cs{label}-\cs{ref} mechanism for saving the page % numbers of the glosses. An internal integer called % \cs{g__lngx_page_ref_int} is used to generate unique % numbers. The kernel provides \cs{seq_remove_duplicates:N}, % but as it iterates on each and every item, it is slow. The % duplicates can be avoided if the items are added to the % sequence conditionally and only when they don’t exist % already in the sequence. This way duplicates are not % generated at all. This method is used for adding to the % sequences that respectively store the page numbers of % glosses and the order in which they were used. Imagine if % a gloss is used twice on a page, it doesn’t make sense to % add the same page number twice. Similarly, if a gloss is % used, it is added to the sequence of used glosses. It % doesn’t make sense to add it 10 times again and removing % the 9 duplicates later. % \begin{macrocode} \int_gincr:N \g__lngx_page_ref_int \exp_args:Ne \label { lngx_gloss_ \int_use:N \g__lngx_page_ref_int } \cs_if_exist:cT { r @ lngx_gloss_ \int_use:N \g__lngx_page_ref_int } { \group_begin: \tl_clear:N \l_tmpa_tl \tl_set:Ne \l_tmpa_tl { \exp_not:N \use_ii:nnnnn \use:c { r @ lngx_gloss_ \int_use:N \g__lngx_page_ref_int } } \seq_if_in:cVF { g_lngx_ \str_use:N \l_tmpa_str _pages_seq } \l_tmpa_tl { \seq_gput_right:ce { g_lngx_ \str_use:N \l_tmpa_str _pages_seq } { \exp_not:N \use_ii:nnnnn \use:c { r @ lngx_gloss_ \int_use:N \g__lngx_page_ref_int } } } \group_end: } \seq_if_in:NeF \g__lngx_gls_use_order_seq { \str_use:N \l_tmpa_str } { \seq_gput_right:Ne \g__lngx_gls_use_order_seq { \str_use:N \l_tmpa_str } } } \group_end: } \cs_gset_eq:NN \newgloss \lngx_gloss_new:nn % \end{macrocode} % \end{macro} % \begin{macro}{\renewgloss} % Implementing the \cs{renewgloss} command is actually quite % easy. The definition of \cs{lngx_gloss_new:nn} uses only a % single command that errors if the control sequence is % already defined, i.e., \cs{cs_new_protected:cpn}. In order % to renew a gloss, simply undefining the existing command % declared with \cs{lngx_gloss_new:nn} suffices. Later the % arguments are passed to the same command again. No \LaTeX3 % equivalent for this is provided. % \begin{macrocode} \NewDocumentCommand \renewgloss { m m } { \cs_undefine:c { __lngx_gloss_ #1 : } \lngx_gloss_new:nn { #1 } { #2 } } % \end{macrocode} % \end{macro} % \begin{macro}{\glx} % The command to use a gloss takes three arguments where the % first is an optional asterisk. If it is used, the % expansion of the gloss is printed without any special % tags, just as plain text. Otherwise the internal command % for printing the gloss is used with the third argument. % The third argument is a clist. Any number of glosses can % be added to the list. The action is then repeated on each % and every item of the list. The second argument is a list % of options for customising the output. Everything is % computed locally so that for the settings don’t leak. I % perform the action on the first item as desired, then the % same is applied to the remaining items with a preceding % separator. So that all the items are separated properly. % \begin{macrocode} \NewDocumentCommand \glx { s O{ } m } { \group_begin: \IfBooleanT { #1 } { \bool_set_true:N \l_lngx_expansion_bool \str_set:Nn \l__lngx_separator_str { expansion } \keys_set:nn { lngx_glossing } { separator = { , \c_space_tl } } } \keys_set:nn { lngx_glossing } { #2 } \tl_clear:N \l_tmpa_tl \seq_clear:N \l_tmpa_seq \seq_set_from_clist:Nn \l_tmpa_seq { #3 } \seq_pop_left:NN \l_tmpa_seq \l_tmpa_tl \str_set:Ne \l_tmpa_str { \exp_args:Ne \str_lowercase:n { \tl_use:N \l_tmpa_tl } } \bool_if:NTF \l_lngx_expansion_bool { \str_case:Vn \l__lngx_gls_expansion_case_str { { lowercase } { \text_lowercase:n { \tl_use:c { g_lngx_ \str_use:N \l_tmpa_str _expansion_tl } } } { title~ case~ all } { \text_titlecase_all:n { \tl_use:c { g_lngx_ \str_use:N \l_tmpa_str _expansion_tl } } } { title~ case~ first } { \text_titlecase_first:n { \tl_use:c { g_lngx_ \str_use:N \l_tmpa_str _expansion_tl } } } } } { \use:c { __lngx_gloss_ \str_use:N \l_tmpa_str : } } \seq_if_empty:NF \l_tmpa_seq { \seq_map_inline:Nn \l_tmpa_seq { \group_begin: \str_clear:N \l_tmpa_str \str_set:Ne \l_tmpa_str { \exp_args:Ne \str_lowercase:n { ##1 } } \bool_if:NTF \l_lngx_expansion_bool { \str_case:Vn \l__lngx_gls_expansion_case_str { { lowercase } { \tl_use:N \l_lngx_expansion_separator_tl \text_lowercase:n { \tl_use:c { g_lngx_ \str_use:N \l_tmpa_str _expansion_tl } } } { title~ case~ all } { \tl_use:N \l_lngx_expansion_separator_tl \text_titlecase_all:n { \tl_use:c { g_lngx_ \str_use:N \l_tmpa_str _expansion_tl } } } { title~ case~ first } { \tl_use:N \l_lngx_expansion_separator_tl \text_titlecase_first:n { \tl_use:c { g_lngx_ \str_use:N \l_tmpa_str _expansion_tl } } } } } { \tl_use:N \l_lngx_gloss_separator_tl \use:c { __lngx_gloss_ \str_use:N \l_tmpa_str : } } \group_end: } } \group_end: } % \end{macrocode} % \end{macro} % \begin{macro}{\__lngx_dotfill:nnn} % For the dotfill between the gloss and the expansion, I % create a custom internal command. The code is based on % user Jonathan P.\ Spratte’s answer seen here: % \url{topanswers.xyz/tex?q=8155#a7758}. The dotfill should % not be tagged at all and in fact it should be suppressed % so that the readers don’t go ‘dot, dot, dot, dot \dots’ % (Frank has convinced us forever with his \textsc{tug} 2025 % talk). % \begin{macrocode} \cs_new_protected:Npn \__lngx_dotfill:nnn #1#2#3 { %% Courtesy: Jonathan P. Spratte %% topanswers.xyz/tex?q=8155#a7758 (LPPL) \l__lngx_entry_separator_tl \smallskip \group_begin: \rightskip = 0pt plus -1fil \prg_do_nothing: \parfillskip = 0pt plus 1fil \prg_do_nothing: \leftskip = 1em plus 1fil \prg_do_nothing: \finalhyphendemerits = 0 \prg_do_nothing: \parindent = -1em \prg_do_nothing: \bool_if:NT \l__lngx_gls_bold_bool { \textbf } { \lngx_gloss_format:n { #1 } \tl_use:N \l_lngx_glossary_separator_tl } #2 \leavevmode \quad \IfDocumentMetadataT { \tag_mc_end: \tag_struct_begin:n { tag = { Span }, actualtext = { } } \tag_mc_begin:n { tag = { Span } } } \cleaders \hbox to 0.44em { \hss . \hss } \hskip 0.5cm plus 1fill \prg_do_nothing: \IfDocumentMetadataT { \tag_mc_end: \tag_struct_end: \tag_mc_begin:n { } } \quad \kern 0pt \prg_do_nothing: \em #3 \l__lngx_entry_separator_tl \group_end: } % \end{macrocode} % \end{macro} % \begin{macro}{lngx_multicols} % Here I define the custom multicolumn environment which % does nothing if the number of columns is 1. % \begin{macrocode} \NewDocumentEnvironment { lngx_multicols } { m } { \int_compare:nNnTF { 1 } < { \int_use:N \l__lngx_glossary_columns_int } { \begin { multicols } { \int_use:N \l__lngx_glossary_columns_int } [ #1 ] } { #1 } \noindent } { \int_compare:nNnT { 1 } < { \int_use:N \l__lngx_glossary_columns_int } { \end { multicols } } } % \end{macrocode} % \end{macro} % \begin{macro}{\lngx_gloss_list:} % Finally we come to the command that prints the glosses. % First it sets the boolean for creating the aux file to % false. % \begin{macrocode} \cs_new_protected:Npn \lngx_gloss_list: { \bool_gset_false:N \g_lngx_trigger_aux_file_bool % \end{macrocode} % I start a group, clear a scratch sequence and set it equal % to the sequence that stores the order of the glosses. If % the aux file is read, the |aux| flag is added to the % variable, or else it is read on the fly. % \begin{macrocode} \group_begin: \seq_clear:N \l_tmpa_seq \seq_set_eq:NN \l_tmpa_seq \g__lngx_gls_use_order_seq % \end{macrocode} % If the sorting order is set to |alphabetical|, the % sequence needs to get sorted. For that, I use \LaTeX3’s % mechanism for sorting strings. % \begin{macrocode} \str_case:Vn \l__lngx_gls_sorting_order_str { { alphabetical } { \seq_sort:Nn \l_tmpa_seq { \str_compare:nNnTF { ##1 } > { ##2 } { \sort_return_swapped: } { \sort_return_same: } } } } % \end{macrocode} % If the style used is |inline|, the glosses come after the % each other. That means the default entry separator, i.e., % |\par| must be changed. Here I set it to |,~| by default % (locally). The separator between the gloss and the entry % is defined as a colon followed by a space. % \begin{macrocode} \str_if_eq:VnTF \l__lngx_glossary_style_str { inline } { \group_begin: \keys_set:nn { lngx_glossing } { separator = { \c_colon_str \c_space_tl }, entry~ separator = { ,~ } } % \end{macrocode} % Then each item from the sequence is popped (from the % left). It is then passed to a string variable to get rid % of the catcodes. The string variable is then used in % \cs{MakeLinkTarget*}. The gloss is then printed with its % separator in bold shape. % \begin{macrocode} \tl_clear:N \l_tmpa_tl \str_clear:N \l_tmpa_str \seq_pop_left:NN \l_tmpa_seq \l_tmpa_tl \str_set:NV \l_tmpa_str \l_tmpa_tl \tag_mc_end: \tag_struct_begin:n { tag = { Span }, } \tag_mc_begin:n { tag = { Span } } \MakeLinkTarget * { lngx_ \str_use:N \l_tmpa_str _glossary } \bool_if:NT \l__lngx_gls_bold_bool { \textbf } { \lngx_gloss_format:n { \tl_use:N \l_tmpa_tl \tl_use:N \l_lngx_glossary_separator_tl } } \tag_mc_end: \tag_struct_end: % \end{macrocode} % Then it is checked in which case the expansion is % requested. According to that the |tl| is printed. % \begin{macrocode} \str_case:Vn \l__lngx_gls_expansion_case_str { { lowercase } { \lngx_expansion_format:n { \text_lowercase:n { \tl_use:c { g_lngx_ \str_use:N \l_tmpa_str _expansion_tl } } } } { title~ case~ all } { \lngx_expansion_format:n { \text_titlecase_all:n { \tl_use:c { g_lngx_ \str_use:N \l_tmpa_str _expansion_tl } } } } { title~ case~ first } { \lngx_expansion_format:n { \text_titlecase_first:n { \tl_use:v { g_lngx_ \str_use:N \l_tmpa_str _expansion_tl } } } } } % \end{macrocode} % After printing one entry successfully, if there are any % more items left in the sequence, they are printed with the % same method, but with an entry separator at the beginning. % \begin{macrocode} \seq_if_empty:NF \l_tmpa_seq { \seq_map_inline:Nn \l_tmpa_seq { \group_begin: \tl_use:N \l__lngx_entry_separator_tl \MakeLinkTarget * { lngx_ ##1 _glossary } \textbf { \lngx_gloss_format:n { ##1 \tl_use:N \l_lngx_glossary_separator_tl } } \str_case:Vn \l__lngx_gls_expansion_case_str { { lowercase } { \lngx_expansion_format:n { \text_lowercase:n { \exp_not:v { g_lngx_ ##1 _expansion_tl } } } } { title~ case~ all } { \lngx_expansion_format:n { \text_titlecase_all:n { \exp_not:v { g_lngx_ ##1 _expansion_tl } } } } { title~ case~ first } { \lngx_expansion_format:n { \text_titlecase_first:n { \exp_not:v { g_lngx_ ##1 _expansion_tl } } } } } \group_end: } } \group_end: } { % \end{macrocode} % If the style is not |inline|, then the default |block| % style is assumed and firstly the word ‘glossary’ is % printed in a sectioning command controlled by the keys. % The \cs{glossaryname} command is provided by \pkg{babel}. % If it is undefined, that means the user hasn’t loaded % \pkg{babel}. In that case, I define the command with the % string |Glossary|. % \begin{macrocode} \ProvideDocumentCommand \glossaryname { } { Glossary } % \end{macrocode} % Then the |lngx_multicols| environment starts which % doesn’t do anything if the number of columns is 1. % \begin{macrocode} \begin { lngx_multicols } { \str_if_eq:VnF \l__lngx_gls_sectioning_str { null } { \use:e { \exp_not:N \use:c { \str_use:N \l__lngx_gls_sectioning_str } \bool_if:NF \l__lngx_gls_section_number_bool { * } { \exp_not:N \glossaryname } } } } \seq_map_inline:Nn \l_tmpa_seq { % \end{macrocode} % In this style, even the page numbers are printed along % with glosses. We save the page numbers in a temporary % sequence which is locally cleared. % \begin{macrocode} \group_begin: \seq_clear:N \l_tmpb_seq \seq_map_inline:cn { g_lngx_ ##1 _pages_seq } { % \end{macrocode} % The pages are hyperlinked with the internal \textsc{pdf} % names. % \begin{macrocode} \seq_put_right:Ne \l_tmpb_seq { ####1 } } % \end{macrocode} % The page numbers are separated using dotfill. Before the % glosses, \cs{MakeLinkTarget*} is used. % \begin{macrocode} \__lngx_dotfill:nnn { \MakeLinkTarget * { lngx_ ##1 _glossary } ##1 } { % \end{macrocode} % The case of expansion is checked and then the appropriate % casing commands are used for expansions. % \begin{macrocode} \str_case:Vn \l__lngx_gls_expansion_case_str { { lowercase } { \lngx_expansion_format:n { \text_lowercase:n { \exp_not:v { g_lngx_ ##1 _expansion_tl } } } } { title~ case~ all } { \lngx_expansion_format:n { \text_titlecase_all:n { \exp_not:v { g_lngx_ ##1 _expansion_tl } } } } { title~ case~ first } { \lngx_expansion_format:n { \text_titlecase_first:n { \exp_not:v { g_lngx_ ##1 _expansion_tl } } } } } } { % \end{macrocode} % The list of page numbers is printed. % \begin{macrocode} \seq_use:Nn \l_tmpb_seq { ,~ } } \group_end: } \end { lngx_multicols } } \group_end: } % \end{macrocode} % \end{macro} % \begin{macro}{\listofglosses} % Here is the command that defines the user-side command for % printing the glosses. It defines the separator by default % if not provided. All settings are local in order to avoid % leaking. \cs{l_lngx_separator_tl} is the generic string % that is used inside the |separator| key that sets the % separator contextually. This command uses the \LaTeX3 % function for printing the glosses. % \begin{macrocode} \NewDocumentCommand \listofglosses { O { } } { \group_begin: \str_set:Nn \l__lngx_separator_str { glossary } \keys_set:nn { lngx_glossing } { separator = { \c_colon_str \c_space_tl } } \keys_set:nn { lngx_glossing } { #1 } \lngx_gloss_list: \group_end: } % % \end{macrocode} % \end{macro} % \newpage % \lngximplementation{ipa} % \begin{macrocode} %<*ipa> \ProvidesExplPackage{linguistix-ipa} {2026-02-02} {v0.8} {% A package for typesetting the IPA (International Phonetic Alphabet) from the ‘LinguisTiX’ bundle.% } % \end{macrocode} % Then, I load \pkg{unicode-math} or \pkg{lua-unicode-math} % (depending on the engine used), \lngxnfsslogo\ and % \lngxbaselogo\ (if they are not already loaded). % \begin{macrocode} \sys_if_engine_luatex:TF { \IfPackageLoadedF { unicode-math } { \IfPackageLoadedF { lua-unicode-math } { \RequirePackage { fontspec, lua-unicode-math } } } } { \IfPackageLoadedF { unicode-math } { \RequirePackage { unicode-math } } } \IfPackageLoadedF { linguistix-base } { \RequirePackage { linguistix-base } } \IfPackageLoadedF { linguistix-nfss } { \RequirePackage { linguistix-nfss } } \IfPackageLoadedF { linguistix-fixpex } { \RequirePackage { linguistix-fixpex } } % \end{macrocode} % \begin{macro}{\ipatext,\ipatext*} % The |\ipatext| command along with its starred variant is % developed here. % \begin{macrocode} \NewDocumentCommand \ipatext { s m } { \IfBooleanTF { #1 } { { \lngxipa / #2 / } } { { \lngxipa [ #2 ] } } } % \end{macrocode} % \end{macro} % \newpage % \begin{macro}{^^A % \g__lngx_ipa_main_fonts_prop,^^A % \g__lngx_ipa_main_font_features_tl,^^A % ipa upright,ipa upright features,ipa bold upright,ipa bold % upright features,ipa italic,ipa italic features,ipa bold % italic,ipa bold italic features,ipa slanted,ipa slanted % features,ipa bold slanted,ipa bold slanted features,ipa % swash,ipa swash features,ipa bold swash,ipa bold swash % features,ipa small caps,ipa small caps features,^^A % } % These variables store the values for fonts and features % for the serif \textsc{ipa}. % \begin{macrocode} \prop_gclear_new:N \g__lngx_ipa_main_fonts_prop \tl_gclear_new:N \g__lngx_ipa_main_font_features_tl \clist_map_inline:nn { upright, bold~ upright, italic, bold~ italic, slanted, bold~ slanted, swash, bold~ swash, small~ caps } { % \end{macrocode} % All the keys here are prefixed with the word |ipa| in % order to distinguish them from the keys provided by the % \lngxfontslogo\ package. These keys have identical method % as their text counterparts, though. % \begin{macrocode} \keys_define:nn { lngx_keys } { ipa~ #1 .code:n = { \group_begin: \str_clear:N \l_tmpa_str \str_set:Ne \l_tmpa_str { \text_titlecase_all:n { #1 } Font } \str_replace_all:Nnn \l_tmpa_str { ~ } { } \prop_gput:Nne \g__lngx_ipa_main_fonts_prop { ipa~ #1 } { \str_use:N \l_tmpa_str = { ##1 } } \group_end: }, ipa~ #1~ features .code:n = { \group_begin: \str_clear:N \l_tmpa_str \str_set:Ne \l_tmpa_str { \text_titlecase_all:n { #1 } Features } \str_replace_all:Nnn \l_tmpa_str { ~ } { } \prop_gput:Nne \g__lngx_ipa_main_fonts_prop { ipa~ #1~ features } { \str_use:N \l_tmpa_str = { ##1 } } \group_end: } } } % \end{macrocode} % \end{macro} % \begin{macro}{ipa extra features} % This key adds to the property that stores the extra % features for the serif fonts. % \begin{macrocode} \keys_define:nn { lngx_keys } { ipa~ extra~ features .prop_gput:N = \g__lngx_ipa_main_fonts_prop } % \end{macrocode} % \end{macro} % \newpage % \begin{macro}{^^A % \g__lngx_ipa_sans_fonts_prop,^^A % \g__lngx_ipa_sans_font_features_tl,^^A % \g__lngx_ipa_mono_fonts_prop,^^A % \g__lngx_ipa_mono_font_features_tl,^^A % ipa sans upright,ipa sans upright features,ipa sans % bold upright,ipa sans bold upright features,ipa sans % italic,ipa sans italic features,ipa sans bold % italic,ipa sans bold italic features,ipa sans % slanted,ipa sans slanted features,ipa sans bold % slanted,ipa sans bold slanted features,ipa sans % swash,ipa sans swash features,ipa sans bold swash,ipa % sans bold swash features,ipa sans small caps,ipa sans % small caps features,ipa mono upright,ipa mono upright % features,ipa mono bold upright,ipa mono bold upright % features,ipa mono italic,ipa mono italic features,ipa % mono bold italic,ipa mono bold italic features,ipa mono % slanted,ipa mono slanted features,ipa mono bold % slanted,ipa mono bold slanted features,ipa mono % swash,ipa mono swash features,ipa mono bold swash,ipa % mono bold swash features,ipa mono small caps,ipa mono % small caps features^^A % } % Since the only difference between the upcoming keys is % that of the word |sans| and |mono|, we combine them % together and use a nested |clist|. The rest of the % mechanism is identical. % \begin{macrocode} \prop_gclear_new:N \g__lngx_ipa_sans_fonts_prop \tl_gclear_new:N \g__lngx_ipa_sans_font_features_tl \prop_gclear_new:N \g__lngx_ipa_mono_fonts_prop \tl_gclear_new:N \g__lngx_ipa_mono_font_features_tl \clist_map_inline:nn { sans, mono } { \clist_map_inline:nn { upright, bold~ upright, italic, bold~ italic, slanted, bold~ slanted, swash, bold~ swash, small~ caps } { \keys_define:nn { lngx_keys } { ipa~ #1~ ##1 .code:n = { \group_begin: \str_clear:N \l_tmpa_str \str_set:Ne \l_tmpa_str { \text_titlecase_all:n { ##1 } Font } \str_replace_all:Nnn \l_tmpa_str { ~ } { } \prop_gput:cne { g__lngx_ipa_ #1 _fonts_prop } { ipa~ #1~ ##1 } { ####1 } \group_end: }, ipa~ #1~ ##1~ features .code:n = { \group_begin: \str_clear:N \l_tmpa_str \str_set:Ne \l_tmpa_str { \text_titlecase_all:n { #1 } Features } \str_replace_all:Nnn \l_tmpa_str { ~ } { } \prop_gput:cne { g__lngx_ipa_ #1 _fonts_prop } { ipa~ #1~ ##1~ features } { \str_use:N \l_tmpa_str = { ####1 } } \group_end: } } } \keys_define:nn { lngx_keys } { ipa~ #1~ extra~ features .prop_gput:c = { g__lngx_ipa_ #1 _fonts_prop } } } % \end{macrocode} % \end{macro} % \begin{macro}{^^A % \g__lngx_ipa_main_font_tl,\g__lngx_ipa_sans_font_tl,^^A % \g__lngx_ipa_mono_font_tl,ipa main font,ipa sans font,ipa % mono font^^A % } % These keys provide keys to set fonts for \textsc{ipa}. % \begin{macrocode} \clist_map_inline:nn { main, sans, mono } { \keys_define:nn { lngx_keys } { ipa~ #1~ font .tl_gset:c = { g__lngx_ipa_ #1 _font_tl } } } % \end{macrocode} % \end{macro} % \begin{macro}{ipa newcm} % This key is of type |.meta:n|. It sets certain other keys % that enable the New Computer Modern fonts in book weight % and in all of the serif, sans serif and monospaced % families for \textsc{ipa}. Stylistic set 5 of NewCM is % dedicated to linguistics. So we use it here. For correct % diacritic placement, we need HarfBuzz renderer. That also % is loaded here. % \begin{macrocode} \keys_define:nn { lngx_keys } { ipa~ newcm .meta:n = { ipa~ extra~ features = { Renderer = {HarfBuzz}, StylisticSet = {05} }, ipa~ sans~ extra~ features = { Renderer = {HarfBuzz}, StylisticSet = {05} }, ipa~ mono~ extra~ features = { Renderer = {HarfBuzz}, StylisticSet = {05} }, ipa~ main~ font = { NewCM10-Book.otf }, ipa~ sans~ font = { NewCMSans10-Book.otf }, ipa~ mono~ font = { NewCMMono10-Book.otf } } } % \end{macrocode} % \end{macro} % \begin{macro}{ipa newcm sans} % This is a |.meta:n| key that sets the default \textsc{ipa} % font to the sans family. % \begin{macrocode} \keys_define:nn { lngx_keys } { ipa~ newcm~ sans .meta:n = { ipa~ extra~ features = { Renderer = {HarfBuzz}, StylisticSet = {05} }, ipa~ sans~ extra~ features = { Renderer = {HarfBuzz}, StylisticSet = {05} }, ipa~ mono~ extra~ features = { Renderer = {HarfBuzz}, StylisticSet = {05} }, ipa~ main~ font = { NewCMSans10-Book.otf }, ipa~ sans~ font = { NewCMSans10-Book.otf }, ipa~ mono~ font = { NewCMMono10-Book.otf } } } % \end{macrocode} % \end{macro} % \begin{macro}{ipa newcm mono} % This is a |.meta:n| key that sets the default \textsc{ipa} % fonts to the monospaced family. % \begin{macrocode} \keys_define:nn { lngx_keys } { ipa~ newcm~ mono .meta:n = { ipa~ extra~ features = { Renderer = {HarfBuzz}, StylisticSet = {05} }, ipa~ sans~ extra~ features = { Renderer = {HarfBuzz}, StylisticSet = {05} }, ipa~ mono~ extra~ features = { Renderer = {HarfBuzz}, StylisticSet = {05} }, ipa~ main~ font = { NewCMMono10-Book.otf }, ipa~ sans~ font = { NewCMSans10-Book.otf }, ipa~ mono~ font = { NewCMMono10-Book.otf } } } % \end{macrocode} % \end{macro} % \begin{macro}{ipa newcm regular} % This is a |.meta:n| key that sets the default fonts to the % regular variant of the New Computer Modern family. % \begin{macrocode} \keys_define:nn { lngx_keys } { ipa~ newcm~ regular .meta:n = { ipa~ extra~ features = { Renderer = {HarfBuzz}, StylisticSet = {05} }, ipa~ sans~ extra~ features = { Renderer = {HarfBuzz}, StylisticSet = {05} }, ipa~ mono~ extra~ features = { Renderer = {HarfBuzz}, StylisticSet = {05} }, ipa~ main~ font = { NewCM10-Regular.otf }, ipa~ sans~ font = { NewCMSans10-Regular.otf }, ipa~ mono~ font = { NewCMMono10-Regular.otf } } } % \end{macrocode} % \end{macro} % \begin{macro}{ipa newcm regular sans} % This is a |.meta:n| key that sets the default \textsc{ipa} % fonts to the regular sans variant of the New Computer % Modern family. % \begin{macrocode} \keys_define:nn { lngx_keys } { ipa~ newcm~ regular~ sans .meta:n = { ipa~ extra~ features = { Renderer = {HarfBuzz}, StylisticSet = {05} }, ipa~ sans~ extra~ features = { Renderer = {HarfBuzz}, StylisticSet = {05} }, ipa~ mono~ extra~ features = { Renderer = {HarfBuzz}, StylisticSet = {05} }, ipa~ main~ font = { NewCMSans10-Regular.otf }, ipa~ sans~ font = { NewCMSans10-Regular.otf }, ipa~ mono~ font = { NewCMMono10-Regular.otf } } } % \end{macrocode} % \end{macro} % \begin{macro}{ipa newcm regular mono} % This is a |.meta:n| key that sets the default \textsc{ipa} % fonts to the regular monospaced variant of the New % Computer Modern family. % \begin{macrocode} \keys_define:nn { lngx_keys } { ipa~ newcm~ regular~ mono .meta:n = { ipa~ extra~ features = { Renderer = {HarfBuzz}, StylisticSet = {05} }, ipa~ sans~ extra~ features = { Renderer = {HarfBuzz}, StylisticSet = {05} }, ipa~ mono~ extra~ features = { Renderer = {HarfBuzz}, StylisticSet = {05} }, ipa~ main~ font = { NewCMMono10-Regular.otf }, ipa~ sans~ font = { NewCMSans10-Regular.otf }, ipa~ mono~ font = { NewCMMono10-Regular.otf } } } % \end{macrocode} % \end{macro} % We set the |ipa newcm| key by default. % \begin{macrocode} \lngx_set_keys:n {ipa~ newcm} % \end{macrocode} % \begin{macro}{^^A % \lngx_set_main_ipa_font:nn,\lngx_main_ipa:,^^A % lngx_ipa_rm_nfss,^^A % \lngx_set_sans_ipa_font:nn,\lngx_sans_ipa:,^^A % lngx_ipa_sf_nfss,^^A % \lngx_set_mono_ipa_font:nn,\lngx_mono_ipa:,^^A % lngx_ipa_tt_nfss^^A % } % Here, I develop font-setting commands for \textsc{ipa}. % These commands are set with |\setfontfamily|, so they % keep overriding the definitions of the same command names. % These commands set \textsc{nfss} families that we use % later for setting the \textsc{ipa} fonts. These functions % and \textsc{nfss} families are public, but manipulating % them has effects (mostly desired) at several other places, % so use them with caution. % \begin{macrocode} \cs_new_protected:Npn \lngx_set_main_ipa_font:nn #1#2 { \setfontfamily \lngx_main_ipa: [ #1, NFSSFamily = { lngx_ipa_rm_nfss } ] { #2 } } \cs_new_protected:Npn \lngx_set_sans_ipa_font:nn #1#2 { \setfontfamily \lngx_sans_ipa: [ #1, NFSSFamily = { lngx_ipa_sf_nfss } ] { #2 } } \cs_new_protected:Npn \lngx_set_mono_ipa_font:nn #1#2 { \setfontfamily \lngx_mono_ipa: [ #1, NFSSFamily = { lngx_ipa_tt_nfss } ] { #2 } } \cs_generate_variant:Nn \lngx_set_main_ipa_font:nn { VV } \cs_generate_variant:Nn \lngx_set_sans_ipa_font:nn { VV } \cs_generate_variant:Nn \lngx_set_mono_ipa_font:nn { VV } % \end{macrocode} % \end{macro} % \begin{macro}{lngx_ipa} % Here, I create a \enquote{super font family} with % |\lngx_super_font_family:nn|, a macro provided by % \lngxnfsslogo. Please see the documentation of that % package for more information. Note that |lngx_ipa| is a % super family responsible for all the \textsc{ipa}-related % functions of the package. It is associated with the % \textsc{nfss} families defined just now for the % \textsc{ipa}. % \begin{macrocode} \lngx_super_font_family:nn { lngx_ipa } { rm = { lngx_ipa_rm_nfss }, sf = { lngx_ipa_sf_nfss }, tt = { lngx_ipa_tt_nfss } } % \end{macrocode} % \end{macro} % \begin{macro}{\lngxipa,\lngx_ipa:} % I use |\lngx_softer_super_font_family:n| provided by % \lngxnfsslogo for defining this switch to the % \textsc{ipa}. % \begin{macrocode} \cs_new_protected:Npn \lngx_ipa: { \lngx_softer_super_font_family:n { lngx_ipa } } \cs_gset_eq:NN \lngxipa \lngx_ipa: % \end{macrocode} % \end{macro} % Now, I have used the exact same method that I described in % the implementation of \lngxfontslogo\ for setting the size % variants. This is done with lazy evaluation, just before % |\begin{document}|. % \begin{macrocode} \clist_map_inline:nn { main, sans, mono } { \cs_new_protected:cpn { lngx_build_ #1 _ipa_font_features: } { \prop_map_inline:cn { g__lngx_ipa_ #1 _fonts_prop } { \tl_gput_right:cn { g__lngx_ipa_ #1 _font_features_tl } { ####2 } } } } \hook_gput_code:nnn { begindocument / before } { . } { \lngx_build_main_ipa_font_features: \lngx_set_main_ipa_font:VV \g__lngx_ipa_main_font_features_tl \g__lngx_ipa_main_font_tl \lngx_build_sans_ipa_font_features: \lngx_set_sans_ipa_font:VV \g__lngx_ipa_sans_font_features_tl \g__lngx_ipa_sans_font_tl \lngx_build_mono_ipa_font_features: \lngx_set_mono_ipa_font:VV \g__lngx_ipa_mono_font_features_tl \g__lngx_ipa_mono_font_tl } % % \end{macrocode} % \newpage % \lngximplementation{languages} % \begin{macrocode} %<*lang> \ProvidesExplPackage{linguistix-languages} {2026-02-02} {v0.8} {% An assistant package for automatically loading fonts and more settings for languages.% } % \end{macrocode} % \lngxbaselogo\ is loaded (if not already done) for the % key-value parser. % \begin{macrocode} \IfPackageLoadedF { linguistix-base } { \RequirePackage { linguistix-base } } % \end{macrocode} % The \textsf{babel} package is loaded with |provide*=*| % option as it mandates the use of modern mechanism. % \begin{macrocode} \IfPackageLoadedF { babel } { \RequirePackage [ provide * = * ] { babel } } % \end{macrocode} % \begin{macro}{\g_lngx_main_language_tl} % I declare a |tl| that I will use for storing the main % language. It is publicly available. % \begin{macrocode} \tl_new:N \g_lngx_main_language_tl % \end{macrocode} % \end{macro} % \begin{macro}{\g_lngx_languages_clist} % I declare a |clist| that I will use for storing languages. % It is publicly available. % \begin{macrocode} \clist_new:N \g_lngx_languages_clist % \end{macrocode} % \end{macro} % \begin{macro}{\lngx_languages:nn,\providelanguage} % I develop a wrapper macro with a |:VV| variant. % \begin{macrocode} \cs_new_protected:Npn \lngx_languages:nn #1#2 { \babelprovide [ #1 ] { #2 } } \cs_generate_variant:Nn \lngx_languages:nn { VV } \cs_gset_eq:NN \providelanguage \lngx_languages:nn % \end{macrocode} % \end{macro} % The \pkg{babel} package produces an \enquote{info} message % if the fonts are not set with |\babelfont|. Mostly they % aren’t set with this mechanism, so this warning is % inevitable in default situations. Imagine loading % \lngxfontslogo\ first and then loading this package. The % fonts are already set with |\setmainfont| and friends. % Thus we will be prompted with this warning always. In % order to avoid that, I renew the wrapper functions around % |\setmainfont| to |\babelfont|. Note that this only % affects the usage when \lngxfontslogo\ is loaded. If you % use \lngxlanguageslogo\ and then use |\setmainfont|-like % commands, you will get |babel|’s warning and I have no % intention to suppress that behaviour. % \begin{macrocode} \IfPackageLoadedTF { linguistix-fonts } { \cs_gset_protected:Npn \lngx_set_main_font:nn #1#2 { \babelfont { rm } [ #1 ] { #2 } } \cs_gset_protected:Npn \lngx_set_sans_font:nn #1#2 { \babelfont { sf } [ #1 ] { #2 } } \cs_gset_protected:Npn \lngx_set_mono_font:nn #1#2 { \babelfont { tt } [ #1 ] { #2 } } } { \cs_new_protected:Npn \lngx_set_main_font:nn #1#2 { \babelfont { rm } [ #1 ] { #2 } } \cs_new_protected:Npn \lngx_set_sans_font:nn #1#2 { \babelfont { sf } [ #1 ] { #2 } } \cs_new_protected:Npn \lngx_set_mono_font:nn #1#2 { \babelfont { tt } [ #1 ] { #2 } } } % \end{macrocode} % \begin{macro}{^^A % \lngx_other_main_font:nnn,^^A % \lngx_other_sans_font:nnn,^^A % \lngx_other_mono_font:nnn % } % The following macros set fonts for other languages using % the |\babelfont| command. % \begin{macrocode} \cs_gset_protected:Npn \lngx_other_main_font:nnn #1#2#3 { \babelfont [ #1 ] { rm } [ #2 ] { #3 } } \cs_gset_protected:Npn \lngx_other_sans_font:nnn #1#2#3 { \babelfont [ #1 ] { sf } [ #2 ] { #3 } } \cs_gset_protected:Npn \lngx_other_mono_font:nnn #1#2#3 { \babelfont [ #1 ] { tt } [ #2 ] { #3 } } \cs_generate_variant:Nn \lngx_other_main_font:nnn { nee } \cs_generate_variant:Nn \lngx_other_sans_font:nnn { nee } \cs_generate_variant:Nn \lngx_other_mono_font:nnn { nee } % \end{macrocode} % \end{macro} % \begin{macro}{\lngx_load_languages:n,\loadlanguages} % I provide a simple macro that only does the job of loading % languages, both in \LaTeX3 style, as well as the in the % plain style. % \begin{macrocode} \cs_new_protected:Npn \lngx_load_languages:n #1 { \lngx_set_keys:n { languages = { #1 } } } \cs_gset_eq:NN \loadlanguages \lngx_load_languages:n % \end{macrocode} % \end{macro} % I equate the \cs{arabic} command to a new command I want % to provide. This is done in order to get control over the % default \LaTeX\ counters. The command is manipulated when % plugs are activated. % \begin{macro}{\lngx_counter:n} % \begin{macrocode} \cs_gset_eq:NN \lngx_counter:n \arabic % \end{macrocode} % \end{macro} % Now all the default counters are changed from \cs{arabic} % to \cs{lngx_counter:n}. % \begin{macrocode} \cs_set:Npn \thechapter { \lngx_counter:n { chapter } } \cs_set:Npn \thesection { \lngx_counter:n { section } } \cs_set:Npn \thesubsection { \lngx_counter:n { subsection } } \cs_set:Npn \thesubsubsection { \lngx_counter:n { subsubsection } } \cs_set:Npn \theparagraph { \lngx_counter:n { section } } \cs_set:Npn \thesubparagraph { \lngx_counter:n { section } } \cs_set:Npn \thepage { \lngx_counter:n { page } } \cs_set:Npn \thefigure { \lngx_counter:n { figure } } \cs_set:Npn \thetable { \lngx_counter:n { table } } \cs_set:Npn \thefootnote { \lngx_counter:n { footnote } } \cs_set:Npn \thempfootnote { \lngx_counter:n { mpfootnote } } \cs_set:Npn \theequation { \lngx_counter:n { equation } } % \end{macrocode} % Here, I define the socket |lngx/native-numbering|. % \begin{macrocode} \socket_new:nn { lngx / native-numbering } { 0 } % \end{macrocode} % \begin{macro}{strict} % This plug sets the numbering strictly to the main % language. If used, the function \cs{lngx_counter:n} is % changed to the respective |\xxxxcounter| command (where % |xxxx| stands for the main language of the document). % \begin{macrocode} \socket_new_plug:nnn { lngx / native-numbering } { strict } { \cs_gset_eq:Nc \lngx_counter:n { \tl_use:N \g_lngx_main_language_tl counter } } % \end{macrocode} % \end{macro} % \begin{macro}{logical} % Here, I define the |logical| plug for % |lngx/native-numbering|. The mechanism is pretty similar % as the one used for |strict|, but here I don’t renew it to % the main language counter, but instead I use the % |\localecounter| command provided by the \pkg{babel} % package. The counters are then printed contextually (and % \TeX-logically). % \begin{macrocode} \socket_new_plug:nnn { lngx / native-numbering } { logical } { \cs_gset_protected:Npn \lngx_counter:n ##1 { \localecounter { digits } { ##1 } } } % \end{macrocode} % \end{macro} % \begin{macro}{off} % If the |off| plug is selected, then native digits are not % needed. Thus the \cs{lngx_counter:n} is set to the % unmodified \cs{arabic} again. % \begin{macrocode} \socket_new_plug:nnn { lngx / native-numbering} { off } { \cs_gset_eq:NN \lngx_counter:n \arabic } % \end{macrocode} % \end{macro} % \begin{macro}{native numbering} % The three choices for the |native numbering| key, i.e., % |strict|, |logical| and |off| are defined here. All of % them activate the plugs of their name with the % |lngx/native-numbering| socket. % \begin{macrocode} \cs_generate_variant:Nn \socket_assign_plug:nn { ne } \keys_define:nn { lngx_keys } { native~ numbering .choices:nn = { strict,logical,off } { \socket_assign_plug:ne { lngx / native-numbering } { \str_use:N \l_keys_choice_str } \socket_use:n { lngx / native-numbering } }, % \end{macrocode} % Similarly, we set the default value to on. % \begin{macrocode} native~ numbering .default:n = { strict } } % \end{macrocode} % \end{macro} % \begin{macro}{\lngx_misc_reset:} % Despite having sufficient control with the two plugs, % there are some additional settings required by some % languages that are often not needed by most others. E.g., % Marathi renews the way enumerated lists are printed and % that is supposed to be renewed when the language is % changed. I provide a shorthand to be used for resetting % such settings. It can be used in the packages of languages % that don’t need special settings. % \begin{macrocode} \cs_new_protected:Npn \lngx_misc_reset: { \cs_set:Npn \theenumii { \alph { enumii } } \cs_set:Npn \labelenumii { ( \theenumii ) } \cs_set:Npn \theenumiii { \roman { enumiii } } \cs_set:Npn \labelenumiii { \theenumiii . } \cs_set:Npn \theenumiv { \Alph { enumiv } } \cs_set:Npn \labelenumiv { \theenumiv . } \IfPackageLoadedT { expex } { \lingset { labeltype = alpha } } \cs_gset_eq:NN \emph \textit } % \end{macrocode} % \end{macro} % Here, I write a message to be issued when user loads an % unsupported language. % \begin{macrocode} \msg_new:nnn { linguistix-languages } { no_support } { ‘#1’~ is~ not~ supported.\\ If~ you~ want~ it~ to~ be~ supported,~ please~ report~ to~ the~ maintainers. } % \end{macrocode} % \begin{macro}{languages} % I use the |.code:n| type for developing the |languages| % key. % \begin{macrocode} \keys_define:nn { lngx_keys } { languages .code:n = { % \end{macrocode} % I pass the argument of this key to a global |clist|. It is % stored for public use. % \begin{macrocode} \clist_gset:Nn \g_lngx_languages_clist { #1 } % \end{macrocode} % Since this is a public |clist| for accessing the names of % the languages, I copy it to a temporary one so that the % items of public interest are not lost during the % operations. % \begin{macrocode} \clist_set_eq:NN \l_tmpa_clist \g_lngx_languages_clist % \end{macrocode} % I check if the |clist| is empty or not. If it is empty, % that means the user used the key without a value. In that % case, \textsf{babel} already loads an % \enquote{info}-message saying that no language is loaded. % So we ignore the branch and silently move to the false % branch. % \begin{macrocode} \clist_if_empty:NF \l_tmpa_clist { % \end{macrocode} % In the false branch, I pop out the first element from the % clist to |\l_tmpa_tl|. This is the first language passed % by the user. In \lngxlanguageslogo, I assume that it is % intended to be the first language. It is important to pop % the element out because the settings used for the main % language are different than the ones used for other % languages. % \begin{macrocode} \clist_pop:NN \l_tmpa_clist \l_tmpa_tl % \end{macrocode} % Since this |tl| stores the language that is going to be % the main one, I equate it to another public |tl| that I % will be using later in language files. % \begin{macrocode} \tl_set_eq:NN \g_lngx_main_language_tl \l_tmpa_tl % \end{macrocode} % In |\l_tmpb_tl|, I save the options that need to go with % the language stored in |\l_tmpa_tl|. The package used to % have |onchar| option loaded conditionally with Lua\LaTeX, % but to avoid potential clashes, now it has moved to the % individual package files of languages. Now I directly load % the |main| option which makes the concerned language the % \enquote{main} language of the document. % \begin{macrocode} \tl_set:Ne \l_tmpb_tl { main, % \end{macrocode} % To load the data from |ini| files, I use the |import| % parameter. % \begin{macrocode} import } % \end{macrocode} % I use the |\babelprovide| wrapper we saw earlier with the % values of the first language. % \begin{macrocode} \lngx_languages:VV \l_tmpb_tl \l_tmpa_tl % \end{macrocode} % I scan if the package for this language is available. If % it is, it is loaded. % \begin{macrocode} \file_if_exist:nTF { linguistix - \l_tmpa_tl . sty } { \exp_args:Ne \RequirePackage { linguistix - \l_tmpa_tl } } { % \end{macrocode} % If it is not, I issue the |no_ldf| warning message. It % takes one argument that is the name of the language. It is % extracted using the |V| argument type. % \begin{macrocode} \msg_warning:nnV { linguistix-languages } { no_support } \l_tmpa_tl } % \end{macrocode} % The temporary |tl|s are cleared. % \begin{macrocode} \tl_clear:N \l_tmpa_tl \tl_clear:N \l_tmpb_tl % \end{macrocode} % I again check if the |clist| is empty. If it is, it means % the user is typesetting a monolingual document as they % don’t need any other language than the \enquote{main} one. % \begin{macrocode} \clist_if_empty:NF \l_tmpa_clist { % \end{macrocode} % Now I have to repeat the same actions for all the pending % languages. I do it with |\clist_map_inline:Nn|. % \begin{macrocode} \clist_map_inline:Nn \l_tmpa_clist { \clist_pop:NN \l_tmpa_clist \l_tmpa_tl \tl_set:Ne \l_tmpb_tl { import } \lngx_languages:VV \l_tmpb_tl \l_tmpa_tl \file_if_exist:nTF { linguistix - \l_tmpa_tl . sty } { \exp_args:Ne \RequirePackage { linguistix - \l_tmpa_tl } } { \msg_warning:nnV { linguistix-languages } { no_ldf } \l_tmpa_tl } \tl_clear:N \l_tmpa_tl \tl_clear:N \l_tmpb_tl } } } } } % % \end{macrocode} % \end{macro} % \newpage % \lngximplementation{logos} % \begin{macrocode} %<*logos> \ProvidesExplPackage{linguistix-logos} {2026-02-02} {v0.8} {% Logos of the ‘LinguisTiX’ bundle.% } % \end{macrocode} % The \pkg{fontspec} package (if not already loaded). % \begin{macrocode} \IfPackageLoadedF { fontspec } { \RequirePackage { fontspec } } % \end{macrocode} % \begin{macro}{\lngx_logo_font:} % This is a command that switches to the New Computer Modern % Uncial font family. % \begin{macrocode} \newfontfamily \lngx_logo_font: [ UprightFont = { NewCMUncial10-Book.otf }, UprightFeatures = { SizeFeatures = { { Size = {-8}, Font = {NewCMUncial08-Book.otf} }, { Size = {8-}, Font = {NewCMUncial10-Book.otf} }, } }, BoldFont = { NewCMUncial10-Bold.otf }, BoldFeatures = { SizeFeatures = { { Size = {-8}, Font = {NewCMUncial08-Bold.otf} }, { Size = {8-}, Font = {NewCMUncial10-Bold.otf} }, } } ]{ NewCMUncial10-Book.otf } % \end{macrocode} % \end{macro} % \begin{macro}{lngx_purple_color} % The following defines the |lngx_purple_color|. % \begin{macrocode} \color_set:nn { lngx_purple_color } { blue ! 50 ! red } % \end{macrocode} % \end{macro} % \begin{macro}{\lngxlogo} % Here, I define the commands for printing various logos. % \begin{macrocode} \NewDocumentCommand \lngxlogo { O{} } {% \group_begin: \lngx_logo_font: LinguisTi \color_group_begin: \color_select:n { lngx_purple_color } X \color_group_end: \IfBlankF { #1 } { - #1 } \group_end: } % \end{macrocode} % \end{macro} % Since we need expandable commands, I use the non-protected % function, |\cs_new:Npn| for defining them. % \begin{macrocode} \cs_new:Npn \lngxpkg { \IfPackageLoadedTF { hyperref } { \texorpdfstring { \lngxlogo } { LinguisTiX } } { \lngxlogo } } % \end{macrocode} % Here, I define all the logos with a |clist|. The package % names are stored in the |clist| and then used at % appropriate positions. % \begin{macrocode} \clist_map_inline:nn { base,examples,fixpex,fonts,ipa,languages,logos,nfss, marathi,british,american,english,greek,malayalam,glossing, leipzig } { % \end{macrocode} % |#1| is substituted with the package name. First, for the % command-name itself, then as the optional argument of % |\lngxlogo| and then in the \textsc{pdf}-string. % \begin{macrocode} \cs_new:cpn { lngx #1 logo } { \texorpdfstring { \lngxlogo [ #1 ] } { LinguisTiX - #1 } } } % % \end{macrocode} % \lngximplementation{nfss} % \begin{macrocode} %<*nfss> \ProvidesExplPackage{linguistix-nfss} {2026-02-02} {v0.8} {% An extension to the core NFSS commands from the ‘LinguisTiX’ bundle.% } % \end{macrocode} % I need a few temporary |tl|s. I declare them here. As % noted by the use of |__|, these are package-internal % |tl|s. Even though I don’t have any intention to change % them, these are better not touched by the users. % \begin{macrocode} \tl_new:N \l__lngx_normalfont_tmp_tl \tl_new:N \l__lngx_selectfont_tmp_tl \tl_new:N \l__lngx_family_tmp_tl \tl_new:N \l__lngx_nfss_tmp_tl % \end{macrocode} % These |tl|s are required for saving some values that are % accessed later by the package as well as by the users. % \begin{macrocode} \tl_new:N \l_lngx_current_encoding_tl \tl_new:N \l_lngx_current_meta_family_tl \tl_new:N \l_lngx_current_super_family_tl \tl_new:N \l_lngx_current_series_tl \tl_new:N \l_lngx_current_shape_tl % \end{macrocode} % \begin{macro}{^^A % \c_lngx_default_rmdefault_tl,^^A % \c_lngx_default_sfdefault_tl,^^A % \c_lngx_default_ttdefault_tl % } % Here, I start the |begindocument/end| hook. After the % document has started, a lot of initialisation can be % assumed to have happened. I set some publicly available % |tl|s here. % \begin{macrocode} \hook_gput_code:nnn { begindocument / end } { . } { \tl_const:Ne \c_lngx_default_rmdefault_tl { \rmdefault } \tl_const:Ne \c_lngx_default_sfdefault_tl { \sfdefault } \tl_const:Ne \c_lngx_default_ttdefault_tl { \ttdefault } % \end{macrocode} % \end{macro} % \begin{macro}{^^A % \l_lngx_current_encoding_tl,^^A % \l_lngx_current_meta_family_tl,^^A % \l_lngx_current_super_family_tl,^^A % \l_lngx_current_series_tl,^^A % \l_lngx_current_shape_tl % } % First, I set the value |default| for the initial super % font family. % \begin{macrocode} \tl_set:Nn \l_lngx_current_super_family_tl { default } % \end{macrocode} % The current encoding is saved in the relevant |tl|. % \begin{macrocode} \tl_set:Ne \l_lngx_current_encoding_tl { \encodingdefault } % \end{macrocode} % When the package was first released, there was no public % interface for guessing the current meta family, but from % |ltnews42|, |\@currentmetafamily| became available. Thanks % Frank for pointing this out. % \begin{macrocode} \tl_set:Ne \l_lngx_current_meta_family_tl { \@currentmetafamily % new from ltnews42, thanks Frank! } % \end{macrocode} % Here, the series and shape |tl|s are set to their % defaults. % \begin{macrocode} \tl_set:Nn \l_lngx_current_series_tl { md } \tl_set:Nn \l_lngx_current_shape_tl { up } } % \end{macrocode} % \end{macro} % The |\selectfont| command overrides the encoding. I trick % the command by saving the encoding that was active before % |\selectfont| in a temporary |tl|. % \begin{macrocode} \hook_gput_code:nnn { cmd / selectfont / before } { . } { \tl_set:Ne \l__lngx_selectfont_tmp_tl { \f@encoding } } % \end{macrocode} % After the processing of |\selectfont|, I equate the % temporary |tl| with the one that the package is tracking. % This way, the effect of |\selectfont| remains unchanged, % but we still save the values that were there before using % it. Only encoding needs this special setting. Other % attributes aren’t reset by |\selectfont|. % \begin{macrocode} \hook_gput_code:nnn { cmd / selectfont / after } { . } { \tl_set_eq:NN \l_lngx_current_encoding_tl \l__lngx_selectfont_tmp_tl \tl_clear:N \l__lngx_selectfont_tmp_tl } % \end{macrocode} % Now, after each |\XXfamily| commands, I save the family % name in the respective |tl| for accessing later. All of % these commands too reset the encoding. I repeat my trick % for them too. % \begin{macrocode} \hook_gput_code:nnn { cmd / rmfamily / before } { . } { \tl_set:Nn \l_lngx_current_meta_family_tl { rm } \tl_set:Ne \l__lngx_family_tmp_tl { \f@encoding } } \hook_gput_code:nnn { cmd / rmfamily / after } { . } { \tl_set:Nn \l_lngx_current_meta_family_tl { rm } \tl_set_eq:NN \l_lngx_current_encoding_tl \l__lngx_family_tmp_tl \tl_clear:N \l__lngx_family_tmp_tl } \hook_gput_code:nnn { cmd / sffamily / before } { . } { \tl_set:Nn \l_lngx_current_meta_family_tl { sf } \tl_set:Ne \l__lngx_family_tmp_tl { \f@encoding } } \hook_gput_code:nnn { cmd / sffamily / after } { . } { \tl_set:Nn \l_lngx_current_meta_family_tl { sf } \tl_set_eq:NN \l_lngx_current_encoding_tl \l__lngx_family_tmp_tl \tl_clear:N \l__lngx_family_tmp_tl } \hook_gput_code:nnn { cmd / ttfamily / before } { . } { \tl_set:Nn \l_lngx_current_meta_family_tl { tt } \tl_set:Ne \l__lngx_family_tmp_tl { \f@encoding } } \hook_gput_code:nnn { cmd / ttfamily / after } { . } { \tl_set:Nn \l_lngx_current_meta_family_tl { tt } \tl_set_eq:NN \l_lngx_current_encoding_tl \l__lngx_family_tmp_tl \tl_clear:N \l__lngx_family_tmp_tl } % \end{macrocode} % After the series commands, I save the series name in the % |tl|. Note that, I don’t use the traditional \LaTeX\ % labels |m|, |bx| etc. Using, |md| and |bx| is more % intuitive, plus they also can be used in the argument of % |\use:c| directly. % \begin{macrocode} \hook_gput_code:nnn { cmd / mdseries / after } { . } { \tl_set:Nn \l_lngx_current_series_tl { md } } \hook_gput_code:nnn { cmd / bfseries / after } { . } { \tl_set:Nn \l_lngx_current_series_tl { bf } } % \end{macrocode} % For shape related commands too, I save the names that are % more closer to their respective commands. % \begin{macrocode} \hook_gput_code:nnn { cmd / upshape / after } { . } { \tl_set:Nn \l_lngx_current_shape_tl { up } } \hook_gput_code:nnn { cmd / itshape / after } { . } { \tl_set:Nn \l_lngx_current_shape_tl { it } } \hook_gput_code:nnn { cmd / scshape / after } { . } { \tl_set:Nn \l_lngx_current_shape_tl { sc } } \hook_gput_code:nnn { cmd / sscshape / after } { . } { \tl_set:Nn \l_lngx_current_shape_tl { ssc } } \hook_gput_code:nnn { cmd / slshape / after } { . } { \tl_set:Nn \l_lngx_current_shape_tl { sl } } \hook_gput_code:nnn { cmd / swshape / after } { . } { \tl_set:Nn \l_lngx_current_shape_tl { sw } } \hook_gput_code:nnn { cmd / ulcshape / after } { . } { \tl_set:Nn \l_lngx_current_shape_tl { ulc } } % \end{macrocode} % % \begin{macro}[pTF]{\lngx_if_encoding:n} % I provide a conditional for checking the current encoding % with the given argument. % \begin{macrocode} \prg_new_conditional:Nnn \lngx_if_encoding:n { p, T, F, TF } { \tl_if_eq:NnTF \l_lngx_current_encoding_tl { #1 } { \prg_return_true: } { \prg_return_false: } } % \end{macrocode} % \end{macro} % \begin{macro}{\IfEncodingTF,\IfEncodingT,\IfEncodingF} % For non-\LaTeX3 contexts, these simpler alternatives are % provided. % \begin{macrocode} \cs_new_eq:NN \IfEncodingTF \lngx_if_encoding:nTF \cs_new_eq:NN \IfEncodingT \lngx_if_encoding:nT \cs_new_eq:NN \IfEncodingF \lngx_if_encoding:nF % \end{macrocode} % \end{macro} % \begin{macro}[pTF]{\lngx_if_meta_family:n} % A conditional for checking the meta family with the given % argument. % \begin{macrocode} \prg_new_conditional:Nnn \lngx_if_meta_family:n { p, T, F, TF } { \tl_if_eq:NnTF \l_lngx_current_meta_family_tl { #1 } { \prg_return_true: } { \prg_return_false: } } % \end{macrocode} % \end{macro} % \begin{macro}{^^A % \IfMetaFamilyTF,^^A % \IfMetaFamilyT,^^A % \IfMetaFamilyF % } % User-facing conditionals for meta family. % \begin{macrocode} \cs_new_eq:NN \IfMetaFamilyTF \lngx_if_meta_family:nTF \cs_new_eq:NN \IfMetaFamilyT \lngx_if_meta_family:nT \cs_new_eq:NN \IfMetaFamilyF \lngx_if_meta_family:nF % \end{macrocode} % \end{macro} % \begin{macro}[pTF]{\lngx_if_super_family:n} % A conditional for checking the super family with the given % argument. % \begin{macrocode} \prg_new_conditional:Nnn \lngx_if_super_family:n { p, T, F, TF } { \tl_if_eq:NnTF \l_lngx_current_super_family_tl { #1 } { \prg_return_true: } { \prg_return_false: } } % \end{macrocode} % \end{macro} % \begin{macro}{^^A % \IfSuperFamilyTF,^^A % \IfSuperFamilyT,^^A % \IfSuperFamilyF % } % User-facing conditionals for super family. % \begin{macrocode} \cs_new_eq:NN \IfSuperFamilyTF \lngx_if_super_family:nTF \cs_new_eq:NN \IfSuperFamilyT \lngx_if_super_family:nT \cs_new_eq:NN \IfSuperFamilyF \lngx_if_super_family:nF % \end{macrocode} % \end{macro} % \begin{macro}[pTF]{\lngx_if_series:n} % A conditional for checking the current series with the % given argument. % \begin{macrocode} \prg_new_conditional:Nnn \lngx_if_series:n { p, T, F, TF } { \tl_if_eq:NnTF \l_lngx_current_series_tl { #1 } { \prg_return_true: } { \prg_return_false: } } % \end{macrocode} % \end{macro} % \begin{macro}{\IfSeriesTF,\IfSeriesT,\IfSeriesF} % Its user-side macros. % \begin{macrocode} \cs_new_eq:NN \IfSeriesTF \lngx_if_series:nTF \cs_new_eq:NN \IfSeriesT \lngx_if_series:nT \cs_new_eq:NN \IfSeriesF \lngx_if_series:nF % \end{macrocode} % \end{macro} % \begin{macro}[pTF]{\lngx_if_shape:n} % A conditional for checking the current shape with the % current argument. % \begin{macrocode} \prg_new_conditional:Nnn \lngx_if_shape:n { p, T, F, TF } { \tl_if_eq:NnTF \l_lngx_current_shape_tl { #1 } { \prg_return_true: } { \prg_return_false: } } % \end{macrocode} % \end{macro} % \begin{macro}{\IfShapeTF,\IfShapeT,\IfShapeF} % User-side macros for the same. % \begin{macrocode} \cs_new_eq:NN \IfShapeTF \lngx_if_shape:nTF \cs_new_eq:NN \IfShapeT \lngx_if_shape:nT \cs_new_eq:NN \IfShapeF \lngx_if_shape:nF % \end{macrocode} % \end{macro} % Now I will use the |\clist_map_inline:nn| technique for % generating multiple conditionals of the same pattern. For % that, I need a |cnn| variant of |\prg_new_conditional:Nnn| % that I create with the following. % \begin{macrocode} \cs_generate_variant:Nn \prg_new_conditional:Nnn { cnn } % \end{macrocode} % % \begin{macro}[pTF]{^^A % \lngx_if_meta_family_rm:,\lngx_if_meta_family_sf:,^^A % \lngx_if_meta_family_tt: % } % These are separate conditionals for |rm|, |sf| and |tt| % families. They don’t require arguments. No user side % commands are provided for these. % \begin{macrocode} \clist_map_inline:nn { rm, sf, tt } { \prg_new_conditional:cnn { lngx_if_meta_family_ #1 : } { p, T, F, TF } { \tl_if_eq:NnTF \l_lngx_current_meta_family_tl { #1 } { \prg_return_true: } { \prg_return_false: } } } % \end{macrocode} % \end{macro} % \begin{macro}[pTF]{^^A % \lngx_if_series_md:,\lngx_if_series_bf: % } % Separate conditionals for both the series. % \begin{macrocode} \clist_map_inline:nn { md, bf } { \prg_new_conditional:cnn { lngx_if_series_ #1 : } { p, T, F, TF } { \tl_if_eq:NnTF \l_lngx_current_series_tl { #1 } { \prg_return_true: } { \prg_return_false: } } } % \end{macrocode} % \end{macro} % \begin{macro}[pTF]{^^A % \lngx_if_shape_up:,\lngx_if_shape_it:,^^A % \lngx_if_shape_sc:,\lngx_if_shape_ssc:,^^A % \lngx_if_shape_sl:,\lngx_if_shape_sw:,^^A % \lngx_if_shape_ulc: % } % Separate conditionals for all the shapes. % \begin{macrocode} \clist_map_inline:nn { up, it, sc, ssc, sl, sw, ulc } { \prg_new_conditional:cnn { lngx_if_shape_ #1 : } { p, T, F, TF } { \tl_if_eq:NnTF \l_lngx_current_shape_tl { #1 } { \prg_return_true: } { \prg_return_false: } } } % \end{macrocode} % \end{macro} % These keys are used in the argument of % |\lngx_super_font_family:nn|. This is why they are % separated from the set |lngx_keys|. We create new |tl|s % using these keys that save the |rm|, |sf| and |tt| % defaults of the new super font family. % |\l__lngx_nfss_tmp_tl| is defined by the command that % creates the super font family. % \begin{macrocode} \clist_map_inline:nn { rm, sf, tt } { \keys_define:nn { lngx_nfss } { #1 .code:n = { \tl_gclear_new:c { g_lngx_ \l__lngx_nfss_tmp_tl _ #1 default _tl } \tl_gset:cn { g_lngx_ \l__lngx_nfss_tmp_tl _ #1 default _tl } { ##1 } } } } % \end{macrocode} % \begin{macro}{^^A % \lngx_super_font_family:nn,\superfontfamily^^A % } % I first set the temporary |tl| with the name of the super % font family retrieved from the first argument. % \begin{macrocode} \cs_new_protected:Npn \lngx_super_font_family:nn #1#2 { \tl_set:Ne \l__lngx_nfss_tmp_tl { #1 } % \end{macrocode} % Now, I pass the second argument to the key-set I just % defined. The temporary |tl| is cleared. This function % comes with a user-side macro. % \begin{macrocode} \keys_set:nn { lngx_nfss } { #2 } \tl_clear:N \l__lngx_nfss_tmp_tl } \cs_gset_eq:NN \superfontfamily \lngx_super_font_family:nn % \end{macrocode} % \end{macro} % \begin{macro}{^^A % \lngx_soft_super_font_family:nn,\softsuperfontfamily % } % I set the |tl| that saves the current font family to the % first argument. % \begin{macrocode} \cs_new_protected:Npn \lngx_soft_super_font_family:nn #1#2 { \tl_set:Ne \l_lngx_current_super_family_tl { #1 } % \end{macrocode} % I first check if the |tl|s for rm, sf and tt are empty or % not. Only if they are not, I use their content in the % respective |\XXdefault|. This makes the use of all the % keys optional. Only the keys that the user has used are % processed here. % \begin{macrocode} \clist_map_inline:nn { rm, sf, tt } { \tl_if_empty:cF { g_lngx_ #1 _ ##1 default_tl } { \cs_set:cpe { ##1 default } { \tl_use:c { g_lngx_ #1 _ ##1 default _tl } } } } % \end{macrocode} % After setting the |\XXdefault|, I use the |\normalfont| to % initialise the super font family. % \begin{macrocode} \normalfont % \end{macrocode} % Now all the aspects are reset. But, we have them saved in % our |tl|s. So now depending on the attributes that the % user wants to retrieve, I call those attributes again. The % second argument is (expected to be) a comma-separated list % of all such attributes. Thus, we change the super font % family, but retain the already active attributes. This % command has a user-facing macro. % \begin{macrocode} \clist_map_inline:nn { #2 } { \str_case:nn { ##1 } { { encoding } { \exp_args:NV \fontencoding \l_lngx_current_encoding_tl } { family } { \use:c { \l_lngx_current_meta_family_tl family } \exp_args:NV \fontencoding \l_lngx_current_encoding_tl \selectfont } { series } { \use:c { \l_lngx_current_series_tl series } } { shape } { \use:c { \l_lngx_current_shape_tl shape } } } } } \cs_gset_eq:NN \softsuperfontfamily \lngx_soft_super_font_family:nn % \end{macrocode} % \end{macro} % \begin{macro}{^^A % \lngx_softer_super_font_family:n,\softersuperfontfamily % } % This function excludes the encoding and resets all the % other attributes. It comes with a user-side macro. % \begin{macrocode} \cs_new_protected:Npn \lngx_softer_super_font_family:n #1 { \lngx_soft_super_font_family:nn { #1 } { family, series, shape } } \cs_gset_eq:NN \softersuperfontfamily \lngx_softer_super_font_family:n % \end{macrocode} % \end{macro} % \begin{macro}{^^A % \lngx_softest_super_font_family:n,\softestsuperfontfamily % } % This function resets all the attributes. It is available % as a user-side macro. % \begin{macrocode} \cs_new_protected:Npn \lngx_softest_super_font_family:n #1 { \lngx_soft_super_font_family:nn { #1 } { encoding, family, series, shape } } \cs_gset_eq:NN \softestsuperfontfamily \lngx_softest_super_font_family:n % \end{macrocode} % \end{macro} % \begin{macro}{^^A % \lngx_soft_normal_font:n,\softnormalfont % } % Following the same logic, I now provide the command for % resetting to the default super family, but retaining the % active attributes. I provide a user-side macro for this. % \begin{macrocode} \cs_new_protected:Npn \lngx_soft_normal_font:n #1 { \tl_set:Ne \l_lngx_current_super_family_tl { default } \clist_map_inline:nn { rm, sf, tt } { \cs_set:cpe { ##1 default } { \tl_use:c { c_lngx_default_ ##1 default _tl } } } \normalfont \clist_map_inline:nn { #1 } { \str_case:nn { ##1 } { { encoding } { \exp_args:NV \fontencoding \l_lngx_current_encoding_tl } { family } { \use:c { \l_lngx_current_meta_family_tl family } \exp_args:NV \fontencoding \l_lngx_current_encoding_tl \selectfont } { series } { \use:c { \l_lngx_current_series_tl series } } { shape } { \use:c { \l_lngx_current_shape_tl shape } } } } } \cs_gset_eq:NN \softnormalfont \lngx_soft_normal_font:n % \end{macrocode} % \end{macro} % \begin{macro}{^^A % \lngx_softer_normal_font:,\softernormalfont % } % This is a parallel to the \enquote{softer} super family % command for the default super family. % \begin{macrocode} \cs_new_protected:Npn \lngx_softer_normal_font: { \lngx_soft_normal_font:n { family, series, shape } } \cs_gset_eq:NN \softernormalfont \lngx_softer_normal_font: % \end{macrocode} % \end{macro} % \begin{macro}{^^A % \lngx_softest_normal_font:,\softestnormalfont % } % This is a parallel to the \enquote{softest} super family % command for the default super family. % \begin{macrocode} \cs_new_protected:Npn \lngx_softest_normal_font: { \lngx_soft_normal_font:n { encoding, family, series, shape } } \cs_gset_eq:NN \softestnormalfont \lngx_softest_normal_font: % \end{macrocode} % \end{macro} % \begin{macro}[EXP]{^^A % \CurrentEncoding,\CurrentMetaFamily,\CurrentSeries,^^A % \CurrentShape % } % Lastly, we create the commands that print the current % values of the font attributes and end the package. % \begin{macrocode} \cs_new:Npn \CurrentEncoding { \tl_use:N \l_lngx_current_encoding_tl } \cs_new:Npn \CurrentMetaFamily { \tl_use:N \l_lngx_current_meta_family_tl } \cs_new:Npn \CurrentSuperFamily { \tl_use:N \l_lngx_current_super_family_tl } \cs_new:Npn \CurrentSeries { \tl_use:N \l_lngx_current_series_tl } \cs_new:Npn \CurrentShape { \tl_use:N \l_lngx_current_shape_tl } % % \end{macrocode} % \end{macro} % \end{implementation} % \newpage % \printbibliography % \newpage % \PrintIndex % \Finale