没有不值得去解决的问题,也没有不值得去学习的技术!

为 SlyTranslate 的 GLM 5.2 整篇翻译补上 Plaintext 智能处理,并修复 Code Block Pro 区块失效

图3:清理英文 Host 下的对象与术语关系缓存后,英文文章重新显示 SEO Tools、Yoast SEO 和 Blog SEO Log

作者:

,

最近我一直在优化 WordPress 中文技术文章的英文翻译流程。

目前使用的基础方案是:

  • WordPress + Polylang
  • SlyTranslate 1.9.0
  • 智谱 GLM 5.2
  • 自定义 MU 插件
  • 一次性整篇正文翻译
  • 保留 Gutenberg 区块、HTML、短代码和代码块

前面的测试已经证明,GLM 5.2 在技术准确性、英文自然度和长文章稳定性方面表现不错。但在进一步处理 Plaintext 代码块时,又暴露出了几个比较隐蔽的问题:

  1. Plaintext 中的自然语言是否应该翻译;
  2. URL、域名、路径等机器内容不能被修改;
  3. 让模型看到 Plaintext 后,不能破坏 Gutenberg 区块顺序;
  4. Code Block Pro 区块前台虽然正常,重新打开编辑器却会提示无效;
  5. 分类、系列和标签虽然写入数据库,前台缓存却可能没有及时更新。

这篇文章记录这一轮完整的排查与修复过程。


一、为什么要单独处理 Plaintext 代码块

技术文章中的 Plaintext 并不都是同一种内容。

有些 Plaintext 只包含 URL、域名或文件路径:

Plaintext
https://en.shuijingwanwq.com/sitemap_index.xml
Plaintext
/data/wwwroot/www.shuijingwanwq.com/

这些内容当然不能翻译。

但也有一些 Plaintext 实际上是界面提示、错误信息或操作结果,例如:

Plaintext
区块包含未预料的或无效的内容。

如果整块保护,英文文章中就会残留中文。

因此,理想方案不是简单地规定:

Plaintext 全部翻译。

也不是:

Plaintext 全部不翻译。

而是让模型结合上下文判断:

  • URL、域名、路径、命令和机器数据保持原样;
  • 自然语言说明翻译为英文;
  • 真实界面证据根据上下文决定是否保留。

这也是这一轮优化的核心目标之一。


二、原生 SlyTranslate 如何保护代码块

SlyTranslate 原有流程会把完整代码块替换成占位符。

例如 Bash、PHP、HTML 等 Code Block Pro 区块,会被替换为类似:

Plaintext
SWQBLOCK000001END

模型看不到代码块内部内容,因此不会误改代码、命令和 HTML。

这种方式对于真正的代码很安全,但用于 Plaintext 时会带来一个问题:

模型完全看不到 Plaintext 中的内容,也无法结合上下文判断其中是否需要翻译。

因此,我在自定义 MU 插件中对 Plaintext 使用了不同处理方式。


三、Plaintext 使用前后标记开放给模型

Plaintext 不再整块替换为单个占位符,而是把其中的文本暴露给模型:

Plaintext
SWQPLAINSTART000001END
这里是 Plaintext 中的内容
SWQPLAINSTOP000001END

模型可以看到中间的文本,也能看到它前后的文章上下文。

这样就能处理类似下面的句子:

本次调整后,在网域资源 shuijingwanwq.com 中提交以下 Sitemap。

其中域名和 Sitemap URL 保持不变,普通说明文字则翻译为英文。

对于 Bash、PHP、HTML 等真正的代码块,仍继续使用完整区块占位,不开放内部内容。


四、第一次遇到的问题:模型交换了相邻代码块

测试一篇包含大量 URL、域名和 Plaintext 的长文章时,模型返回的占位符数量完全正确,但两个相邻代码块的顺序发生了交换。

源文结构大致是:

Plaintext
在网域资源:
[域名代码块]

中提交:
[Sitemap URL 代码块]

模型为了适应英文语序,将其改写成:

Plaintext
Submitted:
[Sitemap URL 代码块]

to the domain property:
[域名代码块]

从英文语义看并不错误,但 Gutenberg 区块顺序已经变化。

最终校验结果是:

Plaintext
expected_count=139
actual_count=139
fixed_order_valid=false

占位符没有丢失,也没有重复,只是两个相邻区块交换了位置。

