Post

Modify Chirpy theme to build a functional bilingual Jekyll blog with Polyglot

How to manually modify the Chirpy theme to build a fully functional, smooth bilingual blog with Polyglot.

In the issue section of Polyglot, I found someone complaining that he cannot configure Polyglot correctly with the Chirpy theme and asked for some help.

Chirpy is the most popular technical-writing blog theme in Jekyll community right now. After all, Polyglot is a niche plugin with a unique implementation method, so it’s not realistic to expect most themes to have built-in support for Polyglot. You have to do it by yourself.

Basic Modification

Chirpy officially provides two different approaches to deploy itself . One is to use the starter repository template to create the project, another one is to fork the repository then modify it by yourself. The former is more convenient for updating and the latter can support you to modify it in a high flexibility.

You have to choose the latter if you want to customize it. Otherwise, all the webpage template files are integrated in the gem of the theme and is not support to be modified.

The principle of Polyglot execution is to scan the entire project when compiling the entire project, generating content for each language. Finally, in the _site directory, the main language site is located in the root directory, while each non-main language will have their own website directory.

When generating the website, the variable site.active_lang will be assigned with the identifier of the language currently being generated. Jekyll uses Liquid templates to generate HTML. You can reference these contents in webpage templates using Liquid syntax, such as modifying the website title interface to automatically switch different languages’ website titles:

1
2
3
4
<h1 class="site-title">
      <a href="/">AnotherTurret</a>
</h1>
<p class="site-subtitle fst-italic mb-0">Just another study note blog</p>

Articles written in different languages need to be placed in directories with corresponding language code identifiers, but they should have the same file name. For example, on my website where English is the primary language, Chinese articles will be placed under _post/zh-CN.

Chirpy defaults to using only one language for a site, defined by the lang parameter in _config.yml. During the rendering process, most language-related template entries use variable assignments defined in the _data directory, which are then referenced by site.data.locales[site.lang].variable_name.

In order to adapt to Polyglot, we need to replace all content related to [site.lang] with [site.active_lang]. I suggest use a text editor like VS Code to find within all the files and execute the replacement operation. Remember to tick the “match whole word” option.

For further information of the, you can also refer to the introduction from Polyglot official website.

Language Switcher

In order to let the readers to switch the language on all the pages, you need to add a language switcher in _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>

In the previous article, I forgot to mention how to add the corresponding CSS. You need to modify _sass/addon/common.sass and add the following content within .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;
    }

In order to display the national flag on the Windows platform, I deliberately chose NotoColorEmoji as the preferred font-family for the language selection bar.

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 Customization

The author of Chirpy made a customized RSS file. It is stored at assets/feed.xml.

I prefer RSS that can output full text. So I modified it: switch the <summary> and <content> . The RSS can output full text right now.

1
2
3
4
5
6
7
  <summary></summary>
  <content type="html">
  <![CDATA[ 
  {%- include no-linenos.html content=post.content -%}
  	{{- content | html -}}
  ]]>
  </content>

Using the no-linenos.html template is to remove line numbers from code blocks.

SEO Recipes

Chirpy theme uses jekyll-seo-tag as the SEO optimization plugin. jekyll-seo-tag defaults to assigning values of site.title, site.description, and site.lang to the <meta> tags for SEO content.

This conflicts with the specific language variables that need to be selected using site.active_lang as mentioned earlier.

Directly modifying seo.html will not solve this problem. I have created a jekyll-seo-tag specifically for Polyglot as a workaround. You need to remove or comment out the line using jekyll-seo-tag in jekyll-theme-chirpy.gemspec. Also, include my modified plugin in 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

If you are testing on your local machine, don’t forget to use bundle install and bundle update to install this new plugin.

In addition, Polyglot also has its own SEO solution. It is recommended to add both. That is, in head.html, add `

` before the paragraph of SEO.

1
2
3
4
5
6
  <meta http-equiv="Content-Language" content="en">
<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 -->

Possible Deployment Error in Vercel

I don’t know why, but after using my custom plugins, every time Vercel automatically deploys, there is an error in the git fetch stage. It seems to be because its environment configuration does not support fetching Ruby gems from GitHub repositories.

I don’t want to research it anymore. So I just add edVERCEL_FORCE_NO_BUILD_CACHE=1 in the deployment environment variables of Vercel to disable using the previous environment cache, requiring it to compile from scratch every time it is deployed, which can solve this problem. In this way, the deployment time will increase from 40 seconds to 80 seconds. But is generally fine for a static blog deployment, as we don’t need to get the feedback that soon.

This post is licensed under CC BY 4.0 by the author.