魔改 Chirpy 主题构建适配 Polyglot 插件的 Jekyll 双语博客
如何自己手动修改 Chirpy 主题的模板,构建功能完全的,顺畅的 Polyglot 双语博客。
在 Polyglot 的 Issue 区下,我发现有人问如何在 Chirpy 主题下配置 Polyglot。
Chirpy 现在已经是当之无愧的 Jekyll 技术写作类博客模板一哥。而毕竟 Polyglot 是一款具有独特实现方式的小众插件,想让大多数主题内置对 Polyglot 的支持并不现实。得自己动手折腾起来啦。
基础修改
Chirpy 官方提供了两种部署方式。一种是使用 Starter 仓库模板创建项目,另一种是直接 fork 主题再加以修改。前者的好处是更新方便,后者的好处是能更多地魔改主题。
如果要自定义这个主题,必须选择后一种方式。否则,所有的网页模板文件都会内嵌在主题的 gem 里,无法手动修改。
Polyglot 执行上的原理是在编译整个项目时扫描整个项目,把每种语言生成一遍内容。最后在 _site
目录下,主语言站点在根目录下,而每种非主语言会各存在一个完整网站的目录。
在生成网站时,变量 site.active_lang
会以当前正在生成的语言标识符赋值。Jekyll 采用 Liquid 模板生成 HTML。可以在网页的模板中根据 Liquid 语法引用这些内容,比如如此修改网站标题界面来实现自动切换不同语言的网站标题:
1
2
3
4
<h1 class="site-title">
<a href="/">交界处的空间站</a>
</h1>
<p class="site-subtitle fst-italic mb-0">各类技能笔记</p>
不同语言创作的文章需要放在对应语言标识符的目录下,但是具有相同的文件名,比如我的这个网站英语是主语言,中文文章都会放在 _post/zh-CN
下。
而 Chirpy 默认一个站点只选用了一种语言,由 _config.yml
下的 lang
参数定义。在渲染过程中,绝大多数语言相关的模板词条采用的都是_data
目录下定义的变量赋值,然后再由 site.data.locales[site.lang].variable_name
引用该变量。
为了能适配 Polyglot,我们需要把所有涉及到 [site.lang]
的内容都改成 [site.active_lang]
。建议使用 vscode 之类的文本编辑器的全项目文件搜索替换实现。记得加完整词条匹配设置。
更加具体的使用方法,也可以外加参照 Polyglot 官网对这一特性的介绍。
菜单选择器
如果要让读者能在各种界面都自由调换语言,就需要在 _include/sidebar.html
里添加一个语言选择菜单。
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
<div class="sidebar-bottom d-flex flex-wrap align-items-center w-100">
<div class="lang-div d-flex flex-wrap w-100" >
<p style="font-weight: bold;" id="language"> {{site.data.locales[site.active_lang].tabs.languages}}
</p>
</div>
<!-- jekyll-polyglot will process ferh= into href= through the static_href liquid block tag without relativizing the url; useful for making language navigation switchers -->
<div class="lang-div d-flex flex-column">
{% for tongue in site.languages %}
<p class="lang-name-box">
{% if tongue == site.active_lang %}
<a class="lang-name" id="current-lang" style="font-weight: bold;">
{{ site.data.locales[tongue].tabs.lang_name }}
</a>
{% else %}
{% if page.lang-exclusive %}
{% assign is_lang_exclusive = false %}
{% for lang in page.lang-exclusive %}
{% if tongue == lang %}
{% assign is_lang_exclusive = true %}
<span>This language is in the lang_ex list</span>
{% endif %}
{% endfor %}
{% if is_lang_exclusive == false %}
<a class="lang-name disabled-lang">
{{ site.data.locales[tongue].tabs.lang_name }}
</a>
{% else %}
<a class="lang-name" {% static_href %}href="{% if tongue == site.default_lang %}{{site.baseurl}}{{page.url}}{% else %}{{site.baseurl}}/{{ tongue }}{{page.url}}{% endif %}"{% endstatic_href %}>
{{ site.data.locales[tongue].tabs.lang_name }}
</a>
{% endif %}
{% else %}
<a class="lang-name" {% static_href %}href="{% if tongue == site.default_lang %}{{site.baseurl}}{{page.url}}{% else %}{{site.baseurl}}/{{ tongue }}{{page.url}}{% endif %}"{% endstatic_href %}>
{{ site.data.locales[tongue].tabs.lang_name }}
</a>
{% endif %}
{% endif %}
</p>
{% endfor %}
</div>
</div>
这里用了一个比较复杂的写法,判断当前页面有没有对某种语言单独呈现。最后实现的效果就是如果没有对应语言页面,则该按钮不包含超链接,且具有独特的 disabled-lang
class,方便处理 CSS。
上一篇文章里忘了讲对应的 CSS 怎么做,需要修改 _sass/addon/common.sass
,在 .sidebar-bottom
内增加如下内容:
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
.lang-name-box {
font-family: 'NotoColorEmojiLimited', -apple-system, BlinkMacSystemFont,
'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji',
'Segoe UI Emoji', 'Segoe UI Symbol';
margin: 0.1rem;
margin-bottom: 0.15rem;
.lang-name {
padding: 0.8rem;
border: 1px solid transparent;
border-radius: 25%/75%;
width: 100%;
text-align: left;
font-size: 0.9rem;
margin-bottom: 0.1rem;
justify-content: left;
color: var(--sidebar-active-color);
// background-color: var(--sidebar-bg);
}
.disabled-lang {
background-color: var(--sidebar-disabled-color);
color: #ff0000;
&:hover {
background-color: #ffe3e5;
}
}
#current-lang {
background-color: var(--sidebar-hover-bg);
}
}
.lang-div {
margin-bottom: 0.2rem;
padding: 0;
}
#language {
font-size: 1.1rem;
margin-bottom: 0.3rem;
}
这里为了能在 Windows 平台上也显示出国旗,我特意选择了 NotoColorEmoji
作为语言选项栏字体的首选 font-family
。
1
2
3
4
5
@font-face {
font-family: NotoColorEmojiLimited;
unicode-range: U+1F1E6-1F1FF;
src: url(https://raw.githack.com/googlefonts/noto-emoji/main/fonts/NotoColorEmoji.ttf);
}
RSS 定制化
Chirpy 的作者自制了主题的 RSS 输出格式。RSS 文件在 assets/feed.xml
里。
我个人比较喜欢全文输出的 RSS。所以对其进行魔改。主要是把 <summary>
和 <content>
改一下。这样,RSS 就可以输出全文了。
1
2
3
4
5
6
7
<summary></summary>
<content type="html">
<![CDATA[
{%- include no-linenos.html content=post.content -%}
{{- content | html -}}
]]>
</content>
使用 no-linenos.html
模板是为了移除代码块的行数。
SEO 优化
Chirpy 主题采用的 SEO 优化插件是 jekyll-seo-tag。jekyll-seo-tag 默认取 site.title
、site.description
和 site.lang
为 SEO 内容的 <meta>
标签赋值。
这就和我们之前提到的需要改用 site.active_lang
来选取的特定语言的对应变量有所冲突。
直接修改 seo.html
不能解决这个问题。我做了一个专门适用于 Polyglot 的 jekyll-seo-tag 作为临时解决方案。需要在 jekyll-theme-chirpy.gemspec
中移除或注释掉使用 jekyll-seo-tag 的那一行。同时在 GEMFILE
中引入我的修改版插件。
1
2
3
4
5
6
7
8
9
10
11
12
# jekyll-theme-chirpy.gemspec
spec.required_ruby_version = "~> 3.1"
spec.add_runtime_dependency "jekyll", "~> 4.3"
spec.add_runtime_dependency "jekyll-paginate", "~> 1.1"
spec.add_runtime_dependency "jekyll-redirect-from", "~> 0.16"
# spec.add_runtime_dependency "jekyll-seo-tag", "~> 2.8" <- remove it
spec.add_runtime_dependency "jekyll-archives", "~> 2.2"
spec.add_runtime_dependency "jekyll-sitemap", "~> 1.4"
spec.add_runtime_dependency "jekyll-include-cache", "~> 0.2"
1
2
3
4
5
6
7
8
# GEMFILE
group :jekyll_plugins do
gem "jekyll-polyglot"
gem "jekyll-seo-tag", git:"https://github.com/aturret/jekyll-seo-tag-polyglot.git" # my version of the plugin
end
如果是在本机测试,别忘了使用 bundle install
和 bundle update
安装这个新的插件。
此外,Polyglot 也有自带的 SEO 解决方案。建议把两个都加上。即在 head.html
中,在 SEO 的段落之前加入 `
`。
1
2
3
4
5
6
<meta http-equiv="Content-Language" content="zh-CN">
<link rel="alternate" hreflang="en" href="https://aturret.space//posts/:title/"/>
<link rel="alternate" hreflang="zh-CN" href="https://aturret.space/zh-CN//posts/:title/"/>
<!-- Setup Open Graph image -->
可能引发的 Vercel 部署错误
不知道为什么,采用自定义插件之后,每次 Vercel 自动部署都会在 git fetch
环节报错。似乎是因为其环境配置不支持从 GitHub 仓库获取 Ruby gem 导致的。
不想思考那么多了。在 Vercel 的部署环境变量中添加 VERCEL_FORCE_NO_BUILD_CACHE=1
,禁用采用先前环境缓存要求其每次部署都从头编译,即可解决这个问题。这样一来,每次部署时间会从40秒提升到80秒。但对于静态博客来说重要的是省心,这点时间问题不是事。