Build a Multilingual Blog Site with Hexo and Minos

In this article, I will show you how to build your own blog site with Hexo and Minos.

Install Node.js and Git

If you already have both installed on your computers, great! You can skip to Install Hexo.

Node.js

Node.js provides official installer for most platforms.

For installing via package manager, refer to the guide provided by Node.js.

Git

Git also provides official installer for most plaforms.

Install Hexo

Once Node.js is installed, you can install Hexo with npm:

1
$ npm install -g hexo-cli

For MacOS user, if you encounter a permission error, try use sudo together with the command above.

You can check Hexo’s version to see if it’s successfully installed (the version you see may differ from below):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ hexo -version

hexo-cli: 4.3.0
os: darwin 20.5.0 11.4

node: 14.15.3
v8: 8.4.371.19-node.17
uv: 1.40.0
zlib: 1.2.11
brotli: 1.0.9
ares: 1.16.1
modules: 83
nghttp2: 1.41.0
napi: 7
llhttp: 2.1.3
openssl: 1.1.1g
cldr: 37.0
icu: 67.1
tz: 2020a
unicode: 13.0

Install Minos

Before installing Minos theme, you have to create a Hexo site:

1
$ hexo init my-blog-site

Then go into the site folder (in this case my-blog-site):

1
$ cd my-blog-site

Now install Minos theme:

1
$ git clone https://github.com/ppoffice/hexo-theme-minos.git themes/minos

Configure Hexo

Only multilingual site related settings are mentioned here. For general configuration, refer to Hexo documentation.

Open the _config.yml file under the root folder of your blog site.

Specify Theme

Set theme to minos:

1
2
3
4
# Extensions
## Plugins: https://hexo.io/plugins/
## Themes: https://hexo.io/themes/
theme: minos

Specify Supported Languages

Set language to the languages you want to support. In my case, I want to support both English (en) and Chinese (zh-cn), and English is the default language.

1
2
3
language:
- en
- zh-cn

Note that the values like zh-cn should match exactly the language file name under themes/minos/languages/.

Customize Permalink and New Post Name

Set permalink and new_post_name as below:

1
2
3
permalink: :lang/:title/

new_post_name: :lang/:title.md # File name of new posts

Configure Minos

In /themes/minos folder, there is an example theme config file named _config.yml.example. Make a copy of it and rename it _config.yml. In our case, this will be the config file for the default language, i.e. English.

Then make another copy from _config.yml.example and rename it _config.zh-cn.yml. This will be the config file for the Chinese version of our site.

Note that now we have three _config.yml files. What is the precedency?

When generating static files, the configuration takes effect in following order:

  1. read settings specified in front-matter in invididual posts/pages, override the counterparts in language specific config YAML file
  2. if current language is not the default language, read corresponding config file, e.g. _config.zh-cn.yml when the language is zh-cn and override the counterparts in _config.yml in theme folder
  3. read _config.yml in theme folder, override the counterparts in _config.yml in Hexo site root folder
  4. read _config.yml in Hexo site root folder

I’ll take navigation bar menu links as an example, other fields like title, author, etc. can also be set the same way.

Specify Menus in English

In _config.yml under themes/minos/ folder, set the menus as below (This is only an example, you may want to set it to the menus fulfill your need):

1
2
3
4
5
6
# Navigation bar menu links.
menu:
Archives: /archives
Categories: /categories
Tags: /tags
About: /about

Specify Menus in Chinese

In _config.zh-cn.yml under themes/minos folder, set the menus as below:

1
2
3
4
5
6
# Navigation bar menu links.
menu:
归档: /zh-cn/archives
分类: /zh-cn/categories
标签: /zh-cn/tags
关于: /zh-cn/about

Create New Posts

When creating a new posts, explicitly specify the language of this post, for example:

1
$ hexo new post "hello world" --lang en

This will create a hello-world.md file under source/_posts/en.

1
$ hexo new post "hello world" --lang zh-cn

This will create a hello-world.md file under source/_post/zh-cn.

Note that it’s better to keep the same post in different language the same file name, because when a user wants to see a different language version and select target language from UI, Hexo will only prepend the language code, e.g. zh-cn to the post title in the URL address. If the same post of different languages has different file name, Hexo won’t be able to find it.

Limitations

Here are some limitations I find for current version of Hexo (5.4.0) and Minos (2.4.0)

Create New Pages

Creating new pages of language other than the default language doesn’t work, so I created them manually.

Take my about page for example, the folder structure is as below:

1
2
3
4
5
6
7
8
- source
|-- _posts
|-- about
|-- index.md
|-- gallery
|-- zh-cn
|-- about
|-- index.md

Read More

By default, blogs are shown fully in the home page. To enable Read More button in the home page, you have to add <!-- more --> in the .md file. While after you click on it, the page will be redirected to Read More anchor in the blog page, not from the beginning.

I see there are some hexo plugins out there that can help to add excerpt dynamically based on the word count in the blog but not sure if they are compatible with Minos. I’ll try out and update.

Image Preview

Minos by default enables a out-of-box gallery plugin. Any picture files located under source/gallery/ can be used by any post/page directly via following syntax:

1
![](/gallery/a-beautiful-picture.jpeg)

And it can be loaded from the home page successfully.

Though I could put every single picture of my posts in this gallery folder, it is not a good choice to me to manage the images.

I enabled post asset folder in Hexo’s _config.yml:

1
post_asset_folder: true

In this way every post I created will associate with a folder of the same name, for example:

1
2
3
4
5
6
- source
|-- _posts
|-- en
|-- hello-world
|-- forest.jpeg
|-- hello-world.md

I can put all the images belong to this post, e.g. forest.jpeg, in the folder and use it with below syntax:

1
![Forest](forest.jpeg)

Note there is no / before the image file name.

This gives me a more organized structure while it also has a problem: in home page, the images in gallery folder can be renderred but the ones in the post’s folder will break.

The root cause is that in the home page, the src of the image file is still the relative one, i.e. forest.jpeg, but currently we are at the root folder of the site.

Not sure if this is a bug of Hexo or Minos, I’ll dig further and get back.

Update 08/05/2021

This can be fixed by setting following fields in _config.yml under site root folder:

1
2
3
4
post_asset_folder: true
marked:
prependRoot: true
postAsset: true

More discussion see Image cannot be load by relative path using markdown syntax

Google AdSense

Minos, unlike NexT, doesn’t support Google AdSense out of the box.

While the author of Minos, ppoffice, has another theme named icarus that supports Google AdSense. I’ll see if I can merge that to Minos.

Deploy the Site

Netlify

Personally I’m a fan of Netlify for frontend stuff. In addition, one advantage of deploying on Netlify is that it supports private GitHub repositories.

  1. Create a new site on Netlify
  2. Select the repository you want to deploy (link your Netlify account to your GitHub account first if you haven’t done so)
  3. Configure the settings, e.g. branch to deploy, build command, publish directory, etc.
  4. Click “Deploy site”, sit back and relax, Netlify will do the rest

GitHub

Deploying hexo site on GitHub pages is documented in details in this guide.

Reference

  1. Hexo Documentation
  2. Minos Documentation
  3. A Step-by-Step Guide: Hexo on Netlify
276 Paint Fence

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×