fix: 修复多页面国际化文案调用路径错误

将多处误用的 common.前缀国际化调用改为顶层路径,同时新增语言调用错误的回归测试用例,防止后续再次出现类似的命名空间误用问题
This commit is contained in:
2026-07-23 10:37:22 +08:00
parent 94142268a0
commit 70a01bfd2b
4 changed files with 63 additions and 3 deletions

View File

@@ -308,7 +308,7 @@ export default {
success: function(res) {
if (res.code === 0) {
uni.showToast({
title: self.$lang('common.submitSuccess'),
title: self.$lang('submitSuccess'),
icon: 'success'
});
// 重置表单

View File

@@ -69,7 +69,7 @@
mounted() {
// 初始化 i18n 默认文案,实际展示以服务端配置 config.title / config.text 为准
if (!this.config.title) this.config.title = this.$lang('common.goodsRecommendTitle');
if (!this.config.text) this.config.text = this.$lang('common.buyNow');
if (!this.config.text) this.config.text = this.$lang('buyNow');
if (this.auto) {
this.getLikeList();
}

View File

@@ -67,7 +67,7 @@ export default {
},
onLoad(options) {
this.config.text = this.$lang('goods.list.buyText') || this.$lang('common.buyNow');
this.config.text = this.$lang('goods.list.buyText') || this.$lang('buyNow');
this.$api.sendRequest({
url: '/api/lucky/status',

View File

@@ -387,6 +387,66 @@ test('嵌套命名空间: common 顶层键 vs common.common 子对象双层结
assert.strictEqual(fakeLang(en, 'common.goodsRecommendTitle'), 'Guess you like');
});
test('嵌套命名空间: 双重 common.<key> 误用回归保护(扫所有顶层 key)', () => {
// 防御:common.js 的 lang 对象整体即 common namespace,
// 顶层 key 不应再带 'common.' 前缀,否则会找不到
// 这个测试是 2026-07-23 真实 console 报错后追加的回归保护
//
// 策略:自动枚举 zh/en 顶层所有 key,
// 对每个 key,验证 fakeLang(zh, 'common.' + key) === ''
// —— 这样不管以后谁写出 common.<topLevelKey>,测试都会自动 fail
// 收集两包顶层 key 的并集(只要 zh 或 en 一方有就检查)
const topKeys = new Set();
for (const k of Object.keys(zh)) {
if (typeof zh[k] === 'string') topKeys.add(k);
}
for (const k of Object.keys(en)) {
if (typeof en[k] === 'string') topKeys.add(k);
}
const mistakes = [];
for (const k of topKeys) {
// 注意:跳过常见会被合法命中的 key(common 里的合法子对象)
// 这些 key 在 zh.common / en.common 子对象里也存在(双 common 合法)
if (zh.common && typeof zh.common[k] === 'string') continue;
if (en.common && typeof en.common[k] === 'string') continue;
const zhHit = fakeLang(zh, 'common.' + k);
const enHit = fakeLang(en, 'common.' + k);
if (zhHit !== '' || enHit !== '') {
mistakes.push({ k, zhHit, enHit });
}
}
if (mistakes.length > 0) {
console.error('以下 key 在顶层,但用 common.<key> 调用居然命中了:');
for (const m of mistakes) {
console.error(` common.${m.k} → zh="${m.zhHit}" en="${m.enHit}"`);
}
}
assert.strictEqual(mistakes.length, 0,
'不应有任何 common.<key> 调用能命中顶层 key(应该是空串)');
});
test('嵌套命名空间: 双重 common.buyNow 是不存在的(防止误用回归)', () => {
// 历史 bug:common.buyNow 被当作 fallback,实际 key 是顶层 buyNow
assert.strictEqual(
fakeLang(zh, 'common.buyNow'),
'',
'common.buyNow 双前缀不存在,真实调用必须用 $lang("buyNow")'
);
assert.strictEqual(
fakeLang(en, 'common.buyNow'),
'',
'en-us 同理,common.buyNow 双前缀不存在'
);
// 同时验证顶层 buyNow 存在
assert.strictEqual(fakeLang(zh, 'buyNow'), '立即购买');
assert.strictEqual(fakeLang(en, 'buyNow'), 'Buy Now');
});
test('嵌套命名空间: 4 层路径 diy.networkErrorTitle', () => {
assert.strictEqual(fakeLang(zh, 'diy.networkErrorTitle'), '提示');
assert.strictEqual(fakeLang(en, 'diy.networkErrorTitle'), 'Notice');