如何在 Next.js (Pages Router) v16 中标记混合语言内容
为不同语言的文本标记以提高可访问性
问题
当页面包含多种语言的文本时,浏览器和辅助技术会将所有内容视为页面主要语言的一部分。配置为英语的屏幕阅读器会尝试用英语发音规则来朗读法语短语、西班牙语书名或德语公司名称,这会为依赖音频的用户生成难以理解的输出。浏览器会基于错误的语言应用拼写检查和排版规则,将正确拼写的外语单词标记为错误,并错误处理语言特定的标点符号和格式规则。
这为依赖准确发音的视障用户制造了障碍,同时由于错误的拼写检查警告和不正确的文本渲染引入了视觉噪音,降低了所有用户的体验。
解决方案
将 HTML 的 lang 属性应用于包含外语文本的元素,明确声明该内容的语言。此属性向浏览器和辅助技术发出信号,表明标记的文本应使用其声明语言的规则进行处理,而不是页面主要语言的规则。屏幕阅读器会切换到适当的发音引擎,浏览器会应用正确的拼写检查字典,排版引擎会使用语言特定的格式规则。
通过将外语文本包裹在带有正确 lang 属性的元素中,可以在内容中创建清晰的语言边界,从而保持多语言文本的完整性。
步骤
1. 创建一个带语言标记的文本组件
构建一个 React 组件,将外语内容包裹在带有适当 lang 属性的 span 元素中。
interface ForeignTextProps {
lang: string;
children: React.ReactNode;
}
export function ForeignText({ lang, children }: ForeignTextProps) {
return <span lang={lang}>{children}</span>;
}
此组件接受一个语言代码,并将其子元素包裹在一个带有 lang 属性的 span 中,从而创建一个辅助技术和浏览器可以识别的语言边界。
2. 使用组件标记外语短语
在内容中使用组件包裹外语文本,并指定适当的 ISO 639-1 语言代码。
export default function ArticlePage() {
return (
<article>
<h1>了解法国美食</h1>
<p>
<ForeignText lang="fr">mise en place</ForeignText> 的概念是
专业烹饪的基础。这意味着在开始之前准备好并组织好所有的食材。
</p>
<p>
位于纽约的餐厅 <ForeignText lang="fr">Le Bernardin</ForeignText>
几十年来一直保持着米其林三星的荣誉。
</p>
</article>
);
}
每个外语短语都用组件包裹,并附上其语言代码,确保屏幕阅读器正确发音,浏览器应用适当的语言规则。
3. 处理较长的外语段落
对于多句的外语内容,将整个段落包裹在一个带有语言标记的元素中,以避免语言上下文的分割。
export default function QuotePage() {
return (
<article>
<h1>世界人权宣言</h1>
<h2>第一条</h2>
<blockquote lang="es">
<p>
Todos los seres humanos nacen libres e iguales en dignidad y derechos
y, dotados como están de razón y conciencia, deben comportarse
fraternalmente los unos con los otros.
</p>
</blockquote>
</article>
);
}
将 lang 直接应用于块级元素(如 blockquote 或 p),标记整个段落,确保屏幕阅读器在整个段落中保持一致的发音,浏览器对完整的上下文应用语言规则。
4. 在格式化消息中标记外语文本
当外语内容出现在翻译消息中时,在消息的富文本格式中使用组件标记外语内容。
import { FormattedMessage } from "react-intl";
export default function RecipePage() {
return (
<div>
<FormattedMessage
id="recipe.description"
defaultMessage="这道菜在法式料理中被称为 {dishName}。"
values={{
dishName: <ForeignText lang="fr">coq au vin</ForeignText>,
}}
/>
</div>
);
}
该组件与 react-intl 的富文本格式集成,允许您在翻译内容中标记外语术语,同时为辅助技术保留语言边界。
5. 为语义强调创建变体
扩展模式以在外语文本需要强调或惯用样式时使用语义 HTML 元素。
interface ForeignEmphasisProps {
lang: string;
children: React.ReactNode;
}
export function ForeignEmphasis({ lang, children }: ForeignEmphasisProps) {
return <i lang={lang}>{children}</i>;
}
i 元素语义上表示以另一种语气或情绪呈现的文本,非常适合用于需要从周围文本中区分出来的外语术语。lang 属性确保正确的发音,同时该元素提供语义意义。
6. 记录支持的语言代码
创建一个类型或常量来定义您的应用程序支持的语言代码,以确保一致性并在开发时捕获错误。
export const SUPPORTED_LANGUAGES = {
FRENCH: "fr",
SPANISH: "es",
GERMAN: "de",
ITALIAN: "it",
JAPANESE: "ja",
CHINESE: "zh",
} as const;
type LanguageCode =
(typeof SUPPORTED_LANGUAGES)[keyof typeof SUPPORTED_LANGUAGES];
interface ForeignTextProps {
lang: LanguageCode | string;
children: React.ReactNode;
}
export function ForeignText({ lang, children }: ForeignTextProps) {
return <span lang={lang}>{children}</span>;
}
将支持的语言定义为常量可以在编辑器中提供自动补全功能,并记录应用程序中使用的语言代码,同时在需要时仍允许使用任意语言代码。