概要

外部APIと連携して入力したテキストを翻訳できるアプリを Vue3 で実装します。
今回、実装するアプリの完成品は以下のようになります。

Translate コンポーネントの作成

src/componentsにtranslate.vueファイルを用意します。
テンプレートにアプリに必要な入力要素を追加します。

<template>
  <form class="flex">
    <textarea placeholder="テキストを入力" />
    <select>
      <option>言語を選択</option>
    </select>
    <textarea placeholder="結果の表示" />
    <button>翻訳</button>
  </form>
</template>

LibreTranslate API

アプリにロジックを書いていく前に翻訳に使う外部APIの使い方を調べます。
使用するのはオープンソースの LibraTranslate です。

まずはどのような言語に対応しているかを調べてみましょう。
このAPIではサポートしている言語をGET /languagesで取得することができます。

これをfetchで取得する関数を実装すると以下のようになります。

const getLanguageList = async () => {
  const resp = await fetch("https://libretranslate.de/languages")
  return resp.json()
}

テキストの翻訳結果を取得したい場合は/translateエンドポイントに POSTでリクエストを送信します。
必要なパラメータは翻訳したいテキスト、元々の言語、翻訳する言語の3つです。

const translateText = async (text, source, target) => {
  const resp = await fetch("https://libretranslate.de/translate", {
    method: "POST",
    body: JSON.stringify({
      q: text,
      source: source,
      target: target
    }),
    headers: { "Content-Type": "application/json" }
  })
  return resp.json()
}

翻訳結果の取得には入力されたテキストの言語が何かを指定する必要があります。
POST /detectエンドポイントを使えばテキストの言語が何かを調べることができます。

const detect = async (text) => {
  const resp = await fetch("https://libretranslate.de/detect", {
    method: "POST",
    body: JSON.stringify({ q: text }),
    headers: { "Content-Type": "application/json" }
  })
  return resp.json()
}

フォームに入力された値のステート管理

必要なことは調べ終わったのでTranslateコンポーネントの実装に戻ります。
まずは翻訳したいテキストの入力フォームから変更を加えていきます。

入力されたテキストのデータを保持する変数を用意します。

const inputText = ref("")

入力フォームの要素とv-modelで紐付けて入力されたテキストが変数に反映されるようにします。

<textarea placeholder="テキストを入力" v-model="inputText" />

翻訳したい言語の選択

翻訳したい言語をセレクトボックスで選択できるようにします。
言語のリストは先ほど調べたgetLanguageList関数を使って取得します。

setup内に以下のコードを追加してください。

const target = ref("")
const languageList = ref([])

const getLanguageList = async () => {
  const resp = await fetch("https://libretranslate.de/languages")
  return resp.json()
}
getLanguageList().then(result => languageList.value = result)

取得したリストはv-forを使ってセレクトボックスの選択肢として展開します。
選択肢が選ばれたときにcodeの値をtarget変数に格納するようにします。

<select @change="(e) => target = e.target.value">
  <option>言語を選択</option>
  <option
    v-for="lang in languageList"
    :key="lang.code"
    :value="lang.code"
  >
    {{ lang.name }}
  </option>
</select>

翻訳結果の取得

翻訳ボタンが押されると結果を表示するテキストエリアに翻訳結果が表示されるようにします。

ボタンが押されると入力されたテキストの言語をdetect関数で取得し、それからtranslateText関数で翻訳結果を取得するようにします。
結果を取得したらデータを変数に格納してテキストエリアに表示させます。

const resultText = ref("")

const onTranslate = async () => {
  const data = await detect(inputText.value)
  const result = await translateText(inputText.value, data[0].language, target.value)
  
  resultText.value = result.translatedText
}

最後に結果を表示するテキストエリアとresultTextを紐付けすれば完成です。

<textarea placeholder="結果の表示" :value="resultText"></textarea>