texlive[72607] Master/texmf-dist: babel (20oct24)

commits+karl at tug.org commits+karl at tug.org
Sun Oct 20 22:23:26 CEST 2024


Revision: 72607
          https://tug.org/svn/texlive?view=revision&revision=72607
Author:   karl
Date:     2024-10-20 22:23:26 +0200 (Sun, 20 Oct 2024)
Log Message:
-----------
babel (20oct24)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/latex/babel/README.md
    trunk/Master/texmf-dist/doc/latex/babel/babel-code.pdf
    trunk/Master/texmf-dist/doc/latex/babel/babel.pdf
    trunk/Master/texmf-dist/source/latex/babel/babel.dtx
    trunk/Master/texmf-dist/source/latex/babel/babel.ins
    trunk/Master/texmf-dist/source/latex/babel/bbcompat.dtx
    trunk/Master/texmf-dist/source/latex/babel/locale.zip
    trunk/Master/texmf-dist/tex/generic/babel/babel.def
    trunk/Master/texmf-dist/tex/generic/babel/babel.sty
    trunk/Master/texmf-dist/tex/generic/babel/hyphen.cfg
    trunk/Master/texmf-dist/tex/generic/babel/locale/el/babel-el-polyton.ini
    trunk/Master/texmf-dist/tex/generic/babel/locale/el/babel-el.ini
    trunk/Master/texmf-dist/tex/generic/babel/locale/el/babel-greek.tex
    trunk/Master/texmf-dist/tex/generic/babel/locale/el/babel-polytonicgreek.tex
    trunk/Master/texmf-dist/tex/generic/babel/locale/grc/babel-ancientgreek.tex
    trunk/Master/texmf-dist/tex/generic/babel/locale/grc/babel-grc.ini
    trunk/Master/texmf-dist/tex/generic/babel/locale/kmr/babel-kmr.ini
    trunk/Master/texmf-dist/tex/generic/babel/luababel.def
    trunk/Master/texmf-dist/tex/generic/babel/nil.ldf

Modified: trunk/Master/texmf-dist/doc/latex/babel/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/latex/babel/README.md	2024-10-20 20:22:44 UTC (rev 72606)
+++ trunk/Master/texmf-dist/doc/latex/babel/README.md	2024-10-20 20:23:26 UTC (rev 72607)
@@ -1,6 +1,6 @@
-## Babel 24.11
+## Babel 24.12
 
-2024-10-05
+2024-10-20
 
 `babel` is the multilingual framework to localize documents in
 LaTeX, LuaLaTeX, XeLaTeX. It manages culturally-determined
@@ -10,9 +10,9 @@
 
 The latest stable version is available on <https://ctan.org/pkg/babel>.
 
-Changes in version 24.11 are described in:
+Changes in version 24.12 are described in:
 
-https://latex3.github.io/babel/news/whats-new-in-babel-24.11.html
+https://latex3.github.io/babel/news/whats-new-in-babel-24.12.html
 
 Apart from the manual, you can find information on some aspects of babel at:
 
@@ -48,9 +48,14 @@
 
 ### Summary of latest changes
 ```
-24.11  2024-10-05
-       * Start a thorough review of the manual.
-       * (lua) Transform variables.
+24.12  2024-10-20
+       * Fixes: 
+         - Date sometimes missing with lazy loading.
+         - Wrong stigma in some Greek numerals.
+         - Wrong handling of ‘complex’ class options.
+       * More tools for automated document generation workflows:
+         - New LaTeX hook: presets.
+         - New command: \PassOptionsToLocale.
 ```
 
 ### Previous changes

Modified: trunk/Master/texmf-dist/doc/latex/babel/babel-code.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/babel/babel.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/source/latex/babel/babel.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/babel/babel.dtx	2024-10-20 20:22:44 UTC (rev 72606)
+++ trunk/Master/texmf-dist/source/latex/babel/babel.dtx	2024-10-20 20:23:26 UTC (rev 72607)
@@ -32,7 +32,9 @@
 %
 % \iffalse
 %<*filedriver>
-\ProvidesFile{babel.dtx}[2024/10/05 v24.11 The Babel package]
+\ProvidesFile{babel.dtx}%
+  [2024/10/20 v24.12
+   The multilingual framework for pdfLaTeX, LuaLaTeX and XeLaTeX] 
 \documentclass{ltxdoc}
 \GetFileInfo{babel.dtx}
 \usepackage{fontspec}
@@ -396,12 +398,11 @@
 (see |\babelfont| below). 
 
 \begin{example}
-  Here is a simple full example for “traditional” \TeX{} engines
-  (see below for \xetex{} and \luatex{}). The packages |fontenc| and
-  |inputenc| do not belong to \babel, but they are included in the
-  example because typically you will need them. It assumes UTF-8, the
-  default encoding:
-\setengine{pdftex}
+  Here is a simple full example for “traditional” \TeX{} engines (see
+  below for \xetex{} and \luatex{}). The package |fontenc| does not
+  belong to \babel, but it is included in the example because typically
+  you will need it. It assumes UTF-8, the default encoding:
+  \setengine{pdftex}
 \begin{verbatim}
 \documentclass{article}
 
@@ -506,9 +507,7 @@
 \end{troubleshooting}
 
 \begin{troubleshooting}
