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

A Tour of Go Chinese Translation: How to Translate Only Code Comments Without Breaking Go Code

Figure 1: Browser preview of the methods/16 Simplified Chinese page

作者:

在

,

Recently, I continued advancing the Simplified Chinese translation calibration for the go-tour-i18n project.

In the previous record, the generics/1 page encountered consecutive issues with protected token duplication, order changes, and legacy present inline code boundaries. This time, I started processing a new representative page:

Plaintext
methods/16 — Type switches

This page is not long, but it raised an issue that had not been carefully determined before:

For code blocks in the left-side lesson text of A Tour of Go, if they contain English instructional comments, should these comments be translated?

It is already established that the Go example code in the right-side editor must remain exactly as the official version. However, the left-side tutorial code blocks are not exactly the same, and the comments within them are often part of the lesson explanation.

This time, rather than choosing to “keep the entire code block in English” or allowing the model to freely modify the entire code block, I implemented a more fine-grained approach:

Only allow the translation of comment text that can be confirmed as instructional explanation, while strictly protecting non-comment code, indentation, comment positions, and Go identifiers within the comments.

1. First Translation: All Tokens Correct, but Structure Validation Failed

methods/16 introduces Go’s type switches. The English original contains the following code:

Go
switch v := i.(type) {
case T:
	// here v has type T
case S:
	// here v has type S
default:
	// no match; here v has the same type as i
}

When executing the GLM-5.2 translation for the first time, the API call completed successfully:

  • HTTP status: 200
  • protected tokens: 15
  • missing: none
  • duplicate: none
  • unknown: none
  • order errors: none

The model also naturally translated the three comments:

Go
switch v := i.(type) {
case T:
	// 这里 v 的类型为 T
case S:
	// 这里 v 的类型为 S
default:
	// 没有匹配;这里 v 与 i 的类型相同
}

However, the candidate was not generated.

The validator reported:

Plaintext
protected structure validation failed:
preformatted code mismatch at index 3

expected:
		// here v has type T

actual:
		// 这里 v 的类型为 T

The reason was straightforward: the validation rules at the time required all preformatted code content to match verbatim. Even if the model only modified the comments, it was still treated as a change to the code block.

2. Should Left-Side Code Comments Be Translated?

Initially, I considered the most conservative solution:

Replace the entire preformatted code block with a protected token, making the code block completely invisible to the model.

This approach is simple to implement and the safest. The model cannot modify keywords, variables, indentation, or comments.

But it also brings an obvious problem: important instructional comments in the left-side tutorial would remain in English forever.

The three comments in methods/16 are not optional supplements; they directly explain the type of the variable v in each branch of the type switch:

  • In case T, the type of v is T;
  • In case S, the type of v is S;
  • In default, v retains the same interface type as the interface value i.

For Chinese learners, these comments are themselves part of the lesson text.

Therefore, I re-distinguished between two types of code.

Right-Side Runnable Examples

The right-side editor loads the official .go file via the .play directive.

In the first phase, we continue to:

  • Keep the Go code as-is;
  • Not translate code comments;
  • Keep filenames and example behavior consistent with the official version;
  • Not maintain a copy of the code for each language.

Left-Side Instructional Code Blocks

The left-side code blocks are embedded directly in the lesson text, and the natural language comments within them may serve an instructional purpose.

Therefore, a more reasonable rule is:

  • The Go code itself cannot be modified;
  • Explanatory comments can be translated;
  • Code-style comments and type tags remain as-is;
  • If the purpose cannot be confirmed, choose not to translate.

3. Auditing All 103 Official Pages

Before modifying the implementation, I first performed a read-only audit of all official pages of the Tour.

The audit scope included:

  • 7 .article files;
  • 103 official pages;
  • Using golang.org/x/tools/present to actually parse Sections;
  • Only counting present.Text{Pre:true} in the parsed results;
  • Using a Go scanner to identify comments, rather than simply searching for //.

The audit results are as follows:

ItemCount
Official pages103
Pages containing preformatted code blocks35
Total preformatted code blocks57
Total lines in code blocks136
Go code blocks without comments44
Go code blocks with // comments13
With /* ... */ block comments0
Unable to safely classify0

Of the 13 code blocks containing line comments, about 10 contain natural language explanations worth translating.

For example:

Go
byte // alias for uint8

rune // alias for int32
     // represents a Unicode code point

These comments are suitable for translation into:

Go
byte // uint8 的别名

rune // int32 的别名
     // 表示一个 Unicode 码点

Also, in the pointers page:

Go
fmt.Println(*p) // read i through the pointer p
*p = 21         // set i through the pointer p

And in the channels page:

Go
ch <- v    // Send v to channel ch.
v := <-ch  // Receive from ch, and
           // assign value to v.

These comments all have clear instructional significance.

However, not all comments should be translated. For example:

Go
// int
// float64
// complex128
// OK
// len(a)=5
// len(b)=0, cap(b)=5

These are type names, status markers, or code-style results. Translating them is meaningless and could even break the technical meaning.

