如何在切换语言时保持 URL 参数不丢失
解读
在国内多语言站点中,用户往往通过顶部导航或下拉框切换语言。常见做法是把语言标识拼进路由(如 /zh-cn/、/en/),但直接跳转会把当前页面的查询串(?a=1&b=2)或 Hash(#detail)丢掉,导致筛选条件、分页、埋点参数等关键信息失效。面试官想知道你是否能在纯前端构建阶段用 Grunt 把“零丢失”方案固化到工程里,而不是上线后靠后端补救。
知识点
- Grunt 任务生命周期:
initConfig → registerTask → run,可在watch触发时动态重写模板。 - 模板引擎变量注入:用
grunt.template.process把当前location.search预埋在 HTML 的data-*属性里,供运行时读取。 - 无刷新语言切换:通过
history.replaceState只改路径,不丢 query;需要浏览器兼容方案时,Grunt 可打包两套逻辑(replaceState+location.href降级)。 - 多语言路径规则:国内主流采用子路径(
/zh-cn/)、子域(cn.example.com)或查询参数(?lang=zh),Grunt 需在构建期把静态资源引用路径同步修正,避免 404。 - Hash 与 Query 共存:部分老项目用 Hash 做路由,Grunt 的
string-replace任务要把window.location.hash也拼回跳转地址。 - 缓存击穿策略:若 CDN 按 URL 缓存,切换语言后需保留
v=xxx版本号,Grunt 的filerev任务应保证参数顺序固定,防止重复缓存。
答案
分“构建期”和“运行期”两步:
-
构建期
a. 在 Gruntfile 里新建任务i18n:url,用grunt-contrib-copy把入口 HTML 拷到dist/zh-cn/、dist/en/等目录;同时用grunt-string-replace把
<a class="lang-switch" href="__LANG__">
替换成
<a class="lang-switch" href="javascript:;" data-lang="__LANG__" data-keep="true">
其中__LANG__会被替换成目标语言路径。
b. 用grunt-contrib-uglify把公共逻辑i18n.js压缩,该文件包含:function switchLang(targetLang){ var s = location.search, h = location.hash; var newPath = location.pathname.replace(/^\/(zh-cn|en)\//, '/' + targetLang + '/'); if(history.replaceState){ history.replaceState(null, '', newPath + s + h); location.reload(); // 走同一路由,后端透传模板 }else{ location.href = newPath + s + h; // 降级 } }c. 在
watch里监听i18n.js变化,触发i18n:url,保证开发时实时生效。 -
运行期
页面加载后,给所有带data-keep="true"的切换按钮绑定switchLang,把当前 search 与 hash 完整拼到新路径,实现零丢失。
若站点采用查询参数模式(?lang=en),则把switchLang改为
location.href = location.pathname + '?lang=' + targetLang + s.replace(/[?&]lang=[^&]*/,'') + h;
同样通过 Grunt 在构建期注入,避免手写散落逻辑。
拓展思考
- SSR 场景:若公司用 Node 直出,Grunt 可在构建完把多语言模板推到
views/zh-cn/目录,并通过grunt-express-server预渲染,保证爬虫拿到的链接已带完整参数,对国内 SEO 更友好。 - 微前端:子应用语言由主应用下发,Grunt 打包时把
__INJECT_LANG__占位符留好,主应用切换语言后通过postMessage下发,子应用用history.replaceState同步,避免重复跳转。 - 统计埋点:国内常用百度统计、神策,切换语言后如果 URL 参数顺序变化,会导致“来源”丢失。Grunt 的
string-replace可把参数按字母序排序,保证埋点一致性。 - 灰度发布:结合
grunt-filerev给每个语言目录生成manifest.json,在 CDN 回源时带上?lang=xx&v=hash,实现语言维度灰度,回滚只需改目录名即可。