-Another typical error when using \babel{} is the
-  following:\footnote{In old versions the error read ``You haven't
-  loaded the language LANG yet''.}
+Another typical error when using \babel{} is the following:
 \trouble{Unknown language `LANG'}
 \begin{verbatim}
 ! Package babel Error: Unknown language `#1'. Either you have
@@ -546,11 +545,10 @@
 
 \begin{troubleshooting}
 \textit{You are loading directly a language style.}
-Loading directly |sty| files in \LaTeX{} (ie,
-    |\usepackage{<language>}|) was deprecated many years ago and you will get the
-    error:\footnote{In old versions the error read ``You have used an
-    old interface to call babel'', not very helpful.}
-  \trouble{You are loading directly a language style}
+Loading directly
+|sty| files in \LaTeX{} (ie, |\usepackage{<language>}|) was deprecated
+many years ago and you will get the error: \trouble{You are loading
+directly a language style}
 \begin{verbatim}
 ! Package babel Error: You are loading directly a language style.
 (babel)                This syntax is deprecated and you must use
@@ -778,6 +776,37 @@
 \end{verbatim}
 \end{note}
 
+\subsection{Multilingual documents: the ‘modern’ way}
+
+If lazy loading is not enough for your purposes, you can still tell
+which languages should be loaded as either class or package options.
+However, there are three options to set which method you want, which
+cover the most typical cases:
+\begin{itemize}
+\item |provide=*| is the option explained above for monolingual
+  documents. If there are more languages, it applies only to the main
+  language, while the rest will be loaded in the ‘classical’ way.
+\item |provide+=*| loads the main language in the ‘classical’ way,
+  and the rest in the ‘modern’ one.
+\item |provide*=*| is the same for all languages, ie, main and
+  secondary  ones are loaded in the ‘modern’ way.
+\end{itemize}
+
+\begin{example}
+Your document is written in Thai with large chunks in Dutch and German,
+and you want the |ldf| files in the latter because, for example, you
+need their shorthands. The font is Norasi, which covers the three
+languages:
+\setengine{luatex/xetex}
+\begin{verbatim}
+\usepackage[dutch,ngerman,thai,provide=*]{babel}
+\babelfont{rm}{Norasi}
+\end{verbatim}
+\end{example}
+
+More complex combinations can be handled with |\babelprovide|,
+explained below.
+
 \subsection{Languages supported by \babel{} in the ‘classical’ mode}
 
 (To be updated.) In the following table most of the languages supported
@@ -988,7 +1017,6 @@
 \bigskip\hrule\nobreak
 
 \makeatletter
-\def\tag#1{\par\@hangfrom{\makebox[1em][l]{#1}}\ignorespaces}
 \def\tag#1#2#3{\par
   \hspace{-2em}\textcolor{thered}{\texttt{#1}}#2\enspace
   \mbox{\footnotesize(#3)}}
@@ -1078,6 +1106,7 @@
 \tag{baluchi}{}{bal}
 \tag{bambara}{}{bm}
 \tag{bangla}{\hascapu}{bn}
+\subtag{bengali}{\hascapu}{bn}
 \tag{basaa}{}{bas}
 \tagmin{bashkir}{}{ba}
 \tag{basque}{\hascapu\hascapl}{eu}
@@ -1086,7 +1115,6 @@
 \tag{belarusian}{\hascapu\hascapl}{be}
 \tag{bemba}{}{bem}
 \tag{bena}{}{bez}
-\tag{bengali}{\hascapu}{bn}
 \tag{bhojpuri}{}{bho}
 \tag{blin}{}{byn}
 \tag{bodo}{}{brx}
@@ -1104,6 +1132,7 @@
 \tag{cebuano}{}{ceb}
 \tag{centralatlastamazight}{}{tzm}
 \tag{centralkurdish}{\hascapu}{ckb}
+\subtag{sorani}{\hascapu}{ckb}
 \subtag{centralkurdish-latin}{\hascapu}{ckb-Latn}
 \subtag{centralkurdish-latn}{\hascapu}{ckb-Latn}
 \tag{chakma}{}{ccp}
@@ -1176,7 +1205,6 @@
 \tag{ewe}{}{ee}
 \tag{ewondo}{}{ewo}
 \tag{faroese}{}{fo}
-\tag{farsi}{\hascapu}{fa}
 \tag{filipino}{}{fil}
 \tag{finnish}{\hascapu\hascapl}{fi}
 \tag{french}{\hascapu\hascapl}{fr}
@@ -1261,7 +1289,6 @@
 \subtag{korean-hani}{\hascapu}{ko-Hani}
 \tag{koyraborosenni}{}{ses}
 \tag{koyrachiini}{}{khq}
-\tag{kurmanji}{\hascapu\hascapl}{kmr}
 \tag{kwasio}{}{nmg}
 \tag{kyrgyz}{}{ky}
 \tagmin{ladino}{}{lad}
@@ -1334,10 +1361,12 @@
 \tag{nko}{}{nqo}
 \tag{northernfrisian}{}{frr}
 \tag{northernkurdish}{\hascapu\hascapl}{kmr}
+\subtag{kurmanji}{\hascapu\hascapl}{kmr}
 \subtag{northernkurdish-arab}{\hascapu}{kmr-Arab}
 \subtag{northernkurdish-arabic}{\hascapu}{kmr-Arab}
 \tag{northernluri}{}{lrc}
 \tag{northernsami}{\hascapu\hascapl}{se}
+\subtag{samin}{\hascapu\hascapl}{se}
 \tag{northernsotho}{}{nso}
 \tag{northndebele}{}{nd}
 \tag{norwegian}{\hascapu\hascapl}{no}
@@ -1393,7 +1422,6 @@
 \tag{sakha}{}{sah}
 \tagmin{samaritan}{}{smp}
 \tag{samburu}{}{saq}
-\tag{samin}{\hascapu\hascapl}{se}
 \tag{sango}{}{sg}
 \tag{sangu}{}{sbp}
 \tag{sanskrit}{}{sa}
@@ -1451,11 +1479,10 @@
 \tag{sinhala}{\hascapu}{si}
 \tagmin{sinteromani}{}{rmo}
 \tag{slovak}{\hascapu\hascapl}{sk}
-\tag{slovene}{\hascapu\hascapl}{sl}
 \tag{slovenian}{\hascapu\hascapl}{sl}
+\subtag{slovene}{\hascapu\hascapl}{sl}
 \tag{soga}{}{xog}
 \tag{somali}{}{so}
-\tag{sorani}{\hascapu}{ckb}
 \tagmin{southernaltai}{}{alt}
 \tag{southernsotho}{}{st}
 \tag{southndebele}{}{nr}
@@ -1559,14 +1586,19 @@
 it for you with the first |\babelfont|. (See also the package
 \textsf{combofont} for a complementary approach.)
 
+\begin{note}
+  There is a list of fonts in
+  \href{https://latex3.github.io/babel/guides/which-method-for-which-language.html}{Which
+  method for which language}. If you know the codepoint of a character
+  in the script you need, you can find fonts containing it with the
+  commands line, with \textsf{albatross} (requires Java) or with
+  something like \texttt{fc-list :charset=1033C family} (in this case,
+  a Gothic character, the script required by the |gothic| language).
+\end{note}
+
 \Describe\babelfont{\oarg{language-list}\marg{font-family}%
   \oarg{font-options}\marg{font-name}}
 
-% \begin{note}
-%   See the note in the previous section about some issues in
-%   specific languages.
-% \end{note}
-
 The main purpose of |\babelfont| is to define at once the fonts
 required by the different languages, with their corresponding language
 systems (script and language). So, if you load, say, 4 languages,
@@ -1591,10 +1623,11 @@
 is just ignored.
 
 \Babel{} takes care of the font language and the font script when
-languages are selected (as well as the writing direction). In most
-cases, you will not need \textit{font-options}, which is the same as in
-\textsf{fontspec}, but you may add further key/value pairs if
-necessary.
+languages are selected (as well as the writing direction). In other
+words, there is usually no need to set the |Language| and the |Script|
+explicitly; in fact, it’s even discouraged. In most cases, you will not
+need \textit{font-options}, which is the same as in \textsf{fontspec},
+but you may add further key/value pairs if necessary.
 
 |\babelfont| can be used to implicitly define a new font family. Just
 write its name instead of |rm|, |sf| or |tt|. This is the preferred way
@@ -1653,11 +1686,23 @@
 \begin{verbatim}
   \babelfont[_*arabic, *devanagari_]{rm}[_Renderer=Harfbuzz_]{FreeSerif}
 \end{verbatim}
-\Babel{} does the rest for you, including setting the font language and
-script.
+\Babel{} does the rest for you, including setting the font script
+\textit{and} language.
 \end{example}
 
 \begin{example}
+  Since each locale is a separate ‘language’, they can be assigned
+  different fonts. In this example, we set Simplified and Tradicional
+  Chinese:
+\begin{verbatim}
+\babelfont[chinese-_simplified_]{rm}{Noto Serif CJK _SC_}
+\babelfont[chinese-_simplified_]{sf}{Noto Sans CJK _SC_}
+\babelfont[chinese-_traditional_]{rm}{Noto Serif CJK _TC_}
+\babelfont[chinese-_traditional_]{sf}{Noto Sans CJK _TC_}
+\end{verbatim}
+\end{example}
+
+\begin{example}
   Here is how to declare a new family:
 \setengine{luatex/xetex}
 \begin{verbatim}
@@ -1904,6 +1949,66 @@
 it is a \textit{text} command, and therefore it doesn’t change the
 paragraph direction.
 
+\begin{example}
+Here is a document putting in practice some the techniques described,
+which shows how to deal neatly with complex multilingual documents
+in \xetex{} and \luatex, with the help of logical markup. You are
+writing a book on Indic literature with many extracts in several
+languages, which fits in the category of ‘mostly monolingual’. Loading
+of locales and fonts is lazy, which greatly simplifies the preamble.
+\catcode`@=13 \def@#1@{{\fontspec[Script=Devanagari]{FreeSans}#1}}
+\begin{verbatim}
+\documentclass{article}
+
+_\usepackage[english]{babel}_
+
+_\babelfont[*devanagari]{rm}[Renderer=Harfbuzz]{FreeSans}_
+
+\newenvironment{excerpt}[1]
+  {\begin{quote}_\begin{otherlanguage*}{#1}_}
+  {_\end{otherlanguage*}_\end{quote}}
+
+\begin{document}
+
+\section{Sanskrit literature}
+
+Here is an excerpt:
+\begin{excerpt}{sanskrit}
+  @संस्कृतम्@
+\end{excerpt}
+
+\section{Hindi literature}
+
+Here is an excerpt:
+\begin{excerpt}{hindi}
+  @हिन्दी@
+\end{excerpt}
+
+\section{Marathi literature}
+
+Here is an excerpt:
+\begin{excerpt}{marathi}
+  @मराठी@
+\end{excerpt}
+
+\section{Nepali literature}
+
+Here is an excerpt:
+\begin{excerpt}{nepali}
+  @नेपाली@
+\end{excerpt}
+
+\section{Rajasthani literature}
+
+Here is an excerpt:
+\begin{excerpt}{rajasthani}
+  @संस्कृतम्@
+\end{excerpt}
+
+\end{document}
+\end{verbatim}
+\end{example}
+
 \subsection{Plain}
 
 In e-Plain and pdf-Plain, load languages styles with |\input| and then use
@@ -1999,7 +2104,7 @@
 can add further macros with the key |include| in the optional argument
 (without commas). Macros not to be modified are listed in
 |exclude|. You can also enforce a font encoding with the option
-|fontenc|.\footnote{With it, encoded strings may not work as expected.}
+|fontenc| (with it, encoded strings may not work as expected).
 A couple of examples:
 \begin{verbatim}
 \babelensure[include=\Today]{spanish}
@@ -2287,10 +2392,10 @@
 \end{example}
 
 \begin{note}
-  With a recent version of \LaTeX, an alternative method to execute
-  some code just after an |ldf| file is loaded is with |\AddToHook| and
-  the hook |file/<language>.ldf/after|. \Babel{} does not predeclare
-  it, and you have to do it yourself with |\ActivateGenericHook|.
+  An alternative method to execute some code just after an |ldf| file
+  is loaded is with |\AddToHook| and the hook
+  |file/<language>.ldf/after|. You can also execute some code before
+  with |file/<language>.ldf/before|.
 \end{note}
 
 \begin{warning}
@@ -2331,29 +2436,23 @@
   \babel).
 \end{example}
 
-\New{3.49} Alternatively, you can tell \babel{} to load all or some
-languages passed as options with |\babelprovide| and not from the |ldf|
-file in a few few typical cases. Thus, |provide=*| means ‘load the main
-language with the |\babelprovide| mechanism instead of the |ldf| file’
-applying the basic features, which in this case means |import| and |main|.
-There are (currently) three options:
-\begin{itemize}
-\item |provide=*| is the option just explained, for the main language;
-\item |provide+=*| is the same for additional languages (the main
-  language is still the |ldf| file);
-\item |provide*=*| is the same for all languages, ie, main and
-  additional.
-\end{itemize}
-
 \begin{note}
   The \texttt{ini} files just define and set some parameters, but the
   corresponding behavior is not always implemented. Also, there are
   some limitations in the engines. A few remarks follow (which could no
   longer be valid when you read this manual, if the packages involved
-  have been updated). The Harfbuzz renderer still has some issues, so as
-  a rule of thumb prefer the default renderer, and resort to Harfbuzz
-  only if the former does not work for you. Fortunately, fonts can be
-  loaded twice with different renderers; for example:
+  have been updated). The Harfbuzz renderer still has some issues, so
+  as a rule of thumb:
+\begin{itemize}
+\item prefer the default renderer in alphabetic scripts (like Latin,
+  Greek and Cyrillic);
+\item resort to Harfbuzz in complex scripts with heavy contextual
+  analysis (like Arabic and Devanagari).
+\end{itemize}
+  See
+  \href{https://github.com/latex3/luaotfload/wiki/Comparing-the-modes}{Comparing
+  the modes} for further info. Fortunately, fonts can be loaded twice
+  with different renderers; for example:
 \begin{verbatim}
 \babelfont[spanish]{rm}{FreeSerif}
 \babelfont[hindi]{rm}[Renderer=Harfbuzz]{FreeSerif}
@@ -2522,8 +2621,8 @@
 
 \subsection{Captions}
 
-In the case of caption names a specific macro is provided,
-because this is perhaps the most frequent change.
+This is perhaps the most frequent change, so a specific macro is
+provided.
 
 \Describe{\setlocalecaption}{%
   \marg{language-name}\marg{caption-name}\marg{string}}
@@ -2550,8 +2649,8 @@
   (In this particular case, instead of the |captions| group you may need
   to modify the |captions.licr| one.)
 
-\item The ‘old way’ to redefine a caption, still valid for many
-languages but discouraged in general, is the following:
+\item The low-level ‘old way’ to redefine a caption, still valid for
+many languages but discouraged in general, is the following:
 \begin{verbatim}
 \addto\captionsenglish{%
   \renewcommand\contentsname{Foo}%
@@ -2564,7 +2663,7 @@
 \item The ‘new way’, which is found in |bulgarian|, |azerbaijani|,
     |spanish|, |french|, |turkish|, |icelandic|, |vietnamese| and a few
     more, as well as in languages created with |\babelprovide| and its
-    key |import|, is:
+    key |import|, or with the package option |provide=|, is:
 \begin{verbatim}
 \renewcommand\spanishchaptername{Foo}
 \end{verbatim}
@@ -2891,6 +2990,55 @@
 
 Its natural place of use is in hooks or in |\extras<language>|.
 
+\subsection{Presets}
+
+\New{24.12} Apart from configuration files, which are loaded before the
+locale files, you can preset some options even before loading \babel.
+One on the aims of this feature is to ease the integration with
+automated document generation or conversion workflows.
+
+\Describe{\AddToHook\{babel/presets\}}{\marg{settings}}
+
+This \LaTeX{} hook is executed just before locale files (either
+\texttt{ini} or \texttt{ldf}) are loaded. It’s in fact, similar to the
+config files, but it’s executed a little later and there is no need to
+a separate file. The following command has been devised for this hook,
+but other candidates are |\AfterBabelLanguage| and |\DeclareOption|
+(although the latter can be somewhat dangerous).
+
+Note these declarations are valid ‘just in case’. If \babel{} is not
+loaded, they are ignored.
+
+\Describe{\PassOptionsToLocale}{\marg{option-list}\marg{locale-name}}
+
+Its purpose is what its name suggests, and it was devised to be used
+with the previous hook.
+
+\begin{example}
+  You are writing a class and expect lazy loading of secondary
+  languages. You also want to make sure |french|, if used, activates
+  its rules for punctuation spacing, and |malayalam|, if used, maps
+  digits to the native ones (with \luatex):
+\setengine{luatex}
+\begin{verbatim}
+\AddToHook{babel/presets}{%
+  \PassOptionsToLocale{transforms=punctuation.space}{french}%
+  \PassOptionsToLocale{mapdigits}{malayalam}}
+\end{verbatim}
+  If you want to take a step further and force \babel{} to use always
+  |ini| files in all secondary languages, you can resort to the \LaTeX{}
+  mechanism to pass options to packages:
+\begin{verbatim}
+  \PassOptionsToPackage{provide+=*}{babel}
+\end{verbatim}
+\end{example}
+
+\begin{note}
+  Remember localized fonts are preset, too, with lazy loading. In
+  the previous example you can set, for example,
+  |\babelfont[malayalam]{rm}{FreeSerif}|.
+\end{note}
+
 \section{Creating a language}
 
 \New{3.10} And what if there is no style for your language or none fits
@@ -2934,7 +3082,7 @@
 \babelprovide{arhinish}
 \setlocalecaption{arhinish}{chapter}{Chapitula}
 \setlocalecaption{arhinish}{refname}{Refirenke}
-\renewcommand\arhinishhyphenmins{22}
+\babelhyphenmins[arhinish]{2}{2}
 \end{verbatim}
 \end{example}
 
@@ -3649,9 +3797,9 @@
 \item[Turkish] |: ! =|
 \end{description}
 In addition, the \babel{} core declares |~| as a one-char shorthand
-which is let, like the standard |~|, to a non breaking
-space.\footnote{This declaration serves to nothing, but it is
-preserved for backward compatibility.}
+which is let, like the standard |~|, to a non breaking space. Actually,
+this declaration serves to nothing, but it is preserved for backward
+compatibility.
 
 \Describe\ifbabelshorthand{\marg{character}\marg{true}\marg{false}}
 
@@ -4388,8 +4536,8 @@
 certain default. Even the \babel{} core defined |\textlatin|, but is
 was somewhat buggy because in some cases it messed up encodings and
 fonts (for example, if the main Latin encoding was |LY1|), and
-therefore it has been deprecated.\footnote{But still defined for
-backwards compatibility.}
+therefore it has been deprecated (but still defined for
+backwards compatibility).
 
 The locales currently available cover the following scripts:
 \begin{multicols}{4}
@@ -4918,6 +5066,8 @@
 
 \section{Relation with other packages}
 
+\subsection{Compatibility}
+
 There are compatibility issues with the following packages.
 
 \begingroup
@@ -4941,34 +5091,47 @@
 \trans{cleveref}{Because of a long standing bug in this package, some
 languages can raise and error (particularly |spanish| and |greek|).}
 
+\trans{natbib}{Load it before \babel.}
+
+\trans{bidi}{\Babel\ relies on \textsc{bidi} with \xetex{} and
+|bidi=bidi|, which has a multitude of incompatibilities. Please, refer
+to its manual, and remember for short and simple texts you can rely on
+|bidi=default| instead.}
+
 \vspace{2mm}\hrule\nobreak\bigskip
 \endgroup
 
+\subsection{Related packages}
+
 The following packages can be useful in multilingual contexts (the list
-is far from complete):
+is far from exhaustive):
 \begin{description}
 \itemsep=-\parskip
-\item[csquotes] Logical markup for quotes.
-\item[iflang] Tests correctly the current language.
-\item[hyphsubst] Selects a different set of patterns for a language.
-\item[translator] An open platform for packages that need to be
+\item[\sffamily babelbib] Multilingual bibliographies.
+\item[\sffamily biblatex] Programmable bibliographies and citations.
+\item[\sffamily bicaption] Bilingual captions.
+\item[\sffamily csquotes] Logical markup for quotes.
+\item[\sffamily hyphsubst] Selects a different set of patterns for a language.
+\item[\sffamily iflang] Tests correctly the current language.
+\item[\sffamily microtype] Adjusts the typesetting according to
+  some languages (kerning and spacing). Ligatures can be disabled.
+  Search in its manual for |babel| and |DeclareMicrotypeBabelHook|.
+\item[\sffamily mkpattern] Generates hyphenation patterns.
+\item[\sffamily siunitx] Typesetting of numbers and physical quantities.
+\item[\sffamily substitutefont] Combines fonts in several encodings.
+\item[\sffamily tracklang] Tracks which languages have been requested.
+\item[\sffamily translator] An open platform for packages that need to be
   localized.
-\item[siunitx] Typesetting of numbers and physical quantities.
-\item[biblatex] Programmable bibliographies and citations.
-\item[bicaption] Bilingual captions.
-\item[babelbib] Multilingual bibliographies.
-\item[microtype] Adjusts the typesetting according to
-some languages (kerning and spacing). Ligatures can be disabled.
-\item[substitutefont] Combines fonts in several encodings.
-\item[mkpattern] Generates hyphenation patterns.
-\item[tracklang] Tracks which languages have been requested.
-\item[ucharclasses] (\xetex) Switches fonts when you switch from one
-  Unicode block to another.
-\item[zhspacing] Spacing for CJK documents in \xetex.
+\item[\sffamily ucharclasses] (\xetex) Switches fonts when you switch from one
+  Unicode block to another. Note it doesn’t work with RTL scripts.
+\item[\sffamily zhspacing] Spacing for CJK documents in \xetex.
 \end{description}
 
-For multilingual indexing, see \textsf{upmendex} and \textsf{xindex}.
+\subsection{Indexing}
 
+For multilingual indexing, see \textsf{upmendex} and \textsf{xindex},
+currently preferred to \textit{xindy}.
+
 \section{Tentative and experimental code}
 
 See the code section for |\foreignlanguage*| (a new starred
@@ -5017,11 +5180,11 @@
 
 In that file the person who maintains a \TeX\ environment has to record
 for which languages he has hyphenation patterns \emph{and} in which
-files these are stored\footnote{This is because different operating
-systems sometimes use \emph{very} different file-naming
-conventions.}. When hyphenation exceptions are stored in a separate
-file this can be indicated by naming that file \emph{after} the file
-with the hyphenation patterns.
+files these are stored (this was because different operating systems
+sometimes used \emph{very} different file-naming conventions, but this
+issue is not currently so serious as before). When hyphenation
+exceptions are stored in a separate file this can be indicated by
+naming that file \emph{after} the file with the hyphenation patterns.
 
 The file can contain empty lines and comments, as well as lines which
 start with an equals (\texttt{=}) sign. Such a line will instruct
@@ -5038,9 +5201,8 @@
 \end{verbatim}
 
 You may also set the font encoding the patterns are intended for by
-following the language name by a colon and the encoding
-code.\footnote{This is not a new feature, but in former versions it
-didn't work correctly.} For example:
+following the language name by a colon and the encoding code. For
+example:
 \begin{verbatim}
 german:T1 hyphenT1.ger
 german hyphen.ger
@@ -5117,8 +5279,8 @@
 \item Do not switch scripts. If you want to make sure a set of glyphs
   is used, switch either the font encoding (low-level) or the language
   (high-level, which in turn may switch the font encoding). Usage of things
-  like |\latintext| is deprecated.\footnote{But not removed, for backward
-  compatibility.}
+  like |\latintext| is deprecated (but not removed, for backward
+  compatibility).
 \item Please, for ``private'' internal macros do not use the |\bbl@|
   prefix. It is used by \babel{} and it can lead to incompatibilities.
 \end{itemize}
@@ -5203,7 +5365,8 @@
 \renewcommand\spanishhyphenmins{34}
 \end{verbatim}
 (Assigning |\lefthyphenmin| and |\righthyphenmin| directly in
-|\extras<language>| has no effect.)
+|\extras<language>| has no effect.) This is a low-level setting. In
+documents you should rely on |\babelhyphenmins|.
 
 \DescribeMacro{\providehyphenmins}
 The macro |\providehyphenmins| should be used in the language
@@ -5611,9 +5774,7 @@
 engine is used. This is not done by default to prevent backward
 incompatibilities, but if you are creating a new language this version
 is better. It's up to the maintainers of the current languages to
-decide if using it is appropriate.\footnote{This replaces in 3.9g a
-short-lived \texttt{\string\UseStrings} which has been removed because
-it did not work.}
+decide if using it is appropriate.
 
 \Describe{\EndBabelCommands}{}
 Marks the end of the series of blocks.
@@ -5796,8 +5957,8 @@
 % \section{Tools}
 %
 %    \begin{macrocode}
-%<<version=24.11>>
-%<<date=2024/10/05>>
+%<<version=24.12>>
+%<<date=2024/10/20>>
 %    \end{macrocode}
 %
 % \textbf{Do not use the following macros in \texttt{ldf} files. They
@@ -6200,8 +6361,10 @@
 %
 %    \begin{macrocode}
 %<*package>
-\NeedsTeXFormat{LaTeX2e}[2005/12/01]
-\ProvidesPackage{babel}[<@date@> v<@version@> The Babel package]
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{babel}%
+  [<@date@> v<@version@>
+   The multilingual framework for pdfLaTeX, LuaLaTeX and XeLaTeX]
 %    \end{macrocode}
 %
 % Start with some “private” debugging tools, and then define macros for
@@ -6466,7 +6629,6 @@
       \def\bbl at opt@provide{#2}%
     \fi}
 \fi
-%
 %    \end{macrocode}
 %
 % If there is no |shorthands=<chars>|, the original \textsf{babel}
@@ -6585,6 +6747,8 @@
 % interlude, because the actual code is below, tagged as
 % \textit{Emulate LaTeX}.
 %
+% First, exit immediately if previouly loaded.
+%
 %    \begin{macrocode}
 %<*core>
 \ifx\ldf at quit\@undefined\else
@@ -6595,15 +6759,12 @@
   <@Emulate LaTeX@>
 \fi
 <@Basic macros@>
+%</core>
 %    \end{macrocode}
 %
 % That is all for the moment. Now follows some common stuff, for both
 % Plain and \LaTeX{}. After it, we will resume the \LaTeX-only stuff.
 %
-%    \begin{macrocode}
-%</core>
-%    \end{macrocode}
-%
 % \section{\texttt{babel.sty} and \texttt{babel.def} (common)}
 %
 %    \begin{macrocode}
@@ -6720,38 +6881,6 @@
     \fi
   \fi\fi}
 \let\bbl at initoload\relax
-%</package|core>
-%<*package>
-\def\bbl at provide@locale{%
-  \ifx\babelprovide\@undefined
-    \bbl at error{base-on-the-fly}{}{}{}%
-  \fi
-  \let\bbl at auxname\languagename % Still necessary.
-  \bbl at ifunset{bbl at bcp@map@\languagename}{}% Move uplevel??
-    {\edef\languagename{\@nameuse{bbl at bcp@map@\languagename}}}%
-  \ifbbl at bcpallowed
-    \expandafter\ifx\csname date\languagename\endcsname\relax
-      \expandafter
-      \bbl at bcplookup\languagename-\@empty-\@empty-\@empty\@@
-      \ifx\bbl at bcp\relax\else  % Returned by \bbl at bcplookup
-        \edef\languagename{\bbl at bcp@prefix\bbl at bcp}%
-        \edef\localename{\bbl at bcp@prefix\bbl at bcp}%
-        \expandafter\ifx\csname date\languagename\endcsname\relax
-          \let\bbl at initoload\bbl at bcp
-          \bbl at exp{\\\babelprovide[\bbl at autoload@bcpoptions]{\languagename}}%
-          \let\bbl at initoload\relax
-        \fi
-        \bbl at csarg\xdef{bcp at map@\bbl at bcp}{\localename}%
-      \fi
-    \fi
-  \fi
-  \expandafter\ifx\csname date\languagename\endcsname\relax
-    \IfFileExists{babel-\languagename.tex}%
-      {\bbl at exp{\\\babelprovide[\bbl at autoload@options]{\languagename}}}%
-      {}%
-  \fi}
-%</package>
-%<*package|core>
 %    \end{macrocode}
 %
 % \macro{\iflanguage}
@@ -6975,9 +7104,6 @@
 \let\bbl at restorelastskip\relax
 \let\bbl at savelastskip\relax
 %
-\newif\ifbbl at bcpallowed
-\bbl at bcpallowedfalse
-%
 \def\select at language#1{% from set@, babel at aux, babel at toc
   \ifx\bbl at selectorname\@empty
     \def\bbl at selectorname{select}%
@@ -7500,20 +7626,142 @@
      rebuild the format. Now I will use the patterns\\%
      preloaded for \bbl at nulllanguage\space instead}}
 \let\bbl at usehooks\@gobbletwo
+%    \end{macrocode}
+%
+% Here ended the now discarded |switch.def|.
+%
+% Here also (currently) ends the \textsf{base} option.
+%
+%    \begin{macrocode}
 \ifx\bbl at onlyswitch\@empty\endinput\fi
-  % Here ended switch.def
 %    \end{macrocode}
 %
-% Here ended the now discarded |switch.def|. Here also (currently) ends
-% the \textsf{base} option.
+% \subsection{More on selection}
 %
+% \macro{\babelensure}
+%
+% The user command just parses the optional argument and creates a
+% new macro named |\bbl at e@<language>|. We register a hook at the
+% |afterextras| event which just executes this macro in a
+% ``complete'' selection (which, if undefined, is |\relax| and does
+% nothing). This part is somewhat involved because we have to make
+% sure things are expanded the correct number of times.
+%
+% The macro |\bbl at e@<language>| contains
+% |\bbl at ensure|\marg{include}\marg{exclude}\marg{fontenc}, which in in
+% turn loops over the macros names in |\bbl at captionslist|, excluding
+% (with the help of |\in@|) those in the |exclude| list. If the
+% |fontenc| is given (and not |\relax|), the |\fontencoding| is also
+% added. Then we loop over the |include| list, but if the macro
+% already contains |\foreignlanguage|, nothing is done.  Note this
+% macro (1) is not restricted to the preamble, and (2) changes are
+% local.
+%
 %    \begin{macrocode}
+\bbl at trace{Defining babelensure}
+\newcommand\babelensure[2][]{%
+  \AddBabelHook{babel-ensure}{afterextras}{%
+    \ifcase\bbl at select@type
+      \bbl at cl{e}%
+    \fi}%
+  \begingroup
+    \let\bbl at ens@include\@empty
+    \let\bbl at ens@exclude\@empty
+    \def\bbl at ens@fontenc{\relax}%
+    \def\bbl at tempb##1{%
+      \ifx\@empty##1\else\noexpand##1\expandafter\bbl at tempb\fi}%
+    \edef\bbl at tempa{\bbl at tempb#1\@empty}%
+    \def\bbl at tempb##1=##2\@@{\@namedef{bbl at ens@##1}{##2}}%
+    \bbl at foreach\bbl at tempa{\bbl at tempb##1\@@}%
+    \def\bbl at tempc{\bbl at ensure}%
+    \expandafter\bbl at add\expandafter\bbl at tempc\expandafter{%
+      \expandafter{\bbl at ens@include}}%
+    \expandafter\bbl at add\expandafter\bbl at tempc\expandafter{%
+      \expandafter{\bbl at ens@exclude}}%
+    \toks@\expandafter{\bbl at tempc}%
+    \bbl at exp{%
+  \endgroup
+  \def\<bbl at e@#2>{\the\toks@{\bbl at ens@fontenc}}}}
+\def\bbl at ensure#1#2#3{% 1: include 2: exclude 3: fontenc
+  \def\bbl at tempb##1{% elt for (excluding) \bbl at captionslist list
+    \ifx##1\@undefined % 3.32 - Don't assume the macro exists
+      \edef##1{\noexpand\bbl at nocaption
+        {\bbl at stripslash##1}{\languagename\bbl at stripslash##1}}%
+    \fi
+    \ifx##1\@empty\else
+      \in@{##1}{#2}%
+      \ifin@\else
+        \bbl at ifunset{bbl at ensure@\languagename}%
+          {\bbl at exp{%
+            \\\DeclareRobustCommand\<bbl at ensure@\languagename>[1]{%
+              \\\foreignlanguage{\languagename}%
+              {\ifx\relax#3\else
+                \\\fontencoding{#3}\\\selectfont
+               \fi
+               ########1}}}}%
+          {}%
+        \toks@\expandafter{##1}%
+        \edef##1{%
+           \bbl at csarg\noexpand{ensure@\languagename}%
+           {\the\toks@}}%
+      \fi
+      \expandafter\bbl at tempb
+    \fi}%
+  \expandafter\bbl at tempb\bbl at captionslist\today\@empty
+  \def\bbl at tempa##1{% elt for include list
+    \ifx##1\@empty\else
+      \bbl at csarg\in@{ensure@\languagename\expandafter}\expandafter{##1}%
+      \ifin@\else
+        \bbl at tempb##1\@empty
+      \fi
+      \expandafter\bbl at tempa
+    \fi}%
+  \bbl at tempa#1\@empty}
+\def\bbl at captionslist{%
+  \prefacename\refname\abstractname\bibname\chaptername\appendixname
+  \contentsname\listfigurename\listtablename\indexname\figurename
+  \tablename\partname\enclname\ccname\headtoname\pagename\seename
+  \alsoname\proofname\glossaryname}
+%    \end{macrocode}
+%
+% \subsection{Short tags}
+%
+% \macro{\babeltags}
+% This macro is straightforward. After zapping spaces, we
+% loop over the list and define the macros |\text<tag>| and
+% |\<tag>|. Definitions are first expanded so that they don't
+% contain |\csname| but the actual macro.
+%
+%   \begin{macrocode}
+\bbl at trace{Short tags}
+\newcommand\babeltags[1]{%
+  \edef\bbl at tempa{\zap at space#1 \@empty}%
+  \def\bbl at tempb##1=##2\@@{%
+    \edef\bbl at tempc{%
+      \noexpand\newcommand
+      \expandafter\noexpand\csname ##1\endcsname{%
+        \noexpand\protect
+        \expandafter\noexpand\csname otherlanguage*\endcsname{##2}}
+      \noexpand\newcommand
+      \expandafter\noexpand\csname text##1\endcsname{%
+        \noexpand\foreignlanguage{##2}}}
+    \bbl at tempc}%
+  \bbl at for\bbl at tempa\bbl at tempa{%
+    \expandafter\bbl at tempb\bbl at tempa\@@}}
+%    \end{macrocode}
+%
+% \subsection{Compatibility with language.def}
+%
+% Plain e-\TeX{} doesn’t rely on language.dat, but babel can be made
+% compatible with this format easily.
+%
+%    \begin{macrocode}
+\bbl at trace{Compatibility with language.def}
 \ifx\directlua\@undefined\else
   \ifx\bbl at luapatterns\@undefined
     \input luababel.def
   \fi
 \fi
-\bbl at trace{Compatibility with language.def}
 \ifx\bbl at languages\@undefined
   \ifx\directlua\@undefined
     \openin1 = language.def % TODO. Remove hardcoded number
@@ -7561,66 +7809,6 @@
   \fi}
 %    \end{macrocode}
 %
-% The macro |\initiate at active@char| below takes all the necessary
-% actions to make its argument a shorthand character. The real work
-% is performed once for each character. But first we define a little
-% tool.
-%
-%    \begin{macrocode}
-\def\bbl at withactive#1#2{%
-  \begingroup
-    \lccode`~=`#2\relax
-    \lowercase{\endgroup#1~}}
-%    \end{macrocode}
-%
-% \macro{\bbl at redefine}
-%
-% To redefine a command, we save the old meaning of the macro. Then
-% we redefine it to call the original macro with the `sanitized'
-% argument. The reason why we do it this way is that we don't want
-% to redefine the \LaTeX\ macros completely in case their
-% definitions change (they have changed in the past). A macro named
-% |\macro| will be saved new control sequences named |\org at macro|.
-%
-%    \begin{macrocode}
-\def\bbl at redefine#1{%
-  \edef\bbl at tempa{\bbl at stripslash#1}%
-  \expandafter\let\csname org@\bbl at tempa\endcsname#1%
-  \expandafter\def\csname\bbl at tempa\endcsname}
-\@onlypreamble\bbl at redefine
-%    \end{macrocode}
-%
-% \macro{\bbl at redefine@long}
-% This version of |\babel at redefine| can be used to redefine |\long|
-% commands such as |\ifthenelse|.
-%
-%    \begin{macrocode}
-\def\bbl at redefine@long#1{%
-  \edef\bbl at tempa{\bbl at stripslash#1}%
-  \expandafter\let\csname org@\bbl at tempa\endcsname#1%
-  \long\expandafter\def\csname\bbl at tempa\endcsname}
-\@onlypreamble\bbl at redefine@long
-%    \end{macrocode}
-%
-% \macro{\bbl at redefinerobust}
-% For commands that are redefined, but which \textit{might} be
-% robust we need a slightly more intelligent macro. A robust
-% command |foo| is defined to expand to |\protect|\verb*|\foo |. So
-% it is necessary to check whether \verb*|\foo | exists. The result
-% is that the command that is being redefined is always robust
-% afterwards.  Therefore all we need to do now is define \verb*|\foo |.
-%
-%    \begin{macrocode}
-\def\bbl at redefinerobust#1{%
-  \edef\bbl at tempa{\bbl at stripslash#1}%
-  \bbl at ifunset{\bbl at tempa\space}%
-    {\expandafter\let\csname org@\bbl at tempa\endcsname#1%
-     \bbl at exp{\def\\#1{\\\protect\<\bbl at tempa\space>}}}%
-    {\bbl at exp{\let\<org@\bbl at tempa>\<\bbl at tempa\space>}}%
-    \@namedef{\bbl at tempa\space}}
-\@onlypreamble\bbl at redefinerobust
-%    \end{macrocode}
-%
 % \subsection{Hooks}
 %
 % Admittedly, the current implementation is a somewhat simplistic and
@@ -7673,90 +7861,12 @@
 \fi
 %    \end{macrocode}
 %
-% \macro{\babelensure}
+% Since the following command is meant for a hook (although a \LaTeX
+% one), it’s placed here.
 %
-% The user command just parses the optional argument and creates a
-% new macro named |\bbl at e@<language>|. We register a hook at the
-% |afterextras| event which just executes this macro in a
-% ``complete'' selection (which, if undefined, is |\relax| and does
-% nothing). This part is somewhat involved because we have to make
-% sure things are expanded the correct number of times.
-%
-% The macro |\bbl at e@<language>| contains
-% |\bbl at ensure|\marg{include}\marg{exclude}\marg{fontenc}, which in in
-% turn loops over the macros names in |\bbl at captionslist|, excluding
-% (with the help of |\in@|) those in the |exclude| list. If the
-% |fontenc| is given (and not |\relax|), the |\fontencoding| is also
-% added. Then we loop over the |include| list, but if the macro
-% already contains |\foreignlanguage|, nothing is done.  Note this
-% macro (1) is not restricted to the preamble, and (2) changes are
-% local.
-%
 %    \begin{macrocode}
-\bbl at trace{Defining babelensure}
-\newcommand\babelensure[2][]{%
-  \AddBabelHook{babel-ensure}{afterextras}{%
-    \ifcase\bbl at select@type
-      \bbl at cl{e}%
-    \fi}%
-  \begingroup
-    \let\bbl at ens@include\@empty
-    \let\bbl at ens@exclude\@empty
-    \def\bbl at ens@fontenc{\relax}%
-    \def\bbl at tempb##1{%
-      \ifx\@empty##1\else\noexpand##1\expandafter\bbl at tempb\fi}%
-    \edef\bbl at tempa{\bbl at tempb#1\@empty}%
-    \def\bbl at tempb##1=##2\@@{\@namedef{bbl at ens@##1}{##2}}%
-    \bbl at foreach\bbl at tempa{\bbl at tempb##1\@@}%
-    \def\bbl at tempc{\bbl at ensure}%
-    \expandafter\bbl at add\expandafter\bbl at tempc\expandafter{%
-      \expandafter{\bbl at ens@include}}%
-    \expandafter\bbl at add\expandafter\bbl at tempc\expandafter{%
-      \expandafter{\bbl at ens@exclude}}%
-    \toks@\expandafter{\bbl at tempc}%
-    \bbl at exp{%
-  \endgroup
-  \def\<bbl at e@#2>{\the\toks@{\bbl at ens@fontenc}}}}
-\def\bbl at ensure#1#2#3{% 1: include 2: exclude 3: fontenc
-  \def\bbl at tempb##1{% elt for (excluding) \bbl at captionslist list
-    \ifx##1\@undefined % 3.32 - Don't assume the macro exists
-      \edef##1{\noexpand\bbl at nocaption
-        {\bbl at stripslash##1}{\languagename\bbl at stripslash##1}}%
-    \fi
-    \ifx##1\@empty\else
-      \in@{##1}{#2}%
-      \ifin@\else
-        \bbl at ifunset{bbl at ensure@\languagename}%
-          {\bbl at exp{%
-            \\\DeclareRobustCommand\<bbl at ensure@\languagename>[1]{%
-              \\\foreignlanguage{\languagename}%
-              {\ifx\relax#3\else
-                \\\fontencoding{#3}\\\selectfont
-               \fi
-               ########1}}}}%
-          {}%
-        \toks@\expandafter{##1}%
-        \edef##1{%
-           \bbl at csarg\noexpand{ensure@\languagename}%
-           {\the\toks@}}%
-      \fi
-      \expandafter\bbl at tempb
-    \fi}%
-  \expandafter\bbl at tempb\bbl at captionslist\today\@empty
-  \def\bbl at tempa##1{% elt for include list
-    \ifx##1\@empty\else
-      \bbl at csarg\in@{ensure@\languagename\expandafter}\expandafter{##1}%
-      \ifin@\else
-        \bbl at tempb##1\@empty
-      \fi
-      \expandafter\bbl at tempa
-    \fi}%
-  \bbl at tempa#1\@empty}
-\def\bbl at captionslist{%
-  \prefacename\refname\abstractname\bibname\chaptername\appendixname
-  \contentsname\listfigurename\listtablename\indexname\figurename
-  \tablename\partname\enclname\ccname\headtoname\pagename\seename
-  \alsoname\proofname\glossaryname}
+\providecommand\PassOptionsToLocale[2]{%
+  \bbl at csarg\bbl at add@list{passto@#2}{#1}}
 %    \end{macrocode}
 %
 % \subsection{Setting up language files}
@@ -7911,31 +8021,12 @@
     \immediate\write\@mainaux{\string\@nameuse{bbl at beforestart}}%
   \fi
   \expandafter\selectlanguage\expandafter{\bbl at main@language}%
-%</package|core>
-%<*package>
-  \ifx\bbl at normalsf\@empty
-    \ifnum\sfcode`\.=\@m
-      \let\normalsfcodes\frenchspacing
-    \else
-      \let\normalsfcodes\nonfrenchspacing
-    \fi
-  \else
-    \let\normalsfcodes\bbl at normalsf
-  \fi
-%</package>
-%<*package|core>
   \ifbbl at single  % must go after the line above.
     \renewcommand\selectlanguage[1]{}%
     \renewcommand\foreignlanguage[2]{#2}%
     \global\let\babel at aux\@gobbletwo  % Also as flag
   \fi}
-%</package|core>
-%<*package>
-\AddToHook{begindocument/before}{%
-  \let\bbl at normalsf\normalsfcodes
-  \let\normalsfcodes\relax} % Hack, to delay the setting
-%</package>%
-%<*package|core>
+%
 \ifcase\bbl at engine\or
   \AtBeginDocument{\pagedir\bodydir}
 \fi
@@ -7955,6 +8046,19 @@
 %
 % \subsection{Shorthands}
 %
+% The macro |\initiate at active@char| below takes all the necessary
+% actions to make its argument a shorthand character. The real work
+% is performed once for each character. But first we define a little
+% tool.
+%
+%    \begin{macrocode}
+\bbl at trace{Shorhands}
+\def\bbl at withactive#1#2{%
+  \begingroup
+    \lccode`~=`#2\relax
+    \lowercase{\endgroup#1~}}
+%    \end{macrocode}
+%
 % \macro{\bbl at add@special}
 % The macro |\bbl at add@special| is used to add a new character (or
 % single character control sequence) to the macro |\dospecials| (and
@@ -7968,7 +8072,6 @@
 % done with |\nfss at catcodes|, added in 3.10.
 %
 %    \begin{macrocode}
-\bbl at trace{Shorhands}
 \def\bbl at add@special#1{% 1:a macro like \", \?, etc.
   \bbl at add\dospecials{\do#1}% test @sanitize = \relax, for back. compat.
   \bbl at ifunset{@sanitize}{}{\bbl at add\@sanitize{\@makeother#1}}%
@@ -8844,7 +8947,7 @@
 \AtBeginDocument{\bbl at clear@ttribs}
 %    \end{macrocode}
 %
-% \subsection{Support for saving macro definitions}
+% \subsection{Support for saving and redefining macros}
 %
 % To save the meaning of control sequences using |\babel at save|, we use
 % temporary control sequences. To save hash table entries for these
@@ -8876,15 +8979,14 @@
 % \macro{\babel at savevariable}
 %
 % The macro |\babel at save|\meta{csname} saves the current meaning of the
-% control sequence \meta{csname} to
-% |\originalTeX|\footnote{\cs{originalTeX} has to be expandable,
-% i.\,e.\ you shouldn't let it to \cs{relax}.}. To do this, we let the
-% current meaning to a temporary control sequence, the restore commands
-% are appended to |\originalTeX| and the counter is incremented. The
-% macro |\babel at savevariable|\meta{variable} saves the value of the
-% variable. \meta{variable} can be anything allowed after the |\the|
-% primitive. To avoid messing saved definitions up, they are saved only
-% the very first time.
+% control sequence \meta{csname} to |\originalTeX| (which has to be
+% expandable, i.\,e.\ you shouldn't let it to \cs{relax}). To do this,
+% we let the current meaning to a temporary control sequence, the
+% restore commands are appended to |\originalTeX| and the counter is
+% incremented. The macro |\babel at savevariable|\meta{variable} saves the
+% value of the variable. \meta{variable} can be anything allowed after
+% the |\the| primitive. To avoid messing saved definitions up, they are
+% saved only the very first time.
 %
 %    \begin{macrocode}
 \def\babel at save#1{%
@@ -8905,15 +9007,62 @@
   \bbl at exp{\def\\\originalTeX{\the\toks@\the#1\relax}}}
 %    \end{macrocode}
 %
+% \macro{\bbl at redefine}
+%
+% To redefine a command, we save the old meaning of the macro. Then
+% we redefine it to call the original macro with the `sanitized'
+% argument. The reason why we do it this way is that we don't want
+% to redefine the \LaTeX\ macros completely in case their
+% definitions change (they have changed in the past). A macro named
+% |\macro| will be saved new control sequences named |\org at macro|.
+%
+%    \begin{macrocode}
+\def\bbl at redefine#1{%
+  \edef\bbl at tempa{\bbl at stripslash#1}%
+  \expandafter\let\csname org@\bbl at tempa\endcsname#1%
+  \expandafter\def\csname\bbl at tempa\endcsname}
+\@onlypreamble\bbl at redefine
+%    \end{macrocode}
+%
+% \macro{\bbl at redefine@long}
+% This version of |\babel at redefine| can be used to redefine |\long|
+% commands such as |\ifthenelse|.
+%
+%    \begin{macrocode}
+\def\bbl at redefine@long#1{%
+  \edef\bbl at tempa{\bbl at stripslash#1}%
+  \expandafter\let\csname org@\bbl at tempa\endcsname#1%
+  \long\expandafter\def\csname\bbl at tempa\endcsname}
+\@onlypreamble\bbl at redefine@long
+%    \end{macrocode}
+%
+% \macro{\bbl at redefinerobust}
+% For commands that are redefined, but which \textit{might} be
+% robust we need a slightly more intelligent macro. A robust
+% command |foo| is defined to expand to |\protect|\verb*|\foo |. So
+% it is necessary to check whether \verb*|\foo | exists. The result
+% is that the command that is being redefined is always robust
+% afterwards.  Therefore all we need to do now is define \verb*|\foo |.
+%
+%    \begin{macrocode}
+\def\bbl at redefinerobust#1{%
+  \edef\bbl at tempa{\bbl at stripslash#1}%
+  \bbl at ifunset{\bbl at tempa\space}%
+    {\expandafter\let\csname org@\bbl at tempa\endcsname#1%
+     \bbl at exp{\def\\#1{\\\protect\<\bbl at tempa\space>}}}%
+    {\bbl at exp{\let\<org@\bbl at tempa>\<\bbl at tempa\space>}}%
+    \@namedef{\bbl at tempa\space}}
+\@onlypreamble\bbl at redefinerobust
+%    \end{macrocode}
+%
+% \subsection{French spacing}
+%
 % \macro{\bbl at frenchspacing}
 % \macro{\bbl at nonfrenchspacing}
 % Some languages need to have |\frenchspacing| in effect. Others
 % don't want that. The command |\bbl at frenchspacing| switches it on
 % when it isn't already in effect and |\bbl at nonfrenchspacing|
-% switches it off if necessary. A more refined way to switch the
-% catcodes is done with |ini| files. Here an auxiliary macro is
-% defined, but the main part is in |\babelprovide|. This new method
-% should be ideally the default one.
+% switches it off if necessary. 
 %
 %    \begin{macrocode}
 \def\bbl at frenchspacing{%
@@ -8924,6 +9073,13 @@
     \let\bbl at nonfrenchspacing\nonfrenchspacing
   \fi}
 \let\bbl at nonfrenchspacing\nonfrenchspacing
+%    \end{macrocode}
+%
+% A more refined way to switch the catcodes is done with |ini| files.
+% Here an auxiliary macro is defined, but the main part is in
+% |\babelprovide|. This new method should be ideally the default one.
+%
+%    \begin{macrocode}
 \let\bbl at elt\relax
 \edef\bbl at fs@chars{%
   \bbl at elt{\string.}\@m{3000}\bbl at elt{\string?}\@m{3000}%
@@ -8954,32 +9110,6 @@
   \fi\fi\fi}
 %    \end{macrocode}
 %
-% \subsection{Short tags}
-%
-% \macro{\babeltags}
-% This macro is straightforward. After zapping spaces, we
-% loop over the list and define the macros |\text<tag>| and
-% |\<tag>|. Definitions are first expanded so that they don't
-% contain |\csname| but the actual macro.
-%
-%   \begin{macrocode}
-\bbl at trace{Short tags}
-\def\babeltags#1{%
-  \edef\bbl at tempa{\zap at space#1 \@empty}%
-  \def\bbl at tempb##1=##2\@@{%
-    \edef\bbl at tempc{%
-      \noexpand\newcommand
-      \expandafter\noexpand\csname ##1\endcsname{%
-        \noexpand\protect
-        \expandafter\noexpand\csname otherlanguage*\endcsname{##2}}
-      \noexpand\newcommand
-      \expandafter\noexpand\csname text##1\endcsname{%
-        \noexpand\foreignlanguage{##2}}}
-    \bbl at tempc}%
-  \bbl at for\bbl at tempa\bbl at tempa{%
-    \expandafter\bbl at tempb\bbl at tempa\@@}}
-%    \end{macrocode}
-%
 % \subsection{Hyphens}
 %
 % \macro{\babelhyphenation}
@@ -9045,10 +9175,10 @@
 %
 % \macro{\bbl at allowhyphens}
 %
-% This macro makes hyphenation possible. Basically its definition
-% is nothing more than |\nobreak| |\hskip| \texttt{0pt plus
-% 0pt}\footnote{\TeX\ begins and ends a word for hyphenation at a
-% glue node. The penalty prevents a linebreak at this glue node.}.
+% This macro makes hyphenation possible. Basically its definition is
+% nothing more than |\nobreak| |\hskip| \texttt{0pt plus 0pt}. \TeX\
+% begins and ends a word for hyphenation at a glue node. The penalty
+% prevents a linebreak at this glue node.
 %
 %    \begin{macrocode}
 \def\bbl at allowhyphens{\ifvmode\else\nobreak\hskip\z at skip\fi}
@@ -9989,43 +10119,6 @@
 %    \begin{macrocode}
 \bbl at trace{Bidi layout}
 \providecommand\IfBabelLayout[3]{#3}%
-%</package|core>
-%<*package>
-\newcommand\BabelPatchSection[1]{%
-  \@ifundefined{#1}{}{%
-    \bbl at exp{\let\<bbl at ss@#1>\<#1>}%
-    \@namedef{#1}{%
-      \@ifstar{\bbl at presec@s{#1}}%
-              {\@dblarg{\bbl at presec@x{#1}}}}}}
-\def\bbl at presec@x#1[#2]#3{%
-  \bbl at exp{%
-    \\\select at language@x{\bbl at main@language}%
-    \\\bbl at cs{sspre@#1}%
-    \\\bbl at cs{ss@#1}%
-      [\\\foreignlanguage{\languagename}{\unexpanded{#2}}]%
-      {\\\foreignlanguage{\languagename}{\unexpanded{#3}}}%
-    \\\select at language@x{\languagename}}}
-\def\bbl at presec@s#1#2{%
-  \bbl at exp{%
-    \\\select at language@x{\bbl at main@language}%
-    \\\bbl at cs{sspre@#1}%
-    \\\bbl at cs{ss@#1}*%
-      {\\\foreignlanguage{\languagename}{\unexpanded{#2}}}%
-    \\\select at language@x{\languagename}}}
-\IfBabelLayout{sectioning}%
-  {\BabelPatchSection{part}%
-   \BabelPatchSection{chapter}%
-   \BabelPatchSection{section}%
-   \BabelPatchSection{subsection}%
-   \BabelPatchSection{subsubsection}%
-   \BabelPatchSection{paragraph}%
-   \BabelPatchSection{subparagraph}%
-   \def\babel at toc#1{%
-     \select at language@x{\bbl at main@language}}}{}
-\IfBabelLayout{captions}%
-  {\BabelPatchSection{caption}}{}
-%</package>
-%<*package|core>
 %    \end{macrocode}
 %
 % \subsection{Load engine specific macros}
@@ -10075,7 +10168,7 @@
   \bbl at vforeach{captions,date,import,main,script,language,%
       hyphenrules,linebreaking,justification,mapfont,maparabic,%
       mapdigits,intraspace,intrapenalty,onchar,transforms,alph,%
-      Alph,labels,labels*,calendar,date,casing,interchar}%
+      Alph,labels,labels*,calendar,date,casing,interchar, at import}%
     {\bbl at csarg\let{KVP@##1}\@nnil}%
   \global\let\bbl at release@transforms\@empty
   \global\let\bbl at release@casing\@empty
@@ -10084,7 +10177,10 @@
   \global\let\bbl at extend@ini\@gobble
   \global\let\bbl at included@inis\@empty
   \gdef\bbl at key@list{;}%
-  \bbl at forkv{#1}{%
+  \bbl at ifunset{bbl at passto@#2}%
+    {\def\bbl at tempa{#1}}%
+    {\bbl at exp{\def\\\bbl at tempa{\[bbl at passto@#2],\unexpanded{#1}}}}%
+  \expandafter\bbl at forkv\expandafter{\bbl at tempa}{%
     \in@{/}{##1}% With /, (re)sets a value in the ini
     \ifin@ 
       \global\let\bbl at extend@ini\bbl at extend@ini at aux
@@ -10101,6 +10197,10 @@
   \ifx\bbl at screset\@undefined
     \bbl at ldfinit
   \fi
+  % ==
+  \ifx\bbl at KVP@@import\@nnil\else \ifx\bbl at KVP@import\@nnil
+    \def\bbl at KVP@import{\@empty}%
+  \fi\fi
   % == date (as option) ==
   % \ifx\bbl at KVP@date\@nnil\else
   % \fi
@@ -10198,97 +10298,6 @@
       {\directlua{
          Babel.set_chranges_b('\bbl at cl{sbcp}', '\bbl at cl{chrng}') }}%
   \fi
-   % == onchar ==
-  \ifx\bbl at KVP@onchar\@nnil\else
-    \bbl at luahyphenate
-    \bbl at exp{%
-      \\\AddToHook{env/document/before}{{\\\select at language{#2}{}}}}%
-    \directlua{
-      if Babel.locale_mapped == nil then
-        Babel.locale_mapped = true
-        Babel.linebreaking.add_before(Babel.locale_map, 1)
-        Babel.loc_to_scr = {}
-        Babel.chr_to_loc = Babel.chr_to_loc or {}
-      end
-      Babel.locale_props[\the\localeid].letters = false
-    }%
-    \bbl at xin@{ letters }{ \bbl at KVP@onchar\space}%
-    \ifin@
-      \directlua{
-        Babel.locale_props[\the\localeid].letters = true
-      }%
-    \fi
-    \bbl at xin@{ ids }{ \bbl at KVP@onchar\space}%
-    \ifin@
-      \ifx\bbl at starthyphens\@undefined % Needed if no explicit selection
-        \AddBabelHook{babel-onchar}{beforestart}{{\bbl at starthyphens}}%
-      \fi
-      \bbl at exp{\\\bbl at add\\\bbl at starthyphens
-        {\\\bbl at patterns@lua{\languagename}}}%
-      \directlua{
-        if Babel.script_blocks['\bbl at cl{sbcp}'] then
-          Babel.loc_to_scr[\the\localeid] = Babel.script_blocks['\bbl at cl{sbcp}']
-          Babel.locale_props[\the\localeid].lg = \the\@nameuse{l@\languagename}\space
-        end
-      }%
-    \fi
-    \bbl at xin@{ fonts }{ \bbl at KVP@onchar\space}%
-    \ifin@
-      \bbl at ifunset{bbl at lsys@\languagename}{\bbl at provide@lsys{\languagename}}{}%
-      \bbl at ifunset{bbl at wdir@\languagename}{\bbl at provide@dirs{\languagename}}{}%
-      \directlua{
-        if Babel.script_blocks['\bbl at cl{sbcp}'] then
-          Babel.loc_to_scr[\the\localeid] =
-            Babel.script_blocks['\bbl at cl{sbcp}']
-        end}%
-      \ifx\bbl at mapselect\@undefined  % TODO. almost the same as mapfont
-        \AtBeginDocument{%
-          \bbl at patchfont{{\bbl at mapselect}}%
-          {\selectfont}}%
-        \def\bbl at mapselect{%
-          \let\bbl at mapselect\relax
-          \edef\bbl at prefontid{\fontid\font}}%
-        \def\bbl at mapdir##1{%
-          \begingroup
-            \setbox\z@\hbox{% Force text mode
-              \def\languagename{##1}%
-              \let\bbl at ifrestoring\@firstoftwo % To avoid font warning
-              \bbl at switchfont
-              \ifnum\fontid\font>\z@ % A hack, for the pgf nullfont hack
-                \directlua{
-                  Babel.locale_props[\the\csname bbl at id@@##1\endcsname]%
-                          ['/\bbl at prefontid'] = \fontid\font\space}%
-              \fi}%
-          \endgroup}%
-      \fi
-      \bbl at exp{\\\bbl at add\\\bbl at mapselect{\\\bbl at mapdir{\languagename}}}%
-    \fi
-    % TODO - catch non-valid values
-  \fi
-  % == mapfont ==
-  % For bidi texts, to switch the font based on direction
-  \ifx\bbl at KVP@mapfont\@nnil\else
-    \bbl at ifsamestring{\bbl at KVP@mapfont}{direction}{}%
-      {\bbl at error{unknown-mapfont}{}{}{}}%
-    \bbl at ifunset{bbl at lsys@\languagename}{\bbl at provide@lsys{\languagename}}{}%
-    \bbl at ifunset{bbl at wdir@\languagename}{\bbl at provide@dirs{\languagename}}{}%
-    \ifx\bbl at mapselect\@undefined % TODO. See onchar.
-      \AtBeginDocument{%
-        \bbl at patchfont{{\bbl at mapselect}}%
-        {\selectfont}}%
-      \def\bbl at mapselect{%
-        \let\bbl at mapselect\relax
-        \edef\bbl at prefontid{\fontid\font}}%
-      \def\bbl at mapdir##1{%
-        {\def\languagename{##1}%
-         \let\bbl at ifrestoring\@firstoftwo % avoid font warning
-         \bbl at switchfont
-         \directlua{Babel.fontmap
-           [\the\csname bbl at wdir@##1\endcsname]%
-           [\bbl at prefontid]=\fontid\font}}}%
-    \fi
-    \bbl at exp{\\\bbl at add\\\bbl at mapselect{\\\bbl at mapdir{\languagename}}}%
-  \fi
   % == Line breaking: intraspace, intrapenalty ==
   % For CJK, East Asian, Southeast Asian, if interspace in ini
   \ifx\bbl at KVP@intraspace\@nnil\else % We can override the ini or set
@@ -10295,24 +10304,6 @@
     \bbl at csarg\edef{intsp@#2}{\bbl at KVP@intraspace}%
   \fi
   \bbl at provide@intraspace
-  % == Line breaking: CJK quotes ==
-  \ifcase\bbl at engine\or
-    \bbl at xin@{/c}{/\bbl at cl{lnbrk}}%
-    \ifin@
-      \bbl at ifunset{bbl at quote@\languagename}{}%
-        {\directlua{
-           Babel.locale_props[\the\localeid].cjk_quotes = {}
-           local cs = 'op'
-           for c in string.utfvalues(%
-               [[\csname bbl at quote@\languagename\endcsname]]) do
-             if Babel.cjk_characters[c].c == 'qu' then
-               Babel.locale_props[\the\localeid].cjk_quotes[c] = cs
-             end
-             cs = ( cs == 'op') and 'cl' or 'op'
-           end
-        }}%
-    \fi
-  \fi
   % == Line breaking: justification ==
   \ifx\bbl at KVP@justification\@nnil\else
      \let\bbl at KVP@linebreaking\bbl at KVP@justification
@@ -10328,6 +10319,7 @@
   \bbl at xin@{/e}{/\bbl at cl{lnbrk}}%
   \ifin@\else\bbl at xin@{/k}{/\bbl at cl{lnbrk}}\fi
   \ifin@\bbl at arabicjust\fi
+  % WIP
   \bbl at xin@{/p}{/\bbl at cl{lnbrk}}%
   \ifin@\AtBeginDocument{\@nameuse{bbl at tibetanjust}}\fi
   % == Line breaking: hyphenate.other.(locale|script) ==
@@ -11206,11 +11198,8 @@
        \ifx\bbl at savetoday\@empty
          \bbl at exp{% TODO. Move to a better place.
            \\\AfterBabelCommands{%
-             \def\<\languagename date>{\\\protect\<\languagename date >}%
-             \\\newcommand\<\languagename date >[4][]{%
-               \\\bbl at usedategrouptrue
-               \<bbl at ensure@\languagename>{%
-                 \\\localedate[####1]{####2}{####3}{####4}}}}%
+             \gdef\<\languagename date>{\\\protect\<\languagename date >}%
+             \gdef\<\languagename date >{\\\bbl at printdate{\languagename}}}%
            \def\\\bbl at savetoday{%
              \\\SetString\\\today{%
                \<\languagename date>[convert]%
@@ -11217,8 +11206,34 @@
                   {\\\the\year}{\\\the\month}{\\\the\day}}}}%
        \fi}%
       {}}}
+\def\bbl at printdate#1{%
+  \@ifnextchar[{\bbl at printdate@i{#1}}{\bbl at printdate@i{#1}[]}}
+\def\bbl at printdate@i#1[#2]#3#4#5{%
+  \bbl at usedategrouptrue
+  \@nameuse{bbl at ensure@#1}{\localedate[#2]{#3}{#4}{#5}}}
 %    \end{macrocode}
 %
+% \subsection{French spacing (again)}
+% 
+% For the following declarations, see issue \#240. |\nonfrenchspacing|
+% is set by |document| too early, so it’s a hack.
+%
+%    \begin{macrocode}
+\AddToHook{begindocument/before}{%
+  \let\bbl at normalsf\normalsfcodes
+  \let\normalsfcodes\relax}
+\AtBeginDocument{%
+  \ifx\bbl at normalsf\@empty
+    \ifnum\sfcode`\.=\@m
+      \let\normalsfcodes\frenchspacing
+    \else
+      \let\normalsfcodes\nonfrenchspacing
+    \fi
+  \else
+    \let\normalsfcodes\bbl at normalsf
+  \fi}
+%    \end{macrocode}
+%
 % \textbf{Dates} will require some macros for the basic formatting.
 % They may be redefined by language, so ``semi-public'' names (camel
 % case) are used. Oddly enough, the CLDR places particles like “de”
@@ -11512,6 +11527,11 @@
 % The parser for |casing| and |casing.|\meta{variant}. 
 %
 %    \begin{macrocode}
+\ifcase\bbl at engine % Converts utf8 to its code (expandable)
+  \def\bbl at utftocode#1{\the\numexpr\decode at UTFviii#1\relax}
+\else
+  \def\bbl at utftocode#1{\expandafter`\string#1}
+\fi
 \def\bbl at casemapping#1#2#3{% 1:variant
   \def\bbl at tempa##1 ##2{% Loop
     \bbl at casemapping@i{##1}%
@@ -11584,36 +11604,6 @@
 \@namedef{bbl at info@extension.x.tag.bcp47}{extx}
 %    \end{macrocode}
 %
-% \LaTeX{} needs to know the BCP 47 codes for some features. For that,
-% it expects |\BCPdata| to be defined. While |language|, |region|,
-% |script|, and |variant| are recognized, |extension.<s>| for
-% singletons may change.
-%
-%    \begin{macrocode}
-\ifcase\bbl at engine % Converts utf8 to its code (expandable)
-  \def\bbl at utftocode#1{\the\numexpr\decode at UTFviii#1\relax}
-\else
-  \def\bbl at utftocode#1{\expandafter`\string#1}
-\fi
-% Still somewhat hackish. WIP. Note |\str_if_eq:nnTF| is fully
-% expandable (|\bbl at ifsamestring| isn’t). The argument is the prefix to
-% tag.bcp47. Can be prece
-\providecommand\BCPdata{}
-\ifx\renewcommand\@undefined\else % For plain. TODO. It’s a quick fix
-  \renewcommand\BCPdata[1]{\bbl at bcpdata@i#1\@empty}
-  \def\bbl at bcpdata@i#1#2#3#4#5#6\@empty{%
-    \@nameuse{str_if_eq:nnTF}{#1#2#3#4#5}{main.}%
-      {\bbl at bcpdata@ii{#6}\bbl at main@language}%
-      {\bbl at bcpdata@ii{#1#2#3#4#5#6}\languagename}}%
-  \def\bbl at bcpdata@ii#1#2{%
-    \bbl at ifunset{bbl at info@#1.tag.bcp47}%
-      {\bbl at error{unknown-ini-field}{#1}{}{}}%
-      {\bbl at ifunset{bbl@\csname bbl at info@#1.tag.bcp47\endcsname @#2}{}%
-        {\bbl at cs{\csname bbl at info@#1.tag.bcp47\endcsname @#2}}}}
-\fi
-\@namedef{bbl at info@casing.tag.bcp47}{casing}
-%    \end{macrocode}
-%
 % With version 3.75 |\BabelEnsureInfo| is executed always, but there is
 % an option to disable it.
 %
@@ -11667,6 +11657,67 @@
   \typeout{*******}}
 %    \end{macrocode}
 %
+% \subsection{BCP-47 related commands}
+%
+%    \begin{macrocode}
+\newif\ifbbl at bcpallowed
+\bbl at bcpallowedfalse
+\def\bbl at provide@locale{%
+  \ifx\babelprovide\@undefined
+    \bbl at error{base-on-the-fly}{}{}{}%
+  \fi
+  \let\bbl at auxname\languagename % Still necessary.
+  \bbl at ifunset{bbl at bcp@map@\languagename}{}% Move uplevel??
+    {\edef\languagename{\@nameuse{bbl at bcp@map@\languagename}}}%
+  \ifbbl at bcpallowed
+    \expandafter\ifx\csname date\languagename\endcsname\relax
+      \expandafter
+      \bbl at bcplookup\languagename-\@empty-\@empty-\@empty\@@
+      \ifx\bbl at bcp\relax\else  % Returned by \bbl at bcplookup
+        \edef\languagename{\bbl at bcp@prefix\bbl at bcp}%
+        \edef\localename{\bbl at bcp@prefix\bbl at bcp}%
+        \expandafter\ifx\csname date\languagename\endcsname\relax
+          \let\bbl at initoload\bbl at bcp
+          \bbl at exp{\\\babelprovide[\bbl at autoload@bcpoptions]{\languagename}}%
+          \let\bbl at initoload\relax
+        \fi
+        \bbl at csarg\xdef{bcp at map@\bbl at bcp}{\localename}%
+      \fi
+    \fi
+  \fi
+  \expandafter\ifx\csname date\languagename\endcsname\relax
+    \IfFileExists{babel-\languagename.tex}%
+      {\bbl at exp{\\\babelprovide[\bbl at autoload@options]{\languagename}}}%
+      {}%
+  \fi}
+%    \end{macrocode}
+%
+% \LaTeX{} needs to know the BCP 47 codes for some features. For that,
+% it expects |\BCPdata| to be defined. While |language|, |region|,
+% |script|, and |variant| are recognized, |extension.<s>| for
+% singletons may change.
+%
+% Still somewhat hackish. WIP. Note |\str_if_eq:nnTF| is fully
+% expandable (|\bbl at ifsamestring| isn’t). The argument is the prefix to
+% tag.bcp47. Can be prece
+%
+%    \begin{macrocode}
+\providecommand\BCPdata{}
+\ifx\renewcommand\@undefined\else % For plain. TODO. It’s a quick fix
+  \renewcommand\BCPdata[1]{\bbl at bcpdata@i#1\@empty}
+  \def\bbl at bcpdata@i#1#2#3#4#5#6\@empty{%
+    \@nameuse{str_if_eq:nnTF}{#1#2#3#4#5}{main.}%
+      {\bbl at bcpdata@ii{#6}\bbl at main@language}%
+      {\bbl at bcpdata@ii{#1#2#3#4#5#6}\languagename}}%
+  \def\bbl at bcpdata@ii#1#2{%
+    \bbl at ifunset{bbl at info@#1.tag.bcp47}%
+      {\bbl at error{unknown-ini-field}{#1}{}{}}%
+      {\bbl at ifunset{bbl@\csname bbl at info@#1.tag.bcp47\endcsname @#2}{}%
+        {\bbl at cs{\csname bbl at info@#1.tag.bcp47\endcsname @#2}}}}
+\fi
+\@namedef{bbl at info@casing.tag.bcp47}{casing}
+%    \end{macrocode}
+%
 % \section{Adjusting the Babel behavior}
 %
 % A generic high level interface is provided to adjust some global
@@ -11952,11 +12003,6 @@
 % when |\begin{document}| is executed, so we need to postpone the
 % different redefinition.
 %
-%    \begin{macrocode}
-  \AtBeginDocument{%
-    \@ifpackageloaded{natbib}{%
-%    \end{macrocode}
-%
 % Notice that we use |\def| here instead of |\bbl at redefine| because
 % |\org@@citex| is already defined and we don't want to overwrite
 % that definition (it would result in parameter stack overflow
@@ -11966,6 +12012,8 @@
 % doesn't seem fixable in a simple way. Just load \pkg{natbib} before.)
 %
 %    \begin{macrocode}
+  \AtBeginDocument{%
+    \@ifpackageloaded{natbib}{%
     \def\@citex[#1][#2]#3{%
       \@safe at activestrue\edef\bbl at tempa{#3}\@safe at activesfalse
       \org@@citex[#1][#2]{\bbl at tempa}}%
@@ -12062,6 +12110,44 @@
 \fi
 %    \end{macrocode}
 %
+% \subsection{Layout}
+%
+%    \begin{macrocode}
+\newcommand\BabelPatchSection[1]{%
+  \@ifundefined{#1}{}{%
+    \bbl at exp{\let\<bbl at ss@#1>\<#1>}%
+    \@namedef{#1}{%
+      \@ifstar{\bbl at presec@s{#1}}%
+              {\@dblarg{\bbl at presec@x{#1}}}}}}
+\def\bbl at presec@x#1[#2]#3{%
+  \bbl at exp{%
+    \\\select at language@x{\bbl at main@language}%
+    \\\bbl at cs{sspre@#1}%
+    \\\bbl at cs{ss@#1}%
+      [\\\foreignlanguage{\languagename}{\unexpanded{#2}}]%
+      {\\\foreignlanguage{\languagename}{\unexpanded{#3}}}%
+    \\\select at language@x{\languagename}}}
+\def\bbl at presec@s#1#2{%
+  \bbl at exp{%
+    \\\select at language@x{\bbl at main@language}%
+    \\\bbl at cs{sspre@#1}%
+    \\\bbl at cs{ss@#1}*%
+      {\\\foreignlanguage{\languagename}{\unexpanded{#2}}}%
+    \\\select at language@x{\languagename}}}
+\IfBabelLayout{sectioning}%
+  {\BabelPatchSection{part}%
+   \BabelPatchSection{chapter}%
+   \BabelPatchSection{section}%
+   \BabelPatchSection{subsection}%
+   \BabelPatchSection{subsubsection}%
+   \BabelPatchSection{paragraph}%
+   \BabelPatchSection{subparagraph}%
+   \def\babel at toc#1{%
+     \select at language@x{\bbl at main@language}}}{}
+\IfBabelLayout{captions}%
+  {\BabelPatchSection{caption}}{}
+%    \end{macrocode}
+%
 % \subsection{Marks}
 %
 % \macro{\markright}
@@ -12724,6 +12810,7 @@
   \bbl at load@language{hebrew}}
 \DeclareOption{hungarian}{\bbl at try@load at lang{}{magyar}{}}
 \DeclareOption{lowersorbian}{\bbl at try@load at lang{}{lsorbian}{}}
+% \DeclareOption{northernkurdish}{\bbl at try@load at lang{}{kurmanji}{}}
 \DeclareOption{polutonikogreek}{%
   \bbl at try@load at lang{}{greek}{\languageattribute{greek}{polutoniko}}}
 \DeclareOption{russian}{\bbl at try@load at lang{}{russianb}{}}
@@ -12763,16 +12850,26 @@
 % above, the names of the option and the file are the same. We first
 % pre-process the class and package options to determine the main
 % language, which is processed in the third ‘main’ pass,
-% \textit{except} if all files are \texttt{ldf} \textit{and} there is no |main|
-% key. In the latter case (|\bbl at opt@main| is still |\@nnil|), the
-% traditional way to set the main language is kept — the last loaded is
-% the main language.
+% \textit{except} if all files are \texttt{ldf} \textit{and} there is
+% no |main| key. In the latter case (|\bbl at opt@main| is still
+% |\@nnil|), the traditional way to set the main language is kept — the
+% last loaded is the main language.
 %
+% For efficiency, first preprocess the class options to remove those
+% with |=|, which are becoming increasingly frequent (no language
+% should contain this character).
+%
 %    \begin{macrocode}
+\def\bbl at tempf{,}
+\bbl at foreach\@raw at classoptionslist{%
+  \in@{=}{#1}%
+  \ifin@\else
+    \edef\bbl at tempf{\bbl at tempf\zap at space#1 \@empty,}%
+  \fi}
 \ifx\bbl at opt@main\@nnil
   \ifnum\bbl at iniflag>\z@  % if all ldf's: set implicitly, no main pass
     \let\bbl at tempb\@empty
-    \edef\bbl at tempa{\@classoptionslist,\bbl at language@opts}%
+    \edef\bbl at tempa{\bbl at tempf,\bbl at language@opts}%
     \bbl at foreach\bbl at tempa{\edef\bbl at tempb{#1,\bbl at tempb}}%
     \bbl at foreach\bbl at tempb{%    \bbl at tempb is a reversed list
       \ifx\bbl at opt@main\@nnil % ie, if not yet assigned
@@ -12816,11 +12913,11 @@
     \else                      % + * (other = ini)
       \DeclareOption{#1}{%
         \bbl at ldfinit
-        \babelprovide[import]{#1}%
+        \babelprovide[@import]{#1}% %%%%%
         \bbl at afterldf{}}%
     \fi
   \fi}
-\bbl at foreach\@classoptionslist{%
+\bbl at foreach\bbl at tempf{%
   \def\bbl at tempa{#1}%
   \ifx\bbl at tempa\bbl at opt@main\else
     \ifnum\bbl at iniflag<\tw@    % 0 ø (other = ldf)
@@ -12833,7 +12930,7 @@
        \IfFileExists{babel-#1.tex}%
          {\DeclareOption{#1}{%
             \bbl at ldfinit
-            \babelprovide[import]{#1}%
+            \babelprovide[@import]{#1}%  %%%%%%
             \bbl at afterldf{}}}%
          {}%
      \fi
@@ -12840,14 +12937,17 @@
   \fi}
 %    \end{macrocode}
 %
-% And we are done, because all options for this pass has been
-% declared. Those already processed in the first pass are just
-% ignored.
+% And we are done, because all options for this pass has been declared.
+% Those already processed in the first pass are just ignored. There is
+% still room for last minute changes with a \LaTeX{} hook (not a
+% \Babel{} one).
 %
 % The options have to be processed in the order in which the user
 % specified them (but remember class options are processes before):
 %
 %    \begin{macrocode}
+\NewHook{babel/presets}
+\UseHook{babel/presets}
 \def\AfterBabelLanguage#1{%
   \bbl at ifsamestring\CurrentOption{#1}{\global\bbl at add\bbl at afterlang}{}}
 \DeclareOption*{}
@@ -12867,7 +12967,7 @@
 %    \begin{macrocode}
 \bbl at trace{Option 'main'}
 \ifx\bbl at opt@main\@nnil
-  \edef\bbl at tempa{\@classoptionslist,\bbl at language@opts}
+  \edef\bbl at tempa{\bbl at tempf,\bbl at language@opts}
   \let\bbl at tempc\@empty
   \edef\bbl at templ{,\bbl at loaded,}
   \edef\bbl at templ{\expandafter\strip at prefix\meaning\bbl at templ}
@@ -12891,7 +12991,9 @@
     \bbl at ldfinit
     \let\CurrentOption\bbl at opt@main
     \bbl at exp{%  \bbl at opt@provide = empty if *
-       \\\babelprovide[\bbl at opt@provide,import,main]{\bbl at opt@main}}%
+       \\\babelprovide
+         [\bbl at opt@provide, at import,main]%  %%%%%
+         {\bbl at opt@main}}%
     \bbl at afterldf{}
     \DeclareOption{\bbl at opt@main}{}
   \else % case 0,2 (main is ldf)
@@ -13514,7 +13616,8 @@
 %
 % Add the bidi handler just before luaoftload, which is loaded by default
 % by LaTeX. Just in case, consider the possibility it has not been
-% loaded. First, a couple of definitions related to bidi [misplaced].
+% loaded. First, a couple of definitions related to bidi (although
+% |default| also applies to \pdftex).
 %
 %    \begin{macrocode}
 %<<*More package options>>
@@ -13761,7 +13864,7 @@
 %
 % \macro{\BabelFootnote}
 %
-% Footnotes
+% Footnotes.
 %
 %    \begin{macrocode}
 %<<*Footnote changes>>
@@ -13890,7 +13993,7 @@
 \def\bbl at provide@extra#1{}
 %    \end{macrocode}
 %
-% \section{Support for interchar}
+% \subsection{Support for interchar}
 %
 % \xetex{} reserves some values for CJK (although they are not set in
 % \textsc{xelatex}), so we make sure they are skipped. Define some user
@@ -14457,6 +14560,22 @@
       callback.register('process_input_buffer',Babel.callback)
     end
   end
+  Babel.linebreaking = Babel.linebreaking or {}
+  Babel.linebreaking.before = {}
+  Babel.linebreaking.after = {}
+  Babel.locale = {}
+  function Babel.linebreaking.add_before(func, pos)
+    tex.print([[\noexpand\csname bbl at luahyphenate\endcsname]])
+    if pos == nil then
+      table.insert(Babel.linebreaking.before, func)
+    else
+      table.insert(Babel.linebreaking.before, pos, func)
+    end
+  end
+  function Babel.linebreaking.add_after(func)
+    tex.print([[\noexpand\csname bbl at luahyphenate\endcsname]])
+    table.insert(Babel.linebreaking.after, func)
+  end
   function Babel.addpatterns(pp, lg)
     local lg = lang.new(lg)
     local pats = lang.patterns(lg) or ''
@@ -14523,9 +14642,9 @@
          str:find( [[\string\babelsublr]] ) then
      str = str:gsub( [[\string\babelsublr%s*(%b{})]],
                      function(m) return m:sub(2,-2) end )
-   end
-   return str 
-end
+     end
+     return str 
+  end
 }
 \endgroup
 \ifx\newattribute\@undefined\else % Test for plain
@@ -14630,25 +14749,6 @@
 % not touched. See Unicode UAX 14.
 %
 %    \begin{macrocode}
-% TODO - to a lua file -- or a logical place
-\directlua{% DL5
-  Babel.linebreaking = Babel.linebreaking or {}
-  Babel.linebreaking.before = {}
-  Babel.linebreaking.after = {}
-  Babel.locale = {} % Free to use, indexed by \localeid
-  function Babel.linebreaking.add_before(func, pos)
-    tex.print([[\noexpand\csname bbl at luahyphenate\endcsname]])
-    if pos == nil then
-      table.insert(Babel.linebreaking.before, func)
-    else
-      table.insert(Babel.linebreaking.before, pos, func)
-    end
-  end
-  function Babel.linebreaking.add_after(func)
-    tex.print([[\noexpand\csname bbl at luahyphenate\endcsname]])
-    table.insert(Babel.linebreaking.after, func)
-  end
-}
 \def\bbl at intraspace#1 #2 #3\@@{%
   \directlua{
     Babel.intraspaces = Babel.intraspaces or {}
@@ -15901,6 +16001,115 @@
     \fi\fi}
 \fi
 \def\bbl at provide@extra#1{%
+   % == onchar ==
+  \ifx\bbl at KVP@onchar\@nnil\else
+    \bbl at luahyphenate
+    \bbl at exp{%
+      \\\AddToHook{env/document/before}{{\\\select at language{#1}{}}}}%
+    \directlua{
+      if Babel.locale_mapped == nil then
+        Babel.locale_mapped = true
+        Babel.linebreaking.add_before(Babel.locale_map, 1)
+        Babel.loc_to_scr = {}
+        Babel.chr_to_loc = Babel.chr_to_loc or {}
+      end
+      Babel.locale_props[\the\localeid].letters = false
+    }%
+    \bbl at xin@{ letters }{ \bbl at KVP@onchar\space}%
+    \ifin@
+      \directlua{
+        Babel.locale_props[\the\localeid].letters = true
+      }%
+    \fi
+    \bbl at xin@{ ids }{ \bbl at KVP@onchar\space}%
+    \ifin@
+      \ifx\bbl at starthyphens\@undefined % Needed if no explicit selection
+        \AddBabelHook{babel-onchar}{beforestart}{{\bbl at starthyphens}}%
+      \fi
+      \bbl at exp{\\\bbl at add\\\bbl at starthyphens
+        {\\\bbl at patterns@lua{\languagename}}}%
+      \directlua{
+        if Babel.script_blocks['\bbl at cl{sbcp}'] then
+          Babel.loc_to_scr[\the\localeid] = Babel.script_blocks['\bbl at cl{sbcp}']
+          Babel.locale_props[\the\localeid].lg = \the\@nameuse{l@\languagename}\space
+        end
+      }%
+    \fi
+    \bbl at xin@{ fonts }{ \bbl at KVP@onchar\space}%
+    \ifin@
+      \bbl at ifunset{bbl at lsys@\languagename}{\bbl at provide@lsys{\languagename}}{}%
+      \bbl at ifunset{bbl at wdir@\languagename}{\bbl at provide@dirs{\languagename}}{}%
+      \directlua{
+        if Babel.script_blocks['\bbl at cl{sbcp}'] then
+          Babel.loc_to_scr[\the\localeid] =
+            Babel.script_blocks['\bbl at cl{sbcp}']
+        end}%
+      \ifx\bbl at mapselect\@undefined  % TODO. almost the same as mapfont
+        \AtBeginDocument{%
+          \bbl at patchfont{{\bbl at mapselect}}%
+          {\selectfont}}%
+        \def\bbl at mapselect{%
+          \let\bbl at mapselect\relax
+          \edef\bbl at prefontid{\fontid\font}}%
+        \def\bbl at mapdir##1{%
+          \begingroup
+            \setbox\z@\hbox{% Force text mode
+              \def\languagename{##1}%
+              \let\bbl at ifrestoring\@firstoftwo % To avoid font warning
+              \bbl at switchfont
+              \ifnum\fontid\font>\z@ % A hack, for the pgf nullfont hack
+                \directlua{
+                  Babel.locale_props[\the\csname bbl at id@@##1\endcsname]%
+                          ['/\bbl at prefontid'] = \fontid\font\space}%
+              \fi}%
+          \endgroup}%
+      \fi
+      \bbl at exp{\\\bbl at add\\\bbl at mapselect{\\\bbl at mapdir{\languagename}}}%
+    \fi
+    % TODO - catch non-valid values
+  \fi
+  % == mapfont ==
+  % For bidi texts, to switch the font based on direction
+  \ifx\bbl at KVP@mapfont\@nnil\else
+    \bbl at ifsamestring{\bbl at KVP@mapfont}{direction}{}%
+      {\bbl at error{unknown-mapfont}{}{}{}}%
+    \bbl at ifunset{bbl at lsys@\languagename}{\bbl at provide@lsys{\languagename}}{}%
+    \bbl at ifunset{bbl at wdir@\languagename}{\bbl at provide@dirs{\languagename}}{}%
+    \ifx\bbl at mapselect\@undefined % TODO. See onchar.
+      \AtBeginDocument{%
+        \bbl at patchfont{{\bbl at mapselect}}%
+        {\selectfont}}%
+      \def\bbl at mapselect{%
+        \let\bbl at mapselect\relax
+        \edef\bbl at prefontid{\fontid\font}}%
+      \def\bbl at mapdir##1{%
+        {\def\languagename{##1}%
+         \let\bbl at ifrestoring\@firstoftwo % avoid font warning
+         \bbl at switchfont
+         \directlua{Babel.fontmap
+           [\the\csname bbl at wdir@##1\endcsname]%
+           [\bbl at prefontid]=\fontid\font}}}%
+    \fi
+    \bbl at exp{\\\bbl at add\\\bbl at mapselect{\\\bbl at mapdir{\languagename}}}%
+  \fi
+  % == Line breaking: CJK quotes ==
+  \ifcase\bbl at engine\or
+    \bbl at xin@{/c}{/\bbl at cl{lnbrk}}%
+    \ifin@
+      \bbl at ifunset{bbl at quote@\languagename}{}%
+        {\directlua{
+           Babel.locale_props[\the\localeid].cjk_quotes = {}
+           local cs = 'op'
+           for c in string.utfvalues(%
+               [[\csname bbl at quote@\languagename\endcsname]]) do
+             if Babel.cjk_characters[c].c == 'qu' then
+               Babel.locale_props[\the\localeid].cjk_quotes[c] = cs
+             end
+             cs = ( cs == 'op') and 'cl' or 'op'
+           end
+        }}%
+    \fi
+  \fi
   % == Counters: mapdigits ==
   % Native digits
   \ifx\bbl at KVP@mapdigits\@nnil\else

Modified: trunk/Master/texmf-dist/source/latex/babel/babel.ins
===================================================================
--- trunk/Master/texmf-dist/source/latex/babel/babel.ins	2024-10-20 20:22:44 UTC (rev 72606)
+++ trunk/Master/texmf-dist/source/latex/babel/babel.ins	2024-10-20 20:23:26 UTC (rev 72607)
@@ -26,7 +26,7 @@
 %% and covered by LPPL is defined by the unpacking scripts (with
 %% extension .ins) which are part of the distribution.
 %%
-\def\filedate{2024/10/05}
+\def\filedate{2024/10/20}
 \def\batchfile{babel.ins}
 \input docstrip.tex
 
@@ -174,9 +174,6 @@
 
 % Compatibility files
 
-\let\minusOption\bblMinus
-\let\plusOption\bblPlus
-
 \def\compatfile#1{\file{#1.sty}{\from{bbcompat.dtx}{styfile,#1}}}
 
 \generate{%

Modified: trunk/Master/texmf-dist/source/latex/babel/bbcompat.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/babel/bbcompat.dtx	2024-10-20 20:22:44 UTC (rev 72606)
+++ trunk/Master/texmf-dist/source/latex/babel/bbcompat.dtx	2024-10-20 20:23:26 UTC (rev 72607)
@@ -30,7 +30,7 @@
 %
 % \iffalse
 %<*dtx>
-\ProvidesFile{bbcompat.dtx}[2024/10/05 v24.]
+\ProvidesFile{bbcompat.dtx}[2024/10/20 v24.]
 %</dtx>
 %
 %% File 'bbcompat.dtx'

Modified: trunk/Master/texmf-dist/source/latex/babel/locale.zip
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/tex/generic/babel/babel.def
===================================================================
--- trunk/Master/texmf-dist/tex/generic/babel/babel.def	2024-10-20 20:22:44 UTC (rev 72606)
+++ trunk/Master/texmf-dist/tex/generic/babel/babel.def	2024-10-20 20:23:26 UTC (rev 72607)
@@ -39,7 +39,7 @@
     \wlog{File: #1 #4 #3 <#2>}%
     \let\ProvidesFile\@undefined}
 \fi
-\ProvidesFile{babel.def}[2024/10/05 v24.11 Babel common definitions]
+\ProvidesFile{babel.def}[2024/10/20 v24.12 Babel common definitions]
 \ifx\AtBeginDocument\@undefined
   \def\@empty{}
 \def\loadlocalcfg#1{%
@@ -595,8 +595,8 @@
     \toks@\expandafter{\bbl at tempc#3}%
     \expandafter\edef\csname extras\languagename\endcsname{\the\toks@}%
   \fi}
-\def\bbl at version{24.11}
-\def\bbl at date{2024/10/05}
+\def\bbl at version{24.12}
+\def\bbl at date{2024/10/20}
 \ifx\language\@undefined
   \csname newcount\endcsname\language
 \fi
@@ -752,8 +752,6 @@
   \fi}
 \let\bbl at restorelastskip\relax
 \let\bbl at savelastskip\relax
-\newif\ifbbl at bcpallowed
-\bbl at bcpallowedfalse
 \def\select at language#1{% from set@, babel at aux, babel at toc
   \ifx\bbl at selectorname\@empty
     \def\bbl at selectorname{select}%
@@ -1047,13 +1045,91 @@
      preloaded for \bbl at nulllanguage\space instead}}
 \let\bbl at usehooks\@gobbletwo
 \ifx\bbl at onlyswitch\@empty\endinput\fi
-  % Here ended switch.def
+\bbl at trace{Defining babelensure}
+\newcommand\babelensure[2][]{%
+  \AddBabelHook{babel-ensure}{afterextras}{%
+    \ifcase\bbl at select@type
+      \bbl at cl{e}%
+    \fi}%
+  \begingroup
+    \let\bbl at ens@include\@empty
+    \let\bbl at ens@exclude\@empty
+    \def\bbl at ens@fontenc{\relax}%
+    \def\bbl at tempb##1{%
+      \ifx\@empty##1\else\noexpand##1\expandafter\bbl at tempb\fi}%
+    \edef\bbl at tempa{\bbl at tempb#1\@empty}%
+    \def\bbl at tempb##1=##2\@@{\@namedef{bbl at ens@##1}{##2}}%
+    \bbl at foreach\bbl at tempa{\bbl at tempb##1\@@}%
+    \def\bbl at tempc{\bbl at ensure}%
+    \expandafter\bbl at add\expandafter\bbl at tempc\expandafter{%
+      \expandafter{\bbl at ens@include}}%
+    \expandafter\bbl at add\expandafter\bbl at tempc\expandafter{%
+      \expandafter{\bbl at ens@exclude}}%
+    \toks@\expandafter{\bbl at tempc}%
+    \bbl at exp{%
+  \endgroup
+  \def\<bbl at e@#2>{\the\toks@{\bbl at ens@fontenc}}}}
+\def\bbl at ensure#1#2#3{% 1: include 2: exclude 3: fontenc
+  \def\bbl at tempb##1{% elt for (excluding) \bbl at captionslist list
+    \ifx##1\@undefined % 3.32 - Don't assume the macro exists
+      \edef##1{\noexpand\bbl at nocaption
+        {\bbl at stripslash##1}{\languagename\bbl at stripslash##1}}%
+    \fi
+    \ifx##1\@empty\else
+      \in@{##1}{#2}%
+      \ifin@\else
+        \bbl at ifunset{bbl at ensure@\languagename}%
+          {\bbl at exp{%
+            \\\DeclareRobustCommand\<bbl at ensure@\languagename>[1]{%
+              \\\foreignlanguage{\languagename}%
+              {\ifx\relax#3\else
+                \\\fontencoding{#3}\\\selectfont
+               \fi
+               ########1}}}}%
+          {}%
+        \toks@\expandafter{##1}%
+        \edef##1{%
+           \bbl at csarg\noexpand{ensure@\languagename}%
+           {\the\toks@}}%
+      \fi
+      \expandafter\bbl at tempb
+    \fi}%
+  \expandafter\bbl at tempb\bbl at captionslist\today\@empty
+  \def\bbl at tempa##1{% elt for include list
+    \ifx##1\@empty\else
+      \bbl at csarg\in@{ensure@\languagename\expandafter}\expandafter{##1}%
+      \ifin@\else
+        \bbl at tempb##1\@empty
+      \fi
+      \expandafter\bbl at tempa
+    \fi}%
+  \bbl at tempa#1\@empty}
+\def\bbl at captionslist{%
+  \prefacename\refname\abstractname\bibname\chaptername\appendixname
+  \contentsname\listfigurename\listtablename\indexname\figurename
+  \tablename\partname\enclname\ccname\headtoname\pagename\seename
+  \alsoname\proofname\glossaryname}
+\bbl at trace{Short tags}
+\newcommand\babeltags[1]{%
+  \edef\bbl at tempa{\zap at space#1 \@empty}%
+  \def\bbl at tempb##1=##2\@@{%
+    \edef\bbl at tempc{%
+      \noexpand\newcommand
+      \expandafter\noexpand\csname ##1\endcsname{%
+        \noexpand\protect
+        \expandafter\noexpand\csname otherlanguage*\endcsname{##2}}
+      \noexpand\newcommand
+      \expandafter\noexpand\csname text##1\endcsname{%
+        \noexpand\foreignlanguage{##2}}}
+    \bbl at tempc}%
+  \bbl at for\bbl at tempa\bbl at tempa{%
+    \expandafter\bbl at tempb\bbl at tempa\@@}}
+\bbl at trace{Compatibility with language.def}
 \ifx\directlua\@undefined\else
   \ifx\bbl at luapatterns\@undefined
     \input luababel.def
   \fi
 \fi
-\bbl at trace{Compatibility with language.def}
 \ifx\bbl at languages\@undefined
   \ifx\directlua\@undefined
     \openin1 = language.def % TODO. Remove hardcoded number
@@ -1086,28 +1162,6 @@
        \xdef#1{\the\toks@}}%
     \fi
   \fi}
-\def\bbl at withactive#1#2{%
-  \begingroup
-    \lccode`~=`#2\relax
-    \lowercase{\endgroup#1~}}
-\def\bbl at redefine#1{%
-  \edef\bbl at tempa{\bbl at stripslash#1}%
-  \expandafter\let\csname org@\bbl at tempa\endcsname#1%
-  \expandafter\def\csname\bbl at tempa\endcsname}
-\@onlypreamble\bbl at redefine
-\def\bbl at redefine@long#1{%
-  \edef\bbl at tempa{\bbl at stripslash#1}%
-  \expandafter\let\csname org@\bbl at tempa\endcsname#1%
-  \long\expandafter\def\csname\bbl at tempa\endcsname}
-\@onlypreamble\bbl at redefine@long
-\def\bbl at redefinerobust#1{%
-  \edef\bbl at tempa{\bbl at stripslash#1}%
-  \bbl at ifunset{\bbl at tempa\space}%
-    {\expandafter\let\csname org@\bbl at tempa\endcsname#1%
-     \bbl at exp{\def\\#1{\\\protect\<\bbl at tempa\space>}}}%
-    {\bbl at exp{\let\<org@\bbl at tempa>\<\bbl at tempa\space>}}%
-    \@namedef{\bbl at tempa\space}}
-\@onlypreamble\bbl at redefinerobust
 \bbl at trace{Hooks}
 \newcommand\AddBabelHook[3][]{%
   \bbl at ifunset{bbl at hk@#2}{\EnableBabelHook{#2}}{}%
@@ -1141,70 +1195,8 @@
   \def\bbl at tempa#1=#2\@@{\NewHook{babel/#1}}
   \bbl at foreach\bbl at evargs{\bbl at tempa#1\@@}
 \fi
-\bbl at trace{Defining babelensure}
-\newcommand\babelensure[2][]{%
-  \AddBabelHook{babel-ensure}{afterextras}{%
-    \ifcase\bbl at select@type
-      \bbl at cl{e}%
-    \fi}%
-  \begingroup
-    \let\bbl at ens@include\@empty
-    \let\bbl at ens@exclude\@empty
-    \def\bbl at ens@fontenc{\relax}%
-    \def\bbl at tempb##1{%
-      \ifx\@empty##1\else\noexpand##1\expandafter\bbl at tempb\fi}%
-    \edef\bbl at tempa{\bbl at tempb#1\@empty}%
-    \def\bbl at tempb##1=##2\@@{\@namedef{bbl at ens@##1}{##2}}%
-    \bbl at foreach\bbl at tempa{\bbl at tempb##1\@@}%
-    \def\bbl at tempc{\bbl at ensure}%
-    \expandafter\bbl at add\expandafter\bbl at tempc\expandafter{%
-      \expandafter{\bbl at ens@include}}%
-    \expandafter\bbl at add\expandafter\bbl at tempc\expandafter{%
-      \expandafter{\bbl at ens@exclude}}%
-    \toks@\expandafter{\bbl at tempc}%
-    \bbl at exp{%
-  \endgroup
-  \def\<bbl at e@#2>{\the\toks@{\bbl at ens@fontenc}}}}
-\def\bbl at ensure#1#2#3{% 1: include 2: exclude 3: fontenc
-  \def\bbl at tempb##1{% elt for (excluding) \bbl at captionslist list
-    \ifx##1\@undefined % 3.32 - Don't assume the macro exists
-      \edef##1{\noexpand\bbl at nocaption
-        {\bbl at stripslash##1}{\languagename\bbl at stripslash##1}}%
-    \fi
-    \ifx##1\@empty\else
-      \in@{##1}{#2}%
-      \ifin@\else
-        \bbl at ifunset{bbl at ensure@\languagename}%
-          {\bbl at exp{%
-            \\\DeclareRobustCommand\<bbl at ensure@\languagename>[1]{%
-              \\\foreignlanguage{\languagename}%
-              {\ifx\relax#3\else
-                \\\fontencoding{#3}\\\selectfont
-               \fi
-               ########1}}}}%
-          {}%
-        \toks@\expandafter{##1}%
-        \edef##1{%
-           \bbl at csarg\noexpand{ensure@\languagename}%
-           {\the\toks@}}%
-      \fi
-      \expandafter\bbl at tempb
-    \fi}%
-  \expandafter\bbl at tempb\bbl at captionslist\today\@empty
-  \def\bbl at tempa##1{% elt for include list
-    \ifx##1\@empty\else
-      \bbl at csarg\in@{ensure@\languagename\expandafter}\expandafter{##1}%
-      \ifin@\else
-        \bbl at tempb##1\@empty
-      \fi
-      \expandafter\bbl at tempa
-    \fi}%
-  \bbl at tempa#1\@empty}
-\def\bbl at captionslist{%
-  \prefacename\refname\abstractname\bibname\chaptername\appendixname
-  \contentsname\listfigurename\listtablename\indexname\figurename
-  \tablename\partname\enclname\ccname\headtoname\pagename\seename
-  \alsoname\proofname\glossaryname}
+\providecommand\PassOptionsToLocale[2]{%
+  \bbl at csarg\bbl at add@list{passto@#2}{#1}}
 \bbl at trace{Macros for setting language files up}
 \def\bbl at ldfinit{%
   \let\bbl at screset\@empty
@@ -1288,6 +1280,10 @@
     \select at language{#1}%
   \fi}
 \bbl at trace{Shorhands}
+\def\bbl at withactive#1#2{%
+  \begingroup
+    \lccode`~=`#2\relax
+    \lowercase{\endgroup#1~}}
 \def\bbl at add@special#1{% 1:a macro like \", \?, etc.
   \bbl at add\dospecials{\do#1}% test @sanitize = \relax, for back. compat.
   \bbl at ifunset{@sanitize}{}{\bbl at add\@sanitize{\@makeother#1}}%
@@ -1700,6 +1696,24 @@
 \def\babel at savevariable#1{%
   \toks@\expandafter{\originalTeX #1=}%
   \bbl at exp{\def\\\originalTeX{\the\toks@\the#1\relax}}}
+\def\bbl at redefine#1{%
+  \edef\bbl at tempa{\bbl at stripslash#1}%
+  \expandafter\let\csname org@\bbl at tempa\endcsname#1%
+  \expandafter\def\csname\bbl at tempa\endcsname}
+\@onlypreamble\bbl at redefine
+\def\bbl at redefine@long#1{%
+  \edef\bbl at tempa{\bbl at stripslash#1}%
+  \expandafter\let\csname org@\bbl at tempa\endcsname#1%
+  \long\expandafter\def\csname\bbl at tempa\endcsname}
+\@onlypreamble\bbl at redefine@long
+\def\bbl at redefinerobust#1{%
+  \edef\bbl at tempa{\bbl at stripslash#1}%
+  \bbl at ifunset{\bbl at tempa\space}%
+    {\expandafter\let\csname org@\bbl at tempa\endcsname#1%
+     \bbl at exp{\def\\#1{\\\protect\<\bbl at tempa\space>}}}%
+    {\bbl at exp{\let\<org@\bbl at tempa>\<\bbl at tempa\space>}}%
+    \@namedef{\bbl at tempa\space}}
+\@onlypreamble\bbl at redefinerobust
 \def\bbl at frenchspacing{%
   \ifnum\the\sfcode`\.=\@m
     \let\bbl at nonfrenchspacing\relax
@@ -1736,21 +1750,6 @@
       \fi}%
     \bbl at fs@chars
   \fi\fi\fi}
-\bbl at trace{Short tags}
-\def\babeltags#1{%
-  \edef\bbl at tempa{\zap at space#1 \@empty}%
-  \def\bbl at tempb##1=##2\@@{%
-    \edef\bbl at tempc{%
-      \noexpand\newcommand
-      \expandafter\noexpand\csname ##1\endcsname{%
-        \noexpand\protect
-        \expandafter\noexpand\csname otherlanguage*\endcsname{##2}}
-      \noexpand\newcommand
-      \expandafter\noexpand\csname text##1\endcsname{%
-        \noexpand\foreignlanguage{##2}}}
-    \bbl at tempc}%
-  \bbl at for\bbl at tempa\bbl at tempa{%
-    \expandafter\bbl at tempb\bbl at tempa\@@}}
 \bbl at trace{Hyphens}
 \@onlypreamble\babelhyphenation
 \AtEndOfPackage{%

Modified: trunk/Master/texmf-dist/tex/generic/babel/babel.sty
===================================================================
--- trunk/Master/texmf-dist/tex/generic/babel/babel.sty	2024-10-20 20:22:44 UTC (rev 72606)
+++ trunk/Master/texmf-dist/tex/generic/babel/babel.sty	2024-10-20 20:23:26 UTC (rev 72607)
@@ -32,8 +32,10 @@
 %% and covered by LPPL is defined by the unpacking scripts (with
 %% extension |.ins|) which are part of the distribution.
 %%
-\NeedsTeXFormat{LaTeX2e}[2005/12/01]
-\ProvidesPackage{babel}[2024/10/05 v24.11 The Babel package]
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{babel}%
+  [2024/10/20 v24.12
+   The multilingual framework for pdfLaTeX, LuaLaTeX and XeLaTeX]
 \@ifpackagewith{babel}{debug}
   {\providecommand\bbl at trace[1]{\message{^^J[ #1 ]}}%
    \let\bbl at debug\@firstofone
@@ -466,8 +468,8 @@
       \expandafter\@secondoftwo
     \fi}
 \fi
-\def\bbl at version{24.11}
-\def\bbl at date{2024/10/05}
+\def\bbl at version{24.12}
+\def\bbl at date{2024/10/20}
 \ifx\language\@undefined
   \csname newcount\endcsname\language
 \fi
@@ -547,34 +549,6 @@
     \fi
   \fi\fi}
 \let\bbl at initoload\relax
-\def\bbl at provide@locale{%
-  \ifx\babelprovide\@undefined
-    \bbl at error{base-on-the-fly}{}{}{}%
-  \fi
-  \let\bbl at auxname\languagename % Still necessary.
-  \bbl at ifunset{bbl at bcp@map@\languagename}{}% Move uplevel??
-    {\edef\languagename{\@nameuse{bbl at bcp@map@\languagename}}}%
-  \ifbbl at bcpallowed
-    \expandafter\ifx\csname date\languagename\endcsname\relax
-      \expandafter
-      \bbl at bcplookup\languagename-\@empty-\@empty-\@empty\@@
-      \ifx\bbl at bcp\relax\else  % Returned by \bbl at bcplookup
-        \edef\languagename{\bbl at bcp@prefix\bbl at bcp}%
-        \edef\localename{\bbl at bcp@prefix\bbl at bcp}%
-        \expandafter\ifx\csname date\languagename\endcsname\relax
-          \let\bbl at initoload\bbl at bcp
-          \bbl at exp{\\\babelprovide[\bbl at autoload@bcpoptions]{\languagename}}%
-          \let\bbl at initoload\relax
-        \fi
-        \bbl at csarg\xdef{bcp at map@\bbl at bcp}{\localename}%
-      \fi
-    \fi
-  \fi
-  \expandafter\ifx\csname date\languagename\endcsname\relax
-    \IfFileExists{babel-\languagename.tex}%
-      {\bbl at exp{\\\babelprovide[\bbl at autoload@options]{\languagename}}}%
-      {}%
-  \fi}
 \def\iflanguage#1{%
   \bbl at iflanguage{#1}{%
     \ifnum\csname l@#1\endcsname=\language
@@ -651,8 +625,6 @@
   \fi}
 \let\bbl at restorelastskip\relax
 \let\bbl at savelastskip\relax
-\newif\ifbbl at bcpallowed
-\bbl at bcpallowedfalse
 \def\select at language#1{% from set@, babel at aux, babel at toc
   \ifx\bbl at selectorname\@empty
     \def\bbl at selectorname{select}%
@@ -946,13 +918,91 @@
      preloaded for \bbl at nulllanguage\space instead}}
 \let\bbl at usehooks\@gobbletwo
 \ifx\bbl at onlyswitch\@empty\endinput\fi
-  % Here ended switch.def
+\bbl at trace{Defining babelensure}
+\newcommand\babelensure[2][]{%
+  \AddBabelHook{babel-ensure}{afterextras}{%
+    \ifcase\bbl at select@type
+      \bbl at cl{e}%
+    \fi}%
+  \begingroup
+    \let\bbl at ens@include\@empty
+    \let\bbl at ens@exclude\@empty
+    \def\bbl at ens@fontenc{\relax}%
+    \def\bbl at tempb##1{%
+      \ifx\@empty##1\else\noexpand##1\expandafter\bbl at tempb\fi}%
+    \edef\bbl at tempa{\bbl at tempb#1\@empty}%
+    \def\bbl at tempb##1=##2\@@{\@namedef{bbl at ens@##1}{##2}}%
+    \bbl at foreach\bbl at tempa{\bbl at tempb##1\@@}%
+    \def\bbl at tempc{\bbl at ensure}%
+    \expandafter\bbl at add\expandafter\bbl at tempc\expandafter{%
+      \expandafter{\bbl at ens@include}}%
+    \expandafter\bbl at add\expandafter\bbl at tempc\expandafter{%
+      \expandafter{\bbl at ens@exclude}}%
+    \toks@\expandafter{\bbl at tempc}%
+    \bbl at exp{%
+  \endgroup
+  \def\<bbl at e@#2>{\the\toks@{\bbl at ens@fontenc}}}}
+\def\bbl at ensure#1#2#3{% 1: include 2: exclude 3: fontenc
+  \def\bbl at tempb##1{% elt for (excluding) \bbl at captionslist list
+    \ifx##1\@undefined % 3.32 - Don't assume the macro exists
+      \edef##1{\noexpand\bbl at nocaption
+        {\bbl at stripslash##1}{\languagename\bbl at stripslash##1}}%
+    \fi
+    \ifx##1\@empty\else
+      \in@{##1}{#2}%
+      \ifin@\else
+        \bbl at ifunset{bbl at ensure@\languagename}%
+          {\bbl at exp{%
+            \\\DeclareRobustCommand\<bbl at ensure@\languagename>[1]{%
+              \\\foreignlanguage{\languagename}%
+              {\ifx\relax#3\else
+                \\\fontencoding{#3}\\\selectfont
+               \fi
+               ########1}}}}%
+          {}%
+        \toks@\expandafter{##1}%
+        \edef##1{%
+           \bbl at csarg\noexpand{ensure@\languagename}%
+           {\the\toks@}}%
+      \fi
+      \expandafter\bbl at tempb
+    \fi}%
+  \expandafter\bbl at tempb\bbl at captionslist\today\@empty
+  \def\bbl at tempa##1{% elt for include list
+    \ifx##1\@empty\else
+      \bbl at csarg\in@{ensure@\languagename\expandafter}\expandafter{##1}%
+      \ifin@\else
+        \bbl at tempb##1\@empty
+      \fi
+      \expandafter\bbl at tempa
+    \fi}%
+  \bbl at tempa#1\@empty}
+\def\bbl at captionslist{%
+  \prefacename\refname\abstractname\bibname\chaptername\appendixname
+  \contentsname\listfigurename\listtablename\indexname\figurename
+  \tablename\partname\enclname\ccname\headtoname\pagename\seename
+  \alsoname\proofname\glossaryname}
+\bbl at trace{Short tags}
+\newcommand\babeltags[1]{%
+  \edef\bbl at tempa{\zap at space#1 \@empty}%
+  \def\bbl at tempb##1=##2\@@{%
+    \edef\bbl at tempc{%
+      \noexpand\newcommand
+      \expandafter\noexpand\csname ##1\endcsname{%
+        \noexpand\protect
+        \expandafter\noexpand\csname otherlanguage*\endcsname{##2}}
+      \noexpand\newcommand
+      \expandafter\noexpand\csname text##1\endcsname{%
+        \noexpand\foreignlanguage{##2}}}
+    \bbl at tempc}%
+  \bbl at for\bbl at tempa\bbl at tempa{%
+    \expandafter\bbl at tempb\bbl at tempa\@@}}
+\bbl at trace{Compatibility with language.def}
 \ifx\directlua\@undefined\else
   \ifx\bbl at luapatterns\@undefined
     \input luababel.def
   \fi
 \fi
-\bbl at trace{Compatibility with language.def}
 \ifx\bbl at languages\@undefined
   \ifx\directlua\@undefined
     \openin1 = language.def % TODO. Remove hardcoded number
@@ -985,28 +1035,6 @@
        \xdef#1{\the\toks@}}%
     \fi
   \fi}
-\def\bbl at withactive#1#2{%
-  \begingroup
-    \lccode`~=`#2\relax
-    \lowercase{\endgroup#1~}}
-\def\bbl at redefine#1{%
-  \edef\bbl at tempa{\bbl at stripslash#1}%
-  \expandafter\let\csname org@\bbl at tempa\endcsname#1%
-  \expandafter\def\csname\bbl at tempa\endcsname}
-\@onlypreamble\bbl at redefine
-\def\bbl at redefine@long#1{%
-  \edef\bbl at tempa{\bbl at stripslash#1}%
-  \expandafter\let\csname org@\bbl at tempa\endcsname#1%
-  \long\expandafter\def\csname\bbl at tempa\endcsname}
-\@onlypreamble\bbl at redefine@long
-\def\bbl at redefinerobust#1{%
-  \edef\bbl at tempa{\bbl at stripslash#1}%
-  \bbl at ifunset{\bbl at tempa\space}%
-    {\expandafter\let\csname org@\bbl at tempa\endcsname#1%
-     \bbl at exp{\def\\#1{\\\protect\<\bbl at tempa\space>}}}%
-    {\bbl at exp{\let\<org@\bbl at tempa>\<\bbl at tempa\space>}}%
-    \@namedef{\bbl at tempa\space}}
-\@onlypreamble\bbl at redefinerobust
 \bbl at trace{Hooks}
 \newcommand\AddBabelHook[3][]{%
   \bbl at ifunset{bbl at hk@#2}{\EnableBabelHook{#2}}{}%
@@ -1040,70 +1068,8 @@
   \def\bbl at tempa#1=#2\@@{\NewHook{babel/#1}}
   \bbl at foreach\bbl at evargs{\bbl at tempa#1\@@}
 \fi
-\bbl at trace{Defining babelensure}
-\newcommand\babelensure[2][]{%
-  \AddBabelHook{babel-ensure}{afterextras}{%
-    \ifcase\bbl at select@type
-      \bbl at cl{e}%
-    \fi}%
-  \begingroup
-    \let\bbl at ens@include\@empty
-    \let\bbl at ens@exclude\@empty
-    \def\bbl at ens@fontenc{\relax}%
-    \def\bbl at tempb##1{%
-      \ifx\@empty##1\else\noexpand##1\expandafter\bbl at tempb\fi}%
-    \edef\bbl at tempa{\bbl at tempb#1\@empty}%
-    \def\bbl at tempb##1=##2\@@{\@namedef{bbl at ens@##1}{##2}}%
-    \bbl at foreach\bbl at tempa{\bbl at tempb##1\@@}%
-    \def\bbl at tempc{\bbl at ensure}%
-    \expandafter\bbl at add\expandafter\bbl at tempc\expandafter{%
-      \expandafter{\bbl at ens@include}}%
-    \expandafter\bbl at add\expandafter\bbl at tempc\expandafter{%
-      \expandafter{\bbl at ens@exclude}}%
-    \toks@\expandafter{\bbl at tempc}%
-    \bbl at exp{%
-  \endgroup
-  \def\<bbl at e@#2>{\the\toks@{\bbl at ens@fontenc}}}}
-\def\bbl at ensure#1#2#3{% 1: include 2: exclude 3: fontenc
-  \def\bbl at tempb##1{% elt for (excluding) \bbl at captionslist list
-    \ifx##1\@undefined % 3.32 - Don't assume the macro exists
-      \edef##1{\noexpand\bbl at nocaption
-        {\bbl at stripslash##1}{\languagename\bbl at stripslash##1}}%
-    \fi
-    \ifx##1\@empty\else
-      \in@{##1}{#2}%
-      \ifin@\else
-        \bbl at ifunset{bbl at ensure@\languagename}%
-          {\bbl at exp{%
-            \\\DeclareRobustCommand\<bbl at ensure@\languagename>[1]{%
-              \\\foreignlanguage{\languagename}%
-              {\ifx\relax#3\else
-                \\\fontencoding{#3}\\\selectfont
-               \fi
-               ########1}}}}%
-          {}%
-        \toks@\expandafter{##1}%
-        \edef##1{%
-           \bbl at csarg\noexpand{ensure@\languagename}%
-           {\the\toks@}}%
-      \fi
-      \expandafter\bbl at tempb
-    \fi}%
-  \expandafter\bbl at tempb\bbl at captionslist\today\@empty
-  \def\bbl at tempa##1{% elt for include list
-    \ifx##1\@empty\else
-      \bbl at csarg\in@{ensure@\languagename\expandafter}\expandafter{##1}%
-      \ifin@\else
-        \bbl at tempb##1\@empty
-      \fi
-      \expandafter\bbl at tempa
-    \fi}%
-  \bbl at tempa#1\@empty}
-\def\bbl at captionslist{%
-  \prefacename\refname\abstractname\bibname\chaptername\appendixname
-  \contentsname\listfigurename\listtablename\indexname\figurename
-  \tablename\partname\enclname\ccname\headtoname\pagename\seename
-  \alsoname\proofname\glossaryname}
+\providecommand\PassOptionsToLocale[2]{%
+  \bbl at csarg\bbl at add@list{passto@#2}{#1}}
 \bbl at trace{Macros for setting language files up}
 \def\bbl at ldfinit{%
   \let\bbl at screset\@empty
@@ -1172,23 +1138,11 @@
     \immediate\write\@mainaux{\string\@nameuse{bbl at beforestart}}%
   \fi
   \expandafter\selectlanguage\expandafter{\bbl at main@language}%
-  \ifx\bbl at normalsf\@empty
-    \ifnum\sfcode`\.=\@m
-      \let\normalsfcodes\frenchspacing
-    \else
-      \let\normalsfcodes\nonfrenchspacing
-    \fi
-  \else
-    \let\normalsfcodes\bbl at normalsf
-  \fi
   \ifbbl at single  % must go after the line above.
     \renewcommand\selectlanguage[1]{}%
     \renewcommand\foreignlanguage[2]{#2}%
     \global\let\babel at aux\@gobbletwo  % Also as flag
   \fi}
-\AddToHook{begindocument/before}{%
-  \let\bbl at normalsf\normalsfcodes
-  \let\normalsfcodes\relax} % Hack, to delay the setting
 \ifcase\bbl at engine\or
   \AtBeginDocument{\pagedir\bodydir}
 \fi
@@ -1199,6 +1153,10 @@
     \select at language{#1}%
   \fi}
 \bbl at trace{Shorhands}
+\def\bbl at withactive#1#2{%
+  \begingroup
+    \lccode`~=`#2\relax
+    \lowercase{\endgroup#1~}}
 \def\bbl at add@special#1{% 1:a macro like \", \?, etc.
   \bbl at add\dospecials{\do#1}% test @sanitize = \relax, for back. compat.
   \bbl at ifunset{@sanitize}{}{\bbl at add\@sanitize{\@makeother#1}}%
@@ -1611,6 +1569,24 @@
 \def\babel at savevariable#1{%
   \toks@\expandafter{\originalTeX #1=}%
   \bbl at exp{\def\\\originalTeX{\the\toks@\the#1\relax}}}
+\def\bbl at redefine#1{%
+  \edef\bbl at tempa{\bbl at stripslash#1}%
+  \expandafter\let\csname org@\bbl at tempa\endcsname#1%
+  \expandafter\def\csname\bbl at tempa\endcsname}
+\@onlypreamble\bbl at redefine
+\def\bbl at redefine@long#1{%
+  \edef\bbl at tempa{\bbl at stripslash#1}%
+  \expandafter\let\csname org@\bbl at tempa\endcsname#1%
+  \long\expandafter\def\csname\bbl at tempa\endcsname}
+\@onlypreamble\bbl at redefine@long
+\def\bbl at redefinerobust#1{%
+  \edef\bbl at tempa{\bbl at stripslash#1}%
+  \bbl at ifunset{\bbl at tempa\space}%
+    {\expandafter\let\csname org@\bbl at tempa\endcsname#1%
+     \bbl at exp{\def\\#1{\\\protect\<\bbl at tempa\space>}}}%
+    {\bbl at exp{\let\<org@\bbl at tempa>\<\bbl at tempa\space>}}%
+    \@namedef{\bbl at tempa\space}}
+\@onlypreamble\bbl at redefinerobust
 \def\bbl at frenchspacing{%
   \ifnum\the\sfcode`\.=\@m
     \let\bbl at nonfrenchspacing\relax
@@ -1647,21 +1623,6 @@
       \fi}%
     \bbl at fs@chars
   \fi\fi\fi}
-\bbl at trace{Short tags}
-\def\babeltags#1{%
-  \edef\bbl at tempa{\zap at space#1 \@empty}%
-  \def\bbl at tempb##1=##2\@@{%
-    \edef\bbl at tempc{%
-      \noexpand\newcommand
-      \expandafter\noexpand\csname ##1\endcsname{%
-        \noexpand\protect
-        \expandafter\noexpand\csname otherlanguage*\endcsname{##2}}
-      \noexpand\newcommand
-      \expandafter\noexpand\csname text##1\endcsname{%
-        \noexpand\foreignlanguage{##2}}}
-    \bbl at tempc}%
-  \bbl at for\bbl at tempa\bbl at tempa{%
-    \expandafter\bbl at tempb\bbl at tempa\@@}}
 \bbl at trace{Hyphens}
 \@onlypreamble\babelhyphenation
 \AtEndOfPackage{%
@@ -2170,39 +2131,6 @@
 \fi
 \bbl at trace{Bidi layout}
 \providecommand\IfBabelLayout[3]{#3}%
-\newcommand\BabelPatchSection[1]{%
-  \@ifundefined{#1}{}{%
-    \bbl at exp{\let\<bbl at ss@#1>\<#1>}%
-    \@namedef{#1}{%
-      \@ifstar{\bbl at presec@s{#1}}%
-              {\@dblarg{\bbl at presec@x{#1}}}}}}
-\def\bbl at presec@x#1[#2]#3{%
-  \bbl at exp{%
-    \\\select at language@x{\bbl at main@language}%
-    \\\bbl at cs{sspre@#1}%
-    \\\bbl at cs{ss@#1}%
-      [\\\foreignlanguage{\languagename}{\unexpanded{#2}}]%
-      {\\\foreignlanguage{\languagename}{\unexpanded{#3}}}%
-    \\\select at language@x{\languagename}}}
-\def\bbl at presec@s#1#2{%
-  \bbl at exp{%
-    \\\select at language@x{\bbl at main@language}%
-    \\\bbl at cs{sspre@#1}%
-    \\\bbl at cs{ss@#1}*%
-      {\\\foreignlanguage{\languagename}{\unexpanded{#2}}}%
-    \\\select at language@x{\languagename}}}
-\IfBabelLayout{sectioning}%
-  {\BabelPatchSection{part}%
-   \BabelPatchSection{chapter}%
-   \BabelPatchSection{section}%
-   \BabelPatchSection{subsection}%
-   \BabelPatchSection{subsubsection}%
-   \BabelPatchSection{paragraph}%
-   \BabelPatchSection{subparagraph}%
-   \def\babel at toc#1{%
-     \select at language@x{\bbl at main@language}}}{}
-\IfBabelLayout{captions}%
-  {\BabelPatchSection{caption}}{}
 \bbl at trace{Input engine specific macros}
 \ifcase\bbl at engine
   \input txtbabel.def
@@ -2230,7 +2158,7 @@
   \bbl at vforeach{captions,date,import,main,script,language,%
       hyphenrules,linebreaking,justification,mapfont,maparabic,%
       mapdigits,intraspace,intrapenalty,onchar,transforms,alph,%
-      Alph,labels,labels*,calendar,date,casing,interchar}%
+      Alph,labels,labels*,calendar,date,casing,interchar, at import}%
     {\bbl at csarg\let{KVP@##1}\@nnil}%
   \global\let\bbl at release@transforms\@empty
   \global\let\bbl at release@casing\@empty
@@ -2239,7 +2167,10 @@
   \global\let\bbl at extend@ini\@gobble
   \global\let\bbl at included@inis\@empty
   \gdef\bbl at key@list{;}%
-  \bbl at forkv{#1}{%
+  \bbl at ifunset{bbl at passto@#2}%
+    {\def\bbl at tempa{#1}}%
+    {\bbl at exp{\def\\\bbl at tempa{\[bbl at passto@#2],\unexpanded{#1}}}}%
+  \expandafter\bbl at forkv\expandafter{\bbl at tempa}{%
     \in@{/}{##1}% With /, (re)sets a value in the ini
     \ifin@
       \global\let\bbl at extend@ini\bbl at extend@ini at aux
@@ -2256,6 +2187,10 @@
   \ifx\bbl at screset\@undefined
     \bbl at ldfinit
   \fi
+  % ==
+  \ifx\bbl at KVP@@import\@nnil\else \ifx\bbl at KVP@import\@nnil
+    \def\bbl at KVP@import{\@empty}%
+  \fi\fi
   % == date (as option) ==
   % \ifx\bbl at KVP@date\@nnil\else
   % \fi
@@ -2345,97 +2280,6 @@
       {\directlua{
          Babel.set_chranges_b('\bbl at cl{sbcp}', '\bbl at cl{chrng}') }}%
   \fi
-   % == onchar ==
-  \ifx\bbl at KVP@onchar\@nnil\else
-    \bbl at luahyphenate
-    \bbl at exp{%
-      \\\AddToHook{env/document/before}{{\\\select at language{#2}{}}}}%
-    \directlua{
-      if Babel.locale_mapped == nil then
-        Babel.locale_mapped = true
-        Babel.linebreaking.add_before(Babel.locale_map, 1)
-        Babel.loc_to_scr = {}
-        Babel.chr_to_loc = Babel.chr_to_loc or {}
-      end
-      Babel.locale_props[\the\localeid].letters = false
-    }%
-    \bbl at xin@{ letters }{ \bbl at KVP@onchar\space}%
-    \ifin@
-      \directlua{
-        Babel.locale_props[\the\localeid].letters = true
-      }%
-    \fi
-    \bbl at xin@{ ids }{ \bbl at KVP@onchar\space}%
-    \ifin@
-      \ifx\bbl at starthyphens\@undefined % Needed if no explicit selection
-        \AddBabelHook{babel-onchar}{beforestart}{{\bbl at starthyphens}}%
-      \fi
-      \bbl at exp{\\\bbl at add\\\bbl at starthyphens
-        {\\\bbl at patterns@lua{\languagename}}}%
-      \directlua{
-        if Babel.script_blocks['\bbl at cl{sbcp}'] then
-          Babel.loc_to_scr[\the\localeid] = Babel.script_blocks['\bbl at cl{sbcp}']
-          Babel.locale_props[\the\localeid].lg = \the\@nameuse{l@\languagename}\space
-        end
-      }%
-    \fi
-    \bbl at xin@{ fonts }{ \bbl at KVP@onchar\space}%
-    \ifin@
-      \bbl at ifunset{bbl at lsys@\languagename}{\bbl at provide@lsys{\languagename}}{}%
-      \bbl at ifunset{bbl at wdir@\languagename}{\bbl at provide@dirs{\languagename}}{}%
-      \directlua{
-        if Babel.script_blocks['\bbl at cl{sbcp}'] then
-          Babel.loc_to_scr[\the\localeid] =
-            Babel.script_blocks['\bbl at cl{sbcp}']
-        end}%
-      \ifx\bbl at mapselect\@undefined  % TODO. almost the same as mapfont
-        \AtBeginDocument{%
-          \bbl at patchfont{{\bbl at mapselect}}%
-          {\selectfont}}%
-        \def\bbl at mapselect{%
-          \let\bbl at mapselect\relax
-          \edef\bbl at prefontid{\fontid\font}}%
-        \def\bbl at mapdir##1{%
-          \begingroup
-            \setbox\z@\hbox{% Force text mode
-              \def\languagename{##1}%
-              \let\bbl at ifrestoring\@firstoftwo % To avoid font warning
-              \bbl at switchfont
-              \ifnum\fontid\font>\z@ % A hack, for the pgf nullfont hack
-                \directlua{
-                  Babel.locale_props[\the\csname bbl at id@@##1\endcsname]%
-                          ['/\bbl at prefontid'] = \fontid\font\space}%
-              \fi}%
-          \endgroup}%
-      \fi
-      \bbl at exp{\\\bbl at add\\\bbl at mapselect{\\\bbl at mapdir{\languagename}}}%
-    \fi
-    % TODO - catch non-valid values
-  \fi
-  % == mapfont ==
-  % For bidi texts, to switch the font based on direction
-  \ifx\bbl at KVP@mapfont\@nnil\else
-    \bbl at ifsamestring{\bbl at KVP@mapfont}{direction}{}%
-      {\bbl at error{unknown-mapfont}{}{}{}}%
-    \bbl at ifunset{bbl at lsys@\languagename}{\bbl at provide@lsys{\languagename}}{}%
-    \bbl at ifunset{bbl at wdir@\languagename}{\bbl at provide@dirs{\languagename}}{}%
-    \ifx\bbl at mapselect\@undefined % TODO. See onchar.
-      \AtBeginDocument{%
-        \bbl at patchfont{{\bbl at mapselect}}%
-        {\selectfont}}%
-      \def\bbl at mapselect{%
-        \let\bbl at mapselect\relax
-        \edef\bbl at prefontid{\fontid\font}}%
-      \def\bbl at mapdir##1{%
-        {\def\languagename{##1}%
-         \let\bbl at ifrestoring\@firstoftwo % avoid font warning
-         \bbl at switchfont
-         \directlua{Babel.fontmap
-           [\the\csname bbl at wdir@##1\endcsname]%
-           [\bbl at prefontid]=\fontid\font}}}%
-    \fi
-    \bbl at exp{\\\bbl at add\\\bbl at mapselect{\\\bbl at mapdir{\languagename}}}%
-  \fi
   % == Line breaking: intraspace, intrapenalty ==
   % For CJK, East Asian, Southeast Asian, if interspace in ini
   \ifx\bbl at KVP@intraspace\@nnil\else % We can override the ini or set
@@ -2442,24 +2286,6 @@
     \bbl at csarg\edef{intsp@#2}{\bbl at KVP@intraspace}%
   \fi
   \bbl at provide@intraspace
-  % == Line breaking: CJK quotes ==
-  \ifcase\bbl at engine\or
-    \bbl at xin@{/c}{/\bbl at cl{lnbrk}}%
-    \ifin@
-      \bbl at ifunset{bbl at quote@\languagename}{}%
-        {\directlua{
-           Babel.locale_props[\the\localeid].cjk_quotes = {}
-           local cs = 'op'
-           for c in string.utfvalues(%
-               [[\csname bbl at quote@\languagename\endcsname]]) do
-             if Babel.cjk_characters[c].c == 'qu' then
-               Babel.locale_props[\the\localeid].cjk_quotes[c] = cs
-             end
-             cs = ( cs == 'op') and 'cl' or 'op'
-           end
-        }}%
-    \fi
-  \fi
   % == Line breaking: justification ==
   \ifx\bbl at KVP@justification\@nnil\else
      \let\bbl at KVP@linebreaking\bbl at KVP@justification
@@ -2475,6 +2301,7 @@
   \bbl at xin@{/e}{/\bbl at cl{lnbrk}}%
   \ifin@\else\bbl at xin@{/k}{/\bbl at cl{lnbrk}}\fi
   \ifin@\bbl at arabicjust\fi
+  % WIP
   \bbl at xin@{/p}{/\bbl at cl{lnbrk}}%
   \ifin@\AtBeginDocument{\@nameuse{bbl at tibetanjust}}\fi
   % == Line breaking: hyphenate.other.(locale|script) ==
@@ -3193,11 +3020,8 @@
        \ifx\bbl at savetoday\@empty
          \bbl at exp{% TODO. Move to a better place.
            \\\AfterBabelCommands{%
-             \def\<\languagename date>{\\\protect\<\languagename date >}%
-             \\\newcommand\<\languagename date >[4][]{%
-               \\\bbl at usedategrouptrue
-               \<bbl at ensure@\languagename>{%
-                 \\\localedate[####1]{####2}{####3}{####4}}}}%
+             \gdef\<\languagename date>{\\\protect\<\languagename date >}%
+             \gdef\<\languagename date >{\\\bbl at printdate{\languagename}}}%
            \def\\\bbl at savetoday{%
              \\\SetString\\\today{%
                \<\languagename date>[convert]%
@@ -3204,6 +3028,24 @@
                   {\\\the\year}{\\\the\month}{\\\the\day}}}}%
        \fi}%
       {}}}
+\def\bbl at printdate#1{%
+  \@ifnextchar[{\bbl at printdate@i{#1}}{\bbl at printdate@i{#1}[]}}
+\def\bbl at printdate@i#1[#2]#3#4#5{%
+  \bbl at usedategrouptrue
+  \@nameuse{bbl at ensure@#1}{\localedate[#2]{#3}{#4}{#5}}}
+\AddToHook{begindocument/before}{%
+  \let\bbl at normalsf\normalsfcodes
+  \let\normalsfcodes\relax}
+\AtBeginDocument{%
+  \ifx\bbl at normalsf\@empty
+    \ifnum\sfcode`\.=\@m
+      \let\normalsfcodes\frenchspacing
+    \else
+      \let\normalsfcodes\nonfrenchspacing
+    \fi
+  \else
+    \let\normalsfcodes\bbl at normalsf
+  \fi}
 \let\bbl at calendar\@empty
 \newcommand\babelcalendar[2][\the\year-\the\month-\the\day]{%
   \@nameuse{bbl at ca@#2}#1\@@}
@@ -3427,6 +3269,11 @@
   \DeclareTitlecaseMapping[\@nameuse{bbl at casing@#1}]{#2}{#3}}
 \newcommand\BabelLowercaseMapping[3]{%
   \DeclareLowercaseMapping[\@nameuse{bbl at casing@#1}]{#2}{#3}}
+\ifcase\bbl at engine % Converts utf8 to its code (expandable)
+  \def\bbl at utftocode#1{\the\numexpr\decode at UTFviii#1\relax}
+\else
+  \def\bbl at utftocode#1{\expandafter`\string#1}
+\fi
 \def\bbl at casemapping#1#2#3{% 1:variant
   \def\bbl at tempa##1 ##2{% Loop
     \bbl at casemapping@i{##1}%
@@ -3488,25 +3335,6 @@
 \@namedef{bbl at info@extension.t.tag.bcp47}{extt}
 \@namedef{bbl at info@extension.u.tag.bcp47}{extu}
 \@namedef{bbl at info@extension.x.tag.bcp47}{extx}
-\ifcase\bbl at engine % Converts utf8 to its code (expandable)
-  \def\bbl at utftocode#1{\the\numexpr\decode at UTFviii#1\relax}
-\else
-  \def\bbl at utftocode#1{\expandafter`\string#1}
-\fi
-\providecommand\BCPdata{}
-\ifx\renewcommand\@undefined\else % For plain. TODO. It’s a quick fix
-  \renewcommand\BCPdata[1]{\bbl at bcpdata@i#1\@empty}
-  \def\bbl at bcpdata@i#1#2#3#4#5#6\@empty{%
-    \@nameuse{str_if_eq:nnTF}{#1#2#3#4#5}{main.}%
-      {\bbl at bcpdata@ii{#6}\bbl at main@language}%
-      {\bbl at bcpdata@ii{#1#2#3#4#5#6}\languagename}}%
-  \def\bbl at bcpdata@ii#1#2{%
-    \bbl at ifunset{bbl at info@#1.tag.bcp47}%
-      {\bbl at error{unknown-ini-field}{#1}{}{}}%
-      {\bbl at ifunset{bbl@\csname bbl at info@#1.tag.bcp47\endcsname @#2}{}%
-        {\bbl at cs{\csname bbl at info@#1.tag.bcp47\endcsname @#2}}}}
-\fi
-\@namedef{bbl at info@casing.tag.bcp47}{casing}
 \let\bbl at ensureinfo\@gobble
 \newcommand\BabelEnsureInfo{%
   \ifx\InputIfFileExists\@undefined\else
@@ -3543,6 +3371,50 @@
   \def\bbl at elt##1##2##3{\typeout{##1/##2 = ##3}}%
   \@nameuse{bbl at inidata@#1}%
   \typeout{*******}}
+\newif\ifbbl at bcpallowed
+\bbl at bcpallowedfalse
+\def\bbl at provide@locale{%
+  \ifx\babelprovide\@undefined
+    \bbl at error{base-on-the-fly}{}{}{}%
+  \fi
+  \let\bbl at auxname\languagename % Still necessary.
+  \bbl at ifunset{bbl at bcp@map@\languagename}{}% Move uplevel??
+    {\edef\languagename{\@nameuse{bbl at bcp@map@\languagename}}}%
+  \ifbbl at bcpallowed
+    \expandafter\ifx\csname date\languagename\endcsname\relax
+      \expandafter
+      \bbl at bcplookup\languagename-\@empty-\@empty-\@empty\@@
+      \ifx\bbl at bcp\relax\else  % Returned by \bbl at bcplookup
+        \edef\languagename{\bbl at bcp@prefix\bbl at bcp}%
+        \edef\localename{\bbl at bcp@prefix\bbl at bcp}%
+        \expandafter\ifx\csname date\languagename\endcsname\relax
+          \let\bbl at initoload\bbl at bcp
+          \bbl at exp{\\\babelprovide[\bbl at autoload@bcpoptions]{\languagename}}%
+          \let\bbl at initoload\relax
+        \fi
+        \bbl at csarg\xdef{bcp at map@\bbl at bcp}{\localename}%
+      \fi
+    \fi
+  \fi
+  \expandafter\ifx\csname date\languagename\endcsname\relax
+    \IfFileExists{babel-\languagename.tex}%
+      {\bbl at exp{\\\babelprovide[\bbl at autoload@options]{\languagename}}}%
+      {}%
+  \fi}
+\providecommand\BCPdata{}
+\ifx\renewcommand\@undefined\else % For plain. TODO. It’s a quick fix
+  \renewcommand\BCPdata[1]{\bbl at bcpdata@i#1\@empty}
+  \def\bbl at bcpdata@i#1#2#3#4#5#6\@empty{%
+    \@nameuse{str_if_eq:nnTF}{#1#2#3#4#5}{main.}%
+      {\bbl at bcpdata@ii{#6}\bbl at main@language}%
+      {\bbl at bcpdata@ii{#1#2#3#4#5#6}\languagename}}%
+  \def\bbl at bcpdata@ii#1#2{%
+    \bbl at ifunset{bbl at info@#1.tag.bcp47}%
+      {\bbl at error{unknown-ini-field}{#1}{}{}}%
+      {\bbl at ifunset{bbl@\csname bbl at info@#1.tag.bcp47\endcsname @#2}{}%
+        {\bbl at cs{\csname bbl at info@#1.tag.bcp47\endcsname @#2}}}}
+\fi
+\@namedef{bbl at info@casing.tag.bcp47}{casing}
 \newcommand\babeladjust[1]{%  TODO. Error handling.
   \bbl at forkv{#1}{%
     \bbl at ifunset{bbl at ADJ@##1@##2}%
@@ -3757,6 +3629,39 @@
   \let\org at bibcite\bibcite
   \let\org@@bibitem\@bibitem
 \fi
+\newcommand\BabelPatchSection[1]{%
+  \@ifundefined{#1}{}{%
+    \bbl at exp{\let\<bbl at ss@#1>\<#1>}%
+    \@namedef{#1}{%
+      \@ifstar{\bbl at presec@s{#1}}%
+              {\@dblarg{\bbl at presec@x{#1}}}}}}
+\def\bbl at presec@x#1[#2]#3{%
+  \bbl at exp{%
+    \\\select at language@x{\bbl at main@language}%
+    \\\bbl at cs{sspre@#1}%
+    \\\bbl at cs{ss@#1}%
+      [\\\foreignlanguage{\languagename}{\unexpanded{#2}}]%
+      {\\\foreignlanguage{\languagename}{\unexpanded{#3}}}%
+    \\\select at language@x{\languagename}}}
+\def\bbl at presec@s#1#2{%
+  \bbl at exp{%
+    \\\select at language@x{\bbl at main@language}%
+    \\\bbl at cs{sspre@#1}%
+    \\\bbl at cs{ss@#1}*%
+      {\\\foreignlanguage{\languagename}{\unexpanded{#2}}}%
+    \\\select at language@x{\languagename}}}
+\IfBabelLayout{sectioning}%
+  {\BabelPatchSection{part}%
+   \BabelPatchSection{chapter}%
+   \BabelPatchSection{section}%
+   \BabelPatchSection{subsection}%
+   \BabelPatchSection{subsubsection}%
+   \BabelPatchSection{paragraph}%
+   \BabelPatchSection{subparagraph}%
+   \def\babel at toc#1{%
+     \select at language@x{\bbl at main@language}}}{}
+\IfBabelLayout{captions}%
+  {\BabelPatchSection{caption}}{}
 \bbl at trace{Marks}
 \IfBabelLayout{sectioning}
   {\ifx\bbl at opt@headfoot\@nnil
@@ -4160,10 +4065,16 @@
              *}}%
     {\bbl at error{config-not-found}{}{}{}}%
 \fi
+\def\bbl at tempf{,}
+\bbl at foreach\@raw at classoptionslist{%
+  \in@{=}{#1}%
+  \ifin@\else
+    \edef\bbl at tempf{\bbl at tempf\zap at space#1 \@empty,}%
+  \fi}
 \ifx\bbl at opt@main\@nnil
   \ifnum\bbl at iniflag>\z@  % if all ldf's: set implicitly, no main pass
     \let\bbl at tempb\@empty
-    \edef\bbl at tempa{\@classoptionslist,\bbl at language@opts}%
+    \edef\bbl at tempa{\bbl at tempf,\bbl at language@opts}%
     \bbl at foreach\bbl at tempa{\edef\bbl at tempb{#1,\bbl at tempb}}%
     \bbl at foreach\bbl at tempb{%    \bbl at tempb is a reversed list
       \ifx\bbl at opt@main\@nnil % ie, if not yet assigned
@@ -4194,11 +4105,11 @@
     \else                      % + * (other = ini)
       \DeclareOption{#1}{%
         \bbl at ldfinit
-        \babelprovide[import]{#1}%
+        \babelprovide[@import]{#1}% %%%%%
         \bbl at afterldf{}}%
     \fi
   \fi}
-\bbl at foreach\@classoptionslist{%
+\bbl at foreach\bbl at tempf{%
   \def\bbl at tempa{#1}%
   \ifx\bbl at tempa\bbl at opt@main\else
     \ifnum\bbl at iniflag<\tw@    % 0 ø (other = ldf)
@@ -4211,11 +4122,13 @@
        \IfFileExists{babel-#1.tex}%
          {\DeclareOption{#1}{%
             \bbl at ldfinit
-            \babelprovide[import]{#1}%
+            \babelprovide[@import]{#1}%  %%%%%%
             \bbl at afterldf{}}}%
          {}%
      \fi
   \fi}
+\NewHook{babel/presets}
+\UseHook{babel/presets}
 \def\AfterBabelLanguage#1{%
   \bbl at ifsamestring\CurrentOption{#1}{\global\bbl at add\bbl at afterlang}{}}
 \DeclareOption*{}
@@ -4222,7 +4135,7 @@
 \ProcessOptions*
 \bbl at trace{Option 'main'}
 \ifx\bbl at opt@main\@nnil
-  \edef\bbl at tempa{\@classoptionslist,\bbl at language@opts}
+  \edef\bbl at tempa{\bbl at tempf,\bbl at language@opts}
   \let\bbl at tempc\@empty
   \edef\bbl at templ{,\bbl at loaded,}
   \edef\bbl at templ{\expandafter\strip at prefix\meaning\bbl at templ}
@@ -4246,7 +4159,9 @@
     \bbl at ldfinit
     \let\CurrentOption\bbl at opt@main
     \bbl at exp{%  \bbl at opt@provide = empty if *
-       \\\babelprovide[\bbl at opt@provide,import,main]{\bbl at opt@main}}%
+       \\\babelprovide
+         [\bbl at opt@provide, at import,main]%  %%%%%
+         {\bbl at opt@main}}%
     \bbl at afterldf{}
     \DeclareOption{\bbl at opt@main}{}
   \else % case 0,2 (main is ldf)

Modified: trunk/Master/texmf-dist/tex/generic/babel/hyphen.cfg
===================================================================
--- trunk/Master/texmf-dist/tex/generic/babel/hyphen.cfg	2024-10-20 20:22:44 UTC (rev 72606)
+++ trunk/Master/texmf-dist/tex/generic/babel/hyphen.cfg	2024-10-20 20:23:26 UTC (rev 72607)
@@ -37,10 +37,10 @@
     \wlog{File: #1 #4 #3 <#2>}%
     \let\ProvidesFile\@undefined}
 \fi
-\ProvidesFile{hyphen.cfg}[2024/10/05 v24.11 Babel hyphens]
+\ProvidesFile{hyphen.cfg}[2024/10/20 v24.12 Babel hyphens]
 \xdef\bbl at format{\jobname}
-\def\bbl at version{24.11}
-\def\bbl at date{2024/10/05}
+\def\bbl at version{24.12}
+\def\bbl at date{2024/10/20}
 \ifx\AtBeginDocument\@undefined
   \def\@empty{}
 \fi

Modified: trunk/Master/texmf-dist/tex/generic/babel/locale/el/babel-el-polyton.ini
===================================================================
--- trunk/Master/texmf-dist/tex/generic/babel/locale/el/babel-el-polyton.ini	2024-10-20 20:22:44 UTC (rev 72606)
+++ trunk/Master/texmf-dist/tex/generic/babel/locale/el/babel-el-polyton.ini	2024-10-20 20:23:26 UTC (rev 72607)
@@ -4,8 +4,8 @@
 
 [identification]
 charset             = utf8
-version = 1.1
-date = 2023-04-10
+version = 1.2
+date = 2024-10-14
 name.local          = Ἐλληνικά
 ; Name from https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry
 name.english        = Polytonic Greek
@@ -196,7 +196,7 @@
 lower.ancient.1 = α β γ δ ε ϛ ζ η θ
 lower.ancient.2 = ι κ λ μ ν ξ ο π ϟ
 lower.ancient.3 = ρ σ τ υ φ χ ψ ω ϡ
-lower.ancient.4 = ͵α ͵β ͵γ ͵δ ͵ε ͵Ϛ ͵ζ ͵η ͵θ
+lower.ancient.4 = ͵α ͵β ͵γ ͵δ ͵ε ͵ϛ ͵ζ ͵η ͵θ
 lower.ancient.S.321 = ʹ
 upper.ancient.1 = Α Β Γ Δ Ε Ϛ Ζ Η Θ
 upper.ancient.2 = Ι Κ Λ Μ Ν Ξ Ο Π Ϟ

Modified: trunk/Master/texmf-dist/tex/generic/babel/locale/el/babel-el.ini
===================================================================
--- trunk/Master/texmf-dist/tex/generic/babel/locale/el/babel-el.ini	2024-10-20 20:22:44 UTC (rev 72606)
+++ trunk/Master/texmf-dist/tex/generic/babel/locale/el/babel-el.ini	2024-10-20 20:23:26 UTC (rev 72607)
@@ -9,8 +9,8 @@
 
 [identification]
 charset = utf8
-version = 1.10
-date = 2023-04-10
+version = 1.11
+date = 2024-10-14
 name.local = Ελληνικά
 name.english = Greek
 name.babel = greek monotonicgreek
@@ -200,7 +200,7 @@
 lower.ancient.1 = α β γ δ ε ϛ ζ η θ
 lower.ancient.2 = ι κ λ μ ν ξ ο π ϟ
 lower.ancient.3 = ρ σ τ υ φ χ ψ ω ϡ
-lower.ancient.4 = ͵α ͵β ͵γ ͵δ ͵ε ͵Ϛ ͵ζ ͵η ͵θ
+lower.ancient.4 = ͵α ͵β ͵γ ͵δ ͵ε ͵ϛ ͵ζ ͵η ͵θ
 lower.ancient.S.321 = ʹ
 upper.ancient.1 = Α Β Γ Δ Ε Ϛ Ζ Η Θ
 upper.ancient.2 = Ι Κ Λ Μ Ν Ξ Ο Π Ϟ

Modified: trunk/Master/texmf-dist/tex/generic/babel/locale/el/babel-greek.tex
===================================================================
--- trunk/Master/texmf-dist/tex/generic/babel/locale/el/babel-greek.tex	2024-10-20 20:22:44 UTC (rev 72606)
+++ trunk/Master/texmf-dist/tex/generic/babel/locale/el/babel-greek.tex	2024-10-20 20:23:26 UTC (rev 72607)
@@ -41,12 +41,12 @@
   \def\greek at num@format#1#2#3#4#5#6#7#8{%
     \BabelGreekNumeralMarker{%
       \BabelGreekNumeralMyriads#1#2#3#4%
-      \ifcase#5\or ͵α\or ͵β\or ͵γ\or ͵δ\or ͵ε\or ͵Ϛ\or ͵ζ\or ͵η\or ͵θ\fi
+      \ifcase#5\or ͵α\or ͵β\or ͵γ\or ͵δ\or ͵ε\or ͵ϛ\or ͵ζ\or ͵η\or ͵θ\fi
       \ifnum#6#7#8=\z@\else
         \BabelGreekNumeralMarkerEnd{%
           \ifcase#6\or ρ\or σ\or τ\or υ\or φ\or χ\or ψ\or ω\or ϡ\fi
           \ifcase#7\or ι\or κ\or λ\or μ\or ν\or ξ\or ο\or π\or ϟ\fi
-          \ifcase#8\or α\or β\or γ\or δ\or ε\or Ϛ\or ζ\or η\or θ\fi}%
+          \ifcase#8\or α\or β\or γ\or δ\or ε\or ϛ\or ζ\or η\or θ\fi}%
       \fi}}
 
   \def\greek at invalid{%

Modified: trunk/Master/texmf-dist/tex/generic/babel/locale/el/babel-polytonicgreek.tex
===================================================================
--- trunk/Master/texmf-dist/tex/generic/babel/locale/el/babel-polytonicgreek.tex	2024-10-20 20:22:44 UTC (rev 72606)
+++ trunk/Master/texmf-dist/tex/generic/babel/locale/el/babel-polytonicgreek.tex	2024-10-20 20:23:26 UTC (rev 72607)
@@ -41,12 +41,12 @@
   \def\greek at num@format#1#2#3#4#5#6#7#8{%
     \BabelGreekNumeralMarker{%
       \BabelGreekNumeralMyriads#1#2#3#4%
-      \ifcase#5\or ͵α\or ͵β\or ͵γ\or ͵δ\or ͵ε\or ͵Ϛ\or ͵ζ\or ͵η\or ͵θ\fi
+      \ifcase#5\or ͵α\or ͵β\or ͵γ\or ͵δ\or ͵ε\or ͵ϛ\or ͵ζ\or ͵η\or ͵θ\fi
       \ifnum#6#7#8=\z@\else
         \BabelGreekNumeralMarkerEnd{%
           \ifcase#6\or ρ\or σ\or τ\or υ\or φ\or χ\or ψ\or ω\or ϡ\fi
           \ifcase#7\or ι\or κ\or λ\or μ\or ν\or ξ\or ο\or π\or ϟ\fi
-          \ifcase#8\or α\or β\or γ\or δ\or ε\or Ϛ\or ζ\or η\or θ\fi}%
+          \ifcase#8\or α\or β\or γ\or δ\or ε\or ϛ\or ζ\or η\or θ\fi}%
       \fi}}
 
   \def\greek at invalid{%

Modified: trunk/Master/texmf-dist/tex/generic/babel/locale/grc/babel-ancientgreek.tex
===================================================================
--- trunk/Master/texmf-dist/tex/generic/babel/locale/grc/babel-ancientgreek.tex	2024-10-20 20:22:44 UTC (rev 72606)
+++ trunk/Master/texmf-dist/tex/generic/babel/locale/grc/babel-ancientgreek.tex	2024-10-20 20:23:26 UTC (rev 72607)
@@ -49,12 +49,12 @@
   \def\greek at num@format#1#2#3#4#5#6#7#8{%
     \BabelGreekNumeralMarker{%
       \BabelGreekNumeralMyriads#1#2#3#4%
-      \ifcase#5\or ͵α\or ͵β\or ͵γ\or ͵δ\or ͵ε\or ͵Ϛ\or ͵ζ\or ͵η\or ͵θ\fi
+      \ifcase#5\or ͵α\or ͵β\or ͵γ\or ͵δ\or ͵ε\or ͵ϛ\or ͵ζ\or ͵η\or ͵θ\fi
       \ifnum#6#7#8=\z@\else
         \BabelGreekNumeralMarkerEnd{%
           \ifcase#6\or ρ\or σ\or τ\or υ\or φ\or χ\or ψ\or ω\or ϡ\fi
           \ifcase#7\or ι\or κ\or λ\or μ\or ν\or ξ\or ο\or π\or ϟ\fi
-          \ifcase#8\or α\or β\or γ\or δ\or ε\or Ϛ\or ζ\or η\or θ\fi}%
+          \ifcase#8\or α\or β\or γ\or δ\or ε\or ϛ\or ζ\or η\or θ\fi}%
       \fi}}
 
   \def\greek at invalid{%

Modified: trunk/Master/texmf-dist/tex/generic/babel/locale/grc/babel-grc.ini
===================================================================
--- trunk/Master/texmf-dist/tex/generic/babel/locale/grc/babel-grc.ini	2024-10-20 20:22:44 UTC (rev 72606)
+++ trunk/Master/texmf-dist/tex/generic/babel/locale/grc/babel-grc.ini	2024-10-20 20:23:26 UTC (rev 72607)
@@ -11,8 +11,8 @@
 
 [identification]
 charset = utf8
-version = 1.8
-date = 2022-07-28
+version = 1.9
+date = 2024-10-14
 name.local = Αρχαία ελληνικά
 name.english = Ancient Greek 
 name.babel = ancientgreek
@@ -179,7 +179,7 @@
 lower.ancient.1 = α β γ δ ε ϛ ζ η θ
 lower.ancient.2 = ι κ λ μ ν ξ ο π ϟ
 lower.ancient.3 = ρ σ τ υ φ χ ψ ω ϡ
-lower.ancient.4 = ͵α ͵β ͵γ ͵δ ͵ε ͵Ϛ ͵ζ ͵η ͵θ
+lower.ancient.4 = ͵α ͵β ͵γ ͵δ ͵ε ͵ϛ ͵ζ ͵η ͵θ
 lower.ancient.S.321 = ʹ
 upper.ancient.1 = Α Β Γ Δ Ε Ϛ Ζ Η Θ
 upper.ancient.2 = Ι Κ Λ Μ Ν Ξ Ο Π Ϟ

Modified: trunk/Master/texmf-dist/tex/generic/babel/locale/kmr/babel-kmr.ini
===================================================================
--- trunk/Master/texmf-dist/tex/generic/babel/locale/kmr/babel-kmr.ini	2024-10-20 20:22:44 UTC (rev 72606)
+++ trunk/Master/texmf-dist/tex/generic/babel/locale/kmr/babel-kmr.ini	2024-10-20 20:23:26 UTC (rev 72607)
@@ -13,7 +13,7 @@
 date = 2020-06-30
 name.local = Kurmancî
 name.english = Northern Kurdish
-name.babel = kurmanji northernkurdish
+name.babel = northernkurdish kurmanji
 name.polyglossia = kurdish
 tag.bcp47 = kmr
 language.tag.bcp47 = kmr

Modified: trunk/Master/texmf-dist/tex/generic/babel/luababel.def
===================================================================
--- trunk/Master/texmf-dist/tex/generic/babel/luababel.def	2024-10-20 20:22:44 UTC (rev 72606)
+++ trunk/Master/texmf-dist/tex/generic/babel/luababel.def	2024-10-20 20:23:26 UTC (rev 72607)
@@ -224,6 +224,22 @@
       callback.register('process_input_buffer',Babel.callback)
     end
   end
+  Babel.linebreaking = Babel.linebreaking or {}
+  Babel.linebreaking.before = {}
+  Babel.linebreaking.after = {}
+  Babel.locale = {}
+  function Babel.linebreaking.add_before(func, pos)
+    tex.print([[\noexpand\csname bbl at luahyphenate\endcsname]])
+    if pos == nil then
+      table.insert(Babel.linebreaking.before, func)
+    else
+      table.insert(Babel.linebreaking.before, pos, func)
+    end
+  end
+  function Babel.linebreaking.add_after(func)
+    tex.print([[\noexpand\csname bbl at luahyphenate\endcsname]])
+    table.insert(Babel.linebreaking.after, func)
+  end
   function Babel.addpatterns(pp, lg)
     local lg = lang.new(lg)
     local pats = lang.patterns(lg) or ''
@@ -290,9 +306,9 @@
          str:find( [[\string\babelsublr]] ) then
      str = str:gsub( [[\string\babelsublr%s*(%b{})]],
                      function(m) return m:sub(2,-2) end )
-   end
-   return str
-end
+     end
+     return str
+  end
 }
 \endgroup
 \ifx\newattribute\@undefined\else % Test for plain
@@ -374,24 +390,6 @@
               {\csname bbl at patterns@\bbl at tempa\endcsname\space}%
             #2}}}%
     \fi}}
-\directlua{% DL5
-  Babel.linebreaking = Babel.linebreaking or {}
-  Babel.linebreaking.before = {}
-  Babel.linebreaking.after = {}
-  Babel.locale = {} % Free to use, indexed by \localeid
-  function Babel.linebreaking.add_before(func, pos)
-    tex.print([[\noexpand\csname bbl at luahyphenate\endcsname]])
-    if pos == nil then
-      table.insert(Babel.linebreaking.before, func)
-    else
-      table.insert(Babel.linebreaking.before, pos, func)
-    end
-  end
-  function Babel.linebreaking.add_after(func)
-    tex.print([[\noexpand\csname bbl at luahyphenate\endcsname]])
-    table.insert(Babel.linebreaking.after, func)
-  end
-}
 \def\bbl at intraspace#1 #2 #3\@@{%
   \directlua{
     Babel.intraspaces = Babel.intraspaces or {}
@@ -1624,6 +1622,115 @@
     \fi\fi}
 \fi
 \def\bbl at provide@extra#1{%
+   % == onchar ==
+  \ifx\bbl at KVP@onchar\@nnil\else
+    \bbl at luahyphenate
+    \bbl at exp{%
+      \\\AddToHook{env/document/before}{{\\\select at language{#1}{}}}}%
+    \directlua{
+      if Babel.locale_mapped == nil then
+        Babel.locale_mapped = true
+        Babel.linebreaking.add_before(Babel.locale_map, 1)
+        Babel.loc_to_scr = {}
+        Babel.chr_to_loc = Babel.chr_to_loc or {}
+      end
+      Babel.locale_props[\the\localeid].letters = false
+    }%
+    \bbl at xin@{ letters }{ \bbl at KVP@onchar\space}%
+    \ifin@
+      \directlua{
+        Babel.locale_props[\the\localeid].letters = true
+      }%
+    \fi
+    \bbl at xin@{ ids }{ \bbl at KVP@onchar\space}%
+    \ifin@
+      \ifx\bbl at starthyphens\@undefined % Needed if no explicit selection
+        \AddBabelHook{babel-onchar}{beforestart}{{\bbl at starthyphens}}%
+      \fi
+      \bbl at exp{\\\bbl at add\\\bbl at starthyphens
+        {\\\bbl at patterns@lua{\languagename}}}%
+      \directlua{
+        if Babel.script_blocks['\bbl at cl{sbcp}'] then
+          Babel.loc_to_scr[\the\localeid] = Babel.script_blocks['\bbl at cl{sbcp}']
+          Babel.locale_props[\the\localeid].lg = \the\@nameuse{l@\languagename}\space
+        end
+      }%
+    \fi
+    \bbl at xin@{ fonts }{ \bbl at KVP@onchar\space}%
+    \ifin@
+      \bbl at ifunset{bbl at lsys@\languagename}{\bbl at provide@lsys{\languagename}}{}%
+      \bbl at ifunset{bbl at wdir@\languagename}{\bbl at provide@dirs{\languagename}}{}%
+      \directlua{
+        if Babel.script_blocks['\bbl at cl{sbcp}'] then
+          Babel.loc_to_scr[\the\localeid] =
+            Babel.script_blocks['\bbl at cl{sbcp}']
+        end}%
+      \ifx\bbl at mapselect\@undefined  % TODO. almost the same as mapfont
+        \AtBeginDocument{%
+          \bbl at patchfont{{\bbl at mapselect}}%
+          {\selectfont}}%
+        \def\bbl at mapselect{%
+          \let\bbl at mapselect\relax
+          \edef\bbl at prefontid{\fontid\font}}%
+        \def\bbl at mapdir##1{%
+          \begingroup
+            \setbox\z@\hbox{% Force text mode
+              \def\languagename{##1}%
+              \let\bbl at ifrestoring\@firstoftwo % To avoid font warning
+              \bbl at switchfont
+              \ifnum\fontid\font>\z@ % A hack, for the pgf nullfont hack
+                \directlua{
+                  Babel.locale_props[\the\csname bbl at id@@##1\endcsname]%
+                          ['/\bbl at prefontid'] = \fontid\font\space}%
+              \fi}%
+          \endgroup}%
+      \fi
+      \bbl at exp{\\\bbl at add\\\bbl at mapselect{\\\bbl at mapdir{\languagename}}}%
+    \fi
+    % TODO - catch non-valid values
+  \fi
+  % == mapfont ==
+  % For bidi texts, to switch the font based on direction
+  \ifx\bbl at KVP@mapfont\@nnil\else
+    \bbl at ifsamestring{\bbl at KVP@mapfont}{direction}{}%
+      {\bbl at error{unknown-mapfont}{}{}{}}%
+    \bbl at ifunset{bbl at lsys@\languagename}{\bbl at provide@lsys{\languagename}}{}%
+    \bbl at ifunset{bbl at wdir@\languagename}{\bbl at provide@dirs{\languagename}}{}%
+    \ifx\bbl at mapselect\@undefined % TODO. See onchar.
+      \AtBeginDocument{%
+        \bbl at patchfont{{\bbl at mapselect}}%
+        {\selectfont}}%
+      \def\bbl at mapselect{%
+        \let\bbl at mapselect\relax
+        \edef\bbl at prefontid{\fontid\font}}%
+      \def\bbl at mapdir##1{%
+        {\def\languagename{##1}%
+         \let\bbl at ifrestoring\@firstoftwo % avoid font warning
+         \bbl at switchfont
+         \directlua{Babel.fontmap
+           [\the\csname bbl at wdir@##1\endcsname]%
+           [\bbl at prefontid]=\fontid\font}}}%
+    \fi
+    \bbl at exp{\\\bbl at add\\\bbl at mapselect{\\\bbl at mapdir{\languagename}}}%
+  \fi
+  % == Line breaking: CJK quotes ==
+  \ifcase\bbl at engine\or
+    \bbl at xin@{/c}{/\bbl at cl{lnbrk}}%
+    \ifin@
+      \bbl at ifunset{bbl at quote@\languagename}{}%
+        {\directlua{
+           Babel.locale_props[\the\localeid].cjk_quotes = {}
+           local cs = 'op'
+           for c in string.utfvalues(%
+               [[\csname bbl at quote@\languagename\endcsname]]) do
+             if Babel.cjk_characters[c].c == 'qu' then
+               Babel.locale_props[\the\localeid].cjk_quotes[c] = cs
+             end
+             cs = ( cs == 'op') and 'cl' or 'op'
+           end
+        }}%
+    \fi
+  \fi
   % == Counters: mapdigits ==
   % Native digits
   \ifx\bbl at KVP@mapdigits\@nnil\else

Modified: trunk/Master/texmf-dist/tex/generic/babel/nil.ldf
===================================================================
--- trunk/Master/texmf-dist/tex/generic/babel/nil.ldf	2024-10-20 20:22:44 UTC (rev 72606)
+++ trunk/Master/texmf-dist/tex/generic/babel/nil.ldf	2024-10-20 20:23:26 UTC (rev 72607)
@@ -32,7 +32,7 @@
 %% and covered by LPPL is defined by the unpacking scripts (with
 %% extension |.ins|) which are part of the distribution.
 %%
-\ProvidesLanguage{nil}[2024/10/05 v24.11 Nil language]
+\ProvidesLanguage{nil}[2024/10/20 v24.12 Nil language]
 \LdfInit{nil}{datenil}
 \ifx\l at nil\@undefined
   \newlanguage\l at nil



More information about the tex-live-commits mailing list.