CJK font preference configuration

,

Hi! On a fresh Fedora 39 KDE install, it seems all the Noto CJK fonts are installed (Chinese, Japanese, Korean). Font rendering is different between the three languages, so to get text to look right it has to use the right font. By default, when there is no language tag, the system prefers the Chinese variant font. I read/write Japanese, so I would like the default/fallback to be Japanese (language tags for text are almost never set right, so you can’t rely on that to pick the right font).

This is a common issue and I know I can fix it by manually editing fontconfig config files (or by uninstalling everything but the Japanese variants), but is there some better supported or more user friendly way to do this in Fedora? It seems kind of silly if Japanese Fedora users have to manually edit config files to get font rendering to look right, so maybe there is an easier way? Does anyone know?

For example, on Android if you add Japanese as a primary or secondary system language, this automatically changes the default fallback font. But doing that in KDE doesn’t seem to do anything, at least not for all apps.

3 Likes

This is a good question. I don’t actually know? But @petersen might know or know someone who does.

I suspect this issue is related to Fedora’s decision in 2019 to adopt Noto fonts as the default system-wide, under DefaultFontsToNoto initiative. This change was intended to provide a unified and high-quality font experience across various languages. However, in this case, it seems to have inadvertently led to a preference for Chinese character rendering, as indicated by fc-match results:

❯ fc-match sans-serif
NotoSans-Regular.ttf: "Noto Sans" "Regular"

❯ fc-match serif
NotoSerif-Regular.ttf: "Noto Serif" "Regular"

❯ fc-match monospace
NotoSansMono-Regular.ttf: "Noto Sans Mono" "Regular"

The default is always going to be wrong for some people, but I wonder if there’s a “unified” way to change this? I know I can just change the font fallback order in the configs, but I guess there should be a UI for this somehow? And if there’s a UI, then there also needs to be some kind of unified way to change the language preference in ~/.fonts.conf without explicitly listing out every font installed that uses it, or redefining the global fallback order from scratch… but I don’t know that much about fontconfig.

Actually the behavior now is super weird… In Konsole in the terminal itself, I get Japanese glyphs. Everywhere else in KDE, I get Chinese glyphs. In my IME popup (fcitx5) in KDE/Qt, I get Chinese glyphs. But in Firefox, my IME popup shows Japanese glyphs. However, Firefox itself shows Chinese glyphs.

And fontconfig actually claims the font selection for the character 直 would be the JP font:

$ fc-match sans:charset=76F4
NotoSansCJK-VF.ttc: "Noto Sans CJK JP" "Regular"

I’m so confused now…

It looks like Firefox does its own thing… the pref is font.cjk_pref_fallback_order. It does default to the right fallback order if your locale is set to Japanese though… so I guess Firefox just ignores whatever fontconfig says and has its own logic. It should work for people who actually set their system locale to Japanese, but for people like me who use multiple languages, having to edit a pref is really obscure…

Maybe Qt is also doing its own fallback and that’s why it disagrees with fontconfig?

1 Like

OK, I figured it out I think. There is actually no Noto Sans CJK in the default fallback order! This is what I get:

