latex3 / babel

The babel system for LaTeX, LuaLaTeX and XeLaTeX
LaTeX Project Public License v1.3c
125 stars 34 forks source link

\selectlanguage{<lang>} triggers \noextras<lang> even if selected language is already <lang> #190

Closed jfbu closed 1 year ago

jfbu commented 1 year ago
\documentclass{article}

\usepackage[french]{babel}

\addto\noextrasfrench{\show\noextrasfrenchNowExecuted}
\begin{document}

\selectlanguage{french}

A
\end{document}

Executing this with latex (twice so aux file is done on second run) demonstrates that \noextrasfrench is executed a number of times.

The babel.pdf says "There is a counterpart for code to be run when a language is unselected: \noextras⟨lang⟩."

But here selecting French causes also first its "un-selection" configuration to be executed.

It turns out babel-french/french.ldf adds \std@math@comma to \noextrasfrench. This is a macro to reset the mathcode of the comma to its original value.

This causes the following problem:

Thus, any attempt from some package to turn from inside the preamble the comma into a math active character (or assign to it some other mathcode) is overruled.

The icomma package does that but babel-french tests for it and does not put anything in \noextrasfrench then. Not so with ncccomma which is another package with makes the comma math active (or more generally speaking modifies its mathcode).

As a result, in presence of babel-french, using numprint with autolanguage is incompatible with (overrules) ncccomma. I hit against this by reading the documentation of package frenchmath which mentions such incompatibility, which incited me into elucidating its mechanism.

Fixing this by re-establishing the math activity of the comma by one more extension to \noextrasfrench is a no-go, because it will make the comma active also under other languages, which is not desired.

(it is made active by packages such as icomma or ncccomma to handle numbers where the decimal separator is a comma, as in French conventions).

The reason that babel-french adds the \std@math@comma is because it has a command \DecimalMathComma which triggers modification of the comma math code to be of mathpunct mathord (edited typo) type, each time French language is entered. So I guess it is logical that on exiting the French language a reset is done (edit: for the comma to recover its default mathpunct status).

Rather to report this to babel-french with a request that it also becomes aware of ncccomma and not only icomma I figured I would report it here, because it appears that a simpler thing would be for \selectlanguage{<lang>} to not execute \noextras<lang> when there is no actual change of language.

(whether \extras<lang> should be executed in this context is another matter; if it is expected that \selectlanguage{<lang>} does some kind of reset, this has its logic, but I would venture to say that depending on what language module authors put inthere, and considering \selectlanguage{<lang>} may be caused by some unexpected external sources --- like package numprint with autolanguage option influencing at begin document --- one could naively argue that perhaps \selectlanguage{<lang>} should be completely transparent when language is already the selected one)

jbezos commented 1 year ago

This is by design, because changes must be done in a balanced way. If \selectlanguage{french} redefines a macro and saves the old definition, a subsequent \selectlanguage{french} without \noextras... will save the new (French) definition and the old one will be lost forever, ie, it won’t be restored if you switch to another language.

jfbu commented 1 year ago

I can see the underlying logic of balanced changes. I focused on \noextras<lang> as It was sort of new to me, but then the question probably is to be seen as: why execute (both) \extras<lang> and \noextras<lang> on \selectlanguage{<lang>} when language is not actually changing ? (I was reaching that at the end of my inital post, but with some hesitation not having spent the needed time to examine the babel documentation).

As per my initial context, the root problem is in babel-french putting in \noextras<lang> some action which is configured arguably too early in preamble. The language module is aware of that as it tests for presence of one package (icomma); a more general approach would let it wait for at begin document to check the mathcode of the comma rather than freeze its value at the time of french.ldf loading.

I am aware it is unlikely the comma will end up being assigned to another math family, and that (in 8bit engines) one could almost as well assume it is always"613B, but in some contexts this may prove wrong, and not only because of some attempt to make it math active. Although fully aware this is not directly the matter of this issue tracker, I am adding here a mwe for having it recorded somewhere.

\documentclass{article}
\usepackage[french]{babel}
\usepackage{mathastext}
% \showthe\mathcode`,
\begin{document}

\the\mathcode`,  (mathcode as set by mathastext)

\selectlanguage{french} (selecting French at a time we are already in French)

\the\mathcode`,  (mathcode was reverted and changed)

\end{document}
jbezos commented 1 year ago

It was sort of new to me, but then the question probably is to be seen as: why execute (both) \extras<lang> and \noextras<lang> on \selectlanguage{<lang>} when language is not actually changing ?

This is a good question. More precisely: should \selectlanguage{<lang>} mean ‘(re)select the language to make sure its definitions are in force in case they have been changed somehow‘ (which is a valid behavior and, in my experience, useful) or should it mean ‘just make sure the language is <lang> by selecting it if and only if necessary’. It can be argued that in the latter case all you need is to add a simple test to check the current language. From its beginnings, babel has opted for the former behavior. The second one makes sense, too, but the current one won’t change (maybe as an option, but not by default).

jbezos commented 1 year ago

I’m closing this issue because the current behavior of \selectlanguage and \(no)extras... is the intended one. Please, consider reporting the issue to the maintainers of french or the other packages.