PRODUCT NOTE / PRD

MyDictly

2 言語を、つなぐ単語学習アプリ。旧名 LangBridge
この文書は「何ができるか」ではなく、なぜ・誰のために・どんな判断で作ってきたかを記録した開発ノートです。

ステータスShipped / Active(継続開発中・オープンソース)
現行バージョンv1.4.0(公開中/MyDictly へ改名。iOS も App Store で公開中)
プラットフォームAndroid(APK 直配布)/ iOS / Web / Mac
対象ユーザー自作の単語リストで語学を学ぶ人(多言語)
最終更新2026-10-02
関連リンク App Store ・ Android APK ・ GitHub(OSS) ・ 変更履歴(Changelog) ・ プロダクトの系譜
TL;DR

ひとことで

MyDictly は、自分で作った単語リスト(スプレッドシート)を取り込み・フラッシュカードで暗記・Google Sheets へ書き戻しまでまとめて行える、シンプルな 2 言語対応の単語学習アプリです。

巨大な辞書 DB は自前で持たず、外部辞書へのリンクと外部 API に委ねることで、アプリは「自作単語帳の管理と学習」に集中します。

ソースコードは GitHub で公開しています。

Problem

背景・解きたい課題

自分で単語を集めて覚えたい学習者には、次の壁があった。

MyDictly では、スプレッドシートを軸にして、取込・暗記・同期・辞書リンクを 1 つにまとめた。

Who

ターゲットユーザー

プライマリ

自分でスプレッドシートに単語を集めて覚えたい語学学習者。当初は中国語⇄日本語を起点にし、現在は言語に依存しない設計(18 言語の読み上げ対応)へ広げている。

主なユースケース

  • スプレッドシートの単語を一括取込
  • フラッシュカードで音声付き暗記
  • 外部辞書リンクからすぐ深掘り
Solution & Scope

解決策とスコープ

コア機能(In scope)

  • Google Sheets 一括取込(列マッピング自動・重複制御)
  • インクリメンタル検索(曖昧/前方/完全一致)
  • フラッシュカード学習(表裏に音声読み上げ・18 言語)
  • 外部辞書リンク統合(Google/Weblio/北辞郎ほか)
  • Google Sheets へのエクスポート
  • AI アシスト・AI 深掘り(意味・例文)
  • Firebase によるデバイス間・自動同期

やらないこと(Non-goals)

  • 自前の巨大辞書 DB は持たない(外部辞書に委ねる)
  • 会話・ロールプレイ学習(Engly が担当)
  • 習慣トラッキング(DayGrid が担当)
Success Metrics

成功指標(KPI)

「自作単語帳が回り、続く」状態になっているかを、次の指標で見る。数値は目標仮置き

1+ 回
初週の取込完了率
(自作リストが載るか)
3+ 回/週
フラッシュカード利用
(暗記が回るか)
> 30%
同期の利用率
(複数端末で続くか)
Decision Log

主要な意思決定ログ

各アップデートの裏にある「なぜ」を、決定・仮説・結果の 3 点で残す。理由は変更内容から再構成

v1.3.7 の後始末 署名鍵移行で Firebase への SHA-1 登録が抜け、Android の Google ログインが3ヶ月近く機能していなかった
DECISION

Firebase Console(Android アプリ jp.langbridge の設定)に、共通リリース鍵(CN=nzw)の SHA-1・SHA-256 フィンガープリントを追加登録し、更新された google-services.json をアプリに反映した。

WHY / 仮説

v1.3.7(2026-07-12)で debug 鍵から共通リリース鍵へ署名を移行した際、update.json の notice は埋めたが、Firebase Console への新しい鍵の SHA-1 登録は行っていなかった。Android の Google Sign-In(Credential Manager)は、アプリの署名証明書を Firebase/Google 側に登録済みのフィンガープリントと照合して認証するため、未登録のままでは認証が成立しない。

厄介なのは失敗の出方で、「このアプリは認証できない」という直接のエラーにはならず、ユーザーが何もしていないのに canceled(キャンセルされた)という結果だけが返る。2026-10-02、APK 版でログインボタンを押すと即座に失敗する、という報告で発覚した。

RESULT

SHA-1 登録後、リリース鍵で再ビルドした APK で確認したところ、以前は即座に失敗していたログインが、正規の Google サインイン画面(アカウント選択)まで進むようになった。

