Make space width / space usage in front of units consistent

Issue

I’ll explain it based on the image below, which shows a part of my stats screen. The problem also appears in other areas like the deck options though.

Green: The space before units is huge (too huge in my opinion). It looks like a wide space character had been used or spacing had been manually adjusted.
Blue: No spacing had been used.
Red / Pink: Spacing had been used but is much smaller than the green spacing. To me this spacing here looks reasonable though.

Proposed solution

  1. I’d like to have a consistent space character usage.
  2. I’d like to have spaces that are less wide than the green ones above. Maybe like the red / pink ones would be nice, or something in between of those two.

Additional info

It seems that the huge space (green) is caused by   (non-breakable space) characters, whereas the red / pink ones use normal spaces and blue none.

Anki and OS Version

Anki Version

Anki 24.11 (87ccd24e) (ao)
Python 3.9.18 Qt 6.6.2 PyQt 6.6.1
Platform: Linux-6.1.0-0.deb11.21-amd64-x86_64-with-glibc2.31

===Add-ons (active)===
(add-on provided name [Add-on folder, installed at, version, is config changed])
AnkiWebView Inspector [‘31746032’, 2023-06-27T21:26, ‘None’, ‘’]
Image Occlusion Enhanced [‘1374772155’, 2022-04-09T09:15, ‘None’, ‘’]
Review Heatmap [‘1771074083’, 2022-06-30T03:43, ‘None’, ‘’]
Study Time Stats [‘1247171202’, 2024-02-24T17:59, ‘None’, ‘’]

===IDs of active AnkiWeb add-ons===
1247171202 1374772155 1771074083 31746032

===Add-ons (inactive)===
(add-on provided name [Add-on folder, installed at, version, is config changed])

OS and OS Version

Debian linux (oldstable), X11, Gnome.

1 Like
  • The month/year radio buttons across the top of the graphs are also spaced too widely in your screenshot
  • No-space between digit and % is generally correct.

I see none of these spacing issues in my Anki, but it’s different than yours in basically every way :sweat_smile: – English, Windows 11, v 24.06, dark theme – so that doesn’t really help narrow down the issue. But maybe if you try flipping some of those switches, we can help narrow down where the difference is coming from?

The nbsp you’ve noticed suggests to me that the interface language is a likely culprit.

1 Like

True, I missed a few during coloring.

Really? Maybe that’s language specific, as in german a space is the correct form (although often left out).

I switched to us english and the problem indeed disappeared.

I wanted to see if there is a difference in pontoon and indeed there is one (see the colored strings in the image):

I can change it. But is there a way of testing the impact of that change before I continue? I don’t want to break that variable thingy by accident.

I think the correct place to manually edit it is:

<repo root>/ftl/core-repo/core/de/statistics.ftl

I didn’t realise that was a thing that was different in other languages.

I guess that means my update to the True Retention table is technically wrong in some languages. I’ll have to look into the correct way to localise numbers with units/percentages.

2 Likes

For your information, according to the german wikipedia it is the correct form as defined in DIN 5008. Maybe there are similiar DINs in other languages.
Also, technically it is a protected space character. But not sure if that is even possible using pontoon.

Thanks, that worked great! I’ll edit it in pontoon too then.
Edit: nevermind, it isn’t applied.

I just did a quick update to my “tweaks” PR and I think it is working correctly for languages like German now.


2 Likes

Yes, that looks fine!

I just noticed it didn’t change on my anki. Here’s what I did:

  1. Edit that file.
  2. Run ./run command.
  3. Open stats screen
    But the changes aren’t applied. Am I missing something here?

It looks like the build system does not notice changes to the translations so just keeps using a cached old version.

I did a clean build and it worked, but it is very slow if you want to try out lots of different edits.
Unfortunately I don’t know how to force it to regenerate just the translation stuff.

I did:

  1. Run git clean -f -d -x N.B. will purge everything not tracked by git
  2. Edit the translation file
  3. Run ./run
1 Like

Something else I noticed: In debian sid it looks normal but still has the &nbsp; character:

