<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>老木哟的小站</title><description>OldWood&apos;s Space (Chinese source feed)</description><link>https://oldwood-u.fun/</link><language>zh-CN</language><item><title>用 AI 给 Unreal Engine 做本地化：AILocalization 插件介绍</title><link>https://oldwood-u.fun/posts/ai-localization-plugin/</link><guid isPermaLink="true">https://oldwood-u.fun/posts/ai-localization-plugin/</guid><description>从拖拽 PO 文件的翻译脚本，到直接集成进 Unreal Editor 的 AI 本地化工作流。</description><pubDate>Tue, 18 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;最近把自己写的一个 Unreal Engine 插件开源了：&lt;/p&gt;
&lt;a id=&quot;GCn7um7r-card&quot; class=&quot;card-github fetch-waiting no-styling&quot; href=&quot;https://github.com/OldWood-u/AILocalization&quot; target=&quot;_blank&quot;&gt;&lt;div class=&quot;gc-titlebar&quot;&gt;&lt;div class=&quot;gc-titlebar-left&quot;&gt;&lt;div class=&quot;gc-owner&quot;&gt;&lt;div id=&quot;GCn7um7r-avatar&quot; class=&quot;gc-avatar&quot;&gt;&lt;/div&gt;&lt;div class=&quot;gc-user&quot;&gt;OldWood-u&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;gc-divider&quot;&gt;/&lt;/div&gt;&lt;div class=&quot;gc-repo&quot;&gt;AILocalization&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;github-logo&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;GCn7um7r-description&quot; class=&quot;gc-description&quot;&gt;Waiting for api.github.com...&lt;/div&gt;&lt;div class=&quot;gc-infobar&quot;&gt;&lt;div id=&quot;GCn7um7r-stars&quot; class=&quot;gc-stars&quot;&gt;00K&lt;/div&gt;&lt;div id=&quot;GCn7um7r-forks&quot; class=&quot;gc-forks&quot;&gt;0K&lt;/div&gt;&lt;div id=&quot;GCn7um7r-license&quot; class=&quot;gc-license&quot;&gt;0K&lt;/div&gt;&lt;span id=&quot;GCn7um7r-language&quot; class=&quot;gc-language&quot;&gt;Waiting...&lt;/span&gt;&lt;/div&gt;&lt;/a&gt;
&lt;p&gt;它叫 &lt;strong&gt;AI Localization&lt;/strong&gt;，是一个只在 Unreal Editor 中运行的 AI 辅助本地化插件。简单来说，就是把原本需要导出、翻译、再导回去的本地化流程，尽量收进编辑器里完成。&lt;/p&gt;
&lt;p&gt;这个插件最初是为我的游戏 &lt;a href=&quot;https://store.steampowered.com/app/4786590/_/&quot; data-content-link-kind=&quot;external&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Lover Completion Plan&lt;/a&gt; 做的。它不是什么特别成熟的大型工具，更像是一个从真实需求里长出来的小项目：够我自己用，也顺手把它放出来了。&lt;/p&gt;
&lt;section&gt;&lt;h2 id=&quot;事情是怎么开始的&quot;&gt;事情是怎么开始的&lt;a class=&quot;anchor&quot; href=&quot;https://oldwood-u.fun/posts/ai-localization-plugin/#%E4%BA%8B%E6%83%85%E6%98%AF%E6%80%8E%E4%B9%88%E5%BC%80%E5%A7%8B%E7%9A%84&quot;&gt;&lt;span class=&quot;anchor-icon&quot; data-pagefind-ignore&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;在写这个插件之前，我已经有一套能工作的翻译流水线。&lt;/p&gt;&lt;p&gt;先从 Unreal 导出某种目标语言的 &lt;code&gt;.po&lt;/code&gt; 文件，再把文件拖到一个 Python 脚本上。脚本会调用 AI，把内容翻译成文件里指定的语言，并输出一份翻译完成的 &lt;code&gt;.po&lt;/code&gt; 文件。&lt;/p&gt;&lt;p&gt;这套方式本身没有问题，甚至已经帮我省下不少时间。但我的游戏需要支持十种语言，如果每一种语言都要单独导出、拖文件、等待翻译、检查结果、再导回项目，重复操作还是很多。语言一多，真正浪费时间的往往不是 AI 翻译本身，而是这些围绕文件来回处理的步骤。&lt;/p&gt;&lt;p&gt;后来我看到了 &lt;a href=&quot;https://solutions.georgy.dev/ai-localization-automator&quot; data-content-link-kind=&quot;external&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;AI Localization Automator&lt;/a&gt;。它的思路和完成度都不错，我也很喜欢这种把翻译流程直接放进编辑器的方式。不过对我这个项目来说，它的价格有点高，于是我就开始想：既然需求已经很明确，能不能自己做一个只满足当前项目需求的版本？&lt;/p&gt;&lt;p&gt;我先把需要解决的流程和大致规划写下来，再让 AI 协助实现。最后得到的就是现在这个插件。它不算精致，但能够配置自己的 API 供应商，把游戏本地化内容整体交给 AI 处理，已经把我最在意的效率问题解决掉了。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2 id=&quot;插件现在能做什么&quot;&gt;插件现在能做什么&lt;a class=&quot;anchor&quot; href=&quot;https://oldwood-u.fun/posts/ai-localization-plugin/#%E6%8F%92%E4%BB%B6%E7%8E%B0%E5%9C%A8%E8%83%BD%E5%81%9A%E4%BB%80%E4%B9%88&quot;&gt;&lt;span class=&quot;anchor-icon&quot; data-pagefind-ignore&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;AI Localization 会接入 Unreal Editor 的本地化工具：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;可以从 &lt;strong&gt;Tools &amp;gt; Localization &amp;gt; AI Localization Manager&lt;/strong&gt; 打开管理器。&lt;/li&gt;
&lt;li&gt;也会出现在 Localization Dashboard 中，并为本地化 Target 和 Target Set 加上 &lt;strong&gt;AI Translate&lt;/strong&gt; 按钮。&lt;/li&gt;
&lt;li&gt;可以选择本地化 Target、一个或多个目标语言，以及适合不同文本类型的预设。&lt;/li&gt;
&lt;li&gt;支持 OpenAI-compatible 的 &lt;code&gt;/chat/completions&lt;/code&gt; 接口，因此可以配置自己的 endpoint、模型和 API key。&lt;/li&gt;
&lt;li&gt;可以控制批大小、并发数、重试次数、超时、最大输出 token、temperature、仅翻译缺失项和是否覆盖已有译文。&lt;/li&gt;
&lt;li&gt;翻译结束后，成功结果会先暂存，再通过 &lt;strong&gt;Apply &amp;amp; Compile&lt;/strong&gt; 走 Unreal 原本的导入和编译流程。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;基本使用流程就是：选择 Target 和目标语言，配置 Provider，点击 &lt;strong&gt;Start Translation&lt;/strong&gt;，检查表格中的结果，最后再 &lt;strong&gt;Apply &amp;amp; Compile&lt;/strong&gt;。这样不需要把 &lt;code&gt;.po&lt;/code&gt; 文件反复拖到外部脚本上，翻译、检查和应用都留在同一个工作流里。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2 id=&quot;我是怎么给-ai-补上下文的&quot;&gt;我是怎么给 AI 补上下文的&lt;a class=&quot;anchor&quot; href=&quot;https://oldwood-u.fun/posts/ai-localization-plugin/#%E6%88%91%E6%98%AF%E6%80%8E%E4%B9%88%E7%BB%99-ai-%E8%A1%A5%E4%B8%8A%E4%B8%8B%E6%96%87%E7%9A%84&quot;&gt;&lt;span class=&quot;anchor-icon&quot; data-pagefind-ignore&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;游戏文本不是单独一句一句存在的。尤其是剧情、对话和角色台词，如果模型只看到一条孤立文本，翻译很容易丢掉说话人、场景和前后顺序。&lt;/p&gt;&lt;p&gt;所以这个插件里用了一个比较简单的上下文策略：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;场景区分&lt;/strong&gt;：先用 &lt;code&gt;namespace&lt;/code&gt; 区分文本所属的场景或上下文。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;顺序整理&lt;/strong&gt;：再按 &lt;code&gt;key&lt;/code&gt; 对说话人和文本顺序排序。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;这样一来，同一场景里的内容会尽量一起交给模型处理，模型能看到更连续的上下文。它当然不是万能的剧情理解系统，但对我项目中的对话翻译来说已经比完全随机、逐条发送稳定不少。&lt;/p&gt;&lt;p&gt;插件还会保护一些不能被翻坏的结构：Unreal 占位符、printf 格式符、富文本标签、首尾空白和多行换行数量都会在接受译文前校验。校验失败的条目会保留给人检查，不会被自动导入。多行文本也会使用受保护的换行 token，减少模型擅自重排换行带来的问题。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2 id=&quot;成本和取舍&quot;&gt;成本和取舍&lt;a class=&quot;anchor&quot; href=&quot;https://oldwood-u.fun/posts/ai-localization-plugin/#%E6%88%90%E6%9C%AC%E5%92%8C%E5%8F%96%E8%88%8D&quot;&gt;&lt;span class=&quot;anchor-icon&quot; data-pagefind-ignore&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;整个插件从规划到可用，AI 开销大概只花了四十多元，不到五十元。对比当时我看到的商业方案，自己做这个小工具的成本还是挺有意思的。&lt;/p&gt;&lt;p&gt;当然，这不是说它能直接替代成熟产品。商业插件有更完整的支持、长期维护和更广泛的兼容性；我这个版本的目标只是把自己的实际翻译流程跑顺。它目前只支持 OpenAI-compatible chat-completions 接口，不支持 streaming response、模型发现和费用统计；它也是 Editor-only 插件，不负责打包后游戏运行时的实时翻译。&lt;/p&gt;&lt;p&gt;API key 也不会写进项目源码。Windows 下会使用 Windows Credential Manager 保存凭据，其他平台只在当前 Editor 会话内保存；预设文件只记录是否存在凭据，不保存 key 本身。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2 id=&quot;开源出来&quot;&gt;开源出来&lt;a class=&quot;anchor&quot; href=&quot;https://oldwood-u.fun/posts/ai-localization-plugin/#%E5%BC%80%E6%BA%90%E5%87%BA%E6%9D%A5&quot;&gt;&lt;span class=&quot;anchor-icon&quot; data-pagefind-ignore&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;现在这个项目已经按照 MIT License 开源：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;GitHub 仓库：&lt;a href=&quot;https://github.com/OldWood-u/AILocalization&quot; data-content-link-kind=&quot;external&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;OldWood-u/AILocalization&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;安装方式：将插件放到项目的 &lt;code&gt;Plugins/AILocalization&lt;/code&gt; 目录，启用后从 Unreal Editor 的 Tools 菜单打开管理器。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;说到底，它就是我为自己的游戏随手做出来的一个小工具，估计大部分时间也只会在自己的项目里使用。不过目前该有的流程基本都能跑，实际用起来也还不错。&lt;/p&gt;&lt;p&gt;如果它刚好能帮到同样需要给 Unreal 项目做多语言本地化的人，欢迎直接使用、修改或 fork；Issue、Pull Request 和改进建议也都欢迎。&lt;/p&gt;&lt;/section&gt;</content:encoded></item><item><title>如何部署一个属于自己的网站</title><link>https://oldwood-u.fun/posts/hello-world/</link><guid isPermaLink="true">https://oldwood-u.fun/posts/hello-world/</guid><description>小站的第一篇文章</description><pubDate>Sun, 09 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;这是 &lt;strong&gt;OldWood 的小站&lt;/strong&gt; 的第一篇文章 🎉&lt;/p&gt;
&lt;p&gt;本站基于 &lt;a href=&quot;https://astro.build/&quot; data-content-link-kind=&quot;external&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Astro&lt;/a&gt; 和 &lt;a href=&quot;https://github.com/LyraVoid/Mizuki&quot; data-content-link-kind=&quot;external&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Mizuki&lt;/a&gt; 主题构建，静态站点部署在 Cloudflare Pages 上。&lt;/p&gt;
&lt;section&gt;&lt;h2 id=&quot;我是怎么写作的&quot;&gt;我是怎么写作的？&lt;a class=&quot;anchor&quot; href=&quot;https://oldwood-u.fun/posts/hello-world/#%E6%88%91%E6%98%AF%E6%80%8E%E4%B9%88%E5%86%99%E4%BD%9C%E7%9A%84&quot;&gt;&lt;span class=&quot;anchor-icon&quot; data-pagefind-ignore&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;我可以在网站后台添加日记或文章。后台保存并不是直接改服务器上的数据库，而是由 Cloudflare Pages Functions 校验请求后，调用 GitHub Contents API，把内容提交到 &lt;code&gt;OldWood-u/oldwood-blog&lt;/code&gt; 的 &lt;code&gt;main&lt;/code&gt; 分支。之后 GitHub Actions 会异步执行检查、翻译和部署，所以保存完成到网站完全更新之间可能会有一小段时间。&lt;/p&gt;&lt;p&gt;公开文章会交给 DeepSeek 生成英语、日语和韩语的翻译 sidecar。翻译工作流会记录源内容哈希，检查受保护的链接、日期、Markdown 和其它结构化内容；如果中文源文件发生变化，旧译文会被识别为过期，而不是悄悄当成最新译文使用。它不是保存请求里同步完成的翻译，也不能保证每一次提交都立刻完成部署。&lt;/p&gt;&lt;p&gt;&lt;del&gt;已经变成全流程流水线啦（骄傲.jpg）&lt;/del&gt;&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2 id=&quot;网站制作&quot;&gt;网站制作&lt;a class=&quot;anchor&quot; href=&quot;https://oldwood-u.fun/posts/hello-world/#%E7%BD%91%E7%AB%99%E5%88%B6%E4%BD%9C&quot;&gt;&lt;span class=&quot;anchor-icon&quot; data-pagefind-ignore&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;由于我主要做游戏开发（程序），所以对于网页搭建并不是那么熟悉。&lt;/p&gt;&lt;p&gt;但我又想做一个好看的网站，该怎么办呢？&lt;/p&gt;&lt;p&gt;&lt;del&gt;睡大觉啦，梦里什么都有&lt;/del&gt;&lt;/p&gt;&lt;p&gt;于是我使用了现成的博客模板，就是 &lt;a href=&quot;https://astro.build/&quot; data-content-link-kind=&quot;external&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Astro&lt;/a&gt; + &lt;a href=&quot;https://github.com/LyraVoid/Mizuki&quot; data-content-link-kind=&quot;external&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Mizuki&lt;/a&gt; 啦～&lt;/p&gt;&lt;p&gt;这里的“后端”需要稍微解释准确一点：Cloudflare Pages 负责静态页面的构建和发布，Pages Functions 负责登录、内容读写、媒体上传等 API；GitHub 仓库则是文章和结构化内容的持久化来源。域名是在阿里云购买的，一个属于我自己的网站就这样慢慢搭起来了。&lt;/p&gt;&lt;blockquote&gt;
&lt;p&gt;我从高中，不对，初中就想做个自己的网站了，居然到现在才正式做出来（哭.jpg）&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;但很显然，如果只是简单地使用模板、改成自己的信息，那就太 low 啦。换言之又是一个换皮网站罢了。&lt;/p&gt;&lt;p&gt;所以我需要定制化修改。&lt;del&gt;其实就是改下布局，把不需要的功能删除/隐藏，新增些自己认为重要的功能&lt;/del&gt;&lt;/p&gt;&lt;section&gt;&lt;h3 id=&quot;修改配置&quot;&gt;修改配置&lt;a class=&quot;anchor&quot; href=&quot;https://oldwood-u.fun/posts/hello-world/#%E4%BF%AE%E6%94%B9%E9%85%8D%E7%BD%AE&quot;&gt;&lt;span class=&quot;anchor-icon&quot; data-pagefind-ignore&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;**这部分才是最折磨的。**我一开始还想自己手搓来着，但很快就放弃了，不是说太难，而是太累了。整个网站的内容比我想的要多，光是改 Config 文件就要费好大劲儿，更别提后面还要新增的内容了。&lt;/p&gt;&lt;p&gt;但现在是什么时代？**AI 时代！**所以我使用 &lt;em&gt;&lt;strong&gt;Opencode + GPT5.6 Sol&lt;/strong&gt;&lt;/em&gt; 帮我梳理整个网站，由 AI 帮我填入，我只需要提供信息就行了。整个流程还是相对顺利的。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2 id=&quot;网站后端是怎么做的&quot;&gt;网站后端是怎么做的？&lt;a class=&quot;anchor&quot; href=&quot;https://oldwood-u.fun/posts/hello-world/#%E7%BD%91%E7%AB%99%E5%90%8E%E7%AB%AF%E6%98%AF%E6%80%8E%E4%B9%88%E5%81%9A%E7%9A%84&quot;&gt;&lt;span class=&quot;anchor-icon&quot; data-pagefind-ignore&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3 id=&quot;文章和结构化内容分开存储&quot;&gt;文章和结构化内容分开存储&lt;a class=&quot;anchor&quot; href=&quot;https://oldwood-u.fun/posts/hello-world/#%E6%96%87%E7%AB%A0%E5%92%8C%E7%BB%93%E6%9E%84%E5%8C%96%E5%86%85%E5%AE%B9%E5%88%86%E5%BC%80%E5%AD%98%E5%82%A8&quot;&gt;&lt;span class=&quot;anchor-icon&quot; data-pagefind-ignore&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;长篇文章放在 &lt;code&gt;src/content/posts/&lt;/code&gt; 中，每篇文章是一个 Markdown 或 MDX 文件。Astro 的内容集合会读取 frontmatter，并校验标题、发布日期、分类、标签、草稿状态等字段；文章详情页再把正文交给 Astro 的 Markdown 管线渲染。&lt;/p&gt;&lt;p&gt;日记、项目、首页横幅和其它频繁编辑的结构化内容则集中在 &lt;code&gt;src/data/admin-content.json&lt;/code&gt;。这样做的好处是：文章正文仍然适合用 Markdown 写作，日记和项目则可以在后台用卡片、日期和图片控件管理，不需要把所有内容都塞进一个格式里。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3 id=&quot;cloudflare-pages-和-pages-functions&quot;&gt;Cloudflare Pages 和 Pages Functions&lt;a class=&quot;anchor&quot; href=&quot;https://oldwood-u.fun/posts/hello-world/#cloudflare-pages-%E5%92%8C-pages-functions&quot;&gt;&lt;span class=&quot;anchor-icon&quot; data-pagefind-ignore&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Cloudflare Pages 负责把仓库里的 Astro 项目构建成静态网站并发布。Pages Functions 是同一个部署环境里的 API 层，后台登录、会话校验、文章读写、结构化内容保存和图片上传都通过它完成。&lt;/p&gt;&lt;p&gt;上传图片时，API 会检查文件大小、允许的 MIME 类型和文件签名，只把安全的图片写入 &lt;code&gt;public/images/uploads/&lt;/code&gt;。文章正文中保存的是最终站内路径，而不是临时的浏览器对象地址。正文预览会在必要时使用本地临时预览，这样刚上传但还没完成新一轮部署的图片也能立即看到。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3 id=&quot;github-apisha-和更新时间&quot;&gt;GitHub API、SHA 和更新时间&lt;a class=&quot;anchor&quot; href=&quot;https://oldwood-u.fun/posts/hello-world/#github-apisha-%E5%92%8C%E6%9B%B4%E6%96%B0%E6%97%B6%E9%97%B4&quot;&gt;&lt;span class=&quot;anchor-icon&quot; data-pagefind-ignore&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;管理后台使用 GitHub Contents API 读写 &lt;code&gt;main&lt;/code&gt; 分支。更新文章时，客户端会带上它读取到的文件 SHA，服务端在写入前再次比较远端 SHA。如果另一个后台窗口已经先改过同一篇文章，SHA 就会不一致，服务端会拒绝这次写入，避免我的修改覆盖别人的修改。&lt;/p&gt;&lt;p&gt;每次编辑已有文章时，服务端会生成新的 &lt;code&gt;updated&lt;/code&gt; ISO 时间并写入 frontmatter；新建文章则不强行写入这个字段。文章页面底部因此可以显示真正的最后修改时间，而不是把发布日期伪装成更新时间。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3 id=&quot;翻译和部署工作流&quot;&gt;翻译和部署工作流&lt;a class=&quot;anchor&quot; href=&quot;https://oldwood-u.fun/posts/hello-world/#%E7%BF%BB%E8%AF%91%E5%92%8C%E9%83%A8%E7%BD%B2%E5%B7%A5%E4%BD%9C%E6%B5%81&quot;&gt;&lt;span class=&quot;anchor-icon&quot; data-pagefind-ignore&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;文章保存到 GitHub 后，GitHub Actions 会根据中文源文件运行翻译脚本。翻译结果保存在 &lt;code&gt;translations/content/en&lt;/code&gt;、&lt;code&gt;ja&lt;/code&gt; 和 &lt;code&gt;ko&lt;/code&gt; 目录的 sidecar 文件中，并带有 &lt;code&gt;sourceHash&lt;/code&gt;、模型和生成状态等信息。草稿、加密文章和密码文章不会发送到翻译服务。&lt;/p&gt;&lt;p&gt;翻译工作流完成后会提交翻译 sidecar，部署工作流再构建 Astro 项目并通过 Wrangler 发布到 Cloudflare Pages。由于这些步骤是异步的，后台提示“已提交”代表 GitHub 写入成功，不代表所有语言的页面已经在同一秒完成更新。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3 id=&quot;安全边界&quot;&gt;安全边界&lt;a class=&quot;anchor&quot; href=&quot;https://oldwood-u.fun/posts/hello-world/#%E5%AE%89%E5%85%A8%E8%BE%B9%E7%95%8C&quot;&gt;&lt;span class=&quot;anchor-icon&quot; data-pagefind-ignore&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;后台 API 需要有效的管理会话，写请求还要通过严格的同源检查。GitHub token、会话签名密钥和 DeepSeek API key 只放在运行环境或 GitHub Secrets 中，不会进入文章、前端代码或日志。Markdown 预览会经过安全清洗，过滤脚本、事件处理器和危险 URL；文件路径、图片类型、请求大小和 GitHub 文件版本也都会在服务端再次校验。&lt;/p&gt;&lt;p&gt;这套方案没有传统意义上的数据库：GitHub 既保存内容源文件，也提供版本历史；Cloudflare Pages 提供静态站点，Pages Functions 提供必要的 API。它不一定是最复杂的架构，但对一个个人站点来说，修改可追踪、部署自动化，而且我可以在后台继续写作，已经足够实用了。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3 id=&quot;前端修改&quot;&gt;前端修改&lt;a class=&quot;anchor&quot; href=&quot;https://oldwood-u.fun/posts/hello-world/#%E5%89%8D%E7%AB%AF%E4%BF%AE%E6%94%B9&quot;&gt;&lt;span class=&quot;anchor-icon&quot; data-pagefind-ignore&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;首先先说明，Mizuki 兼具丰富功能与优雅设计，本人才疏学浅，如果有任何不规范或错误的地方那都是我的错！可以直接提出！&lt;em&gt;（我也不知道为什么要写这个，反正我就是写了）&lt;/em&gt;&lt;/p&gt;&lt;p&gt;整个前端我基本都是 Vibe Coding，因为效率真的很高。而且 Mizuki 包含很多现成的组件可以直接使用，这样也不用担心 AI 会自我发挥，做出些不符合主题的东西了。&lt;/p&gt;&lt;p&gt;基本总结为以下改动：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;修改顶栏标题顺序和内容&lt;/li&gt;
&lt;li&gt;除了深色、浅色模式，还加了个跟随系统&lt;/li&gt;
&lt;li&gt;添加语言更改选项，可以切换中、英、日、韩四语&lt;/li&gt;
&lt;li&gt;日记界面添加日历，可以点进二级菜单&lt;/li&gt;
&lt;li&gt;我的项目添加二级菜单&lt;/li&gt;
&lt;li&gt;主页添加“精选项目”和“日记”的分类&lt;/li&gt;
&lt;li&gt;为后台文章、日记和项目补充 Markdown 编辑、图片媒体库和草稿保护&lt;/li&gt;
&lt;li&gt;将媒体上传、SHA 冲突、更新时间和翻译流程接到同一套发布链路里&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;后面还会继续记录新的功能和踩坑。先这样，下一篇见！&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;</content:encoded></item></channel></rss>