6日目のゴールと今日やること
6日目のテーマは
「翻訳アプリの内部構造を整理し、fetch・async/await・エラーハンドリングを“設計として理解する”」
ことです。
ここまでであなたはすでに、
- 翻訳
- 自動翻訳(デバウンス)
- 履歴
- お気に入り
- コピー機能
- ローディング表示
- 言語一覧の取得
といった機能を実装してきました。
6日目は、これらを 「読みやすく・直しやすく・拡張しやすいコード」 に整理していきます。
つまり今日は、
“中級者としての設計力”を身につける日
です。
状態管理(state)を「アプリの中心」に置く
状態をひとまとめにする理由
昨日までのコードでは、
お気に入り、履歴、ローディング状態などが
バラバラの変数として存在していました。
これをひとつの state にまとめると、
- どこに何があるか迷わない
- UI 更新がしやすい
- 保存(localStorage)と連動しやすい
- デバッグがしやすい
というメリットがあります。
state の基本形
const state = {
isLoading: false,
history: [],
favorites: [],
languages: []
};
JavaScript状態を更新する関数
function updateState(updates) {
Object.assign(state, updates);
}
JavaScriptこの関数があるだけで、
アプリ全体のコードがスッキリします。
fetch を「共通関数」にまとめて再利用する
なぜ共通化が必要なのか
翻訳アプリでは、
- 言語一覧取得
- 翻訳
- 自動翻訳
- 履歴から再翻訳
- お気に入りから再翻訳
など、fetch を使う場面が多いです。
そこで、
fetch のエラーハンドリングを共通化した関数
を作ります。
共通 fetch 関数(重要)
async function requestJson(url, options = {}) {
try {
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`HTTPエラー(${response.status})`);
}
const data = await response.json();
return data;
} catch (error) {
throw new Error(error.message);
}
}
JavaScript深掘りポイント
この関数は、
- fetch の失敗
- HTTP エラー
- JSON パースエラー
を すべて「Error」として上に投げる 役割を持っています。
これにより、
上位の関数は「何をしたいか」だけに集中できます。
翻訳専用の関数を「読みやすい形」にする
翻訳リクエストを共通化
async function requestTranslate(text, source, target, format) {
const body = {
q: text,
source: source,
target: target,
format: format
};
const data = await requestJson("https://libretranslate.com/translate", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body)
});
if (!data.translatedText) {
throw new Error("翻訳結果が取得できませんでした。");
}
return data.translatedText;
}
JavaScript深掘りポイント
requestTranslate は
「翻訳 API の仕様を知っている唯一の関数」
です。
他の関数は、
翻訳 API の細かい仕様を知らなくてよくなります。
ローディング表示を「状態と連動」させる
ローディング開始・終了を関数化
function startLoading(message) {
updateState({ isLoading: true });
statusDiv.textContent = message || "処理中です…";
translateButton.disabled = true;
}
function endLoading() {
updateState({ isLoading: false });
translateButton.disabled = false;
}
JavaScript深掘りポイント
ローディング表示は、
「ユーザーに安心感を与える UI」
です。
状態と UI を連動させることで、
アプリ全体の動きが統一されます。
翻訳処理を「ストーリーとして読める」形にする
translateText の完成形(6日目版)
async function translateText() {
const text = inputText.value.trim();
const source = sourceLang.value;
const target = targetLang.value;
const format = formatMode.value;
if (!text) {
statusDiv.textContent = "翻訳する文章を入力してください。";
resultDiv.textContent = "";
return;
}
if (source === target) {
statusDiv.textContent = "翻訳元と翻訳先が同じです。別の言語を選んでください。";
return;
}
startLoading("翻訳中です…");
resultDiv.textContent = "";
try {
const translated = await requestTranslate(text, source, target, format);
statusDiv.textContent = "翻訳に成功しました。";
resultDiv.textContent = translated;
addHistory(text, translated, source, target);
} catch (error) {
statusDiv.textContent = `翻訳中にエラーが発生しました:${error.message}`;
console.error(error);
} finally {
endLoading();
}
}
JavaScript深掘りポイント
この関数は、
「翻訳の流れをそのまま読める」
という設計になっています。
- 入力チェック
- ローディング開始
- 翻訳
- 成功時の処理
- 失敗時の処理
- ローディング終了
fetch の細かい処理はrequestTranslate に隠れているため、
とても読みやすくなっています。
通信失敗時の分岐を「ユーザー目線」で整理する
エラーの種類を分類する
翻訳アプリでは、次のようなエラーが起きます。
- ネットワークエラー
- HTTP エラー
- JSON パースエラー
- API の中身が想定外
- 入力が空
- 言語が同じ
これらをすべて
「ユーザーが理解できる言葉」
に変換します。
例:429(リクエスト過多)
if (response.status === 429) {
throw new Error("リクエストが多すぎます。少し待ってから再試行してください。");
}
JavaScript深掘りポイント
エラーメッセージは、
「技術的に正しい」より「ユーザーに伝わる」ことが大事
です。
UI を「使いやすい形」に整える
翻訳結果のコピー機能
copyButton.addEventListener("click", () => {
navigator.clipboard.writeText(resultDiv.textContent)
.then(() => statusDiv.textContent = "コピーしました。")
.catch(() => statusDiv.textContent = "コピーに失敗しました。");
});
JavaScript深掘りポイント
コピー機能は地味ですが、
翻訳アプリでは必須級の便利機能
です。
6日目のまとめ
今日やったことを整理すると、こうなります。
- state にアプリの状態を集約
- fetch を requestJson に共通化
- 翻訳処理を requestTranslate に分離
- translateText を「読みやすい流れ」に整理
- ローディング表示を状態と連動
- エラーハンドリングを原因別に整理
- UI の改善(コピー機能など)
どれも新しい文法ではなく、
「fetch / async-await / エラーハンドリングの型をどう設計に落とし込むか」
という話です。
今日いちばん深く理解してほしいこと
6日目の本質は、
「コードは“動けばいい”から、“読めて直せて拡張できる”に育てていくもの」
ということです。
fetch
async/await
try-catch
state
localStorage
UI 更新
これらがひとつの“型”としてまとまり始めています。
7日目では、この翻訳アプリを
中級編の完成形としてまとめる
回にします。
あなたのアプリが「本当に使えるツール」になる瞬間です。

