@tonytopiko

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

iPhoneでWeb Speech APIの英語がカタカナ読みになる問題の解決法を教えてください

【iPhone】Web Speech APIで英語単語がカタカナ読みになる問題の解決法

解決したいこと

初心者です。
バニラJavaScriptでWeb Speech APIを使ったシンプルな英語学習アプリを開発しています。
一部のiPhone端末で、英語単語(例: "apple", "water")が意図した英語発音ではなく、カタカナ読み(「アップル」「ウォーター」)で音声合成されてしまいます。

iPhone端末間で音声合成結果が異なる原因と、確実に英語音声で再生させる方法を教えてください。

発生している問題・エラー

エラーメッセージは出ませんが、以下の症状が発生しています:

期待する結果: "apple" → 英語発音 /ˈæp.əl/
実際の結果: "apple" → カタカナ読み「アップル」

期待する結果: "water" → 英語発音 /ˈwɔː.tər/
実際の結果: "water" → カタカナ読み「ウォーター」

環境差異:

  • 動作正常: 一部のiPhone端末(Safari・Chrome共に正常動作確認済み)
  • カタカナ読み: 別のiPhone端末群(ユーザーから複数報告)
  • PC環境: 問題なし(全ブラウザで英語音声)

該当するソースコード

// 音声合成メイン関数
function speakWord(word) {
    setupSpeech(); // 音声コンテキスト初期化
    
    const textToSpeak = typeof word === 'string' ? word : word.english;
    const utterance = new SpeechSynthesisUtterance(textToSpeak);
    
    // 言語・音声設定
    utterance.lang = 'en-US';
    utterance.rate = 0.8;
    utterance.pitch = 1.0;
    utterance.volume = 1.0;
    
    // 英語音声の優先選択
    const voices = speechSynthesis.getVoices();
    const englishVoice = voices.find(voice => 
        voice.lang.startsWith('en') && 
        (voice.name.includes('English') || 
         voice.name.includes('US') || 
         voice.name.includes('United States'))
    );
    
    if (englishVoice) {
        utterance.voice = englishVoice;
    }
    
    window.speechSynthesis.speak(utterance);
}

// 音声コンテキスト初期化(Safari対策)
function setupSpeech() {
    if ('speechSynthesis' in window) {
        if (!window.speechSynthesis._warmedUp) {
            const dummy = new SpeechSynthesisUtterance('...');
            dummy.lang = 'en-US';
            dummy.rate = 1;
            dummy.volume = 0; // 無音
            dummy.onend = function() {
                window.speechSynthesis._warmedUp = true;
            };
            window.speechSynthesis.speak(dummy);
        }
        return true;
    }
    return false;
}

// 音声リスト取得の非同期対応
let availableVoices = [];
window.speechSynthesis.onvoiceschanged = function() {
    availableVoices = window.speechSynthesis.getVoices();
};

自分で試したこと

  1. 音声コンテキストの事前初期化

    • Safari対策としてダミー音声で初期化
    • speechSynthesis.onvoiceschanged での非同期取得対応
    • 結果:音声再生は安定、カタカナ読み問題は継続
  2. 英語音声の選択ロジック実装

    • voice.lang.startsWith('en') でフィルタリング
    • voice.name で英語音声を優先選択
    • 結果:一部端末で改善されず
  3. ユーザー環境の確認

    • Siri設定の有無は無関係であることを確認
    • ブラウザ種類(Safari・Chrome)は無関係であることを確認
  4. より厳密な音声フィルタリング(検討中)

    const englishVoices = voices.filter(v =>
        v.lang.startsWith('en') &&
        !v.name.match(/日本語|Kyoko|Otoya|Google 日本語|Nihongo/)
    );
    

質問内容:

  • iPhone端末間で音声合成結果が異なる根本的な原因は何でしょうか?
  • 確実に英語音声で再生させるための実装方法はありますか?
  • ユーザー側で設定変更により改善可能な手順はありますか?
  • Web Speech API以外の代替手法(音声ファイル再生等)を検討すべきでしょうか?

よろしくお願いいたします。

0 likes

1Answer

onvoiceschangedのイベントより先に、SpeechSynthesis.getVoices()が呼び出されてしまっているのではないでしょうか?
そのためspeakWord() 実行時にenglishVoiceがnullになる→結果的にデフォルト設定の日本語音声が呼び出されてしまっているのかもしれません。
一度ログを仕込んで実行時の配列の状態をコンソールで表示して確認してみた方が良いですね。
上記が原因だった場合は、onvoiceschangedのイベントを確実に実行してから後続の処理を行うようにロジックを整えていけば問題は解決しそうです。

あと今回のケースに限らず、処理中に利用されるオブジェクトの中身などは適宜ログ表示する事でエラー発生時に原因を特定しやすくなるので、重要だと思われる所には仕込んでおくのをお勧めします。

1Like

Comments

  1. @tonytopiko

    Questioner

    アドバイスをありがとうございます。
    まさにご指摘の通りのタイミング問題でした。
    ログ表示のアドバイスも非常に参考になりました。
    onvoiceschangedイベントの確実な待機とPromiseベースの初期化に修正し、デバッグログも追加してテスト版を作成しました。
    おかげで問題箇所の特定が容易になり、修正版では英語発音で正常に動作するようになりました。
    改めて、的確なご指摘をいただき、ありがとうございました!

  2. @tonytopiko

    Questioner

    解決しましたので、クローズさせていただきます。
    ありがとうございました。

Your answer might help someone💌