34 种语言、49 个 PO 文件:Penpot 多语言本地化工作流完整实战

发布时间:2026/11/1 10:58:52

34 种语言、49 个 PO 文件:Penpot 多语言本地化工作流完整实战 34 种语言、49 个 PO 文件Penpot 多语言本地化工作流完整实战【免费下载链接】penpotPenpot: The open-source design platform for Product teams that need scalable collaboration.项目地址: https://gitcode.com/GitHub_Trending/pe/penpot设计团队打开 Penpot 想以中文评审界面整站却是英文有人补了一条翻译界面上又冒出auth.check-mail这种带点号的文本——这大概率不是 bug而是翻译缺失的显式信号。Penpot 作为开源设计与原型平台其多语言能力由三层构成frontend/src/app/util/i18n.cljs里的翻译引擎、frontend/translations/下的 49 个 PO 文件、以及 Weblate 平台上的社区协作流程。本文按实际操作路径走一遍先把界面切到目标语言再读懂 PO 文件结构然后本地验证改动最后把翻译推回主线。如何把 Penpot 本地界面切到 34 种语言之一先拉取代码并启动开发环境git clone https://gitcode.com/GitHub_Trending/pe/penpot cd penpot ./manage.sh run-devenv界面显示哪种语言由i18n.cljs里的supported-locales表决定共 34 个条目覆盖zh_cn、zh_hant、ar、ja_jp、fr_ca等。语言确定分两条路启动时autodetect读取navigator.language经parse-locale归一化zh-CN变成zh_cn带国家码不支持时回退到纯语言码zh也可以在设置里显式调用set-locale。两种路径都会校验白名单查不到就落到cf/default-language值为en。locale 定下来后load函数动态导入翻译表并挂到全局变量(let [path (str ./translation. locale .js?version cf/version-tag)] (- (mod/import path) (p/fmap (fn [result] (unchecked-get result default))) (p/fnly (fn [data cause] (if cause (js/console.error unexpected error on fetching locale cause) (set-translations locale data))))))而所有 UI 文案统一走tr查表(defn tr ([code] (t *current-locale* code)) ([code args] (apply t *current-locale* code args)))用一句人话概括组件里不硬编码任何字符串文案全部由tr按当前 locale 查表返回。切语言本质上是换一张表所以前端不存在改代码换语言这一步。切完语言后你会发现一部分文案还是英文——这就是缺失回退到en的结果。要补上它得先读懂 PO 文件。如何读懂 frontend/translations 的 49 个 PO 翻译文件frontend/translations/下有 49 个.po文件按 ISO 语言码命名zh_CN.po、ar.po、fr_CA.po等比运行时支持的 34 个多出的部分是尚未接入切换器的储备语言。每条翻译的长这样取自zh_CN.po的真实条目#: src/app/main/ui/auth/register.cljs:214 msgid auth.already-have-account msgstr 已经有账号了三个信息点都有用msgid是键名msgstr是译文#:开头的注释指向该键在源码中的引用位置文件加行号排查上下文不用全局搜索。此外还有两个标志位unused表示这个键已不再被任何源码引用fuzzy表示译文待复核。文件头部的Plural-Forms: nplurals2; plural(n ! 1)声明复数规则中文和英文一样按等于 1 / 不等于 1分两支。复数在代码侧的写法见frontend/src/app/main/ui/dashboard/fonts.cljs[:span (tr dashboard.fonts.fonts-added (i18n/c (count fonts)))](i18n/c ...)把参数标记为计数值t函数检测到翻译值是指数组时按计数等于 1 还是其他取msgstr[0]或msgstr[1]。这就是为什么.po里同一个键会同时出现msgid和msgid_plural两条。回退链路值得记清楚目标语言查不到该键回落到enen也查不到t直接返回键名本身。界面上看到带点号的文本就按这条链路反查是哪个环节漏了。PO 文件改好了下一步是本地验证和批量维护。如何本地验证翻译改动watch 热更新与 rehash、sync 命令开发服务自带热更新。frontend/scripts/watch.js第 95 行起注册了对 translations 目录的监听log.info(watch: translations (~)); h.watch(translations, null, async function (path) { ... })也就是说改完.po文件保存即可前端会自动重新编译加载不用手动重启。批量维护用frontend/目录下的pnpm translations 子命令脚本是frontend/scripts/translations.js提供四个子命令以脚本自带的 help 输出为准rehash用正则\(tr\s([\w\.\-])扫描src/下所有.clj/.cljs/.cljc文件把源码里出现但en.po里没有的键补录进去标fuzzy并写入引用位置同时把源码中已不引用的键标成unused结束时打印Found N used translations和Found N unused strings两个数字sync以en为基准对齐其他语言文件的键集合基准里不存在的键直接从各语言文件中删除fuzzy prefix把某前缀下的所有条目批量标记为 fuzzy适合英文原文批量改动后要求各语言重新确认delete prefix按前缀删除条目。日常节奏是新增文案后先跑rehash补键各语言翻译完成后再跑sync清掉孤儿键。本地验证通过后改动要进入主线还得走审核流程。如何把翻译推回主线Weblate 协作与 waiting for review 状态机Penpot 的官方翻译平台是 Weblate流程定义在docs/contributing-guide/translations/index.njk。入场的门槛是注册 Weblate 账号然后在仓库提交 issue写清三样东西——要翻译的语言、翻译类型新语言 / 补字符串 / 改已有译文、你的 Weblate 用户名由团队授予对应权限。上图为 Weblate 的语言列表页每行显示一种语言的进度铅笔图标用于进入该语言的字符串编辑。三类操作的状态流转不同新增语言在语言列表页点 Start new translation选择语言后开始逐条翻译补充缺失字符串点语言行的编辑图标找到未翻译条目填入译文并保存状态自动变为 waiting for review修改已批准的译文进入该语言点 Browse有权限直接 Save同样进入待审核没有权限则点 Suggest条目状态标记为 Approved strings with suggestions。上图是单个语言的字符串列表未翻译条目一目了然补漏时按这个清单逐条处理即可。团队会定期检查待审核字符串确认无误后批准批准的结果随下个版本发布。界面文案这条链路到此闭环但多语言产品还有另一半设计稿本身要能承载不同语言的排版。设计稿区域化组件覆盖与灵活布局的多语言适配i18n 体系只覆盖产品界面文案用户设计稿里的多语言适配要靠设计手段。官方文档docs/user-guide/designing/text-typo.njk覆盖了 RTL从右到左文本的排版规则阿拉伯语、希伯来语这类市场在设计阶段就要按 RTL 习惯安排对齐与留白。组件层的做法是把语言作为变体维度一个按钮组件拆出中文-主要英文-次要等变体实际使用时通过组件覆盖component override替换为对应语言的文本节点而不是复制整份组件。上图展示了在组件实例上覆盖属性的操作语言变体切换走的正是这条机制。文本长度差异用灵活布局吸收容器不写死宽度依赖 flex 的换行与伸缩规则docs 中的 flexlayout 系列演示德语比英语长 30% 左右、东亚文字密度更高时布局自动重排而不会撑破容器。关键文案建议再收敛到设计标记Design Tokens统一管理docs/user-guide/design-tokens/有完整说明。设计和翻译两边都就绪后交付前过一遍下面的清单。交付前检查清单在i18n.cljs的supported-locales中确认目标语言已注册否则界面切换器不会出现该语言逐个切换目标语言扫描界面有无带点号的键名文本有则说明该键缺失或回退到en打开目标语言的.po文件头核对Plural-Forms与该语言的复数规则一致并抽查一条msgid_plural的两支译文在frontend/下执行pnpm translations rehash确认输出中没有新增fuzzy条目、没有遗留该清理的unused键需要多语言键集合对齐时补跑pnpm translations sync确认没有其他语言文件残留孤儿键Weblate 上的目标条目状态为已批准approved而非停留在 waiting for review设计稿侧组件覆盖的语言变体文本已更新承载多语言文本的容器使用灵活布局而非固定宽度。七项全绿这套从tr查表到 PO 文件、再到社区审核的 Penpot 多语言链路就算完整跑通了。【免费下载链接】penpotPenpot: The open-source design platform for Product teams that need scalable collaboration.项目地址: https://gitcode.com/GitHub_Trending/pe/penpot创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/10/31 15:39:33

