14
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

GLOBISAdvent Calendar 2021

Day 7

メディアサイトを多言語対応する【Nuxt.js】

Last updated at Posted at 2021-12-06

はじめに

こちらの記事はグロービスアドベントカレンダー2021の15日目の記事になります。

こんにちは!グロービス・デジタル・プラットフォームのエンジニアの@couragenkiです。
グロービスではGLOBIS UnlimitedのフロントエンドをReact.jsで開発したりグロービス経営大学院 ナノ単科 の学習アプリケーションの開発をFlutterで開発しております。

今回作成したサイト

今回は個人開発で作成したNuxt.jsのメディアサイトの多言語対応を実装したお話になります。
下記の画像のように言語切り替えを行うとページと記事の言語が切り替わる実装を行いました。
今回作成した多言語サイトのデモはこちらになります。

画面収録_2021-12-05_7_52_46_SparkVideo.gif

用途

多言語対応が必要で記事が多いサイトに向いています。

  • コーポレートサイト
  • メディアサイト
  • FAQサイト

サイトのヘッダーやフッター以外にもお知らせや投稿なども多言語化して管理したい場合に向いています。
SSRで各言語ごとにページを生成するのでSEO的にもメリットがあるので検索流入を狙うケースでも使えます。

Nuxt.jsでのサイトの基本的な実装について

多言語化するサイトのベースの実装はこちらのNuxt/Contentを利用したサイトです。
こちらでのサイトの立ち上げが個人的に楽なのでよく使っています。
今回はこちらで作成したサイトを多言語に対応させていく内容になります。

サイトを多言語化する

多言語化するためにi18n対応していきます。
i18nとは?という方にはこちらの記事がわかりやすくておすすめです。

nuxt-i18nを使った多言語化

nuxt-i18nを使って多言語対応していきます。

nuxt-i18nを導入

まずはインストールする

npm i nuxt-i18n

言語のデータを保存するjsonを追加する

jsonに変換する言語データを保存する

日本語のデータ

ja.json
{
  "HELLO_WORLD": "こんにちは、世界",
  "FOODS": "食べ物",
  "INTORO": "こちらは多言語で作られたサイトのデモです。",
  "SITE_TITLE": "サイトのタイトル",
  "ARTICLES": "投稿",
  "LINKS": "リンク",
  "NEWS": "お知らせ"
}

英語のデータ

en.json
{
  "HELLO_WORLD": "Hello World",
  "FOODS": "FOODS",
  "INTORO": "Here is a demo of a site created in multiple languages.",
  "SITE_TITLE": "SITE TITLE",
  "ARTICLES": "Articles",
  "LINKS": "Links",
  "NEWS": "News"
}

このようにデータを作成し/lang以下のディレクトリに置きます。

言語設定を追加する

nuxt.config.jsに言語設定を追加します。
今回はデフォルトの言語を日本語にしていますが例えば英語をデフォルトにしたい場合などはdefaultLocalefallbackLocaleenに変更すればOKです。

日本語の言語コードはjaで国コードはjpなのでどちらのコードを使うべきか迷ったので調べたのですが、i18nの場合はjaを使うようでした。

