Select ZHH, ZHS and ZHT for a Chinese region in the lang attribute (#191) - #202
Merged
jakejackson1 merged 2 commits intoSep 17, 2026
Merged
Conversation
This was referenced Sep 16, 2026
) OtlTags::language() fell back from the language subtag to the language and region run together, 'zhhk', but the only region keys in Ucdn::$ot_languages are written with a hyphen, 'zh-hk'. The branch could never match, so zh-HK, zh-TW, zh-MO, zh-CN and zh-SG all laid text out with the script's DFLT entry. It now joins them with the hyphen. No font in tests/data/ttf or packages/ has a Chinese language system. NotoSansTC-RegionLangSys-Synthetic is a subset of Noto Sans TC whose GSUB offers hani with a 'locl' lookup under each of ZHH, ZHS and ZHT, giving the same character a different glyph under each. For every row of the issue's table and zh-Hant-HK, mPDF now draws the glyph hb-shape --language draws. No existing fixture moves: the golden masters set no language. HarfBuzz also reads the script subtag, takes ZHS for bare zh, and ZHTM then ZHH for Macao. That is #201, and OtlTagsTest pins zh, zh-Hant and zh-Hans as they stand. Test font: NotoSansTC-RegionLangSys-Synthetic (Noto Sans TC 2.004, OFL 1.1), built in fontTools 4.59.2. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
jakejackson1
force-pushed
the
fix/192-indic-script-fallback
branch
from
September 17, 2026 01:47
a17f1fa to
47eabba
Compare
jakejackson1
force-pushed
the
fix/191-chinese-region-langsys
branch
from
September 17, 2026 01:47
b38b6fd to
4c81cc3
Compare
Member
Author
|
Rebased: #190 was squash-merged into |
Member
Author
|
This PR merged into a base branch that had already been squash-merged, so its change never reached |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #191
What
OtlTags::language()falls back from the language subtag to the language and region. It joined them with nothing in between, so it looked upzhhk, but the only region keys inUcdn::$ot_languagesare written with a hyphen (zh-cn,zh-hk,zh-mo,zh-sg,zh-tw, atsrc/Ucdn.php:778-782). No other key is four or more letters long, so the branch could never match. Every Chinese region laid text out with the script'sDFLTentry.The fix belongs in the lookup key, not in
Ucdn. The hyphenated keys are the table's own convention, generated like the rest of it.How
langis splitlanguage()splits the tag on-and lower-cases each part:Hantis skippedSo
zh-HK,zh-hkandzh-Hant-HKall look upzh-hk.zh-Hantalone has no region and gets no language system. A language with its own key (e.g.sr) still wins over its region, as before.Test font and shaping test
I checked every font in
tests/data/ttfandpackages/*/fontsfor a language system startingZHin GSUB or GPOS: none has one.NotoSansTC-RegionLangSys-Synthetic.ttfmakes the fix visible. It's Noto Sans TC 2.004 (OFL 1.1), subset in fontTools 4.59.2 to space, 骨, 一, 二 and 三. GPOS, BASE, STAT and the vertical metrics are dropped, and name IDs 1, 4 and 6 are renamed. It also gets a GDEF marking the four Han glyphs as bases, because mPDF refuses OpenType layout to a font without GDEF. Its GSUB is replaced by one script,hani, with no default features and onelocllookup per language system:ZHHZHSZHTChineseRegionLangSysTestwrites<p lang="…">骨</p>and records the glyph drawn throughTextRecordingMpdf. It runszh-HK,zh-TWandzh-CN, one per language system. I measured every row below the same way:langhb-shape --language14.3.1zh-HKzh-Hant-HKzh-TWzh-twzh-MOzh-CNzh-SGOtlTagsTesthas a case for every row of the issue's table, pluszh-Hant-HK, lower case, and a region the table has no entry for (zh-US→DFLT).Where HarfBuzz goes further: #201
HarfBuzz's
hb_ot_tags_from_complex_language()(src/hb-ot-tag-table.hh) also maps the script subtag, and it checks the script before the region:It also maps bare
zh→ZHS, and Macao →ZHTMthenZHH. The issue asks for the region mapping, and mPDF has no equivalent for the rest, so I opened #201 instead of widening this PR. It coverszh,zh-Hant,zh-Hans, a script that disagrees with its region (zh-Hans-HK,zh-Hant-CN), and Macao. Thezh-MOrow above follows the issue andUcdn's own'zh-mo' => 'ZHT 'entry.OtlTagsTest::testChineseWithoutARegionHasNoLanguageSystempinszh,zh-Hantandzh-Hansas they stand, with a reference to #201.Fixtures
Regenerated from cold. I deleted
tests/Mpdf/tmp/mpdf,tmp/mpdfandtmp/ttfontdata, then rancomposer fontcache:update all,otldump:update all,shaping:update allandsubset:update all.git statusshowed only the new font's five files. No existing fixture moved, which is expected because none of the golden masters sets a language. The new font'sotldumplistshaniwithZHH,ZHSandZHT, each withlocl. Its shaping master shapes with no language, so 骨 comes back unchanged.Mutation check
With the key put back to
$lang . $countryand the caches cleared, 10 tests fail:ChineseRegionLangSysTest::testTheRegionSelectsTheLanguageSystemOtlTagsTest::testAChineseRegionSelectsItsLanguageSystem(all exceptzh-US)Mirroring upstream
Upstream
Otl::_getOTLLangTag()has the same key atsrc/Otl.php:6183ondevelopment:The mirror changes
$lang . '' . $countryto$lang . '-' . $countryin both places. Upstream splits the tag the same way (preg_split('/-/', …), region from a two-letter second subtag or any third subtag), so nothing else changes. The upstream PR also needs aCHANGELOG.mdentry. The test font,ChineseRegionLangSysTest, and the language rows (as calls to_getOTLLangTagthrough reflection) can be carried over.Base
Stacked on #200 (
fix/192-indic-script-fallback) → #198 → #190 → #188 → #186 →gravitypdf. Before pushing I checked all five: all still open, none merged, so this targetsfix/192-indic-script-fallbackwithout a rebase./simplify
Applied:
$regionChineseRegionLangSysTestnow runs one region per language system (zh-HK,zh-TW,zh-CN), becauseOtlTagsTestalready covers every row of the table without building anMpdffor eachSkipped:
$lang != ''guard on the region branch. It's redundant, but it was there before this change and it matches the branch above it.TextRecordingMpdf. That would mean editing about a dozen tests outside this diff.Verification
vendor/bin/phpunit: 2084 tests, 5955 assertions, 1 skipped (Fall back from a v2 Indic tag to its own original tag only (#192) #200 is 2065 / 5924 / 1).vendor/bin/phpunit --group=snapshot: OK, 79 tests, 110 assertions.composer cs: clean.🤖 Generated with Claude Code