fb5 UI-TW: the machine-translation mark — _meta.machineTranslated: true, a new optional manifest field of a language pack (docs/PACKS.md): shared/i18nPacks.js langFields reads it (true or false), shared/packs.js normalizeManifest warns about a value that is not a boolean (read as false; the pack still loads) and packIndexEntry passes it into the index entry like complete (only when true), so the client's registry has it from the index (langMetaOf → registerLangs → langInfo) or from the pack's own _meta without one; 设置 shows a note under the language switch while the CURRENT language's pack has it (ui/lang.js machineTranslationNote, msgid 「当前语言的界面文字为机器翻译,可能不够准确,欢迎在 GitHub 上指正。」 — English in en.json, 目前語言的介面文字為機器翻譯… in zh-TW.json; ja / ko leave it to the integrator); tests: test/i18n-packs.test.js (the field from the manifest through the index to langInfo, the warning, the shipped zh-TW manifest, the note shown / hidden by language), test/ui/i18n.e2e.test.js (the shipped packs' own UI strings read from their files — zh-TW now 開始 — and the 设置 note, none in Chinese); docs/I18N.md says how the zh-TW pack is made (OpenCC twp, the official TW terms, a manual pass; a later msgid the same way) and that the ja / ko strings are machine translations open to corrections (edit public/i18n/<code>.json, node tools/i18n.mjs check <code> --strict)

This commit is contained in:
sganggs committed 2026-10-07 11:47:09 +08:00
1 parent 6613c3d0fb
commit c11ba03da4
11 files changed
+173 -38

No files matched your search

+9 -3
View File
@@ -23,13 +23,14 @@
// englishName its English name
// authors a string or a list; credits free text; license an SPDX id or free text
// files a folder pack: role → path inside the folder (type "lang": { "ui": "ui.json", "data": "data.json" })
// … the type's own fields (type "lang": lang, base, fallback, complete, numberUnits — shared/i18nPacks.js)
// … the type's own fields (type "lang": lang, base, fallback, complete, machineTranslated, numberUnits —
// shared/i18nPacks.js; a machineTranslated that is not a boolean is warned about and reads as false)
//
// Index (GET /packs/index.json — the server's live list; `node tools/packs.mjs index` writes packs/index.json for a
// static host): { version: 1, app: "<the server's app version>", packs: [entry …] } — the packs of supported types,
// sorted by type then id. An entry: id, type, name, englishName, version?, app?, compatible, authors?, credits?,
// license?, files (role → URL on this server) and the type's fields; a language entry: lang, base?, fallback,
// complete?, numberUnits?, strings (how many translations its UI file holds).
// complete?, machineTranslated?, numberUnits?, strings (how many translations its UI file holds).
import { APP_VERSION } from './constants.js';
import { SOURCE_LANG, canonicalLang, isLangCode, languageName, langFields } from './i18nPacks.js';
@@ -134,7 +135,8 @@ export function appVersionMatches(range, version = APP_VERSION) {
/**
* @typedef {{ id: string, type: string, name: string, englishName: string, version: string, app: string,
* compatible: boolean, authors: string[], credits: string, license: string, files: Record<string, string>,
* lang?: string, base?: string|null, fallback?: string[], complete?: boolean, numberUnits?: string[]|null }} PackManifest
* lang?: string, base?: string|null, fallback?: string[], complete?: boolean, machineTranslated?: boolean,
* numberUnits?: string[]|null }} PackManifest
*/
/**
@@ -178,6 +180,9 @@ export function normalizeManifest(raw, ctx) {
else {
if (m.lang !== undefined && !isLangCode(m.lang) && !ctx.lang) warnings.push(`"lang": "${m.lang}" read as ${code}`);
Object.assign(out, langFields(code, m));
// anything but true reads as false: say so when another value was meant
const mt = m.machineTranslated;
if (mt !== undefined && typeof mt !== 'boolean') warnings.push(`"machineTranslated": ${String(JSON.stringify(mt)).slice(0, 40)} is not true or false (read as false)`);
out.name ||= languageName(code);
out.englishName ||= languageName(code, 'en');
}
@@ -220,6 +225,7 @@ export function packIndexEntry(manifest, extra) {
if (manifest.base !== undefined) e.base = manifest.base;
e.fallback = manifest.fallback || [];
if (manifest.complete) e.complete = true;
if (manifest.machineTranslated) e.machineTranslated = true;
if (manifest.numberUnits) e.numberUnits = manifest.numberUnits;
e.strings = extra.strings ?? 0;
}