豪鬼メモ

一瞬千撃

EPUBリーダ用のEPUB英和辞書を作ろう

EPUB対応の電子書籍リーダーで共通して使えるEPUBの電子辞書データを作ろうと思いたち、例のWiktionaryWordNetの統合辞書データを変換して実際に作ってみた。また、一連の英和辞書関連のプロジェクトページも作った。
f:id:fridaynight:20201020165111p:plain


EPUBベースの辞書データの仕様は2015年にEPUB Dictionaries and Glossaries 1.0として制定されているので、それに基づいて作ってみた。実際のデータはこのEPUBファイルをダウンロードすれば見られる。EPUB文書としてはMacのBookでもAndroidGoogle Play Booksでも閲覧できる。epubcheckのDICTプロファイルのチェックを通っているので、データの仕様準拠は問題ないだろう。

しかし、ここで残念なお知らせである。EPUB辞書に対応した検索機能を備えるEPUBリーダを私は知らない。現状では各ベンダーが独自仕様の辞書を内臓する形が一般的なようだ。EPUBの辞書データをアドインしてポップアップ辞書などの形で利用できるものは見つけられなかった。ただ、通常のEPUB文書として閲覧して文書内検索をすれば一応英和辞書としても使える。


作り方についてメモしておこう。まず、EPUBファイルとは、規程に基づいたディレクトリ構造にXML文書群を収めたデータ群のZIPアーカイブである。ベースディレクトリを base とした場合のディレクトリ構造は以下である。

  • base/mimetype
  • base/META-INF/container.xml
  • base/OEBPS/package.opf
  • base/OEBPS/skmap.xml
  • base/OEBPS/style.css
  • base/OEBPS/nav.xhtml
  • base/OEBPS/main.xhtml

mimetypeファイルは、application/epub+zip というMIMEタイプの文字列だけを含むテキストファイルであり、EPUBファイルの識別に使われる。アーカイブ内に収める際に最初に来る必要があり、またファイルシステムメタデータをつけたり圧縮したりしてはいけないらしい。MIMEタイプの文字列の後に改行を入れてもいけない。

META-INF/container.xmlファイルは名前固定で、以下の内容を持つ。つまり、OEBPS/package.opfを読めということだけを伝えるのが目的っぽい。

<?xml version="1.0"?>
<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
<rootfiles>
<rootfile full-path="OEBPS/package.opf" media-type="application/oebps-package+xml"/>
</rootfiles>
</container>

OEBPSはOpen eBook Publication Structureの略らしい。別の名前にしても規約上は大丈夫なのだが、いちおう慣習に従っておこう。その中にOPFファイルやその他のデータファイルを置く。OPFとはOpen Package Formatの略らしい。OEBPS/package.opf は以下のような内容を持つ。

<?xml version="1.0" encoding="utf-8"?>
<package unique-identifier="pub-id" version="3.0" xmlns="http://www.idpf.org/2007/opf" xml:lang="ja">
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/">
<dc:identifier id="pub-id">urn:uuid:961b61ca-1291-11eb-9cdc-2beeacfc5b1b</dc:identifier>
<dc:publisher>dbmx.net</dc:publisher>
<dc:title>統合英和辞書</dc:title>
<dc:language>ja</dc:language>
<dc:language>en</dc:language>
<dc:type id="tp">dictionary</dc:type>
<meta property="dcterms:modified">2020-10-20T05:03:26Z</meta>
<meta property="dcterms:type" refines="#tp">bilingual</meta>
<meta property="source-language">en</meta>
<meta property="target-language">ja</meta>
</metadata>
<manifest>
<item id="skmap" properties="search-key-map dictionary" href="skmap.xml" media-type="application/vnd.epub.search-key-map+xml"/>
<item id="style" href="style.css" media-type="text/css"/>
<item id="nav" href="nav.xhtml" media-type="application/xhtml+xml" properties="nav"/>
<item id="main" href="main.xhtml" media-type="application/xhtml+xml"/>
</manifest>
<spine page-progression-direction="default">
<itemref idref="nav"/>
<itemref idref="main"/>
</spine>
</package>

dc:identifier要素はリビジョン管理に用いられ、アーカイブファイルがビット単位で同一でない場合には異なるUUIDを割り当てる必要がある。その他のメタデータはまあ見ればわかるだろう。辞書データとして特徴的なのは、dc:language要素で言語を指定することだ。英和辞書なので、第一言語としてja(語義は日本語)、第二言語としてen(見出し語は英語)を指定している。同様に、meta要素でもソース言語としてja、ターゲット言語としてenを指定している。また、dc:type要素で辞書データであることを明示している。meta要素の更新日時はISO 8601のT区切りZ終わり方式で書く。あと、二言語辞書の場合にはmetaう要素のdcterms:typeプロパティでbilingualを指定すべきらしい。

