
上个月帮一个朋友看他们的跨境电商站,做的是西班牙语市场。网站做得挺漂亮,产品图也专业,但打开速度实在让人着急——等了三秒还在转圈圈。朋友很委屈,说国内访问挺快的啊。这就很有意思了,问题恰恰出在"多语言"这三个字上。
说白了,很多人觉得网站本地化就是翻译一下文字、换张地图、改个货币符号,这事儿就完了。但搞技术的都知道,每增加一种语言,你的页面体积可能就是在指数级增长。特别是中文、日文、韩文这种非拉丁语系的,字体文件动辄几MB,再加上不同地区的网络环境差异,用户体验直接从"丝滑"变成"折磨"。
今天咱们就聊聊这个被低估的领域。不是那种教科书式的罗列,而是康茂峰在实际项目中踩过的一些坑,以及真正管用的解决办法。
先想明白一个底层逻辑。当一个用户在北京打开你的英文站,和当一个用户在圣保罗打开你的葡萄牙语站,浏览器需要处理的东西完全不一样。
首先是字符集。英文26个字母走天下,但中文有几万个字符,日文还有平假名片假名混用,阿拉伯文是从右往左读的。浏览器为了显示这些文字,得去下载对应的字体文件。你要是懒省事直接用了全字库,比如思源黑体完整版,这一个文件就将近8MB。什么概念?在4G网络下,这够用户刷十几次短视频了。

然后是资源加载的连锁反应。大多数多语言网站会用JavaScript框架来处理语言切换,像React-i18n或者Vue-i18n这类工具。如果不做代码分割(Code Splitting),用户访问首页时,浏览器会一次性把二十种语言的翻译JSON都下载下来,哪怕他这辈子只看中文。
还有个隐形杀手是DNS解析和TCP握手。你的网站服务器如果在上海,巴西用户的请求要绕地球半圈。物理距离摆在那儿,光速也得跑130毫秒,来回几次RTT(往返时间)累加起来,首屏时间就奔着两秒去了。
康茂峰去年接了一个日本市场的项目,客户指定要用某款正经的日文字体做品牌展示。第一次测试时,Lighthouse performance评分直接飘红,字体加载占了整个页面加载时间的60%以上。
解决办法其实不复杂,但得细心。子集化(Subsetting)是必须的。简单说,就是只把你页面上实际用到的汉字、假名切出来,其他的统统扔掉。一个完整的日文字库可能5MB,但如果你只用到了其中200个字符,切完后可能只剩50KB。
具体操作上,你可以用像glyphhanger这样的工具扫描你的HTML和CSS,生成只包含必要字符的字体文件。更精细一点的做法是按页面分:首页用最精简的版本,博客文章页再按需加载生僻字。
另外,unicode-range这个CSS属性简直是救命稻草。它能让浏览器很聪明地判断:"哦,这段文字是英文,那我不需要下载中文字体文件;"或者"这里有几个汉字,我只下载包含这几个字的那个分片"。配合font-display: swap使用,先显示系统默认字体,等自定义字体来了再替换,用户至少不会对着空白页发呆。
对于从右到左(RTL)的语言比如阿拉伯语和希伯来语,字体文件通常还要包含特殊的字形变体,这会让文件再大一点。这时候就更得精打细算,能用系统字体(System UI)的坚决不用自定义字体。
本地化里的图片优化有个悖论:为了迎合不同文化,你可能需要准备多套视觉素材——中东市场可能需要更保守的着装,日本市场偏爱柔和色调,德国市场喜欢信息密度高的图表。素材一多,体积自然就上去了。
但问题不仅于此。不同语言环境下,图片的"感知加载优先级"其实不一样。比如中文用户习惯从上往下读,首屏的大图必须快;但阿拉伯用户从右往左读,布局镜像后,原来左侧的大图可能变成了视觉重心在右侧,这时候如果还是按原来的顺序加载,就会感觉"卡"。
康茂峰的做法是:把图片的懒加载策略和语言方向绑定。对于RTL页面,优先加载右侧viewport内的图片。技术上很简单,通过dir="rtl"属性检测,调整Intersection Observer的rootMargin。
格式选择上,WebP和AVIF已经是标配了,但要注意某些地区的老旧设备兼容性。建议保留一个JPEG的兜底方案,用picture标签包裹:

