OSXのユーザ辞書の作り方

投稿者 nanki 2007-11-26 04:20:00 GMT

Leopardからは、小学館の辞書データとWikipediaが追加されて、とっても便利なDictionary.app.

たぶん、キーボード使用を前提とした小気味よいインターフェースがいいんだと思う。 慣れてしまうと、もう生のWikipediaを使う気はなかなか起きない。

こうなると、なんでもかんでも、同じインターフェースで済ませたくなるもので、そんな時に、こんな検索しにくいページを見たら、「Dictionary.appで検索できて然るべき」と思ってしまうのが自然な流れ。

というわけで、ライフゲームの辞書、Life LexiconをDictionary.app用に変換します。

まずは、テンプレートをコピーしてくる。 試しにmakeすると、あっさり辞書が作られる。 make installすれば、~/Library/Dictionaries 以下にコピーされ、Dictionary.appから検索できる状態になる。(Dictionary.appの環境設定で有効にしないとだめかも)

$ cp -r /Developer/Examples/Dictionary Development Kit/project_templates dict
$ cd dict
$ make
"""/Developer/Extras/Dictionary Development Kit"/bin"/build_dict.sh"  "My Dictionary" MyDictionary.xml MyDictionary.css MyInfo.plist
- Building My Dictionary.dictionary.
- Cleaning objects directory.
- Preparing dictionary template.
- Preprocessing dictionary sources.
- Extracting index data.
- Preparing dictionary bundle.
- Adding body data.
- Preparing index data.
- Building key_text index.
- Building reference index.
- Fixing dictionary property.
- Copying CSS.
- Copying other resources.
- Finished building ./objects/My Dictionary.dictionary.
echo "Done."
Done.

重要なのは、MyDictionary.xmlファイル。 辞書の元となるデータをパースして、XMLファイルを作ってやる。

<?xml version="1.0" encoding="UTF-8"?>                                                                               
<d:dictionary xmlns="http://www.w3.org/1999/xhtml" xmlns:d="http://www.apple.com/DTDs/DictionaryService-1.0.rng">    
  <d:entry id="blinker puffer" d:title="blinker puffer">                                                             
    <d:index d:value="blinker puffer" d:title="blinker puffer" />                                                    
    <d:index d:value="puffer" d:title="blinker puffer" />                                                            
    <h1><span class="headword">blinker puffer</span></h1>                                                            
    <span class="meaning">Any <a href="x-dictionary:r:puffer">puffer</a> whose output is <a href="x-dictionary:r:blinker">blinker</a>s.  However, the term is particularly used for p8 c/2 puffers.  ....
    </span>
  </d:entry>
  <!-- 以下d:entry の山 -->
</d:dictionary>

意味はほとんど見た目通り。
それぞれの項目は、インデックスと内容のXHTMLで構成される。 他の単語を参照する、href=”x-dictionary:r:ID”とかが特徴的か。 上の例では「blinker puffer」という単語に対して、pufferでも検索に引っかかって欲しいので、indexに加えてある。

パースしてXMLを吐くコードは、汎用性がないのでここには載せないが、今回は以下のようなLifeを表す図を、rcairoでpng画像に変換もしている。

OO..
O..O
..OO

画像などのリソースは、dict/OtherResources 以下の適当な場所に置いておき、普通のHTMLのように、<img>タグを使って埋め込む。

<p><img src="Images/blinker%20puffer_0.png"/></p>

これで、

$ make
$ make install

すれば、ユーザ辞書の完成。

続き

さて、これだけで終わりではもったいないので、先日作ったQuartz Compositionを組み込めないか、頑張ってみる。

HTMLにQuartz Compositionを組み込むのは簡単で、EMBEDタグを使って、

<embed id="composition" type="application/x-quartzcomposer" src="LifeLexicon.qtz" width="300px" height="300px" />

とする。

これで、普通のムービーならスタートするのだけど、ライフゲームなので第0世代の画像を渡してやらないといけない。

Quartz ComposerのWebKitプラグインにはJavaScript APIが用意されていて、publishしたパラメータを設定できるようになっている。 が、文字列しか設定できないようだ。画像はどうやって渡すのだろう。

調べてみると、Compositionの中で、Image Downloaderというパッチを使うらしい。 Image Downloaderは指定されたURLの画像をImageとして出力するパッチ。 なるほど。 ImageDownloaderの入力を、imageLocationという名前でPublishして・・・

var composition = document.getElementById("composition");
composition.setInputValue("imageLocation", "fullpath.png");

こんな感じになるのかな。 しかし、フルパス指定じゃないといけないのが面倒だなぁ・・・

先生、こちらにできあがったものが用意してあります。

結局、location.href と、EMBEDに勝手に付け加えたimage属性から、フルパスを取得する仕組みに。 文中のSpaceはCompositionというか、Universeというか。

//LifeLexicon.js
(function () {
  var waitForSpaces = function (spaces) {
    if (spaces.length == 0) return;

    if (spaces[0].loaded && spaces[0].loaded()) {
      var space = spaces.shift();
      var base = location.href.substr(0, location.href.lastIndexOf("/"))
      space.setInputValue("imageLocation", base + space.getAttribute('image'));
    } 
      
    with ({callee: arguments.callee}) {
      setTimeout(function () {callee(spaces)}, 100);
    }
  };

  var arrayFromNodeList = function (nodelist) {
    var result = [];
    for (var i = 0; i < nodelist.length; i++) {
      result.push(nodelist.item(i));
    }
    return result;
  };

  waitForSpaces(arrayFromNodeList(document.getElementsByTagName('EMBED'))); 
})();

なぜか、<script src="LifeLexicon.js">だと読み込まれないので、

<script>
  var tag = document.createElement("SCRIPT");
  tag.src = "./LifeLexicon.js";
  document.getElementsByTagName("HEAD")[0].appendChild(tag);
</script>

というコードも、<d:entry>内に埋め込むように。

これで「生きた」LifeLexiconが完成。

LifeLexicon

CREDITをどこかに入れないと配布できないらしいので、欲しい人には直接送ります。 いないだろうけど。

誰か、Ruby Reference Manualをこれで。

参考:

This entry was posted on 2007-11-26 04:20:00 GMT and カテゴリ , , , , , . You can follow any response to this entry through the Atom feed. or a trackback from your own site.

タグ ,


トラックバック

トラックバックリンク:
http://blog.netswitch.jp/trackbacks?article_id=8598