去年くらいから、 E-Inkディスプレイ搭載のAndroid端末 BOOX Leaf2 で、KindleやO’Reillyアプリの電子書籍を読んでいます*1。
BOOX Leaf2 – SKT株式会社
普通のAndroidタブレットで電子書籍を読むのに比べたら、 Leaf2 は目はあまり疲れない感じです。
また、KindleやO’Reillyアプリは起動時がややもっさりしますが、一度起動してしまえばそこまでのストレスはありません。
ところで、O’Reillyアプリでは洋書も読んでいるものの、「この単語は何だっけ...?」となることがよくあります。
Leaf2 に辞書機能はあるものの、その中には英和辞書がありません。
辞書を追加する方法がないか調べたところ、BOOXのヘルプページに以下の記載がありました。
To add a dictionary to your device, do the following:
- Search and download the dictionary files on your computer.
- Unzip the downloaded files and put them in a folder.
- Sideload the folder to the "dicts" folder in the root directory of your device.
- In Home Screen, go to Apps and open the Dictionary app.
- Tap the hamburger menu in the upper right corner.
- Choose Preferred Dictionary Setting and tick to add the dictionary.
https://help.boox.com/hc/en-us/articles/10701464167316-Translation-and-Dictionary
また、Leaf2の辞書アプリにも、辞書を追加できそうな記載がありました。
Tips
- StarDict、MDict、Deep Blue Dictionary、Babylonおよび他の辞書ファイル形式をサポートします
- デフォルトの保存場所: storage/dicts/、または外部ストレージ/dicts/
- 各辞書ファイルは、zipやサブフォルダを含まないフォルダに保存する必要があります
さらにWebを調べてみると、BOOXの別の端末に英和辞書を追加している記事がありました。
boox noteのPDFリーダに英和辞書を追加する - 工学おじさんのブログ
また、同じ著者で、Pythonを使って英辞郎のテキストデータをMDict形式にして、BOOXの端末に入れている記事もありました(以降、 参考記事
と表記します)。
英辞郎をMDict形式へ変換する - 工学おじさんのブログ
「参考記事に従えば英和辞書を追加できるかも」と感じたため、次に英辞郎のデータが販売されていないか調べたところ、BOOTHにありました。
英辞郎 Ver.144.9(2024年1月10日版)のテキストデータ - EDP - BOOTH
このBOOTHサイトへは英辞郎公式サイトからもリンクがあり、公式で提供しているデータのようでした。
英辞郎(えいじろう・EIJIRO)の最新情報
そこで、英辞郎のテキストデータからBOOX Leaf2向けの和英辞書を作ってみたので、メモを残します。
目次
- 環境
- 英辞郎のテキストデータを購入
- ツール類の調査
- 実装方針:両ライブラリをfork・修正する
- writemdict をforkして修正
- eiji_to_mdict をforkして修正
- 動作確認
- ソースコード
環境
英辞郎のテキストデータを購入
以下のBOOTHページより、テキストデータを購入しました。
英辞郎 Ver.144.9(2024年1月10日版)のテキストデータ - EDP - BOOTH
購入後、zipファイルをダウンロードしておきます。
ちなみに、BOOTHに書かれていたファイル情報は以下の通りです。
●この圧縮ファイル(EIJIRO-1449.ZIP)(サイズ=48,595,404 バイト)をダウンロードして、ZIPを用いて展開すると、以下のテキストファイルが復元されます。
ファイル名: EIJIRO-1449.TXTサイズ: 152,940,714バイト
論理行数: 2,575,101
改行コード: CR+LF
日本語文字コード: Shift JIS
ツール類の調査
テキストファイルをMDict化するライブラリ writemdict を確認
参考記事では、以下のライブラリを使って英辞郎のテキストデータをMDict化していました。
zhansliu/writemdict: A library for writing dictionary files in the MDict (.mdx) format
リポジトリを見たところ
- masterブランチのメンテナンスは8年前に止まっているっぽい
- Python 3 には対応済だが、3.13で削除される
cgi
モジュールを使っている - pyproject.tomlやsetup.pyがないため、pip installできなさそう
という状態でした。
また、参考記事では
Clone or download→Download ZIPでダウンロード&解凍をお願いします。
と書かれていました。手動で使うことを前提にしたライブラリのようです。
そのため、変換処理を自動化するPythonスクリプトに writemdict
を import して使うのは厳しそうでした。
MDictフォーマットに変換できるライブラリを調査
続いて、MDictをフォーマットに変換できるライブラリを調査してみました。
まずは mdict-utils
です。
liuyug/mdict-utils: MDict pack/unpack/list/info tool
starがそこそこあり、「MDict pack/unpack tool」と書かれていることから期待が持てました。
ただ、実際に使ってみると
- MDictへの変換については、
writemdict.py
を取り込んでいる - ただ、
writemdict.py
は拡張されており、単に差し替えただけでは動作しなかった - READMEのUsageを見ると、ライブラリというよりはツールの雰囲気
mdict
コマンドの実行例しか記載されていないため
と、使いこなすのには時間がかかりそうでした。
次は pyglossary
を見てみます。
ilius/pyglossary: A tool for converting dictionary files aka glossaries. Mainly to help use our offline glossaries in any Open Source dictionary we like on any modern operating system / device.
ただ、READMEによると、MDictファイルへの書き込みには対応していないようでした。
他にはPythonでMDictを扱えるようなライブラリは見当たりませんでした。
MDictフォーマットについて調査
そもそもMDictフォーマットとは何か分かってなかったので調べたところ、2016年時点の記事がありました。辞書のフォーマットは非公開のようです。
EBWin EBPocket のMDict対応検討 - hishidaの開発blog
次に、MDictの公式サイトを見に行きました。
https://www.mdict.cn/wp/?page_id=5325&lang=en
ただ、アプリはあるものの、ソースコードやファイルフォーマットが公開されていませんでした。
これらより、MDictのライブラリを自作するのも容易ではなさそうと感じました。
StarDictについて調査
ところで、Leaf2 がサポートしている辞書は、前述の通り
- StarDict
- MDict
- Deep Blue Dictionary
- Babylon
- その他
のようです。
このうち、 Deep Blue Dictionary
と Babylon
は調べてみても出てきませんでした。
一方、 StarDict
については、いくつかの記事でふれられていたので、少し調べてみることにしました。
まず、以下のサイトでは、英辞郎をStarDict形式に変換するスクリプトが公開されていました。
英辞郎をStarDict形式に直接変換するスクリプト「eiji2sd」 - 実録コンピュータ物語
ただ、言語が PowerShell か Perl のようで、そのまま使うのは難しそうでした。
次に、Pythonの penelope
パッケージを使うことで StarDict 形式にも対応できそうな記事がありました。
フリーの辞書をKindle用辞書に変換: ドイツ語の本読んでみ・・
そこで、 penelope
を見に行くと 2018年にアーカイブされていました。
pettarin/penelope: Penelope is a multi-tool for creating, editing and converting dictionaries, especially for eReader devices
READMEにはImportant Updateが記載されており、「メンテナンスされていないこと」や「PyGlossaryが使えるかもしれないこと」が記載されていました。
そのため、 penelope
を使うのは厳しそうでした。
最後に、StarDict形式については規格の行方が厳しそうな話もありました。
StarDict 計画 進捗(2) - hishidaの開発blog
そのため、StarDictでなんとかする方向はやめておきました。
英辞郎のテキストファイルをMDict化するライブラリ eiji_to_mdict.py を確認
ありがたいことに、参考記事ではMDict化するライブラリ eiji_to_mdict.py
のソースコードがGistで公開されていました。
英辞郎をMDict形式に変換します。
ただ、参考記事にもあるように、 writemdict
のディレクトリの中に入れて使う想定で作られています。
そのため、importした時に処理が走ってしまうことから、これも別のPythonスクリプトに import
して使うのは厳しそうでした。
実装方針:両ライブラリをfork・修正する
ここまでの調査で
- 参考記事にある両ライブラリを import して、そのまま使うのは厳しい
- 容易な代替案もない
ということが分かりました。
そのため、方針案としては
- 参考記事にあるように、Python 3系の古いバージョンをインストールし、手動で実行
- 両ライブラリをforkして修正を加え、ある程度自動で変換できるようにする
あたりを考えました。
ただ、辞書の更新を考えると、なるべく自動でMDict化したくなりました。
そこで、後者の案をもとにした
writemdict
をforkし、pip installできるように修正eiji_to_mdict
をforkし、英辞郎をMDict化するコマンドeiji_to_mdict
を用意
という方針で進めることにしました。
ちなみに、英辞郎のデータ仕様は公開されているため、多少修正を加えても仕様を満たしていれば問題なく動作しそうです。
英辞郎の紹介:データ仕様
以降では、修正作業を行っていきます。
writemdict をforkして修正
writemdict
に対しては
- 自分のGithubアカウントへforkする
- ブランチ
feature/python_package
にて、必要な修正を実施する
という流れで作業します。
なお、fork元がアクティブでないことから、自分のリポジトリでは、ブランチ feature/python_package
を master
へマージせずに置いておきます。
廃止される cgi.escape を html.escape へ差し替える
cgi.escape
の代わりになるモジュールを探したところ、PythonのWikiに以下の記載がありました。
The cgi module that comes with Python has an escape() function:
However, it doesn't escape characters beyond &, <, and >. If it is used as cgi.escape(string_to_escape, quote=True), it also escapes ".
Recent Python 3.2 have html module with html.escape() and html.unescape() functions. html.escape() differs from cgi.escape() by its defaults to quote=True:
両者ではエスケープするときの挙動がほんの少しだけ異なるようです。
ただ、PyCQA/banditのプルリクでもそのまま置き換えている感じだったので、今回の用途でもそのまま置き換えてしまっても良さそうでした。
Use html.escape() instead of cgi.escape() by ericwb · Pull Request #339 · PyCQA/bandit
pip installできるよう、writemdictディレクトリの作成とpyproject.tomlを用意
pip installを可能にするため、最低限の定義を pyproject.toml
に記載します。
また、Pythonのパッケージとして扱えるよう
writemdict
ディレクトリを作成- ルートディレクトリにあったPythonスクリプトをその中へ移動
__init__.py
の作成writemdict.py
のクラスや関数を使えるよう、from .writemdict import *
しておく
とします。
ただ、 writemdict
のリポジトリでは、ルートディレクトリに example_output
というディレクトリがありました。
このままだと
writemdict
example_output
の2つのディレクトリがルートディレクトリに並んでしまい、pip installする時に失敗してしまいます。
そこで、
you can explicitly list the packages in modules:
[tool.setuptools] packages = ["my_package"]
Configuring setuptools using pyproject.toml files - setuptools 69.0.3.post20240124 documentation
とあるように、 [tool.setuptools]
テーブルの packages
を利用して、 writemdict
がパッケージ向けであることを明示化します。
上記を踏まえた pyproject.toml
は以下となりました。
[project] name = "writemdict" version = "0.1" requires-python = ">=3.12" license = {file = "LICENSE"} [tool.setuptools] packages = ["writemdict"]
writemdict.pyでのimportを相対importにする
writemdict.py
の冒頭で ripemd128
と pureSalsa20
が
from ripemd128 import ripemd128 from pureSalsa20 import Salsa20
としてimportされているため、パッケージ化したときにこのままではうまく動きませんでした。
そこで、 .
をつけて相対importできるようにしました。
from .ripemd128 import ripemd128 from .pureSalsa20 import Salsa20
eiji_to_mdict をforkして修正
eiji_to_mdict.py
はGistにあるので、fork後、Githubのリポジトリを作成しました。
今回の修正方針は以下としました。
- やること
- やらないこと
以降では、やったことを簡単なメモに残しておきます。
実装の詳細は、リポジトリにあるソースコードを参照してください。
https://github.com/thinkAmi/eiji_to_mdict
pyproject.tomlの作成
ここでも pyproject.toml は必要最低限の定義とします。
依存ライブラリを dependencies に指定する
今回作成する eiji_to_mdict
を実行する場合、forkした writemdict
が必要になります。
そこで、 pyproject.toml の dependencies
に、forkした writemdict
をパッケージ化したブランチを指定しておきます。
Install dependencies from GitHub with pyproject.toml or requirements.txt — Chris Holdgraf
これにより pip install eiji_to_mdict
した際に、合わせて writemdict
もインストールされるようになります。
eiji_to_mdict コマンドを使えるよう、project.scripts テーブルを定義する
前回の記事に書いた通り、 [project.scripts]
テーブルを用意することで、コマンドを使えるようにします。
Pythonで、実行時のmオプションやpyproject.toml の project.scripts の指定による、実行可能なライブラリを作ってみた - メモ的な思考的な
pyproject.toml の全体像
[project] name = "eiji_to_mdict" version = "0.1" requires-python = ">=3.12" dependencies = [ "writemdict@git+https://github.com/thinkAmi/writemdict@feature/python_package", ] [project.scripts] eiji_to_mdict = "eiji_to_mdict:main"
元々のソースコードの修正
作業としては
- 変換ロジックまわりは
eiji_to_mdict.py
ファイルに移動する - その他の処理は
main.py
ファイルに書く
となります。
変換ロジックまわり
元々のソースコードでは、ファイルを1行ずつ読み込み変換していました。
そこで、関数 update_dicts
を用意して、その部分を移植しました。
なお、副作用には目をつぶり、引数の dict を更新するようにしています。
その他の処理の実装
コマンドの引数としてzipファイル名を受け取る方法について
元々は sys.argv
を使っていましたが、今回は argparser
を使いました。
最近だと click
が便利なようですが、今回は標準ライブラリだけにしたかったので、使いませんでした。
Welcome to Click — Click Documentation (8.2.x)
ファイルの存在チェックについて
いちおうバリデーションしておこうということで、 pathlib
を使ってファイルの存在チェックを行いました。
https://docs.python.org/ja/3/library/pathlib.html#pathlib.Path.exists
zipファイルの扱いについて
標準ライブラリの zipfile
ではzipアーカイブをいい感じに処理できます。
https://docs.python.org/ja/3/library/zipfile.html
今回はここらへんを使いました。
- zipアーカイブに含まれるファイル名を取得する
- zipファイルを開く
- zipファイルの中にあるファイルを開く
また、 ZipFile.open()
のコンテキストマネージャで取得したファイルライクオブジェクトは、 io.TextIOWrapper
でいい感じに扱えます。
そのため、zipファイルまわりはこんな感じになります。
with zipfile.ZipFile(path) as zf: originalFileName = zf.namelist()[0] with zf.open(originalFileName) as tf: for line in io.TextIOWrapper(tf, encoding='Shift-JIS', errors='ignore'): update_dicts(line, d, idiom)
動作確認
ここまでで実装が終わったので、WSL2上で動作確認します。
英辞郎のテキストデータをMDict形式に変換するところまで
eiji_to_mdict
コマンドにてMDictファイルが作成されているかを確認します。
$ python --version Python 3.12.1 $ python -m venv env $ source env/bin/activate (env) $ python -m pip install -e . # Windowsのダウンロードディレクトリにあったので、コピーする (env) $ cp /mnt/c/Users/<UserName>/Downloads/EIJIRO-1449.zip . # 実行 ## デバッグ用のコードが入っているので、それも出力される $ eiji_to_mdict EIJIRO-1449.zip <副> 内部で、内側は ... 処理を終了します # mdxファイル化できたことを確認 $ ls EIJIRO-1449.zip eijidiom.mdx eijiro.mdx ...
BOOX Leaf2 で辞書を設定して確認
今回作成した単語辞書(eijiro.mdx
)と熟語辞書(eijidiom.mdx
)を、Leaf2の辞書に設定し、O’Reillyアプリで使ってみます。
まずは、Windows側に両ファイルをコピーします。
$ cp eijiro.mdx /mnt/c/Users/<UserName>/Downloads/ $ cp eijidiom.mdx /mnt/c/Users/<UserName>/Downloads/
続いて、Leaf2に辞書ファイルを転送するため、Leaf2の BooxDrop
アプリを使います。
Transfer with Your Computer – BOOX Help Center
転送先として Internal Storage > dicts
を開きます。
次に
の2つのディレクトリを作成し、その中に各ファイルを転送します。
転送が終わったら辞書アプリを起動し、優先する辞書を設定します。
Translation and Dictionary – BOOX Help Center
- 右上のハンバーガーメニューをタップ
- 優先辞書設定をタップ
Eijiro
とEijideom
チェックを入れる- 辞書アプリを閉じる
最後に、O’Reillyアプリを起動して動作確認します。
単語を選択、 辞書
をタップすると翻訳が表示されました。
やや表示が崩れてそうな気もしますが、実用上は問題なさそうです。
ソースコード
Githubに上げました。
https://github.com/thinkAmi/eiji_to_mdict
今回のプルリクはこちら。
https://github.com/thinkAmi/eiji_to_mdict/pull/1
*1:現在では後継のBOOX Pageが販売中のようです: https://sktgroup.co.jp/boox-page/