首页 / 资讯中心 / 文章详情

树莓派中文显示三关:换源、字体与locale配置避坑

树莓派中文显示三关:换源、字体与locale配置避坑 ★ FEATURED ARTICLE
简介面向树莓派初学者与 DIY 爱好者的中文显示设置文档针对 Linux 系统默认英文界面带来的理解与操作障碍提供一套可跟随执行的汉化配置思路。文档以换源、字体安装、区域与语言设置、重启验证为主线记录终端命令、配置项选择及重启后的界面效果便于读者理解各环节之间的依赖关系并在遇到更新缓慢或中文不显示时对照排查。内容预览显示其以分步条目组织先调整软件源以提升更新速度再补齐中文字体最后借助系统配置工具完成语言、时区与键盘布局设定并在末尾附上效果查看。资源包共 1 个 docx 文件大小约 732KB篇幅集中、结构清晰适合离线查阅与逐步实践。已有 231 人学习说明该主题对入门用户具有实际参考价值。对于希望减少英文界面障碍、快速搭建中文使用环境的树莓派学习者这份文档可作为轻量而完整的基础材料。1. 树莓派改中文显示三关没过完装多少字体都是方块树莓派刷完系统第一次接显示器桌面菜单是英文的打开浏览器访问中文页面却满屏方块——这两个现象看着像同一件事其实是两条独立的链路。树莓派改中文显示要过三关仓库源得能连通否则字体包根本下不下来字体包得提供中文字形否则有编码没形状方块照旧locale 得把语言环境指到zh_CN.UTF-8否则系统压根不认为自己该说中文。绝大多数人卡在第三关装完文泉驿正黑发现界面纹丝不动就是 locale 没动过。这套流程适合刚拿到板子、想一次配好的新手也适合已经换过源、却被 404 和方块字反复折腾的人——下面按这三关的顺序拆每一步都给能直接抄的命令和出错时的判断依据。2. 换源这一步树莓派 OS 的代号、路径与 apt update 的三种报错换源是整个流程里最容易把人带沟里的一步因为它看起来只是复制两行地址。实际上源文件里写死的发行版代号、仓库路径、组件列表三者必须和板子上跑的系统严丝合缝错一个字符就是apt update一路 404。原始教程里那两行jessie的写法放在当年的 Raspbian 上是对的但jessie是 Debian 8 的代号主镜像站早就把它挪进归档区了今天照着抄大概率连不上。所以第一步不是打开编辑器而是先认清手里这块板子到底跑的是哪一代。2.1 先认清代号再决定往文件里写什么Debian 系的代号是有顺序的jessie(8)、stretch(9)、buster(10)、bullseye(11)、bookworm(12)越往后越新。树莓派 OS 一直跟着 Debian 走不同年份烧的卡代号可能差好几代。代号写错不会立刻报错而是等你执行apt update时才集中爆发所以先花十秒确认。# 一次性打印发行版全名、代号、架构三条信息都影响源地址怎么写 . /etc/os-release printf 系统: %s\n代号: %s\n架构: %s\n $PRETTY_NAME $VERSION_CODENAME $(dpkg --print-architecture)逻辑说明. /etc/os-release是把系统的元信息文件当脚本 source 进来VERSION_CODENAME就是bookworm这类小写代号PRETTY_NAME是给人看的完整描述。参数说明dpkg --print-architecture输出armhf或arm64它决定你能不能混用别人给的源——32 位系统配 64 位仓库的包装上去也是白装。把代号记下来后面所有地方都必须用它不要凭印象写。还有一点要留意较新的树莓派 OS 把仓库拆成了两处。Debian 官方包在/etc/apt/sources.list树莓派自己的驱动、固件、专用工具在/etc/apt/sources.list.d/raspi.list部分版本已经换成 deb822 格式的raspi.sources。只换前者会出现「装普通软件飞快、装树莓派专用包还是龟速」的割裂感只换后者系统基础包又慢。常见做法是两个都换或者干脆统一交给镜像站提供的配置脚本来做。2.2 注释旧行、写入新行以及 CtrlO 和 CtrlX 的区别原始教程里说「按 ctrl-x 保存」这是个流传很广的笔误。nano里CtrlO是写入Write OutCtrlX是退出Exit退出时如果缓冲区有改动它会问你Save modified buffer?敲Y再回车也能存。两种路径都通向同一个结果但如果你的习惯是「CtrlX 然后一路回车」在某些终端下回车键会把提示跳过文件其实没落盘后面apt update用的还是旧源人就开始怀疑人生。改之前先备份这条我从来不敢省# 备份两个源文件出问题能一条命令还原比重刷系统便宜太多 sudo cp -a /etc/apt/sources.list /etc/apt/sources.list.bak sudo cp -a /etc/apt/sources.list.d/raspi.list /etc/apt/sources.list.d/raspi.list.bak 2/dev/null || true # 看看现在生效的到底是哪些行过滤掉注释行 grep -rhs ^[^#] /etc/apt/sources.list /etc/apt/sources.list.d/*.list 2/dev/nullcp -a的-a是归档模式保留权限和时间戳源文件属于 root必须带sudo。最后那条grep的-h去掉文件名前缀、-s静默不存在的文件^[^#]是「行首不是井号」的正则正好把注释掉的行筛掉一眼就能看出当前真正在用的是哪几个地址。如果这条命令什么都没输出说明源被.sources格式接管了那就要去改/etc/apt/sources.list.d/*.sources。接着编辑。用nano也好用脚本一次性写入也好核心是三件事旧行前面加#注释掉而不是删掉留着方便对照回滚、新地址的仓库路径要跟代号匹配、组件列表别乱删。国内镜像站的路径各家写法不同有的是/raspbian/raspbian/有的是/debian/还有的只镜像了树莓派自有仓库而没镜像 Debian 主仓。路径必须照着你选的那家镜像站的官方说明写不能照抄旧教程这是 404 的第一大来源。# 变量化写法避免手抖打错MIRROR 换成你选定镜像站的主机名 MIRRORmirror-host CODENAMEbookworm # 用 2.1 打印出来的真实代号别照抄这一行 sudo tee /etc/apt/sources.list.d/raspi.list /dev/null EOF # 原有地址已注释保留回滚时直接取消注释即可 # deb http://legacy.example/raspbian/raspbian/ jessie main contrib non-free rpi deb http://${MIRROR}/raspbian/raspbian/ ${CODENAME} main contrib non-free rpi EOFtee配合sudo是往 root 文件写内容的稳妥方式/dev/null只是把 tee 顺手打到屏幕上的那份内容丢掉。heredoc 里的${MIRROR}和${CODENAME}会被 shell 展开所以变量必须提前定义好。参数说明main contrib non-free是 Debian 的三大组件区rpi是树莓派专属区删掉任何一个都会导致某些包「明明存在却装不上」。bookworm之后部分仓库新增了non-free-firmware组件如果你的镜像站说明里带了它一并加上别自作主张精简。2.3 apt update 之后怎么判断这次是真通了apt update成功和失败的区别不在退出码而在输出里的E:和W:。正常情况是一串Hit、Get、Ign最后Reading package lists... Done失败则会出现404 Not Found、Release file for ... is not valid yet、does not have a Release file这几种。把输出留存下来比反复重跑强。# 把更新日志落盘然后只挑错误和警告行看 sudo apt update 21 | tee /tmp/apt-update.log grep -nE ^(E|W): /tmp/apt-update.log || echo 无 E/W 行源基本可用21把 stderr 并进 stdout否则 apt 的错误信息不在管道里tee抓不到。grep -nE ^(E|W):只匹配行首的E:或W:能过滤掉大量无关的Hit噪音|| echo表示 grep 没匹配到退出码非 0时打印兜底提示。三种典型报错的对应关系是这样报错关键字大概率原因处理方向404 Not Found仓库路径写错或代号与镜像站支持的版本不匹配回镜像站文档核对路径curl -I手动探一下地址does not have a Release file目录层级不对多一层或少一层逐段砍 URL 试找到能返回 200 的那一层is not valid yet板子系统时间不对证书与 Release 校验失败先校时再重跑 update时间那条特别阴树莓派没有 RTC 电池断电量久了开机时间会飘到几年前这时候源地址完全正确也照样报错。timedatectl看一眼就知道sudo timedatectl set-ntp true让它在联网后自动校准。3. 字体与 locale 拆开看为什么装完文泉驿界面还是英文这一步是整套流程里认知门槛最高的地方。字体包和 locale 是两个完全正交的东西字体包回答「这台机器上有没有中文字形」locale 回答「系统该不该用中文来显示」。两个都到位中文才会出来只做一个结果就是「字能显示但界面还是英文」或者「界面语言变了但全是方块」。很多人装完字体发现没反应就放弃了其实是漏了后面那半。3.1 字体包解决的是「有没有字形」先确认包名原始教程里写的是ttf-wqy-zenhei这是老一代 Debian 的包名。较新的发行版把它改成了fonts-wqy-zenhei两者在部分版本里靠过渡包兼容但不是所有镜像都保留了过渡包。稳妥的做法是先查再装别硬套教程里的名字。# 先看仓库里到底提供了哪些文泉驿相关的包 apt-cache search wqy # 再看具体包的版本和来源确认它能从你刚换的源里拿到 apt-cache policy fonts-wqy-zenhei ttf-wqy-zenheiapt-cache search是按包名和描述做关键词匹配输出里会带一行简短说明。apt-cache policy更关键它会打印Installed已装版本、Candidate可装版本和来源行——如果Candidate是(none)说明你换的源里根本没有这个包那问题不在字体回到第 2 章检查源。参数说明同时列两个包名是为了看清哪个是真实包、哪个只是过渡包装真实包就行别两个都装。# 正黑和微米黑一起装前者用于桌面后者体积小、适合嵌入式场景 sudo apt install -y fonts-wqy-zenhei fonts-wqy-microhei # 刷新字体缓存让 fontconfig 立刻感知到新字形 fc-cache -fv /dev/null # 验证中文字形的数量以及默认匹配到的字体 fc-list :langzh | wc -l fc-match WenQuanYi Zen Heifc-cache -fv的-f强制重建、-v输出细节重定向到/dev/null只是不想刷屏出问题时把重定向去掉再看。fc-list :langzh用 fontconfig 的语言过滤器列出所有支持中文的字体wc -l数行数——大于 0 就说明字形已经进系统了。fc-match是按名字找最接近的匹配注意字体族名是英文的WenQuanYi Zen Hei写中文名它认不出来。这一步通过之后说明第一关和字形这一关都过了剩下的纯粹是 locale 的问题。如果fc-list :langzh是 0但dpkg -l | grep wqy显示已安装那是缓存没刷或者字体装到了非标准目录fc-cache -fv再跑一遍还不行就fc-list | grep -i wqy看它实际被识别成了什么名字。3.2 locale 的生成与写入别碰 LC_ALLlocale 这套机制分两层第一层是系统里「生成了哪些语言环境」第二层是「当前会话用哪一个」。locale-gen负责第一层update-locale或环境变量负责第二层。新手最常见的错误是直接export LANGzh_CN.UTF-8结果一重启就没了或者编辑/etc/default/locale写了LC_ALLzh_CN.UTF-8导致所有分类被强制覆盖SSH 登录时报一堆setlocale警告。# 1) 看当前状态LANG 是什么有没有 LC_ALL 在捣乱 locale # 2) 看系统里到底生成了哪些中文 locale locale -a | grep -i zh_CNlocale不带参数会打印全部LC_*分类重点看LANG和LC_ALL两行后者为空才是健康的。locale -a列出的是已生成的语言环境如果只看到C、C.UTF-8、POSIX说明中文环境从来没被生成过——这时候你把LANG设成zh_CN.UTF-8也不会生效系统会悄悄回退到C。# 3) 在 locale.gen 里取消 zh_CN.UTF-8 那一行的注释幂等重复执行无害 sudo sed -i s/^#\s*\(zh_CN\.UTF-8\s\UTF-8\)/\1/ /etc/locale.gen grep -n zh_CN /etc/locale.gen # 4) 真正生成这一步会编译 locale 数据慢一点是正常的 sudo locale-gen # 5) 写进系统默认配置只设 LANG 和 LANGUAGE sudo update-locale LANGzh_CN.UTF-8 LANGUAGEzh_CN:zhsed那条正则拆开看^#\s*匹配行首的井号加任意空白\(...\)是捕获组把zh_CN.UTF-8 UTF-8原样保留替换成不带井号的版本。\s在 GNU sed 里可用如果报错就换成[[:space:]]*。grep -n zh_CN是自检应该看到那一行没有行首井号了。locale-gen不带参数会读/etc/locale.gen全量生成只生成需要的语言能省不少时间。update-locale写的是/etc/default/localeLANGUAGEzh_CN:zh是消息翻译的优先级列表先中文后备用这一项不设的话某些程序的界面文案仍然是英文。注意不要往/etc/default/locale里写LC_ALL。它优先级最高会把LC_TIME、LC_NUMERIC、LC_COLLATE全部拉成中文副作用是日期格式、小数点、排序规则一起变脚本里解析date输出的地方会莫名其妙出错。3.3 raspi-config 里那几个选项本质是在改什么sudo raspi-config是个封装脚本它的 Localisation Options 底下那几项做的事情和上面手敲的命令完全一致只是多了个 TUI 界面。Locale 那一项本质是「勾选要生成的语言环境 写/etc/default/locale」Timezone 写/etc/timezone并同步硬件时钟Keyboard 改的是/etc/default/keyboard。用空格键选中、Tab 切到Ok回车这套操作在 SSH 里也能跑只是方向键偶尔会和终端快捷键打架。# 改完之后核对它到底写了什么进去这是最直接的证据 cat /etc/default/locale # 期望看到类似两行 # LANGzh_CN.UTF-8 # LANGUAGEzh_CN:zh # 再看 locale.gen 里中文那行是否已被取消注释 grep -v ^# /etc/locale.gen | grep -i zh_CN如果cat出来的LANG是en_GB.UTF-8或干脆没有这一行说明 TUI 里那一步没保存成功——常见原因是勾选时只按了回车没按空格[ ]和[*]的区别就在一个空格键。这个坑我踩过不止一次界面看起来「点过了」其实状态没变。核对完再往下走能省掉一轮重启。4. 桌面、SSH、TTY三条链路上中文各自在哪一段断掉同样是「中文没显示」发生在桌面、SSH 会话、纯文本控制台这三个场景原因完全不同。桌面看的是会话级 locale 加字体匹配SSH 看的是服务端有没有把LANG传过来加上客户端终端字体TTY 则受限于内核控制台字体本身的能力。搞清楚自己是在哪条链路上出问题比盲目重装字体有效得多。4.1 本地桌面会话重启才生效重启服务会踢人桌面环境下/etc/default/locale是登录时读取的改完之后当前已经登录的会话不会自动刷新。所以「改完没反应」很多时候不是没生效是会话还是老的。最稳的做法是sudo reboot急的话重启显示管理器也行但要知道它会把你当前的图形会话直接断掉。# 重启显示管理器代价是当前桌面会话被强制注销 sudo systemctl restart lightdm # 如果用的是较新的系统服务名可能是 display-manager systemctl status display-manager --no-pagersystemctl restart对lightdm是硬重启所有未保存的图形程序内容会丢所以这条命令不该在写到一半的文档上执行。display-manager是个别名单元指向当前实际使用的显示管理器用status看一眼就知道该操作哪个名字。参数说明--no-pager是防止输出被less接管在脚本或窄终端里很有用。桌面里还有一层容易被忽略应用自己的语言设置。浏览器、编辑器这类程序有的会读LANG有的有自己的语言偏好配置两者不一致时就会出现「桌面菜单中文了、某个软件还是英文」。另外图标显示成方块通常是图标主题里没有对应的中文字体回退用fc-match -s sans-serif | head -5看回退链的前几位有没有中文字体没有的话手动指定一次字体族就能解决。4.2 SSH 会话两端都要对缺一不可SSH 场景下中文乱码八成不是板子的问题而是「服务端没把 locale 传过去」或者「你本地终端字体不含中文」。SSH 协议里LANG这类环境变量需要通过SendEnv/AcceptEnv显式协商默认是不传的所以你会看到一个很诡异的组合板子本地桌面全是中文SSH 上去locale显示LANGC。# 服务端确认 sshd 允许接收哪些环境变量 grep -i AcceptEnv /etc/ssh/sshd_config # 客户端连接时显式发送 LANG ssh -o SendEnvLANG pihostAcceptEnv在服务端配置里写的是允许客户端发送的变量名模式常见默认值包含LANG LC_*。如果这一行被注释掉了客户端发过去也会被丢弃。ssh -o SendEnvLANG是临时在命令行覆盖客户端配置适合排查用长期用还是写进~/.ssh/config更省事。如果不想依赖客户端配合可以在服务端做兜底但要注意兜底的写法不能覆盖用户自己的选择# 服务端兜底仅在 LANG 未设置时补一个默认值用 : 而不是 sudo tee /etc/profile.d/zh-cn.sh /dev/null EOF # 只在当前为空时赋值避免覆盖客户端或用户显式设置的值 : ${LANG:zh_CN.UTF-8} export LANG EOF:和的区别是这次操作的核心${LANG:x}在LANG为空或未定义时才赋值${LANGx}在未定义时赋值但空值不处理而直接LANGx是无条件覆盖。放在/etc/profile.d/下的脚本会被所有登录 shell 自动 sourceheredoc 用EOF加引号是为了禁止变量在写入时被展开否则${LANG:...}会在写文件的那一刻就被求值成空字符串。4.3 纯文本控制台这一层的中文期望值要放低按CtrlAltF1切进去的那个黑底白字界面是内核 framebuffer 控制台。它用的是console-setup配置的点阵字体常见选择是 Terminus 系列而这些字体里不含 CJK 字形。也就是说即使 locale 和字体包全都配好了这一层的中文大概率仍然是方块或问号——这不是配置错了是这一层的技术栈本身不支持。# 确认控制台编码是 UTF-8字体配置是否合理 grep -E ^(CHARMAP|CODESET|FONT|FONTSIZE) /etc/default/console-setup # 重新配置键盘与控制台TUI 里选 UTF-8 / Guess optimal / Terminus sudo dpkg-reconfigure keyboard-configuration sudo dpkg-reconfigure console-setup sudo setupconCHARMAP必须是UTF-8这是编码层的前提FONT决定字形FONTSIZE影响一屏能放多少字符。dpkg-reconfigure会重新走一遍该包的配置向导setupcon是让改动立即应用到当前控制台不用重启。这三条命令能保证「编码正确、英文显示正常」但不能变出中文字形。真要在这一层看中文得靠fbterm这类在 framebuffer 上自绘字形的工具配置成本不低日常运维更常见的做法是直接用 SSH 或图形界面把 TTY 当成救援通道用。5. 避坑记录五条把系统搞到要重刷的翻车现场下面这几条都是实际会让人卡住半天以上的按「现象 → 原因 → 解决」写遇到对应的现象直接对号入座不用从头再捋一遍流程。第一条apt update一片 404越更新错误越多。现象是执行后刷出一屏404 Not Found每个源都报但网络明明是通的。原因是把旧教程里的jessie代号和/raspbian/raspbian/路径原封不动搬到了bookworm的系统上——代号和路径必须成对匹配跨代混用必然 404。解决是先跑 2.1 那条命令拿到真实代号再回镜像站文档核对路径层级用curl -I url/dists/codename/Release手动探一次返回 200 才写进文件。已经写错的用备份的.bak覆盖回去重新来一遍。第二条装完字体桌面菜单还是英文但网页中文正常了。现象很迷惑浏览器里中文显示没问题说明字形有了可系统菜单始终是英文。原因是只做了「字体」这一半LANG还停在en_GB.UTF-8或C.UTF-8系统认为界面语言就该是英文。解决是按 3.2 走完locale-gen加update-locale两步再用locale确认LANGzh_CN.UTF-8最后重启。注意locale -a里没有zh_CN.utf8时光改LANG是无效的系统会静默回退。第三条SSH 上去中文全是问号本地桌面却好好的。现象是同一台板子接显示器看是中文SSH 进来ls中文文件名变成????。原因是 SSH 默认不传LANG服务端会话拿到的是C或POSIX加上你本地终端字体可能也不含中文两端任一环节断掉都表现成问号。解决分两步验证先在 SSH 里echo $LANG是C就走 4.2 的SendEnv或profile.d兜底LANG已经正确还乱码就换一个含中文字形的终端字体再试把服务端和客户端的问题分开定位。第四条两个源同时写apt install报依赖冲突装一半卡死。现象是apt update能过但装包时提示某个包「有未满足的依赖」或者版本互相打架严重时dpkg停在半途之后每次操作都提示要dpkg --configure -a。原因是在sources.list和raspi.list里写了重复或版本不一致的仓库apt 拿到同一份包的两个不同版本解依赖时打架。解决是先sudo dpkg --configure -a把中断的事务收尾再用apt-cache policy 包名看这个包到底有几个来源把多余的那一行注释掉只保留一个版本匹配的仓库。第五条改完源文件重启系统起不来卡在登录前。现象是重启后黑屏或停在某个服务启动失败SSH 也连不上。原因是源文件改坏之后某次apt upgrade装上了不匹配版本的核心包或者sources.list格式错误导致 apt 相关服务启动失败。解决只能上救援把 SD 卡拔下来插到另一台机器挂载后恢复.bak文件或者用另一台机器 SSH 进去如果网络服务还活着sudo cp /etc/apt/sources.list.bak /etc/apt/sources.list后sudo apt install -f。这条最贵的教训是改源之前一定备份而且不要在同一时间既换源又做大版本升级两件事分开做出问题才知道是哪一步的锅。6. 验证与回滚重启之后用一段脚本确认三关都过了重启完之后别急着看桌面先用一段脚本把三关挨个验一遍比肉眼观察靠谱。下面这段可以直接存成check-zh.sh每次改完配置跑一次输出的 OK/NG 就是判断依据。#!/usr/bin/env bash # 一次性校验源可用性、中文字形、locale 三项是否全部落地 set -u fail0 . /etc/os-release echo [1] 系统代号: ${VERSION_CODENAME} echo [2] 当前 locale: locale | sed s/^/ / case ${LANG:-} in zh_CN.UTF-8*) echo OK: LANG 指向中文 ;; *) echo NG: LANG 不是 zh_CN.UTF-8; fail1 ;; esac [ -n ${LC_ALL:-} ] { echo NG: LC_ALL 被设置成了 ${LC_ALL}; fail1; } echo [3] 中文字形数量: n$(fc-list :langzh 2/dev/null | wc -l) echo ${n} 个 [ $n -gt 0 ] || { echo NG: 系统里没有可用中文字形; fail1; } echo [4] apt 源检查: if sudo apt update -qq 2/tmp/apt.err; then echo OK: apt update 通过 else echo NG: 见 /tmp/apt.err sed s/^/ / /tmp/apt.err | head -5 fail1 fi [ $fail -eq 0 ] echo 三关全过 || echo 有项目未通过按上面的 NG 行回查 exit $failset -u让未定义变量直接报错避免${LANG:-}之外的变量拼错却静默通过。sed s/^/ /只是给每行加缩进让输出层次清楚。apt update -qq的-qq把输出压到最少只看退出码错误信息重定向到/tmp/apt.err备查。整段脚本的退出码就是失败项的数量标记方便挂到开机自检里。回滚路径也要提前想好不然真出事只能重刷。三个层面的还原改坏的东西回滚命令说明源文件sudo cp /etc/apt/sources.list.bak /etc/apt/sources.list前提是改之前备份过localesudo update-locale LANGC.UTF-8 LANGUAGE先退回中性值再重配locale 数据sudo locale-gen --purge清空重生成耗时较长update-locale后面跟空值会把对应变量从文件里删掉这是撤掉LANGUAGE的干净做法。locale-gen --purge会先清空已生成的数据再重建只在怀疑 locale 数据损坏时用日常回滚用不到它。最后说个习惯。早些年我在一块板子上同时换了源、装了字体、改了 locale重启后黑屏因为没备份源文件又判断不出是哪一步的问题只能把卡拔下来重刷一个下午就没了。从那以后我每次动sources.list之前都强制走一遍备份并且规定自己一轮只改一类东西先换源、验证、重启再装字体、验证最后动 locale。三关分开过出问题时范围立刻缩小到刚改的那一项。另外那个check-zh.sh我也一直留着每次配完新卡跑一遍比凭肉眼在桌面上找中文靠谱得多。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站