feedback5 WI: UI strings through t() with an English switch on the title screen and in 设置; pilot screens converted

public/i18n/en.json: Chinese msgid -> English, seeded from PR #70 (@YuriRestia, credited) for every Chinese
literal of the current code (≈830 entries; 966 of the 1 036 literals left for phase 2 already translated),
completed by hand in the official EN terms. public/js/ui/lang.js: boot language (?lang=en|zh, then
localStorage sp.pref.lang, else Chinese; the browser language is not consulted), switchLang, useLang,
LangToggle; main.js renders after initLang and re-renders in place on a switch, and translates server
texts (m.toast / m.ticker frames, room.closed reasons, error codes via ui/toasts.js describeError).
Converted: title screen (English title, wordmark hidden), lobby, room, settings (语言 row, On/Off,
quality, hotkeys), the shell (crash screen, toasts) and DifficultyTag.

tools/i18n.mjs: extract (msgids + untranslated literals per file), check (msgids missing from en.json),
codemod (html`` text / attributes / strings / template literals -> t(), nested strings, N_ for module
level, i18n-ignore lines), seed (fill en.json from a msgid map).
This commit is contained in:
sganggs committed 2026-10-05 20:19:58 +08:00
1 parent e596478bef
commit a12a539e4d
13 files changed
+2102 -171

No files matched your search

+9 -7
View File
@@ -8,6 +8,7 @@ import { h } from '../../vendor/preact.module.js';
import { useEffect, useReducer } from '../../vendor/hooks.module.js';
import htm from '../../vendor/htm.module.js';
import { ERR_TEXT } from '../../../shared/constants.js';
import { t } from '../../../shared/i18n.js';
// no shared static vnodes (see components.js hFresh: htm's static cache would retain unmounted DOM)
function hFresh(type, props, ...children) {
@@ -87,17 +88,18 @@ export function dismissToast(id) {
}
/**
* Text for an error-ish value: NetError / {code,msg} / Error / string.
* Text for an error-ish value: NetError / {code,msg} / Error / string — in the current language (the Chinese texts are
* msgids: ERR_TEXT, net.js CLIENT_ERR_TEXT, a server `msg`; anything else is shown as it is).
* @param {any} err
* @returns {string}
*/
export function describeError(err) {
if (!err) return '发生未知错误';
if (typeof err === 'string') return ERR_TEXT[err] || err;
if (err.code && ERR_TEXT[err.code]) return ERR_TEXT[err.code];
if (typeof err.message === 'string' && err.message) return err.message;
if (typeof err.msg === 'string' && err.msg) return err.msg;
return '发生未知错误';
if (!err) return t('发生未知错误');
if (typeof err === 'string') return t(Object.hasOwn(ERR_TEXT, err) ? ERR_TEXT[err] : err);
if (err.code && Object.hasOwn(ERR_TEXT, err.code)) return t(ERR_TEXT[err.code]);
if (typeof err.message === 'string' && err.message) return t(err.message);
if (typeof err.msg === 'string' && err.msg) return t(err.msg);
return t('发生未知错误');
}
/**