What is it, naokirin?

Webサイトの入力をtextlintでチェックして、正しい日本語の記述を補助する

普通に日本語チェックするのめんどいよねーという話が定期的に上がるけれど、有料のサービス組み込むほどじゃない、ということで、textlintで気軽にできないかなと思い立ったのでやってみました。

なんとなくRailsにActiveAdmin突っ込んで、管理画面のフォームの入力時にJavascriptでチェックという遠回りをしましたが、他でも普通に使えると思います。

サンプルでとりあえず動かしたときのリポジトリ
github.com

textlintとは

いわゆるESLintなどのLinterツールのように使える、自然言語向けのLinterです。

github.com

特徴として、プラグインを導入したりすることで、比較的簡単に検出したいパターンを増やすことができます。textlint-rule-prh というプラグインを利用することで、簡単にYAMLファイルでパターンを追加で設定することもできます。また日本人の方が作っているということで、日本での利用も多く、日本語向けのプラグインやルールも多数公開されています。

TypeScriptで作られており、npmで簡単にインストールして使うことができるのも特徴です。

textlintをWebサイトで利用する

さて、TypeScriptで作られていて、npmで公開されているということで、単純なパッケージ追加でフロントエンドに導入できるかというとそうではありません。Linterなのでコマンドとしての利用がメインであり、ブラウザでの動作は直接パッケージを入れるだけでは対応できません。

そこで、 @textlint/script-compiler を使ってJavaScriptライブラリを生成して利用することになります。これによりルールの設定なども取り込んだ形の単一スクリプトファイルになるため、そのスクリプトを呼び出して利用します。

スクリプトを生成できるようにする

まずは必要なパッケージを追加します。

今回はスクリプトファイルを生成する @textlint/script-compiler に加え、ルールの追加として textlint-rule-preset-japanesetextlint-rule-prh を入れます。スクリプトファイル生成時にしか使わないため、devDependenciesとして追加します。

yarn add -D @textlint/script-compiler textlint-rule-preset-japanese textlint-rule-prh

その後、スクリプトを生成するためのコマンドを yarn で実行できるように package.json に追加します。

"scripts": {
  "compile-textlint-worker": "textlint-script-compiler --mode production --output-dir ./public --metadataName 'textlint-worker' --metadataNamespace 'http://localhost:3000/' --metadataHomepage 'http://localhost:3000/'"
}

次に、textlintの設定ファイルとして .textlintrc を作成します。

ここで textlint-rule-preset-japanese の有効化と、prhルールとして、 icsmediaWEB+DB PRESS の公開されているルールを追加してみました。こちらは普通にYAMLファイルをダウンロードして追加しています(ディレクトリは適宜変えてください)。

{
  "rules": {
    "preset-japanese": true,
    "prh": {
      "rulePaths": [
        "./config/textlint_rules/prh_rules/icsmedia/prh_idiom.yml",
        "./config/textlint_rules/prh_rules/icsmedia/prh_open_close.yml",
        "./config/textlint_rules/prh_rules/icsmedia/prh_redundancy.yml",
        "./config/textlint_rules/prh_rules/icsmedia/prh_duplicate.yml",
        "./config/textlint_rules/prh_rules/icsmedia/prh_cho_on.yml",
        "./config/textlint_rules/prh_rules/icsmedia/prh_corporation.yml",
        "./config/textlint_rules/prh_rules/icsmedia/prh_web_technology.yml",
        "./config/textlint_rules/prh_rules/WEB+DB_PRESS.yml"
      ]
    }
  }
}

ここまでできれば、スクリプトを作成できます。

yarn compile-textlint-worker

生成したスクリプトを利用する

生成されたスクリプトを利用してみましょう。

まず、Workerを生成して、メッセージをtextlintに渡します(textlintに渡す部分は関数にしています)。

// 生成したスクリプトからWorkerを生成する
const textlintWorker = new Worker("/textlint-worker.js");

// textlintに渡す
function postToTextlint(text) {
  textlintWorker.postMessage({
    command: "lint",
    text: text,
    ext: ".txt",
  });
}

次にメッセージの処理が完了した後に結果を発行するイベントに結果を受け取って行う処理を登録をします。

// textlintの処理後の結果を受け取る
function registerTextlintCallback() {
  textlintWorker.onmessage = (event) => {
    if (event.data.command === "lint:result") {
      const messages = event.data.result.messages;
      // 行と列、エラーメッセージを文字列にして配列とする
      const result = messages.map(
        (message) => `[${message.line}:${message.column}] ${message.message}`
      );

      // 結果を処理する関数に渡す
      setTextlintResult(result);
    }
  };
}

これを利用して、フォーム入力時にJavaScriptでtextlintでチェックをかけてみました。

f:id:naokirin:20211217213624j:plain

無事に表示することができました。

実際のスクリプトは以下を参照してください。

activeadmin_textlint/textarea_textlint.js at main · naokirin/activeadmin_textlint · GitHub

最後に

textlintを組み込むってできるのかな?と最初は思いましたが、やってみると意外と簡単にできることがわかりました。

注意点として、最初にtextlintの特徴としてプラグインの利用を挙げましたが、 @textlint/script-compiler を利用する場合、利用できないプラグインも多いので注意が必要です。内部でローカルファイルにアクセスするようになっていたりすると、残念ながらブラウザで利用させる場合、動作させることができません(私も少しハマりました)。

とはいえ、そうではないプラグインは今回のように使えますし、prhで自分で設定をある程度作り込むということもできるので、社内運用で入力する際のチェックとして導入するといったときにはかなり有用ではないかと思います。

参考

今回はほとんど以下のサイトを参考にしています。

shrkw.hatenablog.com

www.collabo-style.co.jp