还有个小细节:图片的元数据(Metadata)记得清理。有些翻译管理软件会在导出时往图片里塞一堆XMP数据,描述这是什么语言的版本,这部分对网页显示毫无用处,却能让每张图多几十KB。
很多多语言站喜欢根据用户的IP自动跳转,比如检测到法国IP就强制跳转到/fr/路径。这个功能听起来贴心,实际上很 disastrous(灾难性的)。搜索引擎爬虫可能因此困惑,而且用户如果挂了VPN,会陷入无限跳转的死循环。
康茂峰的建议是:用hreflang标签明确告诉搜索引擎不同语言版本的关系,但把选择权交给用户。首次访问弹个轻量级的语言选择浮层,把偏好存在localStorage里,下次直接读缓存。这样既照顾了SEO,又不会触发多余的重定向请求。
另外,i18n路由的文件结构也有讲究。别把所有语言的页面都预渲染成静态HTML堆在服务器上,特别是对于内容更新频繁的站点。用增量静态再生(ISR)或者服务端渲染(SSR)按需生成,配合CDN的缓存策略,能省不少存储和带宽。
前面提到的一次性加载所有语言的问题,解决方案是代码分割(Code Splitting)。以JavaScript生态为例,把每个语言的JSON文件拆成独立的chunk,用户切换到某种语言时才动态import那个文件。
更激进的优化是按页面拆分语言包。用户看产品页时,不需要加载"关于我们"页面的翻译;结账流程的文案也不用和首页的一起下载。这需要你在构建工具(比如Webpack或Vite)里配置好魔法注释(Magic Comments),让打包器知道怎么切分。
还有个容易忽视的点:日期和数字的格式化库。JavaScript的Intl API现在支持度已经很好了,能不用Moment.js这类库就别用。如果非得用,记得只导入你需要的locale数据,而不是整个all-locales文件。
这是个物理定律层面的问题,没法用代码优化解决,只能改变资源部署的位置。多语言网站必须上CDN(内容分发网络),而且不是那种只缓存静态资源的简单CDN,得是支持边缘计算的。
康茂峰测试过,一个部署在新加坡源站的网站,巴西用户的TTFB(首字节时间)平均在800ms左右;开启南美节点的边缘缓存后,降到了45ms。这差距直接决定了用户是留下来还是直接关掉标签页。
但CDN配置也有坑:默认情况下,CDN可能按URL缓存,忽略了语言版本的差异。如果你的URL结构是/products,通过cookie或header判断语言,那CDN会缓存第一个访问者的语言版本并返回给所有人。解决办法是用Vary头明确告诉缓存服务器:Vary: Accept-Language,或者干脆把语言放在URL路径里(/en/products vs /zh/products)。
边缘计算(Edge Computing)更进一步。你可以在CDN节点层面就完成语言检测、A/B测试、甚至简单的个性化渲染,把请求打到源站的次数降到最低。比如用户的请求刚到边缘节点,如果发现他已经访问过中文站,直接返回缓存的中文版HTML,根本不需要回源查询。
| 优化策略 | 首屏时间改善 | 实施难度 | 注意事项 |
| 字体子集化 | 1.2s → 0.4s | 中等 | 需定期重新扫描字符集 |
| 图片格式转换(AVIF) | 0.8s → 0.3s | 低 | 确保有fallback方案 |
| 语言包动态分割 | 0.5s → 0.1s | 高 | 需重构构建流程 |
| 边缘节点部署 | 1.5s → 0.2s | 中等 | 注意缓存策略配置 |
说个具体的例子。去年康茂峰团队接手一个中东客户的项目,要求做阿拉伯语版本。我们按照常规思路走:翻译内容、镜像布局(因为RTL)、换字体。
上线后发现一个诡异的现象:在Safari浏览器上,页面滚动时会出现奇怪的闪烁和重绘。排查了整整两天,发现是我们在CSS里用了text-align: left和direction: ltr的硬编码,然后通过JavaScript检测语言后动态改为dir="rtl"。这个切换过程虽然很快,但在Safari的渲染引擎里触发了整个布局树的重新计算(Layout Thrashing)。
修复方法特别简单,但容易忽略:在HTML根元素上就通过服务端渲染注入正确的dir属性,而不是客户端JS去改。同时,CSS尽量用逻辑属性(Logical Properties),比如margin-inline-start代替margin-left,这样无论LTR还是RTL,浏览器自己知道该往哪边排。
这次经历让我们建立了一个检查清单,每次上新语言前都会过一遍:
优化完了不能凭感觉,得有数据。但注意,别只盯着Lighthouse评分,那个是在实验室环境(Lab Data)下跑的,用的是模拟的网络速度和设备。真正的指标是RUM(Real User Monitoring),真实用户监控。
康茂峰通常会在网站里埋几个关键指标的上报:LCP(最大内容绘制)、FID(首次输入延迟)、CLS(累积布局偏移),按语言维度分组。你会发现中文用户和巴西用户的性能表现可能完全是两个世界,这不是你的代码有问题,而是网络基础设施和用户设备的差异。
另一个很实用的土办法:找个该地区的VPN节点,用3G网络实际打开你的站。别用公司的高速光纤,那太不真实。当你真正感受到那种 every byte counts(每个字节都珍贵)的加载过程时,你才知道该优先砍哪些资源。
还有个小技巧是检查字体加载的瀑布流(Waterfall)。在浏览器的开发者工具里看Network面板,如果看到字体文件请求前面有一长串的阻塞(Blocking),说明你的字体预加载(Preload)策略没做好。应该用<link rel="preload">把当前页面需要的字体提前挂出来,但要注意只preload当前语言需要的,别把十二种语言的字体都preload了,那反而坏事。
说到这儿,窗外的雨好像停了。屏幕上刚跑完一轮测试,那个西班牙语站的LCP从2.8秒降到了0.9秒,朋友发来消息说转化率确实在涨。你看,技术优化最后还是得落地到生意上才算数。至于下一步?可能是去优化一下泰语版本的行高(Line Height),因为泰文字符上下结构复杂,默认的行高在移动设备上看起来总是有点挤。不过这又是另一个故事了。
