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

A Tour of Go Multilingual Translation: When Correct Chinese Word Order Is Misjudged by Protected Tag Order Validation

Figure 2: A Tour of Go methods/20 "Exercise: Errors" Chinese candidate page final rendering

作者:

在

,

While continuing the A Tour of Go multilingual translation project, I was originally just preparing to complete the next representative calibration page methods/20.

The title of this page is:

Exercise: Errors

Which translates to “Exercise: Errors”.

Structurally, the page is not particularly complex: regular body text, inline code, a cross-section link, two preformatted Go code blocks, a bolded Note paragraph, and the final .play example.

Previously, the project had progressively refined the protection and validation of inline code, legacy present syntax, preformatted code, instructional code comments, and emphasis structures through several representative pages. I originally judged that this page could go straight into the first development translation.

Unexpectedly, the first translation failed again.

This time, however, the real problem was not GLM-5.2’s translation, but a rule I had previously designed that seemed reasonable but was actually too strict for multilingual translation:

All protected tokens must strictly maintain their original global order.

This troubleshooting ultimately led me to redraw a very important boundary:

Structural validation should be responsible for structural safety that machines can reliably determine, rather than misjudging normal word order changes between languages as structural damage.


1. methods/20 First Translation: API Normal, but Automatic Validation Failed

The official original text corresponding to methods/20 is as follows:

Plaintext
* Exercise: Errors

Copy your `Sqrt` function from the [[/tour/flowcontrol/8][earlier exercise]] and modify it to return an `error` value.

`Sqrt` should return a non-nil error value when given a negative number, as it doesn't support complex numbers.

Create a new type

	type ErrNegativeSqrt float64

and make it an `error` by giving it a

	func (e ErrNegativeSqrt) Error() string

method such that `ErrNegativeSqrt(-2).Error()` returns `"cannot`Sqrt`negative`number:`-2"`.

*Note:* A call to `fmt.Sprint(e)` inside the `Error` method will send the program into an infinite loop. You can avoid this by converting `e` first: `fmt.Sprint(float64(e))`. Why?

Change your `Sqrt` function to return an `ErrNegativeSqrt` value when given a negative number.

.play methods/exercise-errors.go

The first development translation was executed:

Bash
go run ./cmd/tour-i18n translate run --locale zh-CN --id methods/20 --dev

The GLM-5.2 request itself completed normally:

Plaintext
Attempt: 1
finish_reason: stop

But automatic validation failed:

JSON
{
  "attempt": 1,
  "api_success": true,
  "token_valid": false,
  "present_valid": false,
  "failures": [
    "protected token order mismatch at 1",
    "protected token order mismatch at 2",
    "protected token order mismatch at 6",
    "protected token order mismatch at 7",
    "protected token order mismatch at 10",
    "protected token order mismatch at 11"
  ],
  "passed": false
}

The page therefore remained in:

Plaintext
pending

At first glance, this looked like another case of the model failing to follow the Protected Token rules.

But upon further inspection, I found that was completely not the case.


2. 16 Protected Tokens, Not a Single One Lost

A total of 16 protected tokens were generated for this page.

GLM-5.2:

  • Did not delete any tokens;
  • Did not duplicate any tokens;
  • Did not fabricate unknown tokens;
  • All 16 tokens were fully preserved.

The only thing that actually changed was that three groups of tokens swapped their order of appearance:

  • Sqrt and the link target;
  • error and a preformatted code block;
  • fmt.Sprint(e) and Error.

In other words, this failure was not:

The model destroying protected content.

But rather:

The model rearranging some protected content according to natural Chinese word order.

The nature of these two problems is completely different.


3. First Reorder: Link Appears First, Sqrt Appears Later

Original text:

Copy your Sqrt function from the earlier exercise…

In English word order, this roughly translates to:

Plaintext
Copy
→ your Sqrt function
→ from the earlier exercise

And the Chinese generated by the model was:

从之前的练习中复制你的 Sqrt 函数……

The more natural Chinese word order is clearly:

Plaintext
From the earlier exercise
→ copy
→ your Sqrt function

Therefore, in the model’s output, the protected token corresponding to the link target appeared before Sqrt.

What the old validator saw was:

Plaintext
Source order:

Sqrt
→ link target

The model output became:

Plaintext
link target
→ Sqrt

So it judged:

Plaintext
protected token order mismatch

But in terms of translation quality:

“从之前的练习中复制你的 Sqrt 函数”

Not only is this completely correct, but it is also clearly more natural than forcibly maintaining the English order.


4. Second Reorder: error Moved After the Code Block

