While continuing to test SlyTranslate’s full-article translation feature, I encountered another full-article translation failure.
This time, the WordPress admin returned the following error:
swq_full_article_token_validation_failed
Judging from the error name, the issue was still related to the protected placeholders used during full-article translation.
Further investigation showed that no placeholder had been lost, reformatted, or moved out of its fixed order. Instead, GLM 5.2 duplicated an entire adjacent paragraph while generating the translation, causing the same SWQINLINE placeholder to appear twice.
In the end, I did not loosen the existing validation rules or simply delete the duplicate placeholder. Instead, I refined the full-article translation prompt sent to the model.
After the change, I translated post 19445 again, and the process completed successfully.
1. Why Full-Article Translation Needs Placeholders
I currently use SlyTranslate with GLM 5.2 to translate complete WordPress technical articles in a single request.
To prevent the model from changing code, commands, URLs, HTML structure, and Gutenberg block comments, the custom plugin first replaces content that must not be translated with protected placeholders.
For example:
SWQSTRUCT000018END
SWQBLOCK000018END
SWQINLINE000018END
SWQHTML000018END
Each placeholder type serves a different purpose:
SWQSTRUCT: protects Gutenberg block boundaries;SWQBLOCK: protects complete code blocks or other non-translatable elements;SWQINLINE: protects inline code within paragraphs;SWQHTML: protects fixed HTML elements.
After the model translates the natural-language content, the plugin restores these placeholders to their original values.
This approach substantially reduces the risk of code blocks and WordPress structure being translated by mistake, but it depends on the model returning the correct placeholder count, format, and order.
2. What Went Wrong This Time
After the translation failed, the diagnostic file reported:
expected_count: 629
actual_count: 630
expected_fixed_count: 584
actual_fixed_count: 584
fixed_order_valid: true
missing_tokens: []
unexpected_tokens: []
duplicated_tokens:
SWQINLINE000013END: 2

