Introduction

To create a blog that can be switched between English and Chinese, I researched various tutorials online. Most of them utilize the next theme or the hexo-generator-i18n plugin.

After some searching, I found a solution for bilingual switching by referring to this link.

The general idea involves creating two repositories on GitHub, one for each language, and setting up config.yml and _config.butterfly.yml for both the Chinese and English versions. Locally, two folders, source-en and source-zh, are manually translated into English and Chinese, respectively. Manual translation was chosen due to the unsatisfactory nature of most automatic translation APIs, and the fact that only GPT achieves relatively desirable results, but it’s a paid API.

Step 1 - Create the Second Repository

Refer to this guide and create a repository. This repository should be named with language abbreviations like en, zh, sp, etc., resulting in URLs such as https://username.github.io/en and https://username.github.io/zh, where https://username.github.io is your blog URL.

Note: Ensure the repository is set to public; otherwise, GitHub Pages functionality will require a monthly fee of around $48.

Step 2 - Set up config.yml

  1. Duplicate config.yml, naming one copy config-zh.yml and the other config-en.yml.
1
2
3
4
5
6
7
8
9
10
.
├── node_modules
├── source
├── themes
├── _config.butterfly.yml
├── config-en.yml # <== here
├── config-zh.yml # <== here
├── db.json
├── package-lock.json
└── package.json
  1. Modify/add the following code in the respective files.

config-zh.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Set to Chinese
language: zh-CH

# Use the original URL
url: https://your_url # Modify 'your_url' to replace it with your blog URL, e.g., https://aursus.github.io
root: /

# Specify the startup path
source_dir: source
public_dir: public

# Exclude English source
include:
exclude:
ignore:
- source-en/

deploy:
type: git
repository: https://github.com/YourUserName/YourUserNameURL.git
branch: main

config-en.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Set to English
language: en

# Add en
url: https://your_url/en # Modify 'your_url' to replace it with your blog URL, e.g., https://aursus.github.io/en
root: /en/

# Specify the startup path
source_dir: source-en
public_dir: public-en

# Exclude Chinese source
include:
exclude:
ignore:
- source/

# Modify repository name
deploy:
type: git
repository: https://github.com/YourUserName/en.git # Replace this with your English repository name
branch: main

STEP 3 - Setting up the language-switching JavaScript script

Modify btf.js in source/self, and add the following content. If there is no btf.js, create a new one in that location.

The content of btf.js is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
(() => {
// Check if it's in English
const isIncludeEN = item => {
const key = '/en/'
return item.includes(key)
}

// Create redirection to different language URLs
window.loadFullPage = (url) => {
window.location.href = url
}

// Redirection function
const eventFn = (elements, includeEN) => {
elements.forEach(item => {
if (!includeEN || !isIncludeEN(item.href)) {
item.href = `javascript:loadFullPage('${item.href}');`
}
})
}

// Check if it's currently in English
const nowIncludeEN = isIncludeEN(window.location.href)

// Modify your URL
const selector = nowIncludeEN
? document.querySelectorAll('a[href^="https://<your-url>"]') // Only need to modify this line, replacing https://<your-url> with your blog URL.
: document.querySelectorAll('a[href^="/en/"]')

eventFn(selector, nowIncludeEN)
})()

STEP 4 - Copy the source folder

Duplicate the source folder and rename it as source-en. Ensure that both folders contain the btf.js file inside the source/self directory.

1
2
3
4
5
6
7
8
9
10
11
.
├── node_modules
├── source
├── source-en # <== here
├── themes
├── _config.butterfly.yml
├── config-en.yml
├── config-zh.yml
├── db.json
├── package-lock.json
└── package.json

STEP 5 - Configure config-butterfly.yml

  1. Copy the _config.butterfly.yml file and rename the duplicates as config-butterfly-zh.yml and config-butterfly-en.yml.
1
2
3
4
5
6
7
8
9
10
11
12
.
├── node_modules
├── source
├── source-en
├── themes
├── config-butterfly-zh.yml # <== here
├── config-butterfly-en.yml # <== here
├── config-en.yml
├── config-zh.yml
├── db.json
├── package-lock.json
└── package.json
  1. Modify the config-butterfly-zh.yml and config-butterfly-en.yml files according to the following code.

