填空式的一页简历生成器:python fill.py 一题一题地问,问完写成一份内容 TOML,
再 make render 出 PDF / HTML / PNG。
不想被问就 python fill.py --blank 拿一份空白表单,在编辑器里把每个空填上。
想边填边看版面就 python webui.py,浏览器里左边填字、右边实时看 A4(只听本机)。
答案存成 TOML,版面用 CSS 排——内容和版式始终是分开的两个文件。
排版交给 WeasyPrint 的 CSS 盒模型,间距由引擎计算——不手工算坐标,所以不会出现 "标题压住上一段文字"这种事。内容超过一页时程序报错拒绝生成,不会偷偷给你第二页。
上图是仓库里的
content.example.toml渲染出来的。人名、公司、数字全是编的; 顶部那两条链接是模板作者的(eigentime.org · github.com/wowayou),当署名用,你自己那份换掉就行。
- 想要一份克制、能过 ATS、黑白打印也清楚的一页简历(中文、英文都行);
- 不想从零排版,也不想被在线编辑器绑住:回答一串问题就有一份 PDF;
- 愿意把内容和版式分开:改内容只动 TOML,调版式只动
theme.toml; - 需要按岗位做多个定制版,而且不想让真实姓名手机邮箱进 Git。
不适合:需要多页、需要花哨图形、需要在线编辑器的场景。
这个仓库是公开的,所以它被设计成工具和数据分离:
| 在哪 | 进 Git 吗 | |
|---|---|---|
| 程序、版式、设计令牌 | 本仓库 | ✅ 跟踪 |
content.example.toml 虚构示例 |
本仓库 | ✅ 跟踪 |
你的真实内容 content.toml |
本仓库目录内,或仓库外任意路径 | ❌ 被 .gitignore 挡住 |
fill.py 留的备份 content.toml.bak |
内容文件旁边 | ❌ 被 .gitignore 挡住 |
生成物 build/ |
本仓库 build/ 或你指定的目录 |
❌ 被 .gitignore 挡住 |
四道防线:
-
.gitignore里是content*.toml+!content.example.toml——除了示例,任何 内容文件都进不去。按公司做定制版叫content.acme.toml也一样安全。*.toml.bak另有一条:content.toml.bak后缀变了,不匹配content*.toml, 而备份里装的是一模一样的真实内容。 -
build/整个目录忽略。PDF 的正文是可被全文搜索的,手机号进了 Git 历史就得重写 历史才删得掉。 -
./scripts/check-privacy.sh(=make check)在提交前扫一遍被跟踪的文件里 有没有手机号、真实邮箱、私人内容文件或生成物。再建一个
.identifiers文件(已在 .gitignore 里),一行一个写上你的姓名、 个人域名、雇主名,改示例时手滑粘了真东西进去会被当场拦住:cat > .identifiers <<'EOF' 张三 yourdomain.com 某某科技有限公司 EOF
有些标识是你故意公开的——比如示例简历里当署名的个人域名。这种在竖线右边 列出允许出现的文件(空格分隔),出现在别处照样报错:
yourdomain.com | content.example.toml⚠️ 不要把这些串写进脚本本身——脚本是公开仓库的一部分,写进去等于亲手 公开你本想拦截的东西。.identifiers存在才做这项检查,不存在就跳过。 -
预览图不许过期。 README 顶部那张
examples/preview.png是生成物:改了示例 内容或版式却忘了重渲,README 上就会一直挂着旧内容。examples/preview.sha256记着四份输入(content.example.toml+theme.toml+resume.css+render.py)的哈希, 对不上make check就报错。改完示例跑一次make preview,它会重渲、覆盖图片、 更新哈希,两个文件一起提交。
更稳的做法:把真实内容文件放在本仓库之外(比如另一个私有仓库、或
~/.private/resume/me.toml),用 --content 指过来。这样连"误改 .gitignore"
这条路都堵死了:
python render.py --content ~/.private/resume/me.toml --out-dir ~/.private/resume/build在没装过任何东西的机器上(Debian / Ubuntu / WSL2,或 macOS + Homebrew),只要仓库 在手上,一条命令就绪:
git clone https://github.com/<你的账号>/onepage-resume.git
cd onepage-resume
make bootmake boot 依次做三件事,幂等(重复跑不会坏事):
scripts/bootstrap.sh—— 自动探测包管理器,把 WeasyPrint 要的系统库和 CJK 字体 装齐(缺才装,不会反复跳出来要 sudo);非交互、没有 sudo 时会打印手动命令而不是卡死。make setup—— 建.venv并装 Python 依赖。make example—— 渲染虚构示例冒烟。build/example/resume.pdf出来就说明环境通了。
然后挑一种填法开始(见下),最后 make render 出你自己的 PDF。
不用碰 start.cmd,它是给「从 Windows 那边进来」用的。在 WSL 终端里就是两条:
cd ~/onepage-resume
make boot # 只有第一次要跑(幂等,重复跑不会坏事)
make ui # 以后每次就这一条make ui 会自己去开 Windows 那边的浏览器(走 wslview 或 powershell.exe)。
开不成它会把网址再打一遍,手工点开 http://127.0.0.1:8765 一样用。
原生 Windows 用户:装好 WSL2 + 一个 Ubuntu 发行版后,双击仓库根目录的
start.cmd 即可——它会自动进 WSL 跑完上面三步,等端口通了再打开浏览器。
仓库放在哪都行,两种位置它都认:
- 在 WSL 里(
\\wsl.localhost\<发行版>\home\...,推荐、也更快):它会把这个 UNC 路径拆回「发行版名 + Linux 路径」,用wsl -d <发行版> --cd /home/...进去。 - 映射成了网络驱动器(比如
Z:\home\...指向\\wsl.localhost\Ubuntu-24.04): 也认。wsl自己认不了盘符(会说Failed to translate 'Z:\...'),所以脚本先用net use把盘符还原成 UNC,再按上一条处理。 - 在 Windows 盘上(
C:\...):能用,但要经/mnt/c绕一圈,I/O 慢、实时预览迟钝。
走的是 WSL2 默认开着的 localhostForwarding;被关了的话见「排障」。
make dist # 生成 dist/onepage-resume-<版本>.tar.gz内容取自 git HEAD 的跟踪文件(含 bootstrap.sh、Makefile、README、start.cmd),
所以先把改动 commit 再打。它永远不会带上你的真实内容——content*.toml 和 build/
本来就不进 Git,也不会进包。拿到包的人在另一台机器上 make boot 即可。
make ui # 浏览器里填:左边填字,右边实时看 A4(只听本机)
make render # 出 build/<你起的文件名>.pdf不想开浏览器就看下面的"三种填法"。没有 make 也不用怕:先跑 scripts/bootstrap.sh
装系统库,再手动建 venv:
scripts/bootstrap.sh
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/python fill.py
.venv/bin/python render.py〇、浏览器里填(想边填边看版面就用这个,零终端的正门)
make ui # 绑到 127.0.0.1 时会自动打开浏览器
# 在 WSL 里会去开 Windows 那边的浏览器;开不成会把网址再打一遍让你自己点
# 不想自动开(远程 / 无桌面): python webui.py --no-open
# 手工访问也行: http://127.0.0.1:8765左边是照着字段表长出来的表单。打字停下约 0.4 秒后,右边用 render.py 排版,
再把同一次排版生成的 PDF 转成页面图,标注为 PDF 实渲。换行、字体和页数都
来自 PDF,不依赖浏览器重新排版;超页时最多展示前两页,状态栏仍报告实际总页数。
每个窗口最多保留一个在途预览,期间的新输入合并到下一次请求,旧响应不会覆盖新内容。
缺少 pdftoppm 时明确标注为 HTML 近似:仍然计算真实 PDF 页数,但屏幕换行
仅供参考,定稿请以 PDF 为准。窄屏优先显示表单,页数、空白和下载状态仍保留。
顶上那条状态栏是这个界面的重点:
- 页数 1 ✓ / 2 ✗——超一页当场变红,不用等点了"生成 PDF"才发现。
- 空白 N 处——鼠标停上去列出还差哪些空;未完成校验、有空白或超过一页时, "生成 PDF"都禁用,避免把旧预览当成当前内容的校验结果。
- 数组块(联系方式、技能、经历、项目)可以加一条、删一条、上下移。
- 换
theme.en.toml立刻重渲,中英文版式可以来回比。
点生成 PDF 之后,状态栏右侧出现「查看 / 下载」两组链接:PDF 和 PNG 的 查看在新标签页里用浏览器自带的阅读器或图片查看器打开,下载照旧存文件; HTML 只给下载——内联打开会让生成的页面脚本跑在本服务的源下。
改动只在浏览器里,点保存 TOML 才写进文件(覆盖前照样留 .bak)。
保存先写同目录临时文件,再原子替换,不会留下半份 TOML;新文件和备份仅当前用户可读写。
同一文件若被另一个窗口或编辑器改过,会拒绝覆盖并提示重新读取。另存为一个已存在
的文件名也会被拦下,必须先读取目标文件。保存期间继续输入,新输入仍标为未保存。
它和 fill.py 读写的是同一份 content.toml,两种界面可以来回换:
命令行填一半,网页里接着改,再回命令行都认。
⚠️ 这个服务默认只听127.0.0.1,而且没有登录、没有口令——门禁就是"只听本机"。 所以别加--host 0.0.0.0:那等于把你的姓名、手机、邮箱敞开给整个局域网, 别人还能写你的内容文件。程序真被这么启动时会打印一条显眼的警告。它能碰的文件也被夹死在两处:内容目录下匹配
content*.toml的文件(正是.gitignore挡住的那一批),以及生成物目录里的 .pdf / .html / .png。content.example.toml是仓库里跟踪的示例,可以读进来看版面,不许写回去。真实内容想放仓库外:
python webui.py --content-dir ~/.private/resume。 这个边界也适用于extends的每一层;不接受目录穿越、绝对路径或符号链接。 写接口仅接受 JSON,并检查浏览器来源,拒绝其他网站借本机服务写入文件。
一、被问着填(不想开浏览器就用这个)
python fill.py一题一题往下走,每题都带一句解释和一个例子。回车 = 跳过选填项;数组类的 (联系方式、技能、经历、项目)每填完一条会问你要不要再来一条;Ctrl-C 随时退出, 不会写半份文件。
再跑一次就是"改一处":它会先把已有的 content.toml 读进来,每题显示当前值,
回车保留、输入覆盖。覆盖前旧文件会备份成 content.toml.bak(同样不进 Git)。
二、自己在编辑器里填
python fill.py --blank # 生成 content.toml:每个空都在,但都空着
python fill.py --blank --sample # 想先看版面,就用带示例答案的那一份
$EDITOR content.toml表单里每个空上面都有一行注释,写清楚这个空是干什么的、该写多长、例子长什么样。 数组表想加一条就整段复制粘贴。
--blank 只创建新文件,目标已存在时会拒绝覆盖。已有文件损坏、字段类型错误或含有
未知字段时,程序会明确报错,不会把它当成空表重写。修正原文件后再继续。
list 类字段(关键词、身份事实、面包屑、教育信息)用 空格 / 空格 分隔;
斜杠至少一侧带空白才算分隔符,所以 https://example.com/a/b、日期里的裸斜杠
都保留。命令行、空白表单和浏览器共用 schema.py 发布的同一规则,包括 Unicode
空白。单个条目不要包含带空白的分隔斜杠;它本来就表示两个条目。
多行正文、制表符、引号和反斜杠在保存时按 TOML 规则转义,读取后保留原值。
空没填完会怎样:渲染时被拦下来,逐条告诉你哪个表的哪个字段还空着—— 不会渲染出一份带着空标题的 PDF,那种"看上去成功了"的 PDF 最容易被直接发出去。
python fill.py --check # 只检查,不渲染正常不用手工做这一节——make boot 会自动装齐。这里写给想手动装、或排查
"我的环境为什么渲染不出来"的人。
WeasyPrint 不是纯 Python,它要 dlopen 系统的 pango / cairo / harfbuzz /
fontconfig。中文字体推荐 Noto Sans CJK SC + Noto Serif CJK SC——字体会被嵌进
PDF,所以对方电脑上没装也能看到一样的排版。
sudo apt update
sudo apt install -y python3-venv python3-pip \
libpango-1.0-0 libpangoft2-1.0-0 libharfbuzz0b libfontconfig1 libcairo2 \
fonts-noto-cjk fonts-noto-cjk-extra fonts-noto-core \
poppler-utilspoppler-utils 提供 pdftoppm,只用来出 PNG 预览;不装的话 PDF 照常生成,
程序会打印一行"跳过"。
brew install pango cairo harfbuzz poppler
brew install --cask font-noto-sans-cjk font-noto-serif-cjk只是打开、投递已有的 PDF:什么都不用装,字体已嵌入。
要在原生 Windows 上重新生成,有两个坎:一是那几个 DLL 不随 pip 包附带,得另装 GTK3 runtime 并加进 PATH;二是没有 Noto 系列时衬线会回落到 SimSun,而 SimSun 没有 真 Bold,姓名和栏目名会变成伪粗体,与验证过的版本不一致。
所以在 Windows 上推荐走 WSL2(见下一节),而不是折腾原生环境。
程序在生成前会检查字体:Linux / macOS 走 fc-list,原生 Windows 读注册表。
中文字体完全缺失时报警告,回落到非首选字体时给提示——不会静默生成一份方块 PDF。
从零开始的完整步骤。假设新机器上 WSL2 和 Ubuntu 已经装好了。
cd ~ # 就是 /home/<你>,不要用 /mnt/c/...
pwd # 应该显示 /home/<你>
⚠️ 不要把仓库放在/mnt/c/下面。 跨文件系统的 I/O 慢一个数量级, WeasyPrint 读字体和写 PDF 都会明显卡;文件权限也会一团糟。
git clone https://github.com/<你的账号>/onepage-resume.git ~/onepage-resume
cd ~/onepage-resume
make boot # 系统库 + 字体 + venv + 依赖 + 渲染示例,一步到位make boot 里的 scripts/bootstrap.sh 就是下面这些命令的自动版(缺才装,已装跳过)。
想手动装 / 排查时才需要看它们:
sudo apt update
sudo apt install -y git python3-venv python3-pip \
libpango-1.0-0 libpangoft2-1.0-0 libharfbuzz0b libfontconfig1 libcairo2 \
fonts-noto-cjk fonts-noto-cjk-extra fonts-noto-core \
poppler-utils
fc-cache -fv # 刷新字体缓存
fc-list | grep -i "Noto Sans CJK" # 有输出才算装上了boot 最后那步 make example 是关键。 环境问题(缺 DLL、缺字体)会在渲染示例时
暴露,这时候还没有牵涉你的真实数据,排查干净。
这一份不在公开仓库里,得手动搬。三条路,按推荐程度:
- 放进你的私有仓库(推荐):真实内容常年住在一个 private repo 里,
新机器上
git clone那个私有仓库,然后用--content指过去。 换机器、回滚、多版本都有 Git 兜底。 - 加密后随便传:
age或gpg -c加密成一个文件,走网盘 / 邮件都行, 在新机器上解密。 - 手动重填:
make fill照着旧的抄一遍。最笨但零传输风险。
❌ 不要把真实内容 push 进这个公开仓库来"同步",哪怕只是一次、哪怕马上删掉—— Git 历史留着,GitHub 的缓存和各种镜像爬虫也留着。
内容文件放在仓库里(叫 content.toml):
cd ~/onepage-resume
make render
# 或: .venv/bin/python render.py内容文件放在仓库外:
cd ~/onepage-resume
.venv/bin/python render.py \
--content ~/private-resume/content.toml \
--out-dir ~/private-resume/build第一行会打印这次用的是哪个内容文件。看到"虚构示例"字样,说明你的文件没被找到—— 检查文件名拼写。
explorer.exe build # 在 Windows 资源管理器里打开生成目录
# 或者直接拷到 Windows 桌面
cp build/resume.pdf /mnt/c/Users/<你的Windows用户名>/Desktop/投递前肉眼过一遍 build/resume.png,再发 build/resume.pdf。
make check # 或 ./scripts/check-privacy.sh
git status # 不该出现 content.toml / build/ 里的任何东西schema.py—— 字段表:这份简历一共有哪些"空",只在这里定义一次。fill.py照着它提问,fill.py --blank照着它生成空白表单,render.py照着它 检查空白,webui.py照着它长出网页表单。加一个字段只改这一处,四边自动跟上—— 分开写迟早会出现"问卷问了但渲染不认"的字段。 数组块上还有个identity,写明"哪个字段能认出这一条",定制版的[keep]用它。fill.py—— 命令行填空程序。交互提问、生成空白表单、检查空白,最后写出内容 TOML。content_io.py—— 共享读写层:继承、路径约束、版本冲突检查、备份和原子保存。 不依赖 WeasyPrint,所以fill.py --check不需要先装排版引擎。webui.py—— 浏览器版的填空。默认只听本机,没有登录也没有口令。静态文件在webui/。 日常维护内容时不要编辑这个文件。content.example.toml—— 虚构示例,仓库里跟踪的就是它。改版面结构(新增技能行、 调整经历顺序)时才动它,改完把同样的改动同步到你自己的内容文件,并跑一次make preview刷新预览图,否则make check会拦下来。content.toml/content.local.toml/content.*.toml—— 你要投出去的那一份。 全部被 gitignore。查找优先级:content.local.toml→content.toml→content.example.toml。按公司做的定制版用extends继承其中一份,只写要改的 几项,见上面「按岗位做多个定制版」。theme.toml—— 设计令牌:字体、颜色、页边距、字号、间距、线宽。每一项都会变成 一个 CSS 变量。theme.en.toml—— 英文版式。用extends = "theme.toml"继承上面那份,只写不同的 几项(竖脊更宽——英文栏目名塞不进两个中文字的宽度;行距更紧——纯西文不需要中文 那么松的行距)。写英文简历时--theme theme.en.toml。resume.css—— 版式规则。文件开头写了五条设计约束,改版式前先读。render.py—— 渲染程序。正常维护内容时不要编辑。scripts/bootstrap.sh—— 开箱即用的一半:自动探测 apt / brew,把系统库和 CJK 字体 装齐(缺才装)。被make boot调用,也能单独跑。start.cmd—— 原生 Windows 的双击入口:检测到 WSL2 后,自动进默认发行版跑make boot,起网页版,等端口通了再由 Windows 这边开浏览器。端口只在文件顶部的WEBUI_PORT里定义一次,改它要和webui.py的DEFAULT_PORT同步。 纯 ASCII + CRLF,提示是英文的——cmd.exe 按控制台代码页解析 .cmd,中文字节会被 错读成命令(见下面「排障」)。中文说明就在你正读的这份 README 里。跟踪。.gitattributes—— 钉住行尾:.cmd检出成 CRLF,其余一律 LF。跟踪。webui/—— 网页表单的静态文件(index.html/app.css/app.js)。 表单本身不写在这里:它由app.js照着schema.py的字段表长出来。tests/—— Pythonunittest与 Node.js 内置测试器的回归测试,make test跑。 测试需要 Node.js 22+(CI 使用 24),日常填写和渲染不需要 Node.js,也不需要 npm 包。 覆盖字段往返、保存冲突、继承/路径安全、真实 HTTP、单页渲染和浏览器异步状态。examples/preview.png—— README 顶部那张图,由make preview生成。跟踪。examples/preview.sha256—— 上面那张图对应的输入哈希,make check用它判断图是否 过期。跟踪,由make preview写入,不要手改。build/—— 生成物。不跟踪。
python fill.py [--out PATH] [--blank] [--sample] [--check]
--out写到哪,默认content.toml。配合--blank写成-就打到标准输出。 真实内容建议写到仓库外:python fill.py --out ~/.private/resume/me.toml。--blank不提问,直接生成一份空白表单。--sample配合--blank:把示例答案填进去,用来先看版面。投递前必须自己重填。--check只检查--out指的那个文件还有哪些空没填。
python render.py [--content PATH] [--theme PATH] [--css PATH]
[--out-dir DIR] [--name BASENAME]
--content内容 TOML 路径。省略时按上面的优先级在脚本目录里找。 指到定制版(写了extends的那种)时会先把继承链合并好再渲。--theme/--css换一套设计令牌或版式。英文简历用--theme theme.en.toml; 自己做定制版时新建一份,开头写extends = "theme.toml",只列要改的令牌。--out-dir生成物目录,默认build/。--name生成物文件名主干;不给就读[document]的output_basename, 再不给就是resume。想投出去的附件叫张三-SEO-简历.pdf,在内容文件里写output_basename = "张三-SEO-简历"即可。 命令行与浏览器都拒绝路径分隔符、控制字符、Windows 保留名称和过长文件名, 不会静默清洗成另一个名字。HTML / PDF / PNG 先在临时目录生成,超页或 PNG 转换 失败时不替换已有生成物。缺pdftoppm时只更新 HTML / PDF,已有 PNG 不会被更新, 不要把旧图当成本次结果。
python webui.py [--host ADDR] [--port N] [--content-dir DIR]
[--out-dir DIR] [--css PATH] [--no-open]
--host绑定地址,默认127.0.0.1。这个服务没有认证,改成0.0.0.0等于把真实简历敞开给整个局域网;真要这么做,外面得自己套一层认证。--port端口,默认8765。--content-dir内容文件所在目录,默认本仓库目录。真实内容建议放仓库外。--out-dir/--css同render.py。
投五家公司,五份简历只差求职意向、概况和技能顺序。整份抄五遍的代价是:以后换个 手机号要记得改五处,而人是会忘的。
所以内容文件可以像 theme.en.toml 继承 theme.toml 那样,只写要改的地方:
# content.acme.toml
extends = "content.toml"
[document]
output_basename = "张三-Acme-简历"
[profile]
intent = "独立站运营 · Google SEO" # 只换这一句,姓名和联系方式继承
[summary]
text = "……按这家公司的 JD 重写一遍……"
# 从基底的技能里挑几条,顺序也按这里给的来
[keep]
skills = ["Technical SEO", "数据分析", "英文内容"]python render.py --content content.acme.toml合并规则三条:
-
普通表深合并——你写了的键覆盖基底,没写的继承。改一句就只写一句。
-
数组表整块替换——写了
[[skills]]就用你写的那几条;没写就全继承。 没有"改第 2 条"这种半自动写法:基底加一条之后下标就全错位了。 -
[keep]按天然键挑选并排序——只是想"从 6 条里留 4 条、换个顺序"时用它, 比整块重写省事。每个数组块用哪个字段作键:数组块 认哪个字段 skillslabelexperiencescompanyprojectstitlecontactsvalue名字拼错会当场报错,并把可选值列给你。它不会静默丢掉一整条经历—— 那种错在 PDF 上看不出来,投出去才发现少了一段。
继承可以多层(基底 → 行业版 → 公司版),成环会报错。
fill.py 和网页版都是"整份重写",会把 extends 和
[keep] 一起抹掉,让定制版退化成一份和基底一模一样的全量拷贝——而且不报错,
下次改基底时才发现这一份没跟着变。所以两边都会拦下来:
python fill.py --out content.acme.toml # 报错,让你直接编辑
python fill.py --check --out content.acme.toml # 这个可以:检查合并后还缺什么基底的天然键重复、[keep] 重复选择、继承成环或超出 32 层,都会明确报错。
网页版的继承链只能引用同一内容目录里的 content*.toml,CLI 可以引用目录外的基底。
网页版可以读定制版(显示合并后的样子、照常预览和出 PDF),但状态栏会标明它是 定制版、只读;点保存会被拒。
- 删掉不适用于目标岗位的技能或项目。不要靠缩小字号硬塞。
- 把
[document]的preview_note和edition清空,页脚那行整条消失。 带着"示例内容"字样投出去,等于告诉对方这是没填完的模板。 (网页版写出去的这两行本来就是空的。) - 重新生成,确认第一行打印的是你自己的内容文件。 网页版看状态栏右边那个文件名,别对着示例改了半天。
- 打开
build/*.png复核,再发build/*.pdf。 git status应该是干净的。用过网页版的话,顺手看一眼有没有留下content.<随手起的名字>.toml——它们都被 gitignore 挡着,但堆多了自己会认错。
- 嫌挤先加间距,不要缩字号。
theme.toml里section-gap/entry-gap/bullet-gap/skill-row-gap四个值专门管块与块之间的停顿。版面显得密,通常是因为 没有停顿,不是因为字太大——缩字号只会让它既密又难读。加到装不下时程序会报错, 那时该砍的是内容里的字。 - 一句话别拖到换行后只剩两三个字。 这种"孤儿行"是全页最伤阅读的东西。改完看一眼 PNG,发现了就把句子删掉几个字,通常砍掉句尾的评论性收尾就够了。
- 不可断空格:示例里
Looker Studio、Top 10、Cloudflare Pages中间是 U+00A0 不换行空格,用来防止词组被拆到两行。新增同类词组时照着写, 在 TOML 里也可以写成转义\u00A0。 - 字重只有两档:Noto CJK 只有 Regular 和 Bold。
resume.css里不要写font-weight: 500,会被静默降级成 Regular,标签和正文就分不出来了—— HR 黑白打印时尤其明显。
| 症状 | 原因 | 处理 |
|---|---|---|
| PDF 里中文是方块 | 没装 CJK 字体 | sudo apt install fonts-noto-cjk && fc-cache -fv |
cannot load library 'libgobject-2.0-0' |
缺 pango / glib 系统库 | 按"环境准备"装齐 apt 包 |
渲染出了 2 页 |
内容超了 | 砍内容,别缩字号 |
| 打印"虚构示例" | 没找到你的内容文件 | 检查文件名,或用 --content 指定 |
| 没有 PNG | 缺 pdftoppm |
sudo apt install poppler-utils |
| 字重不对 / 伪粗体 | 回落到了 SimSun | 装 Noto Serif CJK SC,或直接用 WSL2 |
网页版 Host 头不被接受 |
用了 127.0.0.1 之外的域名进来(防 DNS 重绑定) | 用 http://127.0.0.1:<端口> 打开 |
| 网页版存不了 | 文件名不是 content*.toml、是那份示例、或是定制版 |
换成 content.toml / content.<公司>.toml;定制版请手工编辑 |
[keep] … 里写了 X,但被继承的那份里没有这一条 |
基底改了名字,定制版没跟上 | 按报错里列出的可选值改;这正是它该拦住的事 |
是定制版(extends = …) |
想用 fill.py 或网页版改定制版 |
直接编辑那十几行;查空白用 fill.py --check |
| WSL2 里开了服务,Windows 打不开 | localhostForwarding 被关了(默认是开的) |
在 %UserProfile%\.wslconfig 里写 [wsl2] + localhostForwarding=true,再 wsl --shutdown 重开 |
WSL 里 make ui 没弹出浏览器 |
发行版里没有 Linux 浏览器,也没装 wslu |
它会退到 powershell.exe 去开 Windows 默认浏览器;两条都不成时按提示手工打开那个网址 |
双击 start.cmd 满屏 'xxx' 不是内部或外部命令 |
文件被改成了 UTF-8 中文或 LF 行尾。cmd.exe 按 CP936 解析,GBK 前导字节会吃掉换行,下一行被当命令跑;LF 还会让 goto 找不到标签 |
保持纯 ASCII + CRLF——.gitattributes 和 make test 都会管住。别在里面写中文,写在 README 里 |
start.cmd 说 No Makefile next to this script |
双击的是一份被拷到别处(桌面 / 下载)的 start.cmd。它只能在仓库根目录、和 Makefile 并排时用 |
回仓库根目录双击;或直接在 WSL 里 make boot && make ui |
WSL_E_DISTRO_NOT_FOUND |
发行版名被带引号传给了 wsl -d,引号会算进名字里 |
-d 后面不要加引号(start.cmd 里已按这个写) |
wsl: Failed to translate 'Z:\...' |
从映射成网络驱动器的 WSL 目录双击。wsl 认不了盘符 |
start.cmd 现在会用 net use 把盘符还原成 UNC 再拆——升级到最新一版即可 |
MIT,见 LICENSE。示例内容里的人名、公司、数字均为虚构; 顶部两条链接指向模板作者 eigentime.org。 拿去改成你自己的,不用署名,留着也不介意。