
PhotoCraft 简体中文本地化深度指南从切换 zh-hans 到区域标签解析与翻译覆盖测试【免费下载链接】photocraftPhotoCraft: An open-source, photo editor written by scratch in pure Rust项目地址: https://gitcode.com/gh_mirrors/pho/photocraftPhotoCraft 是一个纯 Rust 重写的开源照片编辑器其简体中文本地化通过共享 i18n 目录机制实现一个zh-hansTSV 目录承载全部文案语言注册表声明复数规则与覆盖承诺区域标签解析保证简繁正确分流。本文讲清楚如何切换语言、zh-CN与zh-TW为何命中不同目录以及用哪些测试命令防止翻译腐化。先看现象为什么zh-CN出简体、zh-TW出繁体不同系统上的同一份构建在 Auto 模式下会呈现不同字形大陆系统显示文件、编辑而繁体偏好系统的菜单则是檔案、編輯。结论先行分流不靠语言名的主观判断而是由一段确定性的标签解析规则完成——系统 locale 标签解析结果zh、zh-CN、zh-SG、zh-Hans、zh-Hans-CN、zh_CN.UTF-8zh-hans简体中文zh-TW、zh-HK、zh-MO、zh-Hant、zh-Hant-HK、zh_TW.UTF-8zh-hant繁體中文独立目录这套行为被单元测试tags_map_to_languages逐条锁定所有简体变体必须解析到zh-hans且从不落入繁体目录。需要注意的边界是Web 构建不会自动检测浏览器语言wasm32下系统标签探测直接返回空列表Auto 回退英语Web 端必须手动选择语言。切换简体中文的三种方式首选项对话框中选择简体中文在Preferences Interface Language的下拉框中选择即可。对话框本身会实时预览所选语言——标题、控件和按钮先变成该语言Cancel 丢弃预览、Apply 提交但不关闭、OK 提交并关闭由 scoped preview 机制保证预览不泄漏到主窗口。用prefs.set命令编程设置CLI、MCP 或桌面控制通道走同一入口把interface.language设为zh-hans{method:engine.execute,params:{command:prefs.set,params:{path:interface.language,value:zh-hans}}}引擎侧对该偏好做格式校验非法值如传入 JSON 数组会返回interface.language must be auto or a language code such as en or ja并保持英语。测试a_control_request_changes_the_drawing_language_in_the_same_frame还验证了一个细节控制请求在处理时先于绘制语言同步执行所以菜单文案在同一帧内就变成目标语言无需等待重启。让 Auto 跟随系统区域Auto 模式依次读取 Unix 的LANG/LC_*、macOS 的首选语言列表CFLocaleCopyPreferredLanguages和 Windows 用户 UI 语言GetUserPreferredUILanguages经由固定版本的sys-locale依赖安全调用标签被限制为最多 64 条、每条 128 字节以内的 ASCII 白名单字符。PHOTOCRAFT_LOCALE环境变量可作单标签覆盖用于可复现启动。两个值得记住的首启行为interface.language默认是auto启动流程不会把检测到的语言写回偏好文件而用户显式选择过的语言在系统语言变化后重启依然保留an_explicit_language_survives_restart_on_a_different_system_language测试验证了这一点。目录文件内部zh-hans.tsv 如何组织三千行文案全部简体中文翻译存放在 crates/ui-egui/src/i18n/zh-hans.tsv三千多行UTF-8、TAB 分隔的三列contextTABsourceTABtranslation第一列context的取值决定这一行属于哪种键空间context 取值含义空普通 UI 文本英文原文直接查译文如File 文件id以稳定命令 ID 为键同一英文标签在不同命令下可译为不同文本plural复数消息源列为one\|other中文只有一种形式如{n} preset\|{n} presets → {n} 个预设其他字符串如cameraData上下文消歧同一英文单词在不同面板含义不同解析侧catalog.rs把条目分桶到plain/contextual/ids/plurals四个 HashMap普通字符串查找是每帧执行的热路径。格式错误的行被报告并跳过而不崩溃——坏翻译不会弄坏 UI但测试会强制捆绑目录零错误。列内支持\n、\t、\\转义。两个动态行为的设计细节快捷键占位符目录里同时存在平台特化行和{key}模板行macOS 填⌥、Windows/Linux 填Altfmt()在翻译之后填充{name}占位符未知占位符原样保留译者可以自由调整占位符位置。单一复数形式中文没有复数变化zh-hans注册为plural_none任何计数都返回索引 0若索引超出目录列出的形式数查找会钳位到最后一项而不是越界。另外注意目录并非运行时读盘。build.rs 会把 TSV 压缩打包进二进制条目行只存译文、英文键全语言共享去重因此修改 TSV 需要重新编译运行时不能热替换。查不到任何键时tr()原样返回英文字符串——这是框架级兜底所以下面才需要覆盖测试。 LANGUAGES 注册表与区域标签解析zh-hans在 i18n/mod.rs 的LANGUAGES静态注册表中登记当前共 22 种语言LangInfo { code: zh-hans, name: 简体中文, source: catalog!(zh-hans), plural: plural_none, complete_menus: true, catalog: OnceLock::new(), }complete_menus: true是关键字段它声明该目录覆盖全部菜单字符串与tl!字面量从而被纳入覆盖门禁下文会讲。代码匹配忽略大小写所以ZH-Hans作为interface.language的值也能命中。真正的分流逻辑在candidates()它把一个标签从最具体到最一般展开为候选序列zh_TW.UTF-8得到[zh-tw, zh-hant, zh]zh-CN得到[zh-cn, zh-hans, zh]。核心是这一小段——主标签为zh且未显式给出hans/hant书写系统时按地区推断if primary zh !parts.iter().any(|p| matches!(*p, hans | hant)) { // Chinese by region when no script is given. let script if parts.iter().any(|p| matches!(*p, tw | hk | mo)) { zh-hant } else { zh-hans }; out.insert(out.len() - 1, script.to_string()); }设计意图很直白裸zh没有书写系统信息而使用裸zh或zh-CN的用户绝大多数在大陆/新加坡所以默认简体只有tw/hk/mo三个地区码才翻转为繁体。lang_from_tag()按候选序列取第一个受支持的语言C/POSIX直接视为英语多语言偏好列表如[zh-Hans-CN, zh-TW]按顺序取第一个受支持者测试system_preferences_are_negotiated_in_order覆盖了这种协商。✅ 翻译不腐化测试门禁与验证命令翻译即数据、约定即测试是这套架构的底线。与zh-hans直接相关的防线有bundled_catalogs_are_consistent逐行校验所有捆绑目录——零格式错误、无重复键、占位符集合与源一致、结尾…与源一致会开对话框的命令必须保留省略号、id键必须是真实存在的命令 ID、复数形式数量与语言的复数规则匹配。tags_map_to_languages/candidates_walk_from_specific_to_general锁定上文那张简繁分流表与候选序列展开。简体中文专属回归simplified_chinese_resolves_from_preferences断言ZH-Hans命中且缺失键回退英语行为级测试dynamic_brush_sections_draw_in_the_selected_language切到 zh-hans 后离屏绘制断言画笔面板分区行显示中文译名而非 Brush Tip Shapecjk_font_order_follows_the_selected_language断言 CJK 字体回退链首位是简体中文字形脚本。cargo xtask i18n-coverage静态扫描 crates/ui-egui/src 的全部tl!字面量、trn(调用、menu_catalog、UI 命令表与引擎CommandSpec逐语言列出缺失键缺失的字符串会以英语显示直到补上译文。字体交付与翻译数据解耦目录不附带任何字体资源原生构建由 shell 的 CJK 回退加载器惰性加载已安装系统字体切换语言时重建字体定义并重置加载器。所以切目录本身不会补齐缺字需要在各目标平台上人工目检缺字、标签布局与平台特定快捷键。常规验证流程来自 本地化总览cargo test -p photocraft-ui-egui cargo clippy -p photocraft-ui-egui --all-targets -- -D warnings cargo xtask i18n-coverage cargo xtask layers cargo xtask wasm最后用现成的离屏snapshot示例crates/ui-egui/examples/snapshot.rs以 zh-hans 渲染并检查菜单、首选项与代表性对话框其输出 JSON 里会带resolved: zh-hans之类的字段便于确认最终生效语言。贡献简体中文翻译时的硬性约定维护 zh-hans.tsv 时必须保持的约束多数已被上面的测试直接执行英文源键、上下文、命令 ID、占位符与转义符不可改动——翻译的是英文文本的含义键本身是契约文件头注释明确声明 clean-room 原则未参考或提取任何专有翻译资源遵循 MIT OR Apache-2.0。会打开对话框的命令保留结尾…。缺失翻译回退英语用户提供的名称图层名、文档名、预设名与文档数据不翻译。产品名与技术名保留原拼写PhotoCraft、ArtCraft、OpenType、RGB、CMYK、Lab。状态消息、错误与自动化输出保持英语——目录全覆盖不等于这些字符串也被翻译。术语上zh-hans 目录采用如下核心译法新增翻译应保持同一用词English简体中文Layer / Adjustment Layer图层 / 调整图层Mask / Clipping Mask蒙版 / 剪贴蒙版Selection / Feather选区 / 羽化Blend Mode / Opacity混合模式 / 不透明度Smart Object / Smart Filter智能对象 / 智能滤镜Canvas / Artboard画布 / 画板Path / Rasterize路径 / 栅格化Preset / Swatch预设 / 色板Export / Preferences导出 / 首选项当英文文案变更时同步更新源键与译文并保留上下文、占位符跑一遍cargo xtask i18n-coverage确认无缺失再人工对照当前英文 UI 复查语义是否仍对应——这就是zh-hans目录从切换、解析到维护的完整闭环。【免费下载链接】photocraftPhotoCraft: An open-source, photo editor written by scratch in pure Rust项目地址: https://gitcode.com/gh_mirrors/pho/photocraft创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考