【科普向】为什么安卓更换字体后,无法完全正确的显示日文韩文以及部分文字显示别扭?
好早之前就发现,换了字体后,总是有一部分字无法正确显示(能显示,但无法正确显示为新字体的样式),看着很别扭。
后来稍稍了解了下发现问题出在字体文件没有该字符。但实际上,很多常见的字有时候也无法正确显示,这是咋回事?
起因是我收到运营商的一条提醒短信,瞅了一眼,发现短信中的广(标注1)字形明显怪异。这是常用字,字体应该包含了才对,为什么会出现这种情况?
于是把这个字复制出来,放到python里读一下字体unicode编码
发现这两个字的编码不相同,短信里的广编码为U+2F34,对应查询下该编码的区域
该字码位于康熙部首的unicode编码范围,康熙部首是清代康熙字的构成部分,而康熙部首作为不再用于交流的“古文字”,主流的字体都不会去支持,包括涵盖600多种语言的MiSans(小米开源字体、MIUI默认字体)都不包含
如下图为MiSans字体,并不包含康熙部首(羽、毛、自、木)
当出现这种情况,系统会尝试回退查找字体:
用户自定义字体 -> 系统默认字体 -> Noto Sans CJK
Noto Sans CJK是Google提供的开源多语言字体(包括康熙部首),内置在安卓系统中:/system/fonts/NotoSansCJK-Regular.ttc
至此我们解决了第一个问题:看起来很常见的字,不能被正确显示,原因是这个字他真的不是常见字,只是字形像而已。
像最上面的短信,这么做是防止被短信防火墙(如关键字黑名单)拦截
这里还可以扩展和顺带解决其他字体疑问(以下“正确显示”均指换了系统字体,显示的字没跟随着换)
例如
为什么有些app的字体不会跟随系统变化?
APP内置了字体,优先使用内置字体渲染文字
为什么有些app一些生僻字无法正确显示?
生僻字在第三方字体中兼容性参差不齐,大部分字体都没实现生僻字,当遇到时,就会调用系统默认的Noto Sans CJK字体进行渲染
为什么有些app能正确显示康熙部首,有些则不能?
原因同上,app内置的字体,包含了康熙部首的编码
为什么同一个字,比如康熙部首的广,在某些网页上正常显示,在短信、记事本里不能正确显示?
网页可以引入康熙部首字体文件进行渲染,当然能正确显示。而你的系统中现在默认的字体没有该字体,就使用了Google内置的Noto Sans CJK
解决完上面这个,我还想起,经常遇到日文韩文部分字体错误显示的问题
比如日文的“真”和中文的“真”写法如下所示
但实际上在当你系统语言为简中时,你输入的日文中的“真”都是简体中文的真
而当你系统语言为日文时,输入的“真”都是日文中的真
两者的“真”字经查看发现编码都是U+771F
,一个编码在不同语言环境会显示为不同的字形?!
经过查询发现,现在大统一的unicode编码字体中,把不同语言变体存储为一个编码,
字体内是这么实现的,通过locl去切换字符:
feature locl {
script hans; language ZH; substitute U+771F -> 真; # 中文
script hans; language JA; substitute U+771F -> 眞; # 日文
};
所以在简中系统下,你看到的很多韩文、日文字体都是有错误的。
那有没有解决方法呢?目前是没有统一的解决方法
如果是翻译软件,如简中->日文
开发者需要把翻译框设置为日文
// Android 示例:设置 TextView 的语言
textView.textLocale = Locale.JAPANESE // 触发日文字形
如果是网页,开发者同样需要进行指定语言
<p lang="zh">简中:真</p> <!-- 显示简体/繁体「真」 -->
<p lang="ja">日文:真</p> <!-- 显示日文「眞」 -->
而对于像微信朋友圈、微信聊天、小黑盒小红书酷安这些,如果要完全正确显示日文韩文等汉字变体字,则需要在编辑器里给用户可以指定某个段落某个字符的语言的功能才能完整兼容
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
评论已关闭