如何在切换语言时保持 URL 参数不丢失

解读

在国内多语言站点中,用户往往通过顶部导航或下拉框切换语言。常见做法是把语言标识拼进路由(如 /zh-cn//en/),但直接跳转会把当前页面的查询串(?a=1&b=2)或 Hash(#detail)丢掉,导致筛选条件、分页、埋点参数等关键信息失效。面试官想知道你是否能在纯前端构建阶段用 Grunt 把“零丢失”方案固化到工程里,而不是上线后靠后端补救。

知识点

  1. Grunt 任务生命周期initConfig → registerTask → run,可在 watch 触发时动态重写模板。
  2. 模板引擎变量注入:用 grunt.template.process 把当前 location.search 预埋在 HTML 的 data-* 属性里,供运行时读取。
  3. 无刷新语言切换:通过 history.replaceState 只改路径,不丢 query;需要浏览器兼容方案时,Grunt 可打包两套逻辑(replaceState + location.href 降级)。
  4. 多语言路径规则:国内主流采用子路径/zh-cn/)、子域cn.example.com)或查询参数?lang=zh),Grunt 需在构建期把静态资源引用路径同步修正,避免 404。
  5. Hash 与 Query 共存:部分老项目用 Hash 做路由,Grunt 的 string-replace 任务要把 window.location.hash 也拼回跳转地址。
  6. 缓存击穿策略:若 CDN 按 URL 缓存,切换语言后需保留 v=xxx 版本号,Grunt 的 filerev 任务应保证参数顺序固定,防止重复缓存。

答案

分“构建期”和“运行期”两步:

  1. 构建期
    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,保证开发时实时生效。

  2. 运行期
    页面加载后,给所有带 data-keep="true" 的切换按钮绑定 switchLang把当前 search 与 hash 完整拼到新路径,实现零丢失。
    若站点采用查询参数模式?lang=en),则把 switchLang 改为
    location.href = location.pathname + '?lang=' + targetLang + s.replace(/[?&]lang=[^&]*/,'') + h;
    同样通过 Grunt 在构建期注入,避免手写散落逻辑。

拓展思考

  1. SSR 场景:若公司用 Node 直出,Grunt 可在构建完把多语言模板推到 views/zh-cn/ 目录,并通过 grunt-express-server 预渲染,保证爬虫拿到的链接已带完整参数,对国内 SEO 更友好
  2. 微前端:子应用语言由主应用下发,Grunt 打包时把 __INJECT_LANG__ 占位符留好,主应用切换语言后通过 postMessage 下发,子应用用 history.replaceState 同步,避免重复跳转
  3. 统计埋点:国内常用百度统计、神策,切换语言后如果 URL 参数顺序变化,会导致“来源”丢失。Grunt 的 string-replace 可把参数按字母序排序,保证埋点一致性
  4. 灰度发布:结合 grunt-filerev 给每个语言目录生成 manifest.json,在 CDN 回源时带上 ?lang=xx&v=hash实现语言维度灰度,回滚只需改目录名即可。