Recently, I’ve made a “big move” to my personal blog - I’ve upgraded it I upgraded my blog from a monolingual version to a multilingual site (Simplified Chinese, Traditional Chinese, English, Japanese). And the whole process is automated. 💪
Mainly includes:
- Automatic synchronization of master articles
- Automatic AI translation of content
- Automatically build and deploy multilingual sites
Why Hugo?
Because of its confident slogan:
“The world’s fastest framework for building websites.”
– and with that statement, I decided it was it 😆.
But instead of the traditional “one theme, many languages” approach, I have separate themes for each language. Instead, I have separate themes for each language. This way, each language version retains its own aesthetics and typography. It’s really a “cultural localization”.
Design goals and constraints 🎯
- Languages: support for Simplified Chinese, Traditional Chinese, English, Japanese, with future extensions.
- Themes: use the most appropriate Hugo theme for each language, not forced reuse.
- Content Synchronization: All languages share a common content repository for on-demand translation.
- Deployment strategy: Each language is built and published independently, and can be deployed to different branches or domains.
- Customized pages: Pages like “Links”, “Library”, “Archive”, etc. should be consistent across multiple languages.
Multi-language configuration strategy 🧩
I have a separate configuration file for each language:
config/<lang>.toml, they are mainly responsible for:
- specifying the theme (e.g.
theme = "PaperMod"). - defining the language-specific
title/description/keywords. - rewrite the menu configuration
[[params.menu]]to match the navigation structure of different themes. - Inject custom styles to ensure overall visual consistency.
This structure is very clear and convenient for future expansion of more language versions.
GitHub Actions Automated Deployment Matrix ⚙️
The CI/CD part is left entirely to GitHub Actions.
In .github/workflows/hugo.yml, I use matrix builds that
to build and release independently for each language:
matrix.
include.
- lang: en
config: config/en.toml
publish_branch: dist-en
- lang: zh-cn
config: config/zh.toml
publish_branch: dist-zh
- lang: ja
config: config/ja.toml
publish_branch: dist-ja
- lang: zh-hant
config: config/zh-hant.toml
publish_branch: dist-zh-hant
Build phase 👇
- name: Build ${{ matrix.lang }}
working-directory: hugo-site
run: |
hugo \
--config "${{ matrix.config }}" \
--destination "public/${{ matrix.lang }}"
Release phase 👇
- name: Publish
uses: peaceiris/actions-gh-pages@v3
with.
publish_branch: ${{ matrix.publish_branch }}
publish_dir: hugo-site/public/${{ matrix.lang }}
Final result 🌐🌐
After deployment, I got the following structure:
| Languages | Branching | Domains |
|---|---|---|
| English | dist-en |
en.moejue.cn |
| Simplified Chinese | dist-zh |
zh.moejue.cn |
| Japanese | dist-ja |
ja.moejue.cn |
| Traditional Chinese | dist-zh-hant |
tw.moejue.cn |
The whole process achieves a complete closed loop from content synchronization → automatic translation → independent build → automatic deployment. Next just write the article and let the script run the rest. ✨

Postscript
Before this, both MoeKoe Music Web and MoeKoe Music have started their internationalization programs. The blog never caught up, so I’ll make up for it this time. 😄
The biggest takeaway is not the multilingual site itself: I revisited the whole “how to make content more visible to the world” thing.
Maybe that’s what tossing a blog is all about. 😉
