Files
lucky_shop/docs/i18n-audit-report.md
ZF sun 55a5a68517 refactor: 统一多语言key的组件命名格式为短横线分隔
根据i18n规范,将所有组件相关的多语言key从驼峰式改为短横线分隔格式,同步更新文档中的示例说明。
2026-06-30 10:28:36 +08:00

15 KiB
Raw Blame History

国际化(i18n)全量审计报告

审计范围:z:\D\projects\shop-projects\frontend 下所有 .vue / .js 文件(排除 node_modules、uni_modules、unpackage、docs、scripts 等) 审计时间:2026-06-29 当前静态校验:node scripts/i18n-check.js 通过(zh-cn / en-us key 完全一致) 修复状态:P0 / P1 / P2(兜底 + 验证)已修复并验证 ✅

一、核心结论

项目已大规模使用 $lang(),但仍存在 三类问题:

  1. Resolver/代码不匹配导致的 raw key(用户可见):组件/页面调用的 key 与语言包实际结构不一致,英文环境下会直接显示 key 名。
  2. 硬编码中文文本(英文环境下仍显示中文):.vue 模板和 .js 脚本中存在未替换为 $lang() 的静态中文。
  3. 动态 key 无法静态校验:9 处依赖运行时数据拼接 key,需人工确认对应 key 是否完整。

二、P0 - 会显示 raw key 的调用错误(已修复 ✅)

修复文件:

  • components-diy/diy-article.vue
  • pages_promotion/point/goods_list.vue
  • pages_tool/member/cancelstatus.vue
  • pages_tool/member/card_buy.vue

验证:自定义脚本验证所有修改后的 key 均可解析,npm run i18n:check 通过。

1. components-diy/diy-article.vue

行 错误调用 语言包实际 key 说明
93 $lang('components-diy.diy-article.viewMore') components-diy.diy-article.viewMore 组件名大小写不一致,normalizeSharedLangPack 将 diy-article 转为 diyArticle
98 $lang('components-diy.diy-article.noArticles') components-diy.diy-article.noArticles 同上

修复建议:统一改为 $lang('components-diy.diy-article.viewMore') / $lang('components-diy.diy-article.noArticles')。

2. pages_promotion/point/goods_list.vue

行 错误调用 语言包实际 key 说明
9, 17, 20, 29, 38, 62, 75, 86, 94, 98, 101, 104, 109, 112, 123, 124, 286, 292, 299, 305 $lang('goods_list.xxx') 扁平 key(如 searchPlaceholder) normalizePageLangPack 将文件名 goods_list camelCase 为 goodsList,导致 goods_list.xxx 无法解析

修复建议:页面内所有 $lang('goods_list.xxx') 改为 $lang('xxx')(该页面语言包为扁平结构),或改为 $lang('goodsList.xxx')。

3. pages_tool/member/cancelstatus.vue

行 错误调用 语言包实际 key 说明
8, 9, 16, 17, 26, 27, 32, 33, 84, 85 $lang('member.cancelStatus.xxx') member.cancelstatus.xxx(小写 s) 文件名 cancelstatus camelCase 后为 cancelstatus,页面调用为 cancelStatus

修复建议:统一改为 $lang('member.cancelstatus.xxx')。

4. pages_tool/member/card_buy.vue

行 错误调用 语言包实际 key
353 $lang('common.tip') customerService.tip(位于 common.customerService.tip)

修复建议:改为 $lang('customerService.tip'),或根据业务语义使用其他 key。


三、P1 - 模板中硬编码中文(已修复 ✅)

共 59 处硬编码中文已替换为 $lang() 调用,并补充了对应的中/英文语言包。

  • 验证:自定义 P1 验证脚本 verify_p1_keys.js 全部通过。
  • 静态校验:npm run i18n:check 通过(zh-cn / en-us key 完全一致)。
  • 语法检查:相关 .js 文件均通过 node --check。

原始 59 处按模块归类如下(实际落地 key 与最初建议略有差异,详见文末“命名空间修正记录”):

3.1 公共组件(components/)

