Hexo 配置 i18n
运营个人博客时,可能会遇到这样的需求:希望网站能够支持多语言,让来自不同地区的读者都能便捷地阅读我们的内容。
这就需要用到网站的国际化(也就是 i18n)功能。
对于使用 Hexo 搭建的博客而言,实现国际化不仅需要考虑内容的翻译,还要处理模板渲染等问题。
基础配置
为了避免困扰:
- Hexo 根目录下的
_config.yml
将被称呼为 Hexo 配置项themes/**/_config.yml
将被称呼为 主题配置项
首先,我们需要在 Hexo 的配置文件中进行一些基本设置。这些设置将决定网站的语言选项和 URL 结构。
1 | language: [zh, en] # 支持的语言列表,第一个为默认语言 |
接着在主题配置项里配置想要的菜单链接:
1 | menu: |
目录结构
以下是必需的目录结构:
1 | source/ |
当然,你也可以选择其他语言,但其他语言的目录需要和对应的
themes/**/languages/*.yml
的名称相同。
请确保每个 *.md
的 Front-Matter 中都有 lang: **
。
语言文件配置
网站的固定文本(如导航菜单、按钮文字等)需要通过语言文件来实现国际化。这些文件需要放在 themes/**/languages/
目录下。
这是我的例子:
-
zh.yml
:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16menu:
home: 首页
archive: 归档
tags: 标签
categories: 分类
about: 关于
friendlinks: 友情链接
archive_title: 归档
tags_title: 标签
categories_title: 分类
prev: 上一页
next: 下一页
prev_post: 上一篇
next_post: 下一篇
more: ...阅读全文
translated: 翻译 · 原文地址 -
en.yml
:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16menu:
home: HOME
archive: ARC
tags: TAGS
categories: CATE
about: ABOUT
friendlinks: Friend Links
archive_title: Archive
tags_title: Tags
categories_title: Categories
prev: PREV
next: NEXT
prev_post: PREV POST
next_post: NEXT POST
more: ...MORE
translated: Translate · Original Link
模板文件实现
从这里开始,只写关于我的博客网站所用的方案。
请按照自己的主题,自行进行修改。
分类页面模板
分类页面需要两个模板:分类列表页面和具体分类页面。
-
分类列表页面(
category-index.pug
):1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20extends partial/layout
block container
.archive
// 标题内容优先使用 page.title
// 如果不存在则使用国际化函数 __() 获取 categories_title 的翻译
h2.archive-title= page.title || __('categories_title')
.category-list
// 获取所有分类数据
each category in get_categories().data
// 对每个分类计算符合当前语言的文章数量
- var postCount = category.posts.data ? category.posts.data.filter(post => post.lang === page.lang).length : 0
if postCount > 0
.category-item
// 每个分类显示为一个链接,包含分类名称、文章数量计数
// url_for_lang() 生成多语言支持的 URL
- var categoryPath = category.slug || category.name
a.post-title-link(href=url_for_lang(page.lang, 'categories/' + categoryPath))
= category.name
span.category-count= ` (${postCount})` -
具体分类页面(
category.pug
):1
2
3
4
5
6
7extends partial/layout
block container
include mixins/post
.archive
h2.archive-title= page.category
+postList()这里文章显示相关的功能被封装成了一系列混入(mixins),方便在不同页面重用(
mixins/post.pug
):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
28mixin postInfo(item)
.post-info
!= full_date(item.date, 'l')
// 如果文章有 from 属性且当前页面是首页或者文章页
if item.from && (is_home() || is_post())
// 显示一个表示文章翻译来源的链接
a.post-from(href=item.from target="_blank" title=item.from)!= __('translated')
mixin posts()
ul.home.post-list
// 遍历所有的文章
- for (var post of page.posts.data || [])
// 只显示与当前页面语言匹配的文章
- if (post.lang == page.lang)
li.post-list-item
article.post-block
h2.post-title
a.post-title-link(href= url_for(post.path))
!= post.title
+postInfo(post)
// 如果有摘要,就显示摘要和“阅读全文”链接
if post.excerpt
.post-content
!= post.excerpt
a.read-more(href= url_for(post.path))!= __('more')
else
.post-content
!= post.content
标签页面模板
和分类页面模板近乎一致:
-
tag-index.pug
:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22extends partial/layout
block container
include mixins/post
.archive
h2.archive-title= page.title || __('tags_title')
.tag-list
each tag in get_tags().data
- var postCount = tag.posts.data ? tag.posts.data.filter(post => post.lang === page.lang).length : 0
if postCount > 0
.tag-item
- var tagPath = tag.slug || tag.name
a.post-title-link(href=url_for_lang(page.lang, 'tags/' + tagPath))
= tag.name
span.tag-count= ` (${postCount})`
block pagination
include mixins/paginator
+home()
block copyright
include partial/copyright -
tag.pug
:1
2
3
4
5
6
7
8
9
10
11
12
13
14extends partial/layout
block container
include mixins/post
.archive
h2.archive-title= page.tag
+postList()
block pagination
include mixins/paginator
+home()
block copyright
include partial/copyright
归档页面模板
归档页面只需要一个 archive.pug
:
1 | extends partial/layout |
它调用的混入:
1 | mixin postList() |
导航栏实现
导航栏是实现语言切换的关键接口(nav.pug
)。
由于我的博客主题中,导航栏并不宽,因此我写了顶底部来区分开部分链接:
1 | ul.nav.nav-list |
使用方法
完成上述配置后,创建新文章时需要在 Front-Matter 中指定语言:
1 | --- |
如果想创建同一篇文章的其他语言版本,只需要创建一个新的 Markdown 文件,指定相应的 lang
,并在 Front-Matter中通过 from
字段关联原文:
1 | --- |