Hexo NexT 多语言支持

本文详述如何配置 Hexo NexT 多语言支持。

Hexo 的默认 Index 生成插件 hexojs/hexo-generator-index: Index generator plugin for Hexo. 目前不支持生成多语言版本的 Index 。搜索解决方案的时候有发现这个插件 xcatliu/hexo-generator-index-i18n: I18n index generator plugin for Hexo,它可以为各个语言生成自己的 Index,但如果需要为默认首页设置默认语言则与官方的 Index 插件不兼容,是在早期版本的基础上开发的,缺少hidden, top 的特性。因此我把这两个插件进行了结合,已经提交 PR,未被合并,需要多语言的可以参考以下设置。

使用本地插件生成 index

  1. 新建插件目录
1
mkdir -p plugins/hexo-generator-index
  1. 复制原来的插件到本地
1
cp -r node_modules/hexo-generator-index/* plugins/hexo-generator-index/
  1. 修改 package.json 引用路径
package.json
1
2
3
4
5
6
"dependencies": {
- "hexo-generator-index": "^4.0.0",
……
+ "hexo-generator-index": "file:./plugins/hexo-generator-index",
……
}
  1. 修改插件代码,需要修改两个地方,一个是 index.js, 一个是 lib/generator.js
index.js
1
2
3
4
5
6
7
8
9
10
'use strict';

hexo.config.index_generator = Object.assign({
per_page: typeof hexo.config.per_page === 'undefined' ? 10 : hexo.config.per_page,
order_by: '-date',
layout: ['index', 'archive'],
+ single_lang_index: false
}, hexo.config.index_generator);

hexo.extend.generator.register('index', require('./lib/generator'));
lib/generator.js
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
'use strict';

const pagination = require('hexo-pagination');
const path = require('path');

function generateIndexPage(indexPath, posts, config) {
const paginationDir = config.index_generator.pagination_dir || config.pagination_dir || 'page';

return pagination(indexPath, posts, {
perPage: config.index_generator.per_page,
layout: config.index_generator.layout || ['index', 'archive'],
format: paginationDir + '/%d/',
data: {
__index: true
}
});
}

module.exports = function(locals) {
const config = this.config;
const posts = locals.posts.filter(post => !post.hidden).sort(config.index_generator.order_by);

posts.data.sort((a, b) => (b.sticky || 0) - (a.sticky || 0));

const indexPath = config.index_generator.path || '';
const langs = [].concat(config.language);

if (langs.length <= 1) {
return generateIndexPage(indexPath, posts, config);
}

// Generate default index page
let indexPages = generateIndexPage(
indexPath,
config.index_generator.single_lang_index ? posts.filter(post => post.lang === langs[0]) : posts,
config
);

// Generate index pages for each language
indexPages = [].concat(
indexPages,
...langs.map(lang => generateIndexPage(
path.join(lang, indexPath),
posts.filter(post => post.lang === lang),
config
))
);

return indexPages;
};
  1. _config.yml 中添加多语言配置,single_lang_index 为 true 时,首页只生成第一个语言的文章,默认配置则为 false
1
2
3
4
5
6
7
8
9
10
11
12
13
language: 
- zh-CN
- en

permalink: :lang/:title/

new_post_name: :lang/:title.md

index_generator:
path: ''
per_page: 7
order_by: -date
single_lang_index: true
  1. 配置_config.next.yml
1
language_switcher: true
  1. post 文章结构如下:
1
2
3
4
5
6
7
8
9
10
11
└── workspace/
└── source/
├── _posts/
│ ├── zh-CN/
│ │ ├── welcome.md
│ │ ├── blogpost.md
│ │ └── ...
│ └── en/
│ ├── welcome.md
│ ├── blogpost.md
│ └── ...

配置完成后,就可以对应生成 / 的默认主页,/en 只生成英语文章的 index 页, /zh-CN 只生成中文文章的 index 页。

修改 NexT 的语言转换器配置

NexT 的语言转换器默认行为是,转换语言如果是到默认语言,也就是第一个语言的时候,不会带 :lang 路径,这样如果按照上面的 permalink配置会导致切换语言时路径丢失。我们使用 patch-package 来实现变更。

  1. 安装 patch-package
1
npm install patch-package --save-dev
  1. 修改 node_modules/hexo-theme-next/scripts/helpers/engine.js 文件
engine.js
1
2
3
4
5
6
hexo.extend.helper.register('i18n_path', function(language) {
const { path, lang } = this.page;
const base = path.startsWith(lang) ? path.slice(lang.length + 1) : path;
- return this.url_for(`${this.languages.indexOf(language) === 0 ? '' : '/' + language}/${base}`);
+ return this.url_for(`${'/' + language}/${base}`);
});
  1. 创建补丁
1
npx patch-package hexo-theme-next
  1. 应用补丁:
packge.json
1
2
3
4
5
"scripts": {
……
+ "postinstall": "patch-package"
……
}

这样就可实现多语言的索引页和多语言切换了,建议还要加上404页面的配置,以免语言切换时找不到页面。