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

Troubleshooting SlyTranslate Full-Article Translation Failures: Strengthening GLM 5.2 Paragraph and Placeholder Constraints

图1:Codex 输出 Token 校验诊断结果

作者:

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:

Plaintext
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:

Plaintext
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:

Plaintext
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
Figure 1: Token validation diagnostics produced by Codex
Figure 1: Token validation diagnostics produced by Codex

These values describe the problem fairly precisely.

The response was expected to contain 629 placeholders, but the model returned 630.

At the same time:

Plaintext
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:

Plaintext
expected_fixed_count: 584
actual_fixed_count:   584
fixed_order_valid:    true

The only anomaly was:

Plaintext
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:

HTML
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:

Plaintext
模型: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:

Plaintext
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:

Plaintext
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:

Plaintext
SWQSTRUCT000018END

into:

Plaintext
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:

PHP
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:

PHP
$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.

Plaintext
全文翻译模式:

输入内容是一篇技术文章的完整正文。请将它作为一个连贯、可直接发布的完整文档翻译成目标语言。

请根据文章内容判断其实际技术领域,不要预设每篇文章都与 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:

Plaintext
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:

Plaintext
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:

Plaintext
swq_full_article_token_validation_failed

The validator also found none of the following:

  • duplicate SWQINLINE placeholders;
  • 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:

Plaintext
提示词降低错误概率
+
严格 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:

Plaintext
/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:

Plaintext
AGENTS.md

It explicitly states that:

Plaintext
只读分析
→ 本地副本修改
→ 等待明确部署授权
→ 创建生产备份
→ 上传指定文件
→ 完成生产验证

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:

Plaintext
保护 Gutenberg、HTML 和代码内容
→ 一次性发送完整文章
→ GLM 5.2 翻译自然语言
→ 检查 Token 数量、格式、唯一性和顺序
→ 通过校验后还原原始内容
→ 写入 WordPress 英文文章

The prompt has now been strengthened against the two types of failures observed in real tests:

Plaintext
相邻段落和 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

评论

发表回复

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

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