HTML多语言支持:dir与lang配合使用
只设 dir="rtl" 或者只改 lang,都是不够的。对于阿拉伯语这类 RTL 语言,两者必须共存、各司其职。少一个,光标错位、数字乱码、连字失效、语音朗读出错这些状况,几乎是必然的。 为什么 lang 和 dir 必须同时写,且不能互换 想象一下:只设 lang="ar" 但没加 dir,阿拉
只设 dir="rtl" 或者只改 lang,都是不够的。对于阿拉伯语这类 RTL 语言,两者必须共存、各司其职。少一个,光标错位、数字乱码、连字失效、语音朗读出错这些状况,几乎是必然的。
为什么 lang 和 dir 必须同时写,且不能互换
想象一下:只设 lang="ar" 但没加 dir,阿拉伯文字会以 LTR 流向显示,象“”这样的词会被拆成孤立字符,哈姆扎的位置也会错乱。反过来,只设 dir="rtl" 但 lang="en",数字仍然会使用 ASCII 字符(012…),而不是阿拉伯-印度数字(…),屏幕阅读器也会按英语的发音规则去念阿拉伯语单词。更隐蔽的问题是,如果在 html 标签上漏掉任何一个属性,header、nav 这些顶层结构就无法正确继承方向或语言逻辑,菜单翻转了但文字不连字,表单输入的光标从左边开始。这些都不是小问题。
dir="rtl" 必须显式加在 和 上
即使父容器已经设置了 dir="rtl",在 Chrome 和 Firefox 中,原生表单控件默认仍然按 LTR 的行为来处理输入。我们来对比两个场景:
- 错误写法:
。你会发现占位符虽然右对齐了,但光标还是从左边界进入,选中文本时方向也是一片混乱。 - 正确写法:直接在
上显式声明:。这样,所有行为才会统一。 - 对于
textarea,还有一个额外的坑:换行行为。按下回车后,新的一行应该从右边界开始。如果发现异常,别急着找布局问题,先检查一下是不是误用了padding-left,正确的做法应该是用padding-inline-start。
混合内容里怎么隔离 LTR 片段(比如 URL、代码、英文术语)
在 dir="rtl" 的容器里直接写 https://example.com,BIDI 算法会把它当成阿拉伯语片段来处理,后果就是斜杠错位、域名被反转。正确的做法是用语义化标签包裹,并显式声明它们的语言和方向。
- 用
https://example.com,而不是只加一个direction: ltr的 CSS 属性。后者只影响视觉,不改变底层逻辑。 - 技术术语推荐使用
。这样,IDE 插件可以据此启用英文语法高亮,浏览器也会把它识别为独立的语言单元,不会受到父级 RTL 方向的干扰。useState - 如果需要引述外文原文,务必用
。用Je suis franais.
的话,翻译工具和语音引擎很可能无法正确识别。- 还有一个容易被忽略的细节:避免在已经设置
dir="rtl"的容器里再写text-align: right。这种冗余声明反而会让 BIDI 行为变得不可预测。动态切换语言时,
lang和dir怎么同步更新前端做多语言切换,如果只替换文案文本,那是远远不够的。必须同步更新
document.documentElement.lang和document.documentElement.dir。否则,SSR 渲染会残留旧配置,语音朗读会卡在之前的语种上,CSS 的:lang()选择器也不会生效。- 切换到阿拉伯语时,执行:
document.documentElement.lang = "ar"; document.documentElement.dir = "rtl"; - 切回中文时,执行:
document.documentElement.lang = "zh-CN"; document.documentElement.dir = "ltr"; - 别只修改某个
标签的lang。屏幕阅读器、搜索引擎、翻译插件,基本都只看标签上的声明。 - 对于服务端渲染的页面,
lang和dir应该从路由前缀(比如/ar/about)或用户的偏好头中提取,然后硬编码进 HTML 的初始状态。
最容易被忽略的,一个是表单控件上的
dir必须单独设置,不能靠继承;另一个是混合内容中,每一个 LTR 片段都得带上lang和dir的双重声明。少一个,BIDI 就可能在某个浏览器里崩一次。这绝不是什么“兼容性补丁”,而是 HTML 多语言排版的底层契约。 - 还有一个容易被忽略的细节:避免在已经设置