manifest要素の中にはパッケージに含まれるファイルを列挙する。ここで、後述する検索キーマップファイルやスタイルシートやコンテンツ本体のXHTMLファイルを指定する。また、コンテンツ本体のXHTMLデータに関しては、そのIDをspine要素で列挙する。spine=背骨というだけあって、ここで書いた順序で表示や読み上げが行われるらしい。

OEBPS/skmap.xml は辞書データならではのファイルであり、通常のEPUB文書には含まれない。これは検索キーに応じてコンテンツ本体のどこを表示するかを指定するファイルだ。以下のようなデータが書かれる。ここではappleとgoodの分のエントリを記述している。名詞の複数形などの屈折形を列挙することで、ポップアップ辞書などで屈折形からも検索ができるようにしている。

<?xml version="1.0" encoding="UTF-8"?>
<search-key-map xmlns="http://www.idpf.org/2007/ops" xml:lang="en">
<search-key-group href="main.xhtml#apple">
<match value="apple">
<value value="apples"/>
</match>
</search-key-group>
<search-key-group href="main.xhtml#good">
<match value="good">
<value value="better"/>
<value value="best"/>
</match>
</search-key-group>
</search-key-map

OEBPS/style.cssCSSスタイルシートだ。EPUBベースの全てのリーダはXHTMLレンダリングエンジンを積んでいて、また多くはCSSに対応しているので、Webページを書くつもりでデザインをすればよい。

OEBPS/nav.xhtmlはコンテンツ本体の内で、目次のページを表現する。おそらくなくても構わないのだが、慣習的にはつけるものらしい。以下のような普通のXHTMLデータを書けばよい。nav要素の中にol-li構造で参照先を列挙すると、それに応じてファンシーな目次を生成してくれるリーダもあるらしいので、いちおうそれに従う。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">
<head>
<title>統合英和辞書: 目次</title>
<link rel="stylesheet" href="style.css"/>
</head>
<body>
<h1>統合英和辞書</h1>
<article>
<h2>目次</h2>
<nav epub:type="toc">
<ol>
<li><a href="main.xhtml">見出し語</a></li>
</ol>
</article>
</body>
</html>

ナビゲーション以外に、使い方の説明用のページやライセンスのXHTMLページを別途儲けてもよい。その場合には、それらもパッケージファイルに登録して、またナビゲーションからも飛べるようにリンクを列挙するlことになる。

OEBPS/main.xhtmlはコンテンツ本体の内で、見出し語とその語義を集めたものである。ファイルが大きくなる傾向にあるので、見出し語の最初の文字でファイルを分けるなどの工夫をしてもよい。XHTMLベースではあるが、辞書ならではの構造もある。

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" lang="ja">
<head>
<title>統合英和辞書</title>
<link rel="stylesheet" href="style.css"/>
</head>
<body epub:type="dictionary">
<article id="apple">
<aside epub:type="condensed-entry" hidden="hidden">
<dfn>apple</dfn>
<span epub:type="phonetic-transcription" lang="en-fonipa" class="pron">ˈæp.əl</span>
<ul>
<li>リンゴ, りんご, 林檎, りんごの木, 苹果</li>
</ul>
</aside>
<dfn>apple</dfn>
<span epub:type="phonetic-transcription" lang="en-fonipa" class="pron">ˈæp.əl</span>
<ul>
<li>リンゴ, りんご, 林檎, りんごの木, 苹果</li>
<li>fruit with red or yellow or green skin and sweet to tart crisp whitish flesh</li>
<li>native Eurasian tree widely cultivated in many varieties for its firm rounded edible fruits</li>
</ul>
</article>
<article id="">
<aside epub:type="condensed-entry" hidden="hidden">
<dfn>abby</dfn>
<span epub:type="phonetic-transcription" lang="en-fonipa" class="pron">ˈæb.i</span>
<ul>
<li>修道院, 大修道院, 僧院, 修道士, 修道女</li>
</ul>
</aside>
<dfn>abby</dfn>
<span epub:type="phonetic-transcription" lang="en-fonipa" class="pron">ˈæb.i</span>
<ul>
<li>修道院, 大修道院, 僧院, 修道士, 修道女</li>
<li>a monastery ruled by an abbot</li>
<li>a church associated with a monastery or convent</li>
</ul>
</article>
</body>
</html>