This part of the original text is rather special:

Plaintext
and make it an `error` by giving it a

	func (e ErrNegativeSqrt) Error() string

method such that ...

The English expresses:

By giving it the following method, make it an error

After the model translated it, it became:

Plaintext
并为其实现

	func (e ErrNegativeSqrt) Error() string

方法,使它成为一个 `error`

Thus:

Plaintext
`error`
→ preformatted code block

Became:

Plaintext
preformatted code block
→ `error`

If we only look at the global order of protected tokens, this certainly changed.

But further analysis of the present structure revealed:

  • The second code block remained in its original code block position;
  • The code content did not change by a single byte;
  • The two preformatted code blocks were not swapped;
  • Only the error in the regular body text moved from before the code block to after it.

In other words:

The code block did not move at all.

Only the organization of the natural language before and after the code block changed.

After final manual polishing, I adjusted this paragraph to:

并为其实现
func (e ErrNegativeSqrt) Error() string
方法,使其实现 error 接口……

Not only is the structure correct, but the technical expression is also more accurate than “make it an error“.


5. Third Reorder: Error and fmt.Sprint(e)

Original text:

A call to fmt.Sprint(e) inside the Error method will send the program into an infinite loop.

The English order is:

Plaintext
fmt.Sprint(e)
→ Error

And the model translated it as:

在 Error 方法中调用 fmt.Sprint(e) 会导致程序陷入无限循环。

In Chinese, it naturally becomes:

Plaintext
Error
→ fmt.Sprint(e)

The old rule thus judged the token order as incorrect again.

But there is no technical problem with this Chinese sentence.

On the contrary, if we were to forcibly maintain the English token order, writing something like:

调用 fmt.Sprint(e) 在 Error 方法中……

The Chinese would clearly become worse.


6. This Was Not the First Time: generics/1 Had Already Exposed the Same Problem

After continuing to review previous translation records, I found that this was not the first time this had happened.

In a historical translation attempt for generics/1, the following also occurred:

Plaintext
T
→ comparable

Became:

Plaintext
comparable
→ T

The original text roughly expresses:

type T that fulfills the built-in constraint comparable

Natural Chinese, however, is better written as:

满足内置约束 comparable 的任意类型 T

This is also a very typical difference between English and Chinese word order.

At the time, I only treated it as an isolated token reorder failure.

It wasn’t until this methods/20 page had three similar cases in a row that I had enough evidence to confirm:

The problem was not that the model occasionally failed to follow the rules, but that the rule “all Protected Tokens must maintain global order” is inherently unsuitable as a multilingual structural invariant.


7. What Exactly Needs to Be Protected?

This raises a very crucial design question.

Assuming two inline code snippets swap positions after translation, can the validator determine based solely on the present AST or token order:

Is this a normal Chinese word order change?

Or:

Has the technical semantics actually been incorrectly reversed?

In many cases, the answer is no.

For example:

Plaintext
T / comparable

And:

Plaintext
fmt.Sprint(e) / Error

From the perspective of the present structure, they are both just program spans in regular body text.

Relying solely on static structural information, there is no general algorithm that can simultaneously:

  • Allow correct cross-lingual word order changes;
  • And accurately reject all incorrect transpositions in technical semantics.

If forced to implement this, it would likely devolve into an ever-growing set of heuristic rules tailored to English, Chinese, or even specific sentence patterns.

This runs counter to the project’s future goal of supporting more languages.

Therefore, I redefined the validator’s responsibilities:

The validator is responsible for the structural safety that machines can reliably verify.

Whether cross-lingual technical semantics are correct should not be disguised as a static structural validation capability.


8. Before Restoration: No Longer Requiring Global Protected Token Order Consistency

The modified Protected Token restoration rules remain very strict.

The model output must satisfy:

  • Correct total token count;
  • No unknown tokens allowed;
  • Each expected token appears exactly once;
  • No missing tokens allowed;
  • No duplicate tokens allowed;
  • Token payloads are still restored verbatim according to the deterministic mapping.

The only thing removed was:

All tokens must strictly maintain a single global original order.

At the same time, the boundary normalization for inline tokens was adjusted to be based on:

The token order in the model’s actual output

It is executed this way, and the corresponding rules are judged based on each token’s own type.

This allows the model to adjust positions for natural expression in the target language, but it still cannot:

  • Delete code;
  • Duplicate code;
  • Modify code;
  • Fabricate tokens;
  • Substitute protected content.

9. After Restoration: Letting present Structural Validation Truly Take Responsibility for Structural Safety

Removing the global order restriction does not mean abandoning strict validation.

