fix(i18n): localize all user-facing Life OS text

This commit is contained in:
Codex committed 2026-09-27 14:24:42 +00:00
1 parent 4297f1ee42
commit a95d3652ca
12 files changed
+1057 -110

No files matched your search

+34 -1
View File
@@ -1,11 +1,44 @@
import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
const worker = await import(new URL("../dist/server/index.js", import.meta.url));
assert.equal(typeof worker.default?.fetch, "function");
const assets = await import(new URL("../dist/server/assets.js", import.meta.url));
assert.match(assets.indexHtml, /!\[1,2\]\.includes\(d\.schemaVersion\)/);
assert.doesNotMatch(assets.indexHtml, /localizeDynamicText|createTreeWalker|NodeFilter\.SHOW_TEXT|const ZH=/);
assert.match(assets.indexHtml, /locales\/en\.js/);
assert.match(assets.addonsJs, /window\.exportData = exportData/);
assert.match(assets.addonsJs, /schemaVersion: 2/);
assert.match(assets.addonsJs, /settings: settings\(\), system: sys\(\)/);
assert.match(assets.addonsJs, /if \(mergedLocalBoard\) await uploadCloudState\(\)/);
assert.match(assets.i18nRenderersJs, /dialog\.goals/);
console.log("Life OS Worker artifact is valid");
assert.match(assets.i18nRenderersJs, /shell\.wallpaperTitle/);
assert.match(assets.i18nRenderersJs, /window\.museumApp/);
assert.equal(assets.manifest.includes('"description"'), false);
const flatten = (value, prefix = "") => Object.entries(value).flatMap(([key, child]) => child && typeof child === "object" && !Array.isArray(child) ? flatten(child, prefix ? `${prefix}.${key}` : key) : [prefix ? `${prefix}.${key}` : key]).sort();
const enKeys = flatten(assets.localeEn), zhKeys = flatten(assets.localeZh);
assert.deepEqual(enKeys, zhKeys, "English and Chinese locale keys must match");
const resolveKey = (locale, key) => key.split(".").reduce((value, part) => value?.[part], locale);
for (const source of [assets.i18nRenderersJs, assets.addonsJs, assets.indexHtml]) {
for (const match of source.matchAll(/(?:\bt|LifeI18n\.t)\(['"`]([A-Za-z][\w.]+)['"`]/g)) {
assert.notEqual(resolveKey(assets.localeEn, match[1]), undefined, `Missing locale key: ${match[1]}`);
assert.notEqual(resolveKey(assets.localeZh, match[1]), undefined, `Missing Chinese locale key: ${match[1]}`);
}
}
for (const locale of [assets.localeEn, assets.localeZh]) {
assert.ok(locale.login.title && locale.login.description && locale.login.continue && locale.login.footnote);
assert.equal(locale.prompt.films.length, 30);
assert.equal(locale.prompt.lines.length, 30);
}
for (const script of [assets.tasksJs, assets.calendarJs]) {
assert.doesNotMatch(script, /createTreeWalker|NodeFilter\.SHOW_TEXT/);
}
const source = await readFile(new URL("../public/index.html", import.meta.url), "utf8");
assert.doesNotMatch(source, /localizeDynamicText|createTreeWalker|NodeFilter\.SHOW_TEXT|const ZH=/);
const zhLogin = await worker.default.fetch(new Request("https://life-os.test/", { headers: { "accept-language": "zh-CN,zh;q=0.9" } }), {});
assert.match(await zhLogin.text(), /登录 ChatGPT/);
const enLogin = await worker.default.fetch(new Request("https://life-os.test/", { headers: { "accept-language": "en-US,en;q=0.9" } }), {});
assert.match(await enLogin.text(), /Sign in with ChatGPT/);
const localeResponse = await worker.default.fetch(new Request("https://life-os.test/locales/zh-CN.js"), {});
assert.equal(localeResponse.status, 200);
assert.match(await localeResponse.text(), /window\.LifeOSLocales\['zh-CN'\]/);
console.log(`Life OS artifact valid · ${enKeys.length} bilingual locale keys`);