最近、友人から日本語版と英語版のウェブサイトを作るように言われました。 私は国際化されたウェブサイトを書いたことはありませんが、ローカリゼーションがどのように機能するかについて強い意見を持っています。 そこで、ヘッドレスCMSであるCosmicJSを使用してギャツビーの国際化に取り組む1つの方法を紹介します。

コンテキストのビット

ローカリゼーションに取り組む方法はたくさんあり、いつものように特効薬はありません。 それぞれのアプローチは、さまざまな方法で問題を解決します。 だからここに私の文脈があります:

  • できるだけメンテナンスコストの少ないサイトを作りたいです。
  • コンテンツライターにはプログラミングの経験がありません
  • サイトのメンテナンスコストは可能な限り低くする必要があります。
  • サイトは、サイトの1つのバージョンでユーザーを強制するべきではありません。

この最後の点は私にとってとても重要です。 あなたが外国にいるとき、いくつかのウェブサイトはあなたに彼らのサイトのローカルバージョンを使用することを強制します。 [array of multinational companies]が私を[long array of languages I don't understand]バージョンのWebサイトに強制すると、私は怒ります。 ページの自動翻訳でも同じ問題が発生します。 ウェブサイトの自動翻訳が必要な場合は、素晴らしいGoogle翻訳Chrome拡張機能を使用できます。

このウェブサイトは、日本語と英語の両方のユーザーを対象としています。 そのため、サイトのすべてのページに英語版と日本語版が必要です。 ユーザーがWebサイトの現在のバージョンを変更したい場合は、ナビゲーションバーの言語メニューをクリックできます。

私のアプローチ

GatsbyとReactは、ローカリゼーション(l10n)と国際化(i18n)にアプローチするための多くのツールを提供します。

私は最初にgatsby-plugin-i18nを使用してルートを簡単に生成しました。

たとえば、/page/team.ja.jsは次のURLを生成します:/ja/teamjaは日本の言語コードです)。

これは本当に素晴らしいプラグインですが、問題はそれがプログラム的ではないということです。 言語ごとに新しいファイルを作成する必要があります。 各ファイルで、データをフェッチするために特定のGraphQLクエリを作成する必要があります。 したがって、たとえば、CMSに新しい言語を導入した場合、新しい言語拡張機能を使用してすべてのルートを再度作成する必要があります。

そこで、代わりに、プラグインなしでl10nをビルドすることにしました。 このプロジェクトのすべてのコードは、https://github.com/alligatorio/kodouで入手できます。

このコンテキストでは、コンテンツライターはローカリゼーションに完全に責任があります。 彼女が日本語版のウェブサイトを書くとき、彼女は日付の形式が正しいことを確認する必要があります。 これが、Internationalization APIに依存し、今後の投稿のトピックとなるreact-intlを使用しない理由です。

CosmicJSのセットアップ

優れたヘッドレスCMSオプションであるCosmicJSを使用すると、新しいオブジェクトタイプを作成するときにローカリゼーションをアクティブ化できます。

screenshot: l10n option in Cosmic JS

優先ロケールを選択することを忘れないでください。そうしないと、新しいオブジェクトが保存されません。

新しいサイトにはチームページがあるので、チームメンバーオブジェクトを作成します。 新しいチームメンバーを作成するときに、その言語を選択できるようになりました。

screenshot: Team Member language selection in Cosmic JS

Gatsbyからそのデータにアクセスするには、gatsby-source-cosmicjsソースプラグインを追加する必要があります。

$ yarn add gatsby-source-cosmicjs

次に、pluginsに次のコードを追加して、gatsby-source-cosmicjsを使用するようにgatsby-config.jsを構成する必要があります。

モジュール:gatsby-config.js
{
  resolve: "gatsby-source-cosmicjs",
  options: {
    bucketSlug: process.env.COSMIC_BUCKET,
    // We add the 'team-members' object type to be able to fetch it later
    objectTypes: ["team-members"],
    // If you have enabled read_key to fetch data (optional).
    apiAccess: {
      read_key: process.env.COSMIC_ENV_KEY,
    }
  }
}

コードの残りの部分では、次を実行してCosmicJSからチームメンバーデータにアクセスできます。

graphql(`
  {
    allCosmicjsTeamMembers  {
      edges {
      # Here we have the structure of out `team-members` object
        node {
          title
          locale
          content
          metadata {
            profile_picture {
              imgix_url
            }
          }
        }
      }
    }
  }
`)

これで、ローカリゼーションの魔法が起こります。

ローカライズされたページの生成

