diff --git a/game-studio/index.html b/game-studio/index.html index 80343ebe..6a2f88f2 100644 --- a/game-studio/index.html +++ b/game-studio/index.html @@ -1,10 +1,21 @@ - + - - game-studio + + 造梦AI + +
diff --git a/game-studio/package.json b/game-studio/package.json index e465cf1b..0dc242f1 100644 --- a/game-studio/package.json +++ b/game-studio/package.json @@ -13,6 +13,7 @@ "pinia": "^3.0.4", "vant": "^4.9.24", "vue": "^3.5.34", + "vue-i18n": "^10.0.0", "vue-router": "^4.6.4" }, "devDependencies": { diff --git a/game-studio/src/composables/useAppearance.ts b/game-studio/src/composables/useAppearance.ts new file mode 100644 index 00000000..bfd7fd73 --- /dev/null +++ b/game-studio/src/composables/useAppearance.ts @@ -0,0 +1,64 @@ +/** + * 外观(主题 + 语言)统一管理:持久化 + 同步 + i18n locale 切换。 + * 全局单例响应式状态,多组件共享(设置页切换 → 全局即时生效)。 + * 与 index.html 的防闪烁脚本配套:脚本在首屏前先设属性,本模块在挂载前 initAppearance() 再对齐 i18n。 + */ +import { ref } from 'vue' +import { i18n } from '../i18n' + +export type ThemeMode = 'dark' | 'light' | 'dim' +export type LangCode = 'zh-CN' | 'en-US' + +const THEME_KEY = 'studio.theme' +const LANG_KEY = 'studio.lang' + +// 读持久化主题(隐私模式 localStorage 抛错时回落暗色) +function readTheme(): ThemeMode { + try { + const v = localStorage.getItem(THEME_KEY) + if (v === 'dark' || v === 'light' || v === 'dim') return v + } catch { /* 忽略 */ } + return 'dark' +} +function readLang(): LangCode { + try { + const v = localStorage.getItem(LANG_KEY) + if (v === 'zh-CN' || v === 'en-US') return v + } catch { /* 忽略 */ } + return 'zh-CN' +} + +// 全局单例(模块级,跨组件共享同一引用) +const theme = ref(readTheme()) +const lang = ref(readLang()) + +// 暗色为默认(:root),不写 data-theme;浅/柔写属性触发语义层覆盖 +function applyTheme(t: ThemeMode): void { + const el = document.documentElement + if (t === 'dark') el.removeAttribute('data-theme') + else el.setAttribute('data-theme', t) +} +function applyLang(l: LangCode): void { + document.documentElement.setAttribute('lang', l) + i18n.global.locale.value = l +} + +export function useAppearance() { + function setTheme(t: ThemeMode): void { + theme.value = t + try { localStorage.setItem(THEME_KEY, t) } catch { /* 忽略 */ } + applyTheme(t) + } + function setLang(l: LangCode): void { + lang.value = l + try { localStorage.setItem(LANG_KEY, l) } catch { /* 忽略 */ } + applyLang(l) + } + return { theme, lang, setTheme, setLang } +} + +// main.ts 挂载前调用一次:把持久化外观应用到 DOM + i18n +export function initAppearance(): void { + applyTheme(theme.value) + applyLang(lang.value) +} diff --git a/game-studio/src/i18n/index.ts b/game-studio/src/i18n/index.ts new file mode 100644 index 00000000..190ff328 --- /dev/null +++ b/game-studio/src/i18n/index.ts @@ -0,0 +1,18 @@ +/** + * vue-i18n 初始化(组合式 API,legacy:false)。 + * zh-CN 为基线;缺 key 回落 zh-CN。实际生效语言由 useAppearance.initAppearance() + * 在挂载前从持久化读取并应用(与 index.html 防闪烁脚本一致)。 + */ +import { createI18n } from 'vue-i18n' +import zhCN from '../locales/zh-CN' +import enUS from '../locales/en-US' + +export const i18n = createI18n({ + legacy: false, // 组合式 API(useI18n / $t),关闭 legacy 选项式 + globalInjection: true, // 模板内可直接用 $t + locale: 'zh-CN', + fallbackLocale: 'zh-CN', + messages: { 'zh-CN': zhCN, 'en-US': enUS }, +}) + +export default i18n diff --git a/game-studio/src/locales/en-US.ts b/game-studio/src/locales/en-US.ts new file mode 100644 index 00000000..81bd5518 --- /dev/null +++ b/game-studio/src/locales/en-US.ts @@ -0,0 +1,17 @@ +/** + * 英文文案(与 zh-CN 同构)。缺 key 时由 i18n 回落 zh-CN。 + */ +export default { + common: { + brand: 'ZaoMeng AI', + nav: { feed: 'Feed', create: 'Create', message: 'Inbox', me: 'Me', discover: 'Discover' }, + action: { play: 'Play now', share: 'Share', save: 'Save', submit: 'Submit', cancel: 'Cancel', confirm: 'Confirm', back: 'Back', retry: 'Retry', more: 'More' }, + state: { loading: 'Loading', empty: 'Nothing here yet', saved: 'Saved', failed: 'Failed', success: 'Success' }, + status: { draft: 'Draft', review: 'In review', published: 'Published', rejected: 'Rejected' }, + }, + appearance: { + title: 'Appearance', + theme: 'Theme', themeDark: 'Dark', themeLight: 'Light', themeDim: 'Dim', + language: 'Language', langZh: '中文', langEn: 'English', + }, +} diff --git a/game-studio/src/locales/zh-CN.ts b/game-studio/src/locales/zh-CN.ts new file mode 100644 index 00000000..a01cf13a --- /dev/null +++ b/game-studio/src/locales/zh-CN.ts @@ -0,0 +1,18 @@ +/** + * 中文(基线)文案。命名空间:common 通用 / appearance 外观设置。 + * P4 起按页域增 feed / create / profile 等命名空间;新组件文案一律走此处,禁裸中文。 + */ +export default { + common: { + brand: '造梦AI', + nav: { feed: '游戏流', create: '创作', message: '消息', me: '我的', discover: '发现' }, + action: { play: '立即玩', share: '分享', save: '保存', submit: '提交', cancel: '取消', confirm: '确定', back: '返回', retry: '重试', more: '更多' }, + state: { loading: '加载中', empty: '这里还没有内容', saved: '已保存', failed: '失败', success: '成功' }, + status: { draft: '草稿', review: '审核中', published: '已发布', rejected: '已驳回' }, + }, + appearance: { + title: '外观', + theme: '主题', themeDark: '暗色', themeLight: '浅色', themeDim: '柔和', + language: '语言', langZh: '中文', langEn: 'English', + }, +} diff --git a/game-studio/src/main.ts b/game-studio/src/main.ts index 217ad9e1..e410fe92 100644 --- a/game-studio/src/main.ts +++ b/game-studio/src/main.ts @@ -16,11 +16,19 @@ import App from './App.vue' import router from './router' import { pinia } from './store' +// —— i18n(中英双语)+ 外观(主题/语言)初始化 —— +import i18n from './i18n' +import { initAppearance } from './composables/useAppearance' + const app = createApp(App) // 注册顺序:Pinia(状态)→ Router(路由)→ Vant(UI 组件 + 指令) app.use(pinia) app.use(router) app.use(Vant) +app.use(i18n) + +// 挂载前应用持久化的主题/语言到 DOM 与 i18n(防首屏不一致/闪烁) +initAppearance() app.mount('#app')