---
title: "繁体中文闪一下又变英文？我让 AI 当“跑腿翻译”，自己专心钉死 LocalStorage 那条线"
date: 2025-06-10
description: "一桩很土、很烦、很真实的 SPA：zh_HK 用户登录完像被英文附体。不写“赋能”小作文，只记我怎么把几小时的骂娘换成半小时能动手验证的节奏——AI 帮着列单子，我喂日志和代码；再补几句大实话：模型是在猜下一个词，不是你的线上替身；跳转前同步 lang 进 LS、多源优先级写死，真能救命。"
canonical_url: "https://yijinlee.com/articles/article-3"
tags:
  - 状态管理
  - LocalStorage
  - "URL SearchParams"
  - I18n
  - "竞态条件 (Race Condition)"
  - "LLM 辅助排障"
topic: "AI 外骨骼"
---

那次 Bug 不尖叫、不抛栈，只在心里捅一刀：用户在繁体商品页点购买，跳完登录回来，界面礼貌地闪过一秒“像中文的东西”，然后非常体贴地回到英文默认。没有红字报错，只有你自己知道又输了。

我盯着 LocalStorage 和 `URLSearchParams` 盯到酸，才把另一位“同事”拽进群：大语言模型。下文两句就够——**它到底能帮啥**，以及**咋用才不糟蹋电**。

---

### 先说人话：没人“思考”，大家都在接龙

自回归模型干的事很无聊：**根据上文猜下一个 token**。堆栈干净、重定向顺序写清楚，它接的话就更像隔壁 senior，而不是算命先生。

有人会塞文档片段进去（常说的 RAG）：不是开光，是**减少胡编文件名**的概率，少开十个 Tab 也是赚的。

但它**没有你的运行时**：可以写漂亮优先级，却闻不到登录域和商城共用一个 origin、LS 里还躺着三年前 A/B 测试写的 `language: en_US`。我的习惯：**让它吐假设和验证步骤，我来断点、看 Network、记谁先在谁头上踩了一脚。**

---

### 一、案发现场：繁體中文去哪儿了

**第一步：** 用户在 zh_HK 商品页点 `login()`，心里以为稳了。

**第二步：** 跳转账大概是 `https://.../login?lang=zh_HK`，看上去人畜无害。

**第三步：** 登录成功，认证中心抡回业务域——你以为老乡见老乡，实际像被人偷偷按了“恢复默认”。

我当时的咆哮压成气音，只对显示器负责。

---

### 二、真凶往往不叫丢参，叫“谁覆盖谁”

断点一加，两个老六浮上来，都不配写进 README 自豪栏：

**同域混用_LS：** 商城和登录共用一个“客厅”LocalStorage。登录初始化若先舔一口残留的 `language: en_US`，再假装没看见 URL 上的 `?lang=zh_HK`，你就会拿下一局**静默覆盖**。用户眼里是闪一下；debugger 里是**时序赢了，气质输光**。

**i18n 不认账：** 资源里只有 `zh_CN`，没有 `zh_HK`，框架温柔地英文兜底——温柔得你想请客吃饭换成请写检讨。

一句话收束：**没有可信的“状态信任链”，只剩一堆“你肯定懂我”的幻觉。**

---

### 三、和 AI 怎么分工，补丁才贴得牢

#### 1. 让它打小票，你来盖章

我会丢：读语言的函数片段、跳转前后两行日志、Network 里 302 排队姿势。它常吐这类东西：

**可能 A：** URL 先读还是 LS 先读。

**可能 B：** 哪些 key 名跨项目容易撞车。

**可能 C：** 要不要在重定向前强行 `setItem`。

我不让它判死刑，但**少按几次 F5**也是实在的。Copilot 同理：省的是敲样板和翻旧 PR，**脑力留给竞态**，别留给和模型吵架。

#### 2. 修起来很土，但要土得统一

共识写墙上：**LocalStorage（用户明确选择）> URL（这一轮想说啥）> 默认 fallback。** 别指望口耳相传能挡住线上翻车。

跳转前别装优雅，同步一锤子最实在：

```javascript
const lang =
  getUrlValue("lang") || getAppLocale() || "en_US";

try {
  localStorage.setItem("language", lang);
} catch (e) {
  // 隐身模式、策略禁存：别让整个登录陪葬
  console.error("Storage sync failed:", e);
}

window.location.href = `${loginUrl}?lang=${encodeURIComponent(lang)}`;
```

**别省** `encodeURIComponent`：有的语言码长得刁钻，不作不一定会死，作一下比较像干这行的。

#### 3. i18n：可以偷懒，别对用户偷懒

给 `zh_HK`、`zh_MO` 一条台阶——先用简体包顶着也比陡然英文强，长期该补资源还是补：

```javascript
const i18nConfig = {
  "zh-HK": messages["zh-CN"],
  "zh-MO": messages["zh-CN"],
};
```

文档写“已支持繁体”，代码 **fallback 到 en**，这种冷笑话我见得多了。AI 可以帮你扫一遍 locale 字符串、拉张现状表，**省的是怨气，不是责任。**

---

### 四、收尾：脏活各干各的，才像成年人干活

复杂 SPA 要问的不止“数据躺哪”，还有**啥时候被谁顺手改了一刀**：

**偏机器的：** 拼清单、对坑、把 Slack 碎嘴整理成能执行的步骤——像招了个文员。

**偏人的：** 对真实用户拍板、盯时序、拒掉“看起来很对但跟日志分手”的结论——像项目经理兼半个肇事司机。

再加几条 hygiene：LS 用 try-catch 包一下；同域多应用 key 加 namespace；优先级画张图贴墙上，比口头祖传靠谱。

送给深夜的你：**AI 不会让你一夜封神，只会让你更快发现——跟你在抢 LocalStorage 的，往往是六个月前那个觉得“先这样上”的自己。**

## 参考文章：相关链接

- [MDN · Window.localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage)（官方文档）— 同源存储读写与配额边界，锁定「闪一下又变英文」的状态线。
- [Vue I18n · Legacy API / Composition](https://vue-i18n.intlify.dev/guide/advanced/composition.html)（权威引文）— locale 响应式与 Composition API 切换点，便于对照 URL 参数竞态。
- [App弹窗惊现"英意"二语混编？深度拆解混合架构下的 i18n 状态同步惨案](https://yijinlee.com/articles/article-32)（站内深度）— 容器与 H5 双端 locale 不同步的升级版案例。
- [前端多语言兜底方案重构：彻底解决 Vue3 响应式陷阱与状态死循环](https://yijinlee.com/articles/article-33)（站内深度）— 从个案排障上升到可复用的 i18n 兜底架构。

