【Nuxt.js+microCMS】APIで受け取ったデータを自作プラグインでサイト内どこでも簡単に日本語変換できるようにした話

6 min read読了の目安(約6200字 2

前置き

Nuxt.js+microCMSでサイト制作をしました。
各コンテンツはmicroCMSでコンテンツ管理をし、axiosでデータを取得しサイトに反映しています。

ただ、「カテゴリ」「都道府県」など、受け取るデータは英語名だけども表示させるのは日本語がいい。どうしよう。という問題にあたりました。

今回はそれをどう解決したのかまとめます。
(自分はこの形に行き着いたというだけなので、考え方が違うなどあれば教えていただけたら嬉しいです!)

Nuxt.jsmicroCMSの基本的な使い方については割愛します。

環境

"@nuxtjs/axios": "^5.13.1"
"nuxt": "^2.15.3"

①とりあえずSwitch文で自作関数書いた

プラグインの作り方

  • /plugins 内にこのように記載した関数は、injectすることでクライアントサイドならVueインスタンスに、サーバーサイドならcontextに挿入され、 $doSomething() などの形でサイト内どこからでも簡単に呼び出すことができるとのことです。[cf]
/plugins/do-something.js
export default (context, inject) => {
  inject('doSomething', (task) => console.log(`do ${task}!`))
}
nuxt.config.js
export default {
  plugins: ['~/plugins/do-something.js']
}

各コンポーネントにローカルに関数を定義することもでき、「このコンポーネント内でどんな処理を扱っているか」わかりやすいという点ではメリットがあるのかもしれませんが、今回は別にその関数がどんな処理内容なのかをわかりやすくする必要もなく(英語名を日本語名にしてるんでしょ、とわかれば十分)、それよりかは汎用的にサイト内全体で手軽に呼び出せることが大事だと判断して、plugin自作という選択になりました。

書いた

  • まずはこのように、Switch文でconvert-data.jsというファイルに処理を書きました。
    /plugins/convert-data.js
    // news: categoryリスト
    function setNewsCategory(category) {
      let convertedCategory
      switch (category) {
        case 'お知らせ':
          convertedCategory = 'news'
          break
        case 'ご注意':
          convertedCategory = 'announce'
          break
      }
      return convertedCategory
    }
    
    nuxt.config.js
      export default {
          plugins: ['~/plugins/convert-data'],
      }
    
  • これでも動作はしますが、下記の理由でもう少し頑張ることにしました。
    • データと処理が一緒くたになっているのが気になる。分離したい。
    • そしてデータを扱うなら、Vuexを噛ませたい。
    • 単純に関数内の記述が無駄に長い。
    • 今は英語名⇄日本語名の変換だけだが、他の値を持たせたくなったときにプロパティを増やすことができない(関数増やせばいいだけだろうけどキレイじゃない)。

補足:引数として渡す値について

今回の例だと引数として category を渡していますが、ここがmicroCMSで作ったコンテンツをAPIで取得してきている部分になります。
なのでcategoryというプロパティがdata()内にあるのではなく、asyncDataにより非同期にデータを取得し、data()にマージされている状態です。

/pages/news/index.vue
export default {
  async asyncData({ $axios }) {
    // baseURLとAPI KEYはnuxt.config.jsに記述
    const data = await $axios.$get('news')
    return data
  },
}


この中のcatagoryを関数に渡しています。

②json + Vuexを使いデータを処理を分離

  • ということで方針転換。これでやっていきます。
    1. データをjsonに格納
    2. Vuexでデータを管理
    3. plugins内でstoreにアクセス。Vuexに一度持ってきたデータを使って、日本語名を返す処理を書く

1. データをjsonに格納

こんな感じでjsonデータを作成。
/assets/json/ 以下に格納します。

/assets/json/convert-data.json
 {
  "news": [
    {
      "name": "news",
      "ja": "お知らせ"
    },
    {
      "name": "announce",
      "ja": "ご注意"
    }
  ],
  "museum": [],
  ...
 }

2. Vuexでデータを管理

次に、こんな感じで先ほど作ったjsonにアクセスします。

/store/convertData.js
import convertData from '~/assets/json/convert-data'

export const state = () => ({
  convertData,
})

// gettersは今回使用してませんが後述の補足のため
export const getters = {
  convertData: (state) => {
    return state.convertData
  },
}

記述量だけ見ると、これVuexかませる必要あるのかという気がしてきますがどうなのでしょう。
個人的には、「データはVuexで管理する」というルールにサイト全体が従った方が良いと思い今回はこの形にしました。
いきなりプラグインの中でjsonを読み込んでももちろん動作します。

補足:各コンポーネントでローカルに日本語名に変換する

今の方針では「自作pluginでどこでも簡単にアクセス」が目標ですが、このようにローカルで変換することもできます。

/pages/news/index.vue
<span class="p-news__category" :data-category="category[0]">{{
  setNewsCategory(category[0])
}}</span>
/pages/news/index.vue
import { mapGetters } from 'Vuex'

export default {
  computed: {
    ...mapGetters({
      convertData: 'convertData/convertData',
    }),
  },
  methods: {
    setNewsCategory(category) {
      const returnItem = this.convertData.news.filter(
        (news) => news.name === category
      )
      return returnItem[0].ja
    },
  },
}

が、やはり各コンポーネントそれぞれに書かなきゃいけないというのも、やること単純なのにコード量だけ増えて見通しが悪くなるので、個人的にはプラグイン自作で良かったかなと思います。

3. plugins内でstoreにアクセス。Vuexに一度持ってきたデータを使って、日本語名を返す処理を書く

①Switch文のところで書いたように、plugins内にconvert-data.jsを作り処理を書いていきます。違うのは、今回はVuexにアクセスしたいのでstoreを分割代入しているところです。
補足:この書き方の他に、contextを使ってcontext.storeとすることもできるとのことです。

できあがったプラグインの中身はこんな感じ。

/plugins/convert-data.js
export default ({ store }, inject) => {
  const convertTargetDatas = store.state.convertData.convertData
  // news: categoryリスト
  inject('setNewsCategory', (category) => {
    const datas = convertTargetDatas.news
    const returnData = datas.filter((data) => data.name === category)
    return returnData[0].ja
  })
  ...
}
  • 2行目:store内のデータにアクセス(storeではjson呼んでいる)。
  • 4行目:変換したいカテゴリリストごとに関数を書きinject。
  • 5行目:呼びたいデータの配列を定義。ここではnewsのデータ群を格納。
  • 6行目:格納した配列の中で、英語名(nameの値)が引数で渡されたカテゴリ名(英語)と一致するものを返す
  • 7行目:返ってきたデータの中の日本語名(jaの値)を返す。
    ということをしています。

あとは好きなページコンポーネントの中で呼ぶだけ。

/page/news/index.vue
<span class="p-news__category" :data-category="category[0]">{{
  $setNewsCategory(category[0])
}}</span>

先ほどのページでも…

一覧ページでも…

詳細ページでも…

全てこの $setNewsCategory(category[0]) と記述しているだけです。
もっと言うと、他のコラムのカテゴリや恐竜のカテゴリなど、あらゆる範囲で応用させています。

これでサイト内どこでも簡単に日本語変換ができるようになりました!!やったね!
Twitterでアドバイスくれた方、ありがとうございました!!

2021/5/18 追記 microCMS上でもっと簡単に変換する

microCMS開発者様より、コメントでもっと簡単な方法があると教えていただきました。
コンテンツ参照を使うと、今回jsonでデータを持たせてやったようなことがmicroCMS上でできるそうです。[cf

  1. まずは通常のコンテンツとしてリスト形式で「英語名」「日本語名」のデータの入ったデータセットを作る
  2. カテゴリを選択したい元のコンテンツで、API設定をいじり「コンテンツ参照」で先ほど作ったデータセットを選択し変更を公開
  3. コンポーネント内で読み込む
/pages/column/index.vue
// 記事の方法
<span
  class="p-column__category"
  :data-category="content.category[0]"
  >{{ $setColumnCategory(content.category[0]) }}</span
>

// microCMSでコンテンツ参照を使う方法
<span
  class="p-column__category"
  :data-category="content.categoryJapanese.name"
  >{{ content.categoryJapanese.ja }}</span
>

かなり楽で管理もしやすいですね。ありがとうございました!