mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-04-24 16:27:23 +08:00
✨ feat: 国际化功能基础实现
This commit is contained in:
+2
-1
@@ -27,7 +27,8 @@
|
|||||||
"electron-store": "^8.1.0",
|
"electron-store": "^8.1.0",
|
||||||
"electron-updater": "^6.1.7",
|
"electron-updater": "^6.1.7",
|
||||||
"font-list": "^1.5.1",
|
"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": {
|
"devDependencies": {
|
||||||
"@electron-toolkit/eslint-config": "^1.0.2",
|
"@electron-toolkit/eslint-config": "^1.0.2",
|
||||||
|
|||||||
@@ -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'
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -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: '刷新列表'
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -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;
|
||||||
@@ -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;
|
||||||
@@ -2,6 +2,7 @@ import { electronApp, optimizer } from '@electron-toolkit/utils';
|
|||||||
import { app, ipcMain, nativeImage } from 'electron';
|
import { app, ipcMain, nativeImage } from 'electron';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
|
||||||
|
import i18n from '../i18n/main';
|
||||||
import { loadLyricWindow } from './lyric';
|
import { loadLyricWindow } from './lyric';
|
||||||
import { initializeConfig } from './modules/config';
|
import { initializeConfig } from './modules/config';
|
||||||
import { initializeFileManager } from './modules/fileManager';
|
import { initializeFileManager } from './modules/fileManager';
|
||||||
@@ -95,6 +96,13 @@ if (!isSingleInstance) {
|
|||||||
registerShortcuts(mainWindow);
|
registerShortcuts(mainWindow);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 监听语言切换
|
||||||
|
ipcMain.on('change-language', (_, locale) => {
|
||||||
|
i18n.global.locale = locale;
|
||||||
|
// 通知所有窗口语言已更改
|
||||||
|
mainWindow?.webContents.send('language-changed', locale);
|
||||||
|
});
|
||||||
|
|
||||||
// 所有窗口关闭时的处理
|
// 所有窗口关闭时的处理
|
||||||
app.on('window-all-closed', () => {
|
app.on('window-all-closed', () => {
|
||||||
if (process.platform !== 'darwin') {
|
if (process.platform !== 'darwin') {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ type SetConfig = {
|
|||||||
musicQuality: string;
|
musicQuality: string;
|
||||||
fontFamily: string;
|
fontFamily: string;
|
||||||
fontScope: 'global' | 'lyric';
|
fontScope: 'global' | 'lyric';
|
||||||
|
language: string;
|
||||||
};
|
};
|
||||||
interface StoreType {
|
interface StoreType {
|
||||||
set: SetConfig;
|
set: SetConfig;
|
||||||
|
|||||||
+2
-1
@@ -18,5 +18,6 @@
|
|||||||
"fontFamily": "system-ui",
|
"fontFamily": "system-ui",
|
||||||
"fontScope": "global",
|
"fontScope": "global",
|
||||||
"autoPlay": false,
|
"autoPlay": false,
|
||||||
"downloadPath": ""
|
"downloadPath": "",
|
||||||
|
"language": "zh-CN"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { onMounted } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
const { locale } = useI18n();
|
||||||
|
|
||||||
|
const languages = [
|
||||||
|
{ label: '简体中文', value: 'zh-CN' },
|
||||||
|
{ label: 'English', value: 'en-US' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// 从配置中读取语言设置
|
||||||
|
onMounted(() => {
|
||||||
|
const savedLanguage = window.electron.ipcRenderer.sendSync('get-store-value', 'set.language');
|
||||||
|
if (savedLanguage) {
|
||||||
|
locale.value = savedLanguage;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleLanguageChange = (value: string) => {
|
||||||
|
locale.value = value;
|
||||||
|
// 保存语言设置到配置中
|
||||||
|
window.electron.ipcRenderer.send('set-store-value', 'set.language', value);
|
||||||
|
// 通知主进程语言已更改
|
||||||
|
window.electron.ipcRenderer.send('change-language', value);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<n-select
|
||||||
|
v-model:value="locale"
|
||||||
|
:options="languages"
|
||||||
|
size="small"
|
||||||
|
@update:value="handleLanguageChange"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
<!-- 标签页切换 -->
|
<!-- 标签页切换 -->
|
||||||
<n-tabs v-model:value="activeTab" class="flex-1" type="line" animated>
|
<n-tabs v-model:value="activeTab" class="flex-1" type="line" animated>
|
||||||
<n-tab-pane name="songs" tab="热门歌曲">
|
<n-tab-pane name="songs" :tab="$t('artist.songs')">
|
||||||
<div ref="songListRef" class="songs-list">
|
<div ref="songListRef" class="songs-list">
|
||||||
<n-scrollbar style="max-height: 61vh" :size="5" @scroll="handleSongScroll">
|
<n-scrollbar style="max-height: 61vh" :size="5" @scroll="handleSongScroll">
|
||||||
<div class="song-list-content">
|
<div class="song-list-content">
|
||||||
@@ -44,14 +44,14 @@
|
|||||||
:list="true"
|
:list="true"
|
||||||
@play="handlePlay"
|
@play="handlePlay"
|
||||||
/>
|
/>
|
||||||
<div v-if="songLoading" class="loading-more">加载中...</div>
|
<div v-if="songLoading" class="loading-more">{{ $t('common.loading') }}</div>
|
||||||
</div>
|
</div>
|
||||||
<play-bottom />
|
<play-bottom />
|
||||||
</n-scrollbar>
|
</n-scrollbar>
|
||||||
</div>
|
</div>
|
||||||
</n-tab-pane>
|
</n-tab-pane>
|
||||||
|
|
||||||
<n-tab-pane name="albums" tab="专辑">
|
<n-tab-pane name="albums" :tab="$t('artist.albums')">
|
||||||
<div ref="albumListRef" class="albums-list">
|
<div ref="albumListRef" class="albums-list">
|
||||||
<n-scrollbar style="max-height: 61vh" :size="5" @scroll="handleAlbumScroll">
|
<n-scrollbar style="max-height: 61vh" :size="5" @scroll="handleAlbumScroll">
|
||||||
<div class="albums-grid">
|
<div class="albums-grid">
|
||||||
@@ -69,14 +69,14 @@
|
|||||||
type: '专辑'
|
type: '专辑'
|
||||||
}"
|
}"
|
||||||
/>
|
/>
|
||||||
<div v-if="albumLoading" class="loading-more">加载中...</div>
|
<div v-if="albumLoading" class="loading-more">{{ $t('common.loading') }}</div>
|
||||||
</div>
|
</div>
|
||||||
<play-bottom />
|
<play-bottom />
|
||||||
</n-scrollbar>
|
</n-scrollbar>
|
||||||
</div>
|
</div>
|
||||||
</n-tab-pane>
|
</n-tab-pane>
|
||||||
|
|
||||||
<n-tab-pane name="about" tab="艺人介绍">
|
<n-tab-pane name="about" :tab="$t('artist.description')">
|
||||||
<div class="artist-description">
|
<div class="artist-description">
|
||||||
<n-scrollbar style="max-height: 60vh">
|
<n-scrollbar style="max-height: 60vh">
|
||||||
<div class="description-content" v-html="artistInfo?.briefDesc"></div>
|
<div class="description-content" v-html="artistInfo?.briefDesc"></div>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<template #icon>
|
<template #icon>
|
||||||
<i class="ri-refresh-line"></i>
|
<i class="ri-refresh-line"></i>
|
||||||
</template>
|
</template>
|
||||||
刷新列表
|
{{ $t('donation.refresh') }}
|
||||||
</n-button>
|
</n-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="donation-grid" :class="{ 'grid-expanded': isExpanded }">
|
<div class="donation-grid" :class="{ 'grid-expanded': isExpanded }">
|
||||||
@@ -78,27 +78,27 @@
|
|||||||
|
|
||||||
<div class="p-6 rounded-lg shadow-lg bg-light dark:bg-gray-800">
|
<div class="p-6 rounded-lg shadow-lg bg-light dark:bg-gray-800">
|
||||||
<div class="description text-center text-sm text-gray-700 dark:text-gray-200">
|
<div class="description text-center text-sm text-gray-700 dark:text-gray-200">
|
||||||
<p>您的捐赠将用于支持开发和维护工作,包括但不限于服务器维护、域名续费等。</p>
|
<p>{{ $t('donation.description') }}</p>
|
||||||
<p>留言时可留下您的邮箱或 github名称。</p>
|
<p>{{ $t('donation.message') }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<div class="flex flex-col items-center gap-2">
|
<div class="flex flex-col items-center gap-2">
|
||||||
<n-image
|
<n-image
|
||||||
:src="alipay"
|
:src="alipay"
|
||||||
alt="支付宝收款码"
|
:alt="$t('common.alipay')"
|
||||||
class="w-60 h-60 rounded-lg cursor-none"
|
class="w-60 h-60 rounded-lg cursor-none"
|
||||||
preview-disabled
|
preview-disabled
|
||||||
/>
|
/>
|
||||||
<span class="text-sm text-gray-700 dark:text-gray-200">支付宝</span>
|
<span class="text-sm text-gray-700 dark:text-gray-200">{{ $t('common.alipay') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col items-center gap-2">
|
<div class="flex flex-col items-center gap-2">
|
||||||
<n-image
|
<n-image
|
||||||
:src="wechat"
|
:src="wechat"
|
||||||
alt="微信收款码"
|
:alt="$t('common.wechat')"
|
||||||
class="w-60 h-60 rounded-lg cursor-none"
|
class="w-60 h-60 rounded-lg cursor-none"
|
||||||
preview-disabled
|
preview-disabled
|
||||||
/>
|
/>
|
||||||
<span class="text-sm text-gray-700 dark:text-gray-200">微信支付</span>
|
<span class="text-sm text-gray-700 dark:text-gray-200">{{ $t('common.wechat') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import 'remixicon/fonts/remixicon.css';
|
|||||||
|
|
||||||
import { createApp } from 'vue';
|
import { createApp } from 'vue';
|
||||||
|
|
||||||
|
import i18n from '@/../i18n/renderer';
|
||||||
import router from '@/router';
|
import router from '@/router';
|
||||||
import store from '@/store';
|
import store from '@/store';
|
||||||
|
|
||||||
@@ -18,6 +19,8 @@ const app = createApp(App);
|
|||||||
Object.keys(directives).forEach((key: string) => {
|
Object.keys(directives).forEach((key: string) => {
|
||||||
app.directive(key, directives[key as keyof typeof directives]);
|
app.directive(key, directives[key as keyof typeof directives]);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.use(router);
|
app.use(router);
|
||||||
app.use(store);
|
app.use(store);
|
||||||
|
app.use(i18n);
|
||||||
app.mount('#app');
|
app.mount('#app');
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"extends": "@electron-toolkit/tsconfig/tsconfig.node.json",
|
"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": {
|
"compilerOptions": {
|
||||||
"composite": true,
|
"composite": true,
|
||||||
"types": ["electron-vite/node"]
|
"types": ["electron-vite/node"]
|
||||||
|
|||||||
+6
-2
@@ -3,7 +3,10 @@
|
|||||||
"include": [
|
"include": [
|
||||||
"src/preload/*.d.ts",
|
"src/preload/*.d.ts",
|
||||||
"src/renderer/**/*",
|
"src/renderer/**/*",
|
||||||
"src/renderer/**/*.vue"
|
"src/renderer/**/*.vue",
|
||||||
|
"src/i18n/**/*",
|
||||||
|
"src/main/modules/config.ts",
|
||||||
|
"src/main/modules/shortcuts.ts"
|
||||||
],
|
],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"composite": true,
|
"composite": true,
|
||||||
@@ -24,7 +27,8 @@
|
|||||||
],
|
],
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["src/renderer/*"],
|
"@/*": ["src/renderer/*"],
|
||||||
"@renderer/*": ["src/renderer/*"]
|
"@renderer/*": ["src/renderer/*"],
|
||||||
|
"@main/*": ["src/main/*"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user