chore: rebrand product as 省心推 and lock UI to zh-CN

Update server titles, web/desktop window/tray/document titles, login
copy, and electron build metadata to use the Chinese product name 省心推.
Drop the runtime locale switcher and en-US import — the app now ships
zh-CN only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-01 11:03:55 +08:00
parent dca36ed1f6
commit 5a613abc33
16 changed files with 25 additions and 128 deletions
+1 -1
View File
@@ -6,7 +6,7 @@
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>GEO 工具平台</title>
<title>省心推</title>
</head>
<body>
<div id="app"></div>
+1 -7
View File
@@ -1,18 +1,12 @@
<script setup lang="ts">
import enUS from "ant-design-vue/es/locale/en_US";
import zhCN from "ant-design-vue/es/locale/zh_CN";
import { computed } from "vue";
import { useI18n } from "vue-i18n";
import ImageUploadProgressOverlay from "@/components/ImageUploadProgressOverlay.vue";
const { locale } = useI18n();
const antLocale = computed(() => (locale.value === "en-US" ? enUS : zhCN));
</script>
<template>
<a-config-provider
:locale="antLocale"
:locale="zhCN"
:theme="{
token: {
colorPrimary: '#1677ff',
+3 -33
View File
@@ -1,44 +1,14 @@
import { createI18n } from "vue-i18n";
import enUS from "./messages/en-US";
import zhCN from "./messages/zh-CN";
export const LOCALE_STORAGE_KEY = "geo.admin.locale";
export const SUPPORTED_LOCALES = ["zh-CN", "en-US"] as const;
export type AppLocale = (typeof SUPPORTED_LOCALES)[number];
function resolveLocale(): AppLocale {
if (typeof window === "undefined") {
return "zh-CN";
}
const stored = window.localStorage.getItem(LOCALE_STORAGE_KEY);
if (stored && SUPPORTED_LOCALES.includes(stored as AppLocale)) {
return stored as AppLocale;
}
const browserLocale = window.navigator.language;
if (browserLocale.startsWith("zh")) {
return "zh-CN";
}
return "en-US";
}
const APP_LOCALE = "zh-CN";
export const i18n = createI18n({
legacy: false,
locale: resolveLocale(),
fallbackLocale: "en-US",
locale: APP_LOCALE,
fallbackLocale: APP_LOCALE,
messages: {
"zh-CN": zhCN,
"en-US": enUS,
},
});
export function setAppLocale(locale: AppLocale): void {
i18n.global.locale.value = locale;
if (typeof window !== "undefined") {
window.localStorage.setItem(LOCALE_STORAGE_KEY, locale);
}
}
+3 -3
View File
@@ -1,7 +1,7 @@
const zhCN = {
app: {
name: "GEO工具平台",
loginIntro: "面向企业的品牌资产管理与内容生产协作系统",
name: "省心推",
loginIntro: "面向企业和个人的品牌资产管理与内容生产协作系统",
},
locale: {
"zh-CN": "中文简体",
@@ -153,7 +153,7 @@ const zhCN = {
route: {
login: {
title: "欢迎回来",
description: "使用真实租户账号登录 GEO 工具平台。",
description: "登录省心推,开启品牌内容创作之旅",
},
workspace: {
title: "工作台",
-68
View File
@@ -16,7 +16,6 @@ import { useRoute, useRouter } from "vue-router";
import { useI18n } from "vue-i18n";
import { workspaceApi } from "@/lib/api";
import { type AppLocale, setAppLocale } from "@/i18n";
import { useAuthStore } from "@/stores/auth";
const route = useRoute();
@@ -86,22 +85,6 @@ type NavSection = {
items: NavItem[];
};
const localeOptions = computed(() => [
{ label: t("locale.zh-CN"), value: "zh-CN" },
{ label: t("locale.en-US"), value: "en-US" },
]);
const currentLocale = computed({
get: () => locale.value as AppLocale,
set: (value: AppLocale) => {
setAppLocale(value);
},
});
const currentLocaleLabel = computed(() => {
return localeOptions.value.find((opt) => opt.value === currentLocale.value)?.label ?? "Language";
});
const navSections = computed<NavSection[]>(() => {
const base = [
{
@@ -220,10 +203,6 @@ function go(path: string): void {
void router.push(path);
}
function handleLocaleChange({ key }: { key: any }): void {
currentLocale.value = key as AppLocale;
}
async function handleLogout(): Promise<void> {
await authStore.logout();
await router.replace("/login");
@@ -298,22 +277,6 @@ async function handleLogout(): Promise<void> {
</nav>
<div class="admin-header-actions">
<div v-if="!isMembershipBlocked" class="admin-locale-switch">
<a-dropdown placement="bottomRight" :trigger="['click', 'hover']">
<div class="locale-dropdown-trigger">
<GlobalOutlined class="locale-icon" />
<span>{{ currentLocaleLabel }}</span>
</div>
<template #overlay>
<a-menu :selected-keys="[currentLocale]" @click="handleLocaleChange">
<a-menu-item v-for="opt in localeOptions" :key="opt.value">
{{ opt.label }}
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</div>
<!-- Quota Indicator -->
<div v-if="!isMembershipBlocked" class="quota-pill">
<a-tag color="blue" :bordered="false" class="quota-pill-tag">{{ quotaSummary?.plan_name || t("shell.planFallback") }}</a-tag>
@@ -487,37 +450,6 @@ async function handleLogout(): Promise<void> {
margin-left: auto;
}
.admin-locale-switch {
display: flex;
align-items: center;
}
.admin-locale-select {
width: 100px;
}
.locale-dropdown-trigger {
display: flex;
align-items: center;
gap: 6px;
padding: 4px 10px;
height: 32px;
border-radius: 6px;
cursor: pointer;
transition: all 0.2s;
font-size: 14px;
color: #141414;
}
.locale-dropdown-trigger:hover {
background: #f5f5f5;
}
.locale-icon {
font-size: 16px;
color: #595959;
}
.quota-pill {
display: flex;
align-items: center;