Keep Latin families first and read only the tagged language for CJK variants

This commit is contained in:
ZacharyZhang-NY committed 2026-10-05 23:48:00 -04:00
1 parent a62771e2b4
commit ab028e80eb
3 files changed
+115 -60

No files matched your search

+44 -59
View File
@@ -1,20 +1,10 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!-- CJK: give language-tagged text the Noto CJK variant that matches its
language. noto-fonts-cjk ships all five, Han glyph shapes differ between
them, and the generic assigns below would otherwise hand tagged CJK text
to families with no Han coverage, leaving the variant to a charset-scan
lottery. Chinese arrives under many tags (W3C recommends the zh-Hans and
zh-Hant script forms), so the tags are first folded onto one tag per
variant. Order is load-bearing: a bare zh and a bare zh-hant satisfy
the contains test of every one of their extensions, so both are pinned
by exact matches before the extension folds run. Cantonese under its
own primary tag folds to Hong Kong forms, except explicitly
Simplified Cantonese, which folds to SC. -->
<!-- CJK: fold the language tag onto one tag per Noto CJK variant -->
<match target="pattern">
<test name="lang" compare="eq">
<test name="lang" qual="first" compare="eq">
<string>zh</string>
</test>
<edit name="lang" mode="assign">
@@ -23,7 +13,7 @@
</match>
<match target="pattern">
<test name="lang" compare="eq">
<test name="lang" qual="first" compare="eq">
<string>zh-hant</string>
</test>
<edit name="lang" mode="assign">
@@ -32,7 +22,7 @@
</match>
<match target="pattern">
<test name="lang" compare="contains">
<test name="lang" qual="first" compare="contains">
<string>zh-hant-hk</string>
</test>
<edit name="lang" mode="assign">
@@ -41,7 +31,7 @@
</match>
<match target="pattern">
<test name="lang" compare="contains">
<test name="lang" qual="first" compare="contains">
<string>zh-hant-mo</string>
</test>
<edit name="lang" mode="assign">
@@ -50,7 +40,7 @@
</match>
<match target="pattern">
<test name="lang" compare="contains">
<test name="lang" qual="first" compare="contains">
<string>zh-hant</string>
</test>
<edit name="lang" mode="assign">
@@ -59,7 +49,7 @@
</match>
<match target="pattern">
<test name="lang" compare="contains">
<test name="lang" qual="first" compare="contains">
<string>zh-hans</string>
</test>
<edit name="lang" mode="assign">
@@ -68,7 +58,7 @@
</match>
<match target="pattern">
<test name="lang" compare="contains">
<test name="lang" qual="first" compare="contains">
<string>zh-sg</string>
</test>
<edit name="lang" mode="assign">
@@ -77,7 +67,7 @@
</match>
<match target="pattern">
<test name="lang" compare="contains">
<test name="lang" qual="first" compare="contains">
<string>zh-mo</string>
</test>
<edit name="lang" mode="assign">
@@ -86,7 +76,7 @@
</match>
<match target="pattern">
<test name="lang" compare="eq">
<test name="lang" qual="first" compare="eq">
<string>yue</string>
</test>
<edit name="lang" mode="assign">
@@ -95,7 +85,7 @@
</match>
<match target="pattern">
<test name="lang" compare="contains">
<test name="lang" qual="first" compare="contains">
<string>yue-hans</string>
</test>
<edit name="lang" mode="assign">
@@ -104,7 +94,7 @@
</match>
<match target="pattern">
<test name="lang" compare="contains">
<test name="lang" qual="first" compare="contains">
<string>yue-cn</string>
</test>
<edit name="lang" mode="assign">
@@ -113,7 +103,7 @@
</match>
<match target="pattern">
<test name="lang" compare="contains">
<test name="lang" qual="first" compare="contains">
<string>yue</string>
</test>
<edit name="lang" mode="assign">
@@ -121,189 +111,184 @@
</edit>
</match>
<!-- Each variant is then prepended for its tag, ahead of the assigns below
because these test the generic names those assigns replace. Unlike the
Arabic rule further down, these carry a family test, so the prepend
lands just ahead of the matched generic and a concrete family the app
asked for stays in front of the variant. -->
<!-- Then append that variant after the generic family it falls back from -->
<match target="pattern">
<test name="lang" compare="contains">
<test name="lang" qual="first" compare="contains">
<string>zh-cn</string>
</test>
<test name="family">
<string>sans-serif</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<edit name="family" mode="append" binding="strong">
<string>Noto Sans CJK SC</string>
</edit>
</match>
<match target="pattern">
<test name="lang" compare="contains">
<test name="lang" qual="first" compare="contains">
<string>zh-cn</string>
</test>
<test name="family">
<string>serif</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<edit name="family" mode="append" binding="strong">
<string>Noto Serif CJK SC</string>
</edit>
</match>
<match target="pattern">
<test name="lang" compare="contains">
<test name="lang" qual="first" compare="contains">
<string>zh-cn</string>
</test>
<test name="family">
<string>monospace</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<edit name="family" mode="append" binding="strong">
<string>Noto Sans Mono CJK SC</string>
</edit>
</match>
<match target="pattern">
<test name="lang" compare="contains">
<test name="lang" qual="first" compare="contains">
<string>zh-hk</string>
</test>
<test name="family">
<string>sans-serif</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<edit name="family" mode="append" binding="strong">
<string>Noto Sans CJK HK</string>
</edit>
</match>
<match target="pattern">
<test name="lang" compare="contains">
<test name="lang" qual="first" compare="contains">
<string>zh-hk</string>
</test>
<test name="family">
<string>serif</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<edit name="family" mode="append" binding="strong">
<string>Noto Serif CJK HK</string>
</edit>
</match>
<match target="pattern">
<test name="lang" compare="contains">
<test name="lang" qual="first" compare="contains">
<string>zh-hk</string>
</test>
<test name="family">
<string>monospace</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<edit name="family" mode="append" binding="strong">
<string>Noto Sans Mono CJK HK</string>
</edit>
</match>
<match target="pattern">
<test name="lang" compare="contains">
<test name="lang" qual="first" compare="contains">
<string>zh-tw</string>
</test>
<test name="family">
<string>sans-serif</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<edit name="family" mode="append" binding="strong">
<string>Noto Sans CJK TC</string>
</edit>
</match>
<match target="pattern">
<test name="lang" compare="contains">
<test name="lang" qual="first" compare="contains">
<string>zh-tw</string>
</test>
<test name="family">
<string>serif</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<edit name="family" mode="append" binding="strong">
<string>Noto Serif CJK TC</string>
</edit>
</match>
<match target="pattern">
<test name="lang" compare="contains">
<test name="lang" qual="first" compare="contains">
<string>zh-tw</string>
</test>
<test name="family">
<string>monospace</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<edit name="family" mode="append" binding="strong">
<string>Noto Sans Mono CJK TC</string>
</edit>
</match>
<match target="pattern">
<test name="lang" compare="contains">
<test name="lang" qual="first" compare="contains">
<string>ja</string>
</test>
<test name="family">
<string>sans-serif</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<edit name="family" mode="append" binding="strong">
<string>Noto Sans CJK JP</string>
</edit>
</match>
<match target="pattern">
<test name="lang" compare="contains">
<test name="lang" qual="first" compare="contains">
<string>ja</string>
</test>
<test name="family">
<string>serif</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<edit name="family" mode="append" binding="strong">
<string>Noto Serif CJK JP</string>
</edit>
</match>
<match target="pattern">
<test name="lang" compare="contains">
<test name="lang" qual="first" compare="contains">
<string>ja</string>
</test>
<test name="family">
<string>monospace</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<edit name="family" mode="append" binding="strong">
<string>Noto Sans Mono CJK JP</string>
</edit>
</match>
<match target="pattern">
<test name="lang" compare="contains">
<test name="lang" qual="first" compare="contains">
<string>ko</string>
</test>
<test name="family">
<string>sans-serif</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<edit name="family" mode="append" binding="strong">
<string>Noto Sans CJK KR</string>
</edit>
</match>
<match target="pattern">
<test name="lang" compare="contains">
<test name="lang" qual="first" compare="contains">
<string>ko</string>
</test>
<test name="family">
<string>serif</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<edit name="family" mode="append" binding="strong">
<string>Noto Serif CJK KR</string>
</edit>
</match>
<match target="pattern">
<test name="lang" compare="contains">
<test name="lang" qual="first" compare="contains">
<string>ko</string>
</test>
<test name="family">
<string>monospace</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<edit name="family" mode="append" binding="strong">
<string>Noto Sans Mono CJK KR</string>
</edit>
</match>
+1 -1
View File
@@ -16,7 +16,7 @@ Progress source of truth for the `omarchycn` branches of `omarchy`, `omarchy-iso
- [x] T0 Branches and this list
- [x] T1 China package sources (PRD 1): region state, `omarchy-region` reader, `default/region/china/pacman.sed`, applied by `omarchy-refresh-pacman` and `install/post-install/pacman.sh`; tests
- [x] T2 Region choice in the installer (PRD 2): `omarchy_prompt_region` in `setup-form.sh`, ISO configurator screen, orchestrator passes `OMARCHY_REGION`, `install/config/region.sh` records it
- [ ] T3 Input method (PRD 3): rime-ice-installer patch and PKGBUILD in omarchy-pkgs, IME packages in `omarchy-other.packages`, install-time package add, user step runs the installer from bundled assets, ISO build bundles assets and the package
- [x] T3 Input method (PRD 3): rime-ice-installer patch and PKGBUILD in omarchy-pkgs, IME packages in `omarchy-other.packages`, install-time package add, user step runs the installer from bundled assets, ISO build bundles assets and the package
- [ ] T4 CJK fontconfig fix (PRD 4): rebuild PR 9693 on the current base
- [ ] T5 AI (PRD 5): Dim and Kimi Code for every region (rebuild PR 9694), Claude Code third-party provider setup shown only in China
- [ ] T6 Developer mirrors (PRD 6): npm, PyPI/uv, Go, rustup, crates.io, RubyGems, Maven via system drop-ins under `default/region/china/`
+70
View File
@@ -0,0 +1,70 @@
#!/bin/bash
set -euo pipefail
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
if ! command -v fc-match >/dev/null || [[ $(fc-list : file) != *NotoSansCJK-Regular.ttc* ]]; then
skip "fontconfig CJK variants need fc-match and noto-fonts-cjk"
exit 0
fi
test_tmp=$(mktemp -d)
trap 'rm -rf "$test_tmp"' EXIT
{
echo '<?xml version="1.0"?><!DOCTYPE fontconfig SYSTEM "fonts.dtd"><fontconfig>'
echo "<dir>/usr/share/fonts</dir><cachedir>$test_tmp/cache</cachedir>"
for conf in /etc/fonts/conf.d/*.conf; do
if [[ ${conf##*/} == "50-omarchy.conf" ]]; then
echo "<include>$ROOT/default/fontconfig/conf.avail/50-omarchy.conf</include>"
else
echo "<include>$conf</include>"
fi
done
echo '</fontconfig>'
} >"$test_tmp/fonts.conf"
export FONTCONFIG_FILE="$test_tmp/fonts.conf"
fc-cache >/dev/null
declare -A latin=([sans-serif]="Liberation Sans" [serif]="Liberation Serif" [monospace]="JetBrainsMono Nerd Font")
declare -A cjk=([sans-serif]="Noto Sans CJK" [serif]="Noto Serif CJK" [monospace]="Noto Sans Mono CJK")
declare -A variant=(
[zh]=SC [zh-cn]=SC [zh-sg]=SC [zh-hans]=SC [zh-hans-cn]=SC [zh-hans-hk]=SC
[zh-tw]=TC [zh-hant]=TC [zh-hant-tw]=TC
[zh-hk]=HK [zh-mo]=HK [zh-hant-hk]=HK [zh-hant-mo]=HK
[yue]=HK [yue-hk]=HK [yue-hant]=HK [yue-hant-hk]=HK [yue-hant-cn]=HK
[yue-hans]=SC [yue-hans-cn]=SC [yue-hans-hk]=SC [yue-cn]=SC
[ja]=JP [ja-jp]=JP [ko]=KR [ko-kr]=KR
)
family() { LANG=$1 fc-match -f '%{family[0]}' "$2"; }
for locale in C.UTF-8 zh_CN.UTF-8; do
for tag in "${!variant[@]}"; do
for generic in sans-serif serif monospace; do
actual=$(family "$locale" "$generic:lang=$tag")
[[ $actual == "${latin[$generic]}" ]] || fail "$locale $generic:lang=$tag keeps Latin in ${latin[$generic]}" "$actual"
actual=$(family "$locale" "$generic:lang=$tag:charset=9aa8")
expected="${cjk[$generic]} ${variant[$tag]}"
[[ $actual == "$expected" ]] || fail "$locale $generic:lang=$tag sets Han in $expected" "$actual"
done
done
pass "$locale: tagged CJK keeps Omarchy's Latin families and sets Han in the tag's variant"
done
for generic in sans-serif serif monospace; do
actual=$(family zh_CN.UTF-8 "$generic")
[[ $actual == "${latin[$generic]}" ]] || fail "zh_CN untagged $generic keeps ${latin[$generic]}" "$actual"
actual=$(family zh_CN.UTF-8 "$generic:charset=9aa8")
[[ $actual == "${cjk[$generic]} SC" ]] || fail "zh_CN untagged $generic sets Han in SC" "$actual"
done
pass "a Chinese locale keeps Omarchy's Latin families and sets untagged Han in SC"
[[ $(LANG=C.UTF-8 fc-pattern --config "sans-serif:lang=ja" family) == *'"Noto Sans CJK JP"(s)'* ]] ||
fail "lang=ja binds its variant strongly, so the prefix check below can see one"
for tag in jam kok; do
actual=$(LANG=C.UTF-8 fc-pattern --config "sans-serif:lang=$tag" family)
[[ ! $actual =~ CJK\ [A-Z]+\"\(s\) ]] || fail "lang=$tag is not taken for Japanese or Korean" "$actual"
done
pass "languages that only share a prefix with ja or ko get no CJK variant"