「git」は「ギット」?「ジット」?みんなの読み方を投票できる「YOMIKATA」を作った
git は「ギット」なのか「ジット」なのか。
height は「ハイト」なのか「ヘイト」なのか。
エンジニア同士で話していると、技術用語の読み方が人によって違うことがあります。公式の発音を調べることはできても、日本では実際にどう読まれているのかは、なかなか分かりません。
そこで、単語の読み方を検索・登録・投票できるWebサービス「YOMIKATA」を作りました。
YOMIKATAとは
YOMIKATAは、読み方が分かれやすい単語について、みんなが普段どう読んでいるかを集めるサイトです。
辞書のように「正しい読み方」を一つに決めることが目的ではありません。複数の読み方と票数を並べ、読み方の分布そのものを見ることを目的にしています。
たとえば、執筆時点では次のような結果になっています。
| 単語 | 読み方 | 票数 |
|---|---|---|
| git | ギット | 38 |
| git | ジット | 15 |
| git | ジーアイティー | 5 |
| height | ハイト | 20 |
| height | ヘイト | 10 |
| orz | オルツ | 24 |
| orz | オーアールゼット | 10 |
票数は2026年8月31日時点のものです。投票によって変化します。
gif、nginx、vim、emacs、kubernetes、tmux、sudo なども登録されています。技術用語だけでなく、日本語やネットスラングも追加できます。
できること
単語を検索する
検索フォームに単語を入力すると、登録されている単語を探せます。
各単語には /git や /height のような個別URLがあり、登録されている読み方と票数を一覧できます。
読み方に投票する
すでに登録されている読み方には「投票する」ボタンから投票できます。
1つの単語につき1人1票です。別の読み方へ投票し直した場合は票が追加され続けるのではなく、以前の読み方から新しい読み方へ移動します。
新しい読み方を登録する
候補に自分の読み方がなければ、その場で追加できます。単語自体が未登録の場合も、単語と読み方をまとめて登録できます。
トップページには投票数の多い単語ランキングと、新しく登録された読み方も表示しています。
技術構成
主な構成は次のとおりです。
| 用途 | 採用技術 |
|---|---|
| 実行環境 | Cloudflare Workers |
| Webフレームワーク | Hono |
| UI | Hono JSX / TypeScript・TSX |
| データベース | Cloudflare D1 |
| ボット対策 | Cloudflare Turnstile |
| ブラウザ側の投票状態 | Local Storage |
| 配信 | SSR + Cloudflareのエッジキャッシュ |
小規模な個人開発なので、Webサーバーを別途管理せず、アプリケーションとデータベースをCloudflare上にまとめました。
SSRを基本にしつつ、画面遷移は軽くする
トップページや単語ページは、Workers側でHTMLを生成して返しています。最初から本文を含むHTMLになるため、JavaScriptの実行を待たずに内容を表示でき、検索エンジンにも単語ごとのページを認識してもらいやすくなります。
一方、ブラウザ上で単語ページへ移動するときは、ページ全体を毎回読み直さないようにしています。
大まかな流れは次のとおりです。
-
/gitのHTMLを取得する - HTML内の
data-*属性から単語と読み方の状態を取り出す - Hono JSX DOMでメイン領域を更新する
- History APIでURLを
/gitに変更する
単語詳細専用のJSON APIを増やさず、SSR用のHTMLをブラウザ側でも再利用しています。HTMLはエッジキャッシュに載せられるため、サーバーとクライアントで別々の取得経路を管理しなくてよい点も利点でした。
APIは必要なものだけに絞っています。
GET / トップページ
GET /:word 単語ページ
GET /api/search?q=... 単語検索
POST / 読み方の登録・投票
表記揺れで票を分散させない
このサービスで特に重要だったのが、入力値の正規化です。
何も対策しないと、次のような入力が別々のデータとして保存されてしまいます。
Git / git / GIT
やま / ヤマ / ヤマ
そこで、単語と読み方を保存する前に次の処理を行っています。
共通: NFKC正規化 → 制御文字の除去 → 連続する空白の整理 → trim
単語: 共通処理 → 小文字化
読み方: 共通処理 → ひらがなをカタカナへ変換 → 小文字化
この結果、Git、git、GIT は同じ単語として扱われます。読み方も、やま、ヤマ、ヤマ が同じ候補に集約されます。
クライアント側でも登録内容のプレビュー用に同じ正規化を行いますが、ブラウザから送られてくる値は信用せず、サーバー側でも必ず正規化するようにしています。
表記の違いを区別できなくなるというトレードオフはありますが、読み方の票が表記揺れだけで分散する問題を避けることを優先しました。
ログインなしで「1単語につき1票」を実現する
投票のためだけにアカウント登録を求めると、利用のハードルが上がります。そのため、YOMIKATAにはログイン機能を設けていません。
代わりに、初回アクセス時にブラウザでUUIDを生成し、Local Storageへ保存します。データベース側では単語と投票者IDの組み合わせを一意にし、同じ単語へ再投票された場合は、選択中の読み方を上書きします。
UNIQUE(word, voter_id)
この設計により、同じブラウザでは1つの単語に複数票を持てません。
ただし、ブラウザや端末を変えれば別の投票者として扱われます。ログインなしで厳密な「1人1票」を保証することはできないため、次の対策も組み合わせています。
- 登録・投票時にCloudflare Turnstileでボットを抑制する
- 同じIPアドレスから同一単語への投票数に上限を設ける
- ブラウザ内には投票済みの読み方を保存し、現在の選択を表示する
厳密さよりも、すぐに投票できる手軽さとのバランスを取りました。
Turnstileのトークンは送信ごとに取り直す
Turnstileのトークンは単回使用で、有効期限もあります。そのため、ウィジェットを一度表示して終わりにはせず、登録または投票が完了するたびにリセットしています。
処理の流れは次のとおりです。
送信開始
↓
Turnstileトークンを取得
↓
単語・読み方・投票者IDと一緒にPOST
↓
成功・失敗にかかわらずウィジェットをリセット
↓
次回送信用のトークンを取得
Turnstile本体のJavaScriptは非同期で読み込まれるため、APIの準備完了を待つ処理と、トークン取得が終わらない場合のタイムアウトも入れています。
動的HTMLをエッジでキャッシュする
単語ページは動的に生成していますが、アクセスのたびにデータベースを読みに行く必要はありません。
現在はGETで返すHTMLに次の方針のキャッシュヘッダーを付け、Cloudflareのエッジでキャッシュしています。
Cache-Control: public, s-maxage=3600, max-age=0, must-revalidate
- Cloudflare側では最大1時間キャッシュする
- ブラウザには長時間保持させない
- 再検証が必要な状態を明示する
票数の完全なリアルタイム性と、表示速度・データベースアクセス数のどちらを優先するかは悩みどころでした。YOMIKATAでは、投票直後の本人の画面はPOSTのレスポンスで更新し、一般のGETアクセスにはエッジキャッシュを利用する構成にしています。
単語ごとにURLを作る
単語ページをクエリパラメータではなく /git のようなURLにしたのは、共有しやすさと検索性を考えたためです。
各ページでは、単語に合わせてタイトルも変えています。
<title>git の読み方 - YOMIKATA</title>
SSRした本文にも読み方と票数が含まれるので、JavaScriptに依存せず内容を取得できます。シンプルなサービスですが、単語が増えるほど検索から到達できるページも増える構成です。
作ってみて分かったこと
正規化ルールは最初に決めた方がよい
データが増えてから正規化ルールを変更すると、既存データの統合が必要になります。特に全角・半角、大文字・小文字、ひらがな・カタカナをどう扱うかは、テーブル設計より前に決めておくべきでした。
「正解を決めない」とサービスの目的が明確になる
発音の正解を示すサービスにすると、出典や例外処理が大量に必要になります。YOMIKATAでは、正しさではなく実際の読み方の分布を集めることに絞りました。
ログインなしの投票には限界がある
UUID、IP制限、Turnstileを組み合わせても、厳密な本人確認にはなりません。一方で、気になった単語へすぐ投票できることは、このサービスでは大きなメリットです。目的に応じて、どこまで不正対策を行うかを決める必要があります。
まとめ
単語の読み方は、辞書上の正解だけでなく、世代やコミュニティによっても変わります。
YOMIKATAでは、その違いを正誤で裁くのではなく、票数として眺められるようにしました。
普段何気なく読んでいる技術用語があれば、ぜひ検索・投票してみてください。候補がなければ、新しい読み方も登録できます。