DEV Community

Shiqiang Wang
Shiqiang Wang

Posted on

How I Maintain A Tour of Go in 11 Languages

A Tour of Go is one of the first resources many developers encounter when learning Go.

It is interactive, concise, and closely connected to the Go ecosystem. But for developers who are more comfortable learning technical concepts in their native language, language can still be a barrier.

That is why I started maintaining go-tour-i18n, an unofficial, community-maintained multilingual version of A Tour of Go.

Today, the project has 11 translations running in production:

  • Brazilian Portuguese
  • Dutch
  • French
  • German
  • Italian
  • Japanese
  • Korean
  • Simplified Chinese
  • Spanish
  • Swedish
  • Turkish

The project is open source:

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

Several of these translations are also linked from the official A Tour of Go localization page:

https://go.dev/tour/welcome/2

The project is still unofficial and community-maintained.

But after maintaining more and more languages, I learned that translating the text itself is only a small part of the work.

Translation is the easy part

At first, a translation project can look simple:

  1. Take the English source.
  2. Translate it.
  3. Publish the result.

That works until the upstream project changes.

Then other problems begin to appear:

  • terminology becomes inconsistent;
  • code or identifiers are accidentally changed;
  • translated pages fall behind upstream;
  • structurally valid translations still sound unnatural;
  • metadata and UI text do not match the translated course;
  • a new language works locally but is incomplete in production.

For a technical tutorial, a translation can be grammatically correct and still be technically wrong.

It can also pass every structural check and still be poor writing.

So I eventually stopped thinking of this project as a collection of translated pages.

I started treating it as a translation, review, synchronization, and publishing system.

TranslationUnit is the basic unit of work

The project uses a concept called a TranslationUnit.

For a Tour page, one TranslationUnit is a complete top-level page section.

For an eligible Go example, the TranslationUnit is the complete Go source file, while only permitted natural-language comments are translated.

I do not split a page into arbitrary text fragments just because smaller pieces are easier for a model to translate.

Keeping the unit complete makes it possible to associate translation work with a stable source identity and then validate, review, revise, and promote that unit as a whole.

This makes it easier to answer questions such as:

  • Which version of the English source was translated?
  • Which glossary was used?
  • Did the candidate pass mechanical validation?
  • Was its language quality actually reviewed?
  • Has the source changed since the translation was produced?
  • Is the version currently in production still valid?

Once the project expanded beyond one language, those questions became much more important.

Terminology comes before translation

Every locale has its own glossary.

This turned out to matter much more than I expected.

Technical terminology cannot always be handled by literal translation.

Some words should remain in English.

Some have well-established translations in one language but not another.

A term that feels natural to a Japanese developer may need a completely different treatment in Brazilian Portuguese, German, or French.

Because of that, I do not create a new locale by simply machine-translating another locale's glossary.

Terminology decisions are made for each language independently.

The glossary is then treated as part of the translation input rather than as a cleanup step after translation.

Validation is not language quality

This is probably the most important lesson from the project.

The project performs automatic validation designed to protect things that translation must not break, including:

  • code;
  • Go identifiers;
  • URLs;
  • link targets;
  • directives;
  • protected tokens;
  • preformatted content;
  • structural relationships;
  • machine-readable semantics.

Those checks are necessary.

But passing them does not mean that a translation is good.

A sentence can preserve every protected token and still be awkward.

It can preserve the exact technical structure while expressing the idea incorrectly.

It can even be technically understandable while sounding obviously machine-translated to a native speaker.

So the workflow deliberately separates mechanical validation from language-quality review.

A simplified version of the current process looks like this:

glossary preparation
→ translation
→ automatic validation
→ Candidate Snapshot
→ language quality review
→ machine finalization
→ promotion
→ deployment
Enter fullscreen mode Exit fullscreen mode

Automatic validation answers a question like:

Is this candidate structurally safe?

Language review answers a different question:

Is this translation actually good enough to publish?

I do not treat “validator passed” as equivalent to “translation finished.”

