如何在 Next.js(Pages Router)v16 中标记混合语言内容
为不同语言的文本添加可访问性标记
问题
当页面包含多种语言的文本时,浏览器和辅助技术会将所有内容视为页面的主要语言。例如,配置为英语的屏幕阅读器会用英语发音规则来朗读法语短语、西班牙语书名或德语公司名,这会导致依赖音频的用户听到难以理解的内容。浏览器还会根据错误的语言应用拼写检查和排版规则,将拼写正确的外语单词标记为错误,并错误处理特定语言的标点和格式规范。
这会为依赖准确发音的视障用户带来障碍,同时由于错误的拼写警告和不正确的文本渲染,也会影响所有用户的体验,增加视觉干扰。
解决方案
为包含外语文本的元素添加 HTML lang 属性,明确声明该内容的语言。该属性会告知浏览器和辅助技术,标记的文本应按照声明的语言规则处理,而不是页面的主要语言。屏幕阅读器会切换到相应的发音引擎,浏览器会应用正确的拼写检查词典,排版引擎也会采用特定语言的格式规则。
通过将外语文本包裹在带有正确 lang 属性的元素中,可以在内容中创建清晰的语言边界,从而保证多语言文本的完整性。
步骤
1. 创建带语言标记的文本组件
构建一个 React 组件,将外语内容包裹在 span 元素中,并添加合适的 lang 属性。
interface ForeignTextProps {
lang: string;
children: React.ReactNode;
}
export function ForeignText({ lang, children }: ForeignTextProps) {
return <span lang={lang}>{children}</span>;
}
该组件接受一个语言代码,并将其子元素包裹在 span 中,同时设置 lang 属性,从而创建一个语言边界,便于辅助技术和浏览器识别。
2. 使用组件标记外语短语
在内容中使用该组件包裹外语文本,并指定相应的 ISO 639-1 语言代码。
export default function ArticlePage() {
return (
<article>
<h1>Understanding French Cuisine</h1>
<p>
The concept of <ForeignText lang="fr">mise en place</ForeignText> is
fundamental to professional cooking. It means having all ingredients
prepared and organized before you begin.
</p>
<p>
The restaurant <ForeignText lang="fr">Le Bernardin</ForeignText> in New
York has maintained three Michelin stars for decades.
</p>
</article>
);
}
每个外语短语都用组件及其语言代码包裹,确保屏幕阅读器能正确朗读,浏览器能应用合适的语言规则。
3. 处理较长的外语片段
对于多句的外语内容,应将整个片段包裹在单个带有语言标记的元素中,以避免语言上下文被分割。
export default function QuotePage() {
return (
<article>
<h1>Universal Declaration of Human Rights</h1>
<h2>Article 1</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="This dish is called {dishName} in French cuisine."
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>;
}
将支持的语言定义为常量,可以在编辑器中获得自动补全,并清晰记录应用中使用了哪些语言代码,同时在需要时仍可使用任意语言代码。