mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-04-03 14:20:50 +08:00
✨ feat: 国际化功能基础实现
This commit is contained in:
@@ -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",
|
||||
|
||||
29
src/i18n/lang/en-US.ts
Normal file
29
src/i18n/lang/en-US.ts
Normal file
@@ -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'
|
||||
}
|
||||
};
|
||||
35
src/i18n/lang/zh-CN.ts
Normal file
35
src/i18n/lang/zh-CN.ts
Normal file
@@ -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: '刷新列表'
|
||||
}
|
||||
};
|
||||
28
src/i18n/main.ts
Normal file
28
src/i18n/main.ts
Normal file
@@ -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;
|
||||
26
src/i18n/renderer.ts
Normal file
26
src/i18n/renderer.ts
Normal file
@@ -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 { 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') {
|
||||
|
||||
@@ -23,6 +23,7 @@ type SetConfig = {
|
||||
musicQuality: string;
|
||||
fontFamily: string;
|
||||
fontScope: 'global' | 'lyric';
|
||||
language: string;
|
||||
};
|
||||
interface StoreType {
|
||||
set: SetConfig;
|
||||
|
||||
@@ -18,5 +18,6 @@
|
||||
"fontFamily": "system-ui",
|
||||
"fontScope": "global",
|
||||
"autoPlay": false,
|
||||
"downloadPath": ""
|
||||
"downloadPath": "",
|
||||
"language": "zh-CN"
|
||||
}
|
||||
|
||||
36
src/renderer/components/LanguageSwitcher.vue
Normal file
36
src/renderer/components/LanguageSwitcher.vue
Normal file
@@ -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-tab-pane name="songs" tab="热门歌曲">
|
||||
<n-tab-pane name="songs" :tab="$t('artist.songs')">
|
||||
<div ref="songListRef" class="songs-list">
|
||||
<n-scrollbar style="max-height: 61vh" :size="5" @scroll="handleSongScroll">
|
||||
<div class="song-list-content">
|
||||
@@ -44,14 +44,14 @@
|
||||
:list="true"
|
||||
@play="handlePlay"
|
||||
/>
|
||||
<div v-if="songLoading" class="loading-more">加载中...</div>
|
||||
<div v-if="songLoading" class="loading-more">{{ $t('common.loading') }}</div>
|
||||
</div>
|
||||
<play-bottom />
|
||||
</n-scrollbar>
|
||||
</div>
|
||||
</n-tab-pane>
|
||||
|
||||
<n-tab-pane name="albums" tab="专辑">
|
||||
<n-tab-pane name="albums" :tab="$t('artist.albums')">
|
||||
<div ref="albumListRef" class="albums-list">
|
||||
<n-scrollbar style="max-height: 61vh" :size="5" @scroll="handleAlbumScroll">
|
||||
<div class="albums-grid">
|
||||
@@ -69,14 +69,14 @@
|
||||
type: '专辑'
|
||||
}"
|
||||
/>
|
||||
<div v-if="albumLoading" class="loading-more">加载中...</div>
|
||||
<div v-if="albumLoading" class="loading-more">{{ $t('common.loading') }}</div>
|
||||
</div>
|
||||
<play-bottom />
|
||||
</n-scrollbar>
|
||||
</div>
|
||||
</n-tab-pane>
|
||||
|
||||
<n-tab-pane name="about" tab="艺人介绍">
|
||||
<n-tab-pane name="about" :tab="$t('artist.description')">
|
||||
<div class="artist-description">
|
||||
<n-scrollbar style="max-height: 60vh">
|
||||
<div class="description-content" v-html="artistInfo?.briefDesc"></div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<template #icon>
|
||||
<i class="ri-refresh-line"></i>
|
||||
</template>
|
||||
刷新列表
|
||||
{{ $t('donation.refresh') }}
|
||||
</n-button>
|
||||
</div>
|
||||
<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="description text-center text-sm text-gray-700 dark:text-gray-200">
|
||||
<p>您的捐赠将用于支持开发和维护工作,包括但不限于服务器维护、域名续费等。</p>
|
||||
<p>留言时可留下您的邮箱或 github名称。</p>
|
||||
<p>{{ $t('donation.description') }}</p>
|
||||
<p>{{ $t('donation.message') }}</p>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<div class="flex flex-col items-center gap-2">
|
||||
<n-image
|
||||
:src="alipay"
|
||||
alt="支付宝收款码"
|
||||
:alt="$t('common.alipay')"
|
||||
class="w-60 h-60 rounded-lg cursor-none"
|
||||
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 class="flex flex-col items-center gap-2">
|
||||
<n-image
|
||||
:src="wechat"
|
||||
alt="微信收款码"
|
||||
:alt="$t('common.wechat')"
|
||||
class="w-60 h-60 rounded-lg cursor-none"
|
||||
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>
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user