- 桌面应用
- 系统编程
【免费下载链接】mac-mouse-fix
Mac Mouse Fix - Make Your $10 Mouse Better Than an Apple Trackpad!
本文基于 Mac Mouse Fix 仓库中的 Misappropriating XCStrings.md 研究笔记,系统讲解如何绕过 Xcode 字符串目录(String Catalog / .xcstrings)对源文件类型的限制,把MFLocalizedString()宏用于.md与.vue文件,并给出「伪装文件类型」与「xcstringstool sync+ .stringsdata」两条完整技术路线,以及对应的命令行、JSON 结构与注意事项,可直接复用到任何需要本地化非 Swift/Obj-C 文本的 Xcode 项目。
背景:XCStrings 的同步机制与它的边界
.xcstrings字符串目录之所以能保持与源码同步,靠的是 Xcode 编译阶段的自动提取:Xcode 在编译 C/Swift 源文件时,会扫描NSLocalizedString、MFLocalizedString等本地化宏,把字符串 key、注释和默认值写入.xcstrings;反过来,编译时又用xcstringstool等工具从.xcstrings生成运行时使用的.strings与.stringsdict。
这套机制默认只对 C/Swift 工具链覆盖的文件类型生效。Mac Mouse Fix 项目中,本地化宏MFLocalizedString()同时在 Localization.h(C 宏,包装_MFLocalizedString)与 Localization.swift(Swift 函数,签名与 Foundation 的本地化接口对齐)两处定义,因此.h/.m/.swift文件中的字符串都能被 Xcode 正常识别。
问题在于:项目希望把用户可见的文档也本地化——例如 Markdown/Strings/Readme.xcstrings、Acknowledgements.xcstrings 这些字符串目录,其内容实际来自Markdown/Templates/下的模板文件,随后在 MarkdownReadme.md 中通过markdown_generator.py渲染成各语言的最终文档。文档本质是.md文本,甚至未来网站端还会出现.vue组件。默认情况下,Xcode 不会把 Markdown 文本、纯文本中的MFLocalizedString()当作可提取的字符串,这正是「Misappropriating(挪用/征用)XCStrings」这一研究笔记的出发点。
说明:仓库中 Markdown/Strings/Readme.xcstrings 等字符串目录里的条目都带
"extractionState" : "manual",配合 MarkdownReadme.md 的说明——字符串设为 manual 是为了防止 Xcode 误删,实际由mac-mouse-fix-scripts脚本基于模板管理。也就是说,手动维护 XCStrings 是可行的,但研究笔记在探索更自动化的「源码驱动同步」。
路线一:对 Xcode「撒谎」——伪装 .md 的文件类型
第一种思路很直白:既然 Xcode 只对特定文件类型提取本地化宏,那就把.md文件在 Xcode 检查器(File Inspector)中的 Type 改成会被 C/Swift 工具链处理的类型,骗过字符串提取器。
实测有效的文件类型
笔记中列出的、能让 Xcode 识别出MFLocalizedString()宏的类型有五种:
- C Header
- C Preprocessed Source
- C Source
- makefile
- Exported Symbols
实测无效的类型
- Markdown Text(默认类型)
- Plain Text
这条路的代价
笔记明确指出:该方案「hacky but would be ok」(可行但属于 hack),主要问题在于必须构建 Xcode 工程,.xcstrings才会被更新。把一次完整构建塞进 MMF Website 项目的构建流程里可能太慢、太重,而且对.vue文件来说,伪装成 C/Swift 类型还要忍受 Xcode 不再提供语法高亮、自动补全等 Markdown/Vue 编辑体验。因此它只能算保底方案,真正被看好的是一条更底层、更快的路线。
路线二:利用xcstringstool与 .stringsdata 文件
笔记作者发现,Xcode 编译过程中使用了一个名为xcstringstool的命令行工具,负责从.xcstrings提取.strings/.stringsdict;而它的sync子命令可以反过来,基于一个.stringsdata文件自动更新.xcstrings。这等于绕开了「必须构建工程」的约束,直接把任意来源(包括 .md、.vue)的字符串喂给字符串目录。
.stringsdata 文件的逆向结构
.stringsdata是未公开格式,笔记作者在自己工程的构建产物里找到的.stringsdata几乎都是空内容,随后通过在 GitHub 上搜索(搜索串为path:".stringsdata" content:"\"Localizable\"",用Localizable表名过滤出有实际内容的文件)找到了线索——只有运行 iPhone 模拟器 App 时,Xcode 构建目录才会生成含真实内容的.stringsdata。
基于此逆向出的 JSON 结构如下:
{ "source": "/Users/Noah/Desktop/StringsdataFileTest/StringsdataFileTest/ContentView.swift", "tables": { "Localizable": [ { "comment": "", "key": "Hello, world!" } ], "WoodenTable": [ { "comment": "youtbe comment hhihihiahooohohohohoh", "key": "the.keyyy.eyy", "value": "the default value!" } ] }, "version": 1 }字段含义与要点:
source:产生这些字符串的源文件绝对路径(对应一个可翻译源文件)。tables:按表名(table)分组的字符串数组。Localizable是默认表。- 每个字符串条目包含
key(必需)、comment(给译者看的注释)和可选的value(默认值 / 开发语言原文)。 version:格式版本号,当前为1。- JSON 末尾元素后面不能加逗号——笔记作者在测试中多次被这个 JSON 语法细节坑到。
.stringsdata 是怎么生成的
笔记通过一个 iPhone SwiftUI 测试工程验证了 .stringsdata 的生成来源:在ContentView.swift里调用带完整参数的新式本地化 API——
var storedString = "" init() { var options = String.LocalizationOptions() options.replacements = nil // Don't know what this does storedString = String.init(localized: "the.keyyy.eyy", defaultValue: "the default value!", options: options, table: "WoodenTable", bundle: Bundle.main, locale: Locale.current, comment: "youtbe comment hhihihiahooohohohohoh") }然后在 iPhone 模拟器中构建运行,构建目录里就会出现对应的.stringsdata。由此可以确认:.stringsdata 内部就是 JSON,结构简单,完全可以用脚本自动生成。这给了后续「把 .md / .vue 中的 MFLocalizedString 调用解析成 .stringsdata」的自动化方案以信心。
xcstringstool sync命令用法
命令位于 Xcode 开发者工具目录,典型调用如下:
/Applications/Xcode.app/Contents/Developer/usr/bin/xcstringstool sync Markdown/Skeletons/Markdown.xcstrings --stringsdata Markdown/Skeletons/Noahs.stringsdata(路径中的Markdown/Skeletons/是笔记撰写时的示例目录,实际使用时替换为你自己的.xcstrings与.stringsdata路径。)
笔记实测的行为反馈:
.stringsdata中的新 key 会自动加入.xcstrings;- 不再使用的 key 会在开发语言中被标记为 stale(过时);
.stringsdata中定义的value会自动写入/更新.xcstrings的开发语言;- 当开发语言值变化时,各翻译条目会进入
needs_review(待审)状态(笔记标注「我认为是这样,尚未实测」)。
多表、多文件支持
xcstringstool sync一次可以接收多个.stringsdata文件作为输入,也可以合并进多个.xcstrings文件。背后的设计意图(笔记从 WWDC 的 String Catalog 专题视频中回忆而来):
- 每个可翻译源文件对应恰好一个
.stringsdata文件; - 源文件中的每条字符串可以带
table值,而每个.xcstrings文件代表一个表。
不过笔记也补充:对 Mac Mouse Fix 的文档本地化场景来说,大概率用不上这种多表拆分,默认表即可。
相关发现:Xcode 的 Sync Localizations 步骤
在 Xcode 的 Report Navigator(报告导航器)中有一个名为'Sync Localizations'的步骤,笔记推测它执行的就是上述这类同步工作——但它的日志几乎不输出任何信息,无法据此确认细节。对想深挖的读者来说,可以把这个步骤视作xcstringstool sync在 Xcode UI 层面的对应物。
附注:三条传统提取工具与参考资料
笔记末尾还记录了几条「趁还没忘」的补充:
三条可提取 MFLocalizedString 的命令行工具
- genstrings——生成
.strings文件; - extractLocStrings——同样用于生成
.strings文件; - xcodebuild -exportLocalizations——导出
.xcloc本地化交换包。
这些工具与xcstringstool的定位不同:前两者面向传统.strings格式,xcstringstool sync则直接维护.xcstrings字符串目录;-exportLocalizations面向与译者协作的交换格式。
官方文档线索
笔记提到 Apple 官方其实有.xcstrings的文档(此前一直没注意到),主题是「使用字符串目录本地化与变换文本」。这是 String Catalog 的权威入门资料,可作为验证.stringsdata逆向结论之外的正统知识来源。
工程层面的印证
把这条研究路线放回 Mac Mouse Fix 仓库看,闭环是成立的:
- 源码侧的宏与函数定义在 Localization.h 和 Localization.swift,其中
MFLocalizedStringOrEmptyString的存在(Localization.swift)正是因为给MFLocalizedString增加fallBackToEmptyString:参数会破坏 Xcode 的字符串同步——这从侧面印证了「Xcode 提取器对宏签名非常敏感」这一前提,也解释了为什么笔记里反复强调要让.md中的调用形式能被工具链识别; - 文档本地化的现状在 MarkdownReadme.md 中有说明:
.xcstrings条目设为manual以阻止 Xcode 删除,实际由mac-mouse-fix-scripts脚本基于模板更新。这意味着若引入xcstringstool sync自动化,可以逐步替代「手动维护 + 脚本覆盖」的模式,让.md文档中的MFLocalizedString()直接驱动字符串目录,与 Markdown/Strings/Readme.xcstrings 中的既有条目无缝衔接。
小结:两条路线的取舍
| 维度 | 路线一:伪装文件类型 | 路线二:xcstringstool sync |
|---|---|---|
| 原理 | 把 .md 的 Type 改成 C 系类型,骗过提取器 | 用 .stringsdata 反向喂给 .xcstrings |
| 可用文件类型 | C Header / C Source / C Preprocessed / makefile / Exported Symbols | 任意来源(解析后生成 .stringsdata) |
| 是否依赖构建 | 是,必须构建工程才更新 | 否,单独命令行即可更新 |
| 对 .vue / 网页端 | 体验差,需忍受非 Markdown 语法高亮 | 天然适配,可脚本化生成 .stringsdata |
| 维护性 | hack,但可用 | 推荐,快且轻,适合并入 Website 构建流程 |
综合来看,路线二是更符合 Mac Mouse Fix「把 XCStrings 挪用于 .md 与 .vue」目标的做法:.stringsdata结构简单、可用脚本自动生成,sync子命令行为明确(新增 key、标记 stale、更新开发语言值并触发 needs_review),且不依赖完整工程构建,未来完全可以融入 MMF Website 项目的构建流水线。
- 桌面应用
- 系统编程
【免费下载链接】mac-mouse-fix
Mac Mouse Fix - Make Your $10 Mouse Better Than an Apple Trackpad!
相关推荐
Mac Mouse Fix 的 XCStringsDummyApp:用哑元 Target 让 Xcode 导出不打包进 App 的 .xcstrings 文件
Mac Mouse Fix 的 XCStringsDummyApp:用哑元 Target 让 Xcode 导出不打包进 App 的 .xcstrings 文件
桌面应用系统编程Mac Mouse Fix 的 Markdown 渲染引擎:集成 cmark(cjk 分支)解析本地化文本的完整实践
Mac Mouse Fix 的 Markdown 渲染引擎:集成 cmark(cjk 分支)解析本地化文本的完整实践 本篇技术指南以 Frameworks/cm
桌面应用系统编程Mac Mouse Fix 本地化系统深度剖析:从 .strings 手工作业到 .xcstrings/.xcloc 自动化流水线
Mac Mouse Fix 本地化系统深度剖析:从 .strings 手工作业到 .xcstrings/.xcloc 自动化流水线 本指南围绕 Mac Mous
桌面应用系统编程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考