如何在 React Router v7 中标记混合语言内容
为无障碍访问标记不同语言的文本
问题
当页面包含多种语言的文本时,浏览器和辅助技术会假定所有内容都使用页面声明的语言。一台配置为英语的屏幕阅读器会尝试用英语发音规则来朗读法语短语、西班牙语书名或德语名字,这会为依赖音频的用户产生难以理解的输出。浏览器会根据页面语言应用拼写检查和排版规则,错误地将外语单词标记为错误,并错误处理特定语言的标点符号。搜索引擎和翻译工具在没有明确的语言标记时,无法准确处理混合语言内容。
这不仅影响屏幕阅读器用户,还影响任何依赖语言检测的浏览器功能的用户,包括自动翻译、文本转语音和阅读模式。
解决方案
将外语文本包裹在带有正确语言代码的 lang 属性的 HTML 元素中。lang 属性指示浏览器和辅助技术为特定内容切换语言规则,确保屏幕阅读器正确发音,浏览器正确拼写检查和排版。
使用语义化的 HTML 元素,例如 <span> 或 <i>,将内联的外语文本包裹起来,而不会破坏布局。lang 属性接受 ISO 639-1 语言代码(例如法语的 fr 或西班牙语的 es)以及可选的区域代码以处理特定方言。
步骤
1. 创建一个用于标记外语文本的组件
构建一个可重用的组件,将文本包裹在带有适当 lang 属性的 span 元素中。
type ForeignTextProps = {
lang: string;
children: React.ReactNode;
};
export function ForeignText({ lang, children }: ForeignTextProps) {
return <span lang={lang}>{children}</span>;
}
此组件接受一个语言代码,并将其子元素包裹在带有 lang 属性的 span 中,从而允许屏幕阅读器为包裹的文本切换发音规则。
2. 使用组件标记内嵌的外语文本
在内容中使用 ForeignText 组件包裹外语单词或短语。
export default function ArticlePage() {
return (
<article>
<h1>国际美食</h1>
<p>
餐厅的招牌菜是{" "}
<ForeignText lang="fr">coq au vin</ForeignText>,这是一道经典的法式菜肴,与他们的自酿葡萄酒完美搭配。
</p>
<p>
他们的甜点菜单包括{" "}
<ForeignText lang="es">tres leches</ForeignText> 和{" "}
<ForeignText lang="it">tiramisu</ForeignText>。
</p>
</article>
);
}
屏幕阅读器现在会用法语发音 "coq au vin",用西班牙语发音 "tres leches",用意大利语发音 "tiramisu",而周围的英文文本则使用英语发音。
3. 标记较长的外语段落
对于多句的外语内容,将 lang 属性直接应用于块级元素。
export default function QuotePage() {
return (
<article>
<h1>世界人权宣言</h1>
<h2>第一条</h2>
<blockquote lang="fr">
<p>
Tous les êtres humains naissent libres et égaux en dignité et en
droits. Ils sont doués de raison et de conscience et doivent agir les
uns envers les autres dans un esprit de fraternité.
</p>
</blockquote>
</article>
);
}
将 lang 应用于 blockquote 元素会将整个引用标记为法语,从而确保整个段落的正确发音和排版。
4. 与翻译的界面文本结合使用
在显示外语内容与翻译的界面文本时,使用 react-intl 处理界面元素,并对用户生成或引用的内容使用 lang 属性。
import { FormattedMessage } from "react-intl";
import { ForeignText } from "~/components/ForeignText";
export default function BookReview() {
return (
<article>
<h1>
<FormattedMessage id="review.title" defaultMessage="书评" />
</h1>
<p>
<FormattedMessage
id="review.intro"
defaultMessage="这本小说 {title} 探讨了身份和归属感的主题。"
values={{
title: <ForeignText lang="de">Der Steppenwolf</ForeignText>,
}}
/>
</p>
</article>
);
}
界面文本通过 react-intl 根据用户的语言环境进行适配,而书名则保留其原始的德语,并通过适当的语言标记确保可访问性。