On the contrary, the post-restoration structural validation was simultaneously enhanced.

Inline Code

Previously, it required:

Content, count, and order all completely identical.

Now it is adjusted to:

Content and count multiset consistency, while still must correctly parse as a program span.

Therefore:

Plaintext
T / comparable

Can change due to target language word order.

But the following cases must still fail:

  • An inline code snippet disappears;
  • An extra inline code snippet appears;
  • Content is modified;
  • A legacy program span is broken.

10. Legacy Program Spans Still Strictly Protected

methods/20 also contains a very typical legacy present syntax:

Plaintext
`"cannot`Sqrt`negative`number:`-2"`

In present, this is actually a complete program span.

The final page displays it as:

Plaintext
"cannot Sqrt negative number: -2"

This kind of content is still protected as a complete payload.

The model cannot split it, nor can it modify the present encoding within it.

During the final browser check, this section correctly displayed as:

"cannot Sqrt negative number: -2"

There was no internal backtick leakage, and no program span breakage.


11. Links Still Maintain Stricter Rules

Link targets are different from regular inline code.

Currently, they are still strictly checked for:

  • Target content;
  • Target count;
  • Target’s own order;
  • Whether the target is still within a valid link structure.

In other words, although a:

Plaintext
link target

can have a cross-category positional change with an adjacent Sqrt due to Chinese word order, multiple link targets still cannot be arbitrarily swapped with each other for now.

This is an intentionally conservative strategy.

There are currently no real cases proving that multiple links must be swapped for target language word order, so there is no need to prematurely broaden the relaxation scope.


12. Preformatted Code Still Strictly Validated Block by Block

For preformatted code, the rules remain strict.

Continuing to check:

  • Code block count;
  • Code block order;
  • Static code block bytes;
  • Code structure within translatable instructional comments;
  • The Section to which the code block belongs.

Therefore, although this time it allowed:

Plaintext
`error`
→ code block

To be adjusted to:

Plaintext
code block
→ `error`

It absolutely does not allow:

Plaintext
first code block
↔ second code block

To be swapped.

Nor can a code block be moved to another Section.

This is exactly:

Natural language can be reorganized, but structural objects themselves cannot be destroyed.


13. Directives Also Added Section-Level Protection

Directives like .play and .image also continue to be strictly checked for:

  • Content;
  • Count;
  • The directive’s own order;
  • The Section to which it belongs.

In addition, a rule that machines can stably determine was added this time:

If the source directive is the last element in its Section, it must also remain the last element in the candidate.

For example:

Plaintext
.play methods/exercise-errors.go

It not only determines the code file, but also determines the position where the example code appears on the instructional page.

If the model moves the .play, originally located at the end of the page, into the middle of the explanatory text, even if present can still parse it, it should be considered a structural protection failure.

However, I did not further require:

Directives must maintain the exact same relative position with all regular text paragraphs.

Because regular natural language may inherently be split, merged, or have its expression order adjusted due to translation.


14. Fixed Translation Prompts Must Also Be Synchronized

Modifying only the validator is not enough.

The previous fixed zh-CN translation prompt also required:

Protected Token count, order, and form consistency.

If the validator already allows natural word order adjustments, but the prompt still requires strict global order consistency, the two sets of rules contradict each other.

Therefore, the prompt was synchronized and modified this time:

  • All Protected Tokens must be fully preserved;
  • Each token must appear exactly once;
  • Must not be modified;
  • Must not be deleted;
  • Must not be copied;
  • Must not be fabricated;
  • Necessary positional adjustments for natural target language word order are allowed;
  • But structural relationships such as links, code, directives, and preformatted code must not be broken.

This is not a special rule just for Chinese.

It is more suitable as a common principle to follow for future multilingual expansions:

Protect structure, not English word order.


15. The Most Critical Validation: No New GLM-5.2 Call

After the modifications were completed, I did not immediately perform a second translation.

Because if I called GLM-5.2 again, even if the new result passed, it could not directly prove:

The old result was truly only rejected by an incorrect validation rule.

Therefore, I kept the original generated by the first translation:

  • request.json
  • response.json
  • validation.json

Then I directly used the modified production code to perform a deterministic replay on the same original attempt-001 response.

That is to say:

The model output itself remained completely unchanged.

Only the validation rules changed.

Old result:

Plaintext
protected token order mismatch at 1
protected token order mismatch at 2
protected token order mismatch at 6
protected token order mismatch at 7
protected token order mismatch at 10
protected token order mismatch at 11

