文章

Jekyll 双语静态博客部署

本博客的部署配置过程记录。

学习编程的路上,我靠博客园和 CSDN 学了不少碎片化的技巧。所以我一直都觉得网上大家用技术博客互相分享日常工作中遇到的问题的氛围很不错,多记记笔记利人利己。技术博客不需要什么复杂的内容和功能,多数时候单纯图文即可。我因此非常钟意在写作、部署和阅读体验上都更加轻量化的静态博客。

19年时候,经此研究,我开始折腾部署静态博客。市面上最流行的三家是 Hugo、Jekyll 和 Hexo。我最开始用 Hexo 配合 Next 主题写了一阵东西(也就是本博客你能看到的20年及之前的文章)。后来那个技术博客荒废了。等到我再想起来弄一个静态博客已经是23年年初,这次我决定用 Jekyll 再来一次。

为什么是静态博客,为什么是 Jekyll ?

如果真的是想写点东西,随便放在哪个文字托管平台上都好。不过我个人比较倾向于使用独立的静态博客,好处如下——这些好处基本上都是和 WordPress 做对比的:

  • 使用免费托管平台即可,不需要自己提供服务器(虽然我也并不缺服务器用)。
  • 数据完全都在自己手里,文本编辑器和渲染流程分离。
  • 可以更简单地自己调整主题甚至添加功能。

做这个博客,除了技术笔记外,我还有另一个需求是一直都很想弄一个双语博客。一方面是希望借此有一个鼓励自己练好英语的写作契机,此外就是觉得这样确实是很装逼很酷。市面上已有的静态博客对无缝丝滑切换多语言站点的支持普遍都不太好,不过我后来发现了 Jekyll 上有一个插件 Jekyll-Polyglot 在多语言站点的实现上表现得很不错,深得我心。再加上之前尝试使用过 Hexo。我的体验是 Hexo 的热度还是相对较低,因此社区支持水平较差。所以这次我决定用生态更好的 Jekyll 做静态博客。

Jekyll 基本使用

Jekyll 官网的教程已经说得很详细了,这里只是指出一些容易误解的点。

Ruby 安装

Jekyll 是用 Ruby 写的静态网页生成框架。所以自己部署 Jekyll 不可避免地要接触一些 Ruby 编程语言。

好消息是 Ruby 的配置比 Java 和 Python 要方便太多。只要按照 Jekyll 官网安装指南里的指路,完全没有坑可以踩。对 Windows 开发环境来说,只要下载一个安装包就可以一键配置 Ruby 开发环境。

Ruby 有一个包管理器 GEM,使用特定项目配置环境时用到的命令是 bundle ,所有 Jekyll 的命令之前都加上 bundle exec 就是在当前目录的特定环境下进行的指令,类似 Node.js 的 npm run。这些东西的用法就和 Python 的 PIP 或者 Node.js 的 NPM 一样。有包管理器使用经验的话就很好上手。

主题和基本配置

静态博客的一大好处是只需要管理自己的文章就好。对其他配置来说,可以低成本一键切换主题换装。在 _config.yml 中定义自己已经在 bundle 中安装好的主题即可切换。

1
2
# Import the theme
theme: jekyll-theme-chirpy

Google 搜索“best jekyll blog theme 2024”就能找到不少结果。一些专门的网站比如 https://jekyll-themes.com/ 上的内容也值得参考。

挑选了一阵主题后,我选择了 Chirpy。这是一个专注呈现文本内容的双栏主题,对文章分类、时间线归档、文本内媒体插入和评论区等博客常用功能的支持非常完善,比较符合我当前的需要。

Chirpy 这样的大型主题提供两种部署方式,一种是从官方的 starter 仓库中复制一套基本的配置文件,另一种是直接 fork 整个项目仓库进行配置。我有一定的编程经验,想要更好地自定义主题的使用,所以选择了后者。

如果是初学者使用 Jekyll,也可以根据官网教程一步步从空项目写配置做起。当然,如果已经有了心仪的主题,最好参考主题制作者提供的教程进行部署,避免自己瞎折腾白忙一场。

静态页面的生成和部署

在进行本地测试时,可以使用 bundle exec jekyll serve 在本地查看静态网站的效果。

如果要把东西放到服务器上给别人看,就需要使用 bundle exec jekyll build 完整生成出整个站点,再让服务器网关把生成的站点目录作为网站根目录提供给外部进行访问。

为了方便,我们一般采用自动化的部署流程:将整个项目目录上传到 GitHub 上,每次更新后让 GitHub Action 进行响应,在临时的虚拟服务器上进行静态站点的生成,再将其上传到我们自己已经设置好的服务器中,实现更新。

好消息是,当前市面上有很多提供一键托管上述内容的服务商。因此,我们只需负责写作和上传到 GitHub 的步骤即可,剩下的内容都由第三方代劳。

GitHub 本身有免费静态页面托管项目 GitHub Pages。此外 VercelNetlify 也是不错的可选托管提供商。本博客目前部署在 Vercel 上。使用自己的 GitHub 账号注册并登录 Vercel ,选择自己的 Jekyll 博客仓库即可实现一键部署并绑定自己的域名。