iOS は Bundle ID + URL Scheme ベースで認証しており SHA-1 の概念が無いため、元々この問題の影響を受けていない。Web 版も対象外(Firebase Authentication の「承認済みドメイン」という別の仕組みを使う)。

v1.4.0 「辞書を持たない」方針を一部撤回し、辞書は持つが単語帳とは別枠にする
DECISION

PDIC 形式の辞書ファイルを取り込めるようにした。ただし取り込んだ語は単語帳(DictionaryEntry)に流し込まず、引くためだけの参照辞書として別に保持する。

検索結果には「辞書」欄として出るが、マイ単語一覧には現れず、習熟度もお気に入りも持たない。単語カードに混ぜて出題することはできるが、その結果は保存しない。

WHY / 仮説

「自前辞書を持たない」という初期の判断は、外部辞書 API が使える前提で成り立っていた。実際には API の URL が未設定だと辞書欄が丸ごと無反応になり、オフラインでは何も引けない。

一方で単純に辞書を取り込んで単語帳に入れる案は破綻する——単語帳の保存は単一 JSON なので、数万〜数百万語を流し込めば読み書きのたびに全体を舐めることになる。

そこで「辞書は資産として持つが、単語帳のデータモデルには入れない」と線を引いた。PDIC を選んだのは、形式自体がソート済みインデックス+固定長ブロックというランダムアクセス向けの構造で、全件をメモリに載せずに引けるため。

加えて日本語圏の個人作成辞書がこの形式で多く流通している。

RESULT

10 万語規模の辞書でも、二分探索で触れた見出語だけを復号するので 17 回程度の比較で引ける。単語帳側のデータ量は辞書を入れても増えない。

代償として、辞書の語には習熟度が付かない——覚えたい語は単語帳へ手で登録し直す必要があり、ここは今後の課題として残した。

v1.4.0 BOCU-1 デコーダを自前で移植する
DECISION

