Another afternoon wasted: How to choose two fonts with fontconfig

After upgrading to Ubuntu 16.04, the font in my GNOME is a mess (again). So I spent another afternoon trying to figure out how to choose the fonts I need using fontconfig.

This is what I achieved using Source Sans Pro and Source Han Sans CN. The default was to use DejaVu Sans and SimSun.

My goal is to use two fonts, an English one for displaying generic characters, and a Chinese one for, um, Chinese. Although I can use a single Chinese font for both, but the English characters displayed in Chinese font is disastrous. So basically I want to tell fontconfig to use the two fonts in a preferred order: Use English one wherever possible, and fallback to the native one when the former can’t do the job.

Actually I have solved this before, but I forgot what I did back then. So I had to spend another afternoon Googling and reading their long and non-standardized docs on how to express my request in their weird XML tags. After several attempts, I found that the following configuration works just fine.

The whole XML below should be saved as ~/.config/fontconfig/conf.d/99-xiaodu.conf (create non-existent folders when needed), which is the preferred location for user-specific fontconfig files.

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
  <!-- For other languages -->
  <match target="pattern">
    <test qual="any" name="family">
     <string>sans-serif</string>
   </test>
   <edit name="family" mode="prepend" binding="strong">
      <string>Arial</string>
    </edit>
 </match>
  <match target="pattern">
    <test qual="any" name="family">
     <string>serif</string>
    </test>
   <edit name="family" mode="prepend" binding="strong">
      <string>Times New Roman</string>
    </edit>
 </match>
  <match target="pattern">
    <test qual="any" name="family">
     <string>monospace</string>
    </test>
   <edit name="family" mode="prepend" binding="strong">
      <string>Inconsolata</string>
    </edit>
 </match>
  <!-- For Chinese -->
  <match target="pattern">
    <test name="lang">
      <string>zh-cn</string>
    </test>
   <test qual="any" name="family">
     <string>sans-serif</string>
   </test>
   <edit name="family" mode="prepend" binding="strong">
      <string>Arial</string>
      <string>Source Han Sans CN</string>
   </edit>
 </match>
  <match target="pattern">
    <test name="lang">
      <string>zh-cn</string>
    </test>
   <test qual="any" name="family">
     <string>serif</string>
    </test>
   <edit name="family" mode="prepend" binding="strong">
      <string>Times New Roman</string>
      <string>Simsun</string>
   </edit>
 </match>
  <match target="pattern">
    <test name="lang">
      <string>zh-cn</string>
    </test>
   <test qual="any" name="family">
     <string>monospace</string>
    </test>
   <edit name="family" mode="prepend" binding="strong">
      <string>Inconsolata</string>
      <string>Source Han Sans CN</string>
   </edit>
 </match>

</fontconfig>

Basically this file tells fontconfig, when the locale is zh-cn (Chinese), it should to prepend the two fonts (English and Chinese) to the matching list; otherwise just prepend the English one.

Notice that the first font in each <edit> block is the English font, where the second is the native font. You should replace the language code (RFC3066 style) and all six font names using your favorite text editor, with respect to the fonts’ types (sans, serif or mono). If you want to test your work, use fc-match with something like $ LANG=zh-CN fc-match -s sans | head -2.

I just hope one day there would be a nice GUI for all this crap.

中文摘要:这篇文章介绍如何在 Ubuntu 中通过配置 fontconfig 同时选择要使用的英文和中文字体,使用英文字体显示一般字符,中文字体显示中文字符。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注