おもこん

おもこんは「思いつくままにコンピュターの話し」の省略形です

Jekyll初級編(1)英語と日本語のあるウェブ

多言語のウェブサイト構築

Jekyllの勉強を兼ねてブログを書いたおかげで、だいぶ分かってきました。 それをまとめた「はじめてのJekyll + GitHub Pages」が出来上がり、一区切りですが、これからはその続編を書こうと思っています。 前回が入門編でしたので、今度は初級編です。 ネタができたら、ブログに書き留め、ある程度の分量になったら書き直してGitHubにあげようと思います。

今日は国際化もどきです。

言語の切り換え

日本語だけでなく、英語もサポートするウェブを作ることを考えてみます。 動的なサイトの場合、単語やフレーズ単位で日本語と英語を用意して、ユーザからの言語の要求に基づいて切り替えることが良く使われます。 これは、記事に対して行うというより、メニューやメッセージなどのように短く、あらかじめ決まった使い方をするものに対して行われます。

Jekyllが構築するのは静的なサイトなので、画面の一部だけを取り替えることができません。 英語の画面と日本語の画面を別々に用意し、それらの画面をビルドする段階でメニューなどの言語をチョイスすることになります。 また、リンク先も日本語と英語を別々にしなければなりません。 別言語に移動するリンクはメニューの中に用意します。

日本語/英語サイトのイメージ

ページの言語を指定するためにフロントマターに「lang: ja」「lang: en」のハッシュを設けます。

このような仕組みで実際にGitHubにページを作ったものがあります。

このページを例に、リンクの作り方を説明します。

メニューとレイアウト

すべてのページはフロントマターに言語が指定されています。 例えば、英語のaboutページのフロントマターは

---
layout: page
title: About
lang: en
---

このようになっています。 このページのメニューは英語ページへのリンクだけを貼ります。

例に用いる「ToshioCP's Homepage」ではテーマにminimaを使っています。 minimaではメニューをレイアウト自身ではなく、レイアウトがインクルードする「header.html」で記述しています。 そこで、_includesディレクトリの下にカスタマイズ用のheader.htmlを作ります。 まず、minimaのheader.htmlをコピーして、次のように一部変更します。

<header class="site-header">
  {%- if page.lang == "ja" -%}
  {%-   assign root_path = "/index_ja.html" -%}
  {%-   assign lang_change_path = "/" -%}
  {%-   assign lang_change_title = "English" -%}
  {%- else -%}
  {%-   assign root_path = "/" -%}
  {%-   assign lang_change_path = "/index_ja.html" -%}
  {%-   assign lang_change_title = "日本語" -%}
  {%- endif -%}
  <div class="wrapper">
    {%- assign target_pages = site.pages | where: "lang", page.lang -%}
    {%- assign target_default_pages = site.header_pages | where: "lang", page.lang -%}
    {%- assign target_pages = target_default_pages | default: target_pages -%}
    <a class="site-title" rel="author" href="{{ root_path | relative_url }}">{{ site.title | escape }}</a>

    <nav class="site-nav">
      <input type="checkbox" id="nav-trigger" class="nav-trigger" />
      <label for="nav-trigger">
        <span class="menu-icon">
          <svg viewBox="0 0 18 15" width="18px" height="15px">
            <path d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.032C17.335,0,18,0.665,18,1.484L18,1.484z M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.032C17.335,6.031,18,6.696,18,7.516L18,7.516z M18,13.516C18,14.335,17.335,15,16.516,15H1.484 C0.665,15,0,14.335,0,13.516l0,0c0-0.82,0.665-1.483,1.484-1.483h15.032C17.335,12.031,18,12.695,18,13.516L18,13.516z"/>
          </svg>
        </span>
      </label>

      <div class="trigger">
        {%- for target_page in target_pages -%}
          <a class="page-link" href="{{ target_page.url | relative_url }}">{{ target_page.title | escape }}</a>
        {%- endfor -%}
          <a class="page-link" href="{{ lang_change_path | relative_url }}">{{ lang_change_title | escape }}</a>
      </div>
    </nav>
  </div>
</header>
  • 2行目から10行目で、現在開かれているページが日本語か英語かによって、root_pathなどの変数を設定します。
    • root_path それぞれの言語のトップページへのパス
    • lang_change_path 別の言語のトップページへのパス
    • lang_change_title 別の言語へのメニュー文字列
  • 12-14行目でメニューに表示するページの配列をtarget_pagesに代入。 このとき、whereフィルターで同言語のページのみに絞ります。 なお、minimaではsite.header_pagesが設定されていれば、それだけをメニューに表示するようになっています。 これはページの数が多くて、なおかつ全部をメニューに入れる必要がない時に使います。
  • 15行目でトップページへのリンクを貼ります。

下から8行目から5行目がメニューを表示する部分です。 for文でtarget_pagesへのリンクを作ります。

  • target_page.urlにはrelative_urlフィルタをかけなければならない
  • target_page.titleにはHTMLの特別な文字が含まれる可能性があるのでescapeフィルターをかける

for文の次に他の言語へのリンクを付け加えます。 リンク先はその言語のトップページです。

ポイントになるのはwhereフィルターで同言語のページのみを抽出するところです。

以上で日本語ページのメニューには日本語ページへのリンクだけが、英語ページのメニューには英語ページへのリンクだけが設置されます。

トップページのブログの一覧表示

トップページは英語がindex.html、日本語がindex_ja.htmlになります。 それぞれブログへのリンクがリストされますが、英語のトップページには英語のブログだけ、日本語のトップページには日本語のブログだけがリストされます。

これはレイアウトのhome.htmlで設定されています。 カスタマイズのために、_layoutsディレクトリを作り、そこにminimaのhome.htmlをコピーし書き換えます。

---
layout: default
---

<div class="home">
  {%- if page.title -%}
    <h1 class="page-heading">{{ page.title }}</h1>
  {%- endif -%}

  {{ content }}

  {% comment %}
  No pagination is available.
  {% endcomment %}

  {% assign posts = site.posts |where: "lang", page.lang %}


  {%- if posts.size > 0 -%}
    {%- if page.list_title -%}
      <h2 class="post-list-heading">{{ page.list_title | escape }}</h2>
    {%- endif -%}
    <ul class="post-list">
      {%- assign date_format = site.minima.date_format | default: "%b %-d, %Y" -%}
      {%- for post in posts -%}
      <li>
        <span class="post-meta">{{ post.date | date: date_format }}</span>
        <h3>
          <a class="post-link" href="{{ post.url | relative_url }}">
            {{ post.title | escape }}
          </a>
        </h3>
        {%- if site.show_excerpts -%}
          {{ post.excerpt }}
        {%- endif -%}
      </li>
      {%- endfor -%}
    </ul>
  {%- endif -%}

</div>

ポイントは中程やや上にある

  {% assign posts = site.posts |where: "lang", page.lang %}

です。 これで、ブログ記事(site.posts)から同言語のページのみを抽出します。

まとめ

ポイントはリンクを同言語に限るようwhereフィルターを使うところです。 やってみるとさほど複雑ではないことが分かると思います。