開発eurekapu-nuxt4メモ

多言語化の計画書を Codex に4回叩かれた

eurekapu-nuxt4 を ja/en の2言語に分ける計画を朝イチで書き始めた。memo/2026-05-08/cockpit-i18n-plan.md に下書きを置いて、すぐに Codex に投げた。

codex exec -m gpt-5.5 "このプランをレビューして。瑣末な点へのクソリプはしないで。致命的な点だけ指摘して: ..."

1stレビューでは「対象外ページに英語URLでアクセスしたときの挙動が定義されていない」「localePath の fallback がない」など、設計の穴を3つ突かれた。プランを直して resume --last で再レビュー。2nd では route name の生成方法が曖昧と指摘されて自動生成スクリプト案を追記。3rd で hreflang/canonical の SEO 配慮が抜けていると指摘され、useLocaleHead を組み込む方針に書き直した。4th でようやく「致命的な点はない」が返ってきた。

一発で OK が出るのを期待していたが、4回叩かれたおかげで Phase 1 の実装に入る前に設計の輪郭がはっきり見えた。レビュアーがいない一人開発で、Codex は無料で殴ってくれるリードとして機能する。

@nuxtjs/i18n と route name 自動生成

pnpm add -D @nuxtjs/i18n@9.5.6

nuxt.config.ts に i18n 設定を足した。strategy は prefix_except_default、defaultLocale は ja、対象外ページは /en/... でアクセスすると 404 を返す。

317ページ分のルート定義を手で書く気はなかった。pages/ を再帰的に走査して route name を吐くスクリプトを scripts/generate-i18n-routes.ts に置いた。1本走らせると pages.ts に対応表が降ってきた。手動で書いていたら半日溶けていた工程が、5分で終わった。

LangSwitcher と localePath

components/LangSwitcher.vue を1つ作った。useLocaleHead で hreflang・canonical・og:locale を <head> に流し込む。SEO 都合で必要な3点セットが、コンポーザブル1つで埋まる。

リンクは全て localePath('/lessons/...') 経由に直した。対象外ページ(英語版を用意しないページ)にスイッチャーが向くと壊れるので、fallback で /lessons を出す分岐を入れた。

Phase 1 が想定より早く終わったので「全部いこう」

午前中で Phase 1(i18n 基盤)が終わった。当初は Phase 2-4(コンテンツ本体の英訳)を別日に切る計画だったが、基盤の動きが想定通りすぎて止める理由がない。「全部いこう」と判断して、そのままコンテンツ本体に突っ込んだ。

accountsMaster には optional な labelKey を追加して、Account.name(日本語)はそのまま残した。既存の日本語ロジックを壊さずに、表示だけ多言語化できる構造にした。BS / PL / CS / SS / JournalCard / JournalExample コンポーネントを順に開いて、テンプレート内の文字列を全部 t() で包んだ。

取引25件には titleKeyscenarioKey を追加。ja.jsonen.json に英訳を流し込んで、画面で en に切り替えると英語で取引タイトルが出るところまで通した。

ガイド29件 + SVG 22件 + アニメーション 22件をサブエージェント並列で

ガイドテキストとSVG内ラベルとアニメーションキャプションを全部1人で英訳すると、たぶん2日溶ける。サブエージェントを並列で6本立てて分担させた。プロンプトに「会計用語は IFRS 表記寄せ、Income Statement / Cash Flow Statement / Statement of Changes in Equity」を入れて統一した。

並列で走らせている間、メイン側で ElevenLabs の検証に取り掛かった。

ElevenLabs で No.01 の英語音声を試験生成

.env に既に ElevenLabs の API キーは入れていた(VOICEVOX のずんだもん辞典作業のときに使ったやつ)。No.01(株式発行のシナリオ)のガイド音声4本だけを試験生成。706文字を消費して 853KB の mp3 が4本出てきた。

聞いてみると、数字の読み上げで違和感があった。-30 を「マイナスサーティ」と発音せず、ハイフンを無視してしまう。「ネガティブサーティ」と読んでしまう箇所もある。

preprocess を3段階で拡充した

英語版「ユーザー辞書」の代わりに、API に渡す前のテキストに前処理を噛ませることにした。

最初は -30 minus 30 の置換だけ。これで数字は通るようになった。

次に簿記特有の 記号で再びつまずいた。日本の財務諸表では金額のマイナスを ▲100 と書く慣習があり、英語で読み上げると無視される。minus に置換するルールを追加した。

最後にナレーションの正式表記の問題。日本語版では P/L CS SS のような略号で書いていたが、英語ナレーションが「ピー・スラッシュ・エル」と読んでしまう。preprocess で以下を置換した。

  • P&L / P/LIncome Statement
  • CSCash Flow Statement
  • SSStatement of Changes in Equity

3段階で拡充した結果、No.01 の音声を聴き直すと自然に通るようになった。

No.02〜No.09 を生成。10問で打ち止め

No.01 で preprocess が安定したので、No.02 から No.09 まで一気に生成した。48ステップ分・8,245文字を消費して、累積 11MB になった。

ElevenLabs の月1万クレジットの上限を見ると、残りで全25取引は明らかに足りない。今月は10問までで打ち止めにする判断をした。残り15問は来月以降に分割する。

来月の自分が忘れないように memo/2026-06-01/ ディレクトリを切って、英語音声続き対応のメモを置いた。積み残しを来月の頭に投げる運用は、今月の自分が来月の自分にチケットを切る感覚で意外と効く。

getGuideAudioPath を locale 連動に

最後に音声配信側の調整。getGuideAudioPath() を ja/en で分岐するように直して、locale が en のときは audio-assets/en/... を返すようにした。

dev 配信ミドルウェアは元々 audio-assets ディレクトリを直接マップする実装だったので、変更不要だった。設計が綺麗だった過去の自分に感謝した。

1日の振り返り

Codex に4回叩かれた朝、Phase 1 が早く終わって「全部いこう」と判断した昼、ElevenLabs の preprocess を3段階で詰めた夕方、来月の自分にチケットを切った夜。1日の中で4つのフェーズが流れた。

人間は方針判断(「Phase を一気にやる」「10問で打ち止める」)と、画面と耳でのチェック(音声を聴いて違和感を拾う)に集中した。残りの実装・英訳・スクリプト生成は全部 Claude Code とサブエージェントが回した。

英語版の続きは月初に再開する。