这说明:

仅检查占位符数量还不够,还必须检查顺序。


五、增加 Gutenberg 结构占位符

为避免模型合并段落、删除区块边界或交换代码块,我又增加了:

Plaintext
SWQSTRUCT000001END

所有 Gutenberg 开始和结束注释,例如:

HTML
<!-- wp:paragraph -->
<!-- /wp:paragraph -->

都会先转换成固定顺序的结构标记。

模型必须保持:

  • 标记数量不变;
  • 标记顺序不变;
  • 不得合并两个 Gutenberg 区块;
  • 不得移动代码块边界。

修复后重新测试,源文和译文的 Gutenberg 区块数量均为:

Plaintext
350

并且:

Plaintext
block_signature_identical=YES

代码块之外的中文残留也降为:

Plaintext
han_outside_code_blocks=0

从文章结构来看,这一阶段已经成功。


六、英文前台正常,编辑器却提示代码块无效

英文文章发布后,前台页面显示完全正常。

但重新打开 WordPress 区块编辑器时,所有 Code Block Pro 区块都出现提示:

区块包含未预料的或无效的内容。

图1:英文文章编辑器中,Code Block Pro 区块提示包含无效内容
图1:英文文章编辑器中,Code Block Pro 区块提示包含无效内容

一开始我怀疑是复制按钮的无障碍属性被翻译了。

中文代码块中保存的是:

HTML
aria-label="复制"

英文文章中被改成:

HTML
aria-label="Copy"

于是先将 79 处 Copy 恢复成 复制

结果编辑器仍然提示无效,说明问题并不只在 aria-label


七、逐字节对比后发现 Code Block Pro 被重新生成

我对比了中文文章和英文文章中的第一个 Code Block Pro 区块。

结果如下:

Plaintext
source_bytes=2903
target_bytes=2241
byte_identical=NO

第一处差异出现在 codeHTML

原始区块中包含:

HTML
tabindex="0"

英文区块中这一属性已经丢失。

继续比较 PHP 代码块后,又发现:

Plaintext
\u003e

被重新转义成:

Plaintext
\u0026gt;

也就是说,问题不是模型修改了代码,而是代码块在恢复或保存阶段被重新序列化了。

Code Block Pro 的同一份内容并不只保存一次,而是同时存在于:

  1. Gutenberg 区块 JSON 中的 code
  2. Gutenberg 区块 JSON 中的 codeHTML
  3. <textarea>
  4. <pre class="shiki">
  5. 实际显示代码所使用的 <code><span>

只要其中一个位置的格式、转义方式或属性顺序发生变化,Gutenberg 就可能认为区块无效。


八、用 GLM 5.1 做对照测试

为了确认问题来自 SlyTranslate 原生插件,还是自定义的 GLM 5.2 整篇翻译流程,我又做了一次对照测试。

我选择一篇中文草稿,使用 SlyTranslate 原生流程和 GLM 5.1 翻译。

翻译后的 Plaintext 和 PHP 代码块在编辑器中完全正常,没有出现无效提示。

图2:使用 SlyTranslate 原生流程和 GLM 5.1 翻译后,Code Block Pro 正常显示
图2:使用 SlyTranslate 原生流程和 GLM 5.1 翻译后,Code Block Pro 正常显示

这次对照基本确认:

问题不在 Code Block Pro,也不在 SlyTranslate 原生保存逻辑,而在自定义的 GLM 5.2 整篇翻译流程。


九、确认 SlyTranslate 输入阶段没有修改代码块

随后检查 SlyTranslate 的 prepare_single()

源文和准备出的正文单元结果为:

Plaintext
source_chars=377043
unit_chars=377043
whole_content_identical=YES

Code Block Pro 的结果为:

Plaintext
source_code_blocks=79
unit_code_blocks=79
code_blocks_identical=79
code_blocks_different=0

这证明 SlyTranslate 在进入模型翻译之前,并没有修改任何代码块。

真正的问题发生在模型返回后的恢复和保存阶段。


十、Plaintext 原来的恢复方式存在隐患

此前 Plaintext 翻译完成后,插件会调用类似:

PHP
rebuild_plaintext_code_block_pro()

重新构建整个 Code Block Pro 区块。

