豪鬼メモ

一瞬千撃

スター機能付きポップアップ辞書

真にフリーなポップアップ辞書を改良して、任意の見出し語に星印(スター)をつけられるようにした。これで多読と語彙力強化を高いレベルで両立できる。
f:id:fridaynight:20210427234757p:plain


英文を読んでいれば、それなりの頻度で未知語やうろ覚えの語に出会う。ポップアップ辞書は、本文中のそういった語を選択するだけで、辞書を調べて意味をポップアップで表示してくれる機能である。Chromeブラウザの拡張機能として実装しているので、インストールすれば、全てのWebページの英文で辞書機能を利用することができる。そして今回、表示された語に対して星印をつけられるようにした。
f:id:fridaynight:20210427234817p:plain

この豪鬼メモなんぞを読んでいる奇特な人々の多くは、おそらく短期記憶と長期記憶の話をご存知だろう。意味を調べた語の情報は短期記憶に格納されるが、何もしないとそれは数日以内に忘れられてしまう。短期記憶の情報を長期記憶に伝搬させるには、短期記憶に残っているパターンを繰り返して刺激することが必要である。印象的な物語や歌詞や格言などに出てくる言葉を覚えやすいのは、それを脳内で何度も思い出すからだ。つまり、復習が重要ということだ。せっかく辞書で調べて短期記憶に載せたのに、同じ言葉が一定期間に再出しなくて忘れてしまうというのでは勿体無い。そうならないように、定期的に復習の時間を持ち、強制的に短期記憶を刺激するのだ。

てわけで、ポップアップ辞書を引いた際に、その語を覚えておきたいなと思った時には、ポップアップの右肩にある星アイコンをクリックすると良い。調べた全ての語を覚える必要はなく、「この言葉って使えそうだな」「覚えておきたいけど忘れがちだな」と思ったものだけでいい。適切な難易度の英文を小一時間も読んだなら、おそらく10個くらいは星をつけているだろう。そうしたら、休憩に入る前に、一回目の復習をするのだ。アドレスバーの横にある「EJ」アイコンをクリックして、出てきたパネルにある星アイコン「☆」を選ぶ。
f:id:fridaynight:20210427234916p:plain

そうすると、星印をつけた語の一覧が出てくる。デフォルトでは意味が隠されているが、その語の上にカーソルをホバーさせると、意味が表示される。単語を見て意味が思い出せるかどうかを自分でテストしてみてもよい。それがまどろっこしい場合には、太陽アイコン「☼」をクリックして、全ての意味を表示してもよい。デフォルトでは登録日時が新しい順に並べられているが、上下矢印アイコン「⮃」をクリックすると、古い順に並べ替えることができる。いずれにせよ、一語ずつ確認して、完全に覚えているならその左の星アイコンをクリックして、星を外していく作業を行う。うろ覚えで、いずれもう一回復習したいと思ったならば、星はそのままにしてよい。星を全部一気に消したい場合は、流星アイコン「☄」をクリックすればよい。
f:id:fridaynight:20210427234936p:plain

この一連の復習作業を「棚卸し」と呼ぼうか。実際のところ、どのタイミングで棚卸しをするのかは、あなた次第だ。新聞やブログの記事を一つ読んだらでもいいし、小説を一章読み終えたらでもいいし、1日の学習の最後にまとめてやってもいい。確認だけしておいて、星は外さないでおいてもいい。星をどんどん貯めておいて、気が向いた時に、新しい順に100語だけ見返すという使い方でもよいだろう。星は最大1000個までつけられて、それ以降は古い順に捨てられていく。ポップアップ上で星を外してまた付け直すと新しく登録されるので、既に星がついた語を再度調べるはめになったなら、最新の位置に持ってきて確実に復習の対象にすることもできる。