“Noto Sans”(s) “Noto Sans”(w) “Noto Sans”(w) “Noto Sans”(w) “DejaVu Sans”(w) “Verdana”(w) “Arial”(w) “Albany AMT”(w) “Luxi Sans”(w) “Nimbus Sans L”(w) “Nimbus Sans”(w) “Nimbus Sans”(w) “Helvetica”(w) “Nimbus Sans”(w) “Lucida Sans Unicode”(w) “BPG Glaho International”(w) “Tahoma”(w) “Open Sans”(w) “Co
mfortaa”(w) “URW Gothic”(w) “Nimbus Sans”(w) “Nimbus Sans Narrow”(w) “Carlito”(w) “Noto Sans Math”(w) “Mingzat”(w) “Padauk”(w) “Nuosu SIL”(w) “Droid Arabic Kufi”(w) “Droid Sans Armenian”(w) “Droid Sans Devanagari”(w) “Droid Sans Ethiopic”(w) “Droid Sans Fallback”(w) “Droid Sans Georgian”(w) “Droid Sans Hebrew”(w) "
Droid Sans Japanese"(w) “Droid Sans Tamil”(w) “Droid Sans Thai”(w) “Nachlieli”(w) “Lucida Sans Unicode”(w) “Yudit Unicode”(w) “Kerkis”(w) “ArmNet Helvetica”(w) “Artsounk”(w) “BPG UTF8 M”(w) “Waree”(w) “Loma”(w) “Garuda”(w) “Umpush”(w) “Saysettha Unicode”(w) “JG Lao Old Arial”(w) “GF Zemen Unicode”(w) “Pigiarniq”(w)
“B Davat”(w) “B Compset”(w) “Kacst-Qr”(w) “Urdu Nastaliq Unicode”(w) “Raghindi”(w) “Mukti Narrow”(w) “malayalam”(w) “Sampige”(w) “padmaa”(w) “Hapax Berbère”(w) “MS Gothic”(w) “UmePlus P Gothic”(w) “Microsoft YaHei”(w) “Microsoft JhengHei”(w) “WenQuanYi Zen Hei”(w) “WenQuanYi Bitmap Song”(w) “AR PL ShanHeiSun Uni”(
w) “AR PL New Sung”(w) “MgOpen Modata”(w) “VL Gothic”(w) “IPAMonaGothic”(w) “IPAGothic”(w) “Sazanami Gothic”(w) “Kochi Gothic”(w) “AR PL KaitiM GB”(w) “AR PL KaitiM Big5”(w) “AR PL ShanHeiSun Uni”(w) “AR PL SungtiL GB”(w) “AR PL Mingti2L Big5”(w) “MS ゴシック”(w) “ZYSong18030”(w) “TSCu_Paranar”(w) “NanumGothic”(w
) “UnDotum”(w) “Baekmuk Dotum”(w) “Baekmuk Gulim”(w) “KacstQura”(w) “Lohit Bengali”(w) “Lohit Gujarati”(w) “Lohit Hindi”(w) “Lohit Marathi”(w) “Lohit Maithili”(w) “Lohit Kashmiri”(w) “Lohit Konkani”(w) “Lohit Nepali”(w) “Lohit Sindhi”(w) “Lohit Punjabi”(w) “Lohit Tamil”(w) “Meera”(w) “Lohit Malayalam”(w) “Lohit Kan
nada”(w) “Lohit Telugu”(w) “Lohit Oriya”(w) “LKLUG”(w) “FreeSans”(w) “Arial Unicode MS”(w) “Arial Unicode”(w) “Code2000”(w) “Code2001”(w) “sans-serif”(w) “Roya”(w) “Koodak”(w) “Terafik”(w) “sans-serif”(w) “sans-serif”(w) “sans-serif”(w) “sans-serif”(w) “sans-serif”(w) “ITC Avant Garde Gothic”(w) “URW Gothic”(w) “sa
ns-serif”(w) “sans-serif”(w) “Helvetica”(w) “Helvetica Narrow”(w) “Nimbus Sans Narrow”(w) “sans-serif”(w) “sans-serif”(w) “sans-serif”(w) “sans-serif”(w) “sans-serif”(w) “sans-serif”(w) “sans-serif”(w) “sans-serif”(w) “sans-serif”(w) “sans-serif”(w) “sans-serif”(w) “sans-serif”(w) “sans-serif”(w),

However, fontconfig and Qt have different rules for picking a font. Qt just goes through the fallback font list, and finds the first font that has the needed character (I think). That is Droid Sans Fallback (!), which happens to use Chinese glyphs.

Fontconfig uses a more complicated matching system. First it filters out all fonts that don’t have the required characters, then it looks at language selection before even looking at the fallback font list. “Droid Sans Fallback” has lang: ja|zh-tw(w), which does not match en, so it gets filtered out here. And now there are no fonts with CJK characters left in the fallback font list, so it just randomly picks the first font it finds which is left among the rest of the fonts, which happens to be Noto Sans CJK JP by chance.

If your language is set to jp though, the configs do put Noto Sans CJK JP into the list. So that leads to the answer! I think the correct way to set Han glyph preference is like this:

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<fontconfig>
  <match target="pattern">
    <edit name="lang" mode="append"><string>ja</string></edit>
  </match>