其中包括:

  • 重新解析 Gutenberg JSON;
  • 修改 code
  • 重建 codeHTML
  • 重建 <textarea>
  • 重建 Shiki <pre>
  • 重新序列化区块属性。

这种方式虽然能够更新 Plaintext 内容,但很容易改变原始区块中的其他细节。

最终方案需要区分两类 Plaintext。

1. 机器型 Plaintext

例如:

Plaintext
https://en.shuijingwanwq.com/
Plaintext
/data/wwwroot/www.shuijingwanwq.com/

模型可以看到这些内容,以理解文章上下文。

但恢复时直接放回完整原始 Code Block Pro 区块,不重新生成任何 JSON 或 HTML。

2. 自然语言 Plaintext

例如错误提示、操作输出或说明文字。

这些内容仍交给 GLM 5.2 判断并翻译。

同时保留 Plaintext 智能翻译能力,而不是退回到整块不翻译。


十一、最终问题出现在 WordPress 保存过滤器

SlyTranslate 的 Polylang 适配器最终使用:

PHP
wp_update_post( wp_slash( $update_data ) );

保存英文正文。

WordPress 在保存正文时,可能经过 content_save_pre、KSES 或其他过滤器。

SlyTranslate 自己的源码注释中也明确提到,KSES 可能:

  • 删除 tabindex
  • 删除自定义区块的 data-* 属性;
  • 修改区分大小写的 SVG 属性;
  • 导致 Code Block Pro 被 Gutenberg 判定无效。

虽然当前登录用户是管理员,但自定义整篇翻译流程最终生成的正文,仍可能在完整保存过程中发生变化。

因此,仅靠占位符恢复还不够。

还需要保证:

已经校验通过的最终正文,写入数据库后必须与保存前逐字节一致。


十二、增加最终精确写回和 SHA-256 校验

在 MU 插件 2026.07.16.12 中,最终采用了两阶段保存。

第一阶段:仍由 SlyTranslate 正常处理

SlyTranslate 继续负责:

  • 创建或覆盖英文文章;
  • 设置文章状态;
  • 设置 Polylang 语言;
  • 建立中英文文章关联;
  • 复制分类、系列和标签;
  • 保存 Meta。

第二阶段:精确写回正文

取得英文文章 ID 后,再将已经通过完整结构校验的英文正文直接写回 post_content

写回前计算:

Plaintext
expected_hash

重新读取数据库后再计算:

Plaintext
stored_hash

然后比较:

Plaintext
expected_hash === stored_hash

如果哈希不同,立即返回错误,不再把这次翻译视为成功。

这一做法避开了最终保存过滤器对 Code Block Pro 区块的再次改写,同时不影响 SlyTranslate 原有的文章、语言和术语处理流程。


十三、最终验证结果

修复后重新覆盖翻译文章:

Plaintext
中文文章 ID:19383
英文文章 ID:19494

英文编辑器中的所有 Code Block Pro 区块恢复正常,不再提示无效内容。

最终逐区块比较结果:

Plaintext
source_total=79
target_total=79

bash: total=5, identical=5, different=0
html: total=3, identical=3, different=0
php: total=3, identical=3, different=0
plaintext: total=68, identical=47, different=21

这个结果基本符合预期:

  • 5 个 Bash 区块全部逐字节一致;
  • 3 个 HTML 区块全部逐字节一致;
  • 3 个 PHP 区块全部逐字节一致;
  • 68 个 Plaintext 中:
    • 47 个保持原样;
    • 21 个根据上下文完成翻译。

也就是说:

真正的代码、URL、域名、路径和机器数据保持不变;Plaintext 中的自然语言由 GLM 5.2 智能判断并翻译。

这正是本轮优化最希望达到的结果。


十四、分类、系列和标签前台未及时更新

英文文章编辑器中已经可以看到正确的英文分类、系列和标签。

数据库检查结果也完全正常:

Plaintext
category=SEO Tools | Yoast SEO
series=Blog SEO Log
post_tag=Cloudflare | English Subdomain | Polylang | Search Engine Submission | Thin Content Tags | W3 Total Cache | WordPress | XML Sitemap | Yoast SEO

但英文前台一开始仍显示:

Plaintext
Uncategorized

随机查询参数绕过页面缓存后,部分标签已经更新,但分类仍然是旧值。

