The original goal of this multilingual project was actually quite simple:
Translate A Tour of Go.
The initial problems we needed to solve were basically all centered around the Tour.
For example, how to get AI to translate full pages instead of processing them sentence by disconnected sentence; how to protect Go code, inline code, and links; how to prevent code comments from breaking program structure during translation; how to add independent review after generation; how to revise only the TranslationUnits that actually had problems instead of retranslating entire batches; and finally, how to stably publish the reviewed content to the website.
Around these questions, the project gradually formed a fairly complete workflow.
From Generation, machine validation, and Independent Review, to revision, re-QC, promotion, and Surface Review, all the way to final Production, the multilingual translation of A Tour of Go was no longer just “handing English to AI and saving the Chinese result.”
This system was already working fairly stably during the Tour phase.
But as the project moved forward, one problem became increasingly obvious:
What if, in the future, we want to translate more than just A Tour of Go?
This is where v2 truly begins.
The Tour is no longer the project’s only boundary
On the official Go website, there is certainly far more content suitable for localization than just A Tour of Go.
Besides the Tour, there is the website’s own Site shell—namely the navigation, page entry points, and some common interface content; there is Learn; and there is a large amount of Docs.
If the project continues to expand in the future, it may also add more content packages.
At that point, if we still understood the entire system as:
“The A Tour of Go translation project, with a few extra pages supported on the side.”
Many design decisions would start to feel awkward.
The Tour has its own content structure.
Learn and Docs heavily use Markdown, which may also contain headings, lists, links, inline code, code blocks, instructional code comments, and various structures that must be protected.
The Site shell is not a regular article; it is closer to website-level interface content.
Beyond that, there is also navigation, the Homepage, local coverage, canonical, sitemap, 404, Surface, and the final Production that the user actually sees.
So later I became increasingly certain:
This was no longer simply “adding a few dozen more translation pages.”
If we kept patching outward around the Tour’s old boundaries, the maintenance cost would only get higher and higher.
Therefore, this time I decided to make a more complete architectural adjustment.
This is what we now call v2.
v2 is not “version 2 of the translation”
The v2 here has nothing to do with “retranslating the original Chinese from scratch.”
It is more like a redefinition of the project’s boundaries.
The project is moving from:
A Tour of Go multilingual translation
gradually toward:
Go Learning & Documentation multilingual localization.
The Tour remains very important, but it is no longer the only content type around which the entire architecture needs to be built.
The new architecture needs to account for all of these simultaneously:
Site shell, Tour, Learn, Docs, and any other content packages that may appear in the future.
The real question therefore became:
Among these contents, what should be independent of each other, and what should be shared?
This question later influenced many important designs in v2.
Not duplicating a Tour setup for Learn and Docs
The simplest implementation approach is actually easy to think of.
Since the Tour already has a translation workflow, we could just duplicate it for Learn, and duplicate it again for Docs.
In the short term, this might even be the fastest way.
But if we actually did this, another set of problems would quickly emerge.
The Tour has a glossary.
Learn has a glossary.
Docs gets another glossary.
The Tour has its own review status.
Learn and Docs establish separate review statuses.
When adding a new content package later, duplicate it all over again.
The problem with doing this is not that “it won’t run,” but that the same capability will constantly fork.
The same Go term might need to be decided separately in different packages.
The same quality rules might have several slightly different implementations.
A single workflow improvement would also require repeated changes in multiple places.
As the project grows larger, the amount of duplication grows as well.
So the most important direction for v2 is not:
Building another Tour setup for Learn / Docs.
Instead, it is stepping back and rethinking:
What should Tour, Learn, and Docs inherently share?
Locale should be the more stable boundary
One obvious answer is the language itself.
Whether content comes from the Tour, Learn, or Docs, as long as it belongs to the same locale, it should use consistent language standards.
For example, the same Go concept in Simplified Chinese should not have one translation when it appears in the Tour and then have a different one decided all over again when it appears in Docs.
Therefore, a major change in v2 is further promoting the glossary to the locale level.
A single locale maintains only one official glossary.
Different content packages can continuously expand the scope of terminology discovery, but the final terminology governance should not be duplicated as the number of packages grows.
On the surface, this is just “maintaining a few less files,” but the actual impact is huge.
Because once the glossary becomes the common foundation for the entire locale, another question immediately arises:
If the glossary changes, do all completed translations need to be redone?
Obviously not.
If only a term that appears in a handful of pages is modified, there is no reason to invalidate all TranslationUnits across the entire locale.
As a result, we later further developed semantic compatibility, affected scope, and the question of how to determine which existing content can continue to be reused.
This part alone is worth a separate article.
TranslationUnit also needs to be rethought
The addition of Learn and Docs also brought up another very practical problem:
What exactly should be treated as an official translation unit?
Markdown is very easy to split.
A heading can be extracted on its own.
A paragraph can be a single record.
Each item in a list can also be processed individually.
Even a specific instructional comment inside code can become a standalone string.
From a programmatic processing perspective, the finer the split, the easier it seems.
Each piece of content is short, retries are convenient, and differences are easy to compare.
But once you get into actual language quality, the problem is not that simple.
If a full page is split into dozens of independent small fragments, the context visible to Generation decreases, and the context visible to the Reviewer also decreases.
Forward and backward references can break.
The writing style of adjacent paragraphs might become inconsistent.
Some sentences look fine on their own, but seem very stiff when put back into the full page.
Even some positions that originally needed to be adjusted according to natural Chinese word order end up impossible to handle reasonably because the splitting is too fine.
Therefore, v2 gradually established a clear principle:
The machine can split things internally, but official language governance cannot be shattered along with the internal structure.
An actual Page should still be an official TranslationUnit.
Internally, it can certainly contain slots, protected tokens, link bindings, and various structures used by parsers to protect and reconstruct content.
But these are implementation details.
They are not new official translation units.
This distinction later directly influenced the design of Generation, validation, QC, and revision.
v2 is no longer just handling translation problems
As these things gradually came together, I realized that v2 had actually become a more complete content system.
Once an English page enters the system, it is no longer just:
English
↓
AI Translation
↓
ChineseIt is closer to:
Canonical source
↓
TranslationUnit
↓
Generation
↓
Machine validation
↓
Candidate Snapshot
↓
Independent QC
↓
Exact revision
↓
re-QC
↓
Package
↓
Integrated Surface
↓
Preview
↓
ProductionThe longer this chain becomes, the more important the relationships between states are.
For example:
After terminology changes, which TranslationUnits were actually affected?
If a page hasn’t changed, can the previously completed review results continue to be reused?
If a package’s content changes, is the previous Surface Review still valid?
If an English page currently has no local translation, should the website link to the local URL, or continue linking to go.dev?
If a local route doesn’t exist at all, should it automatically redirect to English, or should it return a real 404?
These questions can no longer easily be categorized as:
“How should this sentence be translated?”
They are more about solving:
How a long-running localization system should manage content, state, dependencies, and trusted results.
History also starts becoming part of the architecture
As the system continues to develop, historical results accumulate.
Previously completed translations, QC, revisions, and promotions obviously cannot all be discarded just because v2 has arrived.
If the source hasn’t changed, the relevant terminology hasn’t changed, and the content hasn’t been affected by other changes, then already high-quality completed translations should continue to be reused as much as possible.
This is also one of the greatest values of preserving history:
Avoiding redoing things that were already done right.
But the development process of v2 also made me gradually realize that history itself likewise needs boundaries.
If continuing current work requires constantly tracing back through Snapshots, predecessors, old promotions, and earlier evidence, or even if restoring an old state requires restoring its prior state, then history can slowly shift from “helping reuse results” to “a prerequisite that drags down current work.”
This is also a fairly important architectural adjustment in this v2.
History should be preserved.
Existing results should also be reused as much as possible.
But the system’s true goal is never to endlessly reconstruct the past.
I plan to write about these issues separately later, because they are actually two different topics:
One is why history is worth preserving;
The other is why history cannot endlessly participate in the current workflow.
The fundamental goal hasn’t actually changed
As v2 has progressed, more and more concepts have appeared in the system.
Glossary.
TranslationUnit.
Snapshot.
Quality Check.
Package.
Closure.
Surface.
Identity.
Various evidence.
Looking only at these things, it’s easy to get an illusion:
It seems like the project’s goal has become establishing an increasingly complex workflow.
But that is not actually the case.
These are all just means to an end.
The project’s true goal has always been simple:
To complete the multilingual translation of Go learning and documentation content as quickly as possible, while maintaining the highest possible quality.
We need a glossary to reduce terminology drift.
We need machine validation so that automatically detectable problems don’t enter human review.
We need an Independent Reviewer to reduce the risk of Generation reviewing itself.
We need history to reuse already completed high-quality results instead of repeating labor.
We need Surface Review because a single page being entirely correct does not automatically mean the entire website combined is also correct.
If a certain engineering mechanism starts making this fundamental goal increasingly hard to achieve, then what really needs to be re-examined might not be the translation, but the architecture itself.
This is also a feeling that became increasingly clear to me during the v2 development process.
Why start writing this series before it officially launches
My original plan was to wait until the Simplified Chinese v2 officially launched, and then consolidate this round of the development process.
But once I actually got to the later stages, I felt this wasn’t quite appropriate.
Because many of the problems that emerged in v2 are already substantial enough to warrant their own separate articles.
If they were all crammed into a single “v2 launch summary” in the end, it would likely just result in:
A few paragraphs on the glossary.
A few paragraphs on TranslationUnit.
A few paragraphs on the parser.
A few paragraphs on performance issues.
A few paragraphs on history recovery.
A few more paragraphs on Surface.
Every problem would be mentioned, but none would be truly explained clearly.
So I decided not to wait until the end to consolidate everything at once.
Problems that have already relatively converged can be documented article by article first.
As for exactly how much time the final launch took, and what new problems were discovered in the final stage, I will leave that for a complete retrospective after Production is truly finished.
Therefore, this article is not:
“Now that v2 is complete, let me summarize it.”
It is just answering the most basic question of the entire series first:
Why does this project need v2?
The answer is now quite clear.
Because what the project needs to solve is no longer just the translation of A Tour of Go.
It is gradually becoming a multilingual localization system capable of simultaneously carrying the Site shell, Tour, Learn, Docs, and more content in the future.
And what is truly worth documenting next is not just how many Chinese pages were ultimately added.
What is more worth documenting is:
Why certain designs were ultimately kept, and why some other designs had to be reworked halfway through.
This might also be the most valuable part of v2.
