news 2026/9/18 10:50:50

Bambu Studio 本地化与翻译指南:从 GNU gettext 工作流到源码级实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Bambu Studio 本地化与翻译指南:从 GNU gettext 工作流到源码级实践

Bambu Studio 本地化与翻译指南:从 GNU gettext 工作流到源码级实践

【免费下载链接】BambuStudioPC Software for BambuLab and other 3D printers项目地址: https://gitcode.com/GitHub_Trending/ba/BambuStudio

Bambu Studio 是 Bambu Lab 及其他 3D 打印机配套的开源 PC 切片软件。本文以仓库内 doc/Localization_guide.md 为核心,系统讲解它的本地化(i18n)机制:如何修改现有翻译、如何新增语言、如何在实现新功能时接入翻译资源,以及如何使用 GNU gettext 工具链为自有应用搭建翻译流水线。读完本文,你将掌握 POT/PO/MO 文件的完整生产链路、PoEdit 的实际操作步骤,以及从L()/_()/_CHB()宏到 wxWidgets 运行时加载.mo文件的底层调用关系。

一、本地化技术栈总览:GNU gettext + PoEdit + wxWidgets

Bambu Studio 的本地化采用经典的三层文件模型:

  • POT(Portable Object Template):由源码提取出的"待翻译字符串模板",不含任何译文,是翻译的起点;
  • PO(Portable Object):在 POT 基础上填充目标语言译文后的可编辑文件;
  • MO(Machine Object):PO 经编译生成的二进制文件,是程序运行时真正加载的产物。

工具链由两部分组成:

工具作用说明
GNU gettext从源码提取字符串、创建翻译目录(Catalog)、合并与编译 PO/MO提供xgettextmsgmergemsgcatmsgen等命令
PoEdit面向翻译人员的图形化编辑器帮助消除标点错误,标出 fuzzy(模糊)翻译

