diff --git a/App.vue b/App.vue index 95ae2ba..b960eef 100644 --- a/App.vue +++ b/App.vue @@ -68,8 +68,34 @@ // A) 主题第一次 apply — 走 preset,失败静默走默认 this.$store.dispatch('applyThemeWithRemote', presetName) .catch(e => console.warn('[theme] pre-apply fail', e)), - // B) Lang boot - langBoot.catch(e => console.warn('[i18n] boot fail', e)), + // B) Lang boot — 直接根据返回值判断 toast,不走 lang:fallback 事件 + // 为什么不走事件: + // 1) lang:fallback 受 setRemoteStatus 内部去重影响(fail→fail 不 emit),不可靠 + // 2) 监听器注册时机晚于 boot 完成,首次失败收不到 + // 3) boot() 返回值已经包含了 status/reason,直接判断更清晰 + // 触发条件: + // - status === 'fail': 远端拉取失败(包含"无缓存兜底"和"有缓存兜底"两种) + // - reason !== 'unknown': 排除业务主动设置的未知错误 + // 防刷: 进程内全局标志,只弹一次 + // 延迟弹出: uni.showToast 会覆盖当前 toast,1500ms ≈ 默认 toast duration, + // 等启动期其他 toast / 模态弹窗先消失再弹,降低被覆盖风险 + langBoot.then((res) => { + if (res && res.status === 'fail' && res.reason && res.reason !== 'unknown') { + if (globalThis.__i18nFallbackToastShown) return; + globalThis.__i18nFallbackToastShown = true; + setTimeout(() => { + try { + uni.showToast({ + title: `Failed to load i18n. ${res.reason} Please check your network and try again.`, + icon: 'none', + duration: 10000, + }); + } catch (e) {} + }, 3000); + } + }, (e) => { + console.warn('[i18n] boot fail', e); + }), // C) ThemeOverride boot(brand/light/dark 三桶,bootTimeout=2000ms) ThemeOverride.boot().catch(e => console.warn('[theme] boot fail', e)), ]); @@ -115,27 +141,8 @@ uni.$on && uni.$on('uniacid:changed', () => { try { ThemeOverride.onUniacidChange(); } catch (e) {} }); - // 监听国际化远端拉取失败: 给用户英文 toast 提示 - // 触发时机: lang.js setRemoteStatus('fail', ...) 时 - // 设计: 用 setRemoteStatus 内部归一化后的 reason 决定文案 - // - 'timeout' / 'network' / 'http' / 'parse' / 'exception' 都弹同一句英文说明 - // - 'unknown' 不弹(可能是业务主动设置,不是真失败) - // 防刷: 同一进程内只弹一次(避免重试时反复刷屏) - if (!globalThis.__i18nFallbackToastShown) { - uni.$on && uni.$on('lang:fallback', (detail) => { - const r = detail && detail.reason; - if (r === 'unknown' || r === undefined || r === null) return; - if (globalThis.__i18nFallbackToastShown) return; - globalThis.__i18nFallbackToastShown = true; - try { - uni.showToast({ - title: 'Failed to load i18n. Please check your network and try again.', - icon: 'none', - duration: 4000, - }); - } catch (e) {} - }); - } + // i18n 远端拉取失败的 toast 提示已迁移到上方 boot() 完成的 then() 中, + // 直接根据 boot 返回值判断,不再依赖 lang:fallback 事件 uni.hideTabBar(); // #ifdef MP