Under the new rules, the same response:

  • token integrity: PASS
  • token restoration: PASS
  • present parsing: PASS
  • inline-code: PASS
  • link target: PASS
  • preformatted block: PASS
  • directive: PASS
  • emphasis / font span: PASS
  • glossary: PASS
  • Section structure: PASS
  • candidate validation: PASS

This replay was crucial.

It directly proved:

What failed was not the translation, but the old validation rule.


16. Therefore, No attempt-002 Was Created

Since the original attempt-001:

  • API request was normal;
  • finish_reason=stop;
  • All 16 tokens were intact;
  • Fully passed after fixing the rules;
  • Manual review found no technical mistranslations;

Then calling GLM-5.2 again just for the sake of process formality has no practical meaning.

Ultimately, it still retains:

Plaintext
methods/20
ready
Attempts=1

A second model translation that did not actually exist was not fabricated.

The historical record of the first failure was also not overwritten.

The old validation.json still retains the six order failures from that time, serving as complete historical evidence for this rule evolution.


17. Final Manually Polished Translation

The final adopted translation is as follows:

Plaintext
* 练习:错误

从[[/tour/flowcontrol/8][之前的练习]]中复制你的 `Sqrt` 函数,并修改它,让它返回一个 `error` 值。

当传入负数时,`Sqrt` 应当返回一个非 nil 错误值,因为它不支持复数。

创建一个新类型

	type ErrNegativeSqrt float64

并为其实现

	func (e ErrNegativeSqrt) Error() string

方法,使其实现 `error` 接口,这样 `ErrNegativeSqrt(-2).Error()` 就会返回 `"cannot`Sqrt`negative`number:`-2"`。

*注意:* 在 `Error` 方法中调用 `fmt.Sprint(e)` 会导致程序陷入无限循环。可以先转换 `e` 来避免这个问题:`fmt.Sprint(float64(e))`。为什么?

修改 `Sqrt` 函数,使其在传入负数时返回一个 `ErrNegativeSqrt` 值。

.play methods/exercise-errors.go

Main manual adjustments include:

  • Changed “前一个练习” to “之前的练习”;
  • Changed “并修改它使其返回” to “并修改它,让它返回”;
  • Changed “非 nil 的错误值” to “非 nil 错误值”;
  • Changed “使它成为一个 error” to the more accurate “使其实现 error 接口”.

Then re-executed the formal candidate translation validation:

Plaintext
candidate OK: locale=zh-CN page_id=methods/20

18. Actual Browser Comparison of English and Chinese Pages

After completing the candidate translation validation, I also started the local Tour to perform an actual browser comparison between the methods/20 English original page and the Chinese candidate page.

English Original Page

Figure 1: A Tour of Go methods/20 "Exercise: Errors" English original course page
Figure 1: A Tour of Go methods/20 “Exercise: Errors” English original course page

The English page here can serve as a reference for the final visual structure, including:

  • Body text;
  • Cross-section link;
  • Two preformatted Go code blocks;
  • Note prompt;
  • Right-side exercise-errors.go example.

Chinese Candidate Page

Figure 2: A Tour of Go methods/20 "Exercise: Errors" Chinese candidate page final rendering

The Chinese page screenshot particularly illustrates intuitively why this modification was necessary.

For example, the old validator once rejected:

Plaintext
fmt.Sprint(e)
→ Error

Becoming:

Plaintext
Error
→ fmt.Sprint(e)

But from the final Chinese page, you can directly see:

在 Error 方法中调用 fmt.Sprint(e) 会导致程序陷入无限循环。

This is exactly normal and natural Chinese expression, and it did not cause any present structural damage.

The actual browser comparison confirmed:

  • The “练习:错误” title is normal;
  • The “之前的练习” link is normal;
  • The positions and content of the two Go code blocks are correct;
  • "cannot Sqrt negative number: -2" renders normally;
  • Internal backticks for the legacy present are not exposed;
  • “注意:” is correctly bolded;
  • The Chinese remains natural after adjusting the order of Error and fmt.Sprint(e);
  • The exercise-errors.go corresponding to .play loads normally;
  • The page has no present parsing, rendering, or runtime exceptions.

Therefore, the final browser results further prove:

The three groups of Protected Token reorders rejected by the old rule did not cause structural problems, but were instead normal cross-lingual word order adjustments.


19. Complete Tests Pass Again

After the fix was completed, and the methods/20 commit status baseline was synchronized, the complete tests passed again:

Plaintext
ok github.com/shuijingwan/go-tour-i18n/internal/i18n 0.499s

git diff --check also all passed.

Final commit:

Plaintext
13d9129b3bb0223b5e39af7679868832352e3b42

