VDataTableを日本語対応にする Nuxt3×Vuetify3

# VDataTableを普通に使ってみる
https://vuetifyjs.com/en/components/data-tables/basics/

Vuetify3公式サイトのサンプルコードを使えば簡単に試すことができますが、テーブルに表示される`Items per page`や `1-5 of 10`が英語表記になっています。
日本語化について調べてみても記事がなかったので、ここに投稿します。

![スクリーンショット 2023-09-01 15.27.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252959/0aff3f8d-9e1e-fdfa-e188-79cf7d20826a.png)

Nuxt3にVuetify3をインストールする方法はこちらの記事が非常にわかりやすく簡単でした。

https://qiita.com/usuijuice/items/985ec44cf138b7304ffd


# VDataTableを日本語対応にする方法
この方法を使えば、表示されるテキストを自由に変更することができます。
日本向けにサービスを作る場合は日本語化したほうが良いので、その方法を記載します。

`VDataTable`のAPI一覧はここにあります。

https://vuetifyjs.com/en/api/v-data-table/

これを読んでみるとテーブル内のテキストを変更することができそうです。
他にもデータがない場合のテキストなども変更できそうです。

## 日本語化した画面
![スクリーンショット 2023-09-01 15.50.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252959/0a49ad60-6938-53c2-242e-2bbb74f1784b.png)

![スクリーンショット 2023-09-01 15.50.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252959/8a4109da-d4cf-b717-6b5a-63f71fe1dc0c.png)


## ソースコード
今回はNuxt3のCompositionAPIで記述しています。
v-data-tableに`items-per-page-text`と`page-text`と`items-per-page-options`を使って
一部日本語化しています。

`1-10 件 / 10 件中`の表示は簡単に日本語化できなかったので、pageText computed関数を使って
件数の表示を日本語化しました。

```vue:pages/table.vue
<script setup lang="ts">
import { VDataTable } from 'vuetify/labs/VDataTable'

// レイアウトを指定する場合は記述する
definePageMeta({
  layout: 'default'
})

useHead({
  title: 'VDataTable',
  titleTemplate: '',
  meta: [
    {
      name: 'description',
      content: 'これはディスクリプション'
    }
  ]
})

const currentPage = ref(1)
const itemsPerPage = ref(5)
const headers = ref([
  {
    title: 'Dessert (100g serving)',
    align: 'start',
    sortable: false,
    key: 'name'
  },
  { title: 'Calories', align: 'end', key: 'calories' },
  { title: 'Fat (g)', align: 'end', key: 'fat' },
  { title: 'Carbs (g)', align: 'end', key: 'carbs' },
  { title: 'Protein (g)', align: 'end', key: 'protein' },
  { title: 'Iron (%)', align: 'end', key: 'iron' }
])

const desserts = ref([
  {
    name: 'Frozen Yogurt',
    calories: 159,
    fat: 6.0,
    carbs: 24,
    protein: 4.0,
    iron: '1'
  },
  {
    name: 'Jelly bean',
    calories: 375,
    fat: 0.0,
    carbs: 94,
    protein: 0.0,
    iron: '0'
  },
  {
    name: 'KitKat',
    calories: 518,
    fat: 26.0,
    carbs: 65,
    protein: 7,
    iron: '6'
  },
  {
    name: 'Eclair',
    calories: 262,
    fat: 16.0,
    carbs: 23,
    protein: 6.0,
    iron: '7'
  },
  {
    name: 'Gingerbread',
    calories: 356,
    fat: 16.0,
    carbs: 49,
    protein: 3.9,
    iron: '16'
  },
  {
    name: 'Ice cream sandwich',
    calories: 237,
    fat: 9.0,
    carbs: 37,
    protein: 4.3,
    iron: '1'
  },
  {
    name: 'Lollipop',
    calories: 392,
    fat: 0.2,
    carbs: 98,
    protein: 0,
    iron: '2'
  },
  {
    name: 'Cupcake',
    calories: 305,
    fat: 3.7,
    carbs: 67,
    protein: 4.3,
    iron: '8'
  },
  {
    name: 'Honeycomb',
    calories: 408,
    fat: 3.2,
    carbs: 87,
    protein: 6.5,
    iron: '45'
  },
  {
    name: 'Donut',
    calories: 452,
    fat: 25.0,
    carbs: 51,
    protein: 4.9,
    iron: '22'
  }
])

// 1ページあたり何件表示するかの日本語化
const itemsPerPageOptions = [
  { value: 5, title: '5件' },
  { value: 10, title: '10件' },
  { value: 25, title: '25件' },
  { value: 50, title: '50件' },
  { value: 100, title: '100件' },
  { value: -1, title: 'すべて' }
]

// 何件中何件を表示しているかを表示する
const pageText = computed((): string => {
  if (itemsPerPage.value === -1) {
    return `1-${desserts.value.length} 件 / ${desserts.value.length} 件中`
  }
  const startItem = (itemsPerPage.value * (currentPage.value - 1)) + 1
  const endItem = Math.min(itemsPerPage.value * currentPage.value, desserts.value.length)
  return `${startItem}-${endItem} 件 / ${desserts.value.length} 件中`
})
</script>

<template>
  <h1>v-data-table</h1>
  <a
    href="https://vuetifyjs.com/en/api/v-data-table/VDataTableServer.vue"
    target="_blank"
  >
    v-data-tableのオプション一覧
  </a>
  <v-data-table
    v-model:items-per-page="itemsPerPage"
    :headers="headers"
    :items="desserts"
    item-value="name"
    class="elevation-1"
    items-per-page-text="1ページあたりの表示数"
    :page-text="pageText"
    :items-per-page-options="itemsPerPageOptions"
  />
</template>

<style lang="scss">
// とりあえず記述しないとエラーがでるので適当なCSSを書いておく
.init {
  all: unset;
}
</style>

```