日本語でダミーコンテンツを生成するモジュール Devel Generate Localized を公開

はじめに
こんにちは。スタジオ・ウミの大野です。以前、Drupalの日本語検索についての記事を書きました。その検証をしていた頃、ずっと気になっていたことがあります。開発中にテスト用のダミーコンテンツを大量に作ると、中身がすべて英語のラテン文字になってしまう、という問題です。
日本語サイトを作っているのに本文が英語では、レイアウトの確認も検索の検証もいまひとつ現実味がありません。そこでこの問題を解決するモジュール「Devel Generate Localized」を作り、drupal.orgで公開しました。この記事ではこのモジュールが解決する課題と、その使い方、そして内部の仕組みまでを解説します。
Devel Generateとlorem ipsumの話
Drupal開発者にはおなじみのDevelというモジュールがあります。その中のDevel Generateという機能を使うと、ノード・ユーザー・タクソノミー・メニューといったエンティティをまとめて自動生成できます。動作確認やレイアウトの検証をするときに、手作業でコンテンツを1つずつ作らなくて済むので非常に便利です。
このDevel Generateが生成するコンテンツの本文には、いわゆる「lorem ipsum」と呼ばれるダミーテキストが使われます。次のようなラテン文字の意味のない文章です。
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
英語圏のサイトであればこれで十分なのですが、日本語をはじめとする非ラテン言語のサイトを開発していると、このlorem ipsumが少しやっかいな存在になってきます。
なぜ日本語サイトでlorem ipsumが困るのか
lorem ipsumはあくまでラテン文字の文章です。日本語サイトのテストに使うと、実際のコンテンツとは見た目や振る舞いが大きく異なります。具体的には次のような場面で困ります。
- レイアウト崩れの確認: 日本語と英語では文字の幅や1行に収まる文字数、そして改行される位置がまったく違うため、lorem ipsumで確認したレイアウトが本番の日本語コンテンツで崩れることがある
- 検索インデックスの検証: 前回の記事で解説したとおり、日本語の検索インデックスは単語の分割方法が英語と根本的に異なり、ラテン文字のダミーテキストでは日本語トークナイザーや検索精度の検証にならない
- 文字数・バイト数まわりの検証: 概要(サマリー)の切り詰めや文字数制限など、マルチバイト文字が絡む処理はラテン文字では正しく検証できない
要するに、日本語サイトのテストには日本語のダミーテキストが欲しくなります。とはいえ、テストのたびに日本語の文章を手作業で書いていくのは骨が折れます。
Devel Generate Localizedで解決する
そこで作ったのが今回のモジュールです。Devel Generate Localizedを有効にすると、生成されるエンティティのラベルやテキストフィールドの中身が変わります。lorem ipsumの代わりに、そのエンティティ自身の言語で書かれたダミーテキストが入るようになります。
生成されるテキストはlorem ipsum同様に意味を持たないダミーですが、使われる文字種と語彙は本物のコンテンツと同じになります。そのため、レイアウトの確認やテキスト解析の検証において、より現実に近い振る舞いをしてくれます。
実際に日本語で生成したコンテンツの一覧がこちらです。タイトルや投稿者名が、きちんと日本語になっています。

生成された記事を開くと、タイトル・概要・本文のすべてが日本語のダミーテキストで埋まっています。

Devel Generateが対応するすべてのエンティティタイプに対応しています。
- コンテンツ(ノード。付随するコメントを含む)
- ブロックコンテンツ
- メディア
- メニュー(メニューリンクを含む)
- タクソノミーの用語とボキャブラリー
- ユーザー(その言語に合わせた人名)
インストール
開発用の依存パッケージとしてComposerでインストールします。
composer require --dev drupal/devel_generate_localized
続いてモジュールを有効化します。
drush pm:enable devel_generate_localized
なお、Devel本体と同じく、これは開発用のモジュールです。本番環境では有効化しないでください。設定項目は一切なく、有効化するだけで動作します。
使い方
管理画面のフォームから生成する
通常どおり /admin/config/development/generate からエンティティを生成します。生成フォームで選んだ言語が、そのまま生成されるダミーテキストの言語になります。
各フォームにはLocalize the generated text(生成テキストを現地語化する)というチェックボックスが追加されます。デフォルトで有効になっており、チェックを外すとその回だけ従来どおりのlorem ipsumで生成されます。

