fix(webui): sync localized preboot copy

This commit is contained in:
chengyongru
2026-07-13 23:28:19 +08:00
committed by chengyongru
parent 1e7518a207
commit 6b5820ea89
3 changed files with 103 additions and 15 deletions
+82 -1
View File
@@ -1,3 +1,7 @@
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import { runInNewContext } from "node:vm";
import { act, render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { describe, expect, it, vi } from "vitest";
@@ -5,7 +9,11 @@ import { describe, expect, it, vi } from "vitest";
import { LanguageSwitcher } from "@/components/LanguageSwitcher";
import { ThreadComposer } from "@/components/thread/ThreadComposer";
import { resources } from "@/i18n";
import { LOCALE_STORAGE_KEY, resolveInitialLocale } from "@/i18n/config";
import {
LOCALE_STORAGE_KEY,
resolveInitialLocale,
supportedLocales,
} from "@/i18n/config";
const QUICK_ACTION_KEYS = ["plan", "analyze", "brainstorm", "code", "summarize", "more"];
const IMAGE_QUICK_ACTION_KEYS = ["icon", "sticker", "poster", "product", "portrait", "edit"];
@@ -128,6 +136,46 @@ const LOCALIZED_WORKSPACE_COPY_KEYS = [
"workspace.dialog.usePath",
"workspace.dialog.absolutePathRequired",
];
const INDEX_HTML = readFileSync(resolve(process.cwd(), "index.html"), "utf8");
const PREBOOT_SCRIPT = INDEX_HTML.match(
/<script>\s*(\(function \(\) \{\s*var localeKey = "nanobot\.locale";[\s\S]*?\}\)\(\);)\s*<\/script>/,
)?.[1];
const BOOT_COPY_MARKUP = '<span data-boot-copy>Loading nanobot…</span>';
function runPrebootLocale(storedLocale: string) {
if (!PREBOOT_SCRIPT) throw new Error("Could not find the preboot locale script in index.html");
const documentElement = { lang: "" };
const meta = {
content: "",
setAttribute(name: string, value: string) {
if (name === "content") this.content = value;
},
};
const boot = { textContent: "" };
runInNewContext(PREBOOT_SCRIPT, {
localStorage: {
getItem: (key: string) => key === LOCALE_STORAGE_KEY ? storedLocale : null,
},
navigator: { languages: [], language: "en" },
document: {
documentElement,
querySelector: (selector: string) => {
if (selector === '[data-i18n-meta="description"]') return meta;
if (selector === "[data-boot-copy]") return boot;
return null;
},
},
});
return {
lang: documentElement.lang,
boot: boot.textContent,
description: meta.content,
};
}
function isRecord(value: unknown): value is Record<string, unknown> {
return !!value && typeof value === "object" && !Array.isArray(value);
}
@@ -156,6 +204,39 @@ function interpolationKeys(value: unknown): string[] {
}
describe("webui i18n", () => {
it("runs preboot localization after the splash copy exists", () => {
expect(INDEX_HTML.indexOf(BOOT_COPY_MARKUP)).toBeGreaterThan(-1);
expect(INDEX_HTML.indexOf(PREBOOT_SCRIPT ?? "")).toBeGreaterThan(
INDEX_HTML.indexOf(BOOT_COPY_MARKUP),
);
});
it("keeps preboot copy aligned with every registered locale", () => {
for (const { code } of supportedLocales) {
const result = runPrebootLocale(code);
const expected = resources[code].common.app;
expect({ code, ...result }).toEqual({
code,
lang: code,
boot: expected.loading.boot,
description: expected.meta.description,
});
}
});
it("normalizes Portuguese locales before the app bundle loads", () => {
const expected = resources["pt-BR"].common.app;
for (const locale of ["pt", "pt-PT"]) {
expect(runPrebootLocale(locale)).toEqual({
lang: "pt-BR",
boot: expected.loading.boot,
description: expected.meta.description,
});
}
});
it("defaults to English until the user chooses another language", () => {
localStorage.removeItem(LOCALE_STORAGE_KEY);
expect(resolveInitialLocale()).toBe("en");