diff --git a/package.json b/package.json index 7759cad..5a47882 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,8 @@ "electron-store": "^8.1.0", "electron-updater": "^6.1.7", "font-list": "^1.5.1", - "netease-cloud-music-api-alger": "^4.25.0" + "netease-cloud-music-api-alger": "^4.25.0", + "vue-i18n": "9" }, "devDependencies": { "@electron-toolkit/eslint-config": "^1.0.2", diff --git a/src/i18n/lang/en-US.ts b/src/i18n/lang/en-US.ts new file mode 100644 index 0000000..17b0a7a --- /dev/null +++ b/src/i18n/lang/en-US.ts @@ -0,0 +1,29 @@ +export default { + common: { + play: 'Play', + pause: 'Pause', + next: 'Next', + previous: 'Previous', + volume: 'Volume', + settings: 'Settings', + search: 'Search', + loading: 'Loading...' + }, + settings: { + theme: 'Theme', + language: 'Language', + about: 'About', + logout: 'Logout' + }, + player: { + nowPlaying: 'Now Playing', + playlist: 'Playlist', + lyrics: 'Lyrics' + }, + artist: { + songs: 'Songs', + albums: 'Albums', + mv: 'MV', + description: 'Description' + } +}; diff --git a/src/i18n/lang/zh-CN.ts b/src/i18n/lang/zh-CN.ts new file mode 100644 index 0000000..e7239d5 --- /dev/null +++ b/src/i18n/lang/zh-CN.ts @@ -0,0 +1,35 @@ +export default { + common: { + play: '播放', + next: '下一首', + previous: '上一首', + volume: '音量', + settings: '设置', + search: '搜索', + loading: '加载中...', + alipay: '支付宝', + wechat: '微信支付' + }, + settings: { + theme: '主题', + language: '语言', + about: '关于', + logout: '退出登录' + }, + player: { + nowPlaying: '正在播放', + playlist: '播放列表', + lyrics: '歌词' + }, + artist: { + songs: '热门歌曲', + albums: '专辑', + mv: 'MV', + description: '简介' + }, + donation: { + description: '您的捐赠将用于支持开发和维护工作,包括但不限于服务器维护、域名续费等。', + message: '留言时可留下您的邮箱或 github名称。', + refresh: '刷新列表' + } +}; diff --git a/src/i18n/main.ts b/src/i18n/main.ts new file mode 100644 index 0000000..73e29f8 --- /dev/null +++ b/src/i18n/main.ts @@ -0,0 +1,28 @@ +import type { I18nOptions } from 'vue-i18n'; +import { createI18n } from 'vue-i18n'; + +import { getStore } from '../main/modules/config'; +import enUS from './lang/en-US'; +import zhCN from './lang/zh-CN'; + +// 从配置中获取保存的语言设置 +const store = getStore(); +const savedLanguage = (store?.get('set.language') as string) || 'zh-CN'; + +const options = { + legacy: false, + locale: savedLanguage, + fallbackLocale: 'en-US', + messages: { + 'zh-CN': zhCN, + 'en-US': enUS + }, + silentTranslationWarn: true, + silentFallbackWarn: true +} as I18nOptions; + +const i18n = createI18n(options); + +export const $t: typeof i18n.global.t = i18n.global.t; + +export default i18n; diff --git a/src/i18n/renderer.ts b/src/i18n/renderer.ts new file mode 100644 index 0000000..0521055 --- /dev/null +++ b/src/i18n/renderer.ts @@ -0,0 +1,26 @@ +import type { I18nOptions } from 'vue-i18n'; +import { createI18n } from 'vue-i18n'; + +import enUS from './lang/en-US'; +import zhCN from './lang/zh-CN'; + +// 从配置中获取保存的语言设置 +const savedLanguage = + window?.electron?.ipcRenderer?.sendSync('get-store-value', 'set.language') || 'zh-CN'; + +const options = { + legacy: false, + locale: savedLanguage, + fallbackLocale: 'en-US', + messages: { + 'zh-CN': zhCN, + 'en-US': enUS + }, + globalInjection: true, + silentTranslationWarn: true, + silentFallbackWarn: true +} as I18nOptions; + +const i18n = createI18n(options); + +export default i18n; diff --git a/src/main/index.ts b/src/main/index.ts index f82b78e..3023695 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -2,6 +2,7 @@ import { electronApp, optimizer } from '@electron-toolkit/utils'; import { app, ipcMain, nativeImage } from 'electron'; import { join } from 'path'; +import i18n from '../i18n/main'; import { loadLyricWindow } from './lyric'; import { initializeConfig } from './modules/config'; import { initializeFileManager } from './modules/fileManager'; @@ -95,6 +96,13 @@ if (!isSingleInstance) { registerShortcuts(mainWindow); }); + // 监听语言切换 + ipcMain.on('change-language', (_, locale) => { + i18n.global.locale = locale; + // 通知所有窗口语言已更改 + mainWindow?.webContents.send('language-changed', locale); + }); + // 所有窗口关闭时的处理 app.on('window-all-closed', () => { if (process.platform !== 'darwin') { diff --git a/src/main/modules/config.ts b/src/main/modules/config.ts index bb8348f..f406785 100644 --- a/src/main/modules/config.ts +++ b/src/main/modules/config.ts @@ -23,6 +23,7 @@ type SetConfig = { musicQuality: string; fontFamily: string; fontScope: 'global' | 'lyric'; + language: string; }; interface StoreType { set: SetConfig; diff --git a/src/main/set.json b/src/main/set.json index 05dbb39..94d9657 100644 --- a/src/main/set.json +++ b/src/main/set.json @@ -18,5 +18,6 @@ "fontFamily": "system-ui", "fontScope": "global", "autoPlay": false, - "downloadPath": "" + "downloadPath": "", + "language": "zh-CN" } diff --git a/src/renderer/components/LanguageSwitcher.vue b/src/renderer/components/LanguageSwitcher.vue new file mode 100644 index 0000000..107bab8 --- /dev/null +++ b/src/renderer/components/LanguageSwitcher.vue @@ -0,0 +1,36 @@ + + + diff --git a/src/renderer/components/common/ArtistDrawer.vue b/src/renderer/components/common/ArtistDrawer.vue index 8e3605f..66459b2 100644 --- a/src/renderer/components/common/ArtistDrawer.vue +++ b/src/renderer/components/common/ArtistDrawer.vue @@ -33,7 +33,7 @@ - +
@@ -44,14 +44,14 @@ :list="true" @play="handlePlay" /> -
加载中...
+
{{ $t('common.loading') }}
- +
@@ -69,14 +69,14 @@ type: '专辑' }" /> -
加载中...
+
{{ $t('common.loading') }}
- +
diff --git a/src/renderer/components/common/DonationList.vue b/src/renderer/components/common/DonationList.vue index 2e43ea9..e61282c 100644 --- a/src/renderer/components/common/DonationList.vue +++ b/src/renderer/components/common/DonationList.vue @@ -5,7 +5,7 @@ - 刷新列表 + {{ $t('donation.refresh') }}
@@ -78,27 +78,27 @@
-