i18n: {
  locales: [
    {
      code: 'ja',
      iso: 'ja',
      file: 'ja.json',
    },
    {
      code: 'en',
      iso: 'en',
      file: 'en.json',
    },
    {
      code: 'cn',
      iso: 'cn',
      file: 'cn.json',
    },
  ],
  langDir: 'lang/',
  fallbackLocale: ['ja'],
  defaultLocale: 'ja',

データを呼び出す

$t()関数の中に呼び出したいjsonのキーを入れて呼び出すことで言語を切り替えて表示することが可能です。

<span>{{ $t('HELLO_WORLD') }}</span>

言語切り替えの実装

今回はこのように言語ごとにリンクを設置して切り替えたい言語を選択する形式にしました。

SetLang.vue
<template>
  <div class="setlang">
    <nuxt-link
      :class="{ selected: $i18n.locale === 'cn' }"
      :to="switchLocalePath('cn')"
      >中国語</nuxt-link
    >
    <nuxt-link
      :class="{ selected: $i18n.locale === 'en' }"
      :to="switchLocalePath('en')"
      >English</nuxt-link
    >
    <nuxt-link
      :class="{ selected: $i18n.locale === 'jp' }"
      :to="switchLocalePath('jp')"
      >日本語</nuxt-link
    >
  </div>
</template>

Linkコンポーネントを作る

必須ではないですがlocalePathの挙動を一括管理するならコンポーネント化した方が楽なのでコンポーネントを作る。

components/Link.vue
<template>
  <n-link :to="localePath(setPath)">
    <slot />
  </n-link>
</template>

ここまでが一般的なi18nの対応になります。

nuxt-contentとnuxt-i18nを組み合わせた多言語化対応

今回のやりたいことのメインはここからになります。
ここからはnuxt/contentで追加したお知らせや投稿などを言語切り替えできるように実装していきます。
nuxt/contentを使うことで記事ごとに翻訳したマークダウンを用意できるのでページ単位で翻訳を管理できます。

まずはcontentに言語ごとに記事を追加する

日本語で記事を追加

content/foods/articles/1.md
---
title: 美味しいハンバーガー
description: 今回は美味しい美味しいハンバーガーについて語っていきたいと思います。
keyword: ハンバーガー
language: jp
image: /articles/1.jpeg
tags:
  - 食べ物
  - ハンバーガー
---

## 美味しいハンバーガーについて

今回は美味しい美味しいハンバーガーについて語っていきたいと思います。

続いて同じ記事の英語版を追加

content/foods/articles/en/1.md
---
title: Delicious burgers
description: In this article, I would like to talk about delicious and tasty hamburgers.
keyword: hamburger
language: en
image: /articles/1.jpeg
tags:
  - foods
  - hamburger
---

## Delicious burgers

In this article, I would like to talk about delicious and tasty hamburgers.

pagesにて記事の言語切り替えを行う

記事を表示する_slug.vueにてi18nで現在表示している言語キーを取得できるのでそちらを使って記事の切り替えを行なっています。
基本的にcontentの中の言語切り替えは他の箇所でもこのやり方で行いました。

/pages/foods/articles/_slug.vue
<template>
  <PostTemplate :post-data="post" />
</template>

<script>
import PostTemplate from '~/components/PostTemplate.vue'
export default {
  components: { PostTemplate },
  async asyncData({ $content, params, i18n }) {
    if (i18n.locale === 'cn') {
      const post = await $content(
        'foods/articles/cn',
        params.slug || 'index'
      ).fetch()

      return { post }
    } else if (i18n.locale === 'en') {
      const post = await $content(
        'foods/articles/en',
        params.slug || 'index'
      ).fetch()

      return { post }
    } else {
      const post = await $content(
        'foods/articles',
        params.slug || 'index'
      ).fetch()
      return { post }
    }
  },
}
</script>

こうすることで記事のページでも言語の切り替えがこんな感じでできます。
ページの中身も言語が同じタイミングで切り替わっていることが分かります。

タグのページも実装する

contentに追加したマークダウンのデータから現在選択されている言語のタグだけを取得するメソッドを追加する。

/pages/foods/tags/index.vue
<template>
  <DefaultTemplate>
    <div class="wrapper">
      <h1 class="title">
        <div>
          <span>{{ $t('FOODS') }}</span>
        </div>
      </h1>

      <h2>Tags</h2>
      <ul v-for="(item, index) in setTags(viewArticlesData)" :key="index">
        <li>
          <Link :path="'/foods/tags/' + item">
            {{ item }}
          </Link>
        </li>
      </ul>
    </div>
  </DefaultTemplate>
</template>

<script>
import DefaultTemplate from '~/components/DefaultTemplate.vue'
export default {
  components: {
    DefaultTemplate,
  },
  async asyncData({ $content }) {
    const articlesQuery = $content('foods/articles', { deep: true }).sortBy(
      'date',
      'desc'
    )
    const articlesData = await articlesQuery.fetch()
    const viewArticlesData = articlesData.sort(function (a, b) {
      return new Date(b.date) - new Date(a.date)
    })

    return { viewArticlesData }
  },
  methods: {
    setTags(arr) {
      const muchTags = []
      for (let i = 0; i < arr.length; i++) {
        if (this.$i18n.locale === arr[i].language) {
          for (let ii = 0; ii < arr[i].tags.length; ii++) {
            if (!muchTags.includes(arr[i].tags[ii])) {
              muchTags.push(arr[i].tags[ii])
            }
          }
        }
      }

      return muchTags
    },
  },
}
</script>

こんな感じで言語切り替えを行なった際にタグの言語も切り替わりタグによる絞り込みもできるようになりました。

まとめ

今回は多言語化対応の勉強とキャッチアップも兼ねてNuxt.jsで多言語サイトを作成しました。
またメディアサイトやFAQサイトは汎用が高いので今後サイトを作る際のテンプレートとして実装したので活躍の機会があればいいなと思います。

Nuxt.jsは現在は業務で触っていませんがとにかくお手軽で気に入っているので個人開発ではよく使っています。
今後も定期的にNuxtのアウトプットをしていきたいです!

以上になります。最後までお読みいただきありがとうございました。

14
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?