These values describe the problem fairly precisely.
The response was expected to contain 629 placeholders, but the model returned 630.
At the same time:
missing_tokens: []
unexpected_tokens: []
This shows that no placeholder was missing and no unrecognized placeholder had been introduced.
The number and order of the fixed structural placeholders were also identical:
expected_fixed_count: 584
actual_fixed_count: 584
fixed_order_valid: true
The only anomaly was:
SWQINLINE000013END
It appeared twice in the model output.
3. This Was Not Simply One Extra Token
A closer look at the model output showed that the problem was not merely a duplicated placeholder string.
The actual output looked roughly like this:
SWQSTRUCT000105END
<p>The cached query results under the SWQINLINE000013END Host:</p>
SWQSTRUCT000106END
SWQSTRUCT000107END
<p>The cached query results under the SWQINLINE000013END Host:</p>
SWQSTRUCT000108END
The model copied the English content of the previous paragraph, including SWQINLINE000013END, into the following structural range.
In other words, the underlying error was:
The model regenerated an adjacent paragraph instead of merely outputting one placeholder twice.
This distinction matters.
Simply deleting the second SWQINLINE000013END might restore the expected Token count, but the duplicated English paragraph would still remain.
More importantly, the later structural range may have had its intended content replaced by a copy of the preceding paragraph.
Forcibly deleting the duplicate Token could therefore make validation appear to pass while leaving the article without a translation for one of the source paragraphs.
For that reason, I did not implement automatic removal of duplicate placeholders.
4. Why Response Truncation Could Be Ruled Out
This request called GLM 5.2 only once. The main figures were:
模型:glm-5.2
max_tokens:32768
请求耗时:约 86 秒
输出字符数:32828
The model response reached the end of the article, and the final structural placeholders were present.
In addition:
missing_tokens: []
This means every expected placeholder could be found in the response.
If the API response had been truncated because max_tokens was too low, many structural Tokens near the end of the article would normally have been missing. It would not usually produce only one extra inline Token.
The following causes could therefore be largely ruled out:
- insufficient
max_tokens; - a network interruption;
- an HTTP request failure;
- a JSON parsing failure;
- the end of the article being truncated;
- response-unpacking logic accidentally removing article content.
The current request path does not yet record the API’s original finish_reason, so it cannot directly prove that the model ended with the normal stop reason.
However, because the article ending was complete and every expected Token was present, the failure did not match the usual pattern of a truncated response.
5. The Existing Strict Validator Worked Correctly
Based on this result, the current full-article translation validator did not produce a false positive.
It correctly detected the following anomalies:
expected_count != actual_count
duplicated_tokens 不为空
It then prevented the invalid translation from being restored and written to the post.
Without this validation layer, an English article containing duplicated paragraphs and potentially missing source content could have been saved directly to WordPress.
The strict validator should therefore not be weakened simply because the model occasionally produces an invalid response.
In particular, the following approaches should be avoided:
- allowing duplicate Tokens to pass validation;
- automatically deleting the second duplicate Token;
- checking only whether a Token exists without checking how many times it appears;
- validating only fixed structural Tokens while ignoring
SWQINLINE; - removing full-article integrity checks to reduce the failure rate.
For a publicly released translation plugin, failed translations certainly affect the user experience. However, silently generating an article that appears structurally complete while containing incorrect body content is a greater risk.
6. A Previous Issue: Lost Leading Zeros
An earlier test exposed another type of placeholder corruption.
The model once changed:
SWQSTRUCT000018END
into:
SWQSTRUCT00018END
In other words, it shortened the fixed six-digit identifier to five digits by removing one leading zero.
The plugin now includes an unambiguous leading-zero restoration rule.
A five-digit identifier is restored to six digits only when the original Token can be determined with certainty, after which the complete strict validation process runs again.
If the repair is ambiguous, or if the repaired result still fails complete validation, the plugin stops the translation instead of forcing the content into the post.
Code-level tolerance should still be treated only as a fallback.
The better approach is to tell the model explicitly in the prompt that:
- placeholder identifiers always contain exactly six digits;
- all leading zeros must be preserved;
- Token types and letter case must not be changed;
- spaces, line breaks, and punctuation must not be inserted inside a Token;
- each Token must appear exactly once.
7. Why I Strengthened the Prompt First
After finding the duplicate Token, I initially considered whether the plugin could simply remove one of the duplicate instances automatically.
However, the actual output showed that the model had duplicated an entire adjacent paragraph, not an isolated Token.
In that situation, deduplication might allow validation to pass without recovering the content that the later paragraph should have contained.
Another possible approach would be to identify the contaminated structural range and retranslate only that section.
That would require solving several additional problems:
- determining which of the two duplicate Tokens belongs to the correct paragraph;
- determining whether the later paragraph has already overwritten other content;
- extracting the corresponding structural range from the source payload;
- calling the model again to translate that range;
- merging the local result back into the full translation;
- running complete Token validation again;
- preventing the local repair from introducing new structural problems.
So far, I have seen only one case of an adjacent paragraph being duplicated, and the existing validator successfully prevented the invalid result from being written.
I therefore chose the smaller change with lower maintenance cost:
Strengthen the full-article translation prompt by explicitly prohibiting paragraph duplication, Token duplication, and the removal of leading zeros.
The existing strict validation, unambiguous leading-zero repair, response restoration, and API request flow remain unchanged.
8. The Current Full-Article Translation Prompt Template
The component modified in this round was:
SWQ_GLM52_Translation_Tuning::build_content_prompt()
The production plugin uses the following code to insert the appropriate writing rules dynamically for the target language:
$language_rules = self::build_target_language_content_rules( $target_language );
The block below therefore shows the complete full-article translation prompt template currently in use.
In actual requests, the position marked “existing target-language writing rules” is replaced with dynamically generated rules.
全文翻译模式:
输入内容是一篇技术文章的完整正文。请将它作为一个连贯、可直接发布的完整文档翻译成目标语言。
请根据文章内容判断其实际技术领域,不要预设每篇文章都与 WordPress、PHP、Nginx、服务器或任何其他固定技术有关。
[原有目标语言写作规则,由 build_target_language_content_rules() 动态插入]
上方提供的文章标题和摘要只用于理解上下文,不得将它们加入返回的正文。
不可翻译的代码、行内代码、固定 HTML 元素、Gutenberg 区块边界以及部分可翻译区域已替换为受保护占位符。
每个受保护占位符都必须逐字符原样复制,并且在输出中必须且只能出现一次。不得遗漏、重复、额外生成、复制、翻译、改名、拆开、包裹或重新编号任何占位符,也不得把一个段落中的占位符复制到另一个段落。占位符的类型、大小写和结尾必须保持不变;编号必须始终是固定 6 位数字,所有前导零都必须保留。
例如,SWQSTRUCT000018END、SWQBLOCK000018END、SWQINLINE000018END 和 SWQHTML000018END 必须完整保留。SWQSTRUCT000018END 不得写成 SWQSTRUCT00018END、SWQSTRUCT000018end、SWQSTRUCT 000018 END 或 SWQSTRUCT000 018END。不得在占位符内部插入空格、换行、标点、HTML 标签或 Markdown 格式。
SWQBLOCK 开头的占位符代表一个完整、独立且不可翻译的代码块或代码元素。把每个 SWQBLOCK 当作不可移动的文档锚点,保持它们原有的相对顺序和文档位置。不得为了让目标语言更流畅而反转、交换或重新组合两个 SWQBLOCK;只能改写固定 Token 前、后或之间的自然语言,同时保持 Token 顺序不变。例如原文结构是“属性中:SWQBLOCK000001END……提交:SWQBLOCK000002END”时,必须保持 000001 在 000002 之前。
SWQINLINE 开头的占位符代表自然语言中的行内代码。每个 SWQINLINE 只能在其原句或原段落内部因英文语序需要而调整位置,不得移动到其他段落、列表项、标题、表格单元格或章节,也不得把前一段的 SWQINLINE 复制到后一段。
SWQHTML 开头的占位符代表固定 HTML 元素,必须逐字符原样保留一次,且不得移动。
SWQSTRUCT 开头的占位符代表原始 Gutenberg 起始或结束区块注释,是不可移动的区块边界。必须保持完整 SWQSTRUCT 序列的数量、顺序和位置,不得交换相邻结构 Token、删除区块边界,或把一个结构区间中的内容移动到另一个结构区间。
匹配的 SWQPLAINSTART 与 SWQPLAINSTOP 之间的文本来自 Plaintext 或预格式化区块。默认翻译其中每个人类语言片段,包括作者编写的标签、注释、摘要、说明和描述,即使它们很短、单独占一行、看起来像终端输出,或与 URL、域名和标识符混合。保留机器值,但翻译其周围的人类语言说明。例如,将“中文站:”和“英文站:”译为“Chinese site:”和“English site:”,将“选择 Browser”译为“Select Browser”,并在保留域名的同时翻译“www.example.com:补丁正常输出”中的说明部分。只有当上下文明示某段原文措辞本身就是实际系统证据,修改它会造成事实错误时,才保留源语言;这项狭窄例外可用于确切界面标签、原始错误消息、原始日志或字面观测值。例如,周围正文说明“中文(中国)”是中文站实际显示的语言切换器标签时,应保留该文字。仅仅位于 Plaintext 区块、看起来像输出或只是短标签,都不足以保留源语言;无法确定自然语言片段用途时,应翻译。若 Plaintext 区域只包含 URL、域名、路径、命令、标识符、状态码或其他机器可读值,则仅将其用于理解上下文,内部文本必须原样复制且不得移动。始终保留 URL、域名、路径、命令、参数、机器标识符、状态码、箭头、标点、行序、行数、空行和缩进,不得添加 Markdown 围栏或引号。
匹配的 SWQALTSTART 与 SWQALTSTOP 之间是图片 alt 值,应自然、简洁地翻译,不得添加引号;外围图片标签会另行还原。
原始 Gutenberg 区块注释由 SWQSTRUCT 表示;其余输入仍包含 HTML 标签及属性、区块属性、URL、域名、短代码、模板变量和文档结构。所有这些内容以及命令、参数、配置键、路径、文件名、标识符、产品名和插件名都必须原样保留。
原文中的每个自然语言段落只能翻译一次。不得重复、遗漏、合并、拆分、替换或重新排列 Gutenberg 区块、HTML 元素、段落、标题、列表项、表格单元格或章节;保持其层级、相对顺序和文档位置。不得把前一个段落的译文复制到相邻段落。即使两个相邻段落内容相似,也必须分别翻译并保留各自结构;不得因前后文相似而跳过其中任何一个段落,也不得自行补充源内容中不存在的段落、标题、说明或总结。
在同一个标题、段落、列表项或表格单元格内部,可以根据自然英文表达需要调整句子结构、主语、修饰语和从句,但不得跨越原有结构边界移动内容。
只翻译自然语言文本。保持原意、事实、技术区别、操作步骤、时间顺序、风险判断、确定程度和结论;不得把链接误写成重定向、把缓存条目误写成数据库记录,或混淆原文中的其他技术区别。英文应自然、准确、克制且适合技术读者,不使用营销表达。
返回前,在内部检查是否存在重复或遗漏的段落、重复或遗漏的占位符、占位符格式变化以及固定结构 Token 的数量或顺序变化;发现问题时应先自行修正,但不得输出检查过程、Token 清单、校验报告或解释。
不得添加解释、引言、结语、评论、免责声明、营销语言、Markdown 代码围栏或源文不存在的内容。最终只返回完整的英文译文正文。
9. What Problems This Prompt Is Designed to Prevent
The prompt is relatively long, but each rule addresses a different translation risk.
1. Preventing Missing and Duplicate Placeholders
The prompt explicitly requires that:
- each placeholder appear exactly once;
- no placeholder be omitted or generated unnecessarily;
- a placeholder from one paragraph never be copied into another paragraph;
- Token type, letter case, and ending remain unchanged.
This section directly addresses the duplicate SWQINLINE000013END seen in this incident.
2. Enforcing Six-Digit Identifiers
The prompt states that every Token identifier must contain exactly six digits and preserve all leading zeros.
It also includes examples of invalid formats:
SWQSTRUCT00018END
SWQSTRUCT000018end
SWQSTRUCT 000018 END
SWQSTRUCT000 018END
This rule addresses the leading-zero loss seen in an earlier test.
3. Restricting Where SWQINLINE May Move
When Chinese and English sentence structures differ, inline code may need to move within a sentence.
For that reason, SWQINLINE cannot be fixed to its original character offset. However, it may move only within the same source sentence or paragraph. It must not move into another paragraph, heading, list item, or table cell.
4. Fixing the Gutenberg Structure in Place
SWQSTRUCT represents Gutenberg opening or closing block comments.
The prompt requires their count, order, and positions to remain unchanged. Adjacent structural Tokens must not be swapped, and content must not be moved from one structural range into another.
5. Preventing Adjacent Paragraphs from Being Copied
The prompt states that each natural-language paragraph must be translated exactly once.
Even when two adjacent paragraphs are similar, they must be translated separately and retain their own structure. The model must not copy the previous paragraph or skip the following one merely because the context is similar.
6. Handling Natural Language Inside Preformatted Regions
Content between SWQPLAINSTART and SWQPLAINSTOP may contain both natural language and machine-readable values.
The current rules require the model to:
- translate labels, explanations, comments, and descriptions;
- preserve URLs, domains, paths, commands, and identifiers;
- preserve line order, blank lines, and indentation;
- retain the original language only when the content is an original log entry, error message, or exact interface label.
7. Requiring an Internal Check Without Returning a Report
Before responding, the prompt asks the model to check:
- whether any paragraph has been duplicated or omitted;
- whether any Token has been duplicated or omitted;
- whether any Token format has changed;
- whether the count and order of fixed structural Tokens are correct.
However, the model must not return its checking process, Token list, or explanation.
The final response must still contain only the English article body, preventing the model from adding:
Translation completed successfully.
All placeholders were verified.
10. Results of the Updated Prompt
After updating the prompt and synchronizing it to the production plugin, I ran a new full-article translation for post 19445.
This translation completed successfully and did not reproduce:
swq_full_article_token_validation_failed
The validator also found none of the following:
- duplicate
SWQINLINEplaceholders; - lost leading zeros in Token identifiers;
- incorrect fixed-Token ordering;
- validation failures caused by duplicated adjacent paragraphs.
This shows that the stronger prompt had a practical effect on the current test article.
However, one successful retry does not prove that GLM 5.2 will never duplicate a paragraph again.
Model output still contains an element of randomness, so the existing strict validation and failure-blocking logic must remain in place.
A more accurate conclusion is:
The new prompt reduces the likelihood of the known errors recurring, but it does not replace code-level validation.
11. Why I Am Not Adding Complex Automatic Repair Yet
In theory, after detecting a duplicate SWQINLINE, the plugin could try to identify the affected structural range and retranslate only the corresponding paragraph.
That would significantly increase implementation complexity.
The unresolved problems would include:
- determining which of the two duplicate Tokens belongs to the correct paragraph;
- determining whether the later paragraph has already overwritten other source content;
- extracting the corresponding structural range again from the source payload;
- translating that range separately;
- merging the local result back into the complete translation;
- running full Token validation again;
- preventing the local retry from introducing new structural errors.
Only one adjacent-paragraph duplication has appeared so far, and the translation succeeded after the prompt was strengthened.
Under these circumstances, adding substantial code and maintenance overhead solely for theoretical automatic recovery is not yet justified.
The current approach remains:
提示词降低错误概率
+
严格 Token 校验阻止错误结果
+
失败后重新执行一次全文翻译
If the same problem begins to occur frequently, one controlled full-article retry would be safer than deleting a duplicate Token directly and simpler than repairing an individual structural range.
12. A Production-Safety Issue Exposed During the Change
The prompt update also exposed a separate issue unrelated to translation quality but worth documenting.
The original Codex task asked it to modify the plugin prompt and included the production file path directly:
/data/wwwroot/www.shuijingwanwq.com/wp-content/mu-plugins/swq-glm52-translation-tuning.php
Codex interpreted “modify the plugin” as authorization to write to production and changed the production file immediately.
The change itself was correct, a backup was created beforehand, and the PHP syntax check passed. Even so, a workflow that modifies production by default carries unnecessary risk.
I later added the following file to the project root:
AGENTS.md
It explicitly states that:
只读分析
→ 本地副本修改
→ 等待明确部署授权
→ 创建生产备份
→ 上传指定文件
→ 完成生产验证
The policy also establishes that:
- every path under
/data/wwwroot/belongs to the production environment; - ordinary wording such as “modify the code,” “fix the plugin,” or “complete the feature” does not authorize a production deployment;
- when deployment has not been requested explicitly, only the local copy may be changed;
- deployment authorization from an earlier task does not automatically carry over to a later task;
- when authorization to write to production is ambiguous, the default is not to write.
This change does not directly improve translation quality, but it reduces production risk when Codex is used to maintain the plugin in the future.
13. Conclusions from This Investigation
This incident further demonstrates that full-article translation stability cannot depend on the model alone.
A technical-article translation workflow intended for long-term use needs at least three layers of protection.
Layer 1: Explicit Prompt Constraints
Tell the model which content may be translated, which content must be preserved character for character, and explicitly prohibit paragraph duplication, omission, and structural movement.
Layer 2: Code-Level Placeholder Protection
Before sending content to the model, replace code, HTML, Gutenberg structure, and machine-readable values with protected Tokens.
Layer 3: Strict Validation of the Returned Content
Validate:
- Token count;
- Token uniqueness;
- Token format;
- fixed-Token order;
- missing Tokens;
- unexpected Tokens;
- duplicate Tokens;
- integrity after unambiguous format repair.
Prompt rules can reduce the probability of errors, but they cannot replace the validator.
The validator can detect structural anomalies, but it cannot guarantee that every natural-language sentence is semantically perfect.
The goal is not to make every model call infallible. It is to prevent an occasional model error from entering a published article and to let the user recover through a simple retry.
14. The Current Full-Article Translation Workflow
After this adjustment, the full-article translation process can continue using the following approach:
保护 Gutenberg、HTML 和代码内容
→ 一次性发送完整文章
→ GLM 5.2 翻译自然语言
→ 检查 Token 数量、格式、唯一性和顺序
→ 通过校验后还原原始内容
→ 写入 WordPress 英文文章
The prompt has now been strengthened against the two types of failures observed in real tests:
相邻段落和 SWQINLINE 重复
Token 六位编号丢失前导零
Post 19445 was translated successfully on the next attempt.
At this stage, it makes sense to continue observing results from future articles rather than rushing to add automatic deletion, local retranslations, or complex recovery mechanisms.
For an automated translation plugin built around a large language model, a simple implementation, strict validation, and clear diagnostics may be more reliable than trying to repair every possible anomaly automatically.
需要长期技术维护或远程问题排查?
我是拥有 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


发表回复