各見出し語とその説明は、各article要素に包含される。その中にaside要素に包含されたポップアップ辞書用の内容と、その外側に詳細表示用の内容が書かれる。見出し語はdfn要素で表現する。それ以外は特に規定はなくどう表示されるか考えて適当にHTMLを書けば良い。発音記号は epub:type="phonetic-transcription" 等の属性を持つspan要素に入れることが推奨されていて、おそらくそれは読み上げをしてくれるリーダが実装しやすいようにだろう。

これらのファイルを書き出したら、あとは以下のようなコマンドでzipアーカイブを作れば良い。ベースディレクトリの中からの相対パスアーカイブを作ることと、mimetypeを最初に非圧縮メタデータなしで登録するところがポイントである。

$ pushd base
$ zip -X0 ../dict.epub mimetype
$ zip -r ../dict.epub META-INF OEBPS
$ popd

作ったデータは、epubcheckというツールにかけると妥当性が検証できる。

$ epubcheck dict.epub


EPUB辞書の作り方がわかったところで、Wiktionary-WordNet統合辞書の実際の内容をどうやって変換するかを考えたい。基本的には、見出し語とその屈折形の情報から検索キーマップを出力し、また見出し語とその語義のリストを辞書本体のXHTMLとして出力すればよい。

EPUBリーダからポップアップ辞書として呼び出すのが主目的であるから、それに合わせて辞書本体の内容を最適化したくなる。ポップアップ辞書とはすなわち、読書中に本文に現れた単語またはフレーズを選択すると、その言葉の意味を辞書で調べてポップアップ内に表示してくれる機能だ。ポップアップは通常画面の30%程度かそれ以下の面積を占めるサブウィンドウとして表現される。その狭い範囲に表示できるのはせいぜい40文字*5行といったところか。そこにいかに有用な情報を詰め込むかが勝負だ。順当に考えれば、ポップアップの内容は以下のような仕様になる。

  • 1行目に見出し語を太字で表示する。
  • 発音情報を見出し語の後ろに置く。慣習に従い、IPA発音記号を「/」で囲んで表示する。
  • 2行目に翻訳語のリストを置く。翻訳語は、重要なものから並べ、最大8個を表示する。
  • 3行目以降に語義のリストを最大5個程度置く。

ポップアップの内容はXHTML文書のaside要素として記載される。ポップアップ辞書は英文読解に使うものなので、例文や文法の詳細は載せない。例文は既に読んでいる状態であり、その文法も適格であると期待できるからだ。主に分からないのは意味と発音であるから、それらが最初に表示されるべきだ。意味に関しては訳語のリストを見るだけでほとんどの場合は理解できるので、語義のリストは余った空間におまけ程度に書くだけだ。

ポップアップから「辞書を見る」的なリンクを選択すると、その語の語義情報の全てを表示する。その内容はaside要素の外に記載される。ポップアップと同様に1行目に見出し語と発音、2行目に翻訳語のリストを置く。その下に、屈折形のリストを置く。そして、語義のリストの全てを載せる。ここでも例文は省略する。

辞書ファイルの要領を節約する工夫もしたい。Wiktionary英語版とWordNet英語版の役割は被っているので、WordNet英語版の情報がある場合、その語のWiktionary英語版の情報は捨てる。また、Wiktionary日本語版の語義がなく、かつWiktionary英語版とWordNet英語版のどちらかの語義しかなく、かつその語の出現率が0.00002を下回る場合には、その語は捨てる。こうすることで、Wiktionary英語版やWordNet英語版に収録されているマイナーは固有名詞を捨てることができる。結果として、収録語彙を9万後に絞ることができ、ZIP圧縮語のファイルサイズは25MB程度になる。


まとめ。EPUB形式の電子書籍を作る作業にちょっと手を加えれば、EPUBリーダ用の辞書データをEPUB形式で作ることができる。対応しているデータがあれば、ポップアップ辞書として機能するはずなので、かなり使い勝手が良いはずだ。例によって訳語のリストを先頭に集めることで、プログレッシブ英和時点とかよりも素早く理解できるようになっている。ただ、対応しているリーダがまだない。いや、私が知らないだけかも。どなたかご存知なら教えてくだされ。

EPUBのデータができればKindle用のmobi形式にも変換してkindleでも使えるはずだが、おそらく既存のツールは検索キーマップ等に対応していないので、kindle用の辞書生成スクリプトは別途自分で書かねばならないだろう。