Linux – Changing Font Family for Characters of a Certain Language Using Fontconfig

deepinfontconfigfontslinux

I am on Arch Linux, Deepin Desktop. I am using Noto Serif as my standard font, but I don't like its Arabic characters. So my goal is to use another font just for arabic characters.

Here is what I have tried. I created a new configuration file in /etc/fonts/conf.d/ with the following contents:

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
    <match target="pattern">
        <test name="lang" compare="contains">
            <string>ar</string>
        </test>
        <test qual="any" name="family">
            <string>sans-serif</string>
        </test>
        <edit name="family" mode="prepend" binding="strong">
            <string>Noto Naskh Arabic</string>
        </edit>
    </match>

    <match target="pattern">
        <test name="lang" compare="contains">
            <string>ar</string>
        </test>
        <test qual="any" name="family">
            <string>serif</string>
        </test>
        <edit name="family" mode="prepend" binding="strong">
            <string>Noto Naskh Arabic</string>
        </edit>
    </match>
</fontconfig>

I then ran fc-cache -r. But this didn't work, the same font is still in use and running fc-match returns NotoSerif-Regular.ttf: "Noto Serif" "Regular" just as before.

Best Answer

Many Noto fonts report to the system that they support the Arabic script, which they do—in part. One of these fonts is the Urdu font, and for whatever reason it has the priority over other fonts that support the Arabic Script.

You can prefer a specific font over the others as follows:

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>

<alias>
  <family>sans-serif</family>
  <prefer>
   <family>Noto Sans</family>
   <family>Noto Naskh Arabic</family>
  </prefer>
 </alias>

 <alias>
  <family>serif</family>
  <prefer>
   <family>Noto Serif</family>
   <family>Noto Naskh Arabic</family>
  </prefer>
 </alias>

 <alias>
  <family>monospace</family>
  <prefer>
   <family>Noto Sans Mono</family>
   <family>Noto Naskh Arabic</family>
  </prefer>
 </alias>

</fontconfig>

The higher the position of the font is, the more preferred it is. In this case, we prefer Noto Naskh Arabic over other Arabic script fonts.

You can do this of course with any language or font of your choice.

For some reason, only the user configuration file worked for me, those located in ~/.config/fontconfig/fonts.conf. Note that $XDG_CONFIG_HOME environmental variable has to be set to your .config directory in your home directory, so $HOME/.config.

You then have to rebuild the configuration for it to take effect using fc-cache. Only newly launched application will be displayed with the new configuration. Restart the X server or your Desktop for the changes to take effect globally.

Edit: If you match against the ar locale that simply won't work on all websites, because some websites use an en locale whilst displaying Arabic UTF-8 characters.

If you go to /etc/fonts/conf.d and read the README and then read any configuration file starting with [30-40] you'd know that this is the right answer.

If say a website asks for a Serif font; fontconfig goes through this list, first to Noto Serif, when it finds an Arabic character it resorts to the second font in the list —Noto Naskh Arabic— and finds that the font supports the Arabic script, thus it's used.

Related Question