私は友達が自分でやりたいことを何でもできるようにしたかったのです。 そこで、/pagesディレクトリを完全に削除して、/templatesディレクトリを優先しました。 Gatsbyテンプレートを使用すると、再利用可能なコンテンツを作成し、プログラムでページを作成できます。 これはまさに私たちがしなければならないことです!

テンプレートファイルを見る前に、CosmicJSからデータをフェッチして新しいページを作成する方法を見てみましょう。

モジュール:gatsby-node.js
// langs contains the languages of our blog and default langKey is the default language of the site
// To be fully programmatic we could calculate langs
// here langs = ['en', 'ja'] and defaultLangKey = 'en'
const { langs, defaultLangKey } = require('../config/languages')
const path = require(`path`)
const { localizeUrl, createLanguagesObject } = require('../utils/localization')

exports.createPages = async ({ actions, graphql }) => {
  const { createPage } = actions

  const result = await graphql(`
    {
      allCosmicjsTeamMembers  {
        edges {
          node {
            title
            locale
            content
            metadata {
              profile_picture {
                imgix_url
              }
            }
          }
        }
      }
    }
  `)

  if (result.errors) {
    console.error(result.errors)
  }

  // Creates a profiles object with out site's languages 
  const profiles = createLanguagesObject(langs)
  // profiles = {
  // 'en': [],
  // 'ja': []  
  // }

  // converting the raw cosmic data into a more useable data structure
  result.data.allCosmicjsTeamMembers.edges.forEach(({ node }) => {
    profiles[node.locale].push(node)
  })
  // profiles = {
  // 'en': [...all English profiles],
  // 'ja': [...all Japanese profiles]  
  // }

  // we create a new page for each language
  langs.forEach(lang =>{
     createPage({
      // the localizeUrl function creates a url which takes into consideration what the default language is
      path: localizeUrl(lang, defaultLangKey, '/team'),
      component: path.resolve(`src/templates/team.js`),
      context: {
        profiles: profiles[lang]
      }
    })
  })
}

このコードは、パス/ja/team/teamを使用して2つの新しいページを作成します(デフォルト言語として英語を設定しているため、/enはありません)。

ご覧のとおり、createPageは、pathcomponentcontextの3つのフィールドを持つオブジェクトを引数として取ります。 パスは、新しいページに必要なパスです。 componentは使用したいテンプレートです。 contextは、テンプレートに渡したいデータです。 ここでは、希望する言語で書かれたプロファイルを渡します。

テンプレート

チームテンプレートを見てみましょう。

import React from "react"
import Layout from "../components/layout"
import SEO from "../components/seo"

const TeamPage = (props) => {
  // We will see about pageContext in the next section
  const {profiles} = props.pageContext
  return (
  <Layout location={props.location}>
    <SEO title="Team" />
    <h1>Team</h1>
    // Iterating trough the array of profiles
    {profiles.map((profile,i)=>(
      <div key={i} className="columns">
        <div className="column">
          // Here are some nice profile pictures of our team members
          <div className="square-image" style={{backgroundImage: `url("${profile.metadata.profile_picture.imgix_url}")`}}/>
        </div>
        <div className="column is-two-thirds">
          <div className="team-member-title">{profile.title}</div>
          // Here is some html content we get from Cosmic
          <div dangerouslySetInnerHTML={{ __html: profile.content }}/>
        </div>
      </div>
      )
    )}
  </Layout>
  )
}

export default TeamPage

要約すると、上記のコードは、CosmicJSから取得したプロファイルの配列であるprofilesプロップを取ります。 各プロファイルには、プロファイル画像オブジェクト、titleおよびcontentフィールドがあります。 contentは実際にはHTMLの文字列であるため、dangerouslySetInnerHTMLプロップを使用して設定する必要があります。

このテンプレートが機能するためには、一貫した結果を得るために事前にCSSファイルを準備することが重要です。 私の友人は、CosmicのWYSIWYGにクラス名またはIDを追加できなくなります。

言うことやすることはもっとたくさんあります:

  • ナビゲーションバーと場所を意識したレイアウトの作成
  • 国際化APIの使用方法
  • ユーザーを自分のバージョンのサイトにソフトリダイレクトする方法

Githubリポジトリを調べて、これらの問題に対処する方法を確認し、kodou.meで結果を確認できます。 または、 Alligator.io を使用して、そのトピックに関する新しいコンテンツをアップロードしたかどうかを確認します。 しかし、1つの投稿で処理することはすでにたくさんあると思います。 上記で、これがあなた自身の国際化されたサイトを構築するのに少しまたは大いに役立つことを願っています。 😉