# How to get/suppress french spacing before punctuation in \href

Attention I have already a possible answer and will add it soon. I thought it would be useful to have a solution about it on the site. (Other answers are naturally welcome too).

Question How to activate or suppress the french spacing before some punctuations like a colon in the text argument of \href locally (for one specific \href) and globally? Switching the language is not an answer!

Minimal examples for tests (the argument of \href should normally be a valid url, so it is a bit unfair to add an example without a colon in the link):

# pdflatex

With pdflatex it depends on the link how the argument of \href is printed:

\documentclass{article}
\usepackage[french]{babel}

\usepackage{hyperref}

\begin{document}
With pdflatex no french spacing in links with colons:

\end{document}


## lualatex

With lualatex the spaces are always there:

\documentclass{article}
\usepackage[french]{babel}

\usepackage{hyperref}

\begin{document}
With lualatex always spaces:

\end{document}


The issue mentioned by Ulrike Fisher with lualatex can be easily fixed. This is done in babel-french’s new version (3.3d) which is on the way to CTAN.

The fix is not related to \href; the way babel-french works now is as follows: to decide whether a non-breaking space should be added or not before the colon, the luatex code checks both nodes surrounding the :’.

1) If a glue (actually width>1sp) is found before the colon, it is removed and replaced by a non-breaking space (penalty + appropriate glue).

2) If no space precedes the colon, in default mode (AutoSpacePunctuation=true), a non-breaking space is added before the colon only if the next node is not a glyph (this is new to v.3.3d).

This way, URLs, MS-DOS paths (C:\Program Files) and timetables (10:55) no longer require {\NoAutoSpacing ...} to be printed correctly. This works for luatex only, my attempts to do the same using \futurelet failed with xetex and lead to unreliable results with pdftex.

@jfbu: "the \hskip1sp trick" (\href{link:colon}{a\hskip1sp:b}) is neither indicative of some kind of possible bug’’ in babel-french, nor an alternative to the documented \NoAutoSpacing command.

As explained in the documented code of babel-french, this trick is meant for tabular l’ columns: the following exemple’s output is correct with lualatex (left image) and wrong with xelatex (right image) and pdflatex.

\documentclass[french]{article}
\usepackage{babel}
\begin{document}
\begin{tabular}{|l|l|}
\hline
Char&Code\\ \hline
.&U+002E\\
:&U+003A\\
\hline
\end{tabular}
\end{document}


Unfortunately, the XeTeXinterchar mechanism provides one single class (4095) for all non-characters tokens (glues, kerns, penalties, \hbox, math boundaries, etc.); this is not sufficient to distinguish between small glues (<=1sp, which should not trigger extra space) and other tokens which do require extra space before French high punctuation characters.

• Thanks that you are trying so hard to improve the situation! – Ulrike Fischer Oct 21 '17 at 10:20

The behaviour of \href is different for links with a colon as hyperref does a sort of "link type" recognition. If a colon is found in the link, the text argument is passed through \hyper@linkurl which calls hyper@chars which deactivates active chars.

The following code shows a number of possibilities. It works with xelatex too. It contains a number of zzz in the patches which are only for demo! They show which \href are affected by a patch.

\documentclass{scrartcl}
\usepackage[ngerman,french]{babel}

\usepackage{hyperref,etoolbox,ifluatex}

\begin{document}
\minisec{Default behaviour \ifluatex lualatex \else pdflatex \fi}

\selectlanguage{ngerman}

\selectlanguage{french}

\minisec{Suppress the space locally}

\href{link:colon}{\csname NoAutoSpacing\endcsname a:bcolon} %not needed with pdflatex

\minisec{Activate the space locally}
(will activate other active characters too)

\href{link}{\csname @safe@activesfalse\endcsname a:b} %not needed, default

\href{link:colon}{\csname @safe@activesfalse\endcsname a:bcolon}%not needed with lualatex

\selectlanguage{ngerman}

