国际化遗漏的排查经常从一个诡异现象开始:界面已经完成多语言翻译,切换到阿拉伯语后,仍然有按钮显示英文,同时部分布局像被强行翻转了一半,图标和文字间距完全错乱。

这类问题通常不是翻译管理系统没覆盖,而是源码中混入了未外置的硬编码字符串,并且样式层使用了大量向左或向右的物理定位属性。很多前端项目在起步阶段没有考虑多语言,等到业务扩展到中东市场时,开发人员才会集中处理国际化,结果往往只补齐了文案翻译,却漏掉了代码里散落的固定文本和RTL环境下的方向适配。
先定位遗漏:硬编码字符串如何破坏国际化
所谓硬编码字符串,是指直接写在页面结构、JavaScript逻辑或样式表中的用户可见文本。它们不受国际化资源文件控制,无论切换哪种语言,展示的都是原始语言。最常见的落点是按钮文字、表单占位符、错误提示、空状态文案、加载状态说明以及无障碍属性里的 aria-label。比如在 React 组件中直接返回 <button>Submit</button>,或在 Vue 模板里写 <input placeholder="请输入邮箱"/>,这些文本都无法通过切换语言包自动替换。
更隐蔽的是通过字符串拼接生成的语句,例如 '共' + count + '条记录'。有些语言的语序与中文不同,直接拼接会导致语法错误或者表达别扭。还有一类文本藏在CSS的 content 属性中,例如用伪元素显示提示词,这类文本在常规搜索中很难被发现。要彻底定位遗漏,不能只靠人工走查,需要借助扫描工具。
// 错误示例:硬编码文案
import React from 'react';
function Toolbar() {
return (
<div className="toolbar">
<button>提交订单</button>
<span>共 3 条记录</span>
</div>
);
}
这段代码在中文环境表现正常,一进入英文或阿拉伯语环境就会暴露问题。因为 提交订单、共 3 条记录 都写死在了组件内部,没有经过任何国际化处理。即使翻译文件里包含了对应词条,这个组件也不会去读取。因此,字符串外置的第一步不是翻译,而是先把所有用户可见文本从代码中分离出来,形成可管理的资源文件。
字符串外置的工程化实践
字符串外置不只是把文本移动到 JSON 文件里,还需要设计合理的资源结构和键名规范。通常按模块或页面拆分资源文件,例如 login.json、order.json、common.json。键名建议采用层级命名,避免使用中文作为 key,也避免使用没有语义的编号。像 user.login.submit、user.login.placeholder 这样的结构,既便于维护,也方便翻译人员理解上下文。
对于包含变量的文本,应该使用占位符而不是直接拼接。例如将 共 {count} 条记录 改为资源条目 common.totalRecords: '共 {count} 条记录',在渲染时通过插值函数替换 {count}。这样即使目标语言的语序变化,也可以通过调整占位符位置解决。复数形式同样需要单独处理,不同语言对单复数的规则差异很大,最好借助 i18next 或 FormatJS 提供的复数规则支持。
// messages/zh-CN.js
export default {
'toolbar.submit': '提交订单',
'toolbar.total': '共 {count} 条记录',
'toolbar.upload': '请上传文件'
};
// 组件中使用
import { useTranslation } from 'react-i18next';
function Toolbar() {
const { t } = useTranslation();
const count = 3;
return (
<div className="toolbar">
<button>{t('toolbar.submit')}</button>
<span>{t('toolbar.total', { count })}</span>
</div>
);
}
上述示例中,所有可见文字都通过 t 函数从资源文件读取,组件内部不再出现纯文本。如果后续新增语言包,只需提供对应翻译,无需改动组件。外置过程中容易忽略的是 alt、title、aria-label 等属性,这些也属于用户可感知的信息。例如图片的 alt 文本是重要的无障碍内容,不能因为视觉上不可见就跳过外置。
为了验证外置的完整性,可以启用伪本地化。把目标语言包替换成加上前后缀的伪语言,例如把每条翻译变成 [##提交订单##]。如果页面上还有不带前后缀的英文或中文残留,就说明存在遗漏。这种做法比逐个页面人工检查高效得多,也能在开发早期自动暴露拼接和硬编码问题。
RTL布局适配不只是加个dir属性
阿拉伯语、希伯来语、波斯语等语言从右向左阅读,界面整体的镜像方向需要调整。很多开发者误以为只要在 <html> 上加上 dir="rtl" 就能解决问题,实际上这只能改变文字默认对齐方向,并不能自动处理间距、边框、图标和动画。
样式层面最大的隐患是使用了物理方向属性,比如 margin-left、padding-right、border-left、left、right。在RTL环境下,原本靠左的元素应该靠右,原本向右的箭头应该指向左。现代浏览器支持CSS逻辑属性,应该优先使用 margin-inline-start、padding-inline-end、border-inline-start 等。逻辑属性会根据 dir 自动映射到物理方向,这样无需为RTL单独写覆盖样式。
/* 使用逻辑属性替代物理方向 */
.sidebar {
margin-inline-start: 20px;
padding: 10px 16px 10px 0;
}
.toolbar-button {
border-inline-start: 1px solid #e0e0e0;
}
/* 对特定RTL细节做补充调整 */
html[dir="rtl"] .sidebar {
border-inline-end: 1px solid #e0e0e0;
}
图标方向比文字间距更容易被忽略。表示前进、返回、关闭、展开的图标通常带有方向性,比如右箭头在RTL中应该变为左箭头。可以借助CSS transform: scaleX(-1) 进行镜像,但要注意并非所有图标都适合镜像。例如电话听筒、对勾、放大镜等图标本身没有方向,镜像反而会显得奇怪。因此图标资源最好按类型标记,只在方向图标的class上应用镜像。
弹窗、抽屉和表格也需要重新审视。从右侧滑出的抽屉在RTL环境中通常改为从左侧滑出,表格列的顺序往往需要反转,尤其当列带有操作按钮时,主操作应该靠近阅读起点。时间轴和步骤条的连接线方向也要随之调整。这些改动不是简单加一个 dir 属性就能自动完成,需要在组件层面感知方向,或者利用逻辑属性和 [dir="rtl"] 选择器做增量覆盖。
建立可回归的国际化验收基线
要避免国际化问题反复出现,最好把检查前移到开发阶段。可以使用 eslint 插件扫描 JSX、Vue 模板和普通 JavaScript 中的中文字符或未包裹的文本节点。对扫描结果配置白名单,例如注释、日志、测试用例可以排除,但UI组件里出现的任何可见文本都要求通过国际化函数渲染。
同时,在持续集成中增加RTL视觉回归测试。对关键页面分别截取 LTR 和 RTL 两种语言的截图,使用工具比对布局是否出现溢出、遮挡或方向错误。组件库的文档案例也应当同时提供两种方向下的展示,避免开发者在LTR下设计组件,到RTL环境才发现间距和图标方向都不对。
国际化不是一次性任务,而是代码规范的一部分。字符串外置解决的是内容可翻译问题,RTL适配解决的是方向可镜像问题。把这两件事固化到工程流程中,才能在每次新增需求和组件时,都不会重新引入遗漏。