やさしい日本語の情報をやさしい日本語で発信する「やさにちウォッチ」を公開しました。
このオウンドメディアは PowerCMS Xで運営されています。実際にこの PowerCMS Xの製品サイトの CMSと同居していて、一つ専用のスペース(WorkSpace)を作成してそこで運用しています。
この記事では、「やさにちウォッチの舞台裏」と題して、主にCMS構築の観点から、利用している PowerCMS Xの機能を中心にご紹介します。
新バージョンに同梱の標準テーマ「Media」を利用
デザイン自体は非常にシンプルなものですが、Bootstrap 4をベースにした新テーマ(次のバージョンで追加されます)「Media」を使って構築されています。
ある程度のカスタマイズはしていますが、ベースはほぼ標準のテーマに近いものとなっています。
サイトは基本的に静的 HTMLを生成していますが、一部以下の部分で動的機能を利用しています。
- ランキングの表示(ランキングのためのデータ収集)
- フォーム
- ページネーション
尚、ふりがなとわかち書きは静的生成です。
ふりがなとわかち書きの実装
「SimplifiedJapanese」プラグインの機能を利用して、ほとんどのふりがなとわかち書きは自動で設定しています。
やさしい日本語エディタの機能が記事作成画面にありますので、そこで手作業で行っても良いのですが、PowerCMS Xのグローバルモディファイア「furigana」を利用しています。
エディタ上でふりがなを付けるよりも文章の修正などが楽になるメリットがあります。自動でのふりがな付与ですので、当然間違うこともありますが、プレビューで確認しておかしなものは、手動でふりがなを付与するか、あるいは辞書に登録することで修正をしています。
名前 |
説明 |
属性値 |
furigana |
rubyタグを用いてふりがなを追加します。 |
'1'を指定するとふりがなを追加 '2'を指定すると分かち書きしたテキストにふりがなを追加 '3'を指定するとふりがなを追加せずに分かち書きのみを適用 |
今回はわかち書き+ふりがななので、モディファイアの属性値には「2」を指定しています。
<mt:var name="contents" furigana="2">
わかちがきの ON/OFF のために、分かち書きの区切り文字を設定
furiganaモディファイアでわかち書きする文字をプラグイン設定で指定できます。今回は、チェックボックスによってわかち書きとふりがなをそれぞれ ON/OFF できるようにするために、SimplifiedJapaneseプラグインの「分かち書きの区切り文字」に以下のように spanタグに separatorクラスを追加した区切り文字を指定しました。
<span class="separator"> </span>
あとは、読者がチェックを ON/OFF するタイミングで cookieに設定を保存、ふりがなとわかち書きの ON/OFF を切り替えています。
(10月22日追記) rubyのスタイル調整について纏めました。
フォントの切り替え
(12月23日追記) フォントを「Noto Sans Japanese」とモリサワの「UDデジタル教科書体」の2種類から選択できるようにしました。
UDデジタル教科書体はロービジョン (弱視) の人やディスレクシア (読み書き障害) の人に対しての読みやすさについてのエビデンスを取得しているフォントです。教科書体ということで、子どもたちにも親しみがあります。
モリサワのUDフォントは、ユーザ評価に基づく読みやすさのエビデンスを取得しています。
TypeSquareは無料で1書体が使えるプランがあるのですが、残念ながら Ajaxなどで非同期読み込みしたコンテンツには書体が適用されてくれません。ですので、スタンダードプランⅡを契約しました。
ウェブアクセシビリティの改善
Mediaテーマそのままでは、WCSG2.0などのアクセシビリティへの対策が不十分な箇所がありました。以下の部分を主に調整しました。
- 背景色と前景色のコントラスト比 (AAA基準に適合)
- コントロールやリンクのフォーカス
- ハンバーガーメニューからナビゲーションを開いた時、画面サイズが狭いときは position: fixed から、position: relative に変更 ※
※ Bootstrapなどのテーマの開閉するメニューはポジション固定になっているものが多いと思いますが、スマートフォンなど狭い画面上で、ブラウザの文字サイズを拡大している時、スクロールできなくなってしまうので、固定化されないようにしました。アプリのように頻繁にアクセスするパーツでもないですし、ただでさえ画面が狭いので。画像はiPhoneで文字サイズを175%にした場合のスクリーンショットです。
また、ふりがなとわかち書き切り替えボタンですが、マークアップはチェックボックスなのでキーボード操作の時はスペースキーで切り替えできるのですが、見た目がチェックボックスに見えないことから、エンターキーでも変更可能なように JavaScriptで実装して、aria-label でその旨を説明するようにしました。VoiceOverで読み上げられることを確認済みです。
<input type="checkbox" id="furigana" name="furigana" value="1" checked
aria-label="ふりがなが有効です : スペースかエンターキーで切り替え"
data-aria-label--checked="ふりがなが有効です : スペースかエンターキーで切り替え"
data-aria-label--unchecked="ふりがなが無効です : スペースかエンターキーで切り替え">
<label for="furigana">ふりがな</label>
運用時には HTML_CodeSniffer プラグインを有効化して、設定を「AAA」としてチェックを行っています。
キーワード(タグ・アーカイブ)への自動リンク
一覧系ページは、カテゴリアーカイブとタグアーカイブ、年別アーカイブ(いずれも静的)を出力していますが、このうち、タグアーカイブには記事中にあらわれたタグを自動リンクするように設定しています。
Keywordsプラグインのブロックタグ「autokeywords」を使っています。
この機能はサイト公開後に思い立って実装したのですが、すでにタグ付けがされているため当初タグを CSVエクスポートしてキーワードにインポートしようと考えました。
ただ、このためだけにすでに「タグ」として登録されているものを別のテーブルにインポートし直すのは無駄だと考えたので、Keywordsプラグインの機能を拡張することにしました。
まず、ブロックタグ「autokeywords」の model属性に、キーワード以外のモデルを指定できるようにしました。今回は「tag」を指定しています。
タグには、キーワードモデルにあるようなリンク先を登録する「url」カラムがありませんが、やさにちウォッチではタグアーカイブを生成しているので、各々のタグのパーマリンクへのリンクとなるようにしました。
また、リンクの前後がわかち書きされてくれないので、生成したリンクの前後に挿入するわかち書きの区切り文字を enclosure 属性に渡すことによって前後をわかち書きできるようにしました。
<mt:setvarblock name="enclosure"><span class="separator"> </span></mt:setvarblock>
<mt:autokeywords replace_once="1" model="tag" min_length="2" enclosure="$enclosure">
<mt:entrybody convert_breaks="auto">
</mt:autokeywords>
これらの機能追加は、次のバージョンアップで皆様にもご利用いただけるようになります。
とりあえずやってみると、「本」というタグがあり、「日本」の「本」にリンクが付けられてしまいました。そこで、環境変数「keywords_use_mecab」を指定し、タグの判別に MeCabを利用することにしました。
MeCabを利用することで、「東京都」に含まれる「京都」を京都と判定してしまうようなことがなくなります。
ただし、逆に「福岡県」のようなタグを付けている場合「福岡」「県」というように形態素解析の結果がわかれてしまうため、
都道府県についてはキーワードにも別途登録しました(※keywords_use_mecabが有効の時、キーワードに登録された単語は形態素解析の辞書にも登録されるようになっています)。
記事の作成と編集
Webに不慣れなスタッフが記事を作成・編集することも多いため、記事は基本的にリッチテキストエディタを利用しています。
やさしい日本語変換ボタンもありますが、基本的には参考にする程度として、文章作成は基本的に人の手で行っています。
SNSや検索結果などに使われる「概要」(最近は検索結果というより主に SNSですが)欄へは、入力を忘れるケースが多く見られるので、これも Keywordsプラグインによる概要の自動生成を ONにしています。
ただ、基本的には人がそれを見て、適切なものに修正する、という使い方をしています。自動タグ付けも ONにしていますが、これも適切なものに人の手で編集するようにしています。
前述の通り、ふりがなについては、プレビューで意図しないものになってしまうもののみ手動で追加するか辞書に追加します。
ワークフローについては利用せず、ExternalPreviewプラグインが提供する「外部プレビュー」機能を利用し、Slackチャンネルにプレビュー URLを貼り付ける形でレビューを行っています。
ランキング部分の実装
AccessAnalyticsプラグインによってランキングの算出の元となるアクセス解析結果を取得して蓄積し、ブロックタグ「rankedobjects」を利用して出力しています。
アクセスランキングのような、定期的に自動更新されるようなコンテンツは、cronなどを利用して定期的に再構築を行うような方法もありますが、やさにちウォッチでは、動的生成とし、ブロックタグ「cacheblock」を利用することで、24時間キャッシュされるようにして無駄な負荷がかからないようにしています。そして、ページへの埋め込みは Ajaxによって非同期に読み込んでいます。
<mt:cacheblock cache_key="__widget_ranking__" workspace_id="$website_id">
<mt:rankedobjects models="entry" limit="10" include_workspaces="this">
〜
</mt:rankedobjects>
</mt:cacheblock>
RSSによる最新記事の配信
(9月15日追記) リクエストをいただいたので、RSSを追加しました。PowerCMS のRSSテンプレートとほぼ同じ形でインデックス・テンプレートを作成するだけです。ついでにRSSをSlackに自動連携するようにして、記事が公開されたことを社内でシェアするようにしました。
<mt:block regex_replace="'/^%s+$/um',''" remove_blank="1"><?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title><mt:websitename remove_html="1" encode_xml="1"></title>
<link><mt:websiteurl encode_xml="1"></link>
<description><mt:websitedescription remove_html="1" encode_xml="1"></description>
<mt:entries lastn="20">
<item>
<title><mt:entrytitle remove_html="1" encode_xml="1"></title>
<link><mt:entrypermalink encode_xml="1"></link>
<description><mt:entrybody encode_xml="1"></description>
<pubDate><mt:entrydate format_name="rfc822"></pubDate>
<mt:entrycategories>
<category><mt:categorylabel encode_xml="1"></category>
</mt:entrycategories>
</item>
</mt:entries>
</channel>
</rss>
</mt:block>
Twitterとの自動連携
PostOnTwitterプラグインを利用して、Twitterアカウント( @yasanichiwatch ) 別ウィンドウで開きますと連携し、記事の公開と同時にハッシュタグ付きでTwitterへポストするようにしています。
ツイートにはタイトルと概要を含めるようにして、ハッシュタグ「#やさしい日本語 アイコン別ウィンドウで開きます」を付けるようにしました。
<mt:setvarblock name="tweet_body"><mt:var name="object_primary" remove_html><mt:if name="model" eq="entry">
<mt:entryexcerpt remove_html></mt:if></mt:setvarblock><mt:var name="tweet_body" trim_to="107+..."> #やさしい日本語
ふりがな付き文字画像の OGP(og:image)の自動生成機能
(2022年05月12日追記) PowerCMS X の記事やページ作成時に、タイトルなどの文字をふりがな付きの画像文字として OGP(og:image)化、metaタグを自動設定することができる機能を追加したことに伴い、やさにちウォッチの投稿タイトルをふりがな付きで画像化して og:image を自動生成するようにしました。本来 Twitter などの SNS にはルビ(ふりがな)を追加することができないため、やさしい日本語での情報発信は括弧付きでふりがなを追加するか、ひらがなで投稿するなどの方法しかありませんでしたが、この機能を利用することで、ふりがな付きのテキストを画像化してシェアすることができ、スクリーンリーダーのユーザーに対するアクセシビリティを低下させたり、読みやすさを犠牲にすることなく SNS を通じたやさしい日本語での情報発信が実現できるようになります。画像化するテキストには UDフォントを利用しています。
サイト内検索
(2021年11月8日追記) サイト内検索機能を追加しました。Mediaテーマの標準の検索で実現できるのですが、そのままでは、ふりがなが付いている関係で意図したテキストがヒットしない問題と、検索結果のスニペット(概要) が不自然になる問題がありました。
例 : 「やさしい日本語」が「やさしい日本にほん語ご」となってインデックスされてしまう
そこで、プラグインを作成して検索インデックスをカスタマイズしました。あわせて、ひらがなをキーワード指定しても検索できるようにするために、SimplifiedJapaneseプラグインに「hiragana」モディファイアを追加実装して、例えば「西日本」でも「にしにほん」でも検索にマッチするようにカスタマイズしました。
function get_draft_searchestraier ( &$cb, $app, &$title, &$data, &$image_urls ) {
$urlinfo = $cb['urlinfo'];
if ( $urlinfo->workspace_id == 5 ) {
$obj = $cb['object'];
if ( $obj && $obj->_model == 'entry' ) {
$title = $obj->title;
$title = preg_replace( '!<rt[^>]*>.*?</rt>!', '', $title );
$title = strip_tags( $title );
$data = $obj->text;
$data = preg_replace( '!<rt[^>]*>.*?</rt>!', '', $data );
$data = strip_tags( $data );
$plugin = $app->component( 'SimplifiedJapanese' );
$ctx = $app->ctx;
$hiragana = $plugin->filter_hiragana( $data, 1, $ctx );
$hiragana = str_replace( ["\r\n", "\r", "\n"], '', $hiragana );
$data .= "\n\n\n\t{$hiragana}";
}
}
return true;
}
表記ゆれに対応する
(11月10日追記 : この機能は ver.3.01で追加されます) プラグインを書くことで、「西日本」でも「にしにほん」でもマッチするようになりました。ただ、「にしにっぽん」ではマッチしません。(11月10日追記) 表記ゆれの対応を実装したことで「にしにっぽん」でもマッチします。「ウイルス」というテキストを含む場合、「ウィルス」でもマッチするようにしたいということで、KeywordsプラグインとSearchEstraierプラグインを改良して「表記ゆれ」に対応できるようにしました。
表記ゆれの吸収は双方向に行われます。
例えば「ウイルス」に対する代替フレーズ「ウィルス」を登録した時、以下の両方ともどちらのワードでもヒットするようになります。
- キーワード「ウイルス」を含んでいて「ウィルス」を含まないコンテンツ
- キーワード「ウィルス」を含んでいて「ウイルス」を含まないコンテンツ
音声ファイルの追加
(11月18日追記 : この機能は ver.3.01で追加されます) 記事ページに記事を読み上げた音声ファイルを追加しました。
やさしい日本語エディタに「MP3ダウンロード」機能を追加しました。読み上げには Amazon Polly を使っています。
ルビを付けてからエクスポートすれば、その読みが適用されるようになります。エクスポートしたファイルは記事アセットに追加、ビュー(テンプレート)を以下のようにして、音声ファイルが記事アセットにある場合に、音声再生のコントロールを表示させています。
<mt:entryassets class="audio" limit="1">
<div class="mt-2 mb-3">
<audio src="<mt:asseturl>" controls style="width:100%" aria-label="この記事を読み上げる"></audio>
</div>
</mt:entryassets>
(11月26日追記) ファンクションタグ「mt:makemp3」というタグを追加して、音声が添付されていない記事に対しては自動で MP3ファイルを生成して埋め込むようにしました。(2022年1月26日追記) 「mt:makemp3」タグに「js_caption」属性を指定することによって、音声の再生と同期する字幕を表示する JavaScriptファイルを生成して自動で埋め込めるようにしました。
<mt:unless name="audio_out">
<mt:setvarblock name="mp3_path">assets/speech/audio_<mt:entryid>.mp3</mt:setvarblock>
<mt:setvarblock name="mp3_data">「<mt:entrytitle>」<mt:entrybody></mt:setvarblock>
<mt:makemp3 js_caption path="$mp3_path" text="$mp3_data" setvar="mp3_url">
<mt:if name="mp3_url">
<div class="mt-2 mb-3">
<audio id="audio-player" src="<mt:var name="mp3_url">" controls style="width:100%" aria-label="この記事を読み上げる"></audio>
<script src="<mt:var name="mp3_url" regex_replace="'/[^\.]{1,}$/','js'">"></script>
</div>
</mt:if>
</mt:unless>
※ AWS、Amazon Pollyは、AWS の米国およびその他の国における登録商標です。
※ UDデジタル教科書体は株式会社モリサワの商標または登録商標です。
※ NotoはGoogle Inc.の商標です。