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 | 提供xgettext、msgmerge、msgcat、msgen等命令 |
| 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—— 最新提取的翻译模板;- 每个语言子目录(
cs、de、en、es、fr、hu、it、ja、ko、nl、pl、pt_BR、ru、sv、tr、uk、zh_CN、zh_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 Studio、Content-Type: text/plain; charset=UTF-8等元信息),规模足以支撑完整的软件界面翻译。
二、场景一:修改或修正现有翻译
适用场景:某条现有译文不准确、术语不统一或长度不合适。步骤如下:
- 从 bbl/i18n 对应的语言子目录获取 PO 文件(例如中文为
BambuStudio_zh_CN.po); - 在 PoEdit 中以"Edit a translation"(编辑翻译)方式打开该文件;
- 修改对应
msgstr的译文; - 将修改后的
BambuStudio_xx.po推送回原目录; - 编译生成
BambuStudio_xx.mo,将其复制到resources/i18n/xx/并重命名为BambuStudio.mo,然后推送该文件。
PO 文件内部结构(摘自仓库英文文件)形如:
msgid "Main extruder" msgstr ""msgid是源码中的原始字符串,msgstr是译文;中文文件则对应为msgid "右侧热端"与msgstr形式的成对条目。翻译者只需维护msgstr一侧。
三、场景二:新增一种语言支持
适用场景:仓库尚不支持你想贡献的语言。步骤如下:
- 获取 bbl/i18n/BambuStudio.pot 模板;
- 在 PoEdit 中选择"Create new translation"(新建翻译)打开该 POT;
- 选择目标翻译语言(例如法语);
- 得到
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*.cpp、src/slic3r/GUI/Widgets/AMSControl.cpp等; - 核心层:
src/libslic3r/PrintConfig.cpp、src/libslic3r/PlaceholderParser.cpp、src/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)表示:找不到精确匹配时不使用模糊匹配。如果省略-N,msgmerge会把近似匹配标记为 fuzzy(#, fuzzy),PoEdit 会以黄色高亮显示这些条目,提醒翻译者复核。
5.5 拼接多个 PO
msgcat -o new.po old.po用于把旧 PO 中的翻译条目与新的 PO 合并拼接,适合多分支翻译成果的汇总。
5.6 生成英文目录
msgen -o new.po old.po该命令基于已翻译的 PO 生成一份英文对照目录——其中msgid与msgstr内容完全相同,适合作为对照基线或占位目录。
完成目录后,在 PoEdit 中打开 POT 或 PO 文件即可开始翻译。
六、翻译者通用准则(来自原指南)
- 优先使用 PoEdit:它能消除大部分标点错误,并高亮 fuzzy(模糊)翻译项。
- 实测 UI 效果:保存文件后 MO 即生成,重命名为
BambuStudio.mo后运行软件即可在真实界面上验证译文。 - 警惕编码问题:若界面出现乱码,很可能不是你的译文问题,而是软件自身的 bug,应上报。
- 注意 UI 元素的承载能力:尤其按钮,翻译时不要用括号罗列多种备选译法——那会显著加宽按钮,很多时候是难以接受的。原指南配图(
images/long_text_on_button.png)示意了按钮上的过长文本问题;该图位于仓库之外,请以实际 UI 测试为准。 - 批量处理须人工校对:若使用自动更正或批处理工具,输出必须经过非常仔细的校对,否则极易引入破坏性修改。
- 格式占位符必须原样保留:不得改动
%1%(不得改成%1 %)、%%(百分比符号,不得改成%)等,否则会导致应用崩溃。 - 注意空格、换行(
\n)与标点:不要画蛇添足地增加换行,这对参数名尤其重要。 - 参数描述不要带计量单位:例如应写 "Enable fan if layer print time is less than 阈值",而不是 "……n seconds"。
- 单位使用国际单位制:用
s而不是sec。 - 标点与原文一致:短语结尾没有句点就不要加,有则保留。
- 保持术语一致:对
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);AddCatalogLookupPathPrefix把localization_dir()指向的目录(即resources/i18n/<语言代码>/)注册为.mo目录的查找路径;AddCatalog(SLIC3R_APP_KEY)按应用键名(BambuStudio)加载对应语言的目录——这正是"将BambuStudio_xx.mo复制到resources/i18n/xx/并重命名为BambuStudio.mo"这一交付步骤的根本原因:文件名必须与目录名匹配,才能被AddCatalog命中。
语言选择方面,GUI_App.cpp通过wxLocale::FindLanguageInfo、wxLocale::IsAvailable与wxLocale::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),仅供参考