config-butterfly-zh.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Using Chinese menu
menu:
Home: / || fas fa-home
文章: /archives/ || fas fa-archive
链接: /link/ || fas fa-link
关于我: /about/ || fas fa-heart
语言|| fas fa-language:
English: /en/ || fas fa-e
中文: / || fas fa-c

# inject js
...
inject:
bottom:
- <script data-pjax src="/self/btf.js"></script>

config-butterfly-en.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Using English menu
menu:
Home: / || fas fa-home
Archives: /archives/ || fas fa-archive
Link: /link/ || fas fa-link
About: /about/ || fas fa-heart
Language|| fas fa-language:
English: / || fas fa-e
中文: https://aursus.github.io/ || fas fa-c # change to the url of your blog

# inject js
...
inject:
bottom:
- <script data-pjax src="/en/self/btf.js"></script>

Note: In the config-butterfly-en.yml file, any /img/ images or /self/ JavaScript files must be changed to /en/img/ or /en/self/ for correct display.

STEP 6 - Update package.json

Update the package.json file to generate public-en.

package.json

1
2
3
4
5
6
7
8
9
...
"scripts": {
"push": "hexo clean && hexo g && hexo douban && gulp && hexo deploy",
"show": "hexo clean && hexo g && hexo s",
"update": "git init && git add . && git commit -m 'backup' && git push origin main",
"kk": "hexo clean && hexo g && hexo deploy",
"en": "hexo clean && hexo g --config config-en.yml && hexo s --config config-en.yml"
},
...

STEP 7 - Script Deployment

  1. Make sure the following files exist in your root directory:
1
2
3
4
5
6
7
8
9
10
11
12
.
├── node_modules
├── source # <== here
├── source-en # <== here
├── themes
├── config-butterfly-zh.yml # <== here
├── config-butterfly-en.yml # <== here
├── config-en.yml # <== here
├── config-zh.yml # <== here
├── db.json
├── package-lock.json
└── package.json
  1. Create a file named deploy.sh in the root directory.

deploy.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#!/bin/bash

while [[ "$#" -gt 0 ]]; do
case $1 in
-h|--help)
echo "Usage: bash.sh [en|zh|all|show <en|zh>|-h]"
echo "Options:"
echo " [deploy|d] en Deploy English configuration to GitHub Pages"
echo " [deploy|d] zh Deploy Chinese configuration to GitHub Pages"
echo " [deploy|d] all Deploy both English and Chinese configurations to GitHub Pages"
echo " [show|s] en Execute npm run show for English configuration"
echo " [show|s] zh Execute npm run show for Chinese configuration"
echo " -h, --help Display this help message"
exit 0
;;
d | deploy)
lang=$2
if [ "$lang" = "en" ] || [ "$lang" = "zh" ]; then
cp "config-$lang.yml" _config.yml
cp "config-butterfly-$lang.yml" "_config.butterfly.yml"
npm run kk
echo "Deploy $1 success!"
elif [ "$lang" = "all" ]; then
for lang_choice in "zh" "en"; do
cp "config-$lang_choice.yml" _config.yml
cp "config-butterfly-$lang_choice.yml" "_config.butterfly.yml"
npm run kk
echo "Deploy $lang_choice success!"
done
else
echo "Error! Please input 'en' or 'zh' or 'all'!"
fi
shift
;;
s | show)
lang=$2
if [ "$lang" = "en" ] || [ "$lang" = "zh" ]; then
cp "config-$lang.yml" _config.yml
cp "config-butterfly-$lang.yml" "_config.butterfly.yml"
npm run show
echo "Running npm show!"
else
echo "Error! Please use './bash.sh show en' or './bash.sh show zh'!"
fi
shift # Move to the next argument after 'show'
;;
*)
echo "Error! Please input deploy <en|zh|all> or 'show <en|zh>' or '-h' for help!"
exit 1
;;
esac
shift
done
  1. Run the following commands in Git Bash:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Get help
./deploy.sh -h # This code is equivalent to the following
./deploy.sh --help

# Deploy English to the 'en' repository
./deploy.sh deploy en # This code is equivalent to the following
./deploy.sh d en

# Deploy Chinese to the 'zh' repository
./deploy.sh deploy zh # This code is equivalent to the following
./deploy.sh d zh

# Run locally in English
./deploy.sh show en # This code is equivalent to the following
./deploy.sh s en

