利用Hexo框架搭建中英文双语网站

2020.4更新

Next主题配置中,现在可以启用在页脚加入语言切换功能。

1
2
3
# Show multilingual switcher in footer.
language_switcher: true

页脚语言切换


2019.12更新

对该方法进行了更新,文中引用的代码适用于Hexo v4.2.0, Next v7.7.0.
请各位根据自己的版本情况进行相应的微调。


概述

Hexo本身有对于博客国际化的多语言的支持。但 是简单倒腾后发现,所谓的国际化只是在显示文章时,根据文章设定的语言将导航栏,侧边栏中的链接名称改为相对应的语言。但博客本身的博文列表中,各个语言的文章仍然混杂在一起。

而我理想中的中英文双语站点可以通过一张图片非常形象的表示出来:
理想网站结构

通过一段时间的搜索,我发现了两种较为可行的方法来实现这个功能。这里我挑选了一个我认为更加合理的方法来实现。

(另一种方法通过两套Hexo+NexT来实现。即构建中英文两个相互独立的Hexo站点。这样做的好处在于结构清晰,两种语言不存在互相干扰的可能。但缺点则是这样子相当于维护两套Hexo站点,每次生成都需要执行两次,致使操作相对繁杂。具体的实现方法详见:https://chenyxmr.github.io/2016/08/04/hexo-bilingual/)

好了,切入正题,接下来我将详细介绍基于hexo-generator-i18n插件的方法。

实现方法

插件安装

首先,安装hexo-generator-i18n插件。相信这条命令大家已经非常熟悉了。

1
npm install hexo-generator-i18n --save

插件成功安装完成后,在Hexo的根目录中找到package.json文件,这个文件记录了已经安装的各个Hexo插件名称及版本号。在这个文件中将hexo-generator-i18n所在的这一行移动到hexo-generator-的最后一行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
"dependencies": {
"canvas-nest.js": "^2.0.3",
"gitment": "0.0.3",
"hexo": "^3.7.0",
"hexo-asset-image": "0.0.3",
"hexo-deployer-git": "^0.3.1",
"hexo-generator-archive": "^0.1.5",
"hexo-generator-category": "^0.1.3",
"hexo-generator-index": "^0.2.1",
"hexo-generator-searchdb": "^1.0.8",
"hexo-generator-tag": "^0.2.0",
"hexo-generator-i18n": "0.0.7",
"hexo-neat": "^1.0.4",
"hexo-renderer-ejs": "^0.3.1",
"hexo-renderer-marked": "^0.3.2",
"hexo-renderer-stylus": "^0.3.3",

(根据观察,每次重新安装完插件的时候该文件会自动根据首字母重新排序,要记得修改顺序。)

修改配置

首先修改Hexo根目录中的配置文件_config.yml的语言选项:

1
2
3
4
5
6
7
#language: 
#- zh-CN
#- en
language: [zh-CN,en]
i18n:
type: [page, post]
generator: [index, archive, category, tag]

完成后保存并退出。尝试运行命令 hexo clean && hexo g 重新生成public文件夹。
此时,public目录下应该会包含了一个新的目录/en。 这个目录就是英文站相关文件所在的路径。每次执行hexo g命令时,所有的博文会在这两个文件目录中各生成一份。此时,如果我们访问网站时,已经可以通过访问 www.yourwebsite.com/en 来进入英文站点。但是,显而易见,在当前条件下,无论文章是以何种语言呈现,所有的文章都会在中英文网站中各出现一次。这显然也不是我们所希望得到的效果。因此,我们还需要找一个方法,让Hexo在生成页面时,根据文章的语言将其呈现在对应的页面中。

注意: 对于NexT v6.0.0以后的版本,务必在主题配置文件中修改配置:

1
2
cache:
enable: false

否则,在语言切换的过程中,菜单栏以及页脚的语言会出现问题。

添加生成条件

首先,在博文(post)的标题处加上lang:标识。简体中文博客标记为lang: zh-CN,英文版则是lang: en。

在 themes/next/layout/index.swig文件中,为

1
{{ partial('_macro/post.swig', {post: post, is_index: true}) }}

添加判断条件。 (题外话:此处使用行内代码写包含{ % % }这样的语句,会使渲染器尝试解析该断代码,并导致Template render error:这样的错误。我找到的相关解决方法)
具体代码如下(记得删除注释):

1
2
3
4
5
6
7
8
9
10
11
12
13
{% block content %}

<div class="posts-expand">
{%- for post in page.posts.toArray() %}
{% if page.lang === post.lang %}
{{ partial('_macro/post.swig', {post: post, is_index: true}) }}
{% endif %}
{%- endfor %}
</div>

{% include '_partials/pagination.swig' %}

{% endblock %}

再加入该语句之后,只有当页面的语言与文章的语言完全一致时,这篇文章才会被生成。此时再打开首页观察一下,所有的文章都已经根据语言分类到对应的页面中了。

同理,如果站点启用了其他导航页面,你希望在这些页面中,显示的文章同样也根据当前页面的语言来显示的话。那就对其相对应的生成页面做相同的改动就可以了。如,我希望更改归档页面,那就找到themes/next/layout/archive.swig, 并为

1
{{ partial('_macro/post.swig', {post: post, is_index: true}) }}

添加判断条件。

但是,这也还没有结束。虽然我们已经有两个基本符合我们想象的中英文页面,但他们却还互不相通。因此,我们还需要在导航栏中创建一个链接来实现中英文页面之间的跳转。

在目录栏中添加切换语言项

首先,找到/themes/next/_config.yml文件,在Menu:下添加switch_lang:关键词:

1
2
3
4
5
6
7
8
9
10
menu:
home: / || home
#about: /about/ || user
#tags: /tags/ || tags
categories: /categories/ || th
archives: /archives/ || archive
#schedule: /schedule/ || calendar
#sitemap: /sitemap.xml || sitemap
#commonweal: /404/ || heartbeat
switch_lang: /en || language

其中,||之后的值为该链接所使用的FontAwesome Icon的标签名,有需要的话可以自行修改。不过话说回来,我觉得主题默认的图标都还是不错的,没什么必要修改。如果||之后没有填写,则会显示问号图标。

然后,再为NexT的语言支持文件添加对应的翻译。这里的例子中需要修改的是/themes/next/languages/下的zh-CN.yml和en.yml文件。在两个文件中分别添加switch_lang:

1
2
3
4
5
6
7
8
9
10
11
menu:
home: 首页
archives: 归档
categories: 分类
tags: 标签
about: 关于
search: 搜索
schedule: 日程表
sitemap: 站点地图
commonweal: 公益 404
switch_lang: -->English
1
2
3
4
5
6
7
8
9
10
11
menu:
home: Home
archives: Archives
categories: Categories
tags: Tags
about: About
search: Search
schedule: Schedule
sitemap: Sitemap
commonweal: Commonweal 404
switch_lang: -->简体中文

细心的话可能已经会发现,之前在Next主题的_config.yml文件中添加的switch_lang:项所对应的链接为/en。这就意味着,如果我们正在浏览英文页面,虽然目录栏中会显示-->简体中文的语言切换栏,但是点击的话则依旧会跳转到/en页面。也就是说,目前这个跳转链接还只是单向可用的!所以我们还需要一步额外的操作,使英文页面在生成时将这个链接更改为指向我们的主页面(中文首页)。

在themes/next/layout/_custom/head.swig中添加下列js代码,使其在加载完英文页面后,将switch_lang所对应的链接地址替换。
source/_data目录下新建head.swig文件,并添加下列js代码
同时在主题配置文件中找到custom_file_path,将head所在行的注释去除。这样,我们的博客在加载完英文页面后,就可以自动将switch_lang所对应的链接地址替换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script type="text/javascript">
// Wait for the page to load first
var _prevOnload = window.onload;
window.onload = function() {
var switchLang = document.getElementById("menu").getElementsByClassName("menu-item-switch_lang")[0].childNodes[1];
var href = window.location.href;
var indexOfEn = href.toLowerCase().indexOf('/en/');
if(indexOfEn !== -1) {
switchLang.href = href.replace('/en/', '/');
}
else {
switchLang.href = href.replace(/(^http[s]?:\/\/[a-z0-9.]*[:?0-9]*\/)(.*)/i, '$1en/$2');
}
}
</script>

这段代码还有改进的空间。如果有合适的意见请在评论中指出。

好了!终于来到最后一步了:hexo clean && hexo g && hexo d 重新生成并部署。现在应该就能看到一个相对比较理想的中英文双语博客了。

存在的问题

当然,通过这种方法实现的Hexo双语网站也还远远没有完善。还有非常多待改进的地方:

  • 文章页面跳转
    暂时全部跳转到首页
  • 分类中全部显示
    在分类生成时加入相应的判断语句
  • 所有文章都会被分别加入两个文件夹,导致数量不对
    直接调用Hexo中的函数,不好改。有兴趣的话可以重写。

参考资料

https://wm4n.github.io/Hexo-NexT-%E5%90%8C%E6%99%82%E6%94%AF%E6%8F%B4%E5%A4%9A%E8%AA%9E%E7%B3%BB/