ベトナム語🇻🇳↔日本語🇯🇵に特化した、シンプルな翻訳MVPです。
トップページでそのまま翻訳でき、言い換え・ニュアンス・返信例まで確認できます。
入力欄では textarea 右下に音声入力・読み上げボタンを埋め込み、アイコンとツールチップで操作できます。
翻訳結果の各セクションも、読み上げ・コピーをアイコンボタン + ツールチップで利用できます。
翻訳履歴はブラウザの localStorage に最新 100 件まで保存されます。
履歴ペインは desktop ではメインペインと高さを揃えたままページ上部に追従し、ペイン内を独立スクロールできる accordion で、sticky ヘッダーの虫眼鏡からフローティング検索を開けます。各項目のピン留め・再入力・コピー・削除・読み上げを行えます。
UI言語はメインペイン右上のトグルボタン(日本語|ベトナム語)で切り替えられ、Cookie単位で SESSION KV に保存されます。
- Astro + TypeScript
- Cloudflare Pages (
@astrojs/cloudflare) - Astro API routes (
/api/translate,/api/translate-details,/api/reply) - Provider abstraction (
mock/openai)
- Install dependencies:
nvm use 22
npm install- Create local env file:
cp .env.example .env- (Optional) enable a real provider in
.env:
TRANSLATION_PROVIDER=openai
OPENAI_API_KEY=your_api_key
# Optional
OPENAI_MODEL=gpt-4.1-mini
OPENAI_BASE_URL=https://api.openai.com/v1OpenAI-compatible API を openai provider のまま使う場合:
TRANSLATION_PROVIDER=openai
OPENAI_API_KEY=your_compatible_api_key
OPENAI_MODEL=MiniMax-M3
OPENAI_BASE_URL=https://api.minimax.io/v1- Run:
npm run dev- Open:
http://localhost:4321
npm run dev は開発用サーバーです。ビルド後の出力を確認したいときは、先に build してから preview を使います。
- Build:
npm run build- Preview the built app:
npm run preview- Open:
http://localhost:4321
PowerShell 環境で npm ラッパーがうまく動かない場合は、次のように npm.cmd を使ってください。
npm.cmd run build
npm.cmd run previewローカル開発も Cloudflare Pages と同じく Node.js 22 を前提にしてください。
.env を以下のように設定すると、実際の OpenAI 翻訳を使えます。
TRANSLATION_PROVIDER=openai
OPENAI_API_KEY=your_api_key
OPENAI_MODEL=gpt-4.1-mini
OPENAI_BASE_URL=https://api.openai.com/v1その後 npm run dev を起動し、トップページから翻訳を実行してください。
TRANSLATION_PROVIDER を mock に戻すと、即座にモック動作へ切り替わります。
MiniMax を openai provider のまま使う場合は次の設定です。
TRANSLATION_PROVIDER=openai
OPENAI_API_KEY=your_minimax_api_key
OPENAI_MODEL=MiniMax-M3
OPENAI_BASE_URL=https://api.minimax.io/v1- 履歴は各ブラウザの
localStorageに保存されます - 保存対象は原文、主翻訳、言語方向、モード、トーン、作成日時です
- 最新 100 件まで保持し、ピン留めした履歴は先頭のセクションに分けて表示されます
- desktop では履歴ペインがページ上部に追従し、メインペインと同じ高さを保ちながら履歴ペイン内を独立スクロールできます
- 履歴ヘッダーと全件削除ボタンはスクロール中も表示されたままです
- 日付グループは折りたたみでき、各履歴項目の日時サマリーもスクロール中に sticky 表示されます
- 履歴ヘッダーの虫眼鏡ボタンでフローティング検索を開けます
- 検索は原文 + 主翻訳を対象にした部分一致(大文字小文字を区別しない)で、入力中に即時反映されます
- 検索ヒット 0 件時は通常の「履歴なし」とは別メッセージを表示します
- トグル再押下 /
Escape/ 外側クリックで検索を閉じると、検索語は破棄され全件表示に戻ります - 各履歴からピン留め / ピン留め解除、再入力、主翻訳のコピー、主翻訳の読み上げ、個別削除ができます
- 履歴行は視認性向上のために交互に色分けされています
- 補足情報(言い換え候補、ニュアンスメモ、返信例)は履歴には保存されず、再表示時に必要なら再取得します
- メインペイン右上のトグルボタン(日本語|ベトナム語)でUI言語を切り替えられます
- UI言語の設定は Cloudflare SESSION KV に保存され、ユーザーのセッション単位で保持されます
- 翻訳元言語(sourceLang)は従来通り
localStorageに保存されます
Astro のローカル開発では .env を使用します。
TRANSLATION_PROVIDER=mock(デフォルト)OPENAI_API_KEY=(TRANSLATION_PROVIDER=openaiの場合必須)OPENAI_MODEL=gpt-4.1-mini(任意)OPENAI_BASE_URL=https://api.openai.com/v1(任意)
MiniMax を使う場合の例:
TRANSLATION_PROVIDER=openaiOPENAI_API_KEY=your_minimax_api_keyOPENAI_MODEL=MiniMax-M3OPENAI_BASE_URL=https://api.minimax.io/v1
Cloudflare Pages ランタイムでは、Pages プロジェクト設定で同じ環境変数を設定してください。
Wrangler ローカルランタイムを使用する場合は、.dev.vars もサポートされています。
このプロジェクトは Cloudflare Pages Functions 用に設定されています。
wrangler.jsonc の内容:
pages_build_output_dir: "./dist"compatibility_flags: ["nodejs_compat"]- Astro sessions 用
SESSIONKV binding env.previewはデフォルトで production と同じSESSIONKV namespace を使用mainフィールドなし(このリポジトリは Standalone Worker ではなく Cloudflare Pages にデプロイするため)
Preview と Production を分離する必要がある場合は、後で別の Preview KV namespace を追加してください。
npx wrangler kv namespace create SESSION返された ID を wrangler.jsonc にコピーします:
後で Preview KV を分離する場合は、別の namespace を追加して env.preview で上書きしてください。
Cloudflare Pages で:
- この GitHub リポジトリを接続
- Build command:
npm run build - Build output directory:
dist - Node.js version:
22
Pages プロジェクト設定で、ローカル環境の .env で使用するのと同じ環境変数を追加します。
例:
TRANSLATION_PROVIDER=mockTRANSLATION_PROVIDER=openai+OPENAI_API_KEYTRANSLATION_PROVIDER=openai+OPENAI_BASE_URL=https://api.minimax.io/v1TRANSLATION_PROVIDER=openai+OPENAI_MODEL=MiniMax-M3
Pages プロジェクト設定で KV binding を追加します:
- Variable name:
SESSION - KV namespace:
wrangler.jsoncで使用している same namespace
Request:
{
"sourceLang": "ja",
"targetLang": "vi",
"text": "こんにちは",
"mode": "daily",
"tone": "normal"
}Response:
{
"mainTranslation": "...",
"context": {
"sourceLang": "ja",
"targetLang": "vi",
"mode": "daily",
"tone": "normal"
}
}Request:
{
"sourceLang": "ja",
"targetLang": "vi",
"originalText": "こんにちは",
"mainTranslation": "Xin chào",
"mode": "daily",
"tone": "normal"
}Response:
{
"alternatives": ["..."],
"nuanceNotes": ["..."],
"suggestedReplies": ["..."]
}Request:
{
"sourceLang": "ja",
"targetLang": "vi",
"originalText": "こんにちは",
"mainTranslation": "Xin chào",
"mode": "daily",
"tone": "normal"
}Response:
{
"suggestedReplies": ["..."]
}src/lib/translate/ はサービス抽象化を提供します:
mockprovider: 常時利用可能なフォールバックopenaiprovider:POST https://api.openai.com/v1/responsesを呼び出しますOPENAI_BASE_URLを OpenAI-compatible endpoint に切り替えた場合は、その backend に応じてresponsesまたはchat/completionsを自動選択
API routes はいずれも薄く、service layer に委任します。主翻訳は /api/translate、補足情報は /api/translate-details、返信例専用取得は /api/reply です。
トップページは最初に /api/translate で主翻訳を取得し、ユーザー操作で /api/translate-details を追加呼び出しして言い換え候補・ニュアンスメモ・返信例を表示します。/api/reply は独立 endpoint として残っています。
Cloudflare Pages CI 用に、build script は astro build の後に生成された _worker.js/wrangler.json、_worker.js/.dev.vars、.wrangler/deploy/config.json を削除します。また、現在の Pages uploader はデプロイ時にそのファイル名を期待するため、_worker.js/entry.mjs を _worker.js/index.js にコピーします。
開発サーバー起動後に、以下で API の疎通確認ができます。
curl -s -X POST http://localhost:4321/api/translate \
-H "content-type: application/json" \
-d '{
"sourceLang":"ja",
"targetLang":"vi",
"text":"こんにちは",
"mode":"daily",
"tone":"normal"
}'curl -s -X POST http://localhost:4321/api/reply \
-H "content-type: application/json" \
-d '{
"sourceLang":"ja",
"targetLang":"vi",
"originalText":"こんにちは",
"mainTranslation":"Xin chào",
"mode":"daily",
"tone":"normal"
}'curl -s -X POST http://localhost:4321/api/translate-details \
-H "content-type: application/json" \
-d '{
"sourceLang":"ja",
"targetLang":"vi",
"originalText":"こんにちは",
"mainTranslation":"Xin chào",
"mode":"daily",
"tone":"normal"
}'- 音声入力ボタンが無効になっている
SpeechRecognition/webkitSpeechRecognitionが必要です。主に Chrome 系ブラウザで利用できます。非対応時も textarea 内には薄いプレースホルダー風のアイコンが残ります。
- 読み上げが期待した声で再生されない
- 利用できる音声はブラウザと OS に依存します。日本語は
ja-JP、ベトナム語はvi-VNを優先して選択します。
- 利用できる音声はブラウザと OS に依存します。日本語は
OPENAI_API_KEY is required when TRANSLATION_PROVIDER=openai..envにOPENAI_API_KEYが設定されているか確認してください。
- MiniMax を
openaiprovider で使いたいOPENAI_BASE_URL=https://api.minimax.io/v1とOPENAI_MODEL=MiniMax-M3を設定してください。
- 履歴がブラウザごとに違う
- 履歴はサーバー保存ではなく
localStorage保存です。別ブラウザやシークレットウィンドウとは共有されません。
- 履歴はサーバー保存ではなく
- OpenAI 側エラーで
json_object関連メッセージが出る- 実装側で
json指示を入力に含める対応済みです。古い dev サーバープロセスを停止して再起動してください。
- 実装側で
npm run checkで@rollup/rollup-linux-x64-gnu欠落エラー- npm の optional dependency 問題です。
npm iを再実行してください。
- npm の optional dependency 問題です。
npm run dev: Astro の開発サーバーを起動npm run build: Cloudflare Pages 向けの成果物をdist/に生成npm run preview:build後の成果物をローカルで確認npm run check: Astro / TypeScript のチェックを実行
このプロジェクトは MIT License の下でライセンスされています。詳細については LICENSE ファイルを参照してください。