Maybe a bug on debian oldstable? Here’s what I checked:

  • sid and oldstable run the exact same anki (24.11 (87ccd24e)⁩)
  • sid and oldstable use the same font and font sizes
  • I tested oldstable with new, empty anki profile (deleted Anki and Anki2 folders)
  • I tested with no addons enabled / safe mode
  • I changed video driver from OpenGL to software in oldstable
  • I copied Anki and Anki2 folders from oldstable to sid
  • I updated fonts on oldstable

The only difference is that my debian sid is inside a vm.

It doesn’t make sense to me. But if it’s because of oldstable and doesn’t affect newer distros, I’d be fine for me. And for now I can just change the language to US or live with those spaces.

I found something interessting.

My system uses “Noto Sans Regular” font:

In the deck overview it is rightfully set to that font (changing system font changes font in the dev tools as well):

In the stats screen I get this instead:

body {
    ...
    font-family: var(--bs-body-font-family)
    ...
}

which corresponds to this:

system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"

Now look what happens, if I set system-ui font in deck overview:

Suddenly the width of the &nbsp; characters is wrong.

What happens if I remove system-ui in the stats screen? The spacing is normal there, too.

The weird thing is: In debian sid anki uses the exact same css. Besides, directly using

body {
    ...
    font-family: "Noto Sans", sans-serif;
    ...
}

in the stats screen solves this issue completely.

Edit: I found that on debian oldstable there is a font-dummy installed called “System-ui”, which falls back to Vera.ttf: "Bitstream Vera Sans" "Roman" (as shown by sudo fc-match -s "System-ui"). Bitstream Vera Sans has problems with displaying the &nbsp; character correctly though.

I’ll see if I can force another font in anki somehow. There probably is an addon that allows me to permanently overwrite the css (i couldn’t find anything and will probably just switch to english).

Not sure if I should close this thread though. There still is the fact that &nbsp; exists were it probably shouldn’t, since the US english version uses normal spaces there.

I think this is an anki issue due to the following reason:

  1. Anki uses the wrong font in stats, which displays the &nbsp; character wrong on my system (debian oldstable)
  2. I changed my font to something weird and anki now looks like this:

    The stats screen, however, isn’t affected at all:

    If I use dev tools and turn off font-family in body, the font is applied correctly:

    Here’s what it looks like with a normal font (Cantarell):

Using the dev tools it’s evident that body uses a custom font-family, overwriting the correct font-family from html.

Looked into this a little, seemed interesting.

This is where the anki_i18n build step is added, which causes the translations to be codegen’d

I tried doing ninja -v -t clean rslib_i18n && ninja rslib_i18n, but it left the build in an unrecoverable state(?) that could only be fixed by ./tools/clean

As a last resort, I did touch build.rs && cargo build in ./rslib/i18n, which rebuilt the translations and calling ./run after did end up rebuilding its dep tree alone (pylib:rsbridge and pylib:anki:rsbridge), with translation changes being correctly reflected in anki.

It’d be best to ask dae himself, but I’ll leave this here in case it’s helpful to anyone

EDIT: There are rerun-if rules for all translations, not sure why they aren’t being respected

2 Likes

I’m sure you’ll appreciate how far Turkish strays from that path. :sweat_smile:

Unfortunately, I don’t think all of the %-age values are surfaced for translation, so I’ll never be able to reach all of them.

2 Likes

My fix seems to work:

The advantage of fully handing things off to the i18n library instead of making assumptions :sweat_smile:

3 Likes

To get back to the original topic:
Is there a reason the stats screen explicitly sets fonts and e.g. the deck overview doesn’t?

Since disabling the font-family in body (in the stats screen) causes the correct font to be used, even if it’s something weird as shown above, would there be any harm to just remove the font-family from the stats screen?

If not, I could look where it’s defined, remove it and open a PR.

It’s gorgeous!

I’m not sure that Anki is technically doing anything wrong with the fonts.

system-ui is meant to use the default user interface font:

This is meant to work even for the old version of chromium used in the Qt5 version.:

This could be a Qt WebView bug (not handling font-family: system-ui correctly).

It may even technically be fully correct behaviour and is just a weird platform quirk from debian oldstable actually having a font called “System-ui” and overriding the normal behaviour of font-family: system-ui.

I guess potentially something could go wrong if glyphs were used that are missing from the default system font. e.g. emojis

