From dba7b9719019645ecdeee1536f6bb9f8e6a79941 Mon Sep 17 00:00:00 2001 From: argszero Date: Sat, 12 Sep 2026 02:19:33 +0800 Subject: [PATCH] fix(ui): render the raise-request table header in the active language MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The admin "raise requests" table built its `` from Chinese string literals inside `renderRaiseRequests()` (app.js). Because that markup is injected after boot and carries no `data-i18n`, `applyStatic()` had no path to it, so the header stayed Chinese in English mode. The same table's body cells were already translated by C1991 (`data-label` via `T(admin.raise.col.*)`), so the language fix was only half applied - which inverted the result on narrow screens: 1400px, English: th = 成员 / 申请点数 / 原因 / 状态 (Chinese, visible) 390px, English: th hidden, td::before = Member / Requested pts / ... (English) Resolve the four header cells with `T()` at render time instead of embedding literals. Render-time lookup (rather than a `data-i18n` attribute) is required because the table is re-injected by the existing `atp:langchange` -> `renderView` path, so the header must be produced already translated and must re-read the language on every rebuild. This mirrors the existing precedent in this file: the transaction table resolves headers via `col.title()` in `tableTheadHtml()`. No new i18n keys: `admin.raise.col.member/amount/reason/status` already exist in both packs (they were used by the `data-label` attributes right below). Verified in a headless browser against a baseline built from the same generator, EN and ZH, at 1400px and 390px: baseline header = 10 CJK chars in EN (negative control `#emp-body` = 0, proving the probe sees translations), fixed header = 0 CJK with exactly `Member / Requested pts / Reason / Status`; ZH output byte-identical to baseline; body `data-label`s and row count unchanged. A runtime `I18n.setLang("en")` switch with no reload confirms the baseline keeps a Chinese header while its `data-label`s go English (the inversion), and the fixed header follows the switch. --- ui/index.html | 10 +++++----- ui/js/app.js | 9 ++++++++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/ui/index.html b/ui/index.html index d7f7547..1b58c92 100644 --- a/ui/index.html +++ b/ui/index.html @@ -5,7 +5,7 @@ AITokenPool - + @@ -842,9 +842,9 @@

使用模型

- - - - + + + + diff --git a/ui/js/app.js b/ui/js/app.js index 293e693..e7e75b3 100644 --- a/ui/js/app.js +++ b/ui/js/app.js @@ -1243,7 +1243,14 @@ el.innerHTML = loadErrorHtml(T("admin.raise.loadFail"), null, T("err.loadFail")); return; } - el.innerHTML = (list.length ? '
' + + // 表头在渲染期取 i18n(本表由 JS 在 boot 之后注入,无 data-i18n 钩子可走): + // 既保证首屏语言正确,也让 atp:langchange → renderView 能实时换语言 + el.innerHTML = (list.length ? '
成员申请点数原因状态
' + + '" + + '" + + "" + + "" + + "" + list.map((r, i) => "" + '" +
' + esc(T("admin.raise.col.member")) + "' + esc(T("admin.raise.col.amount")) + "" + esc(T("admin.raise.col.reason")) + "" + esc(T("admin.raise.col.status")) + "
" + esc(r.name || r.user) + "
" + esc(r.email) + "
+' + D.fmt(r.amount) + " " + T("common.points") + "