您的捐赠将用于支持开发和维护工作,包括但不限于服务器维护、域名续费等。

-

留言时可留下您的邮箱或 github名称。

+

{{ $t('donation.description') }}

+

{{ $t('donation.message') }}

- 支付宝 + {{ $t('common.alipay') }}
- 微信支付 + {{ $t('common.wechat') }}
diff --git a/src/renderer/main.ts b/src/renderer/main.ts index e0d2fce..f931e0d 100644 --- a/src/renderer/main.ts +++ b/src/renderer/main.ts @@ -7,6 +7,7 @@ import 'remixicon/fonts/remixicon.css'; import { createApp } from 'vue'; +import i18n from '@/../i18n/renderer'; import router from '@/router'; import store from '@/store'; @@ -18,6 +19,8 @@ const app = createApp(App); Object.keys(directives).forEach((key: string) => { app.directive(key, directives[key as keyof typeof directives]); }); + app.use(router); app.use(store); +app.use(i18n); app.mount('#app'); diff --git a/tsconfig.node.json b/tsconfig.node.json index db23a68..e277186 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -1,6 +1,6 @@ { "extends": "@electron-toolkit/tsconfig/tsconfig.node.json", - "include": ["electron.vite.config.*", "src/main/**/*", "src/preload/**/*"], + "include": ["electron.vite.config.*", "src/main/**/*", "src/preload/**/*", "src/i18n/**/*"], "compilerOptions": { "composite": true, "types": ["electron-vite/node"] diff --git a/tsconfig.web.json b/tsconfig.web.json index ceaa995..ecb6e4c 100644 --- a/tsconfig.web.json +++ b/tsconfig.web.json @@ -3,7 +3,10 @@ "include": [ "src/preload/*.d.ts", "src/renderer/**/*", - "src/renderer/**/*.vue" + "src/renderer/**/*.vue", + "src/i18n/**/*", + "src/main/modules/config.ts", + "src/main/modules/shortcuts.ts" ], "compilerOptions": { "composite": true, @@ -24,7 +27,8 @@ ], "paths": { "@/*": ["src/renderer/*"], - "@renderer/*": ["src/renderer/*"] + "@renderer/*": ["src/renderer/*"], + "@main/*": ["src/main/*"] } } }