2日目のゴールと今日やること
2日目のテーマは
「翻訳アプリを“実用レベル”に近づけるために、API から言語一覧を取得し、UI とエラーハンドリングを強化する」
ことです。
1日目であなたはすでに、
- テキストを入力して翻訳
- fetch と async/await の基本
- POST リクエストの書き方
- ローディング表示
- 通信失敗時の基本的な分岐
を習得しました。
2日目はここに、
- LibreTranslate API から言語一覧を取得して自動生成
- ローディング表示の改善
- エラーハンドリングのパターン化
- 入力チェック(バリデーション)
- 「翻訳履歴」の基礎
を追加して、“毎日使える翻訳ツール”に近づけます。
言語一覧を API から取得する
なぜ自動取得が必要なのか
1日目では <select> に手書きで言語を入れていましたが、
実際の翻訳アプリは API から言語一覧を取得して UI を作る のが普通です。
理由はシンプルで、
- API が対応言語を増やしたときに自動で反映される
- コードの保守性が上がる
- UI が常に最新の状態になる
というメリットがあるからです。
LibreTranslate の言語一覧 API
GET https://libretranslate.com/languages
返ってくる JSON はこういう形です。
[
{ "code": "en", "name": "English" },
{ "code": "ja", "name": "Japanese" },
{ "code": "es", "name": "Spanish" }
]
つまり、
「code を value に、name を表示名にして <option> を作る」
という流れになります。
言語一覧を取得して <select> を自動生成する
DOM 要素を取得
const sourceLang = document.getElementById("sourceLang");
const targetLang = document.getElementById("targetLang");
const statusDiv = document.getElementById("status");
JavaScript言語一覧を取得する関数
async function loadLanguages() {
statusDiv.textContent = "言語一覧を取得中です…";
try {
const response = await fetch("https://libretranslate.com/languages");
if (!response.ok) {
statusDiv.textContent = `言語一覧の取得に失敗しました。(${response.status})`;
return;
}
const languages = await response.json();
renderLanguageOptions(languages);
statusDiv.textContent = "言語一覧の取得に成功しました。";
} catch (error) {
statusDiv.textContent = "通信に失敗しました。ネットワークを確認してください。";
console.error(error);
}
}
JavaScript言語一覧を <select> に反映する
function renderLanguageOptions(languages) {
sourceLang.innerHTML = "";
targetLang.innerHTML = "";
languages.forEach((lang) => {
const option1 = document.createElement("option");
option1.value = lang.code;
option1.textContent = lang.name;
const option2 = option1.cloneNode(true);
sourceLang.appendChild(option1);
targetLang.appendChild(option2);
});
sourceLang.value = "en";
targetLang.value = "ja";
}
JavaScriptページ読み込み時に実行
loadLanguages();
JavaScriptローディング表示を改善する
「翻訳中」と「言語取得中」を区別する
1日目ではローディング表示が単一でしたが、
2日目では 状況に応じてメッセージを変える ことで、
ユーザーが「今何が起きているか」を理解しやすくします。
例:
- 言語一覧取得中 → 「言語一覧を取得中です…」
- 翻訳中 → 「翻訳中です…」
ボタン無効化も状況に応じて行う
function startLoading(message) {
statusDiv.textContent = message;
translateButton.disabled = true;
}
function endLoading() {
translateButton.disabled = false;
}
JavaScript翻訳処理のエラーハンドリングを強化する
1日目のエラー分岐を思い出す
- ネットワークエラー
- HTTP エラー
- JSON の中身が想定外
2日目では、これを 「ユーザーに伝わる形」 に整えます。
改良版の翻訳関数
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;
addHistory(text, data.translatedText, source, target);
} catch (error) {
statusDiv.textContent = "通信に失敗しました。ネットワークを確認してください。";
console.error(error);
} finally {
endLoading();
}
}
JavaScript翻訳履歴の基礎を作る
履歴の構造を決める
翻訳履歴はこういう形にします。
- 入力テキスト
- 翻訳結果
- 翻訳元言語
- 翻訳先言語
const history = [];
const historyDiv = document.getElementById("history");
JavaScript履歴を追加する
function addHistory(original, translated, source, target) {
history.unshift({
original,
translated,
source,
target
});
if (history.length > 5) {
history.pop();
}
renderHistory();
}
JavaScript履歴を表示する
function renderHistory() {
if (history.length === 0) {
historyDiv.textContent = "翻訳履歴はまだありません。";
return;
}
let html = "<h3>翻訳履歴</h3>";
history.forEach((item) => {
html += `
<div class="history-item">
<p><strong>${item.original}</strong></p>
<p>→ ${item.translated}</p>
<p>(${item.source} → ${item.target})</p>
</div>
`;
});
historyDiv.innerHTML = html;
}
JavaScript2日目のまとめ
今日やったことを整理すると、こうなります。
- 言語一覧を API から取得して
<select>を自動生成 - ローディング表示を状況に応じて変更
- エラーハンドリングを「ユーザーに伝わる形」に改善
- 翻訳履歴の基礎を実装
- fetch / async/await の“型”をさらに強化
どれも新しい文法ではなく、
「API のレスポンスを理解して、UI に反映する」
という作業の積み重ねです。
今日いちばん深く理解してほしいこと
2日目の本質は、
「API のレスポンスを UI にどう反映するかがアプリの質を決める」
ということです。
言語一覧
翻訳結果
エラー内容
履歴
これらはすべて「API の結果」です。
fetch → async/await → JSON → UI
という流れを理解できれば、
どんな API でも扱えるようになります。
3日目では、
この翻訳アプリに「自動翻訳」「入力補完」「お気に入り翻訳」などを追加して、
さらに実用的なツールに育てていきます。

