JavaScript | 1 日 120 分 × 7 日アプリ学習:API通信アプリ(LibreTranslate API)

APP JavaScript
スポンサーリンク

1日目のゴールと今日やること

LibreTranslate API 中級編 1 日目のテーマは
「テキストを入力 → API に送信 → 翻訳結果を表示する“翻訳アプリの基礎”を作る」
ことです。

扱う技術はこの 3 つ。

  • fetch
  • Promise / async-await
  • エラーハンドリング

そして実装としては、まずこのレベルを目指します。

  • 入力欄に文章を入れる
  • 翻訳元言語・翻訳先言語を選ぶ
  • 「翻訳する」ボタンを押す
  • LibreTranslate API から翻訳結果を取得
  • ローディング表示を出す
  • 通信失敗時にわかりやすいエラーメッセージを出す

翻訳アプリは「入力 → API → 出力」という流れがとても明確なので、
fetch・async/await の練習に最適です。


LibreTranslate API の基本を理解する

どんな API なのか

LibreTranslate は、無料で使える翻訳 API です。
Google 翻訳のように、テキストを送ると翻訳結果を返してくれます。

翻訳用のエンドポイントはこれです。

POST https://libretranslate.com/translate

送るデータは JSON 形式で、

{
  "q": "Hello",
  "source": "en",
  "target": "ja",
  "format": "text"
}

返ってくる JSON はこうです。

{
  "translatedText": "こんにちは"
}

つまり、
「テキストを送る → translatedText を受け取る」
というシンプルな構造です。


今日作るミニ翻訳アプリのイメージ

必要な UI

まずは最低限の UI を考えます。

  • 翻訳元テキスト入力欄
  • 翻訳元言語選択
  • 翻訳先言語選択
  • 翻訳ボタン
  • ステータス表示(ローディング・成功・エラー)
  • 翻訳結果表示欄

HTML のイメージはこんな感じです。

<textarea id="inputText" placeholder="翻訳したい文章を入力"></textarea>

<select id="sourceLang">
  <option value="en">英語</option>
  <option value="ja">日本語</option>
  <option value="es">スペイン語</option>
</select>

<select id="targetLang">
  <option value="ja">日本語</option>
  <option value="en">英語</option>
  <option value="es">スペイン語</option>
</select>

<button id="translateButton">翻訳する</button>

<div id="status"></div>
<div id="result"></div>

fetch を「API にお願いしに行く関数」として理解する

fetch の基本形

fetch は、
「この URL にアクセスして、結果をちょうだい」
とブラウザに頼む関数です。

LibreTranslate は POST リクエストなので、
fetch の書き方はこうなります。

fetch("https://libretranslate.com/translate", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    q: "Hello",
    source: "en",
    target: "ja",
    format: "text"
  })
});
JavaScript

ここで大事なのは、

  • method: “POST”
  • headers で JSON を送ることを宣言
  • body に JSON.stringify したデータを入れる

という 3 点です。


Promise と async/await をかみ砕いて理解する

Promise は「未来の結果の箱」

fetch はすぐに結果を返しません。
「あとで結果がわかるよ」という Promise を返します。

const promise = fetch(url);
JavaScript

then を使うと、

promise.then((response) => {
  console.log("終わったよ", response);
});
JavaScript

async/await は「同期っぽく書ける魔法」

Promise を then でつなぐと読みにくいので、
async/await を使うとスッキリします。

async function translate() {
  const response = await fetch(url);
  const data = await response.json();
}
JavaScript
  • await は「Promise が終わるまで待つ」
  • async は「この関数の中で await を使いますよ」という宣言

この 2 つはセットです。


エラーハンドリングの基本を理解する

エラーは 3 段階で考える

API 通信のエラーは、ざっくり 3 種類あります。

  1. fetch 自体の失敗(ネットワークエラー)
  2. HTTP エラー(ステータスコードが 200 以外)
  3. API が返した JSON の中身が想定外

これを全部 try-catch で扱います。


ローディング表示を入れる理由

翻訳は数百ミリ秒〜数秒かかることがあります。
その間、ユーザーは「押したのに何も起きない」と不安になります。

だから、

  • 「翻訳中です…」と表示
  • ボタンを無効化して連打を防ぐ

という UI が必要です。


中心となる async 関数を作る

DOM 要素を取得する

const inputText = document.getElementById("inputText");
const sourceLang = document.getElementById("sourceLang");
const targetLang = document.getElementById("targetLang");
const translateButton = document.getElementById("translateButton");
const statusDiv = document.getElementById("status");
const resultDiv = document.getElementById("result");
JavaScript

ローディング開始・終了の関数

function startLoading() {
  statusDiv.textContent = "翻訳中です…";
  translateButton.disabled = true;
}

function endLoading() {
  translateButton.disabled = false;
}
JavaScript

翻訳処理の本体(重要)

async function translateText() {
  const text = inputText.value.trim();
  const source = sourceLang.value;
  const target = targetLang.value;

  if (!text) {
    statusDiv.textContent = "翻訳する文章を入力してください。";
    resultDiv.textContent = "";
    return;
  }

  startLoading();
  resultDiv.textContent = "";

  try {
    const response = await fetch("https://libretranslate.com/translate", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        q: text,
        source: source,
        target: target,
        format: "text"
      })
    });

    if (!response.ok) {
      statusDiv.textContent = `サーバーエラーが発生しました。(${response.status})`;
      return;
    }

    const data = await response.json();

    if (!data.translatedText) {
      statusDiv.textContent = "翻訳結果が取得できませんでした。";
      return;
    }

    statusDiv.textContent = "翻訳に成功しました。";
    resultDiv.textContent = data.translatedText;

  } catch (error) {
    statusDiv.textContent = "通信に失敗しました。ネットワークを確認してください。";
    console.error(error);

  } finally {
    endLoading();
  }
}
JavaScript

ボタンにイベントを付ける

translateButton.addEventListener("click", translateText);
JavaScript

通信失敗時の分岐を“ユーザー目線”で設計する

失敗パターンごとにメッセージを変える

  • ネットワークエラー
    → 「通信に失敗しました。ネットワークを確認してください。」
  • HTTP エラー
    → 「サーバーエラーが発生しました。(ステータスコード)」
  • JSON の中身が想定外
    → 「翻訳結果が取得できませんでした。」

これだけで、ユーザーの安心感が大きく変わります。


1日目のまとめ

今日やったことは、翻訳アプリの“基礎の基礎”です。

  • fetch で API にデータを送る
  • async/await で読みやすく書く
  • try-catch で通信エラーを扱う
  • ローディング表示でユーザーを安心させる
  • HTTP エラーと「該当なし」を分ける

そして何より大事なのは、

「API が返す JSON の形を理解してからコードを書く」

という姿勢です。

LibreTranslate は translatedText を返す。
Datamuse は配列を返す。
NewsAPI は articles を返す。

API ごとに形は違うけれど、
fetch・async/await・エラーハンドリングの“型”は同じです。


次のステップ(2日目の予告)

2日目では、今日作った翻訳アプリに

  • 言語一覧を API から取得して自動生成
  • ローディング表示の改善
  • エラー表示のパターン化
  • 翻訳履歴の追加

などを加えて、
「毎日使える翻訳ツール」に育てていきます。

続きも一緒に作っていこう。

タイトルとURLをコピーしました