v1.3.3: 中英双语 i18n + 回归时序根治

i18n(竞品 7 家全有、Aurora 唯一还缺的一线能力)
- site/i18n.js:330 条文案字典,顶栏「中 / EN」切换,偏好存 aa-lang,
  <html lang> 与 document.title 同步
- 设计取舍:以中文源串为字典键,而非抽象 key。中文是规范原文语言也是
  app.js 现有字面量;源串作键意味着未收录文案自动回退原文,不会出现
  空白或 key 泄漏
- 覆盖:导航/侧栏/首页 Hero 与设计原则/总览/快速开始/设计规范(含令牌
  导出区)/For Agents 全表/更新日志/组件详情页(何时使用、API 三表、
  无障碍键盘表、Do&Don't、设计契约、实现资源、相关组件)/Playground/
  主题面板/搜索弹窗/FAB 提示
- 语言感知显示:组件名主次调换(中文模式主显中文名,英文模式主显英文
  名),详情页大标题不再重复;分类名走 CAT_EN 不占字典

修复回归时序(根治偶发)
- DensitySwitcher 对比度偶发失败:断言在演示页内联脚本执行完之前就跑了,
  读到 is-active 尚未应用的中间态(白字未落到品牌蓝底)。单页打开通过、
  并发收集器里偶发失败
- 根因是固定帧数等待(load + 双 rAF)在多个 iframe 抢主线程时不够稳。
  改为就绪轮询:readyState === 'complete' 且 DOM 连续 3 次采样(约 48ms)
  无变化才断言,另设约 4.8s 超时兜底
- 验证:四次连跑全部 100%,偶发不再复现

修复 i18n 接入中的三个真实缺陷
- TDZ 顺序:KIND_KEYS 等模块级常量在 I18N/T 定义前调用 T(),抛
  Cannot read properties of undefined。改为存中文源串、渲染时求值
  (模块级预先求值还会导致语言切换后不更新)
- 局部变量遮蔽:renderDesign 内原有 var T = data.tokens 遮蔽全局翻译
  函数,导致设计规范页整个渲染失败。改名 TOKENS
- 模板拼接括号:el() 调用在包装 T() 后少一个右括号

验证
- 9 个路由 × 2 语言全部正常渲染(中英文内容均非空且确实不同)
- 回归保持 100%:961 断言 / 925 通过 / 0 失败 / 79 页全通过 / N/A 36
This commit is contained in:
aurora-admin
2026-09-11 17:15:42 +08:00
parent 7c9516011b
commit cbed5ba7ca
11 changed files with 1012 additions and 253 deletions
+37 -15
View File
@@ -584,27 +584,49 @@
var clr = document.getElementById('clear-log');
if (clr) clr.addEventListener('click', clearLog);
var frame = document.getElementById(FRAME_ID);
/* 等待演示页真正就绪再断言。
固定帧数(双 rAF)在并发收集器里不够稳:多个 iframe 抢主线程时,
演示页的内联脚本可能还没执行完(例如 DensitySwitcher 的 is-active 尚未加上),
断言读到的就是中间态。改为轮询:readyState 完成 + DOM 连续若干次采样无变化。 */
function whenReady(cb) {
var tries = 0;
var lastSig = null;
var stable = 0;
function tick() {
tries++;
if (!fDoc || !fWin) { if (tries < 200) return setTimeout(tick, 16); return cb(); }
var ready = false;
try { ready = fDoc.readyState === 'complete'; } catch (e) {}
var sig = '';
try {
var root = scope();
sig = root.childElementCount + ':' + root.innerHTML.length;
} catch (e) { sig = 'err'; }
if (ready && sig === lastSig) {
stable++;
// 连续 3 次采样(约 48ms)内容不变 → 认为渲染已稳定
if (stable >= 3) return cb();
} else {
stable = 0;
}
lastSig = sig;
if (tries < 300) setTimeout(tick, 16);
else cb(); // 超时兜底:约 4.8s 后无论如何都跑,避免页面卡死
}
tick();
}
var frame = document.getElementById(FRAME_ID);
if (frame) {
/* 演示页的内联脚本在 load 后才渲染 DOM(含 is-active 等初始状态类)。
直接断言会读到渲染中途的样式,产生时序性误报。
因此:load → 双 rAF(等一次完整样式重算)→ 再断言。 */
var auto = function () {
if (!bindFrame()) { setFrameState('演示页加载失败', 'fail'); return; }
var W = fWin || window;
var raf = W.requestAnimationFrame || window.requestAnimationFrame ||
function (cb) { return setTimeout(cb, 16); };
raf(function () { raf(function () { setTimeout(run, 30); }); });
whenReady(function () { run(); });
};
frame.addEventListener('load', auto);
if (bindFrame()) {
var W0 = fWin || window;
var raf0 = W0.requestAnimationFrame || window.requestAnimationFrame ||
function (cb) { return setTimeout(cb, 16); };
raf0(function () { raf0(function () { setTimeout(run, 30); }); });
} else {
setFrameState('加载中…');
}
if (bindFrame()) whenReady(function () { run(); });
else setFrameState('加载中…');
} else {
setTimeout(run, 0);
}