4. Final Choice: Only Translate Confirmed Instructional Comments

After comparison, I ultimately adopted a more fine-grained approach:

Scan the left-side preformatted Go code blocks, and only expose the confirmed natural language instructional comment text to the model, protecting everything else.

The processing flow is roughly as follows:

  1. Use present parsing to determine preformatted code block boundaries;
  2. Use go/scanner and scanner.ScanComments to scan the code;
  3. Accurately identify actual Go comments;
  4. Exclude // inside strings, raw strings, and URLs;
  5. Determine whether a comment is a natural language explanation, a type name, a code expression, or a static marker;
  6. Only expose the translatable comment text;
  7. Replace all non-comment code, indentation, newlines, and // markers with protected tokens;
  8. After restoration, perform independent validation by the validator.

Code blocks that cannot be reliably confirmed fall back to the most conservative strategy: keeping the entire block as-is.

5. Why We Can’t Just Protect Code and Ignore Identifiers in Comments

After implementing comment-level protection for the first time, the code structure of methods/16 could no longer be modified by the model, but a security gap remained.

The comment text the model sees was still:

Plaintext
here v has type T
here v has type S
no match; here v has the same type as i

Among these:

Plaintext
v
i
T
S

are all identifiers in the Go code.

Although the model happened to preserve them in the second translation, we cannot rely on the model to do so every time. The model might translate v into “variable”, change T to lowercase t, or drop an identifier.

Therefore, the protector added another layer of logic:

  1. Collect token.IDENT from the non-comment code in the same code block;
  2. Find these identifiers within the translatable comment text;
  3. Replace each occurrence with an independent protected token;
  4. Only pass the remaining natural language to the model.

For methods/16, the actual protected identifier sequence is:

Plaintext
[v, T]
[v, S]
[v, i]

The content the model actually receives is equivalent to:

Plaintext
here TOKEN_v has type TOKEN_T
here TOKEN_v has type TOKEN_S
no match; here TOKEN_v has the same type as TOKEN_i

This way, natural language like “here”, “has type”, and “no match” can be translated, while v, i, T, and S must be preserved exactly as-is.

6. Validator Does Not Rely on API Token Validation

Protecting identifiers only when calling GLM-5.2 is not enough.

The candidate may subsequently undergo manual polishing. If a human accidentally deletes i in a comment, or changes T to t, the protected token validation at the API stage can no longer help.

Therefore, the validator will independently re-check:

  • Whether the number of comments is consistent;
  • Whether the order of comments is consistent;
  • Whether the positions of // are consistent;
  • Whether comments still belong to their original code lines and branches;
  • Whether non-comment bytes match verbatim;
  • Whether the number, case, and order of code identifiers in comments are consistent;
  • Whether translatable comments have been changed to empty content;
  • Whether non-translatable comments remain as-is.

In other words, regardless of whether the translation comes from GLM-5.2 or subsequent manual modifications, it must pass the same set of checks.

7. Second Translation Passes Successfully

After completing comment-level protection, I executed the second development-mode translation for methods/16.

The results were:

  • HTTP status: 200
  • prompt tokens: 1669
  • completion tokens: 501
  • total tokens: 2170
  • protected tokens: 19
  • missing: none
  • duplicate: none
  • unknown: none
  • out of order: none
  • present validation: passed
  • candidate: successfully generated
  • page status: ready

The three comments generated by the model were:

Go
// 此处 v 的类型为 T
// 此处 v 的类型为 S
// 没有匹配;此处 v 与 i 的类型相同

After manual polishing, they were finally changed to:

Go
// 此时 v 的类型为 T
// 此时 v 的类型为 S
// 没有匹配项;此时 v 的类型与 i 相同

“At this point” is more appropriate for describing the variable type inside a branch, and “no match” is more complete than “no match”.

8. Manual Polishing Discovers an Emphasis Structure Issue

After the candidate was generated, I manually polished the body text.

The English original uses:

Plaintext
_type_switch_

In present syntax, underscores denote italics.

The correct Chinese structure should be:

Plaintext
_类型选择_

But during one manual modification, it was mistakenly written as:

Plaintext
*类型选择*

Asterisks denote bold in present.

The candidate validator at the time still passed. This showed that although the original validator could check inline code, it did not compare italic and bold structures.

Therefore, a general font structure validation was also added in this round.

Now the validator uses present’s own parsing and style processing results to compare:

  • The number of italic spans;
  • The number of bold spans;
  • The number of program spans;
  • The types and order of various spans;
  • Whether spans have been split or merged.

The text within an emphasis range can be translated normally, but the structure cannot be changed.

For example:

Plaintext
_type_switch_

Translated as:

Plaintext
_类型选择_

can pass.

Changing it to:

Plaintext
*类型选择*

must fail.

9. Final Translation

After technical validation and manual polishing, the final content of methods/16 is:

Plaintext
* 类型选择

_类型选择_ 是一种可以连续执行多个类型断言的语法结构。