</fontconfig>

That basically says that, after your system or text language, fontconfig should prefer fonts for the Japanese language. Dropping that into .fonts.conf.d/05-language-fallback.conf makes KDE do the right thing, without having to hard code font fallback order or specific fonts! It’s basically the same thing Android does, it’s just that (as far as I can tell) it’s not really possible to set a list of languages in Linux and have that propagate to fontconfig in all frameworks and everything else, so you have to do it directly in fontconfig.

I guess KDE maybe should do this with the existing language list in system settings? It feels like it would be a useful addition…

2 Likes

Turns out there’s a bug for this already! I left a comment: 465384 – Support a way to set a preference for CJK character variants (Han unification) in KCM or derive it automatically

I think @tagoh is the best person to answer this in detail.

The simplest solution should be to run your desktop in a Japanese locale in your case.

Another way perhaps would be to install google-noto-sans-jp-fonts instead, though I haven’t tested this (if you are sure you only want Japanese variants).

Or maybe try adding the non-VF Noto CJK fonts instead (google-noto-sans-cjk-fonts or google-noto-serif-cjk-fonts). I believe Qt may have some issues with variable font handling, particularly for complicated fonts like Noto CJK perhaps.

Is your firefox configured to prefer Japanese? (“Settings > Choose your preferred language for displaying pages”)

Also some more specific examples might be helpful.

The simplest solution should be to run your desktop in a Japanese locale in your case.

I mean… Of course that would fix it, but it’s not what I want…

Another way perhaps would be to install google-noto-sans-jp-fonts instead, though I haven’t tested this (if you are sure you only want Japanese variants).

This is only a guaranteed fix if you have zero non-Japanese CJK fonts installed on the system. The way the fallback works in the end, it just picks a random font. Plus this means then other text correctly tagged as a CJK language would not display correctly since you won’t even have a font for it. So you sacrifice the ability to render all of C/J/K correctly.

For me, it’s actually Droid Sans Fallback that becomes the first fallback option (and it uses Chinese glyphs), so that would mean removing google-droid-sans-fonts.

Or maybe try adding the non-VF Noto CJK fonts instead (google-noto-sans-cjk-fonts or google-noto-serif-cjk-fonts). I believe Qt may have some issues with variable font handling, particularly for complicated fonts like Noto CJK perhaps.

I don’t think that has anything to do with it…

Is your firefox configured to prefer Japanese? (“Settings > Choose your preferred language for displaying pages”)

I tried adding Japanese as a secondary language and it didn’t make a difference (and I don’t want it to be the primary language).

Keep in mind that I already have everything working the way I want it. That’s not why I’m reporting this here, what I’m saying is that I had to edit Firefox prefs and Fontconfig config files to do it, and it doesn’t sound right that there is no better way to do this. I’m pretty sure there’s a large number of people who are bilingual in two languages, one of which is CJK, and who prefer the non-CJK language as system/UI primary. Certainly a lot of my friends are like that…

1 Like

If you can’t change your locale and you want to change the order of your preferable languages, you can use LC_CTYPE=ja, or FC_LANG=ja if you want to change it for fontconfig only.

But that’s still editing environment variables/config files for something that should be exposed in the UI… and it won’t fix Firefox either.

I just added a comment from fontconfig perspective. There are no way more than that. In the first place, glyphs being used for CJK languages are unified at Unicode definition. We use the locale and locale-related environment variables to give a priority of a font selection for non-rich text rendering.

For firefox, they have their own config for that. that is another story.

“Choose your preferred language for displaying pages” (that worked for me) or “Set alternatives…” (that only affects the firefox chrome)?

I think what you want is something like PANGO_LANGUAGE=ja but I am not a aware of any equivalent for Qt.

Oh wow, you’re right, I tried it again and it did work. I must’ve messed something up the first time… Sorry!

I’m glad this has a UI in Firefox then! Now if only KDE/Fontconfig had something for the rest of the system…

1 Like

I do agree with you it would be nice if GNOME and KDE had some config UI for this indeed.