消費者庁のサイトが speechSynthesis を使って読み上げ機能を提供しているが壊れている
現代のブラウザには speechSynthesis という API があってそれなりの性能の読み上げをすぐ実装できて便利なのだが、あまり活用例はないという状態だった。
ところが昨日偶然消費者庁がやっている特商法の解説サイトがこれを活用しているのを発見した。しかし盛大に壊れている。どう壊れているかは以下をご確認頂きたい。
消費者庁がやってるこのサイト、読み上げ機能があるんだけど中国語として読み上げようとするのでめちゃくちゃなことになってて面白いhttps://t.co/EKSLkP6N14 pic.twitter.com/vwkypBPsMz
— ナザレのイエス (@ssig33) February 5, 2020
で、なんでこんなことになっているのかとソースコードを見てみた。ぶっ壊れの理由は以下のような実装になっているからである(一部省略して核心部だけ示している)。
var voiceNum = 0;
if(navigator.userAgent.toLowerCase().indexOf('firefox') != -1) {
voiceNum = 0;
console.log('win firefox');
}else if(navigator.appVersion.indexOf('Edge') != -1) {
voiceNum = 0;
console.log('win Edge');
}else if(navigator.appVersion.indexOf('Chrome') != -1) {
voiceNum = 11;
voiceRate = 1.1;
console.log('win Chrome');
}else{
voiceNum = 0;
console.log('win');
}
var utterance = new SpeechSynthesisUtterance();
utterance.lang = 'ja-JP';
utterance.rate = voiceRate;
utterance.voice = speechSynthesis.getVoices()[voiceNum];
このコードは、 speechSynthesis.getVoices() の値が常に一定であることに依存している。しかし MDNの解説を見る限りそれは保証されていないようだし(そもそも This is an experimental technology とある)、実際僕の環境は実装者の意図とは違う値がかえってきているようだ。
ちょっと確認した限りでは、
- Windows 10 の Chrome と Edge ではダメ
- Mac の Chrome は大丈夫
- Mac の Firefox もダメ
というかんじであった。
ではどうすればよかったのか?というと以下のようにすべきである
speechSynthesis.getVoices().find(v => v.lang === 'ja-JP')
で、 Windows 10 の Chrome でこれに置き換えてみたら以下のようになった。
サクっと不具合直してみた、本当はこうなるものと思われる pic.twitter.com/R4R2s4Rxwd
— ナザレのイエス (@ssig33) February 5, 2020
感想
- experimental と書かれている機能を使う場合、継続的にちゃんと動いているかの確認が必要と思う
- speechSynthesis は(ちゃんと使えば)想像以上によく動く。積極的に導入していく価値がある