类型选择与普通的 switch 语句类似,但类型选择的 case 指定的是类型而不是值;这些类型会与给定接口值中所保存值的类型进行比较。

	switch v := i.(type) {
	case T:
		// 此时 v 的类型为 T
	case S:
		// 此时 v 的类型为 S
	default:
		// 没有匹配项;此时 v 的类型与 i 相同
	}

类型选择中的声明与类型断言 `i.(T)` 使用相同的语法,
只是将具体类型 `T` 替换为关键字 `type`。

这个 switch 语句会检查接口值 `i`
中保存的值是否为 `T` 或 `S` 类型。
在 `T` 和 `S` 两个 case 中,变量 `v` 的类型分别为
`T` 和 `S`,并保存 `i` 中的值。
在 default 分支中(即没有匹配项时),变量 `v`
的接口类型和值均与 `i` 相同。

.play methods/type-switches.go

10. Browser Preview Verification

After the automated validation passed, I launched the local Tour preview:

Plaintext
http://127.0.0.1:3999/tour/methods/16

The actual inspection results included:

  • HTTP status is 200 OK;
  • The page title is “类型选择”;
  • No residual GTI18N tokens;
  • _类型选择_ is rendered as <i>, not <b>;
  • The three Chinese instructional comments are fully displayed;
  • switch, case, default, and type remain as-is;
  • v, i, T, and S have no changes;
  • 14 inline code elements are all rendered as independent <code> elements;
  • The right-side type-switches.go loads normally.
Figure 1: Browser preview of the methods/16 Simplified Chinese page
Figure 1: Browser preview of the methods/16 Simplified Chinese page

From the actual page, the Chinese comments in the left-side code block did not affect the code structure, and they are more suitable for Chinese learners than keeping them in English.

11. New Terms Added in This Round

This time, the following mandatory terms were also added:

YAML
type switch: 类型选择
type switches: 类型选择
type assertion: 类型断言
type assertions: 类型断言
interface value: 接口值
interface type: 接口类型
concrete type: 具体类型

The current matcher does not automatically handle singular and plural forms, so:

Plaintext
type switch
type switches

and:

Plaintext
type assertion
type assertions

need to be recorded separately.

switch statement, default case, and dynamic type have not been added yet. The first two can be expressed flexibly based on the specific sentence, and the latter has no actual use cases in the current Tour.

12. Final Commit

The changes in this round were finally committed as:

Plaintext
728adbc feat: 完成 methods/16 并增强代码注释与强调校验

Commit statistics:

Plaintext
19 files changed, 1186 insertions(+), 26 deletions(-)

The commit has been pushed to the main branch on GitHub.

Before committing, the following were completed:

  • internal/i18n full testing;
  • methods/16 candidate validation;
  • git diff --check;
  • Staging area inspection;
  • Manual browser preview.

The final working tree is clean, and the local main and origin/main remain in sync.

13. Current Project Status

As of August 6, 2026:

  • Official pages: 103
  • ready: 11
  • pending: 92
  • blocked: 0

Currently, the representative calibrated pages completed include:

  • generics/1
  • flowcontrol/8
  • methods/16

The next page will be:

Plaintext
methods/20

It will continue to verify other special structures in the methods and interfaces sections.

14. Comparison Regarding Chrome Web Translation

When I was studying A Tour of Go previously, I mainly relied on Chrome’s web translation feature.

Browser translation is indeed very convenient, but when faced with lesson text, Go code, instructional comments, the editor interface, and special present syntax, it is difficult for it to accurately determine what should be translated and what must be preserved.

This time, I will not expand on the comparison between Chrome translation and the project’s translation. Once more representative pages are completed, I plan to select a few pages with different structures and separately prepare a hands-on review article comparing:

  • Technical meaning of the text;
  • Go code protection;
  • Instructional comment processing;
  • Terminology consistency;
  • Links and special structures;
  • Editor interface;
  • Long-term maintainability.

That article will be better suited to fully answering one question:

What is the exact difference between a purposefully maintained Chinese version of A Tour of Go and instant browser translation?

Conclusion

The first failure of methods/16 was not because the model’s translation was too poor, but because the project had not yet determined the content policy for left-side instructional code comments.

If we chose to protect the entire block, it would be technically simplest, but the core instructional explanations in the Chinese course would remain in English.

If we allowed the model to freely translate the entire code block, it might modify keywords, identifiers, strings, operators, or indentation.

The finally adopted approach lies between the two:

Only translate confirmed natural language instructional comments, and perform deterministic protection and independent validation on the code, comment structure, and identifiers within comments.

This time, we also unexpectedly discovered the issue where italics were changed to bold without being intercepted, and further supplemented the present font structure validation.

From the results, the value of the representative page calibration phase is not just completing a few more pages, but rather using each real page to gradually determine translation boundaries, and turning rules that originally relied on human experience into repeatable, executable program validations.

系列导航

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

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

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

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

关于我  ·  GitHub  ·  邮件联系