# Run locally in Chinese
./deploy.sh show zh # This code is equivalent to the following
./deploy.sh s z

Page Language Translation

Modify config-butterfly.yml

Modify config-butterfly-zh.yml and config-butterfly-en.yml

config-butterfly-zh.yml

1
2
3
4
5
6
7
8
9
10
11
12
translate:
enable: true
# The text of a button
default:
# The language of the website (1 - Traditional Chinese / 2 - Simplified Chinese)
defaultEncoding: 1 # Selecting anything doesn't affect the outcome
# Time delay
translateDelay: 0 # Selecting anything doesn't affect the outcome
# The text of the button when the language is English
msgToEnglish: 'EN'
# The text of the button when the language is Simplified Chinese
msgToSimplifiedChinese: '中'

config-butterfly-en.yml

1
2
3
4
5
6
7
8
9
10
11
12
translate:
enable: true
# The text of a button
default: EN
# the language of website (1 - Traditional Chinese/ 2 - Simplified Chinese)
defaultEncoding: 1 # Selecting anything doesn't affect the outcome
# Time delay
translateDelay: 0 # Selecting anything doesn't affect the outcome
# The text of the button when the language is English
msgToEnglish: 'EN'
# The text of the button when the language is Simplified Chinese
msgToSimplifiedChinese: '中'

Create tw_en.js

  1. Create files ch_en.js in both source/self/ and source-en/self/ directories.

  2. Enter the following code in both ch_en.js files:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
document.addEventListener("DOMContentLoaded", function () {
const { defaultEncoding, translateDelay, msgToSimplifiedChinese } =
GLOBAL_CONFIG.translate;
const msgToEnglish = "EN";
const snackbarData = GLOBAL_CONFIG.Snackbar;
let currentEncoding = defaultEncoding;
const targetEncodingCookie = "translate-en-chn";
let targetEncoding =
saveToLocal.get(targetEncodingCookie) === undefined
? defaultEncoding
: Number(saveToLocal.get("translate-en-chn"));
let translateButtonObject;
const isSnackbar = snackbarData !== undefined;

const isIncludeEN = (item) => {
const key = "/en/";
return item.includes(key);
};

const nowIncludeEN = isIncludeEN(window.location.href);
console.log(nowIncludeEN);

function translatePage() {
let currentUrl = window.location.href;
if (nowIncludeEN) {
// 英文 => 中文简体
translateButtonObject.textContent = msgToSimplifiedChinese;
// 网址: /en/... => /...
let newUrl = currentUrl.replace("/en/", "/");
console.log(`Redirect to ${newUrl}`);
window.location.href = newUrl;
} else {
// 中文简体 => 英文
translateButtonObject.textContent = msgToEnglish;
// 网址 /... => /en/...
let newUrl = currentUrl.replace(/^(https?:\/\/[^\/]+)(\/)?/, "$1/en/");
console.log(`Redirect to ${newUrl}`);
window.location.href = newUrl;
}
}

function translateInitialization() {
translateButtonObject = document.getElementById("translateLink");
if (translateButtonObject) {
if (nowIncludeEN) {
translateButtonObject.textContent = msgToSimplifiedChinese;
} else {
translateButtonObject.textContent = msgToEnglish;
}
translateButtonObject.addEventListener('click', translatePage, false)
}
}
document.addEventListener("pjax:complete", translateInitialization);
translateInitialization();
});

Modifyconfig-butterfly.yml

Modify config-butterfly-zh.yml and config-butterfly-en.yml

config-butterfly-zh.yml

1
2
3
4
5
6
inject:
head:
...
bottom:
- <script data-pjax src="/self/btf.js"></script>
- <script data-pjax src="/self/ch_en.js"></script> # <== here

config-butterfly-en.yml

1
2
3
4
5
6
inject:
head:
...
bottom:
- <script data-pjax src="/en/self/btf.js"></script>
- <script data-pjax src="/en/self/ch_en.js"></script> # <== here

(Optional) Remove tw_cn.js

If the blog still displays with traditional and simplified Chinese conversion, delete the tw_cn.js file located at .\node_modules\hexo-theme-butterfly\source\js.

Reload

Enter the following command in Git Bash to refresh the webpage:

1
./deploy.sh deploy all

If there are any errors, please leave a comment for correction. Thank you.