文件 行 中文文本 建议 key
components/chat-message/chat-message.vue 60 客服不在线 components.chat-message.customerOffline
components/chat-message/chat-message.vue 63 客服在线 components.chat-message.customerOnline
components/pick-regions/pick-regions.vue 17 取消 components.pick-regions.cancel
components/pick-regions/pick-regions.vue 18 完成 components.pick-regions.confirm
components/ns-goods-sku/ns-goods-sku.vue 22 {point}积分 components.ns-goods-sku.pointSuffix(使用命名参数)
components/ns-chat/ns-chat-receiveGoods.vue 8 库存: components.ns-chat-receiveGoods.stockPrefix
components/ns-chat/ns-chat-receiveGoods.vue 9 销量: components.ns-chat-receiveGoods.salesPrefix
components/ns-chat/ns-chat-receiveGoods.vue 17 查看商品 components.ns-chat-receiveGoods.viewGoods
components/ns-chat/ns-chat-goods.vue 12 已发送 components.ns-chat-goods.sent
components/ns-chat/ns-chat-goods.vue 25 发送 components.ns-chat-goods.send
components/ns-video-player-popup/ns-video-player-popup.vue 17 视频地址不存在 components.ns-video-player-popup.videoUrlNotExist

3.2 装修组件(components-diy/)

文件 行 中文文本 建议 key
components-diy/diy-search.vue 31 搜索 components-diy.diy-search.searchBtn
components-diy/diy-map.vue 16 一键导航 components-diy.diy-map.navigate
components-diy/diy-kefu.vue 17 立即添加 components-diy.diy-kefu.addNow
components-diy/diy-channel-video.vue 20, 32, 40 {count}次观看 components-diy.diy-channel-video.viewCountSuffix(使用命名参数)
components-diy/diy-live.vue 29 主播: components-diy.diy-live.anchorPrefix
components-diy/diy-live.vue 33 直播商品: components-diy.diy-live.goodsPrefix
components-diy/diy-listmenu.vue 15 查看 components-diy.diy-listmenu.view
components-diy/diy-text.vue 211 专区 components-diy.diy-text.zone
components-diy/diy-goods-recommend.vue 56 售 / 件 components-diy.diy-goods-recommend.soldPrefix / unit.piece
components-diy/diy-notes.vue 42 阅读 components-diy.diy-notes.readPrefix

3.3 页面级(pages_tool/、pages_promotion/)

