
日本語を学びたいのに、通信環境が学習を止めてしまう
Nihongo Pocketは、ミャンマー語を母語とする人のための日本語学習アプリです。単語、会話、ドリル、読解、辞書をN5からN1まで収録し、日本語音声とミャンマー語の説明を一緒に確認できます。
設計の出発点は、機能の多さではありませんでした。
ミャンマーでは、地域や時間帯によって通信速度が安定しないことがあります。停電や通信断でダウンロードが途中で止まることもあり、大容量のデータを一度に取得し続ける前提は現実的ではありません。
そこで「オンラインなら便利」ではなく、「オフラインでも学習そのものは止まらない」を最優先にしました。
技術スタック
モバイルアプリはExpoとReact Native、TypeScriptで開発しています。画面遷移にはExpo Routerを使い、学習進捗とダウンロード状態は端末内のSQLiteへ保存します。
主な構成は次の通りです。
- Expo 57 / React Native 0.86 / TypeScript
- Expo Router
- expo-sqlite:学習進捗とダウンロード済み教材の保存
- expo-file-system:音声・教材パックの永続キャッシュ
- expo-audio:ダウンロード済み日本語音声の再生
- expo-background-task:中断したダウンロードの再開
- Cloudflare Workers + Hono:マニフェスト配信と進捗同期API
- Cloudflare D1:匿名ユーザーと進捗のバックアップ
- Cloudflare R2 + CDN:音声・教材JSON・画像の配信
- Node.js + TypeScriptのコンテンツCLI:検証、TTS生成、パック作成、公開
学習結果は最初に端末へ書き込みます。サーバー同期はバックアップのための補助であり、APIの応答を待たないと次へ進めない設計にはしていません。
初回から使える小さなスターター
アプリには、最初の単語ステージ、ストーリー、必要な音声だけを小さなスターターとして同梱しています。初回起動時にインターネットへ接続できなくても、インストール直後から学習を始められます。
残りの教材は、レベルやテーマごとのパックに分けました。1パックの目安は3〜6MBです。N5だけ、会話だけというように、必要な範囲を選んでダウンロードできます。
ダウンロード済みの教材は端末へ残り、音声を含めて完全にオフラインで使えます。容量を空けたいときは教材パック単位で削除できますが、学習進捗は残します。
音声を「ストリーミングしない」という判断
発音を学ぶアプリでは音声が重要です。しかし、再生するたびにネットワークへ取りに行くと、回線が遅いときに待ち時間や無音が発生します。
Nihongo Pocketでは、日本語音声をIrodori TTSで事前生成し、R2から端末へダウンロードして再生します。未ダウンロードの音声をその場でストリーミングすることはせず、取得済みファイルだけを確実に鳴らします。
音声は学習用途に十分な品質を保ちながら、MP3 32kbps・モノラル・24kHzへ圧縮しています。単語、例文、会話を行き来しても急に音量が変わらないよう、生成後にラウドネスも揃えています。
9,657回のHTTP要求を101回へ
音声を1ファイルずつ取得すると、ファイル自体が小さくてもHTTP接続の回数が増えます。高遅延の回線では、この細かな待ち時間が積み重なります。
そこで、複数のMP3を再圧縮せずに連結した audio.bundle と、各音声の位置・サイズ・SHA-256を記録した audio-index.json を作りました。
37パック・9,620音声で測定した結果、初回取得時のHTTP要求数は9,657回から101回になり、98.95%削減できました。bundleは最大でも約4.24MiBです。
取得後はbundleを端末上で個別音声へ展開し、1件ずつハッシュを検証します。更新時は前の版と同じ音声を端末内で再利用し、変更された音声だけを取り直します。
停電や通信断が起きても、続きから再開する
ダウンロード中に通信が切れても、完了済みのファイルは消しません。状態と進捗をSQLiteへ保存し、アプリの再起動、フォアグラウンド復帰、ネットワーク再接続時にキューを再開します。
ユーザーは一時停止と再開を選べます。Wi-Fiだけでダウンロードする設定も用意し、モバイル通信中はキューを残したまま待機します。
教材本文の小さなJSONを先に取得するため、音声のダウンロードが終わっていなくても文字での学習は始められます。すべて揃うまで画面を止める無限ローディングは使いません。
ファイルはSHA-256で検証し、内容が一致しない場合は破棄して再取得します。教材のURLには版番号を含め、更新途中でも確認済みの旧版を使い続けられるようにしました。
AIで作り、母語話者の感覚を重ねる
数千語の語彙、例文、会話、ドリルを人手だけで初稿から作るのは現実的ではありません。そこでAIを、原稿候補の作成、重複検出、文字種の検査、問題の正答が一つに決まるかの反証に使っています。
ただし、AIが自然だと判定したミャンマー語が、実際の会話でも自然とは限りません。
私の妻はミャンマー出身で、ミャンマー語の母語話者です。AIが作った訳文やアプリ内の表現をそのまま正解とせず、開発者が内容を確認したうえで、母語話者として感じる違和感や伝わり方を確認してもらい、修正へ戻せる流れを作りました。
工程は、AIによる初稿と一次レビュー、機械的な検証、開発者の判断、母語話者のフィードバックという順番です。教材数が多いため、AIレビューだけを「母語話者確認済み」とは扱いません。レビュー状態を記録し、重要な画面文言や学習表現から確認範囲を広げています。
AIは量と見落としの検出に強く、母語話者は文脈、距離感、日常で本当に使う言い回しを判断できます。どちらか一方に任せるのではなく、役割を分けることが品質につながりました。
利用環境から逆算すると、機能の優先順位が変わる
高速な通信を前提にすれば、音声は都度ストリーミングするほうが実装は簡単です。しかし、実際に使う人の環境から考えると、必要なのは派手なオンライン機能よりも、中断しても失わないこと、待たせないこと、一度取得したデータを繰り返し使えることでした。
Nihongo Pocketでは、オフライン対応を追加機能ではなく、データ設計、音声形式、配信単位、UI、テストを決める中心の要件として扱っています。