PDIC/Unicode 辞書の文字符号化である BOCU-1(Unicode UTS #6)のデコーダを、リファレンス実装(C)から Dart へ移植した。

デコードのみ実装し、エンコーダは往復テスト用にテストコード側へ置いた。

WHY / 仮説

pub.dev に Dart 実装が存在しなかった。辞書対応を諦めるか、仕様を読んで書くかの二択で、後者を選んだ。

判断材料は分量よりも「検証できるか」で、UTS #6 にはテストベクタがあり、エンコーダを書けば往復テストで正しさを機械的に確かめられる。

仕様が固定されていて後から変わらない領域なので、一度書けば保守コストはほぼ発生しないとも見た。

RESULT

辞書を原本のまま読めるようになった——取り込み時に独自形式へ変換しないため、変換の待ち時間もディスクの二重消費も発生しない。

BOCU-1 の「0x00〜0x20 の大半を出力しない」「バイト列の大小がコードポイントの大小と一致する」という性質が、そのまま終端判定と二分探索に使えている。

v1.4.0 取り込み口を増やすのではなく、行列に落としてから 1 か所に集める
DECISION

Excel(.xlsx)と CSV / TSV の取り込みを追加するにあたり、取り込み元ごとの処理を作らず、すべてを List<List<String>> の行列へ落としてから共通の ImportRowsUseCase に通す形にした。

ファイルの種類は拡張子ではなく中身のバイト列で判別する。

WHY / 仮説

列マッピング・重複判定・取り込みセッションの記録は、元がスプレッドシートでも Excel でも同じ扱いでよい。取り込み元ごとに分岐を増やすと、この 3 つが経路の数だけ複製される。

拡張子を捨てたのは実地の事情で、配布サイトによっては .dic が download_file.php のような名前で落ちてくるうえ、iOS の「ファイル」App 経由でも拡張子が当てにならない。

RESULT

取り込み元が 2 つ増えても、列マッピング画面と重複判定は 1 実装のまま。

判別をバイト列に寄せた副産物として、名前が壊れたファイルでも正しく振り分けられ、旧形式の .xls だけは「読めない」と明示的に案内できるようになった。

v1.4.0 アプリ名を MyDictly に改め、識別子は据え置く
DECISION

表示名を LangBridge から MyDictly へ変更し、アイコンも刷新した。

変えたのは表示名だけ(ホーム画面・ストア表示・Web manifest・Google Sheets への書き出し名)で、バンドル ID jp.langbridge・配布 URL・GitHub リポジトリ名は据え置いている。

v1.4.0 で反映した。

WHY / 仮説

LangBridge という名前を持つアプリ・サービスが他に複数あり、ストアでも検索でも自分のアプリを指し示せなくなっていたのが発端。

候補は「自分の辞書」という意味を軸に選んだが、辞書=Jisho を織り込んだ案は日本語を知らない人に一切伝わらないため落とした。

最終的に dictionary の一般的な短縮である "dict" と、Bitly / Calendly と同じ -ly を組み合わせ、日本語話者以外でも意味が取れる形にした。

一方で識別子まで変えると APK 直配布のアップデート経路と Firebase 連携が切れ、既存ユーザーが更新を受け取れなくなる。

だから「見える名前」と「動かす名前」を分け、変更は前者に限定した。

RESULT

名前の重複は解消し、既存ユーザーはアップデート経路を保ったまま改名版を受け取れる。

配布ファイル名は MyDictly.apk へ切り替えたが、バンドル ID とリポジトリ名(lang-bridge)は旧名のまま残り、対外的な名前が二重に存在する状態は当面許容している。

design 自前辞書を持たず、外部辞書リンク+外部 API に委ねる
DECISION
巨大な辞書データベースを自分で抱えず、Google/Weblio/北辞郎などの外部辞書へのリンクと外部 API に検索を委ねた。
WHY / 仮説
辞書 DB の構築・保守は個人開発では負担が大きい。既存の辞書資産にリンクで乗り、アプリは「自作単語帳の管理と学習」という独自価値に集中すべきだと考えた。
RESULT

軽量なまま、任意の言語ペアで実用的な検索・学習を提供。アプリの主戦場を明確にした。


※ この判断は v1.4.0 で一部撤回した。外部 API の URL が未設定だと辞書欄が丸ごと無反応になり、オフラインでは何も引けないという穴が実際に効いたため。

ただし撤回したのは「辞書を持たない」の部分だけで、辞書は単語帳とは別枠の参照専用として持つことにした(上の v1.4.0 のエントリを参照)。

AI AI 機能に利用制限を設け、月間利用数を可視化する
DECISION
AI アシスト・AI 深掘りに利用上限を設け、月間利用数をヘッダーに表示。バックエンドの生成 AI 利用も制限を強化した。
WHY / 仮説
生成 AI は 1 リクエストのコストが高く、無制限だと濫用や費用で持続不能になる。上限と可視化で、無料提供と持続可能性を両立させる必要があった。
RESULT
ユーザーが残り利用数を把握でき、運用コストを抑えながら AI 機能を提供し続けられる形に。
v1.3.6 アプリ内アップデート機構を共通基盤へ刷新する
DECISION
APK 直配布のアップデート機構を共通基盤(nzw_app_updater)へ移行し、更新に失敗した場合はサーバーから案内・手動ダウンロードリンクを出せるようにした。
WHY / 仮説
複数アプリで更新機構を個別実装すると保守が破綻する。共通化し、かつ更新失敗時もサーバー側から救済できる導線を持つべきだと考えた。
RESULT
更新の安定性が向上し、meta を編集・デプロイするだけで全ユーザーの更新ダイアログに案内を出せる運用に。
Milestones

これまでの歩み

v1.4.02026-08-20

MyDictly へ改名/PDIC 辞書の取り込み(参照専用)/Excel・CSV 取り込み/iOS を App Store へ提出

v1.3.72026-07-12

リリース署名鍵へ切替(Play プロテクト警告を軽減/要再インストール)

v1.3.62026-07-04

アップデート機構を共通基盤へ刷新/更新失敗時のサーバー案内

v1.3.42026-06-08

フラッシュカードの音声読み上げ(18 言語)/Web 版の自動同期

v1.3.32026-05-22

Firebase 連携でデバイス間同期/スプレッドシート自動同期

v1.1.02026-04-29

AI 辞書アシスト・検索履歴を追加

v1.0.02026-04-26

初回リリース(辞書検索・Google Sheets 同期・フラッシュカード・単語管理)

全バージョンの変更履歴を見る →

Roadmap / Open Questions

これから

未決事項:AI 利用制限の最適値、独自クラウド同期と Google Sheets 同期の役割分担。