chore: 移除i18n守卫插件与废弃的国际化文档
1. 删除vue.config.js中的I18nGuardPlugin构建期审计插件 2. 删除docs目录下全部废弃的国际化规则文档
This commit is contained in:
@@ -1,206 +0,0 @@
|
||||
{
|
||||
"exchangeSuccess": "兑换成功",
|
||||
"spec": "规格",
|
||||
"inputPlaceholder": "搜索商品",
|
||||
"commissiontext": "佣金",
|
||||
"paypassword": "支付密码",
|
||||
"buy": "购买",
|
||||
"passwordInputPlaceholder": "请输入密码",
|
||||
"getDynacode": "获取动态验证码",
|
||||
"make": "立即咨询",
|
||||
"receivingReply": "正在接收回复",
|
||||
"save": "保存",
|
||||
"Search": "请输入您要搜索的商品",
|
||||
"accountPlaceholder": "请输入用户名",
|
||||
"paymentAmount": "支付金额",
|
||||
"serviceTemporaryUnavailable": "抱歉,服务暂时不可用,请稍后重试。",
|
||||
"video": "视频",
|
||||
"coupon": "优惠券",
|
||||
"registrationAgreement": "注册协议",
|
||||
"surePhoneNumber": "请输入正确的手机号",
|
||||
"location": "位置",
|
||||
"loadHistoryFail": "加载历史失败",
|
||||
"Random": "综合",
|
||||
"emojiTitle": "表情",
|
||||
"searchAtBottom": "已到底部",
|
||||
"buynow": "立即购买",
|
||||
"complete": "完成",
|
||||
"pleaseInputNewPassword": "请输入新密码",
|
||||
"settingsTitle": "设置",
|
||||
"menuClearChat": "清空聊天",
|
||||
"total": "合计",
|
||||
"receivingCity": "地区",
|
||||
"startRecordTip": "点击开始录音",
|
||||
"stock": "库存",
|
||||
"status": "该商品已下架",
|
||||
"logoutContent": "确定要退出登录吗",
|
||||
"thanksFeedback": "感谢您的反馈!",
|
||||
"mobileInputPlaceholder": "请输入您的手机号",
|
||||
"copySuccess": "复制成功",
|
||||
"enterCaptchaTip": "请输入验证码",
|
||||
"prompt": "提示",
|
||||
"password": "密码",
|
||||
"moreFunctions": "更多功能",
|
||||
"retry": "重试",
|
||||
"telephonePlaceholder": "收货人固定电话(选填)",
|
||||
"searchPlaceholder": "搜索聊天记录",
|
||||
"recordingTip": "正在录音,松开结束",
|
||||
"home": "首页",
|
||||
"aiThinking": "AI正在思考",
|
||||
"serviceTypeNotSupported": "当前客服类型不支持此页面",
|
||||
"messageContent": "留言内容",
|
||||
"title": "VR",
|
||||
"fallbackWelcome": "您好!我是AI智能客服,很高兴为您服务!\\n\\n我可以帮您:\\n• 解答产品相关问题\\n• 处理订单问题\\n• 提供技术支持\\n• 推荐相关商品\\n\\n请告诉我您需要什么帮助?",
|
||||
"kefu": "客服",
|
||||
"lang": "语言",
|
||||
"aiNickname": "智能助手",
|
||||
"balance": "余额",
|
||||
"login": "登录/注册",
|
||||
"image": "图片",
|
||||
"voiceInputTitle": "语音输入",
|
||||
"sellout": "库存不足",
|
||||
"birthday": "生日",
|
||||
"improveService": "我们会改进服务",
|
||||
"changeAvatarDesc": "自定义您的聊天头像",
|
||||
"noContentToCopy": "无可复制的内容",
|
||||
"operationFailed": "操作失败,请重试",
|
||||
"mobilePhone": "手机",
|
||||
"point": "积分",
|
||||
"waitsend": "待发货",
|
||||
"emptyTips": "暂无记录",
|
||||
"submit": "提交",
|
||||
"dynacodePlaceholder": "请输入动态码",
|
||||
"waitpay": "待付款",
|
||||
"name": "姓名",
|
||||
"changeNickname": "更换昵称",
|
||||
"fileOpenFail": "文件打开失败",
|
||||
"menuExport": "导出记录",
|
||||
"dynacodeInputPlaceholder": "请输入动态码",
|
||||
"newAddAddress": "添加收货地址",
|
||||
"common.searchTip": "请输入搜索关键词",
|
||||
"copy": "复制",
|
||||
"recharge": "充值",
|
||||
"noEmityNickname": "昵称不能为空",
|
||||
"copyFail": "复制失败",
|
||||
"addressPlaceholder": "小区、街道、写字楼",
|
||||
"follow": "收藏",
|
||||
"expandEditorTitle": "编辑内容",
|
||||
"pleaseEnterMessage": "请输入留言内容",
|
||||
"privacyPolicyText": "《隐私条款》",
|
||||
"modifyNickname": "修改昵称",
|
||||
"express": "快递发货",
|
||||
"mobile": "手机",
|
||||
"searchEntrance": "搜索",
|
||||
"send": "配送",
|
||||
"paymentSuccess": "支付成功",
|
||||
"paymentFail": "支付失败",
|
||||
"findanimateCode": "获取动态码",
|
||||
"alikeusername": "与原用户名一致,无需修改",
|
||||
"editNickname": "修改昵称",
|
||||
"privacyPolicy": "隐私协议",
|
||||
"confirmCodeInput": "请输入验证码",
|
||||
"accountInputPlaceholder": "请输入账号",
|
||||
"animateCodeInput": "请输入动态码",
|
||||
"toLogin": "去登录",
|
||||
"leave": "立即留言",
|
||||
"searchClose": "完成",
|
||||
"pleaseEnterMobile": "请输入您的手机号",
|
||||
"avatarChangeSuccess": "头像更换成功",
|
||||
"avatarSelectorTitle": "更换头像",
|
||||
"modify": "修改",
|
||||
"consigneePlaceholder": "收货人姓名",
|
||||
"contactInfo": "联系方式",
|
||||
"menuSettings": "设置",
|
||||
"sales": "销量",
|
||||
"allElection": "全选",
|
||||
"changeAvatar": "更换头像",
|
||||
"requestFailTip": "request:fail",
|
||||
"updateSuccess": "修改成功",
|
||||
"call": "一键拨打",
|
||||
"alikeNickname": "与原昵称一致,无需修改",
|
||||
"alikePhone": "与原手机号一致,无需修改",
|
||||
"cancel": "取消",
|
||||
"chatCleared": "聊天记录已清空,有什么可以帮助您的吗?",
|
||||
"toGoodsCategoryPage": "去逛逛",
|
||||
"mobilePlaceholder": "收货人手机号",
|
||||
"confirmClearChat": "确定要清空聊天记录吗?",
|
||||
"logout": "退出登录",
|
||||
"agreeAgreementTip": "请先阅读并同意协议",
|
||||
"withdrawal": "提现",
|
||||
"noEmityUsername": "用户名不能为空",
|
||||
"Make": "立即咨询",
|
||||
"chooseFromAlbum": "从相册选择",
|
||||
"enterCorrectMobileTip": "请输入正确的手机号",
|
||||
"account": "账号",
|
||||
"cart": "购物车",
|
||||
"details": "商品详情",
|
||||
"loginTpis": "点击登录 享受更多精彩信息",
|
||||
"Price": "价格",
|
||||
"newAddAccount": "新增账户",
|
||||
"serviceUnavailable": "抱歉,AI服务暂时不可用,请稍后重试。",
|
||||
"voiceInputFailed": "语音输入失败",
|
||||
"copyFailed": "复制失败",
|
||||
"welcomeText": "您好,<br />欢迎使用",
|
||||
"edit": "管理",
|
||||
"file": "文件",
|
||||
"pleaseEnterName": "请输入您的姓名",
|
||||
"goHome": "回到首页",
|
||||
"accountType": "账号类型",
|
||||
"consignee": "姓名",
|
||||
"max": "已达最大限购数量",
|
||||
"defaultNickname": "我",
|
||||
"about": "0B",
|
||||
"see": "查看兑换记录",
|
||||
"searchAtTop": "已到顶部",
|
||||
"userServiceAgreementText": "《用户服务协议》",
|
||||
"activist": "售后",
|
||||
"logoutTitle": "提示",
|
||||
"noMatchResult": "未找到匹配结果",
|
||||
"search": "商品搜索",
|
||||
"consult": "立即咨询",
|
||||
"timeFormatYesterday": "昨天",
|
||||
"nicknameTip": "昵称长度限制1-12个字符,仅自己可见",
|
||||
"loadMoreHistory": "加载更多历史消息",
|
||||
"completed": "已完成",
|
||||
"registerAgreementText": "若您未注册,则登录后将自动帮您注册。注册即视为同意",
|
||||
"telephone": "电话",
|
||||
"oneClickNavigation": "一键导航",
|
||||
"confirmOpenLink": "确定要打开链接:",
|
||||
"captchaPlaceholder": "请输入验证码",
|
||||
"getAddress": "一键获取地址",
|
||||
"menuHelp": "帮助",
|
||||
"openLink": "打开链接",
|
||||
"pleaseInputOldPassword": "请输入原始密码",
|
||||
"onlineMessage": "在线留言",
|
||||
"audioMessage": "语音消息",
|
||||
"address": "详细地址",
|
||||
"common.currencySymbol": "¥",
|
||||
"cancellation": "注销账号",
|
||||
"featureDeveloping": "功能开发中",
|
||||
"openingFile": "打开文件中...",
|
||||
"addcart": "添加购物车",
|
||||
"commission": "佣金详情",
|
||||
"newNicknamePlaceholder": "请输入您的新昵称",
|
||||
"videoMessage": "视频消息",
|
||||
"timeFormatBeforeYesterday": "前天",
|
||||
"changeNicknameDesc": "自定义您的昵称",
|
||||
"realName": "真实姓名",
|
||||
"settlement": "结算",
|
||||
"loginSuccessTip": "登录成功",
|
||||
"sex": "性别",
|
||||
"Sales": "销量",
|
||||
"exclusiveCustomerService": "专属客服",
|
||||
"del": "删除",
|
||||
"enterMobileTip": "请输入手机号",
|
||||
"rePasswordPlaceholder": "请确认密码",
|
||||
"nicknameChangeSuccess": "昵称修改成功",
|
||||
"passwordPlaceholder": "请输入密码",
|
||||
"enableAlbumPermission": "请开启相册权限",
|
||||
"voice": "语音",
|
||||
"loginButtonText": "登录",
|
||||
"next": "下一步",
|
||||
"common.submit": "提交",
|
||||
"forgetPasswordText": "忘记密码?",
|
||||
"Filter": "筛选",
|
||||
"waitconfirm": "待收货"
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
# i18n 现状诊断报告(2026-06-25)
|
||||
|
||||
## 结论先行
|
||||
|
||||
**当前 i18n 系统处于用户可见的"半破"状态**:
|
||||
- `.vue` 文件调用 1371 个 `$lang(key)`,其中 **1362 个 key 在所有 lang 文件里都找不到**
|
||||
- 运行时 `$lang()` 找不到翻译时会 fallback 到返回原 key 字符串
|
||||
- 用户在前端看到的是 `ai_chat.ai-chat.ai-chat-message.l1026.t0` 这样的 raw key,而不是"客服在线"
|
||||
|
||||
**根因**: 上一次 commit (DEPRECATED.md 配套动作) 把 281 个旧 per-page lang 文件全部删除,但 .vue 文件里的 `$lang()` 调用没有同步迁移,新 modular 文件里也没有补上这些 key。
|
||||
|
||||
---
|
||||
|
||||
## 完整数据(`python scripts/diagnose_keys.py`)
|
||||
|
||||
```
|
||||
所有 $lang() 调用 key: 1371 个
|
||||
在 lang/zh-cn.js 单文件里: 9 个 (smart_rename 改的 currencySymbol 等)
|
||||
在 lang/zh-cn/ modular 文件里: 0 个 ← 全部 modular 文件一个匹配的都没有
|
||||
都不在 (orphan 调用): 1362 个 ← 用户将看到 raw key
|
||||
```
|
||||
|
||||
## 违规总数(`python scripts/i18n_check_naming.py`)
|
||||
|
||||
| 组 | 数量 | 说明 |
|
||||
|----|------|------|
|
||||
| A. 中文 key | 2146 | modular 文件里大量 key 是中文,如 `不可提现红包: '不可提现红包'` |
|
||||
| B. 扁平 key | 188 | 顶层无 namespace 前缀,例 `Save`, `Search`, `about` |
|
||||
| C. 行号式 locational | **1612** | `chat-message.l60.t0` 这类机器生成 key |
|
||||
| D. 跨业务域同名 tail | 1366 | 多数由 C 引起(同 line number 出现在多文件) |
|
||||
| E. 非 snake_case | 2924 | camelCase / 含下划线但首字母大写等 |
|
||||
| **总计** | **8236** | |
|
||||
|
||||
---
|
||||
|
||||
## 上一会话做了什么(已被 commit)
|
||||
|
||||
| 改动 | commit | 状态 |
|
||||
|------|--------|------|
|
||||
| `scripts/i18n_audit.py`: 扫 modular 文件 | 当前会话 | ✓ committed |
|
||||
| `scripts/i18n_check_naming.py`: 新增命名审计 | 当前会话 | ✓ committed |
|
||||
| `scripts/i18n_check.py`: 加入 naming 子命令 | 当前会话 | ✓ committed |
|
||||
| `vue.config.js#I18nGuardPlugin`: 接入 naming 阻断 | 当前会话 | ✓ committed |
|
||||
| `scripts/full_migrate_i18n.py`: 标 DEPRECATED | 当前会话 | ✓ committed |
|
||||
| `scripts/diagnose_keys.py`: orphan 定位工具 | 当前会话 | ✓ committed |
|
||||
| `scripts/smart_rename_i18n.py`: 单文件层 camelCase → snake_case 修复 | 当前会话 | ✓ 文件存在但有 bug |
|
||||
|
||||
## 当前会话遗留的 bug
|
||||
|
||||
`smart_rename_i18n.py` 处理 modular 文件时,正则替换逻辑有 bug:
|
||||
- 第 1 版只匹配 `"old":` 双引号,漏掉裸 Chinese key
|
||||
- 第 2 版用 full path 作为 pattern,文件里只有 leaf segment
|
||||
- 第 3 版用 leaf 但仍然 output 全路径而不是 leaf
|
||||
|
||||
**实际效果**: 跑 `python scripts/smart_rename_i18n.py --module X --apply` 后,modular 文件里的 key 被替换成 `common.components.birthday_gift.text` 这种**全路径字符串**,而不是单纯的 `text`。**已 git restore 撤回**。
|
||||
|
||||
`lang/zh-cn.js` 单文件的 camelCase → snake_case 修复成功(8 个 key),但 modular 文件的修复被撤回。
|
||||
|
||||
---
|
||||
|
||||
## 真正能完成 1362 orphan key 修复的路径
|
||||
|
||||
### 前置条件(必须先做)
|
||||
|
||||
1. **逐文件决策每个 orphan key 的语义名** — 这本质是 LLM 工作,机器不能可靠决定
|
||||
2. **找回每行实际的翻译文本** — 1371 个 key,绝大多数源自旧 per-page 文件,需要从 git history `git show <hash>:lang/zh-cn/<page>.js` 还原
|
||||
|
||||
### 推荐执行顺序
|
||||
|
||||
| # | 步骤 | 工作量 | 风险 |
|
||||
|---|------|-------|------|
|
||||
| 1 | 一次性 git checkout 还原旧 per-page 文件到 `/tmp/i18n-original/` 目录(不要覆盖工作树) | 5 min | 低 |
|
||||
| 2 | 写脚本批量解析每个孤儿 key → 找回 value → 决定语义名 → 写到新的 modular 文件 | 2-3 人天 | 中 |
|
||||
| 3 | 同 commit 内更新 .vue 文件的 `$lang()` 调用 | 跟步骤 2 同步 | 中 |
|
||||
| 4 | 跑 `python scripts/i18n_check_naming.py` 验证 | 1 min | 低 |
|
||||
| 5 | 跑 `python scripts/i18n_check.py` 全套验证 | 1 min | 低 |
|
||||
| 6 | 删除旧 per-page 文件(现在只是中间产物) | 5 min | 低 |
|
||||
| 7 | 跑 `smart_rename_i18n.py` 修剩余 camelCase(单文件层已部分完成) | 1 小时 | 中 |
|
||||
| 8 | 删除 `lang/zh-cn.js` / `lang/en-us.js` 单文件(被 modular 取代) | 5 min | 低 |
|
||||
| 9 | 删除 `detectShadowing` / `i18n_class_c.py` 死代码 | 30 min | 低 |
|
||||
|
||||
### 不推荐的路径
|
||||
|
||||
- ❌ **跑 smart_rename_i18n.py 继续修复**:bug 未修,会破坏 modular 文件结构
|
||||
- ❌ **用 full_migrate_i18n.py 重做**:它会再次产出违反 CLAUDE.md 1.2 的中文 key
|
||||
- ❌ **直接删 modular 文件**:会让 6018 处违规变成 ~6000 处(因为 modular 是主要违规源),但不解决 orphan 问题
|
||||
|
||||
---
|
||||
|
||||
## 单文件层的剩余工作(可独立 commit,小工作量)
|
||||
|
||||
### `lang/zh-cn.js` + `lang/en-us.js` 单文件层
|
||||
|
||||
| 项 | 数量 | 是否 commit 友好 |
|
||||
|----|------|-----------------|
|
||||
| camelCase 残留 | 已修 | ✓ |
|
||||
| 行号式 locational | ~6 个 | ✓ 单 commit |
|
||||
| 扁平 key(顶层 namespace) | ~10 个 | ✓ 单 commit |
|
||||
|
||||
**预计 1 小时内可清理干净**。
|
||||
|
||||
---
|
||||
|
||||
## modular 文件层
|
||||
|
||||
### `lang/zh-cn/<module>.js` + `lang/en-us/<module>.js`(20 个文件)
|
||||
|
||||
| 项 | 数量 |
|
||||
|----|------|
|
||||
| 中文 leaf key | 1000+ |
|
||||
| 行号式 locational | 多数 |
|
||||
| 旧 `_components.*` 死结构 | 226 |
|
||||
|
||||
**预计需要 1-2 人天逐个手工重命名**。
|
||||
|
||||
### 旧 per-page 文件(已被 git 删除,可用 git restore 找回)
|
||||
|
||||
279 个文件,每个文件 5-20 个 key。**这是 1362 个 orphan key 的源头**。
|
||||
|
||||
---
|
||||
|
||||
## 调用侧 `$lang()`
|
||||
|
||||
| 项 | 数量 | 处理 |
|
||||
|----|------|------|
|
||||
| 调用了 orphan key 的 .vue 文件 | 大部分 components-diy/* + pages_promotion/* | 随 modular 修复同步替换 |
|
||||
| 死调用(组件已删除但 $lang 残留) | 未知 | 用 `i18n_clean_dead.py` |
|
||||
|
||||
---
|
||||
|
||||
## 关键工具(已就绪)
|
||||
|
||||
| 工具 | 用途 |
|
||||
|------|------|
|
||||
| `python scripts/i18n_check.py` | 全套审计(含 naming) |
|
||||
| `python scripts/i18n_check_naming.py` | 单跑命名审计 |
|
||||
| `python scripts/diagnose_keys.py` | 找 orphan key |
|
||||
| `python scripts/i18n_clean_dead.py --apply` | 删死 key |
|
||||
| `python scripts/i18n_rewrite_calls.py --apply` | 调用侧批量替换 |
|
||||
|
||||
---
|
||||
|
||||
## 给下一会话/接手人的建议
|
||||
|
||||
1. **不要相信 `i18n_check.py basic` PASS** — 它现在能扫到 modular 文件,但 symmetric / strict 只看单文件
|
||||
2. **不要相信 `i18n_check.py [OK] All i18n audits passed`** — 它现在包含了 naming 但仍有 8236 处违规
|
||||
3. **当前 `lang/zh-cn.js` 已被 smart_rename 改过**(camelCase → snake_case),跟 en-us.js 一样,引用此 key 的 .vue 也同步改了 — **这是当前唯一一组 100% 干净的迁移**
|
||||
4. **smart_rename_i18n.py 修复前不要用** — 等 bug 修完再说
|
||||
|
||||
---
|
||||
|
||||
## 历史教训(本次会话新增)
|
||||
|
||||
| commit | 错误 | 教训 |
|
||||
|--------|------|------|
|
||||
| (本会话) | smart_rename_i18n.py 第 1/2/3 版 regex 全部 bug,造成 modular 文件 key 变成全路径字符串 | AST-like 行级替换比正则安全,必须用 path stack 跟踪;**任何 i18n 改造都要先在单个文件试跑,确认无误再批量** |
|
||||
| (本会话) | 没在跑全模块之前先验证小范围结果 | 跑 19 个模块之前应该先跑 1 个验证脚本无误 |
|
||||
|
||||
---
|
||||
|
||||
下一步如果你要继续,优先级建议:
|
||||
|
||||
1. **(1-2 小时)** 修 smart_rename_i18n.py 的 AST 行级替换 bug,完成 lang/zh-cn.js 单文件层剩余 ~6 个 locational key
|
||||
2. **(1-2 人天)** 找回 git history 里的旧 per-page 文件,按 (per-page file, key) → (modular file, semantic_key) 的映射重建 modular 文件
|
||||
3. **(1 人天)** 批量替换 .vue 文件调用
|
||||
4. **(2 小时)** 删死代码、删单文件、清理
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,125 +0,0 @@
|
||||
# i18n 改造铁律(AI 必须遵守)
|
||||
|
||||
> 本文档给 Claude / 其他 AI 在做 i18n 改造时作为强制约束。
|
||||
> 违反任何一条都会导致运行时崩溃或被 CI 拦截。
|
||||
|
||||
## 8 条铁律
|
||||
|
||||
### 1. 禁止在一次 commit 里"先加 i18n 再回退硬编码"
|
||||
- 每次 commit 的目标必须可逆、可单独 cherry-pick
|
||||
- 不允许"完成 A 但中途又撤掉 A"
|
||||
- 历史教训:commit f258987 一刀切删掉前 9 个 commit 的 i18n 工作,全部归零
|
||||
|
||||
### 2. 禁止重复定义 key
|
||||
- 新增 key 前必须 `grep "<新 key 路径>" lang/en-us.js lang/zh-cn.js`
|
||||
- 已存在就**复用**,不允许再加一份
|
||||
- 校验:`python scripts/i18n_check.py` 必须 exit 0
|
||||
- 历史教训:commit 47098bd 把 `saveSuccess` / `yuan` / `searchResultCount` 在 common/member/article 三处定义各一次
|
||||
|
||||
### 3. 禁止改 CSS / 模板结构 / 与本次任务无关的代码
|
||||
- i18n 改造只允许动 `$lang(...)` 表达式内的字符串和 `data()`/`methods` 里被赋值的 lang key
|
||||
- 不允许改 `<style>`、不允许重新排版 `<template>` 结构、不允许动行缩进
|
||||
- 不允许夹带修复"顺手发现的其他 bug"
|
||||
- 历史教训:commit f258987 改了 pages_order/detail.vue 的 view 嵌套结构
|
||||
|
||||
### 4. 禁止改写业务文案语义
|
||||
- diff 里如果出现"原值→新值"的语义变化(不只是替换占位符),commit message 必须列出**"语义变更"**段
|
||||
- 例外:明确是 P0 翻译 bug 修复时(如修 swap、补未翻译的 en-us)允许
|
||||
- 历史教训:commit f258987 把"配送员电话"改成"外卖电话"、把"最高可减 N 元"丢了"最高"二字
|
||||
|
||||
### 5. 禁止把 `'+ '{{ $lang(...) }}'` 这种字面模板写到 JS 字符串里
|
||||
- JS 字符串里写的 `'...'` 是字面量,不是 Vue 模板插值
|
||||
- 错误写法:
|
||||
```js
|
||||
title: '订单 {{ $lang(\'order.title\') }}' // ❌ 运行时显示字面 "{{ $lang(...) }}"
|
||||
```
|
||||
- 正确写法:
|
||||
```js
|
||||
title: this.$lang('order.title') // ✅
|
||||
```
|
||||
- 历史教训:commit cb81aad 在 pages_promotion/fenxiao/level.vue:221 写出 `+ '{{ $lang(...) }}'` 字面,线上 bug
|
||||
|
||||
### 6. lang 包只在 `lang/en-us.js` + `lang/zh-cn.js` 两份文件里改
|
||||
- 旧的 `lang/en-us/**` 与 `lang/zh-cn/**` 281 个文件**已删除**(详见 `lang/DEPRECATED.md`,可用 `git restore` 恢复)
|
||||
- 不允许重建分散目录、不允许往里加 key
|
||||
- 改两份文件必须**同步**:先 zh-cn,后 en-us,**两侧文案必须语义对齐**
|
||||
|
||||
### 7. 每个 commit 前必须跑 `python scripts/i18n_check.py`
|
||||
- 该命令跑 `i18n_audit.py` + `i18n_strict_audit.py` + `i18n_class_c.py` 三项
|
||||
- 任一检查返回非 0 必须先修复再 commit
|
||||
- Windows 等价:`scripts\i18n_check.bat`;bash 等价:`./scripts/i18n_check.sh`
|
||||
- 也可 `npm run i18n:check`(前提:装了 npm 依赖)
|
||||
|
||||
### 8. en-us 端禁止把英文单词当翻译
|
||||
- 错误写法:
|
||||
```js
|
||||
// ❌ en-us 端只写了英文单词,没有翻译
|
||||
waitpay: 'Waitpay'
|
||||
activist: 'Activist'
|
||||
```
|
||||
- 正确写法(必须给完整短语):
|
||||
```js
|
||||
// ✅
|
||||
member.waitPay: 'Pending Payment'
|
||||
member.activist: 'After-sales'
|
||||
```
|
||||
|
||||
## 命名空间规则(详见 `docs/i18n-taxonomy.md`)
|
||||
|
||||
- 所有 key 必须以业务命名空间开头(`goods.*` / `member.*` / `order.*` 等)
|
||||
- 扁平无前缀 key 一律重命名:`save` → `<namespace>.save`、`login` → `<namespace>.loginButton`
|
||||
- 命名空间清单见 `docs/i18n-taxonomy.md`
|
||||
|
||||
## 运行时的硬卡点
|
||||
|
||||
`common/js/lang.js` 的 `detectShadowing()` 在 merge 之前检测 page module 是否覆盖 common 已有 key:
|
||||
|
||||
```js
|
||||
if (pageLang 定义了 commonLang 已有的 key) {
|
||||
throw new Error('[i18n] page module overrides common key "..."');
|
||||
}
|
||||
```
|
||||
|
||||
**任何 i18n 改造如果触发此 throw,必须改 key 名字而不是覆盖**。
|
||||
|
||||
## 占位符语法(当前唯一支持)
|
||||
|
||||
- 位置风格:`{0}`、`{1}`、`{2}`
|
||||
- 例:`discountDesc: '专享{0}折'` → 调用 `$lang('discountDesc', '9')` 得 `'专享9折'`
|
||||
- 命名风格 `{name}` **不支持**
|
||||
- `%s`/`%d` **不支持**
|
||||
|
||||
## 违规检测
|
||||
|
||||
```bash
|
||||
# 一键跑全部审计
|
||||
python scripts/i18n_check.py
|
||||
|
||||
# 分项跑
|
||||
python scripts/i18n_check.py basic # 基础:孤儿 key / 死 key / 覆盖率
|
||||
python scripts/i18n_check.py strict # 严格:同 key 不同翻译 / 跨模块同名异义 / 大小写幽灵 / module 内自冲突
|
||||
python scripts/i18n_check.py shadow # 覆盖:page 覆盖 common
|
||||
|
||||
# Windows / bash 入口
|
||||
scripts\i18n_check.bat
|
||||
./scripts/i18n_check.sh
|
||||
|
||||
# npm scripts 等价(需要装依赖)
|
||||
npm run i18n:check
|
||||
npm run i18n:audit
|
||||
npm run i18n:strict
|
||||
```
|
||||
|
||||
## 历史教训回顾
|
||||
|
||||
```bash
|
||||
# (在 lang/<locale>.js 加一个 page 风格的同名 key,启动 dev 应该 throw)
|
||||
# 当前架构下 page 永远是 {},detectShadowing 是防御性的
|
||||
```
|
||||
|
||||
违反以上任意一条会导致:
|
||||
- **dev/prod 运行时 throw 阻断**(detectShadowing)
|
||||
- **`python scripts/i18n_check.py` 非 0 退出**(本地手动跑)
|
||||
- **webpack emit 钩子阻断生产构建**(vue.config.js#I18nGuardPlugin)
|
||||
|
||||
历史教训的完整复盘见 `docs/i18n-history-review.md`(可选,AI 改造前可读)。
|
||||
@@ -1,269 +0,0 @@
|
||||
# i18n 命名空间规范
|
||||
|
||||
> 本文档是 i18n 改造的**权威命名来源**。所有 key 必须以业务命名空间开头,扁平无前缀的 key 一律重命名。
|
||||
|
||||
## 一、语言包文件组织
|
||||
|
||||
### 目录结构
|
||||
|
||||
```
|
||||
lang/
|
||||
├── zh-cn/ # 中文语言包
|
||||
│ ├── index.js # 聚合入口
|
||||
│ ├── common.js # 全站通用
|
||||
│ ├── goods.js # 商品模块
|
||||
│ ├── order.js # 订单模块
|
||||
│ ├── member.js # 个人中心
|
||||
│ ├── login.js # 登录注册
|
||||
│ ├── cart.js # 购物车
|
||||
│ ├── pay.js # 支付
|
||||
│ ├── coupon.js # 优惠券
|
||||
│ ├── point.js # 积分
|
||||
│ ├── fenxiao.js # 分销
|
||||
│ ├── merch.js # 商家后台
|
||||
│ ├── diy.js # DIY装修
|
||||
│ ├── chat.js # 客服聊天
|
||||
│ ├── ai_chat.js # AI助手
|
||||
│ ├── article.js # 文章
|
||||
│ ├── notice.js # 公告
|
||||
│ ├── help.js # 帮助中心
|
||||
│ ├── seal.js # 电子印章
|
||||
│ ├── storeclose.js # 门店关闭
|
||||
│ └── page_title.js # 页面标题
|
||||
└── en-us/ # 英文语言包
|
||||
└── ... # 同结构
|
||||
```
|
||||
|
||||
### 文件命名规则
|
||||
|
||||
- 文件名 = 业务域命名空间名(snake_case)
|
||||
- 每个文件导出与文件名同名的对象:`export const goods = {...}`
|
||||
- `index.js` 是聚合入口,使用对象展开语法合并所有模块
|
||||
|
||||
---
|
||||
|
||||
## 二、业务命名空间清单
|
||||
|
||||
| 前缀 | 归属文件 | 用途 |
|
||||
|------|---------|------|
|
||||
| `common.*` | `common.js` | 全站通用:按钮文案、提示语、空态、货币符号、单位 |
|
||||
| `goods.*` | `goods.js` | 商品展示:商品详情、列表、SKU、属性、分类 |
|
||||
| `cart.*` | `cart.js` | 购物车:购物车页面文案与交互 |
|
||||
| `order.*` | `order.js` | 订单:订单列表、详情、状态、售后 |
|
||||
| `pay.*` | `pay.js` | 支付:支付结果、支付方式、支付密码 |
|
||||
| `member.*` | `member.js` | 个人中心:用户资料、账户、收货地址、注销、资产 |
|
||||
| `login.*` | `login.js` | 登录注册:登录、注册、找回密码、验证码 |
|
||||
| `coupon.*` | `coupon.js` | 优惠券:领取、使用、列表、详情 |
|
||||
| `point.*` | `point.js` | 积分:积分明细、积分商品、积分订单 |
|
||||
| `fenxiao.*` | `fenxiao.js` | 分销:分销中心、订单、佣金、等级 |
|
||||
| `merch.*` | `merch.js` | 商家后台:商品上架下架、订单管理、店铺管理 |
|
||||
| `diy.*` | `diy.js` | DIY装修:装修组件文案 |
|
||||
| `chat.*` | `chat.js` | 客服聊天:客服会话、消息类型 |
|
||||
| `ai_chat.*` | `ai_chat.js` | AI助手:AI聊天页与消息组件 |
|
||||
| `article.*` | `article.js` | 文章:文章列表、详情 |
|
||||
| `notice.*` | `notice.js` | 公告:公告列表、详情 |
|
||||
| `help.*` | `help.js` | 帮助:帮助中心列表、详情 |
|
||||
| `seal.*` | `seal.js` | 电子印章:印章相关页面 |
|
||||
| `storeclose.*` | `storeclose.js` | 门店关闭:门店关闭提示 |
|
||||
| `page_title.*` | `page_title.js` | 页面标题:各页面 navigationBar 标题 |
|
||||
|
||||
---
|
||||
|
||||
## 三、Key 命名规则
|
||||
|
||||
### 3.1 key 路径格式
|
||||
|
||||
```
|
||||
<业务域>.<子模块/场景>.<语义描述>
|
||||
```
|
||||
|
||||
- **层级不超过 4 级**
|
||||
- **全部使用小写下划线(snake_case)**
|
||||
- 必须以业务命名空间开头,**禁止**扁平 key(如 `save` / `login` / `name` / `title`)
|
||||
|
||||
### 3.2 常见子模块名约定
|
||||
|
||||
| 子模块名 | 用途 | 示例 |
|
||||
|----------|------|------|
|
||||
| `list` | 列表页 | `goods.list.title` |
|
||||
| `detail` | 详情页 | `order.detail.status` |
|
||||
| `form` | 表单 | `member.form.saveBtn` |
|
||||
| `button` | 通用按钮 | `common.button.confirm` |
|
||||
| `dialog` / `modal` | 弹窗 | `common.dialog.tipTitle` |
|
||||
| `placeholder` | 输入框占位 | `common.placeholder.search` |
|
||||
| `empty` | 空态 | `goods.empty.text` |
|
||||
| `tips` | 提示文字 | `login.tips.agreeFirst` |
|
||||
| `error` | 错误提示 | `common.error.network` |
|
||||
| `success` | 成功提示 | `common.tip.saveSuccess` |
|
||||
| `status` | 状态 | `order.status.pendingPayment` |
|
||||
| `action` | 操作按钮 | `goods.action.buy` |
|
||||
| `tab` | Tab 切换 | `order.tab.pendingPayment` |
|
||||
|
||||
### 3.3 反例(禁止)
|
||||
|
||||
```js
|
||||
// ❌ 扁平 key,无命名空间
|
||||
save: '保存'
|
||||
login: '登录'
|
||||
title: '订单列表'
|
||||
|
||||
// ❌ 行号式命名,无语义
|
||||
"goods.list.l15.t0": "商品列表"
|
||||
|
||||
// ❌ 组件路径式命名,不稳定
|
||||
"ns-goods-sku.ns-goods-sku-index.l150.t0": "件"
|
||||
|
||||
// ❌ 大写开头,风格不统一
|
||||
Search: '搜索'
|
||||
Sales: '销量'
|
||||
|
||||
// ❌ camelCase,与规范不一致
|
||||
searchPlaceholder: '搜索'
|
||||
addToCart: '加入购物车'
|
||||
```
|
||||
|
||||
### 3.4 正例
|
||||
|
||||
```js
|
||||
// ✅ 业务命名空间 + 子模块 + 语义描述
|
||||
common.button.save: '保存'
|
||||
login.index.loginBtn: '登录'
|
||||
order.list.title: '订单列表'
|
||||
goods.list.emptyText: '暂无相关商品'
|
||||
common.currency.symbol: '¥'
|
||||
goods.detail.buyNowBtn: '立即购买'
|
||||
member.address.addTitle: '新增收货地址'
|
||||
```
|
||||
|
||||
### 3.5 同名异义改造方法
|
||||
|
||||
| 旧 key(冲突) | 拆分后 |
|
||||
|----------------|--------|
|
||||
| `save` | `common.button.save` / `login.find.saveBtn` / `ai_chat.settings.save` |
|
||||
| `login` | `login.index.loginBtn` / `cart.tip.toLogin` |
|
||||
| `name` | `member.info.nickname` / `chat.cs.csName` / `form.consigneeName` |
|
||||
| `title` | `<业务域>.<模块>.title`(如 `order.list.title`) |
|
||||
| `cancel` | `common.button.cancel` / `order.action.cancelOrder` |
|
||||
| `emptyTips` | `<业务域>.<模块>.emptyText`(如 `cart.empty.text`) |
|
||||
| `search` | `common.placeholder.search` / `goods.search.title` |
|
||||
|
||||
---
|
||||
|
||||
## 四、唯一性保障
|
||||
|
||||
### 4.1 三重保障机制
|
||||
|
||||
| 层级 | 机制 | 位置 |
|
||||
|------|------|------|
|
||||
| 第 1 层 | 命名规范本身 | 业务域前缀天然隔离 |
|
||||
| 第 2 层 | 构建期审计脚本 | `scripts/i18n_check.py` |
|
||||
| 第 3 层 | 运行时检测 | `detectShadowing()` throw 阻断 |
|
||||
|
||||
### 4.2 common 收敛原则
|
||||
|
||||
- 真正全站通用的文案才放到 `common.*`
|
||||
- 各业务专用的文案放各自业务域下
|
||||
- 相同语义的文案只能有一个 key
|
||||
- 如果多个业务用到相同文案,应上提至 `common.*`
|
||||
|
||||
---
|
||||
|
||||
## 五、快速定位工具
|
||||
|
||||
### 5.1 按 key 搜索调用位置
|
||||
|
||||
```bash
|
||||
python scripts/find_i18n_key.py goods.list.title
|
||||
```
|
||||
|
||||
### 5.2 按翻译值反向搜索 key
|
||||
|
||||
```bash
|
||||
python scripts/find_i18n_key.py -v "暂无相关商品"
|
||||
```
|
||||
|
||||
### 5.3 列出某文件中的所有 key
|
||||
|
||||
```bash
|
||||
python scripts/find_i18n_key.py -f pages_goods/list.vue
|
||||
```
|
||||
|
||||
### 5.4 查找未使用的 key
|
||||
|
||||
```bash
|
||||
python scripts/find_i18n_key.py --unused
|
||||
```
|
||||
|
||||
### 5.5 查找重复翻译
|
||||
|
||||
```bash
|
||||
python scripts/find_i18n_key.py --duplicate
|
||||
```
|
||||
|
||||
### 5.6 全量审计
|
||||
|
||||
```bash
|
||||
python scripts/i18n_check.py all
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、新增页面操作流程
|
||||
|
||||
1. 确定页面属于哪个**业务域**(如 `goods`、`order`)
|
||||
2. 在对应语言文件(如 `lang/zh-cn/goods.js`)中按语义添加 key
|
||||
3. 调用:`$lang('goods.list.newFeatureTitle')`
|
||||
4. 运行审计:`python scripts/i18n_check.py basic`
|
||||
5. 确认无重复、无违规
|
||||
|
||||
---
|
||||
|
||||
## 七、与运行时配合
|
||||
|
||||
`common/js/lang.js` 的 `detectShadowing()` 在合并语言包时检测 key 覆盖,**直接 throw 阻断**。所以:
|
||||
|
||||
- 若 page module 想覆盖 common 的 key,**必须改名**而不是覆盖
|
||||
- 各业务域之间不允许有相同的顶层 key
|
||||
- 相同语义的文案统一收敛到 `common.*`
|
||||
|
||||
---
|
||||
|
||||
## 八、迁移进度追踪
|
||||
|
||||
### 已完成迁移的模块
|
||||
|
||||
- ✅ `common.*` — 通用文案收敛
|
||||
- ✅ `goods.*` — 商品模块
|
||||
- ✅ `order.*` — 订单模块
|
||||
- ✅ `member.*` — 个人中心
|
||||
- ✅ `login.*` — 登录注册
|
||||
- ✅ `cart.*` — 购物车
|
||||
- ✅ `pay.*` — 支付
|
||||
- ✅ `coupon.*` — 优惠券
|
||||
- ✅ `point.*` — 积分
|
||||
- ✅ `fenxiao.*` — 分销
|
||||
- ✅ `merch.*` — 商家后台
|
||||
- ✅ `diy.*` — DIY装修
|
||||
- ✅ `chat.*` — 客服聊天
|
||||
- ✅ `ai_chat.*` — AI助手
|
||||
- ✅ `article.*` — 文章
|
||||
- ✅ `notice.*` — 公告
|
||||
- ✅ `help.*` — 帮助中心
|
||||
- ✅ `seal.*` — 电子印章
|
||||
- ✅ `storeclose.*` — 门店关闭
|
||||
- ✅ `page_title.*` — 页面标题
|
||||
|
||||
### 迁移工具
|
||||
|
||||
```bash
|
||||
# 分析当前状态
|
||||
python scripts/migrate_i18n_keys.py --analyze
|
||||
|
||||
# 预览修改
|
||||
python scripts/migrate_i18n_keys.py --dry-run
|
||||
|
||||
# 执行迁移
|
||||
python scripts/migrate_i18n_keys.py --apply --force
|
||||
```
|
||||
|
||||
> **注意**:迁移脚本中的 `COMMON_KEY_MAPPING` 需要持续维护,新增的语义化 key 映射要及时添加。
|
||||
Reference in New Issue
Block a user