効率化のための工夫をいくつかしている。本文中以外の語句を調べたいこともよくあるので、アドレスバーの右のアイコンから呼び出せるブラウザアクションパネルからも検索ができるようにしてある。そして、ブラウザアクションパネルはShift+Ctlr+L(MacだとShift+Command+L)というショートカットで呼び出せる。呼び出した直後に検索窓にフォーカスするようになっているので、ポインタに一切触らずにキーボードだけで検索を行うことができる。ブラウザアクションパネルを閉じるには先程のショートカットかEscキーを押せば良い。ブラウザアクションパネル内で再度検索を行いたい場合、Tabキーを押すと良い。そうすると検索窓にある直前の検索語を消した上で、フォーカスが当てられる。何度も検索する際にこれはやたら便利だ。和英検索もできるので、英語の文書とかメールとか書くときにかなり役立つ。そういった作業中についでに見つけた使える言葉にも星がつけられるのがまた良い。


インストールしたくなった人は、まずこのZIPファイルをダウンロードして、展開していただきたい。それからChromeブラウザで chrome://extensions を開いて、右隣のDeveloper Modeを有効にする。そうすると「Load unpacked」とか「パッケージされていない機能拡張をロードする」的なボタンが出るので、それを選ぶとファイル選択画面になるので、先ほど展開したアーカイブディレクトリを選択する。これでインストールは完了だ。
f:id:fridaynight:20210413024600p:plain

アドレスバーの右にあるパズルのピースのようなアイコンが機能拡張の管理メニューである。それをクリックすると、「English-Japanese Union Dictionary」というのが加わっているはずだ。それの横にある虫ピンマークを押すと、アドレスバーの横に辞書用のアイコンが出てくる。それを押す出るパネルにある「ポップアップ検索」がオンになっていれば、見ているページの中で適当な語を選択すると辞書を引いてくれるようになる。パネルの中にある検索窓に英語や日本語を入れて検索してもよい。「?」アイコンをクリックすると詳細な使い方が表示される。

5ドル払ってChrome Web Storeにアカウント登録もした。Chrome Web Storeで拡張機能を公開するには人間の審査を通過せねばならんので、もうちょい時間がかかりそう。上述のようにZIPアーカイブから直でインストールできるので問題はないのだが。


ここから先は実装の与太話だ。このスター機能付きの実装をバージョン2と呼び、以前解説したものをバージョン1と呼ぶ。バージョン1では、ポップアップ辞書の内容をXMLHttpRequest経由でJSONデータとして取得した上で、JavaScriptでDOMを操作して表示していた。バージョン2でもそれをやりたかったのだが、クロスドメインで星データを共有することが難しかったので、iframeを使って全面的に書き換えるはめになった。

辞書データは私の非力なVPSから配信しているので、不特定多数のユーザから利用されると負荷に耐えられるかどうか正直心配だ。とはいえ、DBMの軽量さにものを言わせているし、参照処理だけなので、たとえ1000人くらいに使われたとしても余裕だろう。それでも、ユーザのデータを預かりたくはない。データベースの更新処理を伴うと負荷の制御やバックアップのことも考えなければいけないので面倒だ。よって、星データはクライアント側だけに持たせる。HTML5関連技術としてローカルストレージAPIが使えるので、そこに保存すればよい。主要ブラウザでの容量の限界は5MBくらいらしいが、1000語に限れば200KBも行かないだろう。

ローカルストレージは同一ドメインで動作するスクリプト間でしか共有できない。しかし、ポップアップ辞書は不特定なドメインのサイトで動作するので、そのままだとローカルストレージが使えない。iframeとメッセージングを駆使すればクロスドメインでデータの共有ができるが、今回は不特定多数のドメイン同士のやりとりになるので、CSRFのリスクを考えると現実的ではない(はまちちゃんは元気にしてるかな)。よって、ポップアップの中身にはiframeだけを置いて、その中では辞書サイトから配信されたHTMLとJavaScriptの結果が描画されるということにした。そうすれば、辞書サイト本体だけで星データを管理する機能を実装すればよい。実際のところ辞書サイトを普通にブラウザで開けば全く同じ機能が利用できる。

ローカルストレージは文字列のkey/valueストレージとみなせる。星データのキーは決め打ちで "union_dict_stars" ということにして、値はリストのJSON文字列である。リストの各要素は見出し語の文字列とヒントの文字列のペアであり、古い順に並べられる。ヒントの文字列は、翻訳語がある見出し語にはそのCSVを、翻訳語がない場合は第一語義の英文を、先頭80文字までに限定して表現したものである。つまり、値は以下のようなJSONデータになる。

