Nihongo Pocketのホーム画面と辞書画面

日本語を学びたいのに、通信環境が学習を止めてしまう

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、テストを決める中心の要件として扱っています。

Nihongo Pocketの紹介ページを見る

App StoreでNihongo Pocketを見る