英伟达拟收购Hugging Face:AI模型分发与开发者生态将如何演变?

最近在技术社区里,“Hugging Face 还能不能愉快地下载模型”成了不少 AI 开发者关心的话题。无论你是用 Transformers 调大模型,还是把开源模型下载到本地做微调,Hugging Face 基本都会出现在工作流里。而就在这个时候,一条消息引…

2026/11/1 2:01:37

1.c++入门篇

1.c中的关键字asmdoifreturntrycontinueautodoubleinlineshorttypedefforbooldynamic_castintsignedtypeidpublicbreakelselongsizeoftypenamethrowcaseenummutablestaticunionwchar_tcatchexplicitnamespacestatic_castunsigneddefaultcharexportnewstructusingfriendclassext…

2026/11/1 2:01:37

《江灯合声》:有可行的分框版,也仍可以选择连续鸣谢

武汉江岸区栎坡合唱团在免费节目册《江灯合声》中,以表格集中鸣谢资助者。各家共同要求改为独立小框,团里仍想保留表格。现有全名与支持事项清楚可见,双方此前未承诺具体排版。我支持保留表格。补充的试排材料让选择更具体:分框能…

2026/11/1 2:01:37

关于“贾子猜想”的数学地位、结构特征与讨论边界

关于“贾子猜想”的数学地位、结构特征与讨论边界摘要 本文对“贾子猜想”进行基于公开表述与现有数学事实的分析。该猜想主张:当正整数 n3m>5(即 n6,9,12,15,…)时,方程x₁ⁿ x₂ⁿ ⋯ xₙⁿ yⁿ不存在正整数解。文章首先…

2026/11/1 2:01:37

启动报Port 8088 was already in use?先查是谁占的

启动报Port 8088 was already in use?先查是谁占的 项目启动报 Port 8088 was already in use,意思很直白:这个端口已经有人占了。 先说原理:端口是"门牌号",一间房只住一个进程 端口就是一台机器上的门牌号…

2026/11/1 2:01:37

担心文档上云?本地运行的办公AI才敢放心用

单位上周开了个会,主题是"AI 提效",散会时领导补了一句:涉及客户资料的文档,不许往云端传。这话一出,会议室里本来跃跃欲试的同事全蔫了——大家平时用的那些在线 AI,文档一上传就不知道存哪儿去…

2026/11/1 1:56:37

华为OD机试真题 新系统 2026-10-28 JavaGoC【社交网络消息转发】

目录 题目 思路 Code 题目 题目内容: 在一个社交网络中,有 N 个用户(编号 0 到 N−1);每个用户都有一个「转发名单」(整数),该数二进制格式中的第 i 位为 1 表示此用户会把消息转发给第 i 个用户。 给定一个整数数组 forwardLists 和一个整数 initialSenders,请…

2026/11/1 0:01:26

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/1 1:01:33

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/1 0:01:26

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/1 1:01:33

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/1 0:01:26

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/1 1:01:33

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