[
  ["apple", "リンゴ, りんご, 林檎"],
  ["banana", "バナナ"],
  ["NATO", "North Atlantic Treaty Organization"],
  ["Japan", "日本, ジャパン, 和の国, 大和"]
]

新しい語が登録される場合、まず既存のリストを最初からスキャンして、同じ語があればそれを消す。レコード数が制限を超えていたら最初の要素を消す。その上で、末尾に新しい語のレコードを追加する。てことは時間計算量O(N)なので、あまりリストがでかくなるとやばい。しかも、データが更新される度にDBからの読み込みと書き戻しを行うので、効率の点では最悪である。ただし、所詮はクライアント側で完結している話だし、容量は1000語で一定だし、ユーザアクションで実行されるだけの処理なので、神経質になる必要はない。

辞書サイト単体でスター機能を実装して一通りの動作確認もしておけば、あとはポップアップからそれを呼び出すだけである。とはいえ、ブラウザウィンドウの全ての領域を使って描画することが前提のUIデザインと、最大幅500pxのポップアップのUIデザインは多少なりとも変えねばならない。ポップアップとブラウザアクションパネルは両方とも幅500pxにすれば基本的なデザインを共有できそうだ。なので、CSSのメディアクエリで調整すればよさげだ。

@media (max-width:500px) {
  article { width: 98%; zoom: 85%; padding-bottom: 0.1ex; }
  .entry_view, .list_view, .annot_view, .message_view, .help {
    border: none;
    margin: 0.5ex 0ex; padding: 0.3ex 0.3ex 0.6ex 0.3ex; }
  ...
}

ただし、ブラウザアクションパネルとポップアップの間での差異は別の方法で対処せねばならない。ポップアップでは、検索フォームを出さないようにしたり、語義の表示件数を減らしたりせねばならない。それに関してはサーバ側にx=popupとかいう追加パラメータを送ることで対処した。次に問題となるのは、ポップアップの中での画面遷移に使われるURLの全てにx=popupの有無を伝播させねばならないことだ。正直面倒くさい。よって、HTMLの描画後に、以下のようなJavaScriptコードを走らせてa要素のURLを上書きするというハックで対処した。昔、某社のSEだった頃に、L7スイッチにこの類の書き換えを仕掛けてセキュリティ対応を謳っていたのを思い出した。

function modify_urls() {
  let base_url = new URL(document.location.href);
  if (base_url.search && base_url.search.match(/[&?]x=popup(&|$)/)) {
    let base_prefix = base_url.origin + base_url.pathname;
    let links = document.getElementsByTagName("a");
    for (let link of links) {
      if (!link.href) continue;
      let link_url = new URL(link.href);
      let link_prefix = link_url.origin + link_url.pathname;
      if (link_prefix != base_prefix) continue;
      let new_link_url = link_prefix + "?x=popup"
      if (link.search) {
        new_link_url += link.search.replace("?", "&");
      }
      link.href = new_link_url;
    }
  }
}

あと、クエリに対する該当がなかった場合のフォールバックの条件もポップアップ独自のものをしかけねばならなかったのだが、まあ書くほどのことでもないかな。

星データをクライアント側に持たせることでサーバ側の管理コストを減らしたのはいいが、弊害もある。一人のユーザが複数のデバイスを使った場合に、星データが共有されないことだ。とはいえ、それをやろうとすると、ユーザ認証が必要になって、実装だけでなく、ユーザにとっての障壁が10倍になってしまう。昔、「コナミのゲームを10倍たのしむカートリッジ」が欲しかったけど結局買えなかったのを思い出してしまう。グーグルアカウントとかに紐づけるのもオーバースペック感が半端ないし、どうしたもんか。


まとめ。WordNetWiktionaryを統合したフリーな英和辞書を使ったポップアップ辞書検索システムに、スター機能がついた。英文を読んでいて出会った気になる言葉にスターをつけて、あとで復習できるようにしよう。1時間英文を読み続けるよりも、50分を読むのに当てて10分を復習に回した方がおそらく学習効率が良い。とはいえそのためのノートを書くのな面倒くさい。そんなあなたには、このスター付きポップアップ辞書がうってつけである。