A Pitfall Record from Building a Multilingual Site: Interface Language ≠ Article Language
When I first added multilingual support to this site, I thought all I needed was a language switcher in the footer and letting AI translate the articles. In practice, the issues turned out to be more numerous than expected.
The core point is: interface language, theme configuration language, and article content language cannot be conflated into one concept.
- Interface language: UI copy like navigation, footer, buttons, dates.
- Theme configuration language: theme fields like Hero description, hitokoto, and the "About / More / Contact" in the footer.
- Article language: the actual content versions that exist for an article.
If you only have a Japanese interface, but an article has no Japanese translation, you can't pretend it's a Japanese article, nor can you let the link just 404.
Issues Encountered This Time
Initially, the language switcher would directly include the language in the URL, e.g., /ja/posts/.... But an article might not have a corresponding Japanese version, leading to a disjointed experience:
- User switches to the Japanese interface;
- Clicks an article that only exists in Chinese;
- The page enters the Japanese route;
- No Japanese content is found, resulting in a 404.
Another issue was that the system sometimes auto-detected article content as English. As a result, publishing or notification redirects would go to the English path; and if the backend only configured English as a translation target, an English original would no longer be translated into Chinese, leaving the Chinese site without a viewable version.
Traditional Chinese also exposed a typical problem: zh-TW was incorrectly normalized to zh. It seemed like just a language code detail, but it affected theme configuration, article queries, and API validation:
theme/yohaku.zh-TWclearly exists;- The aggregation API, however, looks for
theme/yohaku.zh; - The footer thus falls back to Simplified Chinese;
- Later, even if the frontend could navigate to
zh-TW, the API would reject the request because it only allowed two-letter language codes.
Current Approach
The site retains five interface languages:
The backend AI translation target languages are also configured to these five.
But it doesn't generate five copies for every article; instead:
For example:
| Original Language | Auto-generated Translations |
|---|---|
Simplified Chinese zh | Traditional Chinese, English, Japanese, Korean |
English en | Simplified Chinese, Traditional Chinese, Japanese, Korean |
Traditional Chinese zh-TW | Simplified Chinese, English, Japanese, Korean |
This way, we avoid redundant translation of the original, and ensure every site language has a real content version, preventing 404s after switching.
Original Language Should Be Declared by the Author
Stop letting the system auto-guess the article language from the content.
Now, the article editor should have a "Content Language / Original Language" field. Authors select the true original language when publishing; if not specifically chosen, it defaults to Simplified Chinese.
This is important because the original language affects:
- Which language to exclude from auto-translation;
- The content hash for translation tasks;
- Which translations need to be regenerated when the article is updated later;
- Notifications, redirects, and content availability checks.
AI can observe the language during translation, but it must not silently override the author-declared original language.
Theme Configuration Should Also Be Overridden by Language
Simplified Chinese theme configuration can serve as the base; for other languages, only maintain the fields that need translation, for example:
There's no need to copy visual configurations like colors, layout, or fonts. This way, when you later change the theme styles, you only need to modify the base configuration.
Traditional Chinese needs to use a unified canonical code:
You can't write zh-TW in some places and collapse it to zh in others. Otherwise, theme overrides, article translations, and API queries will each get different answers.
Boundaries Still to Watch
Auto-generating multilingual translations presupposes that the translation tasks ultimately succeed.
If translation for a certain language fails, it's better to make it visible in the backend task center with retry support, rather than silently showing an empty page on the frontend. For existing old articles, you can manually trigger a full translation task after configuration is complete; subsequently, when articles are updated and saved, the system can incrementally fill in missing or outdated translations.
The biggest takeaway this time: multilingualism is not just adding a prefix to the URL, nor is it a simple translate button.
It requires a clear contract:
As long as content, interface, and theme layers all use the same set of normalized language codes, the multilingual experience won't suddenly break when switching.
Pitfalls of Multilingual Translation