That distinction becomes increasingly important as AI makes translation faster.

AI makes translation faster, but review matters more

AI makes a project like this possible at a scale that would have been much harder for me to maintain alone.

But I do not treat model output as final content.

The current workflow uses AI for work that genuinely requires language understanding, while deterministic tooling handles things such as:

  • source identity;
  • structural validation;
  • protected content;
  • workflow state;
  • stale detection;
  • finalization gates;
  • promotion;
  • production verification.

After automatic validation, every TranslationUnit still needs a language-quality decision before it can be promoted.

If a translation has a language problem, the correct response is to revise the translation.

The validator is not changed simply to make a poor translation pass.

That sounds obvious, but when automation becomes sophisticated, it is surprisingly easy to confuse a successful pipeline with a successful result.

Upstream synchronization matters

A translation of A Tour of Go is not very useful if it slowly becomes a translation of an old version of A Tour of Go.

The project therefore tracks the official Go upstream.

When source content changes, the affected source identity changes as well.

That gives the project a deterministic way to identify translated content that needs attention instead of rebuilding every language blindly.

With one language, manual comparison may be manageable.

With eleven languages, and potentially many more in the future, it needs to be systematic.

The larger the language set becomes, the more important stale detection becomes.

A language is more than its lesson text

Another lesson was that translating course pages is not enough.

A real locale also has other user-facing surfaces:

  • navigation;
  • shared UI messages;
  • language selectors;
  • article metadata;
  • course metadata;
  • SEO descriptions;
  • runtime messages;
  • public URLs;
  • production configuration.

A locale can have excellent lesson translations and still feel unfinished if the surrounding interface contains English leftovers or inconsistent terminology.

So after the TranslationUnits are promoted, the project performs a separate locale-level surface review.

This is intentionally different from TranslationUnit quality review.

One checks individual translation units.

The other checks whether the complete locale works as a coherent product.

Production is part of the workflow

I also wanted each translation to be more than a directory of files in a Git repository.

Each completed locale becomes a real, independently accessible Tour site.

That introduces another set of concerns:

  • building a complete locale;
  • previewing it;
  • checking public routes;
  • deploying it;
  • configuring its public hostname;
  • validating production behavior;
  • handling search engines and sitemaps;
  • keeping future deployments repeatable.

This is one reason the project gradually became much more of an engineering project than I originally expected.

Translation is still at its center.

But reliable multilingual publishing requires much more than translation.

Why I keep the project unofficial

Some of the translations are linked from the official A Tour of Go localization page, which has been very encouraging.

But I still describe the project clearly as unofficial and community-maintained.

It is not maintained by Google, the Go team, or go.dev.

The original Tour source comes from the official Go upstream, while this repository maintains the translation, validation, review, synchronization, and production workflow around those localized versions.

I think making that distinction explicit is important for an open-source community project.

Where the project is today

There are currently 11 translations in production:

  • Brazilian Portuguese
  • Dutch
  • French
  • German
  • Italian
  • Japanese
  • Korean
  • Simplified Chinese
  • Spanish
  • Swedish
  • Turkish

And I am continuing to add more.

The long-term challenge is no longer simply:

How quickly can I translate another language?

It is increasingly:

How can I add languages without making the existing ones harder to maintain?

That means continuing to improve the workflow for terminology, translation, review, stale detection, upstream synchronization, metadata, production, and future maintenance.

Feedback is especially valuable

The project is here:

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

The official A Tour of Go localization page is here:

https://go.dev/tour/welcome/2

If you are a native speaker of one of the supported languages, feedback is especially welcome.

The most useful feedback is often not about obvious broken code or missing text.

It is about sentences that are technically correct but still do not sound like something a developer would naturally say in that language.

Automation can find many classes of problems.

That kind of language judgment is much harder.

And as the project grows, it is also one of the things I value most.


Disclosure: I used AI assistance to help organize and edit this article. The project, implementation experience, workflow decisions, and conclusions described here are my own.

Top comments (0)