fix: switch legal and footer brands by region

This commit is contained in:
monster
2026-07-06 23:42:19 +08:00
parent 20eacf2d55
commit bb217667a3
9 changed files with 185 additions and 51 deletions
+48 -40
View File
@@ -3,48 +3,38 @@ import { Link } from "react-router-dom"
import { useTranslation } from "react-i18next"
import { useAppRuntime } from "@/components/app-runtime-provider"
const LINKS = [
const CHAITIN_LINK = "https://www.chaitin.cn/"
const BAIZHI_LINK = "https://www.baizhi.cloud/"
const CYBERSERVAL_LINK = "https://www.cyberserval.com/"
const SAFELINE_WAF_LINK = "https://cyberserval.tech/home"
const resourceLinks = [
{
titleKey: "welcomeShell.footer.resources",
links: [
{
titleKey: "welcomeShell.footer.productDocs",
href: "https://monkeycode.docs.baizhi.cloud/"
},
{
titleKey: "welcomeShell.footer.forum",
href: "https://bbs.baizhi.cloud/"
},
{
titleKey: "welcomeShell.nav.openSourceRepo",
href: "https://github.com/chaitin/MonkeyCode/"
}
]
titleKey: "welcomeShell.footer.productDocs",
href: "https://monkeycode.docs.baizhi.cloud/"
},
{
titleKey: "welcomeShell.footer.about",
links: [
{
titleKey: "welcomeShell.footer.chaitin",
href: "https://www.chaitin.cn/"
},
{
titleKey: "welcomeShell.footer.baizhi",
href: "https://www.baizhi.cloud/"
},
{
titleKey: "welcomeShell.nav.privacyPolicy",
href: "/privacy-policy"
},
{
titleKey: "welcomeShell.nav.userAgreement",
href: "/user-agreement"
},
{
titleKey: "welcomeShell.footer.icp",
href: "https://beian.miit.gov.cn/"
}
]
titleKey: "welcomeShell.footer.forum",
href: "https://bbs.baizhi.cloud/"
},
{
titleKey: "welcomeShell.nav.openSourceRepo",
href: "https://github.com/chaitin/MonkeyCode/"
}
]
const legalLinks = [
{
titleKey: "welcomeShell.nav.privacyPolicy",
href: "/privacy-policy"
},
{
titleKey: "welcomeShell.nav.userAgreement",
href: "/user-agreement"
},
{
titleKey: "welcomeShell.footer.icp",
href: "https://beian.miit.gov.cn/"
}
]
@@ -52,6 +42,24 @@ const Footer = () => {
const { t } = useTranslation()
const { serverConfig } = useAppRuntime()
const isGlobalRegion = serverConfig?.region === "global"
const companyLinks = isGlobalRegion ? [
{ titleKey: "welcomeShell.footer.cyberserval", href: CYBERSERVAL_LINK },
{ titleKey: "welcomeShell.footer.safelineWaf", href: SAFELINE_WAF_LINK }
]
: [
{ titleKey: "welcomeShell.footer.chaitin", href: CHAITIN_LINK },
{ titleKey: "welcomeShell.footer.baizhi", href: BAIZHI_LINK }
]
const links = [
{
titleKey: "welcomeShell.footer.resources",
links: resourceLinks
},
{
titleKey: "welcomeShell.footer.about",
links: [...companyLinks, ...legalLinks]
}
]
return (
<footer className="bg-primary px-10">
@@ -65,7 +73,7 @@ const Footer = () => {
{t("welcomeShell.footer.brandDescription")}
</p>
</div>
{LINKS.map((link) => (
{links.map((link) => (
<div key={link.titleKey} className="flex flex-col gap-4">
<h3 className="text-background leading-8">{t(link.titleKey)}</h3>
<ul className="text-background/50 text-sm flex flex-col gap-2">
@@ -12,6 +12,8 @@ const SHOWCASE_LINK = "https://showcase.monkeycode-ai.online/";
const SELF_HOSTING_PAGE_PATH = "/self-hosting";
const CHAITIN_LINK = "https://www.chaitin.cn/";
const BAIZHI_LINK = "https://www.baizhi.cloud/";
const CYBERSERVAL_LINK = "https://www.cyberserval.com/";
const SAFELINE_WAF_LINK = "https://cyberserval.tech/home";
const DISCORD_INVITE_LINK = "https://discord.gg/8NgHexaaMa";
const resourceLinks = [
@@ -20,9 +22,7 @@ const resourceLinks = [
{ titleKey: "welcomeShell.nav.openSourceRepo", href: GITHUB_LINK },
];
const aboutLinks = [
{ titleKey: "welcomeShell.footer.chaitin", href: CHAITIN_LINK },
{ titleKey: "welcomeShell.footer.baizhi", href: BAIZHI_LINK },
const legalAboutLinks = [
{ titleKey: "welcomeShell.nav.privacyPolicy", href: "/privacy-policy" },
{ titleKey: "welcomeShell.nav.userAgreement", href: "/user-agreement" },
];
@@ -228,6 +228,17 @@ export function TerminalFooter() {
const { t } = useTranslation();
const { serverConfig } = useAppRuntime();
const isGlobalRegion = serverConfig?.region === "global";
const copyrightKey = isGlobalRegion ? "welcomeShell.footer.globalCopyright" : "welcomeShell.footer.copyright";
const aboutLinks = isGlobalRegion ? [
{ titleKey: "welcomeShell.footer.cyberserval", href: CYBERSERVAL_LINK },
{ titleKey: "welcomeShell.footer.safelineWaf", href: SAFELINE_WAF_LINK },
...legalAboutLinks,
]
: [
{ titleKey: "welcomeShell.footer.chaitin", href: CHAITIN_LINK },
{ titleKey: "welcomeShell.footer.baizhi", href: BAIZHI_LINK },
...legalAboutLinks,
];
return (
<footer id="community" className="relative z-10 mt-10 border-t border-[var(--a-line)] px-5 pb-8 pt-14 sm:px-8">
@@ -287,7 +298,7 @@ export function TerminalFooter() {
</div>
<div className="mt-10 flex flex-col gap-3 border-t border-dashed border-[var(--a-line-2)] pt-5 text-[11px] tracking-[0.06em] text-[var(--a-fg-mute)] sm:flex-row sm:items-center sm:justify-between">
<span>{t("welcomeShell.footer.copyright")}</span>
<span>{t(copyrightKey)}</span>
{!isGlobalRegion ? (
<a href="https://beian.miit.gov.cn/" target="_blank" rel="noreferrer" className="transition-colors hover:text-[var(--a-fg)]">
{t("welcomeShell.footer.icp")}
+7
View File
@@ -1914,7 +1914,10 @@ const cn = {
forum: "技术论坛",
chaitin: "长亭科技",
baizhi: "长亭百智云",
cyberserval: "CyberServal",
safelineWaf: "SafeLine WAF",
copyright: "© 2026 MonkeyCode · 版权所有:北京长亭科技有限公司 · 本应用由 MonkeyCode 开发",
globalCopyright: "© 2026 MonkeyCode · 版权所有:CyberServal Co., Limited · 本应用由 MonkeyCode 开发",
icp: "京ICP备2024055124号-12",
},
community: {
@@ -2545,6 +2548,8 @@ const cn = {
chaitin: "长亭科技官网",
or: " 或 ",
baizhi: "长亭百智云官网",
cyberserval: "CyberServal 官网",
safelineWaf: "SafeLine WAF",
suffix: "。",
},
sections: [
@@ -2646,6 +2651,8 @@ const cn = {
chaitin: "长亭科技官网",
or: " 或 ",
baizhi: "长亭百智云官网",
cyberserval: "CyberServal 官网",
safelineWaf: "SafeLine WAF",
suffix: "。",
},
sections: [
+7
View File
@@ -1914,7 +1914,10 @@ const en = {
forum: "Forum",
chaitin: "Chaitin Tech",
baizhi: "Baizhi Cloud",
cyberserval: "CyberServal",
safelineWaf: "SafeLine WAF",
copyright: "© 2026 MonkeyCode · Copyright: Beijing Chaitin Technology Co., Ltd. · Built with MonkeyCode",
globalCopyright: "© 2026 MonkeyCode · Copyright: CyberServal Co., Limited · Built with MonkeyCode",
icp: "京ICP备2024055124号-12",
},
community: {
@@ -2545,6 +2548,8 @@ const en = {
chaitin: "Chaitin Tech website",
or: " or ",
baizhi: "Chaitin Baizhi Cloud website",
cyberserval: "CyberServal website",
safelineWaf: "SafeLine WAF",
suffix: ".",
},
sections: [
@@ -2646,6 +2651,8 @@ const en = {
chaitin: "Chaitin Tech website",
or: " or ",
baizhi: "Chaitin Baizhi Cloud website",
cyberserval: "CyberServal website",
safelineWaf: "SafeLine WAF",
suffix: ".",
},
sections: [
+17 -5
View File
@@ -18,16 +18,28 @@ export function withContactFooter(
return sections.map((section) => (section.id === "contact" ? { ...section, footer } : section));
}
export function renderOfficialChannels(t: TFunction, keyPrefix: string) {
export function renderOfficialChannels(t: TFunction, keyPrefix: string, isGlobalRegion: boolean) {
const channels = isGlobalRegion ? {
primaryHref: "https://www.cyberserval.com/",
primaryKey: "cyberserval",
secondaryHref: "https://cyberserval.tech",
secondaryKey: "safelineWaf",
} : {
primaryHref: "https://www.chaitin.cn/",
primaryKey: "chaitin",
secondaryHref: "https://www.baizhi.cloud/",
secondaryKey: "baizhi",
};
return (
<>
{t(`${keyPrefix}.prefix`)}
<a className="text-[var(--a-accent)] hover:underline" href="https://www.chaitin.cn/" target="_blank" rel="noreferrer">
{t(`${keyPrefix}.chaitin`)}
<a className="text-[var(--a-accent)] hover:underline" href={channels.primaryHref} target="_blank" rel="noreferrer">
{t(`${keyPrefix}.${channels.primaryKey}`)}
</a>
{t(`${keyPrefix}.or`)}
<a className="text-[var(--a-accent)] hover:underline" href="https://www.baizhi.cloud/" target="_blank" rel="noreferrer">
{t(`${keyPrefix}.baizhi`)}
<a className="text-[var(--a-accent)] hover:underline" href={channels.secondaryHref} target="_blank" rel="noreferrer">
{t(`${keyPrefix}.${channels.secondaryKey}`)}
</a>
{t(`${keyPrefix}.suffix`)}
</>
+4 -1
View File
@@ -1,11 +1,14 @@
import { useAppRuntime } from "@/components/app-runtime-provider";
import LegalTerminalPage from "@/components/welcome/legal-terminal-page";
import { useTranslation } from "react-i18next";
import { type LegalPageCopy, renderOfficialChannels, withContactFooter } from "./legal-page-i18n";
export default function PrivacyPolicyPage() {
const { t } = useTranslation();
const { serverConfig } = useAppRuntime();
const isGlobalRegion = serverConfig?.region === "global";
const page = t("legalPages.privacy", { returnObjects: true }) as LegalPageCopy;
const sections = withContactFooter(page.sections, renderOfficialChannels(t, "legalPages.privacy.contact"));
const sections = withContactFooter(page.sections, renderOfficialChannels(t, "legalPages.privacy.contact", isGlobalRegion));
return (
<LegalTerminalPage
+4 -1
View File
@@ -1,11 +1,14 @@
import { useAppRuntime } from "@/components/app-runtime-provider";
import LegalTerminalPage from "@/components/welcome/legal-terminal-page";
import { useTranslation } from "react-i18next";
import { type LegalPageCopy, renderOfficialChannels, withContactFooter } from "./legal-page-i18n";
export default function UserAgreementPage() {
const { t } = useTranslation();
const { serverConfig } = useAppRuntime();
const isGlobalRegion = serverConfig?.region === "global";
const page = t("legalPages.userAgreement", { returnObjects: true }) as LegalPageCopy;
const sections = withContactFooter(page.sections, renderOfficialChannels(t, "legalPages.userAgreement.contact"));
const sections = withContactFooter(page.sections, renderOfficialChannels(t, "legalPages.userAgreement.contact", isGlobalRegion));
return (
<LegalTerminalPage
+43
View File
@@ -18,13 +18,21 @@ function readSource(path: string) {
test("法律页面使用 legalPages i18n key", () => {
assert.match(sourceFiles.privacyPolicy, /useTranslation/);
assert.match(sourceFiles.privacyPolicy, /useAppRuntime/);
assert.match(sourceFiles.privacyPolicy, /const \{ serverConfig \} = useAppRuntime\(\)/);
assert.match(sourceFiles.privacyPolicy, /const isGlobalRegion = serverConfig\?\.region === "global"/);
assert.match(sourceFiles.privacyPolicy, /t\("legalPages\.privacy"/);
assert.match(sourceFiles.privacyPolicy, /legalPages\.privacy\.contact/);
assert.match(sourceFiles.privacyPolicy, /renderOfficialChannels\(t, "legalPages\.privacy\.contact", isGlobalRegion\)/);
assert.doesNotMatch(sourceFiles.privacyPolicy, cjkPattern);
assert.match(sourceFiles.userAgreement, /useTranslation/);
assert.match(sourceFiles.userAgreement, /useAppRuntime/);
assert.match(sourceFiles.userAgreement, /const \{ serverConfig \} = useAppRuntime\(\)/);
assert.match(sourceFiles.userAgreement, /const isGlobalRegion = serverConfig\?\.region === "global"/);
assert.match(sourceFiles.userAgreement, /t\("legalPages\.userAgreement"/);
assert.match(sourceFiles.userAgreement, /legalPages\.userAgreement\.contact/);
assert.match(sourceFiles.userAgreement, /renderOfficialChannels\(t, "legalPages\.userAgreement\.contact", isGlobalRegion\)/);
assert.doesNotMatch(sourceFiles.userAgreement, cjkPattern);
assert.match(sourceFiles.legalPageI18n, /renderOfficialChannels/);
@@ -42,3 +50,38 @@ test("法律页面提供中英文资源", () => {
assert.equal(cn.legalPages.userAgreement.sections[0].title, "协议适用范围");
assert.equal(en.legalPages.userAgreement.sections[0].title, "Scope of Agreement");
});
test("法律页面官方渠道按国内和国际版切换品牌和链接", () => {
assert.match(sourceFiles.legalPageI18n, /isGlobalRegion \?/);
assert.match(sourceFiles.legalPageI18n, /primaryHref: "https:\/\/www\.chaitin\.cn\/"/);
assert.match(sourceFiles.legalPageI18n, /secondaryHref: "https:\/\/www\.baizhi\.cloud\/"/);
assert.match(sourceFiles.legalPageI18n, /primaryHref: "https:\/\/www\.cyberserval\.com\/"/);
assert.match(sourceFiles.legalPageI18n, /secondaryHref: "https:\/\/cyberserval\.tech"/);
assert.match(sourceFiles.legalPageI18n, /\$\{keyPrefix\}\.\$\{channels\.primaryKey\}/);
assert.match(sourceFiles.legalPageI18n, /\$\{keyPrefix\}\.\$\{channels\.secondaryKey\}/);
const legalPageCopy = JSON.stringify({
cn: cn.legalPages,
en: en.legalPages,
});
assert.match(legalPageCopy, /长亭科技官网/);
assert.match(legalPageCopy, /长亭百智云官网/);
assert.match(legalPageCopy, /Cyberserval|CyberServal/);
assert.match(legalPageCopy, /SafeLine WAF/);
assert.equal(cn.legalPages.privacy.contact.chaitin, "长亭科技官网");
assert.equal(cn.legalPages.privacy.contact.baizhi, "长亭百智云官网");
assert.equal(cn.legalPages.privacy.contact.cyberserval, "CyberServal 官网");
assert.equal(cn.legalPages.privacy.contact.safelineWaf, "SafeLine WAF");
assert.equal(cn.legalPages.userAgreement.contact.chaitin, "长亭科技官网");
assert.equal(cn.legalPages.userAgreement.contact.baizhi, "长亭百智云官网");
assert.equal(cn.legalPages.userAgreement.contact.cyberserval, "CyberServal 官网");
assert.equal(cn.legalPages.userAgreement.contact.safelineWaf, "SafeLine WAF");
assert.equal(en.legalPages.privacy.contact.chaitin, "Chaitin Tech website");
assert.equal(en.legalPages.privacy.contact.baizhi, "Chaitin Baizhi Cloud website");
assert.equal(en.legalPages.privacy.contact.cyberserval, "CyberServal website");
assert.equal(en.legalPages.privacy.contact.safelineWaf, "SafeLine WAF");
assert.equal(en.legalPages.userAgreement.contact.chaitin, "Chaitin Tech website");
assert.equal(en.legalPages.userAgreement.contact.baizhi, "Chaitin Baizhi Cloud website");
assert.equal(en.legalPages.userAgreement.contact.cyberserval, "CyberServal website");
assert.equal(en.legalPages.userAgreement.contact.safelineWaf, "SafeLine WAF");
});
+40
View File
@@ -42,10 +42,45 @@ test("欢迎页外壳提供中英文资源", () => {
assert.equal(en.welcomeShell.actions.console, "Console");
assert.equal(cn.welcomeShell.footer.resources, "资源");
assert.equal(en.welcomeShell.footer.resources, "Resources");
assert.equal(cn.welcomeShell.footer.chaitin, "长亭科技");
assert.equal(en.welcomeShell.footer.chaitin, "Chaitin Tech");
assert.equal(cn.welcomeShell.footer.baizhi, "长亭百智云");
assert.equal(en.welcomeShell.footer.baizhi, "Baizhi Cloud");
assert.equal(cn.welcomeShell.footer.cyberserval, "CyberServal");
assert.equal(en.welcomeShell.footer.cyberserval, "CyberServal");
assert.equal(cn.welcomeShell.footer.safelineWaf, "SafeLine WAF");
assert.equal(en.welcomeShell.footer.safelineWaf, "SafeLine WAF");
assert.match(cn.welcomeShell.footer.copyright, /北京长亭科技有限公司/);
assert.match(en.welcomeShell.footer.copyright, /Beijing Chaitin Technology Co\., Ltd\./);
assert.match(cn.welcomeShell.footer.globalCopyright, /CyberServal Co\., Limited/);
assert.match(en.welcomeShell.footer.globalCopyright, /CyberServal Co\., Limited/);
assert.equal(cn.welcomeShell.legal.contents, "# 目录");
assert.equal(en.welcomeShell.legal.contents, "# Contents");
});
test("欢迎页 footer 公司链接按国内和国际版切换", () => {
assert.match(sourceFiles.footer, /const isGlobalRegion = serverConfig\?\.region === "global"/);
assert.match(sourceFiles.footer, /const companyLinks = isGlobalRegion \?/);
assert.match(sourceFiles.footer, /const CHAITIN_LINK = "https:\/\/www\.chaitin\.cn\/"/);
assert.match(sourceFiles.footer, /const BAIZHI_LINK = "https:\/\/www\.baizhi\.cloud\/"/);
assert.match(sourceFiles.footer, /const CYBERSERVAL_LINK = "https:\/\/www\.cyberserval\.com\/"/);
assert.match(sourceFiles.footer, /const SAFELINE_WAF_LINK = "https:\/\/cyberserval\.tech\/home"/);
assert.match(sourceFiles.footer, /\{ titleKey: "welcomeShell\.footer\.chaitin", href: CHAITIN_LINK \}/);
assert.match(sourceFiles.footer, /\{ titleKey: "welcomeShell\.footer\.baizhi", href: BAIZHI_LINK \}/);
assert.match(sourceFiles.footer, /\{ titleKey: "welcomeShell\.footer\.cyberserval", href: CYBERSERVAL_LINK \}/);
assert.match(sourceFiles.footer, /\{ titleKey: "welcomeShell\.footer\.safelineWaf", href: SAFELINE_WAF_LINK \}/);
assert.match(sourceFiles.terminalChrome, /const CHAITIN_LINK = "https:\/\/www\.chaitin\.cn\/"/);
assert.match(sourceFiles.terminalChrome, /const BAIZHI_LINK = "https:\/\/www\.baizhi\.cloud\/"/);
assert.match(sourceFiles.terminalChrome, /const CYBERSERVAL_LINK = "https:\/\/www\.cyberserval\.com\/"/);
assert.match(sourceFiles.terminalChrome, /const SAFELINE_WAF_LINK = "https:\/\/cyberserval\.tech\/home"/);
assert.match(sourceFiles.terminalChrome, /const aboutLinks = isGlobalRegion \?/);
assert.match(sourceFiles.terminalChrome, /\{ titleKey: "welcomeShell\.footer\.chaitin", href: CHAITIN_LINK \}/);
assert.match(sourceFiles.terminalChrome, /\{ titleKey: "welcomeShell\.footer\.baizhi", href: BAIZHI_LINK \}/);
assert.match(sourceFiles.terminalChrome, /\{ titleKey: "welcomeShell\.footer\.cyberserval", href: CYBERSERVAL_LINK \}/);
assert.match(sourceFiles.terminalChrome, /\{ titleKey: "welcomeShell\.footer\.safelineWaf", href: SAFELINE_WAF_LINK \}/);
});
test("欢迎页终端 header 在国际版隐藏注册入口", () => {
assert.match(sourceFiles.header, /const \{ auth, serverConfig \} = useAppRuntime\(\)/);
assert.match(sourceFiles.header, /const isGlobalRegion = serverConfig\?\.region === "global"/);
@@ -64,6 +99,11 @@ test("欢迎页 footer 在国际版隐藏 ICP 备案信息", () => {
assert.match(sourceFiles.terminalChrome, /!\s*isGlobalRegion \? \([\s\S]*t\("welcomeShell\.footer\.icp"\)[\s\S]*\) : null/);
});
test("欢迎页 terminal footer 版权按国内和国际版切换", () => {
assert.match(sourceFiles.terminalChrome, /isGlobalRegion \? "welcomeShell\.footer\.globalCopyright" : "welcomeShell\.footer\.copyright"/);
assert.match(sourceFiles.terminalChrome, /t\(copyrightKey\)/);
});
test("欢迎页资源列表不展示模型广场", () => {
assert.doesNotMatch(sourceFiles.footer, /modelSquare|model-square/);
assert.doesNotMatch(sourceFiles.terminalChrome, /MODEL_SQUARE_LINK|modelSquare|model-square/);