文件 行 中文文本 建议 key
pages_tool/login/login.vue 396 请输入手机号 login.login.mobileRequired
pages_tool/login/login.vue 400 请输入正确的手机号 login.login.mobileFormatError
pages_tool/login/login.vue 419 {seconds}s后可重新获取 login.login.resendAfterSeconds
pages_tool/login/login.vue 449 获取动态码 login.login.getDynacode
pages_tool/member/index.vue 61 我知道了 member.index.iKnow
pages_tool/index/diy.vue 46 我知道了 index.index.iKnow
pages_tool/member/cancelsuccess.vue 7 您已成功注销账号 member.cancelsuccess.title
pages_tool/member/cancelsuccess.vue 8 待下次与您更好的相遇... member.cancelsuccess.desc
pages_tool/member/cancelsuccess.vue 9 完成 member.cancelsuccess.done
pages_tool/member/cancelrefuse.vue 5 您的申请已拒绝 member.cancelrefuse.title
pages_tool/member/cancelrefuse.vue 6 拒绝理由: member.cancelrefuse.reasonPrefix
pages_tool/member/cancelrefuse.vue 8 返回 member.cancelrefuse.back
pages_tool/member/cancelrefuse.vue 9 重新申请 member.cancelrefuse.reapply
pages_tool/member/public/js/member-public.js 63 风险提示 member.public.riskWarningTitle
pages_tool/member/public/js/member-public.js 64 确定要注销当前账号吗? member.public.cancelAccountConfirm
pages_tool/goods/not_exist.vue 5 您查看的商品不存在... goods.notExist.message
pages_tool/file-preview/file-preview.vue 15, 21 文件地址不存在 filePreview.fileUrlNotExist
pages_tool/file-preview/file-preview.vue 27 视频地址不存在 filePreview.videoUrlNotExist
pages_tool/file-preview/file-preview.vue 32 不支持的文件类型 filePreview.unsupportedFileType
pages_tool/agreement/contenr.vue 11 暂无内容 agreement.noContent
pages_tool/agreement/contenr.vue 12 该协议内容暂未设置 agreement.noContentDesc
pages_tool/agreement/contenr.vue 13 重新加载 agreement.reload
pages_tool/notice/list.vue 10 置顶 notice.list.topTag
pages_tool/notice/list.vue 18 暂无公告 notice.list.noNotice
pages_tool/notice/detail.vue 5 发表时间: notice.detail.publishTimePrefix
pages_tool/help/list.vue 9 暂无帮助信息 help.list.noHelp
pages_tool/help/detail.vue 6 发表时间: help.detail.publishTimePrefix
pages_tool/goods/brand.vue 14 暂无更多品牌,去首页看看吧 goods.brand.noMoreBrand
pages_tool/recharge/order_list.vue 16 充值成功 recharge.orderList.rechargeSuccess
pages_tool/recharge/order_list.vue 34 暂无充值记录 recharge.orderList.noRecord
pages_tool/seal/structure.vue 6 当前选择: / 请选择 seal.structure.currentChoicePrefix / seal.structure.pleaseSelect
pages_tool/seal/structure.vue 12 选型结果: seal.structure.resultPrefix
pages_tool/seal/structure.vue 23 结果文件 seal.structure.resultFile
pages_promotion/fenxiao/bill.vue 11 账单编号: fenxiao.bill.billNoPrefix
pages_promotion/fenxiao/bill.vue 19 暂无账单信息 fenxiao.bill.noBillData

3.4 公共 JS

文件 行 中文文本 建议 key
common/js/auth.js 36, 77 小程序配置错误 common.auth.miniProgramConfigError
common/js/map/openMap.js 11 打开地图失败,请稍后重试 common.map.openMapFailed
common/js/goods_detail_base.js 144, 202 件 unit.piece(common.js 中位于顶层 unit.piece)
pages_order/public/js/refundMethod.js 10 撤销之后本次申请将会关闭... order.refund.cancelRefundContent
pages_order/public/js/refundMethod.js 11 暂不撤销 order.refund.cancelRefundCancelText
pages_goods/public/js/list.js 40 购买 goods.list.buyText

3.5 文档示例(可忽略)

文件 行 中文文本
docs/example/wechat-channel-demo.vue 4-23 微信视频号集成示例、单个视频号、视频号列表、使用说明等

该文件为文档示例,是否国际化可单独评估。


四、P2 - 动态 key 调用(已兜底 + 验证 ✅)

以下 8 处 $lang() 使用运行时变量拼接 key,无法被 scripts/i18n-check.js 静态覆盖。已采取以下措施:

  1. 运行时兜底:对可获取默认文案的场景,为 $lang() 增加第二参数 fallback,避免 key 缺失时暴露 raw key。
  2. 专项验证脚本:新增 scripts/verify-p2-keys.js,枚举所有已知取值并模拟 resolver 校验 zh-cn / en-us 解析结果。
  3. DIY 数据侧:components-diy/diy-tab.vue 的 title 来自运行时配置,已在组件内增加 this.$lang(title, title) 兜底。
文件 行 调用片段 处理
components/payment/payment.vue 27 $lang('components.payment.' + item.type) 增加 item.name fallback
components-diy/diy-tab.vue 907 this.$lang ? this.$lang(title) : title 改为 this.$lang(title, title)
pages_order/list.vue 15 $lang('status.' + statusItem.status) 增加 statusItem.name fallback
pages_promotion/fenxiao/order.vue 6 $lang(item.nameKey) 取值本地枚举,已在 verify-p2-keys.js 验证
pages_promotion/fenxiao/team.vue 7 $lang(item.nameKey) 取值本地枚举,已在 verify-p2-keys.js 验证
pages_promotion/point/order_list.vue 8 $lang('point.orderList.' + statusItem.nameKey) 取值本地枚举,已在 verify-p2-keys.js 验证
pages_tool/goods/evaluate.vue 6 $lang(item.langKey) 取值本地枚举,已在 verify-p2-keys.js 验证
pages_tool/pay/cashier.vue 16 $lang('pay.cashier.' + item.type) 增加 item.name fallback

