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:

  1. specifying the theme (e.g. theme = "PaperMod").
  2. defining the language-specific title / description / keywords.
  3. rewrite the menu configuration [[params.menu]] to match the navigation structure of different themes.
  4. 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. ✨

图 0

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. 😉 图 1