なお、ユーザー・ボキャブラリー・メニューの生成フォームにはもともと言語の選択欄がありません。そのため、これらのフォームにはLanguage of the dummy text(ダミーテキストの言語)という選択欄をモジュール側で追加しています。デフォルトは管理画面の表示言語です。
Drushから生成する
--languages オプションで生成する言語を指定できます。
# 日本語のノードを10件生成する。
drush devel-generate:content 10 --languages=ja
# tagsボキャブラリーにロシア語の用語を5件生成する。
drush devel-generate:terms 5 --bundles=tags --languages=ru
--languages オプションが使えるのは content・terms・block-content・media の各コマンドです。users・vocabs・menus コマンドで作られるエンティティは、サイトのデフォルト言語に従います。
環境変数で言語を上書きする
DEVEL_GENERATE_LOCALE 環境変数を指定すると、エンティティの言語に関係なく、指定した言語でテキストを生成します。--languages オプションを持たないコマンドでも言語を指定できるのがポイントです。
# どんなサイトでも日本語の名前を持つユーザーを20件生成する。
DEVEL_GENERATE_LOCALE=ja drush devel-generate:users 20
DDEVやLandoなどコンテナ内でDrushを動かしている場合は、コンテナ内で環境変数を設定してください。ddev drush のようなラッパーコマンドの手前でホスト側に指定しても、コンテナ内のDrushプロセスには渡らず、エンティティの言語にフォールバックしてしまいます。
ddev exec 'DEVEL_GENERATE_LOCALE=ja drush devel-generate:users 20'
仕組み
ここからは少し技術寄りの話です。このモジュールがどうやって現地語のダミーテキストを生成しているのかを解説します。
FakerPHPでダミーテキストを作る
ダミーテキストの生成にはFakerPHPを使っています。FakerPHPはロケールごとにパブリックドメインの文学作品のデータを持っており、そこに含まれる単語をマルコフ連鎖でつなぎ合わせて、それらしいダミー文章を組み立てます。前述のとおり意味のない文章ですが、文字種と語彙は本物と同じになる、というわけです。
Devel Generateのプラグインを差し替える
Devel Generateの各エンティティタイプはプラグインとして実装されています。このモジュールでは hook_devel_generate_info_alter() を使います。content・menu・user・vocabulary の各プラグインのクラスを、独自のローカライズ対応クラスへ差し替えるためです。
そして生成の仕上げは hook_entity_presave() で行います。エンティティが保存される直前にフックし、ラベルやテキストフィールドを現地語のダミーテキストで埋めていきます。
coreのRandomを継承する
Devel Generateは、ダミーテキストの生成にDrupal coreの \Drupal\Component\Utility\Random クラスを使っています。このモジュールでは Random を継承した LocalizedRandom クラスを用意しました。sentences() や paragraphs() といったメソッドをオーバーライドし、FakerPHPの出力に置き換えています。coreの Random が期待される場所にそのまま差し込めるので、既存の生成ロジックを大きく壊さずに済みます。
スペースのない言語への対応
ここが日本語対応で少し工夫したところです。Devel Generateのタイトルの長さは「単語数」で指定されます。ところが日本語や中国語には単語の区切りとなるスペースがないため、単語数という単位がうまく機能しません。
そこでこのモジュールでは、スペースのない言語について1単語をおよそ5文字として文字数に換算しています。「タイトルの最大単語数」の設定は、日本語では文字数の目安として解釈されるわけです。
言語コードからFakerロケールへの解決
FakerPHPは多くのロケールで人名や住所をローカライズできますが、本文用のテキストデータ(realText() が使うデータ)を持っているのは一部のロケールだけです。そのため、Drupalの言語コードをそのまま渡すのではなく、FakerLocaleResolver というクラスで、本文データを持つFakerロケールへ変換しています。
fr-ca や de-ch のような地域つきの言語コードは、対応するFakerロケールがあればそれを使い、なければその言語のメインロケールにフォールバックします。本文データを持たない言語のエンティティは、変換に失敗するので手を加えず、従来どおりのlorem ipsumのままになります。
対応言語
FakerPHPが本文用のテキストデータを持っている言語に対応しています。日本語・中国語(繁体字)・韓国語・英語・ドイツ語・フランス語・スペイン語・ロシア語・ポルトガル語など、幅広い言語が含まれます。正確な対応範囲はインストールされているFakerPHPのバージョンに依存するので、詳しくはFakerPHPのドキュメントをご確認ください。
既知の制限
hook_devel_generate_info_alter()でプラグインのクラスを差し替えるため、同じクラスを差し替える別のモジュールとは共存できず、どちらか一方しか有効にならない- FakerPHPが本文データを持たない言語のエンティティは、従来どおりのlorem ipsumのままになる
まとめ
日本語サイトの開発では、ダミーコンテンツもまた日本語であってほしい、という地味だけれど確かなニーズがあります。Devel Generate Localizedを使えば、いつものDevel Generateの操作のまま、記事の言語に合ったダミーテキストが手に入ります。レイアウトの確認や検索の検証を、より本番に近い状態で進められるはずです。
開発用モジュールなので派手さはありませんが、日本語をはじめとする非ラテン言語でDrupalサイトを開発している方には、地味に効いてくるモジュールです。よろしければぜひ使ってみてください。