Commit message:

Plaintext
feat: 完成 methods/20 并修复受保护标记顺序校验

Subsequently pushed to origin/main.

Project repository:

https://github.com/shuijingwan/go-tour-i18n

20. Biggest Takeaway This Time: Structural Safety Does Not Equal Unchanged English Order

This issue made one thing clearer to me.

When developing a multilingual translation system, it is easy to conflate:

“Original structure”

And:

“Original surface order”

But they are not the same thing. For example:

Plaintext
fmt.Sprint(e)
→ Error

Is natural order in English.

In Chinese, however, it is more naturally written as:

Plaintext
Error
→ fmt.Sprint(e)

What truly needs to be maintained is:

  • Error is still a correct program span;
  • fmt.Sprint(e) has not been modified;
  • Neither is missing;
  • present can still parse correctly;
  • The technical meaning remains correct.

Rather than:

The two strings must forever be arranged in the order they appear in English.

Similarly:

“从之前的练习中复制你的 Sqrt 函数”

Should not be judged a structural failure just because the link target appears before Sqrt.


21. Stricter Automatic Validation Does Not Mean Higher Quality

This issue also has a very worthwhile lesson to record: strict validation itself is not the goal.

If a rule can reject a large amount of content but cannot distinguish between:

  • Actual structural damage;
  • Normal cross-lingual word order adjustments;

Then the stricter the rule, the more false positives it produces.

A good automatic validator should check facts that machines can truly determine as strictly as possible.

For example:

  • Whether tokens are missing;
  • Whether there are duplicates;
  • Whether there are unknown tokens;
  • Whether code has changed;
  • Whether link targets have been modified;
  • Whether directives still belong to the correct Section;
  • Whether preformatted code blocks have been swapped;
  • Whether present can still parse correctly.

As for:

“After inline code is reordered, is the cross-lingual technical semantics still correct?”

If static structure cannot reliably determine this, this boundary should be acknowledged, rather than designing a seemingly strict but actually unreliable pseudo-semantic rule.


22. Next Step: Complete the Final 3 Representative Pages

Currently, the representative page calibration phase has completed 4 pages:

  1. generics/1
  2. flowcontrol/8
  3. methods/16
  4. methods/20

Next, it has been decided to continue processing another 3 different types of representative pages.

concurrency/7

The only formal page in the official course that contains .image.

Main validations:

  • .image directive;
  • Image and text mixed layout;
  • Non-tail directive;
  • JavaScript target link.

concurrency/11

Long, multi-paragraph, high-link-density page.

Main validations:

  • Large number of link targets;
  • Cross-paragraph links;
  • slides forced term labels;
  • Long text stability without code and directives.

methods/24

API documentation-style page.

Main validations:

  • Longer static interface code block;
  • Multiple API links;
  • Emphasis paragraphs;
  • Tail .play.

If these 3 pages also pass stably, the total representative pages will reach 7.

At that point, we will be ready to end this phase of page-by-page calibration and enter:

Automatic trial run of 10 regular pending pages.

If the 10-page trial run continues to be stable, we will then enter the batch translation phase for the remaining pages.


Conclusion

methods/20 was originally just another planned representative calibration page.

Ultimately, however, it helped this project discover and fix a more fundamental issue:

The global order of Protected Tokens is not a reliable multilingual structural invariant.

The most convincing part this time is that I did not bypass the problem by:

“Translating again until it passes”

Instead, I kept the original failed response, fixed the validator, and then let the same model output go through the complete production validation again.

This ultimately proved: GLM-5.2 had actually translated successfully the first time.

What truly needed correction was the automatic validation system’s definition of “structural safety”.

For a project preparing to expand from Simplified Chinese to more languages, this kind of issue is more important than completing any specific page itself.

Because what truly needs to be built is not a set of rules that “tries to make translations maintain the surface order of the English original”.

But rather a multilingual translation process that allows different languages to express themselves naturally, while still strictly protecting code, links, directives, and present structures.

关于作者 · 持续学习与技术实践

我是一名拥有 15 年以上开发经验的技术从业者,自 2013 年起持续运营个人技术博客,记录工作与个人项目中遇到的真实问题,以及解决问题过程中的探索、实践和思考。

除了技术写作,我也在持续开发和维护自己的独立项目,探索新技术和新工具在实际场景中的应用。我始终相信,没有不值得去解决的问题,也没有不值得去学习的技术。

如果这篇文章对你有所帮助,欢迎浏览博客中的其他文章,也欢迎交流技术经验与想法。

关于我  ·  GitHub  ·  邮件联系