语音合成必须为每个SpeechSynthesisUtterance显式设置符合BCP 47标准的lang属性(如zh-CN),且需配合匹配voice,否则中英文混排、多语言切换或移动端均会出现发音错误或静默失败。

lang 属性不写在 SpeechSynthesisUtterance 上,语音就可能读错音
浏览器的语音合成引擎(speechSynthesis)完全依赖 utterance.lang 决定发音规则。不设或设错,中文“行”可能读成 háng 而非 xíng,英文 “read” 可能固定读 /riːd/ 而不是根据上下文切换 /rɛd/。
-
utterance.lang必须显式赋值,不能靠页面<html lang="zh-CN">继承 - 值必须是 BCP 47 标准格式:
zh-CN有效,zh、zh_cn、ZH-CN全部无效 - Chrome 和 Edge 在
lang缺失时会 fallback 到系统语言,但 iOS Safari 可能直接静默失败 - 同一页面多次调用
synth.speak(),每次都要重设lang,它不会自动复用上一次值
局部多语言内容必须单独设 lang,否则 <mark> 或 <q> 白加
比如一段中英混排的教程:<p>用 <code><mark>flex</mark> 实现响应式布局</p>。如果只在 <html> 设了 zh-CN,flex 这个词仍会被按中文规则切音节,读成 “f-l-e-x” 而非 “fleks”。
- 正确做法:给英文词包裹元素并设
lang="en-US",例如<mark lang="en-US">flex</mark> -
<mark>本身不触发语言切换,只是语义锚点;没配lang,屏幕阅读器和speechSynthesis都无视它的“重点”含义 - 嵌套场景如
<div lang="en"><p>Hello</p></div>,内部所有文本都按英文处理,但子元素不能再用lang="zh-CN"覆盖——除非显式再写一层
SPA 切换语言时只改 document.body.lang,语音合成照样用旧语种
很多 SPA 框架(React/Vue)在切换语言时只更新 document.body.lang 或组件 state,但 speechSynthesis 完全不看这些。它只认 document.documentElement.lang(即 <html> 的 lang)用于 fallback,而真正起效的是每个 SpeechSynthesisUtterance 实例的 lang 属性。
- 语言切换后,新生成的
utterance必须手动设utterance.lang = "ja-JP",不能复用旧实例 - 旧
utterance即使还在队列里,也不会因页面 lang 变更而自动更新语言 - 别依赖
synth.cancel()后立刻synth.speak(newUtterance)就万事大吉——得确保newUtterance.lang已赋值,且值符合 BCP 47
voice 选错比 lang 设错更隐蔽,尤其在移动端
utterance.voice 不设时,浏览器会按 lang 自动匹配可用 voice,但这个匹配不可靠。iOS Safari 常 fallback 到英语 voice,即使 lang="zh-CN" 正确;Android Chrome 可能选中带口音的方言 voice,导致“北京”读成“bei jing”而非标准普通话。
立即学习“前端免费学习笔记(深入)”;
- 务必在
speechSynthesis.getVoices()返回后筛选 voice:voices.find(v => v.lang === 'zh-CN' && v.name.includes('Female')) - 注意
getVoices()是异步的:首次调用返回空数组,需监听synth.onvoiceschanged事件后再取 - 移动端尤其要避免只靠
lang不指定voice——Safari 17+ 对未指定 voice 的中文 utterance 有 30% 概率静默失败
lang,就可能让视障用户听不懂那句关键提示。



















