feedback5 W5S: i18n phase 2, ui — HUD, shop bar, detail card, bond strip and popup, 机变 overlay, enemy drawer, team panel, under-frame, guide, emotes, match chrome, connection banner, components, the loadout / roster models, the store, net and observe texts through t() / tParts() (whole sentences where a number or a name sat inside), msgid tables marked N_() and translated where shown, the shop's refusal reasons compared through t(); tools/i18n.mjs reads aliased imports (t as tr); English for the 59 new msgids; Chinese output unchanged (zh render proof; five rewrites checked by hand, listed in the notes)

This commit is contained in:
sganggs committed 2026-10-06 18:09:50 +08:00
1 parent 166c4fbbfb
commit 647bd23ef2
33 files changed
+530 -427

No files matched your search

+11 -11
View File
@@ -194,12 +194,12 @@ export function tierChipUrl(t) {
* @param {{ tier: number, golden?: boolean, size?: 'sm'|'md'|'lg', class?: string }} props
*/
export function TierChip({ tier, golden = false, size = 'md', class: cls }) {
const t = Math.max(1, Math.min(6, Number(tier) | 0 || 1));
const src = tierChipUrl(t);
const n = Math.max(1, Math.min(6, Number(tier) | 0 || 1));
const src = tierChipUrl(n);
const [bad, setBad] = useState(null);
const img = !!src && bad !== src;
return html`<span class=${cx('tier', `tier--${t}`, `tier--${size}`, golden && 'tier--golden', img && 'tier--img', cls)} aria-label=${`${t}阶`}>
${img ? html`<img src=${src} alt="" draggable=${false} onError=${() => setBad(src)} />` : roman(t)}
return html`<span class=${cx('tier', `tier--${n}`, `tier--${size}`, golden && 'tier--golden', img && 'tier--img', cls)} aria-label=${t('{tier}阶', { tier: n })}>
${img ? html`<img src=${src} alt="" draggable=${false} onError=${() => setBad(src)} />` : roman(n)}
</span>`;
}
@@ -240,7 +240,7 @@ export function BondDisc({
: html`<span class="bond__glyph">${glyph}</span>`}
</span>
${stack != null ? html`<span class="bond__count">${stack}</span>` : null}
${disabled ? html`<span class="bond__ban" aria-label="禁用"><${Icon} name="close" /></span>` : null}
${disabled ? html`<span class="bond__ban" aria-label=${t('禁用')}><${Icon} name="close" /></span>` : null}
</span>
${showName && name ? html`<span class="bond__name">${name}</span>` : null}
<//>`;
@@ -373,7 +373,7 @@ export function Countdown({ deadline, seconds, total, warnAt = 10, label = 'COUN
// untimed phase: no timer on screen (hooks above run unconditionally, so the component may toggle freely)
if (remain == null) return null;
return html`<div class=${cx('countdown', `countdown--${size}`, warn && 'is-warn', cls)} role="timer" aria-label=${remain == null ? '无倒计时' : `剩余${remain}秒`}>
return html`<div class=${cx('countdown', `countdown--${size}`, warn && 'is-warn', cls)} role="timer" aria-label=${remain == null ? t('无倒计时') : t('剩余{remain}秒', { remain })}>
<div class="countdown__main">
<${SevenSeg} text=${text} tone=${warn ? 'orange' : 'mint'} flicker=${warn && remain > 0} />
${label ? html`<span class="countdown__label">${label}</span>` : null}
@@ -489,7 +489,7 @@ export function DialogHost() {
}, []);
const d = dialogs[0];
if (!d) return null;
const { title = '确认', text, okText = '确认', cancelText = '取消', tone, danger, micro = 'CONFIRMATION' } = d.opts;
const { title = t('确认'), text, okText = t('确认'), cancelText = t('取消'), tone, danger, micro = 'CONFIRMATION' } = d.opts;
const isConfirm = d.kind === 'confirm';
// Enter confirms unless a specific button has focus (then the native click decides).
const onKey = (e) => {
@@ -670,7 +670,7 @@ export function Spinner({ size = 'md', label, tone = 'mint', class: cls }) {
<polygon class="spinner__track" points="25,3 44,14 44,36 25,47 6,36 6,14" />
<polygon class="spinner__arc" points="25,3 44,14 44,36 25,47 6,36 6,14" />
</svg>
${label ? html`<span class="spinner__label">${label}</span>` : html`<span class="sr-only">加载中</span>`}
${label ? html`<span class="spinner__label">${label}</span>` : html`<span class="sr-only">${t('加载中')}</span>`}
</span>`;
}
@@ -695,8 +695,8 @@ export function AvatarFrame({ name = '', src, size = 'md', seat = 0, host, bot,
: bot ? html`<${Icon} name="robot" class="avatar__bot" />`
: html`<span class="avatar__glyph">${glyph}</span>`}
</div>
${host ? html`<span class="avatar__badge avatar__badge--host" title="创建者"><${Icon} name="crown" /></span>` : null}
${self ? html`<span class="avatar__badge avatar__badge--self" title="你"><${Icon} name="user" /></span>` : null}
${host ? html`<span class="avatar__badge avatar__badge--host" title=${t('创建者')}><${Icon} name="crown" /></span>` : null}
${self ? html`<span class="avatar__badge avatar__badge--self" title=${t('你')}><${Icon} name="user" /></span>` : null}
${bot && !empty ? html`<span class="avatar__tag">AI</span>` : null}
</div>`;
}
@@ -755,7 +755,7 @@ export function doctorNo(id) {
export function PingPill({ ms, online = true, class: cls }) {
const ok = online && Number.isFinite(ms);
const tier = !ok ? 'off' : ms < 60 ? 'low' : ms < 200 ? 'medium' : 'high';
return html`<span class=${cx('ping', `ping--${tier}`, cls)} title=${ok ? `当前延迟 ${ms}ms` : '未连接'}>
return html`<span class=${cx('ping', `ping--${tier}`, cls)} title=${ok ? t('当前延迟 {ms}ms', { ms }) : t('未连接')}>
<${Icon} name=${ok ? 'signal' : 'wifiOff'} class="ping__icon" />
<span class="ping__value">${ok ? Math.min(9999, Math.round(ms)) : '--'}</span><span class="ping__unit">ms</span>
</span>`;