Update Site source

This commit is contained in:
Codex committed 2026-09-28 09:29:27 +09:00
1 parent 223ad634d7
commit ca116d6cce
8 files changed
+94 -34

No files matched your search

+1 -1
View File
@@ -8,7 +8,7 @@ const meta = new URL("../dist/.openai/", import.meta.url);
await rm(dist, { recursive: true, force: true });
await Promise.all([mkdir(server, { recursive: true }), mkdir(meta, { recursive: true })]);
const [rawIndexHtml, addonsJs, bootGuardJs, i18nJs, tasksJs, calendarJs, i18nRenderersJs, manifest, serviceWorker, icon, localeEn, localeZh] = await Promise.all([text("index.html"), text("addons.js"), text("boot-guard.js"), text("i18n.js"), text("tasks.js"), text("calendar.js"), text("i18n-renderers.js"), text("manifest.webmanifest"), text("service-worker.js"), text("life-os-icon.svg"), readFile(new URL("../public/locales/en.json", import.meta.url), "utf8"), readFile(new URL("../public/locales/zh-CN.json", import.meta.url), "utf8")]);
const release = "1.5.3";
const release = "1.5.4";
const indexHtml = rawIndexHtml.replace('src="addons.js"', `src="addons.js?v=${release}`).replace('src="tasks.js"', `src="tasks.js?v=${release}`).replace('src="calendar.js"', `src="calendar.js?v=${release}`);
await writeFile(new URL("assets.js", server), `export const indexHtml=${JSON.stringify(indexHtml)};\nexport const addonsJs=${JSON.stringify(addonsJs)};\nexport const bootGuardJs=${JSON.stringify(bootGuardJs)};\nexport const i18nJs=${JSON.stringify(i18nJs)};\nexport const localeEn=JSON.parse(${JSON.stringify(localeEn)});\nexport const localeZh=JSON.parse(${JSON.stringify(localeZh)});\nexport const localeEnJs=${JSON.stringify(`window.LifeOSLocales=window.LifeOSLocales||{};window.LifeOSLocales.en=${localeEn};`)};\nexport const localeZhJs=${JSON.stringify(`window.LifeOSLocales=window.LifeOSLocales||{};window.LifeOSLocales['zh-CN']=${localeZh};`)};\nexport const tasksJs=${JSON.stringify(tasksJs)};\nexport const calendarJs=${JSON.stringify(calendarJs)};\nexport const i18nRenderersJs=${JSON.stringify(i18nRenderersJs)};\nexport const manifest=${JSON.stringify(manifest)};\nexport const serviceWorker=${JSON.stringify(serviceWorker)};\nexport const icon=${JSON.stringify(icon)};\n`);
await copyFile(new URL("../worker/index.js", import.meta.url), new URL("index.js", server));
+48 -14
View File
@@ -38,22 +38,56 @@ for (const [, inlineScript] of source.matchAll(/<script>([\s\S]*?)<\/script>/g))
assert.doesNotMatch(source, /localizeDynamicText|createTreeWalker|NodeFilter\.SHOW_TEXT|const ZH=/);
assert.match(source, /id==='system'\)window\.systemApp\(c\)/);
assert.match(source, /id==='today'\)window\.today\(c\)/);
assert.match(assets.i18nRenderersJs, /window\.setLanguage = value/);
assert.match(assets.i18nJs, /window\.setLanguage = setLanguage/);
assert.match(assets.i18nRenderersJs, /window\.renderAll\(\)/);
assert.doesNotMatch(source, /Version 0\.1|Schema v1/);
const langSource = source.match(/function browserLanguage\(\).*?function i18n\(key/)[0].replace(/function i18n\(key[\s\S]*$/, "");
let preferences = { language: "auto", languageMode: "auto" };
const languageContext = vm.createContext({ navigator: { languages: ["zh-CN"], language: "zh-CN" }, settings: () => preferences });
vm.runInContext(langSource, languageContext);
assert.equal(languageContext.lang(), "zh", "auto mode follows Chinese browser language");
languageContext.navigator.languages = ["en-US"];
assert.equal(languageContext.lang(), "en", "auto mode follows English browser language");
preferences = { language: "zh", languageMode: "manual" };
assert.equal(languageContext.lang(), "zh", "manual Chinese choice overrides browser language");
preferences = { language: "en", languageMode: "manual" };
assert.equal(languageContext.lang(), "en", "manual English choice overrides browser language");
preferences = { language: "zh" };
assert.equal(languageContext.lang(), "zh", "legacy manual preference survives settings migration");
const makeStorage = initial => {
const values = new Map(Object.entries(initial || {}));
return { getItem: key => values.get(key) ?? null, setItem: (key,value) => values.set(key,String(value)), values };
};
let legacySettings = { language: "auto", languageMode: "auto" };
const calls = { icons: 0, render: 0, apply: 0, toast: 0 };
const localStorage = makeStorage();
const localeContext = vm.createContext({
navigator: { languages: ["zh-CN"], language: "zh-CN" },
localStorage,
LifeOSLocales: { en: assets.localeEn, "zh-CN": assets.localeZh },
settings: () => legacySettings,
renderIcons() { calls.icons++; }, renderAll() { calls.render++; }, applyLanguage() { calls.apply++; }, toast() { calls.toast++; },
});
localeContext.window = localeContext;
vm.runInContext(assets.i18nJs, localeContext);
assert.equal(localeContext.LifeI18n.preference(), "auto");
assert.equal(localeContext.LifeI18n.language(), "zh", "auto mode follows Chinese browser language");
localeContext.navigator.languages = ["en-US"];
assert.equal(localeContext.LifeI18n.language(), "en", "auto mode follows English browser language");
assert.equal(localeContext.LifeI18n.t("app.today"), "TODAY");
localeContext.setLanguage("zh");
assert.equal(localeContext.LifeI18n.language(), "zh", "manual Chinese choice overrides browser language");
assert.equal(localeContext.LifeI18n.t("app.today"), "今日");
assert.equal(localStorage.getItem("lifeos_language_preference_v1"), "zh");
assert.deepEqual(calls, { icons: 1, render: 1, apply: 1, toast: 1 }, "language selection redraws the desktop and shows feedback");
legacySettings = { language: "en", languageMode: "manual" };
assert.equal(localeContext.LifeI18n.language(), "zh", "cloud settings cannot overwrite the local manual choice");
localeContext.setLanguage("en");
assert.equal(localeContext.LifeI18n.language(), "en", "manual English choice overrides browser language");
assert.equal(localeContext.LifeI18n.t("app.today"), "TODAY");
localeContext.navigator.languages = ["zh-CN"];
localeContext.setLanguage("auto");
assert.equal(localeContext.LifeI18n.preference(), "auto");
assert.equal(localeContext.LifeI18n.language(), "zh", "auto mode ignores stale cloud preference and follows this device");
const migratedStorage = makeStorage({ lifeos_settings: JSON.stringify({ language: "zh" }) });
const migratedContext = vm.createContext({
navigator: { languages: ["en-US"] }, localStorage: migratedStorage,
LifeOSLocales: { en: assets.localeEn, "zh-CN": assets.localeZh },
settings: () => ({ language: "zh", languageMode: "manual" }),
});
migratedContext.window = migratedContext;
vm.runInContext(assets.i18nJs, migratedContext);
assert.equal(migratedContext.LifeI18n.language(), "zh", "legacy manual preference migrates to the local preference key");
assert.match(assets.i18nRenderersJs, /preference === 'zh'/);
assert.match(assets.i18nRenderersJs, /onclick=\"window\.setLanguage\('zh'\)\"/);
assert.doesNotMatch(assets.addonsJs, /lifeos_language_preference_v1/, "the device locale preference stays outside cloud-synced keys");
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" } }), {});