Jekyll 多语言博客插件 Polyglot

Polyglot 是我在全网搜索静态博客丝滑多语言切换解决方案过程中发现的宝藏。哪怕现在 Next.js 和 Gatsby 的声势浩大,Hugo 使用基数超过了 Jekyll,能轻量级地帮我实现多语言博客需求的也只有它了。

我刚开始调试时候被一个 bug 卡得很惨。于是我就干脆帮忙修了这个 bug 并翻译了这个插件的整个演示网站

基本使用

引入插件,并在 _config.yml 中定义站点会出现的语言和站点的主语言。

1
2
3
4
5
6
plugins:
  - jekyll-polyglot

# polyglot configuration
languages: ["en", "zh-CN"]
default_lang: "en"

如果有其他想要自定义的站点变量,也可以引入语言标识符。比如站点标题,介绍等等。

1
2
3
4
5
6
7
8
9
10
11
title: # the main title
  en: AnotherTurret
  zh-CN: 交界处的空间站

tagline: # it will display as the sub-title
  en: Just another study note blog
  zh-CN: 各类技能笔记

description: # used by seo meta and the atom feed
  en: Just another study note blog
  zh-CN: 干正事博客

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 下。

在每篇文章的 front matter 中,使用 lang 定义该篇文章所属的语言:

1
2
3
title: Jekyll 双语静态博客部署
date: 2024-09-28 11:33:00 -0400
lang: zh-CN

根据 Polyglot 的设计,如果不特别标注,默认下其他语言的子站点也会显示该文章以实现一致。就像很多来不及本地化最新博文的企业官方网站一样。如果希望该文章只在特定几种语言的网站渲染过程中出现,可以使用 lang_exclusive 进行自定义:

1
lang_exclusive: ['zh-CN']

也就意味着,本文章只在中文版网站中出现。英文版的网站不会出现本篇文章的中文版本。

语言选择菜单

对已经生成的网站,想要查看其它语言的内容,只需要在 URL 的路径部分加上你提供的语言标识符,进入该目录即可。比如 example.com/zh-CN/post-title/ 就是简体中文版的该文章。然而,插件只是根据语言数量和语言标识符对同一模板渲染多次,本身并不影响网站前端模板,所以我们需要自己手写 HTML 和 CSS 搓一个语言选择菜单出来。

语言选择器的格式大致如下:

1
2
3
4
5
6
7
8
9
10
11
12
    <!-- 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">
    <a class="lang-name" {% if tongue == site.active_lang %} style="font-weight: bold;" {% endif %} {% 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>
    </p>  
    {% endfor %}
    </div>

你可以尝试把这个内容放到其他地方自己调试 HTML 和 CSS。

这就是为什么我需要一个界面基本上全局保持不变的博客主题,不然不太好安排这个选单的位置和形式。对 Chirpy 而言,放在左下方刚刚好。

常见故障

在 Windows 上调试这个插件时,我踩了不少坑,在这里记录一下:

正则表达式报错

本地生成网站时有些时候会报如下错误:

1
C:/Ruby33-x64/lib/ruby/gems/3.3.0/gems/jekyll-polyglot-1.8.1/lib/jekyll/polyglot/patches/jekyll/site.rb:234:in `relative_url_regex': target of repeat operator is not specified: /href="?\/((?:(?!*.gem)(?!*.gemspec)(?!docs)(?!tools)(?!README.md)(?!LICENSE)(?!*.config.js)(?!package*.json)(?!.sass-cache)(?!.jekyll-cache)(?!gemfiles)(?!Gemfile)(?!Gemfile.lock)(?!node_modules)(?!vendor\/bundle\/)(?!vendor\/cache\/)(?!vendor\/gems\/)(?!vendor\/ruby\/)(?!en\/)(?!zh-CN\/)[^,'"\s\/?.]+\.?)*(?:\/[^\]\[)("'\s]*)?)"/ (RegexpError)

Polyglot 执行上的原理是在编译整个项目时扫描整个项目,把每种语言生成一遍内容。其中用到了正则表达式进行匹配。如果此时遇到星号和句点,它会认为是需要执行的正则表达式语句。

把出现了这些正则表达式相关的配置文件注释掉即可解决。

1
2
3
4
5
6
7
8
9
exclude:
  # - "*.gem"
  # - "*.gemspec"
  - docs
  - tools
  - README.md
  - LICENSE
  # - "*.config.js"
  # - package*.json

Windows Ruby 执行报错

Polyglot 的 readme 里也写了,Windows 上不支持 parallel_localization,配置里改成 false 即可。

1
2
3
4
5
6
7
8
plugins:
  - jekyll-polyglot

# polyglot configuration
languages: ["en", "zh-CN"]
default_lang: "en"
exclude_from_localization: ["javascript", "images", "assets", "public"]
parallel_localization: false

其他

先简单介绍到这。以后可以谈谈 Chirpy 主题的一些强大功能的使用心得,以及我是如何修改这个主题的一些部分以满足自己需要的。

推荐阅读

  1. 建立多语言 Jekyll 网站
本文由作者按照 CC BY 4.0 进行授权