验证结果:node scripts/verify-p2-keys.js 全部 ✅;npm run i18n:check 通过。


五、修复优先级建议

  1. P0(已修复):4 个文件共 30+ 处错误调用已在英文环境下直接显示 raw key,已全部修正。
  2. P1(已修复):59 处硬编码中文已按模块补充语言包并替换为 $lang()。
  3. P2(已兜底 + 验证):8 处动态 key 已增加运行时 fallback 并建立枚举值验证脚本。

六、命名空间规范提醒

根据项目约定和 common/js/lang.js 的解析逻辑:

  • 页面语言包:优先使用扁平 key(如 $lang('searchPlaceholder')),必要时使用 camelCase 路径(如 $lang('member.cancelstatus.step1Name'))。
  • 共享组件语言包:统一按 components.{ComponentCamelCase}.key 或 components-diy.{ComponentCamelCase}.key 调用。
  • 公共 JS 文案:统一放入 lang/zh-cn/common.js / lang/en-us/common.js,使用 common.* 命名空间。
  • 新增 key 后务必在 lang/zh-cn/ 和 lang/en-us/ 同步,并运行 npm run i18n:check。

七、P1 实施过程中的命名空间修正记录

在按审计建议替换 P1 硬编码中文时,发现若干组件/页面实际调用的 key 与语言包结构不匹配,已一并修正:

文件 问题 修正
components-diy/diy-listmenu.vue 调用 components-diy.diy-listmenu.view,但 normalizeSharedLangPack 生成的命名空间为 diyListmenu(小写 m) 改为 components-diy.diy-listmenu.view
lang/zh-cn/components/ns-goods-sku.js、lang/en-us/components/ns-goods-sku.js 语言包使用 components.ns-goods-sku.pointSuffix,与文件路径 components/ns-goods-sku 生成的 components.nsGoodsSku 不一致 改为 components.ns-goods-sku.pointSuffix
lang/zh-cn/notice/list.js、lang/en-us/notice/list.js 包内存在嵌套 notice: { ... },导致完整命名空间 notice.list.topTag 无法解析 拍平为扁平结构
lang/zh-cn/notice/detail.js、lang/en-us/notice/detail.js 同上,嵌套 notice 对象 拍平为扁平结构
lang/zh-cn/help/list.js、lang/en-us/help/list.js 同上,嵌套 help 对象 拍平为扁平结构
lang/zh-cn/help/detail.js、lang/en-us/help/detail.js 同上,嵌套 help 对象 拍平为扁平结构
lang/zh-cn/login/login.js、lang/en-us/login/login.js 新增 key 放在 login: { ... } 下,导致 login.login.mobileRequired 解析失败 拍平为扁平结构
lang/zh-cn/member/public.js、lang/en-us/member/public.js 包内为 { public: { ... } },但源码调用 member.public.riskWarningTitle 包装为 { member: { public: { ... } } }
common/js/goods_detail_base.js、components-diy/diy-goods-recommend.vue 调用 common.unit.piece,但 common.js 中该 key 位于顶层 unit.piece 改为 unit.piece
common/js/lang.js 新增组件语言包未注入共享上下文 补充 SHARED_LANG_PACKS 列表

说明:components/ns-goods-sku/*.vue 中大量使用了 goods.detail.* 形式的 key。这些 key 实际定义在页面语言包 lang/zh-cn/goods/detail.js 中,运行时通过 tryResolveQualifiedPageField 动态加载并解析;P1 验证脚本已按此逻辑加载 goods/detail 包进行校验,确认全部可解析。