最终在英文 Host 环境下清理:

  • 文章对象缓存;
  • 术语关系缓存;
  • category、series、post_tag 的关系缓存;

前台才恢复正确内容。

图3:清理英文 Host 下的对象与术语关系缓存后,英文文章重新显示 SEO Tools、Yoast SEO 和 Blog SEO Log
图3:清理英文 Host 下的对象与术语关系缓存后,英文文章重新显示 SEO Tools、Yoast SEO 和 Blog SEO Log

这说明:

分类、系列和标签没有丢失,真正的问题是英文域名对应的 W3 Total Cache / Redis 对象缓存没有及时失效。

后台执行“清除所有缓存”或单独清除页面缓存、对象缓存,并不一定能清理到英文 Host 对应的缓存空间。

这与此前英文站出现语言、Canonical 和分类链接缓存异常的问题属于同一类多域名缓存边界。


十五、系列顺序出现了新的异常

缓存清理完成后,英文文章已经正确出现在 Blog SEO Log 系列中。

但它被排到了系列第一篇,而不是最后一篇。

后台 PublishPress Series 的“当前部分”也显示:

Plaintext
当前没有部分编号
图4:英文文章加入 Blog SEO Log 后被排到系列第一位
图4:英文文章加入 Blog SEO Log 后被排到系列第一位
图5:后台没有设置当前部分编号
图5:后台没有设置当前部分编号

这个问题与 Code Block Pro、Plaintext 翻译和正文保存已经不是同一个问题。

目前可以确认的是:

  • 系列术语绑定正确;
  • 英文文章已经属于正确系列;
  • 文章没有明确的系列编号;
  • PublishPress Series 因此将其显示在第一位。

这一问题暂时留到后续单独排查,不继续混入本轮翻译插件优化。


十六、本轮最终稳定版本

当前使用的 MU 插件版本为:

Plaintext
2026.07.16.12

这一版本已经验证:

  • GLM 5.2 可以一次性翻译完整长文章;
  • Gutenberg 区块数量和顺序保持一致;
  • 区块边界不会被模型合并;
  • Bash、PHP、HTML 完整逐字节保留;
  • Plaintext 可以智能判断是否翻译;
  • URL、域名和路径保持原样;
  • Code Block Pro 编辑器不再提示无效内容;
  • 最终正文写入带 SHA-256 校验;
  • 分类、系列和标签可以正常写入数据库。

目前剩余的主要问题已经不再是翻译质量本身,而是:

  • 多域名环境下的对象缓存失效;
  • PublishPress Series 的文章顺序同步。

这两项更适合后续分别处理。


十七、最终体会

这一轮排查最重要的收获,是不能只根据前台页面判断 Gutenberg 内容是否安全。

前台能够正常显示,并不代表:

  • 区块结构仍然有效;
  • 编辑器可以继续修改;
  • Code Block Pro 的序列化内容没有变化;
  • JSON、HTML 和 Shiki 代码完全一致。

对于技术博客的自动翻译流程,真正需要同时满足的是:

  1. 英文自然;
  2. 技术内容准确;
  3. 代码不被修改;
  4. Gutenberg 结构完整;
  5. 编辑器可以正常重新打开;
  6. 数据库存储结果可验证;
  7. 分类、标签和系列关系能够正确刷新。

相比单纯追求某一篇文章更自然的英文,这些结构和保存层面的稳定性,才更决定自动翻译方案能否长期投入生产。

需要长期技术维护或远程问题排查?

我是拥有 15+ 年经验的 PHP / Go 后端工程师,长期关注已有系统维护、Bug 修复、性能优化、服务器排查、WordPress 网站维护和小功能迭代。

如果你的项目遇到以下情况,可以先从一次小问题排查开始合作:

  • ✅ PHP / Laravel / Yii2 老项目无人维护
  • ✅ Go / Gin 后端接口需要排查或优化
  • ✅ WordPress 网站访问慢、报错或插件冲突
  • ✅ Nginx / MySQL / Redis / Linux 服务器异常
  • ✅ CDN / Cloudflare / DNS / HTTPS 配置问题
  • ✅ 需要长期远程技术支持或兼职维护

更多介绍请查看:关于我 & 合作

微信:13980074657
邮箱:shuijingwanwq@gmail.com
Telegram:@shuijingwan
GitHub:https://github.com/shuijingwan

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理