It may be that the English text is wrong for using normal spaces instead of &nbsp;

Using an &nbsp; between numbers and units makes sense to me because it would be really weird to have a line break like:

Studied 123 cards in 30
minutes today

instead of

Studied 123 cards in
30 minutes today
1 Like

I didn’t try it on qt5, only on qt6, which I’m assuming is much newer.

Wouldn’t this affect every OS and OS version then though?

I did try to find out where this “System-ui” font was coming from, asking in the debian IRC chat as well as removing every font I could. No idea where it came from, but it’s there.
And according to fc-match -s "System-ui" the best fitting font (if available) is Vera.ttf: "Bitstream Vera Sans" "Roman" for the “System-ui” on my system. And the bitsream vera font actually does have issues with the &nbsp; character. So the override might actually be the culprit here.

Full list of `fc-match -s "System-ui"` (best font match at top, worst match at the bottom)
Vera.ttf: "Bitstream Vera Sans" "Roman"
DejaVuSans.ttf: "DejaVu Sans" "Book"
DejaVuSans-Bold.ttf: "DejaVu Sans" "Bold"
DejaVuSans-Oblique.ttf: "DejaVu Sans" "Oblique"
DejaVuSans-BoldOblique.ttf: "DejaVu Sans" "Bold Oblique"
n019003l.pfb: "Nimbus Sans L" "Regular"
NimbusSans-Regular.otf: "Nimbus Sans" "Regular"
VL-Gothic-Regular.ttf: "VL Gothic" "regular"
fonts-japanese-gothic.ttf: "IPAGothic" "Regular"
FreeSans.ttf: "FreeSans" "Mittel"
FreeMono.ttf: "FreeMono" "Standard"
FreeSerif.ttf: "FreeSerif" "Mittel"
opens___.ttf: "OpenSymbol" "Regular"
FontAwesome.otf: "FontAwesome" "Regular"
Quicksand-Regular.ttf: "Quicksand" "Regular"
NotoSansAdlam-Regular.ttf: "Noto Sans Adlam" "Regular"
NotoSansWarangCiti-Regular.ttf: "Noto Sans Warang Citi" "Regular"
texgyreadventor-regular.otf: "TeX Gyre Adventor" "Regular"
DejaVuSansMono.ttf: "DejaVu Sans Mono" "Book"
DejaVuSerif.ttf: "DejaVu Serif" "Book"
VL-PGothic-Regular.ttf: "VL PGothic" "regular"
NotoSansHanifiRohingya-Regular.ttf: "Noto Sans Hanifi Rohingya" "Regular"
NotoSansSoraSompeng-Regular.ttf: "Noto Sans Sora Sompeng" "Regular"
LiberationMono-Regular.ttf: "Liberation Mono" "Regular"
NotoSansArabic-Regular.ttf: "Noto Sans Arabic" "Regular"
NotoSansArmenian-Regular.ttf: "Noto Sans Armenian" "Regular"
texgyreschola-regular.otf: "TeX Gyre Schola" "Regular"
NotoSans-Regular.ttf: "Noto Sans" "Regular"
NotoSansNewa-Regular.ttf: "Noto Sans Newa" "Regular"
NotoSansSymbols2-Regular.ttf: "Noto Sans Symbols2" "Regular"
NotoSerifAhom-Regular.ttf: "Noto Serif Ahom" "Regular"
NotoSansBalinese-Regular.ttf: "Noto Sans Balinese" "Regular"
NotoSansMarchen-Regular.ttf: "Noto Sans Marchen" "Regular"
NotoSansOlChiki-Regular.ttf: "Noto Sans Ol Chiki" "Regular"
NotoSansOldHungarian-Regular.ttf: "Noto Sans Old Hungarian" "Regular"
NotoSansOldItalic-Regular.ttf: "Noto Sans Old Italic" "Regular"
NotoSansSharada-Regular.ttf: "Noto Sans Sharada" "Regular"
NotoSansTakri-Regular.ttf: "Noto Sans Takri" "Regular"
NotoSansTifinagh-Regular.ttf: "Noto Sans Tifinagh" "Regular"
NotoSansZanabazarSquare-Regular.ttf: "Noto Sans Zanabazar Square" "Regular"
NotoSerifGujarati-Regular.ttf: "Noto Serif Gujarati" "Regular"
NotoSerifKannada-Regular.ttf: "Noto Serif Kannada" "Regular"
NotoSerifSinhala-Regular.ttf: "Noto Serif Sinhala" "Regular"
NotoSansAvestan-Regular.ttf: "Noto Sans Avestan" "Regular"
NotoSansBengali-Regular.ttf: "Noto Sans Bengali" "Regular"
NotoSansBhaiksuki-Regular.ttf: "Noto Sans Bhaiksuki" "Regular"
NotoSansBrahmi-Regular.ttf: "Noto Sans Brahmi" "Regular"
NotoSansCaucasianAlbanian-Regular.ttf: "Noto Sans Caucasian Albanian" "Regular"
NotoSansChakma-Regular.ttf: "Noto Sans Chakma" "Regular"
NotoSansDevanagari-Regular.ttf: "Noto Sans Devanagari" "Regular"
NotoSansGeorgian-Regular.ttf: "Noto Sans Georgian" "Regular"
NotoSansGrantha-Regular.ttf: "Noto Sans Grantha" "Regular"
NotoSansGurmukhi-Regular.ttf: "Noto Sans Gurmukhi" "Regular"
NotoSansKaithi-Regular.ttf: "Noto Sans Kaithi" "Regular"
NotoSansKharoshthi-Regular.ttf: "Noto Sans Kharoshthi" "Regular"
NotoSansKhmer-Regular.ttf: "Noto Sans Khmer" "Regular"
NotoSansKhojki-Regular.ttf: "Noto Sans Khojki" "Regular"
NotoSansLao-Regular.ttf: "Noto Sans Lao" "Regular"
NotoSansLinearB-Regular.ttf: "Noto Sans Linear B" "Regular"
NotoSansMalayalam-Regular.ttf: "Noto Sans Malayalam" "Regular"
NotoSansMandaic-Regular.ttf: "Noto Sans Mandaic" "Regular"
NotoSansMath-Regular.ttf: "Noto Sans Math" "Regular"
NotoSansMeeteiMayek-Regular.ttf: "Noto Sans Meetei Mayek" "Regular"
NotoSansMiao-Regular.ttf: "Noto Sans Miao" "Regular"
NotoSansMongolian-Regular.ttf: "Noto Sans Mongolian" "Regular"
NotoSansMyanmar-Regular.ttf: "Noto Sans Myanmar" "Regular"
NotoSansNKo-Regular.ttf: "Noto Sans NKo" "Regular"
NotoSansNewTaiLue-Regular.ttf: "Noto Sans New Tai Lue" "Regular"
NotoSansSiddham-Regular.ttf: "Noto Sans Siddham" "Regular"
NotoSansSignWriting-Regular.ttf: "Noto Sans SignWriting" "Regular"
NotoSansSundanese-Regular.ttf: "Noto Sans Sundanese" "Regular"
NotoSansSylotiNagri-Regular.ttf: "Noto Sans Syloti Nagri" "Regular"
NotoSansSymbols-Regular.ttf: "Noto Sans Symbols" "Regular"
NotoSansTaiTham-Regular.ttf: "Noto Sans Tai Tham" "Regular"
NotoSansTelugu-Regular.ttf: "Noto Sans Telugu" "Regular"
NotoSansTirhuta-Regular.ttf: "Noto Sans Tirhuta" "Regular"
NotoSerifTangut-Regular.ttf: "Noto Serif Tangut" "Regular"
NotoSerifTibetan-Regular.ttf: "Noto Serif Tibetan" "Regular"
NotoMusic-Regular.ttf: "Noto Music" "Regular"
NotoSansAnatolianHieroglyphs-Regular.ttf: "Noto Sans Anatolian Hieroglyphs" "Regular"
NotoSansBamum-Regular.ttf: "Noto Sans Bamum" "Regular"
NotoSansBassaVah-Regular.ttf: "Noto Sans Bassa Vah" "Regular"
NotoSansBatak-Regular.ttf: "Noto Sans Batak" "Regular"
NotoSansBuginese-Regular.ttf: "Noto Sans Buginese" "Regular"
NotoSansBuhid-Regular.ttf: "Noto Sans Buhid" "Regular"
NotoSansCarian-Regular.ttf: "Noto Sans Carian" "Regular"
NotoSansCham-Regular.ttf: "Noto Sans Cham" "Regular"
NotoSansCherokee-Regular.ttf: "Noto Sans Cherokee" "Regular"
NotoSansCoptic-Regular.ttf: "Noto Sans Coptic" "Regular"
NotoSansCuneiform-Regular.ttf: "Noto Sans Cuneiform" "Regular"
NotoSansCypriot-Regular.ttf: "Noto Sans Cypriot" "Regular"
NotoSansDeseret-Regular.ttf: "Noto Sans Deseret" "Regular"
NotoSansDuployan-Regular.ttf: "Noto Sans Duployan" "Regular"
NotoSansEgyptianHieroglyphs-Regular.ttf: "Noto Sans Egyptian Hieroglyphs" "Regular"
NotoSansElbasan-Regular.ttf: "Noto Sans Elbasan" "Regular"
NotoSansEthiopic-Regular.ttf: "Noto Sans Ethiopic" "Regular"
NotoSansGlagolitic-Regular.ttf: "Noto Sans Glagolitic" "Regular"
NotoSansHatran-Regular.ttf: "Noto Sans Hatran" "Regular"
NotoSansImperialAramaic-Regular.ttf: "Noto Sans Imperial Aramaic" "Regular"
NotoSansIndicSiyaqNumbers-Regular.ttf: "Noto Sans Indic Siyaq Numbers" "Regular"
NotoSansInscriptionalPahlavi-Regular.ttf: "Noto Sans Inscriptional Pahlavi" "Regular"
NotoSansInscriptionalParthian-Regular.ttf: "Noto Sans Inscriptional Parthian" "Regular"
NotoSansJavanese-Regular.ttf: "Noto Sans Javanese" "Regular"
NotoSansKhudawadi-Regular.ttf: "Noto Sans Khudawadi" "Regular"
NotoSansLepcha-Regular.ttf: "Noto Sans Lepcha" "Regular"
NotoSansLimbu-Regular.ttf: "Noto Sans Limbu" "Regular"
NotoSansLinearA-Regular.ttf: "Noto Sans Linear A" "Regular"
NotoSansLycian-Regular.ttf: "Noto Sans Lycian" "Regular"
NotoSansLydian-Regular.ttf: "Noto Sans Lydian" "Regular"
NotoSansMahajani-Regular.ttf: "Noto Sans Mahajani" "Regular"
NotoSansManichaean-Regular.ttf: "Noto Sans Manichaean" "Regular"
NotoSansMendeKikakui-Regular.ttf: "Noto Sans Mende Kikakui" "Regular"
NotoSansMeroitic-Regular.ttf: "Noto Sans Meroitic" "Regular"
NotoSansModi-Regular.ttf: "Noto Sans Modi" "Regular"
NotoSansMro-Regular.ttf: "Noto Sans Mro" "Regular"
NotoSansMultani-Regular.ttf: "Noto Sans Multani" "Regular"
NotoSansNabataean-Regular.ttf: "Noto Sans Nabataean" "Regular"
NotoSansOldNorthArabian-Regular.ttf: "Noto Sans Old North Arabian" "Regular"
NotoSansOldPermic-Regular.ttf: "Noto Sans Old Permic" "Regular"
NotoSansOldSogdian-Regular.ttf: "Noto Sans Old Sogdian" "Regular"
NotoSansOldSouthArabian-Regular.ttf: "Noto Sans Old South Arabian" "Regular"
NotoSansOldTurkic-Regular.ttf: "Noto Sans Old Turkic" "Regular"
NotoSansOsage-Regular.ttf: "Noto Sans Osage" "Regular"
NotoSansPahawhHmong-Regular.ttf: "Noto Sans Pahawh Hmong" "Regular"
NotoSansPalmyrene-Regular.ttf: "Noto Sans Palmyrene" "Regular"
NotoSansPauCinHau-Regular.ttf: "Noto Sans Pau Cin Hau" "Regular"
NotoSansPhagsPa-Regular.ttf: "Noto Sans PhagsPa" "Regular"
NotoSansPsalterPahlavi-Regular.ttf: "Noto Sans Psalter Pahlavi" "Regular"
NotoSansRejang-Regular.ttf: "Noto Sans Rejang" "Regular"
NotoSansRunic-Regular.ttf: "Noto Sans Runic" "Regular"
NotoSansSamaritan-Regular.ttf: "Noto Sans Samaritan" "Regular"
NotoSansSaurashtra-Regular.ttf: "Noto Sans Saurashtra" "Regular"
NotoSansShavian-Regular.ttf: "Noto Sans Shavian" "Regular"
NotoSansSogdian-Regular.ttf: "Noto Sans Sogdian" "Regular"
NotoSansSoyombo-Regular.ttf: "Noto Sans Soyombo" "Regular"
NotoSansTagalog-Regular.ttf: "Noto Sans Tagalog" "Regular"
NotoSansTagbanwa-Regular.ttf: "Noto Sans Tagbanwa" "Regular"
NotoSansTaiViet-Regular.ttf: "Noto Sans Tai Viet" "Regular"
NotoSansWancho-Regular.ttf: "Noto Sans Wancho" "Regular"
NotoSansYi-Regular.ttf: "Noto Sans Yi" "Regular"
MaterialIcons-Regular.ttf: "Material Icons" "Regular"
NotoSansMasaramGondi-Regular.ttf: "Noto Sans Masaram Gondi" "Regular"
NotoSerifDogra-Regular.ttf: "Noto Serif Dogra" "Regular"
wasy10.ttf: "wasy10" "LyX"
NotoSansGunjalaGondi-Regular.ttf: "Noto Sans Gunjala Gondi" "Regular"
NotoSansNushu-Regular.ttf: "Noto Sans Nushu" "Regular"
NotoSansMedefaidrin-Regular.ttf: "Noto Sans Medefaidrin" "Regular"
NotoSansTamilSupplement-Regular.ttf: "Noto Sans Tamil Supplement" "Regular"
NotoTraditionalNushu-Regular.ttf: "Noto Traditional Nushu" "Regular"
NotoLoopedLao-Regular.ttf: "Noto Looped Lao" "Regular"
NotoLoopedThai-Regular.ttf: "Noto Looped Thai" "Regular"
NotoSansElymaic-Regular.ttf: "Noto Sans Elymaic" "Regular"
NotoSerifNyiakengPuachueHmong-Regular.ttf: "Noto Serif Hmong Nyiakeng" "Regular"
NotoSerifYezidi-Regular.ttf: "Noto Serif Yezidi" "Regular"
s050000l.pfb: "Standard Symbols L" "Regular"
StandardSymbolsPS.t1: "Standard Symbols PS" "Regular"
texgyrechorus-mediumitalic.otf: "TeX Gyre Chorus" "Regular"
Kleymissky_0283.otf: "Kleymissky" "Regular"

Makes sense.
If I remember correctly there had been reports of emojis not working reliably in the deck options screen. Maybe that is the reason: the font-family is different there.

Sounds reasonable.

So… what do you think the best course of action would be? Should we assume this to be some weird oldstable bug, because it has a “System-ui” font?

Came across this last night while looking up windows 10’s emoji support

The default serif, sans-serif and monospace font for most Linux distributions is DejaVu. … Bitstream Vera is the source of the glyphs used in DejaVu, …

1 Like

I tried to search for how browser find the system-ui font and stumbled across this (which unfortunately does not cite its sources):

It makes me think that the problem is that Linux has multiple competing ways to set the “Default System UI” font.

You changed one of them (gsettings?) which is used by your DE and the native Qt components.

Qt WebView chose to use another one (fontconfig?) which defaulted to the dodgy Vera font on debian oldstable (debian 11?).

It could technically work the same way on newer versions of debian. Newer versions of debian might just have changed the fontconfig defaults to something like Noto Sans instead of Vera so you didn’t notice.

I don’t know if there is a way to force Qt WebView to choose the same method as the rest of Qt.

The “solution” might just be “Don’t use broken fonts. You will have to set the default font in multiple places on Linux” :man_shrugging:

2 Likes