French unbreakable spaces rule

Hello !

Context

In the french typography rules, some characters have unbreakable spaces before them and normal spaces after. So for instance : should be (in typst) ~: . You might see the issue that it can becomes quickly long to deal manually with that for every of these characters.

First solution that does not work

So I tried to make this next code:

/*
 * Define french rules with characters which need unbreakable space.
 */
#let unbreakable = (
  ":",
  ";",
  "?",
  "!",
  "=",
  "/",
  "%",
)

#show regex(" ?([" + unbreakable.join() + "]) ?" ): it => [~#it.text.trim() ]

And it was working perfectly. For instance next code:

interaction:

Give this results:
image

However, I tried to write link()… Which gave a weird results. Every : and / have, obviously, spaces around them. So this solution is not quite good. Here an example on how it looks using next code:

https://typst.app

Give:
image

So how one could correct this issue?

I thought about maybe replacing unbreakable spaces inside links (using #show link), but #show regex apply last (or have higher priority, I am not sure). Meaning that inside link, I have access to the plain URL. Then I can modify it, then #show regex do its jobs. I though about making a condition too inside the regex to apply to everything BUT #link(). I fail to find something…

Thanks for you help!

Hi. You can fix all your problems if you just write by the rules.

#let unbreakable = (":", ";", "?", "!", "=", "/", "%")
#show regex(" [" + unbreakable.join() + "] "): it => [~#it.text.trim() ]

#block(width: 0pt)[interaction : #lorem(3)]
https://typst.app

Or I guess you can compromise:

#let unbreakable = (":", ";", "?", "!", "=", "/", "%")
#show regex(" ?[" + unbreakable.join() + "] "): it => [~#it.text.trim() ]

#block(width: 0pt)[interaction: #lorem(3)]
https://typst.app
1 Like

Hi there @lucas.rouaud, welcome to the forum and thank you for your post. Thanks @Andrew for your answer.

You may be interested to read (and participate) into this related issue and discussion:

Spaces after « and before » should be nobreak in french · Issue #1920 · typst/typst · GitHub.

Also, if you are interested in fine typography, there is a distinction between the two non-breaking spaces in French (for France):

Non-breaking space

  • \u{00A0} or #sym.space.nobreak or ~ in code
    • before :
    • inside the quotes « and », and

Narrow non-breaking space

  • \u{202F} or #sym.space.nobreak.narrow
    • before ;, ? and !,
    • before the thousands separator, and
    • before some symbols such as % and €.

There is still some work to be done for Typst to comply with the French language spacing rules, but it is coming up.

It is already working out of the box for some characters:

#lorem(14) A test » (No)\
#lorem(14) A test ! (Yes)\
#lorem(14) A test ? (Yes)\
#lorem(14) A test : (Yes)\
#lorem(14) A test ; (Yes)\

2 Likes

What would be awesome is if it worked for the French smart quotes.

There is this show rule, but quotes are not mentioned in the OP.

1 Like

Hi @Andrew and @vmartel08!

Thanks a lot for your answers. The solution is a mix of both your answers!

Solution

I decide to go with:

/*
 * Define french rules with characters which need unbreakable space.
 */
let thin_unbreakable = (
  ";",
  "?",
  "!",
)

show regex(" ([" + thin_unbreakable.join() + "]) ?" ): it => {
  [#sym.space.nobreak.narrow#it.text.trim() ]
}

Because as point by @vmartel08, some characters already have unbreakable space if you do, for instance, toto :. I just keep my reflex from LaTeX by doing toto: (which will then add an unbreakable space). Note that I did this modification to have “thin” unbreakable space instead of the normal unbreakable ones.

Specification

About the thin unbreakable VS unbreakable. I knew about thin one between digits, but I did not for symbol like the question mark. So thanks a lot @vmartel08 for the specification. By the way, I made quick test, but doing this:

#lorem(7) "— bonjour, je m'appelle François."

#lorem(7) « — bonjour, je m'appelle François. »

Is actually working (for the first case):

You just need to set up the language to "fr". Thanks again for your help!

1 Like