\href{link}{\csname @safe@activesfalse\endcsname a"=b} %not needed, default

\selectlanguage{french}

\minisec{Suppress the space globally/for a group}
The \texttt{zzz} is only for demo!

\begin{enumerate}
\item With \verb+\NoAutoSpacing+
\begingroup
\makeatletter
{\expandafter{\Hy@tempb}{#4}}
{\expandafter{\Hy@tempb}{zzz\csname NoAutoSpacing\endcsname #4}}
{}{\fail}
\makeatother

\selectlanguage{ngerman}

\selectlanguage{french}

\endgroup

\item With \verb+\@safe@activestrue+. This will affect other active chars too.
\begingroup
\makeatletter
{\expandafter{\Hy@tempb}{#4}}
{\expandafter{\Hy@tempb}{zzz\csname @safe@activestrue\endcsname #4}}
{}{\fail}
\makeatother

\selectlanguage{ngerman}

\selectlanguage{french}

\endgroup

\end{enumerate}

\minisec{Activate the space globally/for a group}

\begin{enumerate}
\item Activate the space by deactivating \verb+\Hy@safe@activestrue+ in
\verb+\hyper@chars+. This affects only links with colons as can seen by the \texttt{zzz}. It
affects also other active chars.

\begingroup
\makeatletter
\renewcommand*\hyper@chars{%
\let\#\hyper@hash
\let\%\@percentchar
%\Hy@safe@activestrue
zzz %for demo only!
}

\selectlanguage{ngerman}

\selectlanguage{french}

\endgroup

This affects both types as seen by the \texttt{zzz}. It also affects other active chars.
\begingroup
\makeatletter
{\expandafter{\Hy@tempb}{#4}}
{\expandafter{\Hy@tempb}{zzz\csname @safe@activesfalse\endcsname #4}}
{}{\fail}
\makeatother

\selectlanguage{ngerman}

\selectlanguage{french}

\endgroup

\end{enumerate}

\end{document}


## Output of lualatex

For one specific \href, a solution working with lualatex (but not with xelatex and pdflatex) is

\href{link:colon}{a\hskip1sp:b}


That it works is indicative of some kind of possible bug of frenchb.

For pdflatex one can use \string: rather, but in default case where the link itself has a colon, the \string: is not needed.

For xelatex the mechanism is othe ne of \XeTeXinterchartokenstate I don't know simple mark-up to deactivate it (apart from turning if off), but anyhow for the local problem here it is always possible (and this is the frenchb documentation recommended method) to use

{\NoAutoSpacing\href{link:colon}{a:b}}


This works will all engines of course.

For globally turning extra French spaces off in \href (works with all engines):

\makeatletter
\let\originalhyper@normalise\hyper@normalise
\def\hyper@normalise{\NoAutoSpacing\originalhyper@normalise}
\makeatother


Default \hyper@normalise starts with a \begingroup, but two semi-simple groups are already entered when the added \NoAutoSpacing gets executed, so no worries here, its effect will be local to the \href execution.

@Ulrike asks about activating the French spaces in the \href text. As seen above this is the case by default with LuaLaTeX, XeLaTeX, so I address here the PDFLaTeX case. For this, use

\href{http://www.foo.com}{\@safe@activesfalse a:b}


Of course this is a bit inconvenient, needs \makeatletter, etc..

Again, hyperref mechanism to de-activate the Babel shorthands fails for frenchb with lualatex/xelatex because frenchb does not use active characters and does not tell Babel to find a way to extend its de-activating mechanism to non-Babel shorthands... which is a bit understandable but causes this issue here that lualatex/xelatex behave differently than pdflatex for \href. (perhaps frenchb should actually declare fake Babel shorthands in lualatex/xelatex case and insert its \FB@spacingfalse locally in the inert form, but has to be local; not thought much more.)

If one wants to do this globally:

\begingroup
\catcode$6 \catcode# 12 \gdef\href@split$1#$2#$3\\$4{\hyper@@link {$1}{$2}{\@safe@activesfalse$4}\endgroup }
\endgroup


There is a way to inject a hack into second argument of \href and force changed catcode regime of the first argument:

\protected\def\myhref#1#2{{%
% \mymacrochangingcatcodes % for example
\endlinechar\m@ne\everyeof{{\@safe@activesfalse#2}}%
\scantokens{\href{#1}}%
}}


This way one does not need to hack some internal macro.

• don't do this if spaces are active, (i.e. make space char non active before the \scantokens),

• of course, one needs to re-instore all needed catcode changes href does for first argument, for example the catcode of # or the one of %, and for the latter it is not possible, because it is too late, for \myhref to have authorized a % in first argument,

• the idea here is in case one needs to change more catcodes than those handled by default by hyperref, (and % must be coded \% to start with in link).

• in this example with an extra \@safe@activesfalse in second argument the hyperref test for an empty second argument will always take the False branch, but this does not look very important (and applies also to the \href@split hacking above)

Such method can be useful when attempting to use \href in context with altered catcodes, beyond what hyperref has provision for. This is however possibly only distantly relevant to the Question here.

• I don't see why you believe that a\hskip1sp:b should work (unless by some side-effect). The code in french.ldf doesn't imply this imho. I don't think that \hyper@normalise is the correct place to patch into hyperref. Code added there will also affect the link, so I wouldn't use if for typesetting effects. Also while suppressing the space works it is imho not possible to activate it there. – Ulrike Fischer Oct 2 '17 at 15:41
• what do you mean? it works, that's all. It looks like a bug of frenchb. And I indicated \NoAutoSpacing as better way. Anyway, the main problem of frenchb (or of babel or both) is that it finds no way to extend the \if@safe@actives babel mechanism to cover its luatex/xetex approaches. hyperref uses this mechanism to get active characters such as : to behave as if non-active (but they still are). As per issuing \NoAutoSpacing in \hyper@normalise the link is not affected. All extra spaces from default do not make it to the dvi ps specials or pdf (I trust) although indeed the – user4686 Oct 2 '17 at 16:14
• \space gets expanded. But one finds in dvi for example ps:SDict begin [/H /I/Border [0 0 1]BorderArrayPatch/Color [0 1 1]/Action <</Subtype/URI/URI(link:colon)>>/Subtype /Link H.B /ANN pdfmark end by default. Adding \NoAutoSpacing changes nothing. – user4686 Oct 2 '17 at 16:15
• a\hskip1sp:b does not work with pdflatex (lualatex is different) and is imho not meant to work. And yes, \if@safe@actives doesn't affect luatex as it doesn't use active chars here. Regarding: \hyper@normalise: There are lots of places in the hyperref code where one can inject the \NoAutoSpacing without doing harm. But that doesn't mean that every place is good. E.g. assume that you don't want to change : so that it suppress the space, but print another glyph instead. How would you do this in \hyper@normalise? – Ulrike Fischer Oct 2 '17 at 16:38
• If you want to affect only the text you have to go via the patching of \href@split as indicated at bottom of my edited answer (I mean by this that \href@split is the earliest opportunity and it is the place to inject arbitrary code into the second argument of \href) . But patching \href@split will imply the hyperref test for empty hyperlink text will fail. Hence \hyper@link@ from your answer perhaps better. However I don't understand, why did you ask this question if you had already decided on which macro to patch? – user4686 Oct 2 '17 at 17:35