本記事は, Typst Advent Calendar 2025 の12日目の記事です.
はじめに
日本語の文書を作成する際, 漢字にルビ (ふりがな) を振りたい場面は多くあります. しかし, 手動でルビを振るのは手間がかかり, ミスも起こりやすいです. そこで, 形態素解析を活用して自動的にルビを振るパッケージを作ってみました. 本記事ではこのパッケージについて紹介します.
パッケージの概要と予備知識
本パッケージの使用方法について述べる前に, パッケージの大まかな処理と関連する予備知識について簡単に説明します. なお, 実装の詳細に関しては省略します.
処理の概要
大まかには以下のような処理を行っています.
- Typst関数を介してユーザが入力したテキストをWebAssembly (WASM) プラグインへ渡す
- (WASMプラグイン内で) Linderaを用いてテキストを形態素解析し, 読みを取得する
- (WASMプラグイン内で) 語の表層形と読みを照合し, 読みから送り仮名を分離する
- WASMプラグインから得られた構造化データをもとに,
rubbyパッケージを用いてルビを描画する
上記からもわかると思いますが, 本パッケージの主な構成要素はLinderaとWASMプラグインです.
形態素解析とは
形態素解析とは, 自然言語のテキストを形態素 (意味を持つ最小単位) に分割し, それぞれの品詞や読みなどの情報を付与する技術です.
例えば, 形態素解析ウェブアプリUniDic-MeCab1で「取り消し」を形態素解析すると
- 書字形: 取り消し
- 発音形: トリケシ
- 語彙素読み: トリケシ
- 語彙素: 取り消し
- 品詞: 名詞-普通名詞-一般
- 語形: トリケシ
- 書字形基本形: 取り消し
- 語種: 和
となります. 本パッケージでは, このように形態素解析により得られる情報のうち, 読み情報を使用して自動ルビ振りを実現しています.
Linderaとは
Linderaとは, Rustで実装された形態素解析器です. Linderaは辞書を組み込むことができ, WebAssemblyにも対応しているため本パッケージの形態素解析器として採用しました.
Typstのプラグインシステムについて
TypstはWASMベースのプラグインシステムをサポートしており, RustやC/C++などで記述された外部コードをドキュメントのコンパイル時に実行可能です. プラグインはTypstのサンドボックス環境内で動作し, ホスト (Typst) とゲスト (WASMモジュール) の間でバイト列を入出力としてデータをやりとりします2.
セキュリティと再現性の観点から, プラグインは原則として副作用を持たない純粋関数 (Pure Function) であることが求められます. また, ファイルシステムへのアクセスやネットワーク通信といったWASI (WebAssembly System Interface) の機能は制限されています.
純粋関数と副作用: Typstのプラグインは純粋関数であることが原則ですが, 初期化処理などで内部状態の変更が必要な場合はplugin transition APIを利用できます.
WASIの互換性: Typstはファイルシステム等へのアクセス (WASI) を直接サポートしていませんが, wasi-stub を用いてWASI呼び出しを無効化 (スタブ化) することで, WASIターゲットとしてコンパイルされた既存のライブラリやモジュールをTypst内で動作させることができます.
使い方
前置きが長くなりましたが, 本パッケージの使い方について説明します.
本パッケージは, IPAdicとUniDicを内包しているため一般的なパッケージと比較してデータサイズが大きいです. そのため, ダウンロードに少し時間がかかります.
自動ルビ振り
自動ルビ振りには show-ruby を使います.
#import "@preview/auto-jrubby:0.3.0": *
#set page(width: auto, height: auto, margin: 0.5cm)
#set text(font: "Hiragino Sans", lang: "ja")
#let sample = "東京スカイツリーの最寄り駅はとうきょうスカイツリー駅です"
#show-ruby(sample)
形態素解析結果の表示
show-analysis-table を使うと, 形態素解析結果を表として表示できます.
#import "@preview/auto-jrubby:0.3.0": *
#set page(width: 21cm, height: auto, margin: 0.5cm)
#set text(font: "Hiragino Sans", lang: "ja")
#let sample = "東京スカイツリーの最寄り駅はとうきょうスカイツリー駅です"
#show-analysis-table(sample)
ユーザ辞書
本パッケージはIPAdicとUniDicに対応3しており, デフォルトではIPAdicを使用しています. そのため, ルビ振りはIPAdicに依存し, 場合によっては正しいルビが振られないことがあります. この問題に対処するため, 本パッケージではユーザ辞書に対応しています.
正しいルビが振られない例
ここでは, 小倉百人一首に収録されている歌「田子の浦にうち出でてみれば白妙の富士の高嶺に雪は降りつつ」を例とします.
IPAdic
#import "@preview/auto-jrubby:0.3.0": *
#set page(width: auto, height: auto, margin: 0.5cm)
#set text(font: "Hiragino Sans", lang: "ja")
#let sample = "田子の浦にうち出でてみれば白妙の富士の高嶺に雪は降りつつ"
#show-ruby(sample)
IPAdicで形態素解析すると, 以下のように間違ったルビが振られてしまいます. 本来は, 「うち出で」は「ウチイデ」, 「降り」は「フリ」となるべきです.
IPAdic + ユーザ辞書
先ほどの誤りにユーザ辞書で対応します. ユーザ辞書は以下のようにCSVとして定義します. なお, 辞書形式はLinderaと同様に <surface>,<part_of_speech>,<reading> としています.
うち出で,カスタム動詞,ウチイデ
降り,カスタム動詞,フリ
CSVファイル以外にも, CSV形式の文字列と配列にも対応しています.
#let user-dict-str = "うち出で,カスタム動詞,ウチイデ
降り,カスタム動詞,フリ"
#let user-dict-arr = (
("うち出で", "カスタム動詞", "ウチイデ"),
("降り", "カスタム動詞", "フリ")
)
ユーザ辞書を使用する際は, CSVファイル (ユーザ辞書) をTypstの組み込み関数である csv で読み込み, show-ruby の user-dict に渡します.
#import "@preview/auto-jrubby:0.3.0": *
#set page(width: auto, height: auto, margin: 0.5cm)
#set text(font: "Hiragino Sans", lang: "ja")
#let user-dict = csv("user_dict.csv")
#let sample = "田子の浦にうち出でてみれば白妙の富士の高嶺に雪は降りつつ"
#show-ruby(sample, user-dict: user-dict)
以下がユーザ辞書を適用した際の組版結果です. ユーザ辞書により正しいルビに修正できています.
また, show-analysis-table で形態素解析結果を確認すると, 「うち出で」と「降り」がカスタム動詞として登録されており, ユーザ辞書が機能していることがわかります.
#import "@preview/auto-jrubby:0.3.0": *
#set page(width: 21cm, height: auto, margin: 0.5cm)
#set text(font: "Hiragino Sans", lang: "ja")
#let user-dict = csv("user_dict.csv")
#let sample = "田子の浦にうち出でてみれば白妙の富士の高嶺に雪は降りつつ"
#show-analysis-table(sample, user-dict: user-dict)
まとめ
本記事では, 形態素解析を用いて自動ルビ振りを行うTypstパッケージについて紹介しました. TypstではWASMプラグインを使用できるため (TeX/LaTeXまたはTypstだけでは難しい) 様々な処理を活用した組版が可能です. 皆さんも試してみてはいかがでしょうか.