按原指南的建议,安装 GNU gettext 后应将gettext/bin加入PATH环境变量,以便在命令行中直接调用xgettext等工具。完整手册可查阅 GNU gettext 官方 Manual(http://www.gnu.org/software/gettext/manual/gettext.html,本仓库不做转发)。

本仓库的 i18n 目录位于 bbl/i18n,其中:

  • BambuStudio.pot—— 最新提取的翻译模板;
  • 每个语言子目录(csdeenesfrhuitjakonlplpt_BRrusvtrukzh_CNzh_TW)各含一个BambuStudio_xx.po
  • bbl/i18n/list.txt —— 含L()宏的源文件清单,供xgettext批量提取使用。

注意:当前仓库中文目录 bbl/i18n/zh_CN/BambuStudio_zh_CN.po 与英文目录 bbl/i18n/en/BambuStudio_en.po 各自包含数万条msgid/msgstr条目(英文文件头部可见Project-Id-Version: Bambu StudioContent-Type: text/plain; charset=UTF-8等元信息),规模足以支撑完整的软件界面翻译。

二、场景一:修改或修正现有翻译

适用场景:某条现有译文不准确、术语不统一或长度不合适。步骤如下:

  1. 从 bbl/i18n 对应的语言子目录获取 PO 文件(例如中文为BambuStudio_zh_CN.po);
  2. 在 PoEdit 中以"Edit a translation"(编辑翻译)方式打开该文件;
  3. 修改对应msgstr的译文;
  4. 将修改后的BambuStudio_xx.po推送回原目录;
  5. 编译生成BambuStudio_xx.mo,将其复制到resources/i18n/xx/并重命名为BambuStudio.mo,然后推送该文件。

PO 文件内部结构(摘自仓库英文文件)形如:

msgid "Main extruder" msgstr ""

msgid是源码中的原始字符串,msgstr是译文;中文文件则对应为msgid "右侧热端"msgstr形式的成对条目。翻译者只需维护msgstr一侧。

三、场景二:新增一种语言支持

适用场景:仓库尚不支持你想贡献的语言。步骤如下:

  1. 获取 bbl/i18n/BambuStudio.pot 模板;
  2. 在 PoEdit 中选择"Create new translation"(新建翻译)打开该 POT;
  3. 选择目标翻译语言(例如法语);
  4. 得到fr.po文件并完成全部翻译后,按以下约定交付:
    • 将文件重命名为BambuStudio_fr.po
    • 点击"Save file",PoEdit 会同时生成BambuStudio_fr.mo
    • BambuStudio_fr.po放入 bbl/i18n/fr 子目录并推送(目录名fr即语言代码);
    • BambuStudio_fr.mo复制到resources/i18n/fr/并重命名为BambuStudio.mo,推送该文件。

语言目录命名遵循 ISO 语言代码惯例:fr表示法语,de表示德语,zh_CN表示简体中文,zh_TW表示繁体中文,pt_BR表示巴西葡萄牙语等,仓库现有目录与此一一对应。

四、场景三:在实现新功能时接入翻译资源

4.1 用L()宏标记可翻译字符串

仓库中所有可翻译字符串都必须显式使用L()宏标记。原指南给出的最小示例:

auto msg = L("This message to be localized");

L()宏仅用于标记字符串以被xgettext提取,它本身返回原字符串(不执行翻译)。真正取用译文时,使用_(s)_CHB(s)等宏。两个宏的定义位于 src/slic3r/GUI/I18N.hpp:

#define _(s) Slic3r::GUI::I18N::translate((s)) #define _CHB(s) wxGetTranslation(wxString(s, wxConvUTF8)).utf8_str()
  • _()返回wxString,是标准 wxWidgets 翻译入口;
  • _CHB()显式指定源字符串为 UTF-8 编码,返回wxScopedCharBuffer(UTF-8 字节串),适合需要std::string/C 字符串的场景。

原指南特别强调(源码注释也印证):_()是标准 wxWidgets 翻译宏;L()只用于标记本地化字符串,供xgettext生成消息目录。若在 libslic3r(非 GUI 模块)中错误地 include GUI 的 I18N 头,会触发编译期报错——src/libslic3r/I18N.hpp 中通过#ifdef SLIC3R_CURRENTLY_COMPILING_GUI_MODULE#error守卫,确保两个模块的翻译体系严格隔离。

4.2 上下文与复数形式

对于需要区分上下文的字符串,GUI 头文件还提供带上下文的翻译族:

#define _CTX(s, ctx) Slic3r::GUI::I18N::translate((s), (ctx)) #define _CTX_utf8(s, ctx) Slic3r::GUI::I18N::translate_utf8((s), (ctx))

其中ctx参数在 wxWidgets ≥ 3.1.1 时传给wxGetTranslation的上下文参数,旧版本则忽略。复数形式则由_L_PLURAL(s, plural, n)宏承担,内部调用I18N::translate(s, plural, n)的复数重载。这意味着 PO 头部需要声明正确的Plural-Forms规则,例如英文文件中的nplurals=2; plural=(n==1) ? 0 : 1;

4.3 新增含L()的文件必须登记

如果你新增了含L()宏的源文件,必须把它追加到 bbl/i18n/list.txt 的文件清单中,否则xgettext不会从该文件提取字符串。从清单内容看,它覆盖了 GUI 与核心库两条路径,例如:

  • GUI 层:src/slic3r/GUI/DeviceTab/...src/slic3r/GUI/Gizmos/GLGizmo*.cppsrc/slic3r/GUI/Widgets/AMSControl.cpp等;
  • 核心层:src/libslic3r/PrintConfig.cppsrc/libslic3r/PlaceholderParser.cppsrc/libslic3r/Support/TreeSupport.cpp等。

五、场景四:用 GNU gettext 为自有应用搭建翻译流程

原指南以 Bambu Studio 为范本,给出了完整的命令行工作流,以下命令均可直接复制执行。

5.1 维护源文件清单

为方便起见,先建立包含L(s)宏的文件列表(即仓库中的 bbl/i18n/list.txt),每行一个源文件路径。

5.2 生成 POT 模板

xgettext --keyword=L --add-comments=TRN --from-code=UTF-8 --debug -o BambuStudio.pot -f list.txt

参数说明:

参数作用
--keyword=L声明L为待提取字符串的关键字,凡L("...")形式均被提取
--add-comments=TRN将源码中以TRN开头的注释带入 POT,作为翻译提示
--from-code=UTF-8声明源字符串为 UTF-8 编码
--debug正确提取带%d%s等格式化占位符的字符串
-o BambuStudio.pot指定输出模板文件名
-f list.txt指定待扫描的源文件清单

5.3 生成 PO 与 MO

在获得 POT 后,用 PoEdit 打开并创建/编辑翻译,即可得到 PO 及编译后的 MO(详见场景一、二);也可以用命令msgfmt将 PO 编译为 MO(PoEdit 的 "Save file" 也会自动完成)。

5.4 合并旧 PO 与新 POT

当源码新增字符串、旧 PO 需要与新 POT 合并时:

msgmerge -N -o new.po old.po new.pot

-N--no-fuzzy)表示:找不到精确匹配时不使用模糊匹配。如果省略-Nmsgmerge会把近似匹配标记为 fuzzy(#, fuzzy),PoEdit 会以黄色高亮显示这些条目,提醒翻译者复核。

5.5 拼接多个 PO

msgcat -o new.po old.po

用于把旧 PO 中的翻译条目与新的 PO 合并拼接,适合多分支翻译成果的汇总。

5.6 生成英文目录

msgen -o new.po old.po

该命令基于已翻译的 PO 生成一份英文对照目录——其中msgidmsgstr内容完全相同,适合作为对照基线或占位目录。

完成目录后,在 PoEdit 中打开 POT 或 PO 文件即可开始翻译。

六、翻译者通用准则(来自原指南)

  1. 优先使用 PoEdit:它能消除大部分标点错误,并高亮 fuzzy(模糊)翻译项。
  2. 实测 UI 效果:保存文件后 MO 即生成,重命名为BambuStudio.mo后运行软件即可在真实界面上验证译文。
  3. 警惕编码问题:若界面出现乱码,很可能不是你的译文问题,而是软件自身的 bug,应上报。
  4. 注意 UI 元素的承载能力:尤其按钮,翻译时不要用括号罗列多种备选译法——那会显著加宽按钮,很多时候是难以接受的。原指南配图(images/long_text_on_button.png)示意了按钮上的过长文本问题;该图位于仓库之外,请以实际 UI 测试为准。
  5. 批量处理须人工校对:若使用自动更正或批处理工具,输出必须经过非常仔细的校对,否则极易引入破坏性修改。
  6. 格式占位符必须原样保留:不得改动%1%(不得改成%1 %)、%%(百分比符号,不得改成%)等,否则会导致应用崩溃。
  7. 注意空格、换行(\n)与标点:不要画蛇添足地增加换行,这对参数名尤其重要。
  8. 参数描述不要带计量单位:例如应写 "Enable fan if layer print time is less than 阈值",而不是 "……n seconds"。
  9. 单位使用国际单位制:用s而不是sec
  10. 标点与原文一致:短语结尾没有句点就不要加,有则保留。
  11. 保持术语一致:对filament等基础术语,全文应使用统一译法,避免混淆用户。

第 6、8、9 条直接关系到运行时安全与参数解析正确性:%系列占位符在应用内部会被格式化引擎替换,任何改动都可能造成崩溃或参数显示错误;而参数名中的多余换行也会破坏选项面板的渲染。

七、运行时加载链路:.mo文件如何被 Bambu Studio 消费

翻译文件最终由 wxWidgets 本地化设施在运行时加载。关键调用位于 src/slic3r/GUI/GUI_App.cpp:

wxFileTranslationsLoader::AddCatalogLookupPathPrefix(from_u8(localization_dir())); // ... m_wxLocale->AddCatalog(SLIC3R_APP_KEY);
  • AddCatalogLookupPathPrefixlocalization_dir()指向的目录(即resources/i18n/<语言代码>/)注册为.mo目录的查找路径;
  • AddCatalog(SLIC3R_APP_KEY)按应用键名(BambuStudio)加载对应语言的目录——这正是"将BambuStudio_xx.mo复制到resources/i18n/xx/并重命名为BambuStudio.mo"这一交付步骤的根本原因:文件名必须与目录名匹配,才能被AddCatalog命中。

语言选择方面,GUI_App.cpp通过wxLocale::FindLanguageInfowxLocale::IsAvailablewxLocale::GetLanguageInfo枚举并校验系统可用语言,构建语言选择列表;运行时再依据用户偏好与系统GetCanonicalName(例如zh_CN)选择目录。因此,新增语言的目录命名必须使用 PoEdit 生成的标准语言代码,才能被运行时正确识别。

八、完整贡献流程速查

把前述内容串成一条端到端流水线:

新增/修改源字符串(L() 标记 + 更新 list.txt) │ ▼ xgettext 生成 BambuStudio.pot │ ▼ msgmerge -N 合并旧 PO(可选) │ ▼ PoEdit 编辑/创建翻译 → 产出 BambuStudio_xx.po │ ▼ 保存生成 BambuStudio_xx.mo │ ├─→ 推送 PO 到 bbl/i18n/<xx>/ └─→ MO 复制为 resources/i18n/<xx>/BambuStudio.mo 并推送

两点补充:

  • 仓库根目录同时存在 BambuStudio.mo 文件,是当前版本编译好的程序内嵌目录,作为发布产物随仓库分发;
  • 本仓库的 i18n 同步还接入了 Localazy 平台(英文 PO 头部可见X-Generator: Localazy,根目录另有 localazy.json 配置文件),但这不影响上述基于 gettext/PoEdit 的手工贡献流程——两者最终都以.po文件形态汇入 bbl/i18n。

参考路径索引

  • 指南原文:doc/Localization_guide.md
  • 翻译模板与各语言目录:bbl/i18n/BambuStudio.pot、bbl/i18n/list.txt
  • 英文翻译样本:bbl/i18n/en/BambuStudio_en.po
  • 简体中文翻译样本:bbl/i18n/zh_CN/BambuStudio_zh_CN.po
  • GUI 层翻译宏定义:src/slic3r/GUI/I18N.hpp
  • 核心层(libslic3r)翻译接口:src/libslic3r/I18N.hpp
  • 运行时加载逻辑:src/slic3r/GUI/GUI_App.cpp(AddCatalogLookupPathPrefix/AddCatalog附近)
  • 本地化发布产物:BambuStudio.mo

【免费下载链接】BambuStudioPC Software for BambuLab and other 3D printers项目地址: https://gitcode.com/GitHub_Trending/ba/BambuStudio

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/18 10:50:24

Gartner数据治理成熟度模型:自评方法与跃迁路径

简介&#xff1a;加特纳企业信息管理成熟度模型&#xff08;中文版&#xff09;定义文档&#xff0c;面向IT管理者、企业架构师与数据治理人员&#xff0c;用于快速评估企业信息管理现状并规划升级路径。资源系统阐述从0级无认知型到5级高效型的完整六级框架&#xff0c;逐级说…

作者头像 李华
网站建设 2026/9/18 10:49:12

人大金仓KingbaseES V8R3 License更新实操指南:从备份到验证全流程

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

作者头像 李华
网站建设 2026/9/18 10:46:53

基于AT89C52与ADC0832的一氧化碳检测报警器设计

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

作者头像 李华
网站建设 2026/9/18 10:46:50

VSCode Remote-SSH + conda 实现 Linux 服务器远程 Python 调试全攻略

人在公司&#xff0c;突如其来的一次线上事故&#xff0c;逼着我第一次正儿八经地在Linux服务器上调试Python代码。手里的笔记本性能倒是不错&#xff0c;但目标服务只在内网的一台CentOS机器上&#xff0c;没显卡没桌面&#xff0c;只有一个SSH登录窗口。那会儿我还在用vim改代…

作者头像 李华
网站建设 2026/9/18 10:46:43

磁盘I/O为何成为性能瓶颈?物理结构、寻道时间与IOPS详解

你有没有遇到过这种情况&#xff1a;程序跑起来CPU使用率不高、内存也很充裕&#xff0c;但整个系统就像被什么东西卡住了一样&#xff0c;点一下窗口要等好几秒才反应。我这些年排查类似的性能问题&#xff0c;十次里有七次最后都指向同一个地方——磁盘I/O。磁盘I/O这个东西&…

作者头像 李华
网站建设 2026/9/18 10:46:16

CANN HIXL 仓库开发工作流指南:仓库导航、构建测试与提交规范全解析

CANN HIXL 仓库开发工作流指南&#xff1a;仓库导航、构建测试与提交规范全解析 【免费下载链接】hixl HIXL&#xff08;Huawei Xfer Library&#xff09;是一个灵活、高效的昇腾单边通信库&#xff0c;面向集群场景提供简单、可靠、高效的点对点数据传输能力。 项目地址: ht…

作者头像 李华