From c219edb037e6073c4c97d923501990c620480da6 Mon Sep 17 00:00:00 2001
From: fspecii <4722521+fspecii@users.noreply.github.com>
Date: Sun, 8 Feb 2026 18:19:08 +0200
Subject: [PATCH] Add i18n system with 4-language support (en/zh/ja/ko)
- Add I18nContext provider with useI18n hook and localStorage persistence
- Add translations.ts with complete strings for English, Chinese, Japanese, Korean
- Wrap App in I18nProvider, replace hardcoded toast messages with t() calls
- Add language selector to SettingsModal with Globe icon
- Add localization credits in About section
- Default language: English
- Add I18N_USAGE.md documentation
---
App.tsx | 48 +-
I18N_USAGE.md | 61 +
components/SettingsModal.tsx | 141 +-
context/I18nContext.tsx | 40 +
i18n/translations.ts | 2361 ++++++++++++++++++++++++++++++++++
5 files changed, 2591 insertions(+), 60 deletions(-)
create mode 100644 I18N_USAGE.md
create mode 100644 context/I18nContext.tsx
create mode 100644 i18n/translations.ts
diff --git a/App.tsx b/App.tsx
index 0f8bdfd..137f936 100644
--- a/App.tsx
+++ b/App.tsx
@@ -15,13 +15,17 @@ import { Song, GenerationParams, View, Playlist } from './types';
import { generateApi, songsApi, playlistsApi, getAudioUrl } from './services/api';
import { useAuth } from './context/AuthContext';
import { useResponsive } from './context/ResponsiveContext';
+import { I18nProvider, useI18n } from './context/I18nContext';
import { List } from 'lucide-react';
import { PlaylistDetail } from './components/PlaylistDetail';
import { Toast, ToastType } from './components/Toast';
import { SearchPage } from './components/SearchPage';
-export default function App() {
+function AppContent() {
+ // i18n
+ const { t } = useI18n();
+
// Responsive
const { isMobile, isDesktop } = useResponsive();
@@ -464,9 +468,9 @@ export default function App() {
if (audio.error && audio.error.code !== 1) {
console.error("Audio playback error:", audio.error);
if (audio.error.code === 4) {
- showToast('This song is no longer available.', 'error');
+ showToast(t('songNotAvailable'), 'error');
} else {
- showToast('Unable to play this song.', 'error');
+ showToast(t('unableToPlay'), 'error');
}
}
setIsPlaying(false);
@@ -502,7 +506,7 @@ export default function App() {
if (err instanceof Error && err.name !== 'AbortError') {
console.error("Playback failed:", err);
if (err.name === 'NotSupportedError') {
- showToast('This song is no longer available.', 'error');
+ showToast(t('songNotAvailable'), 'error');
}
setIsPlaying(false);
}
@@ -631,7 +635,7 @@ export default function App() {
} else if (status.status === 'failed') {
cleanupJob(jobId, tempId);
console.error(`Job ${jobId} failed:`, status.error);
- showToast(`Generation failed: ${status.error || 'Unknown error'}`, 'error');
+ showToast(`${t('generationFailed')}: ${status.error || 'Unknown error'}`, 'error');
}
} catch (pollError) {
console.error(`Polling error for job ${jobId}:`, pollError);
@@ -646,7 +650,7 @@ export default function App() {
if (activeJobsRef.current.has(jobId)) {
console.warn(`Job ${jobId} timed out`);
cleanupJob(jobId, tempId);
- showToast('Generation timed out', 'error');
+ showToast(t('generationTimedOut'), 'error');
}
}, 600000);
}, [token, cleanupJob, refreshSongsList]);
@@ -762,7 +766,7 @@ export default function App() {
if (activeJobsRef.current.size === 0) {
setIsGenerating(false);
}
- showToast('Generation failed. Please try again.', 'error');
+ showToast(t('generationFailed'), 'error');
}
};
@@ -946,10 +950,10 @@ export default function App() {
// Remove from play queue if present
setPlayQueue(prev => prev.filter(s => s.id !== song.id));
- showToast('Song deleted successfully');
+ showToast(t('songDeleted'));
} catch (error) {
console.error('Failed to delete song:', error);
- showToast('Failed to delete song', 'error');
+ showToast(t('failedToDeleteSong'), 'error');
}
};
@@ -1001,9 +1005,9 @@ export default function App() {
}
if (failed.length > 0) {
- showToast(`Deleted ${succeeded.length}/${songsToDelete.length} songs`, 'error');
+ showToast(t('songsDeletedPartial').replace('{succeeded}', String(succeeded.length)).replace('{total}', String(songsToDelete.length)), 'error');
} else {
- showToast('Songs deleted successfully');
+ showToast(t('songsDeletedSuccess'));
}
};
@@ -1020,10 +1024,10 @@ export default function App() {
throw new Error('Failed to delete upload');
}
setReferenceTracks(prev => prev.filter(track => track.id !== trackId));
- showToast('Upload deleted successfully');
+ showToast(t('songDeleted'));
} catch (error) {
console.error('Failed to delete upload:', error);
- showToast('Failed to delete upload', 'error');
+ showToast(t('failedToDeleteSong'), 'error');
}
};
@@ -1038,10 +1042,10 @@ export default function App() {
setSongToAddToPlaylist(null);
playlistsApi.getMyPlaylists(token).then(r => setPlaylists(r.playlists));
}
- showToast('Playlist created successfully!');
+ showToast(t('playlistCreated'));
} catch (error) {
console.error('Create playlist error:', error);
- showToast('Failed to create playlist', 'error');
+ showToast(t('failedToCreatePlaylist'), 'error');
}
};
@@ -1055,11 +1059,11 @@ export default function App() {
try {
await playlistsApi.addSong(playlistId, songToAddToPlaylist.id, token);
setSongToAddToPlaylist(null);
- showToast('Song added to playlist');
+ showToast(t('songAddedToPlaylist'));
playlistsApi.getMyPlaylists(token).then(r => setPlaylists(r.playlists));
} catch (error) {
console.error('Add song error:', error);
- showToast('Failed to add song to playlist', 'error');
+ showToast(t('failedToAddSong'), 'error');
}
};
@@ -1286,7 +1290,7 @@ export default function App() {
onClick={() => setMobileShowList(!mobileShowList)}
className="bg-zinc-800 text-white px-4 py-2 rounded-full shadow-lg border border-white/10 flex items-center gap-2 text-sm font-bold"
>
- {mobileShowList ? 'Create Song' : 'View List'}
+ {mobileShowList ? t('createSong') : t('viewList')}
@@ -1415,3 +1419,11 @@ export default function App() {
);
}
+
+export default function App() {
+ return (
+
+
+
+ );
+}
diff --git a/I18N_USAGE.md b/I18N_USAGE.md
new file mode 100644
index 0000000..e362ecb
--- /dev/null
+++ b/I18N_USAGE.md
@@ -0,0 +1,61 @@
+# ACE-Step UI — Internationalization Guide
+
+## Overview
+
+The project supports 4 languages: English (default), Chinese, Japanese, and Korean.
+
+## Architecture
+
+```
+ace-step-ui/
+├── i18n/
+│ └── translations.ts # All translation strings
+├── context/
+│ └── I18nContext.tsx # React context + useI18n hook
+└── components/ # i18n-enabled components
+```
+
+## Usage
+
+### 1. Use translations in a component
+
+```tsx
+import { useI18n } from '../context/I18nContext';
+
+function YourComponent() {
+ const { t } = useI18n();
+ return
{t('yourTranslationKey')}
;
+}
+```
+
+### 2. Switch language
+
+Users can switch language in Settings. Programmatically:
+
+```tsx
+const { language, setLanguage } = useI18n();
+setLanguage('en'); // 'en' | 'zh' | 'ja' | 'ko'
+```
+
+### 3. Add a new translation key
+
+Add the key to all 4 languages in `i18n/translations.ts`:
+
+```typescript
+export const translations = {
+ en: { yourNewKey: 'English text' },
+ zh: { yourNewKey: '中文文本' },
+ ja: { yourNewKey: '日本語テキスト' },
+ ko: { yourNewKey: '한국어 텍스트' },
+};
+```
+
+## Language Persistence
+
+The selected language is stored in `localStorage` and restored on next visit. Default is English.
+
+## Notes
+
+- All keys must exist in every language object
+- TypeScript's `TranslationKey` type enforces key safety
+- If a key is missing, the raw key name is returned as fallback
diff --git a/components/SettingsModal.tsx b/components/SettingsModal.tsx
index 0f61b8c..e884e1d 100644
--- a/components/SettingsModal.tsx
+++ b/components/SettingsModal.tsx
@@ -1,6 +1,7 @@
import React, { useState } from 'react';
-import { X, User as UserIcon, Palette, Info, Edit3, ExternalLink, Github } from 'lucide-react';
+import { X, User as UserIcon, Palette, Info, Edit3, ExternalLink, Globe, ChevronDown, Github } from 'lucide-react';
import { useAuth } from '../context/AuthContext';
+import { useI18n } from '../context/I18nContext';
import { EditProfileModal } from './EditProfileModal';
interface SettingsModalProps {
@@ -13,6 +14,7 @@ interface SettingsModalProps {
export const SettingsModal: React.FC = ({ isOpen, onClose, theme, onToggleTheme, onNavigateToProfile }) => {
const { user } = useAuth();
+ const { t, language, setLanguage } = useI18n();
const [isEditProfileOpen, setIsEditProfileOpen] = useState(false);
if (!isOpen || !user) {
@@ -29,14 +31,14 @@ export const SettingsModal: React.FC = ({ isOpen, onClose, t
}
return (
-
+
e.stopPropagation()}
>
{/* Header */}
-
Settings
+
{t('settings')}
@@ -91,21 +93,47 @@ export const SettingsModal: React.FC
= ({ isOpen, onClose, t
-
Account
+ {t('account')}
-
+
@{user.username}
+ {/* Language Section */}
+
+
+
+
{t('language')}
+
+
+
+
+
+
+
+
+
{/* Theme Section */}
-
Appearance
+
{t('appearance')}
@@ -116,7 +144,7 @@ export const SettingsModal: React.FC = ({ isOpen, onClose, t
: 'border-zinc-300 dark:border-zinc-700 hover:border-zinc-400 dark:hover:border-zinc-600'
}`}
>
- Light
+ {t('light')}
= ({ isOpen, onClose, t
: 'border-zinc-300 dark:border-zinc-700 hover:border-zinc-400 dark:hover:border-zinc-600'
}`}
>
- Dark
+ {t('dark')}
@@ -135,41 +163,70 @@ export const SettingsModal: React.FC
= ({ isOpen, onClose, t
-
About
+ {t('about')}
-
Version 1.0.0
-
ACE-Step UI - Local AI Music Generator
+
{t('version')} 2.0.0
+
ACE-Step UI - {t('localAIMusicGenerator')}
- Powered by ACE-Step 1.5. Open source and free to use.
+ {t('poweredBy')}
-
@@ -181,7 +238,7 @@ export const SettingsModal: React.FC
= ({ isOpen, onClose, t
onClick={onClose}
className="px-6 py-2 bg-zinc-900 dark:bg-white text-white dark:text-black font-semibold rounded-lg hover:bg-zinc-800 dark:hover:bg-zinc-200 transition-colors"
>
- Done
+ {t('done')}
diff --git a/context/I18nContext.tsx b/context/I18nContext.tsx
new file mode 100644
index 0000000..f8f1065
--- /dev/null
+++ b/context/I18nContext.tsx
@@ -0,0 +1,40 @@
+import React, { createContext, useContext, useState, ReactNode } from 'react';
+import { translations, Language, TranslationKey } from '../i18n/translations';
+
+interface I18nContextType {
+ language: Language;
+ setLanguage: (lang: Language) => void;
+ t: (key: TranslationKey) => string;
+}
+
+const I18nContext = createContext(undefined);
+
+export const I18nProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
+ const [language, setLanguage] = useState(() => {
+ const stored = localStorage.getItem('language') as Language;
+ return stored === 'zh' || stored === 'en' || stored === 'ja' || stored === 'ko' ? stored : 'en';
+ });
+
+ const handleSetLanguage = (lang: Language) => {
+ setLanguage(lang);
+ localStorage.setItem('language', lang);
+ };
+
+ const t = (key: TranslationKey): string => {
+ return translations[language][key] || key;
+ };
+
+ return (
+
+ {children}
+
+ );
+};
+
+export const useI18n = () => {
+ const context = useContext(I18nContext);
+ if (!context) {
+ throw new Error('useI18n must be used within I18nProvider');
+ }
+ return context;
+};
diff --git a/i18n/translations.ts b/i18n/translations.ts
new file mode 100644
index 0000000..a94c795
--- /dev/null
+++ b/i18n/translations.ts
@@ -0,0 +1,2361 @@
+export type Language = 'en' | 'zh' | 'ja' | 'ko';
+
+export const translations = {
+ en: {
+ // Navigation
+ create: 'Create',
+ library: 'Library',
+ search: 'Search',
+ training: 'Training',
+
+ // Theme
+ lightMode: 'Light Mode',
+ darkMode: 'Dark Mode',
+
+ // Auth
+ signIn: 'Sign In',
+ signOut: 'Sign Out',
+ settings: 'Settings',
+
+ // Username Modal
+ welcomeTitle: 'Welcome to ACE-Step UI',
+ welcomeSubtitle: 'Enter your name to get started creating AI music',
+ yourName: 'Your Name',
+ enterYourName: 'Enter your name',
+ getStarted: 'Get Started',
+ gettingStarted: 'Getting Started...',
+ yourMusicYourWay: 'Your music, your way. Create unlimited AI music for free.',
+ usernameMinLength: 'Username must be at least 2 characters',
+ usernameInvalidChars: 'Username can only contain letters, numbers, underscores, and dashes',
+ failedToSetUsername: 'Failed to set username',
+
+ // Toasts
+ songNotAvailable: 'This song is no longer available.',
+ unableToPlay: 'Unable to play this song.',
+ generationTimedOut: 'Generation timed out',
+ generationFailed: 'Generation failed. Please try again.',
+ playlistCreated: 'Playlist created successfully!',
+ failedToCreatePlaylist: 'Failed to create playlist',
+ songAddedToPlaylist: 'Song added to playlist',
+ failedToAddSong: 'Failed to add song to playlist',
+ songDeleted: 'Song deleted successfully',
+ failedToDeleteSong: 'Failed to delete song',
+
+ // Sidebar
+ aceStepUI: 'ACE-Step UI',
+
+ // Common
+ cancel: 'Cancel',
+ save: 'Save',
+ delete: 'Delete',
+ edit: 'Edit',
+ share: 'Share',
+ download: 'Download',
+ play: 'Play',
+ pause: 'Pause',
+ normalSpeed: 'Normal',
+ next: 'Next',
+ previous: 'Previous',
+
+ // Placeholders
+ searchPlaceholder: 'Search...',
+
+ // Settings
+ language: 'Language',
+ english: 'English',
+ chinese: 'Chinese',
+ japaneseLanguage: 'Japanese',
+ koreanLanguage: 'Korean',
+ appearance: 'Appearance',
+ profile: 'Profile',
+ viewProfile: 'View Profile',
+ editProfile: 'Edit Profile',
+ account: 'Account',
+ username: 'Username',
+ memberSince: 'Member since',
+ about: 'About',
+ version: 'Version',
+ localAIMusicGenerator: 'Local AI Music Generator',
+ poweredBy: 'Powered by ACE-Step 1.5. Open source and free to use.',
+ createdBy: 'Created by Ambsd',
+ localizedBy: 'Localization & Training by bdsqlsz',
+ follow: 'Follow',
+ done: 'Done',
+ light: 'Light',
+ dark: 'Dark',
+
+ // Mobile
+ createSong: 'Create Song',
+ viewList: 'View List',
+
+ // CreatePanel - Modes
+ simple: 'Simple',
+ custom: 'Custom',
+
+ // CreatePanel - Sections
+ audio: 'AUDIO',
+ lyrics: 'LYRICS',
+ styleOfMusic: 'STYLE OF MUSIC',
+ title: 'Title',
+ musicParameters: 'Music Parameters',
+ advancedSettings: 'Advanced Settings',
+
+ // CreatePanel - LoRA
+ loraPath: 'LoRA Path',
+ loraPathPlaceholder: 'Enter LoRA model path...',
+ browseFiles: 'Browse files',
+ loraLoaded: 'LoRA Loaded',
+ loraUnloaded: 'LoRA Unloaded',
+ loraLoad: 'Load',
+ loraUnload: 'Unload',
+ loraScale: 'LoRA Scale',
+ loraScaleDescription: 'Adjust the influence strength of the LoRA model',
+
+ // CreatePanel - Audio
+ reference: 'Reference',
+ cover: 'Cover',
+ fromLibrary: 'From library',
+ upload: 'Upload',
+
+ // CreatePanel - Lyrics
+ lyricsPlaceholder: 'Your lyrics here...',
+ leaveLyricsEmpty: 'Leave empty for instrumental or toggle below',
+ vocal: 'Vocal',
+ instrumental: 'Instrumental',
+ vocalLanguage: 'Vocal Language',
+ autoInstrumental: 'Auto / Instrumental',
+ vocalArabic: 'Arabic',
+ vocalAzerbaijani: 'Azerbaijani',
+ vocalBulgarian: 'Bulgarian',
+ vocalBengali: 'Bengali',
+ vocalCatalan: 'Catalan',
+ vocalCzech: 'Czech',
+ vocalDanish: 'Danish',
+ vocalGerman: 'German',
+ vocalGreek: 'Greek',
+ vocalEnglish: 'English',
+ vocalSpanish: 'Spanish',
+ vocalPersian: 'Persian',
+ vocalFinnish: 'Finnish',
+ vocalFrench: 'French',
+ vocalHebrew: 'Hebrew',
+ vocalHindi: 'Hindi',
+ vocalCroatian: 'Croatian',
+ vocalHaitianCreole: 'Haitian Creole',
+ vocalHungarian: 'Hungarian',
+ vocalIndonesian: 'Indonesian',
+ vocalIcelandic: 'Icelandic',
+ vocalItalian: 'Italian',
+ vocalJapanese: 'Japanese',
+ vocalKorean: 'Korean',
+ vocalLatin: 'Latin',
+ vocalLithuanian: 'Lithuanian',
+ vocalMalay: 'Malay',
+ vocalNepali: 'Nepali',
+ vocalDutch: 'Dutch',
+ vocalNorwegian: 'Norwegian',
+ vocalPunjabi: 'Punjabi',
+ vocalPolish: 'Polish',
+ vocalPortuguese: 'Portuguese',
+ vocalRomanian: 'Romanian',
+ vocalRussian: 'Russian',
+ vocalSanskrit: 'Sanskrit',
+ vocalSlovak: 'Slovak',
+ vocalSerbian: 'Serbian',
+ vocalSwedish: 'Swedish',
+ vocalSwahili: 'Swahili',
+ vocalTamil: 'Tamil',
+ vocalTelugu: 'Telugu',
+ vocalThai: 'Thai',
+ vocalTagalog: 'Tagalog',
+ vocalTurkish: 'Turkish',
+ vocalUkrainian: 'Ukrainian',
+ vocalUrdu: 'Urdu',
+ vocalVietnamese: 'Vietnamese',
+ vocalCantonese: 'Cantonese',
+ vocalChineseMandarin: 'Chinese (Mandarin)',
+
+ // CreatePanel - Style
+ stylePlaceholder: 'e.g. upbeat pop rock, emotional ballad, 90s hip hop',
+ genreMoodInstruments: 'Genre, mood, instruments, vibe',
+ refreshGenres: 'Refresh genre suggestions',
+ mainGenre: 'Main Genre',
+ subGenre: 'Sub Genre',
+ nameSong: 'Name your song',
+
+ // CreatePanel - Parameters
+ bpm: 'BPM',
+ auto: 'Auto',
+ duration: 'Duration',
+ seconds: 's',
+ keyScale: 'Key & Scale',
+ timeSignature: 'Time Signature',
+
+ // CreatePanel - Advanced
+ randomSeed: 'Random Seed',
+ thinking: 'Thinking',
+ audioFormat: 'Audio Format',
+ inferenceSteps: 'Inference Steps',
+ guidanceScale: 'Guidance Scale',
+ inferMethod: 'Inference Method',
+ shift: 'Shift',
+ timestepShiftForBase: 'Timestep shift for base models (not effective for turbo)',
+ expertControls: 'EXPERT CONTROLS',
+ lmParameters: 'LM Parameters',
+ controlLyricGeneration: 'Control lyric generation + creativity',
+ transform: 'TRANSFORM',
+ controlSourceAudio: 'Control how much the model follows the source audio',
+ audioCodes: 'Audio Codes',
+ optionalAudioCodes: 'Optional audio codes payload',
+ taskType: 'Task Type',
+ textToMusic: 'Text → Music',
+ audioCoverStrength: 'Audio Cover Strength',
+ repaintingStart: 'Repainting Start',
+ repaintingEnd: 'Repainting End',
+ instruction: 'Instruction',
+ lmTemperature: 'LM Temperature',
+ higherMoreRandom: 'Higher = more random (0-2)',
+ lmCfgScale: 'LM CFG Scale',
+ noCfgScale: '1.0 = no CFG (1-3)',
+ topK: 'Top-K',
+ topP: 'Top-P',
+ lmNegativePrompt: 'LM Negative Prompt',
+ noUserInput: 'NO USER INPUT',
+ thingsToAvoid: 'Things to avoid...',
+ useWhenCfgScaleGreater: 'Use when LM CFG Scale > 1.0',
+ lmTopK: 'LM Top-K',
+ lmTopP: 'LM Top-P',
+
+ // Guidance section
+ guidance: 'GUIDANCE',
+ advancedCfgScheduling: 'Advanced CFG scheduling controls.',
+ cfgIntervalStart: 'CFG Interval Start',
+ cfgIntervalEnd: 'CFG Interval End',
+ customTimesteps: 'Custom Timesteps',
+ timestepsPlaceholder: 'e.g. 1,3,5,7',
+ scoreScale: 'Score Scale',
+ lmBatchChunkSize: 'LM Batch Chunk Size',
+ trackName: 'Track Name',
+ optionalTrackName: 'Optional track name',
+ completeTrackClasses: 'Complete Track Classes',
+ trackClassesPlaceholder: 'class-a, class-b',
+ useAdg: 'Use ADG',
+ allowLmBatch: 'Allow LM Batch',
+ useCotMetas: 'Use CoT Metas',
+ useCotCaption: 'Use CoT Caption',
+ useCotLanguage: 'Use CoT Language',
+ autogen: 'Autogen',
+ constrainedDecodingDebug: 'Constrained Decoding Debug',
+ formatCaption: 'Format Caption',
+ getScores: 'Get Scores',
+ getLrcLyrics: 'Get LRC (Lyrics)',
+ batchSize: 'Batch Size (Variations)',
+ variations: 'Variations',
+ bulkGenerate: 'Bulk Generate',
+ job: 'job',
+ jobs: 'jobs',
+ queueMultipleJobs: 'Queue multiple independent generation jobs with same settings',
+ numberOfVariations: 'Number of song variations to generate',
+ moreStepsBetterQuality: 'More steps = better quality, slower (8 recommended for turbo)',
+ howCloselyFollowPrompt: 'How closely to follow the prompt',
+ seed: 'Seed',
+ randomSeedRecommended: 'Randomized every run (recommended)',
+ fixedSeedReproducible: 'Fixed seed for reproducible results',
+ enterFixedSeed: 'Enter fixed seed',
+ thinkingCot: 'Thinking (CoT)',
+ mp3Smaller: 'MP3 (smaller)',
+ flacLossless: 'FLAC (lossless)',
+ odeDeterministic: 'ODE (deterministic)',
+ sdeStochastic: 'SDE (stochastic)',
+ min: 'min',
+
+ // CreatePanel - Drag & Drop
+ dropToUseAudio: 'Drop to use audio',
+ dropToUpload: 'Drop to upload',
+ usingAsReference: 'Using as Reference',
+ usingAsCover: 'Using as Cover',
+ uploadingAsReference: 'Uploading as Reference',
+ uploadingAsCover: 'Uploading as Cover',
+
+ // CreatePanel - Vocal Gender
+ vocalGender: 'Vocal Gender',
+ male: 'Male',
+ female: 'Female',
+
+ // CreatePanel - LM Backend & Model
+ lmBackendLabel: 'LM Backend',
+ lmBackendPt: 'PT (~1.6 GB VRAM)',
+ lmBackendVllm: 'VLLM (~9.2 GB VRAM)',
+ lmBackendHint: 'PT uses less VRAM, VLLM may be faster on powerful GPUs',
+ lmModelLabel: 'LM Model',
+ lmModel06B: '0.6B (Lightest, ~0.5 GB VRAM)',
+ lmModel17B: '1.7B (Balanced, ~1.5 GB VRAM)',
+ lmModel4B: '4B (Best quality, ~4 GB VRAM)',
+ lmModelHint: 'Controls the LLM used for lyrics/style enhancement. Auto-downloads if not present.',
+
+ // CreatePanel - Transcription
+ transcribing: 'Transcribing...',
+ transcribingWithWhisper: 'Transcribing with Whisper…',
+
+ // CreatePanel - Library Tabs
+ uploaded: 'Uploaded',
+ createdTab: 'Created',
+ useTrack: 'Use',
+ noCreatedSongsYet: 'No created songs yet',
+ generateSongsToReuse: 'Generate songs to reuse them as cover or reference',
+
+ // CreatePanel - Actions
+ generate: 'Generate',
+ generating: 'Generating...',
+ createButton: 'Create',
+ formatLyrics: 'Format Lyrics',
+ formatting: 'Formatting...',
+ clearAll: 'Clear All',
+
+ // Simple Mode
+ describeYourSong: 'DESCRIBE YOUR SONG',
+ songDescriptionPlaceholder: 'A happy pop song about summer adventures with friends...',
+ quickSettings: 'QUICK SETTINGS',
+ key: 'Key',
+ time: 'Time',
+
+ // CreatePanel - Errors
+ loginToGenerate: 'Please login to generate music',
+ uploadFailed: 'Upload failed',
+ formatFailed: 'Format failed',
+ formatFailedDetail: 'Format failed. Make sure the LLM is initialized.',
+ formatFailedLlmUnavailable: 'Format failed. The LLM may not be available.',
+ deleteSongConfirm: 'Are you sure you want to delete "{title}"? This action cannot be undone.',
+ profileUpdateFailed: 'Failed to update profile',
+ ffmpegLoadFailed: 'Failed to load video encoder. Please refresh and try again.',
+ videoRenderFailed: 'Video rendering failed. Please try again.',
+
+ // SongList / Filters
+ searchYourSongs: 'Search your songs...',
+ filters: 'Filters',
+ refineBy: 'REFINE BY',
+ liked: 'Liked',
+ public: 'Public',
+ private: 'Private',
+ generatingStatus: 'Generating',
+ selectSongToView: 'Select a song to view details',
+ noSongsMatchFilters: 'No songs match your filters.',
+ clearFilters: 'Clear filters',
+
+ // RightSidebar - Song Details
+ songDetails: 'Song Details',
+ created: 'Created',
+ styleTags: 'STYLE & TAGS',
+ lyricsSection: 'LYRICS',
+ copyLyrics: 'Copy',
+
+ // Languages
+ japanese: 'Japanese',
+ spanish: 'Spanish',
+ german: 'German',
+ french: 'French',
+ portuguese: 'Portuguese',
+ russian: 'Russian',
+ italian: 'Italian',
+ dutch: 'Dutch',
+ polish: 'Polish',
+ turkish: 'Turkish',
+ vietnamese: 'Vietnamese',
+ czech: 'Czech',
+ persian: 'Persian',
+ arabic: 'Arabic',
+ korean: 'Korean',
+ thai: 'Thai',
+ hindi: 'Hindi',
+ indonesian: 'Indonesian',
+ ukrainian: 'Ukrainian',
+ hungarian: 'Hungarian',
+ swedish: 'Swedish',
+ romanian: 'Romanian',
+ greek: 'Greek',
+
+ // Task Types
+ audio2audio: 'Audio → Audio',
+ coverTask: 'Cover',
+ repaintTask: 'Repaint',
+
+ // Search Page
+ searchSongsPlaceholder: 'Search for songs, playlists, creators, or genres',
+ songsMatching: 'Songs matching',
+ featuredSongs: 'Featured Songs',
+ noSongsFound: 'No songs found matching',
+ creatorsMatching: 'Creators matching',
+ featuredCreators: 'Featured Creators',
+ noCreatorsFound: 'No creators found matching',
+ noCreatorsYet: 'No creators yet. Be the first to share your music!',
+ playlistsMatching: 'Playlists matching',
+ featuredPlaylists: 'Featured Playlists',
+ noPlaylistsFound: 'No playlists found matching',
+ noPlaylistsYet: 'No public playlists yet. Create one and share your favorites!',
+ genres: 'Genres',
+ songs: 'songs',
+
+ // Library View
+ yourLibrary: 'Your Library',
+ newPlaylist: 'New Playlist',
+ likedSongs: 'Liked Songs',
+ playlists: 'Playlists',
+ playlist: 'Playlist',
+ byYou: 'By You',
+
+ // User Profile
+ back: 'Back',
+ loadingProfile: 'Loading profile...',
+ userNotFound: 'User not found',
+ goBack: 'Go Back',
+ likes: 'Likes',
+ plays: 'Plays',
+ recent: 'Recent',
+ top: 'Top',
+ noPublicSongsYet: 'No public songs yet',
+ seeMore: 'See More',
+ joined: 'Joined',
+ supportingSince: 'Supporting since',
+ avatarImage: 'Avatar Image',
+ uploadAvatar: 'Upload Avatar',
+ avatarFormats: 'JPG, PNG, WebP, GIF • Max 5MB',
+ bannerImage: 'Banner Image',
+ clickToUploadBanner: 'Click to upload banner',
+ bannerFormats: 'Recommended: 1500x500px • JPG, PNG, WebP, GIF • Max 5MB',
+ bio: 'Bio',
+ bioPlaceholder: 'Tell us about yourself...',
+ uploadingAvatar: 'Uploading Avatar...',
+ uploadingBanner: 'Uploading Banner...',
+ saving: 'Saving...',
+ saveChanges: 'Save Changes',
+
+ // Playlist Modals
+ createPlaylist: 'Create Playlist',
+ playlistName: 'Name',
+ playlistNamePlaceholder: 'My Awesome Playlist',
+ playlistDescription: 'Description',
+ descriptionPlaceholder: 'Vibes for coding...',
+ addToPlaylist: 'Add to Playlist',
+ createNewPlaylist: 'Create New Playlist',
+ noExistingPlaylists: 'No existing playlists.',
+
+ // Edit Profile Modal (Settings)
+ usernameLabel: 'Username',
+ usernamePlaceholder: 'username',
+ usernameMinLengthError: 'Username must be at least 2 characters',
+ usernameTakenError: 'Username is already taken',
+ usernameUpdateFailedError: 'Failed to update username',
+ usernameRequirements: 'Letters, numbers, underscores, and hyphens only',
+
+ // Song Details (RightSidebar)
+ more: 'more',
+ copy: 'Copy',
+ copied: 'Copied!',
+ copyAllTags: 'Copy all tags',
+
+ // Song Dropdown Menu
+ createVideo: 'Create Video',
+ editAudio: 'Edit Audio',
+ extractStems: 'Extract Stems',
+ reusePrompt: 'Reuse Prompt',
+ deleteSong: 'Delete Song',
+ useAsReference: 'Use as Reference',
+ coverSong: 'Cover Song',
+ confirmDeleteTitle: 'Delete Song',
+ confirmDeleteManyTitle: 'Delete Songs',
+ deleteSongsConfirm: 'Delete {count} songs? This action cannot be undone.',
+ songsDeletedSuccess: 'Songs deleted successfully',
+ songsDeletedPartial: 'Deleted {succeeded}/{total} songs',
+ deleteUploadConfirm: 'Delete this upload? This action cannot be undone.',
+ cannotBeUndone: 'This action cannot be undone.',
+
+ // Player
+ nowPlaying: 'Now Playing',
+ downloadAudio: 'Download Audio',
+ openInEditor: 'Open in Editor',
+ anonymous: 'Anonymous',
+
+ // PlaylistDetail
+ loadingPlaylist: 'Loading playlist...',
+ playlistNotFound: 'Playlist not found',
+ deletePlaylistConfirm: 'Are you sure you want to delete this playlist?',
+ dateAdded: 'Date Added',
+ justNow: 'Just now',
+ unknown: 'Unknown',
+
+ // SongProfile
+ loadingSong: 'Loading song...',
+ songNotFound: 'Song not found',
+ similar: 'Similar',
+ by: 'By',
+
+ // ShareModal
+ shareSong: 'Share Song',
+ shareOnX: 'Share on X',
+ shareOnFacebook: 'Share on Facebook',
+ shareOnWhatsApp: 'Share on WhatsApp',
+ shareOnTelegram: 'Share on Telegram',
+ shareOnReddit: 'Share on Reddit',
+ shareOnLinkedIn: 'Share on LinkedIn',
+ shareViaEmail: 'Share via Email',
+ copyLink: 'Copy Link',
+ emailSubject: 'Check out this AI song',
+ emailBody: 'Hey!\n\nI created this AI-generated song and thought you\'d love it:\n\n"{title}" by {creator}\n{style}\n\nListen here: {url}\n\nMade with ACE-Step UI - free and open source local AI music generation!',
+
+ // Reference Modal
+ referenceModalTitle: 'Reference',
+ coverModalTitle: 'Cover',
+ referenceModalDescription: 'Create songs inspired by a reference track',
+ coverModalDescription: 'Transform an existing track into a new version',
+ uploadAudio: 'Upload audio',
+ uploadingAudio: 'Uploading...',
+ audioFormats: 'MP3, WAV, FLAC',
+ mine: 'Mine',
+ loadingTracks: 'Loading tracks...',
+ noTracksYet: 'No tracks yet',
+ uploadAudioFilesAsReferences: 'Upload audio files to use them as references',
+
+ // Training Module
+ loraTraining: 'LoRA Training',
+ trainingDescription: 'Build datasets from your audio files and train custom LoRA adapters',
+ datasetBuilder: 'Dataset Builder',
+ trainLora: 'Train LoRA',
+ quickStart: 'Quick Start',
+ chooseOneOption: 'Choose one: Load existing dataset OR Scan new directory',
+ loadExistingDataset: 'Load Existing Dataset',
+ loadDataset: 'Load',
+ scanNewDirectory: 'Scan New Directory',
+ scanDataset: 'Scan',
+ datasetSettings: 'Dataset Settings',
+ datasetName: 'Dataset Name',
+ customActivationTag: 'Custom Activation Tag',
+ allInstrumental: 'All Instrumental',
+ tagPosition: 'Tag Position',
+ tagPrepend: 'Prepend (tag, caption)',
+ tagAppend: 'Append (caption, tag)',
+ tagReplace: 'Replace caption',
+ genreRatio: 'Genre Ratio',
+ genreRatioHint: '0% = all Caption, 100% = all Genre',
+ autoLabelWithAI: 'Auto-Label with AI',
+ autoLabelDescription: 'Generate metadata for audio files: Caption, BPM, Key, Time Signature',
+ skipMetas: 'Skip BPM/Key/Time Signature',
+ onlyUnlabeled: 'Only Unlabeled',
+ autoLabelAll: 'Auto-Label All',
+ filename: 'Filename',
+ labeled: 'Labeled',
+ saveDataset: 'Save Dataset',
+ preprocessToTensors: 'Preprocess to Tensors',
+ preprocessDescription: 'Converts dataset to pre-computed tensors for fast training (requires model loaded)',
+ preprocess: 'Preprocess',
+ preprocessedDataset: 'Preprocessed Dataset',
+ loraSettings: 'LoRA Settings',
+ loraRank: 'LoRA Rank',
+ loraAlpha: 'LoRA Alpha',
+ dropout: 'Dropout',
+ trainingParameters: 'Training Parameters',
+ learningRate: 'Learning Rate',
+ maxEpochs: 'Max Epochs',
+ gradientAccumulation: 'Gradient Accumulation',
+ saveEvery: 'Save Every',
+ epochs: 'epochs',
+ outputDirectory: 'Output Directory',
+ useFP8: 'Use FP8 Quantization',
+ fp8Description: 'Reduces VRAM usage',
+ startTraining: 'Start Training',
+ stopTraining: 'Stop Training',
+ trainingProgress: 'Training Progress',
+ trainingLog: 'Training Log',
+ trainingStatus: 'Training Status',
+ tensorboardView: 'TensorBoard View',
+ showTensorboard: 'Show TensorBoard',
+ hideTensorboard: 'Hide TensorBoard',
+ openInNewTab: 'Open in New Tab',
+
+ // Training Status Messages
+ scanning: 'Scanning...',
+ autoLabeling: 'Auto-labeling...',
+ savingDataset: 'Saving...',
+ preprocessing: 'Preprocessing...',
+ loadingDataset: 'Loading...',
+ startingTraining: 'Starting...',
+ error: 'Error',
+ datasetInfo: 'Dataset: {name}, Samples: {samples}, Labeled: {labeled}',
+ trainingStep: 'Step {step} - Loss: {loss}',
+ editSample: 'Edit Sample',
+ caption: 'Caption',
+ genre: 'Genre',
+ promptOverride: 'Prompt Override',
+ musicDescription: 'Music description...',
+ overrideGlobalRatio: 'Override global ratio for this sample',
+ editableUsedForTraining: 'editable, used for training',
+ useGlobalRatio: 'Use Global Ratio',
+ thisSample: 'this sample',
+ },
+ zh: {
+ // Navigation
+ create: '创作',
+ library: '音乐库',
+ search: '搜索',
+ training: '训练',
+
+ // Theme
+ lightMode: '浅色模式',
+ darkMode: '深色模式',
+
+ // Auth
+ signIn: '登录',
+ signOut: '退出',
+ settings: '设置',
+
+ // Username Modal
+ welcomeTitle: '欢迎使用 ACE-Step UI',
+ welcomeSubtitle: '输入您的名字开始创作 AI 音乐',
+ yourName: '您的名字',
+ enterYourName: '请输入您的名字',
+ getStarted: '开始使用',
+ gettingStarted: '正在启动...',
+ yourMusicYourWay: '您的音乐,您的方式。免费创作无限 AI 音乐。',
+ usernameMinLength: '用户名至少需要 2 个字符',
+ usernameInvalidChars: '用户名只能包含字母、数字、下划线和破折号',
+ failedToSetUsername: '设置用户名失败',
+
+ // Toasts
+ songNotAvailable: '该歌曲已不可用。',
+ unableToPlay: '无法播放该歌曲。',
+ generationTimedOut: '生成超时',
+ generationFailed: '生成失败,请重试。',
+ playlistCreated: '歌单创建成功!',
+ failedToCreatePlaylist: '创建歌单失败',
+ songAddedToPlaylist: '已添加到歌单',
+ failedToAddSong: '添加歌曲失败',
+ songDeleted: '歌曲删除成功',
+ failedToDeleteSong: '删除歌曲失败',
+
+ // Sidebar
+ aceStepUI: 'ACE-Step UI',
+
+ // Common
+ cancel: '取消',
+ save: '保存',
+ delete: '删除',
+ edit: '编辑',
+ share: '分享',
+ download: '下载',
+ play: '播放',
+ pause: '暂停',
+ normalSpeed: '正常',
+ next: '下一首',
+ previous: '上一首',
+
+ // Placeholders
+ searchPlaceholder: '搜索...',
+
+ // Settings
+ language: '语言',
+ english: 'English',
+ chinese: '简体中文',
+ japaneseLanguage: '日本語',
+ koreanLanguage: '한국어',
+ appearance: '外观',
+ profile: '个人资料',
+ viewProfile: '查看个人资料',
+ editProfile: '编辑资料',
+ account: '账户',
+ username: '用户名',
+ memberSince: '加入时间',
+ about: '关于',
+ version: '版本',
+ localAIMusicGenerator: '本地 AI 音乐生成器',
+ poweredBy: '由 ACE-Step 1.5 驱动。开源免费使用。',
+ createdBy: '开发者 Ambsd',
+ localizedBy: '本地化翻译 & 训练 青龙圣者',
+ follow: '关注',
+ done: '完成',
+ light: '浅色',
+ dark: '深色',
+
+ // Mobile
+ createSong: '创作歌曲',
+ viewList: '查看列表',
+
+ // CreatePanel - Modes
+ simple: '简单',
+ custom: '自定义',
+
+ // CreatePanel - Sections
+ audio: '音频',
+ lyrics: '歌词',
+ styleOfMusic: '音乐风格',
+ title: '标题',
+ musicParameters: '音乐参数',
+ advancedSettings: '高级设置',
+
+ // CreatePanel - LoRA
+ loraPath: 'LoRA 路径',
+ loraPathPlaceholder: '输入 LoRA 模型路径...',
+ browseFiles: '浏览文件',
+ loraLoaded: 'LoRA 已加载',
+ loraUnloaded: 'LoRA 未加载',
+ loraLoad: '加载',
+ loraUnload: '卸载',
+ loraScale: 'LoRA 强度',
+ loraScaleDescription: '调整 LoRA 模型的影响强度',
+
+ // CreatePanel - Audio
+ reference: '参考',
+ cover: '翻唱',
+ fromLibrary: '从库中选择',
+ upload: '上传',
+
+ // CreatePanel - Lyrics
+ lyricsPlaceholder: '在此输入歌词...',
+ leaveLyricsEmpty: '留空表示纯音乐,或使用下方开关',
+ vocal: '人声',
+ instrumental: '纯音乐',
+ vocalLanguage: '人声语言',
+ autoInstrumental: '自动 / 纯音乐',
+ vocalArabic: '阿拉伯语',
+ vocalAzerbaijani: '阿塞拜疆语',
+ vocalBulgarian: '保加利亚语',
+ vocalBengali: '孟加拉语',
+ vocalCatalan: '加泰罗尼亚语',
+ vocalCzech: '捷克语',
+ vocalDanish: '丹麦语',
+ vocalGerman: '德语',
+ vocalGreek: '希腊语',
+ vocalEnglish: '英语',
+ vocalSpanish: '西班牙语',
+ vocalPersian: '波斯语',
+ vocalFinnish: '芬兰语',
+ vocalFrench: '法语',
+ vocalHebrew: '希伯来语',
+ vocalHindi: '印地语',
+ vocalCroatian: '克罗地亚语',
+ vocalHaitianCreole: '海地克里奥尔语',
+ vocalHungarian: '匈牙利语',
+ vocalIndonesian: '印尼语',
+ vocalIcelandic: '冰岛语',
+ vocalItalian: '意大利语',
+ vocalJapanese: '日语',
+ vocalKorean: '韩语',
+ vocalLatin: '拉丁语',
+ vocalLithuanian: '立陶宛语',
+ vocalMalay: '马来语',
+ vocalNepali: '尼泊尔语',
+ vocalDutch: '荷兰语',
+ vocalNorwegian: '挪威语',
+ vocalPunjabi: '旁遮普语',
+ vocalPolish: '波兰语',
+ vocalPortuguese: '葡萄牙语',
+ vocalRomanian: '罗马尼亚语',
+ vocalRussian: '俄语',
+ vocalSanskrit: '梵语',
+ vocalSlovak: '斯洛伐克语',
+ vocalSerbian: '塞尔维亚语',
+ vocalSwedish: '瑞典语',
+ vocalSwahili: '斯瓦希里语',
+ vocalTamil: '泰米尔语',
+ vocalTelugu: '泰卢固语',
+ vocalThai: '泰语',
+ vocalTagalog: '他加禄语',
+ vocalTurkish: '土耳其语',
+ vocalUkrainian: '乌克兰语',
+ vocalUrdu: '乌尔都语',
+ vocalVietnamese: '越南语',
+ vocalCantonese: '粤语',
+ vocalChineseMandarin: '中文(普通话)',
+
+ // CreatePanel - Style
+ stylePlaceholder: '例如:欢快流行摇滚、抒情民谣、90年代嘻哈',
+ genreMoodInstruments: '曲风、情绪、乐器、氛围',
+ refreshGenres: '刷新风格建议',
+ mainGenre: '大类风格',
+ subGenre: '小类风格',
+ nameSong: '为歌曲命名',
+
+ // CreatePanel - Parameters
+ bpm: '曲速*(BPM)',
+ auto: '自动',
+ duration: '时长',
+ seconds: '秒',
+ keyScale: '调式',
+ timeSignature: '拍号',
+
+ // CreatePanel - Advanced
+ randomSeed: '随机种子',
+ thinking: '思考模式',
+ audioFormat: '音频格式',
+ inferenceSteps: '推理步数',
+ guidanceScale: '引导强度(cfg)',
+ inferMethod: '推理方法',
+ shift: '偏移(shift)',
+ timestepShiftForBase: '基础模型的时间步偏移(turbo 模式无效)',
+ expertControls: '专家控制',
+ lmParameters: 'LM 参数',
+ controlLyricGeneration: '控制歌词生成和创造力',
+ transform: '音频转换',
+ controlSourceAudio: '控制模型遵循源音频的程度',
+ audioCodes: '音频编码',
+ optionalAudioCodes: '可选的音频编码载荷',
+ taskType: '任务类型',
+ textToMusic: '文本 → 音乐',
+ audioCoverStrength: '音频翻唱强度',
+ repaintingStart: '重绘开始',
+ repaintingEnd: '重绘结束',
+ instruction: '指令',
+ lmTemperature: 'LM 温度',
+ higherMoreRandom: '值越高越随机(0-2)',
+ lmCfgScale: 'LM CFG 强度',
+ noCfgScale: '1.0 = 无 CFG(1-3)',
+ topK: 'Top-K',
+ topP: 'Top-P',
+ lmNegativePrompt: 'LM 负面提示词',
+ noUserInput: '无用户输入',
+ thingsToAvoid: '要避免的内容...',
+ useWhenCfgScaleGreater: '当 LM CFG 强度 > 1.0 时使用',
+ lmTopK: 'LM Top-K',
+ lmTopP: 'LM Top-P',
+
+ // Guidance section
+ guidance: '引导控制(guidance)',
+ advancedCfgScheduling: '高级 CFG 调度控制。',
+ cfgIntervalStart: 'CFG 区间开始',
+ cfgIntervalEnd: 'CFG 区间结束',
+ customTimesteps: '自定义时间步',
+ timestepsPlaceholder: '例如:1,3,5,7',
+ scoreScale: '分数缩放',
+ lmBatchChunkSize: 'LM 批次块大小',
+ trackName: '音轨名称',
+ optionalTrackName: '可选的音轨名称',
+ completeTrackClasses: '完整音轨类别',
+ trackClassesPlaceholder: '类别-a, 类别-b',
+ useAdg: '使用 ADG',
+ allowLmBatch: '允许 LM 批处理',
+ useCotMetas: '使用 CoT 元数据',
+ useCotCaption: '使用 CoT 字幕',
+ useCotLanguage: '使用 CoT 语言',
+ autogen: '自动生成',
+ constrainedDecodingDebug: '约束解码调试',
+ formatCaption: '格式化字幕',
+ getScores: '获取分数',
+ getLrcLyrics: '获取 LRC(歌词)',
+ batchSize: '批量大小(变体数)',
+ variations: '变体',
+ bulkGenerate: '批量生成',
+ job: '任务',
+ jobs: '任务',
+ queueMultipleJobs: '使用相同设置排队多个独立生成任务',
+ numberOfVariations: '要生成的歌曲变体数量',
+ moreStepsBetterQuality: '步数越多质量越好,速度越慢(turbo 推荐 8)',
+ howCloselyFollowPrompt: '多严格遵循提示词',
+ seed: '种子',
+ randomSeedRecommended: '每次运行随机(推荐)',
+ fixedSeedReproducible: '固定种子以获得可重现结果',
+ enterFixedSeed: '输入固定种子',
+ thinkingCot: '思考模式(CoT)',
+ mp3Smaller: 'MP3(较小)',
+ flacLossless: 'FLAC(无损)',
+ odeDeterministic: 'ODE(确定性)',
+ sdeStochastic: 'SDE(随机性)',
+ min: '分钟',
+
+ // CreatePanel - Drag & Drop
+ dropToUseAudio: '拖放以使用音频',
+ dropToUpload: '拖放以上传',
+ usingAsReference: '用作参考',
+ usingAsCover: '用作翻唱',
+ uploadingAsReference: '上传为参考',
+ uploadingAsCover: '上传为翻唱',
+
+ // CreatePanel - Vocal Gender
+ vocalGender: '人声性别',
+ male: '男声',
+ female: '女声',
+
+ // CreatePanel - LM Backend & Model
+ lmBackendLabel: 'LM 后端',
+ lmBackendPt: 'PT(~1.6 GB 显存)',
+ lmBackendVllm: 'VLLM(~9.2 GB 显存)',
+ lmBackendHint: 'PT 显存占用更少,VLLM 在高性能 GPU 上可能更快',
+ lmModelLabel: 'LM 模型',
+ lmModel06B: '0.6B(最轻量,~0.5 GB 显存)',
+ lmModel17B: '1.7B(均衡,~1.5 GB 显存)',
+ lmModel4B: '4B(最佳质量,~4 GB 显存)',
+ lmModelHint: '控制用于歌词/风格增强的 LLM。如不存在将自动下载。',
+
+ // CreatePanel - Transcription
+ transcribing: '转录中...',
+ transcribingWithWhisper: '正在使用 Whisper 转录…',
+
+ // CreatePanel - Library Tabs
+ uploaded: '已上传',
+ createdTab: '已创建',
+ useTrack: '使用',
+ noCreatedSongsYet: '暂无已创建歌曲',
+ generateSongsToReuse: '生成歌曲后可作为翻唱或参考使用',
+
+ // CreatePanel - Actions
+ generate: '生成',
+ generating: '生成中...',
+ createButton: '创建',
+ formatLyrics: '格式化歌词',
+ formatting: '格式化中...',
+ clearAll: '清空全部',
+
+ // Simple Mode
+ describeYourSong: '描述你的歌曲',
+ songDescriptionPlaceholder: '一首关于夏日和朋友冒险的快乐流行歌曲...',
+ quickSettings: '快速设置',
+ key: '调式',
+ time: '拍号',
+
+ // CreatePanel - Errors
+ loginToGenerate: '请登录以生成音乐',
+ uploadFailed: '上传失败',
+ formatFailed: '格式化失败',
+ formatFailedDetail: '格式化失败。请确保 LLM 已初始化。',
+ formatFailedLlmUnavailable: '格式化失败。LLM 可能不可用。',
+ deleteSongConfirm: '确定要删除"{title}"吗?此操作无法撤销。',
+ profileUpdateFailed: '更新个人资料失败',
+ ffmpegLoadFailed: '加载视频编码器失败。请刷新后重试。',
+ videoRenderFailed: '视频渲染失败。请重试。',
+
+ // SongList / Filters
+ searchYourSongs: '搜索你的歌曲...',
+ filters: '筛选',
+ refineBy: '筛选条件',
+ liked: '已喜欢',
+ public: '公开',
+ private: '私密',
+ generatingStatus: '生成中',
+ selectSongToView: '选择一首歌曲查看详情',
+ noSongsMatchFilters: '没有歌曲符合你的筛选条件。',
+ clearFilters: '清除筛选',
+
+ // RightSidebar - Song Details
+ songDetails: '歌曲详情',
+ created: '创建于',
+ styleTags: '风格与标签',
+ lyricsSection: '歌词',
+ copyLyrics: '复制',
+
+ // Languages
+ japanese: '日语',
+ spanish: '西班牙语',
+ german: '德语',
+ french: '法语',
+ portuguese: '葡萄牙语',
+ russian: '俄语',
+ italian: '意大利语',
+ dutch: '荷兰语',
+ polish: '波兰语',
+ turkish: '土耳其语',
+ vietnamese: '越南语',
+ czech: '捷克语',
+ persian: '波斯语',
+ arabic: '阿拉伯语',
+ korean: '韩语',
+ thai: '泰语',
+ hindi: '印地语',
+ indonesian: '印尼语',
+ ukrainian: '乌克兰语',
+ hungarian: '匈牙利语',
+ swedish: '瑞典语',
+ romanian: '罗马尼亚语',
+ greek: '希腊语',
+
+ // Task Types
+ audio2audio: '音频 → 音频',
+ coverTask: '翻唱',
+ repaintTask: '重绘',
+
+ // Search Page
+ searchSongsPlaceholder: '搜索歌曲、播放列表、创作者或风格',
+ songsMatching: '匹配的歌曲',
+ featuredSongs: '精选歌曲',
+ noSongsFound: '未找到匹配的歌曲',
+ creatorsMatching: '匹配的创作者',
+ featuredCreators: '精选创作者',
+ noCreatorsFound: '未找到匹配的创作者',
+ noCreatorsYet: '暂无创作者。成为第一个分享音乐的人!',
+ playlistsMatching: '匹配的播放列表',
+ featuredPlaylists: '精选播放列表',
+ noPlaylistsFound: '未找到匹配的播放列表',
+ noPlaylistsYet: '暂无公开播放列表。创建一个并分享你的最爱!',
+ genres: '风格',
+ songs: '首歌曲',
+
+ // Library View
+ yourLibrary: '我的音乐库',
+ newPlaylist: '新建播放列表',
+ likedSongs: '喜欢的歌曲',
+ playlists: '播放列表',
+ playlist: '播放列表',
+ byYou: '由你创建',
+
+ // User Profile
+ back: '返回',
+ loadingProfile: '加载中...',
+ userNotFound: '用户不存在',
+ goBack: '返回',
+ likes: '喜欢',
+ plays: '播放',
+ recent: '最新',
+ top: '热门',
+ noPublicSongsYet: '暂无公开歌曲',
+ seeMore: '查看更多',
+ joined: '加入于',
+ supportingSince: '支持者自',
+ avatarImage: '头像',
+ uploadAvatar: '上传头像',
+ avatarFormats: 'JPG、PNG、WebP、GIF • 最大 5MB',
+ bannerImage: '横幅图片',
+ clickToUploadBanner: '点击上传横幅',
+ bannerFormats: '推荐尺寸:1500x500px • JPG、PNG、WebP、GIF • 最大 5MB',
+ bio: '个人简介',
+ bioPlaceholder: '介绍一下你自己...',
+ uploadingAvatar: '上传头像中...',
+ uploadingBanner: '上传横幅中...',
+ saving: '保存中...',
+ saveChanges: '保存更改',
+
+ // Playlist Modals
+ createPlaylist: '创建播放列表',
+ playlistName: '名称',
+ playlistNamePlaceholder: '我的超棒播放列表',
+ playlistDescription: '描述',
+ descriptionPlaceholder: '编程时的氛围音乐...',
+ addToPlaylist: '添加到播放列表',
+ createNewPlaylist: '创建新播放列表',
+ noExistingPlaylists: '暂无播放列表。',
+
+ // Edit Profile Modal (Settings)
+ usernameLabel: '用户名',
+ usernamePlaceholder: '用户名',
+ usernameMinLengthError: '用户名至少需要 2 个字符',
+ usernameTakenError: '用户名已被占用',
+ usernameUpdateFailedError: '更新用户名失败',
+ usernameRequirements: '仅允许字母、数字、下划线和短横线',
+
+ // Song Details (RightSidebar)
+ more: '更多',
+ copy: '复制',
+ copied: '已复制!',
+ copyAllTags: '复制所有标签',
+
+ // Song Dropdown Menu
+ createVideo: '创建视频',
+ editAudio: '编辑音频',
+ extractStems: '提取音轨',
+ reusePrompt: '重用提示词',
+ deleteSong: '删除歌曲',
+ useAsReference: '用作参考',
+ coverSong: '翻唱歌曲',
+ confirmDeleteTitle: '删除歌曲',
+ confirmDeleteManyTitle: '删除歌曲',
+ deleteSongsConfirm: '确定要删除 {count} 首歌曲吗?此操作无法撤销。',
+ songsDeletedSuccess: '歌曲删除成功',
+ songsDeletedPartial: '已删除 {succeeded}/{total} 首歌曲',
+ deleteUploadConfirm: '确定要删除此上传文件吗?此操作无法撤销。',
+ cannotBeUndone: '此操作无法撤销。',
+
+ // Player
+ nowPlaying: '正在播放',
+ downloadAudio: '下载音频',
+ openInEditor: '在编辑器中打开',
+ anonymous: '匿名用户',
+
+ // PlaylistDetail
+ loadingPlaylist: '加载播放列表中...',
+ playlistNotFound: '播放列表未找到',
+ deletePlaylistConfirm: '确定要删除这个播放列表吗?',
+ dateAdded: '添加日期',
+ justNow: '刚刚',
+ unknown: '未知',
+
+ // SongProfile
+ loadingSong: '加载歌曲中...',
+ songNotFound: '歌曲未找到',
+ similar: '相似',
+ by: '由',
+
+ // ShareModal
+ shareSong: '分享歌曲',
+ shareOnX: '分享到 X',
+ shareOnFacebook: '分享到 Facebook',
+ shareOnWhatsApp: '分享到 WhatsApp',
+ shareOnTelegram: '分享到 Telegram',
+ shareOnReddit: '分享到 Reddit',
+ shareOnLinkedIn: '分享到 LinkedIn',
+ shareViaEmail: '通过邮件分享',
+ copyLink: '复制链接',
+ emailSubject: '来听听这首AI歌曲',
+ emailBody: '嘿!\n\n我创作了这首AI生成的歌曲,觉得你会喜欢:\n\n《{title}》- {creator}\n{style}\n\n点击收听:{url}\n\n使用 ACE-Step UI 制作 - 免费开源的本地AI音乐生成工具!',
+
+ // Reference Modal
+ referenceModalTitle: '参考音频',
+ coverModalTitle: '翻唱音频',
+ referenceModalDescription: '基于参考音轨创作歌曲',
+ coverModalDescription: '将现有音轨转换为新版本',
+ uploadAudio: '上传音频',
+ uploadingAudio: '上传中...',
+ audioFormats: 'MP3、WAV、FLAC',
+ mine: '我的',
+ loadingTracks: '加载中...',
+ noTracksYet: '暂无音轨',
+ uploadAudioFilesAsReferences: '上传音频文件作为参考',
+
+ // Training Module
+ loraTraining: 'LoRA 训练',
+ trainingDescription: '从音频文件构建数据集并训练自定义 LoRA 适配器',
+ datasetBuilder: '数据集构建器',
+ trainLora: '训练 LoRA',
+ quickStart: '快速开始',
+ chooseOneOption: '选择一项:加载现有数据集 或 扫描新目录',
+ loadExistingDataset: '加载现有数据集',
+ loadDataset: '加载',
+ scanNewDirectory: '扫描新目录',
+ scanDataset: '扫描',
+ datasetSettings: '数据集设置',
+ datasetName: '数据集名称',
+ customActivationTag: '自定义激活标签',
+ allInstrumental: '全部纯音乐',
+ tagPosition: '标签位置',
+ tagPrepend: '前置(标签,描述)',
+ tagAppend: '后置(描述,标签)',
+ tagReplace: '替换描述',
+ genreRatio: '风格比例',
+ genreRatioHint: '0% = 全部描述,100% = 全部风格',
+ autoLabelWithAI: 'AI 自动标注',
+ autoLabelDescription: '为音频文件生成元数据:描述、BPM、调式、拍号',
+ skipMetas: '跳过 BPM/调式/拍号',
+ onlyUnlabeled: '仅未标注',
+ autoLabelAll: '自动标注全部',
+ filename: '文件名',
+ labeled: '已标注',
+ saveDataset: '保存数据集',
+ preprocessToTensors: '预处理为张量',
+ preprocessDescription: '将数据集转换为预计算张量以加速训练(需要加载模型)',
+ preprocess: '预处理',
+ preprocessedDataset: '预处理数据集',
+ loraSettings: 'LoRA 设置',
+ loraRank: 'LoRA Rank',
+ loraAlpha: 'LoRA Alpha',
+ dropout: 'Dropout',
+ trainingParameters: '训练参数',
+ learningRate: '学习率',
+ maxEpochs: '最大轮数',
+ gradientAccumulation: '梯度累积',
+ saveEvery: '保存间隔',
+ epochs: '轮',
+ outputDirectory: '输出目录',
+ useFP8: '使用 FP8 量化',
+ fp8Description: '减少显存占用',
+ startTraining: '开始训练',
+ stopTraining: '停止训练',
+ trainingProgress: '训练进度',
+ trainingLog: '训练日志',
+ trainingStatus: '训练状态',
+ tensorboardView: 'TensorBoard 视图',
+ showTensorboard: '显示 TensorBoard',
+ hideTensorboard: '隐藏 TensorBoard',
+ openInNewTab: '在新标签页打开',
+
+ // Training Status Messages
+ scanning: '扫描中...',
+ autoLabeling: '自动标注中...',
+ savingDataset: '保存中...',
+ preprocessing: '预处理中...',
+ loadingDataset: '加载中...',
+ startingTraining: '启动中...',
+ error: '错误',
+ datasetInfo: '数据集:{name},样本数:{samples},已标注:{labeled}',
+ trainingStep: '步骤 {step} - 损失:{loss}',
+ editSample: '编辑样本',
+ caption: '描述',
+ genre: '风格',
+ promptOverride: '提示词覆盖',
+ musicDescription: '音乐描述...',
+ overrideGlobalRatio: '覆盖此样本的全局比例',
+ editableUsedForTraining: '可编辑,用于训练',
+ useGlobalRatio: '使用全局比例',
+ thisSample: '此样本',
+ },
+ ja: {
+ // Navigation
+ create: '作成',
+ library: 'ライブラリ',
+ search: '検索',
+ training: 'トレーニング',
+
+ // Theme
+ lightMode: 'ライトモード',
+ darkMode: 'ダークモード',
+
+ // Auth
+ signIn: 'サインイン',
+ signOut: 'サインアウト',
+ settings: '設定',
+
+ // Username Modal
+ welcomeTitle: 'ACE-Step UIへようこそ',
+ welcomeSubtitle: 'AI音楽作成を始めるために名前を入力してください',
+ yourName: 'お名前',
+ enterYourName: '名前を入力',
+ getStarted: '始める',
+ gettingStarted: '開始中...',
+ yourMusicYourWay: 'あなたの音楽、あなたのスタイルで。無料で無制限にAI音楽を作成。',
+ usernameMinLength: 'ユーザー名は2文字以上である必要があります',
+ usernameInvalidChars: 'ユーザー名は文字、数字、アンダースコア、ハイフンのみ使用できます',
+ failedToSetUsername: 'ユーザー名の設定に失敗しました',
+
+ // Toasts
+ songNotAvailable: 'この曲は利用できません。',
+ unableToPlay: 'この曲を再生できません。',
+ generationTimedOut: '生成がタイムアウトしました',
+ generationFailed: '生成に失敗しました。もう一度お試しください。',
+ playlistCreated: 'プレイリストを作成しました!',
+ failedToCreatePlaylist: 'プレイリストの作成に失敗しました',
+ songAddedToPlaylist: 'プレイリストに追加しました',
+ failedToAddSong: '曲の追加に失敗しました',
+ songDeleted: '曲を削除しました',
+ failedToDeleteSong: '曲の削除に失敗しました',
+
+ // Sidebar
+ aceStepUI: 'ACE-Step UI',
+
+ // Common
+ cancel: 'キャンセル',
+ save: '保存',
+ delete: '削除',
+ edit: '編集',
+ share: '共有',
+ download: 'ダウンロード',
+ play: '再生',
+ pause: '一時停止',
+ normalSpeed: '通常',
+ next: '次へ',
+ previous: '前へ',
+
+ // Placeholders
+ searchPlaceholder: '検索...',
+
+ // Settings
+ language: '言語',
+ english: 'English',
+ chinese: '简体中文',
+ japaneseLanguage: '日本語',
+ koreanLanguage: '한국어',
+ appearance: '外観',
+ profile: 'プロフィール',
+ viewProfile: 'プロフィールを表示',
+ editProfile: 'プロフィールを編集',
+ account: 'アカウント',
+ username: 'ユーザー名',
+ memberSince: '登録日',
+ about: 'について',
+ version: 'バージョン',
+ localAIMusicGenerator: 'ローカルAI音楽ジェネレーター',
+ poweredBy: 'ACE-Step 1.5を搭載。オープンソースで無料で使用できます。',
+ createdBy: '開発者 Ambsd',
+ localizedBy: 'ローカライゼーション&二次開発 bdsqlsz',
+ follow: 'フォロー',
+ done: '完了',
+ light: 'ライト',
+ dark: 'ダーク',
+
+ // Mobile
+ createSong: '曲を作成',
+ viewList: 'リストを表示',
+
+ // CreatePanel - Modes
+ simple: 'シンプル',
+ custom: 'カスタム',
+
+ // CreatePanel - Sections
+ audio: 'オーディオ',
+ lyrics: '歌詞',
+ styleOfMusic: '音楽スタイル',
+ title: 'タイトル',
+ musicParameters: '音楽パラメータ',
+ advancedSettings: '詳細設定',
+
+ // CreatePanel - LoRA
+ loraPath: 'LoRA パス',
+ loraPathPlaceholder: 'LoRA モデルパスを入力...',
+ browseFiles: 'ファイルを参照',
+ loraLoaded: 'LoRA 読み込み済み',
+ loraUnloaded: 'LoRA 未読み込み',
+ loraLoad: '読み込む',
+ loraUnload: 'アンロード',
+ loraScale: 'LoRA スケール',
+ loraScaleDescription: 'LoRA モデルの影響強度を調整',
+
+ // CreatePanel - Audio
+ reference: '参照',
+ cover: 'カバー',
+ fromLibrary: 'ライブラリから',
+ upload: 'アップロード',
+
+ // CreatePanel - Lyrics
+ lyricsPlaceholder: 'ここに歌詞を入力...',
+ leaveLyricsEmpty: 'インストゥルメンタルの場合は空のままにするか、下のトグルを使用',
+ vocal: 'ボーカル',
+ instrumental: 'インストゥルメンタル',
+ vocalLanguage: 'ボーカル言語',
+ autoInstrumental: '自動 / インストゥルメンタル',
+ vocalArabic: 'アラビア語',
+ vocalAzerbaijani: 'アゼルバイジャン語',
+ vocalBulgarian: 'ブルガリア語',
+ vocalBengali: 'ベンガル語',
+ vocalCatalan: 'カタルーニャ語',
+ vocalCzech: 'チェコ語',
+ vocalDanish: 'デンマーク語',
+ vocalGerman: 'ドイツ語',
+ vocalGreek: 'ギリシャ語',
+ vocalEnglish: '英語',
+ vocalSpanish: 'スペイン語',
+ vocalPersian: 'ペルシャ語',
+ vocalFinnish: 'フィンランド語',
+ vocalFrench: 'フランス語',
+ vocalHebrew: 'ヘブライ語',
+ vocalHindi: 'ヒンディー語',
+ vocalCroatian: 'クロアチア語',
+ vocalHaitianCreole: 'ハイチ・クレオール語',
+ vocalHungarian: 'ハンガリー語',
+ vocalIndonesian: 'インドネシア語',
+ vocalIcelandic: 'アイスランド語',
+ vocalItalian: 'イタリア語',
+ vocalJapanese: '日本語',
+ vocalKorean: '韓国語',
+ vocalLatin: 'ラテン語',
+ vocalLithuanian: 'リトアニア語',
+ vocalMalay: 'マレー語',
+ vocalNepali: 'ネパール語',
+ vocalDutch: 'オランダ語',
+ vocalNorwegian: 'ノルウェー語',
+ vocalPunjabi: 'パンジャーブ語',
+ vocalPolish: 'ポーランド語',
+ vocalPortuguese: 'ポルトガル語',
+ vocalRomanian: 'ルーマニア語',
+ vocalRussian: 'ロシア語',
+ vocalSanskrit: 'サンスクリット語',
+ vocalSlovak: 'スロバキア語',
+ vocalSerbian: 'セルビア語',
+ vocalSwedish: 'スウェーデン語',
+ vocalSwahili: 'スワヒリ語',
+ vocalTamil: 'タミル語',
+ vocalTelugu: 'テルグ語',
+ vocalThai: 'タイ語',
+ vocalTagalog: 'タガログ語',
+ vocalTurkish: 'トルコ語',
+ vocalUkrainian: 'ウクライナ語',
+ vocalUrdu: 'ウルドゥー語',
+ vocalVietnamese: 'ベトナム語',
+ vocalCantonese: '広東語',
+ vocalChineseMandarin: '中国語(標準語)',
+
+ // CreatePanel - Style
+ stylePlaceholder: '例:アップビートなポップロック、エモーショナルなバラード、90年代ヒップホップ',
+ genreMoodInstruments: 'ジャンル、ムード、楽器、雰囲気',
+ refreshGenres: 'ジャンル提案を更新',
+ mainGenre: 'メインジャンル',
+ subGenre: 'サブジャンル',
+ nameSong: '曲名を付ける',
+
+ // CreatePanel - Parameters
+ bpm: 'BPM',
+ auto: '自動',
+ duration: '長さ',
+ seconds: '秒',
+ keyScale: 'キーとスケール',
+ timeSignature: '拍子',
+
+ // CreatePanel - Advanced
+ randomSeed: 'ランダムシード',
+ thinking: '思考',
+ audioFormat: 'オーディオ形式',
+ inferenceSteps: '推論ステップ',
+ guidanceScale: 'ガイダンススケール',
+ inferMethod: '推論方法',
+ shift: 'シフト',
+ timestepShiftForBase: 'ベースモデルのタイムステップシフト(turboでは無効)',
+ expertControls: 'エキスパートコントロール',
+ lmParameters: 'LMパラメータ',
+ controlLyricGeneration: '歌詞生成と創造性を制御',
+ transform: '変換',
+ controlSourceAudio: 'モデルがソースオーディオに従う程度を制御',
+ audioCodes: 'オーディオコード',
+ optionalAudioCodes: 'オプションのオーディオコードペイロード',
+ taskType: 'タスクタイプ',
+ textToMusic: 'テキスト → 音楽',
+ audioCoverStrength: 'オーディオカバー強度',
+ repaintingStart: 'リペイント開始',
+ repaintingEnd: 'リペイント終了',
+ instruction: '指示',
+ lmTemperature: 'LM温度',
+ higherMoreRandom: '高いほどランダム(0-2)',
+ lmCfgScale: 'LM CFGスケール',
+ noCfgScale: '1.0 = CFGなし(1-3)',
+ topK: 'Top-K',
+ topP: 'Top-P',
+ lmNegativePrompt: 'LMネガティブプロンプト',
+ noUserInput: 'ユーザー入力なし',
+ thingsToAvoid: '避けるべきこと...',
+ useWhenCfgScaleGreater: 'LM CFGスケール > 1.0の場合に使用',
+ lmTopK: 'LM Top-K',
+ lmTopP: 'LM Top-P',
+
+ // Guidance section
+ guidance: 'ガイダンス',
+ advancedCfgScheduling: '高度なCFGスケジューリング制御。',
+ cfgIntervalStart: 'CFG間隔開始',
+ cfgIntervalEnd: 'CFG間隔終了',
+ customTimesteps: 'カスタムタイムステップ',
+ timestepsPlaceholder: '例:1,3,5,7',
+ scoreScale: 'スコアスケール',
+ lmBatchChunkSize: 'LMバッチチャンクサイズ',
+ trackName: 'トラック名',
+ optionalTrackName: 'オプションのトラック名',
+ completeTrackClasses: '完全なトラッククラス',
+ trackClassesPlaceholder: 'クラス-a、クラス-b',
+ useAdg: 'ADGを使用',
+ allowLmBatch: 'LMバッチを許可',
+ useCotMetas: 'CoTメタを使用',
+ useCotCaption: 'CoTキャプションを使用',
+ useCotLanguage: 'CoT言語を使用',
+ autogen: '自動生成',
+ constrainedDecodingDebug: '制約付きデコーディングデバッグ',
+ formatCaption: 'キャプションをフォーマット',
+ getScores: 'スコアを取得',
+ getLrcLyrics: 'LRC(歌詞)を取得',
+ batchSize: 'バッチサイズ(バリエーション)',
+ variations: 'バリエーション',
+ bulkGenerate: '一括生成',
+ job: 'ジョブ',
+ jobs: 'ジョブ',
+ queueMultipleJobs: '同じ設定で複数の独立した生成ジョブをキューに追加',
+ numberOfVariations: '生成する曲のバリエーション数',
+ moreStepsBetterQuality: 'ステップが多いほど品質が高く、遅くなります(turboには8を推奨)',
+ howCloselyFollowPrompt: 'プロンプトにどれだけ忠実に従うか',
+ seed: 'シード',
+ randomSeedRecommended: '毎回ランダム化(推奨)',
+ fixedSeedReproducible: '再現可能な結果のための固定シード',
+ enterFixedSeed: '固定シードを入力',
+ thinkingCot: '思考(CoT)',
+ mp3Smaller: 'MP3(小さい)',
+ flacLossless: 'FLAC(ロスレス)',
+ odeDeterministic: 'ODE(決定論的)',
+ sdeStochastic: 'SDE(確率的)',
+ min: '分',
+
+ // CreatePanel - Drag & Drop
+ dropToUseAudio: 'ドロップしてオーディオを使用',
+ dropToUpload: 'ドロップしてアップロード',
+ usingAsReference: '参照として使用',
+ usingAsCover: 'カバーとして使用',
+ uploadingAsReference: '参照としてアップロード',
+ uploadingAsCover: 'カバーとしてアップロード',
+
+ // CreatePanel - Vocal Gender
+ vocalGender: 'ボーカルの性別',
+ male: '男性',
+ female: '女性',
+
+ // CreatePanel - LM Backend & Model
+ lmBackendLabel: 'LMバックエンド',
+ lmBackendPt: 'PT(〜1.6 GB VRAM)',
+ lmBackendVllm: 'VLLM(〜9.2 GB VRAM)',
+ lmBackendHint: 'PTはVRAMが少なく、VLLMは高性能GPUで高速',
+ lmModelLabel: 'LMモデル',
+ lmModel06B: '0.6B(最軽量、〜0.5 GB VRAM)',
+ lmModel17B: '1.7B(バランス、〜1.5 GB VRAM)',
+ lmModel4B: '4B(最高品質、〜4 GB VRAM)',
+ lmModelHint: '歌詞/スタイル強化に使用するLLMを制御。未インストールの場合自動ダウンロード。',
+
+ // CreatePanel - Transcription
+ transcribing: '文字起こし中...',
+ transcribingWithWhisper: 'Whisperで文字起こし中…',
+
+ // CreatePanel - Library Tabs
+ uploaded: 'アップロード済み',
+ createdTab: '作成済み',
+ useTrack: '使用',
+ noCreatedSongsYet: '作成した曲がまだありません',
+ generateSongsToReuse: '曲を生成してカバーや参照として再利用',
+
+ // CreatePanel - Actions
+ generate: '生成',
+ generating: '生成中...',
+ createButton: '作成',
+ formatLyrics: '歌詞をフォーマット',
+ formatting: 'フォーマット中...',
+ clearAll: 'すべてクリア',
+
+ // Simple Mode
+ describeYourSong: '曲を説明',
+ songDescriptionPlaceholder: '友達との夏の冒険についての明るいポップソング...',
+ quickSettings: 'クイック設定',
+ key: 'キー',
+ time: '拍子',
+
+ // CreatePanel - Errors
+ loginToGenerate: '音楽を生成するにはログインしてください',
+ uploadFailed: 'アップロードに失敗しました',
+ formatFailed: 'フォーマットに失敗しました',
+ formatFailedDetail: 'フォーマットに失敗しました。LLMが初期化されていることを確認してください。',
+ formatFailedLlmUnavailable: 'フォーマットに失敗しました。LLMが利用できない可能性があります。',
+ deleteSongConfirm: '「{title}」を削除しますか?この操作は元に戻せません。',
+ profileUpdateFailed: 'プロフィールの更新に失敗しました',
+ ffmpegLoadFailed: 'ビデオエンコーダーの読み込みに失敗しました。更新してもう一度お試しください。',
+ videoRenderFailed: 'ビデオレンダリングに失敗しました。もう一度お試しください。',
+
+ // SongList / Filters
+ searchYourSongs: '曲を検索...',
+ filters: 'フィルター',
+ refineBy: '絞り込み',
+ liked: 'いいね',
+ public: '公開',
+ private: '非公開',
+ generatingStatus: '生成中',
+ selectSongToView: '詳細を表示する曲を選択',
+ noSongsMatchFilters: 'フィルターに一致する曲がありません。',
+ clearFilters: 'フィルターをクリア',
+
+ // RightSidebar - Song Details
+ songDetails: '曲の詳細',
+ created: '作成日',
+ styleTags: 'スタイルとタグ',
+ lyricsSection: '歌詞',
+ copyLyrics: 'コピー',
+
+ // Languages
+ japanese: '日本語',
+ spanish: 'スペイン語',
+ german: 'ドイツ語',
+ french: 'フランス語',
+ portuguese: 'ポルトガル語',
+ russian: 'ロシア語',
+ italian: 'イタリア語',
+ dutch: 'オランダ語',
+ polish: 'ポーランド語',
+ turkish: 'トルコ語',
+ vietnamese: 'ベトナム語',
+ czech: 'チェコ語',
+ persian: 'ペルシャ語',
+ arabic: 'アラビア語',
+ korean: '韓国語',
+ thai: 'タイ語',
+ hindi: 'ヒンディー語',
+ indonesian: 'インドネシア語',
+ ukrainian: 'ウクライナ語',
+ hungarian: 'ハンガリー語',
+ swedish: 'スウェーデン語',
+ romanian: 'ルーマニア語',
+ greek: 'ギリシャ語',
+
+ // Task Types
+ audio2audio: 'オーディオ → オーディオ',
+ coverTask: 'カバー',
+ repaintTask: 'リペイント',
+
+ // Search Page
+ searchSongsPlaceholder: '曲、プレイリスト、クリエイター、スタイルを検索',
+ songsMatching: '一致する曲',
+ featuredSongs: '注目の曲',
+ noSongsFound: '一致する曲が見つかりません',
+ creatorsMatching: '一致するクリエイター',
+ featuredCreators: '注目のクリエイター',
+ noCreatorsFound: '一致するクリエイターが見つかりません',
+ noCreatorsYet: 'まだクリエイターがいません。最初に音楽を共有しましょう!',
+ playlistsMatching: '一致するプレイリスト',
+ featuredPlaylists: '注目のプレイリスト',
+ noPlaylistsFound: '一致するプレイリストが見つかりません',
+ noPlaylistsYet: '公開プレイリストがまだありません。作成してお気に入りを共有しましょう!',
+ genres: 'ジャンル',
+ songs: '曲',
+
+ // Library View
+ yourLibrary: 'マイライブラリ',
+ newPlaylist: '新しいプレイリスト',
+ likedSongs: 'いいねした曲',
+ playlists: 'プレイリスト',
+ playlist: 'プレイリスト',
+ byYou: 'あなたが作成',
+
+ // User Profile
+ back: '戻る',
+ loadingProfile: '読み込み中...',
+ userNotFound: 'ユーザーが見つかりません',
+ goBack: '戻る',
+ likes: 'いいね',
+ plays: '再生回数',
+ recent: '最新',
+ top: '人気',
+ noPublicSongsYet: '公開曲がまだありません',
+ seeMore: 'もっと見る',
+ joined: '参加日',
+ supportingSince: 'サポート開始',
+ avatarImage: 'アバター画像',
+ uploadAvatar: 'アバターをアップロード',
+ avatarFormats: 'JPG、PNG、WebP、GIF • 最大5MB',
+ bannerImage: 'バナー画像',
+ clickToUploadBanner: 'クリックしてバナーをアップロード',
+ bannerFormats: '推奨サイズ:1500x500px • JPG、PNG、WebP、GIF • 最大5MB',
+ bio: '自己紹介',
+ bioPlaceholder: '自己紹介を書いてください...',
+ uploadingAvatar: 'アバターをアップロード中...',
+ uploadingBanner: 'バナーをアップロード中...',
+ saving: '保存中...',
+ saveChanges: '変更を保存',
+
+ // Playlist Modals
+ createPlaylist: 'プレイリストを作成',
+ playlistName: '名前',
+ playlistNamePlaceholder: '私の素晴らしいプレイリスト',
+ playlistDescription: '説明',
+ descriptionPlaceholder: 'コーディング時の雰囲気...',
+ addToPlaylist: 'プレイリストに追加',
+ createNewPlaylist: '新しいプレイリストを作成',
+ noExistingPlaylists: 'プレイリストがまだありません。',
+
+ // Edit Profile Modal (Settings)
+ usernameLabel: 'ユーザー名',
+ usernamePlaceholder: 'ユーザー名',
+ usernameMinLengthError: 'ユーザー名は2文字以上である必要があります',
+ usernameTakenError: 'このユーザー名は既に使用されています',
+ usernameUpdateFailedError: 'ユーザー名の更新に失敗しました',
+ usernameRequirements: '文字、数字、アンダースコア、ハイフンのみ使用可能',
+
+ // Song Details (RightSidebar)
+ more: 'もっと',
+ copy: 'コピー',
+ copied: 'コピーしました!',
+ copyAllTags: 'すべてのタグをコピー',
+
+ // Song Dropdown Menu
+ createVideo: 'ビデオを作成',
+ editAudio: 'オーディオを編集',
+ extractStems: 'ステムを抽出',
+ reusePrompt: 'プロンプトを再利用',
+ deleteSong: '曲を削除',
+ useAsReference: '参照として使用',
+ coverSong: 'カバーソング',
+ confirmDeleteTitle: '曲を削除',
+ confirmDeleteManyTitle: '曲を削除',
+ deleteSongsConfirm: '{count}曲を削除しますか?この操作は元に戻せません。',
+ songsDeletedSuccess: '曲を削除しました',
+ songsDeletedPartial: '{succeeded}/{total}曲を削除しました',
+ deleteUploadConfirm: 'このアップロードを削除しますか?この操作は元に戻せません。',
+ cannotBeUndone: 'この操作は元に戻せません。',
+
+ // Player
+ nowPlaying: '再生中',
+ downloadAudio: 'オーディオをダウンロード',
+ openInEditor: 'エディターで開く',
+ anonymous: '匿名ユーザー',
+
+ // PlaylistDetail
+ loadingPlaylist: 'プレイリストを読み込み中...',
+ playlistNotFound: 'プレイリストが見つかりません',
+ deletePlaylistConfirm: 'このプレイリストを削除してもよろしいですか?',
+ dateAdded: '追加日',
+ justNow: 'たった今',
+ unknown: '不明',
+
+ // SongProfile
+ loadingSong: '曲を読み込み中...',
+ songNotFound: '曲が見つかりません',
+ similar: '類似',
+ by: '作成者',
+
+ // ShareModal
+ shareSong: '曲を共有',
+ shareOnX: 'Xで共有',
+ shareOnFacebook: 'Facebookで共有',
+ shareOnWhatsApp: 'WhatsAppで共有',
+ shareOnTelegram: 'Telegramで共有',
+ shareOnReddit: 'Redditで共有',
+ shareOnLinkedIn: 'LinkedInで共有',
+ shareViaEmail: 'メールで共有',
+ copyLink: 'リンクをコピー',
+ emailSubject: 'このAI曲をチェックしてください',
+ emailBody: 'こんにちは!\n\n私がこのAI生成の曲を作りました。気に入ってもらえると思います:\n\n「{title}」by {creator}\n{style}\n\nここで聴いてください:{url}\n\nACE-Step UIで作成 - 無料でオープンソースのローカルAI音楽生成!',
+
+ // Reference Modal
+ referenceModalTitle: 'リファレンス',
+ coverModalTitle: 'カバー',
+ referenceModalDescription: 'リファレンストラックに触発された曲を作成',
+ coverModalDescription: '既存のトラックを新しいバージョンに変換',
+ uploadAudio: 'オーディオをアップロード',
+ uploadingAudio: 'アップロード中...',
+ audioFormats: 'MP3、WAV、FLAC',
+ mine: 'マイトラック',
+ loadingTracks: '読み込み中...',
+ noTracksYet: 'トラックがまだありません',
+ uploadAudioFilesAsReferences: 'リファレンスとして使用するオーディオファイルをアップロード',
+
+ // Training Module
+ loraTraining: 'LoRAトレーニング',
+ trainingDescription: 'オーディオファイルからデータセットを構築し、カスタムLoRAアダプターをトレーニング',
+ datasetBuilder: 'データセットビルダー',
+ trainLora: 'LoRAをトレーニング',
+ quickStart: 'クイックスタート',
+ chooseOneOption: '選択:既存のデータセットを読み込む または 新しいディレクトリをスキャン',
+ loadExistingDataset: '既存のデータセットを読み込む',
+ loadDataset: '読み込む',
+ scanNewDirectory: '新しいディレクトリをスキャン',
+ scanDataset: 'スキャン',
+ datasetSettings: 'データセット設定',
+ datasetName: 'データセット名',
+ customActivationTag: 'カスタム活性化タグ',
+ allInstrumental: '全てインストゥルメンタル',
+ tagPosition: 'タグの位置',
+ tagPrepend: '前置(タグ、キャプション)',
+ tagAppend: '後置(キャプション、タグ)',
+ tagReplace: 'キャプションを置換',
+ genreRatio: 'ジャンル比率',
+ genreRatioHint: '0% = 全てキャプション、100% = 全てジャンル',
+ autoLabelWithAI: 'AIで自動ラベル付け',
+ autoLabelDescription: 'オーディオファイルのメタデータを生成:キャプション、BPM、キー、拍子',
+ skipMetas: 'BPM/キー/拍子をスキップ',
+ onlyUnlabeled: 'ラベルなしのみ',
+ autoLabelAll: '全て自動ラベル付け',
+ filename: 'ファイル名',
+ labeled: 'ラベル付き',
+ saveDataset: 'データセットを保存',
+ preprocessToTensors: 'テンソルに前処理',
+ preprocessDescription: 'データセットを事前計算されたテンソルに変換して高速トレーニング(モデルのロードが必要)',
+ preprocess: '前処理',
+ preprocessedDataset: '前処理済みデータセット',
+ loraSettings: 'LoRA設定',
+ loraRank: 'LoRAランク',
+ loraAlpha: 'LoRA Alpha',
+ dropout: 'ドロップアウト',
+ trainingParameters: 'トレーニングパラメータ',
+ learningRate: '学習率',
+ maxEpochs: '最大エポック数',
+ gradientAccumulation: '勾配累積',
+ saveEvery: '保存間隔',
+ epochs: 'エポック',
+ outputDirectory: '出力ディレクトリ',
+ useFP8: 'FP8量子化を使用',
+ fp8Description: 'VRAMを削減',
+ startTraining: 'トレーニング開始',
+ stopTraining: 'トレーニング停止',
+ trainingProgress: 'トレーニング進行状況',
+ trainingLog: 'トレーニングログ',
+ trainingStatus: 'トレーニングステータス',
+ tensorboardView: 'TensorBoardビュー',
+ showTensorboard: 'TensorBoardを表示',
+ hideTensorboard: 'TensorBoardを非表示',
+ openInNewTab: '新しいタブで開く',
+
+ // Training Status Messages
+ scanning: 'スキャン中...',
+ autoLabeling: '自動ラベル付け中...',
+ savingDataset: '保存中...',
+ preprocessing: '前処理中...',
+ loadingDataset: '読み込み中...',
+ startingTraining: '開始中...',
+ error: 'エラー',
+ datasetInfo: 'データセット: {name}、サンプル数: {samples}、ラベル付き: {labeled}',
+ trainingStep: 'ステップ {step} - 損失: {loss}',
+ editSample: 'サンプルを編集',
+ caption: 'キャプション',
+ genre: 'ジャンル',
+ promptOverride: 'プロンプト上書き',
+ musicDescription: '音楽の説明...',
+ overrideGlobalRatio: 'このサンプルのグローバル比率を上書き',
+ editableUsedForTraining: '編集可能、トレーニングに使用',
+ useGlobalRatio: 'グローバル比率を使用',
+ thisSample: 'このサンプル',
+ },
+ ko: {
+ // Navigation
+ create: '생성',
+ library: '라이브러리',
+ search: '검색',
+ training: '훈련',
+
+ // Theme
+ lightMode: '라이트 모드',
+ darkMode: '다크 모드',
+
+ // Auth
+ signIn: '로그인',
+ signOut: '로그아웃',
+ settings: '설정',
+
+ // Username Modal
+ welcomeTitle: 'ACE-Step UI에 오신 것을 환영합니다',
+ welcomeSubtitle: 'AI 음악 제작을 시작하려면 이름을 입력하세요',
+ yourName: '이름',
+ enterYourName: '이름 입력',
+ getStarted: '시작하기',
+ gettingStarted: '시작 중...',
+ yourMusicYourWay: '당신의 음악, 당신만의 방식으로. 무료로 무제한 AI 음악 제작.',
+ usernameMinLength: '사용자 이름은 최소 2자 이상이어야 합니다',
+ usernameInvalidChars: '사용자 이름은 문자, 숫자, 밑줄, 하이픈만 사용할 수 있습니다',
+ failedToSetUsername: '사용자 이름 설정에 실패했습니다',
+
+ // Toasts
+ songNotAvailable: '이 곡은 더 이상 사용할 수 없습니다.',
+ unableToPlay: '이 곡을 재생할 수 없습니다.',
+ generationTimedOut: '생성 시간 초과',
+ generationFailed: '생성에 실패했습니다. 다시 시도해주세요.',
+ playlistCreated: '재생목록이 생성되었습니다!',
+ failedToCreatePlaylist: '재생목록 생성에 실패했습니다',
+ songAddedToPlaylist: '재생목록에 추가되었습니다',
+ failedToAddSong: '곡 추가에 실패했습니다',
+ songDeleted: '곡이 삭제되었습니다',
+ failedToDeleteSong: '곡 삭제에 실패했습니다',
+
+ // Sidebar
+ aceStepUI: 'ACE-Step UI',
+
+ // Common
+ cancel: '취소',
+ save: '저장',
+ delete: '삭제',
+ edit: '편집',
+ share: '공유',
+ download: '다운로드',
+ play: '재생',
+ pause: '일시정지',
+ normalSpeed: '보통',
+ next: '다음',
+ previous: '이전',
+
+ // Placeholders
+ searchPlaceholder: '검색...',
+
+ // Settings
+ language: '언어',
+ english: 'English',
+ chinese: '简体中文',
+ japaneseLanguage: '日本語',
+ koreanLanguage: '한국어',
+ appearance: '외관',
+ profile: '프로필',
+ viewProfile: '프로필 보기',
+ editProfile: '프로필 편집',
+ account: '계정',
+ username: '사용자 이름',
+ memberSince: '가입일',
+ about: '정보',
+ version: '버전',
+ localAIMusicGenerator: '로컬 AI 음악 생성기',
+ poweredBy: 'ACE-Step 1.5 기반. 오픈 소스이며 무료로 사용 가능합니다.',
+ createdBy: '개발자 Ambsd',
+ localizedBy: '현지화 및 2차 개발 bdsqlsz',
+ follow: '팔로우',
+ done: '완료',
+ light: '라이트',
+ dark: '다크',
+
+ // Mobile
+ createSong: '곡 만들기',
+ viewList: '목록 보기',
+
+ // CreatePanel - Modes
+ simple: '간단',
+ custom: '사용자 정의',
+
+ // CreatePanel - Sections
+ audio: '오디오',
+ lyrics: '가사',
+ styleOfMusic: '음악 스타일',
+ title: '제목',
+ musicParameters: '음악 매개변수',
+ advancedSettings: '고급 설정',
+
+ // CreatePanel - LoRA
+ loraPath: 'LoRA 경로',
+ loraPathPlaceholder: 'LoRA 모델 경로 입력...',
+ browseFiles: '파일 찾아보기',
+ loraLoaded: 'LoRA 로드됨',
+ loraUnloaded: 'LoRA 언로드됨',
+ loraLoad: '로드',
+ loraUnload: '언로드',
+ loraScale: 'LoRA 강도',
+ loraScaleDescription: 'LoRA 모델의 영향 강도 조절',
+
+ // CreatePanel - Audio
+ reference: '참조',
+ cover: '커버',
+ fromLibrary: '라이브러리에서',
+ upload: '업로드',
+
+ // CreatePanel - Lyrics
+ lyricsPlaceholder: '여기에 가사를 입력하세요...',
+ leaveLyricsEmpty: '연주곡의 경우 비워두거나 아래 토글 사용',
+ vocal: '보컬',
+ instrumental: '연주곡',
+ vocalLanguage: '보컬 언어',
+ autoInstrumental: '자동 / 연주곡',
+ vocalArabic: '아랍어',
+ vocalAzerbaijani: '아제르바이잔어',
+ vocalBulgarian: '불가리아어',
+ vocalBengali: '벵골어',
+ vocalCatalan: '카탈루냐어',
+ vocalCzech: '체코어',
+ vocalDanish: '덴마크어',
+ vocalGerman: '독일어',
+ vocalGreek: '그리스어',
+ vocalEnglish: '영어',
+ vocalSpanish: '스페인어',
+ vocalPersian: '페르시아어',
+ vocalFinnish: '핀란드어',
+ vocalFrench: '프랑스어',
+ vocalHebrew: '히브리어',
+ vocalHindi: '힌디어',
+ vocalCroatian: '크로아티아어',
+ vocalHaitianCreole: '아이티 크레올어',
+ vocalHungarian: '헝가리어',
+ vocalIndonesian: '인도네시아어',
+ vocalIcelandic: '아이슬란드어',
+ vocalItalian: '이탈리아어',
+ vocalJapanese: '일본어',
+ vocalKorean: '한국어',
+ vocalLatin: '라틴어',
+ vocalLithuanian: '리투아니아어',
+ vocalMalay: '말레이어',
+ vocalNepali: '네팔어',
+ vocalDutch: '네덜란드어',
+ vocalNorwegian: '노르웨이어',
+ vocalPunjabi: '펀자브어',
+ vocalPolish: '폴란드어',
+ vocalPortuguese: '포르투갈어',
+ vocalRomanian: '루마니아어',
+ vocalRussian: '러시아어',
+ vocalSanskrit: '산스크리트어',
+ vocalSlovak: '슬로바키아어',
+ vocalSerbian: '세르비아어',
+ vocalSwedish: '스웨덴어',
+ vocalSwahili: '스와힐리어',
+ vocalTamil: '타밀어',
+ vocalTelugu: '텔루구어',
+ vocalThai: '태국어',
+ vocalTagalog: '타갈로그어',
+ vocalTurkish: '터키어',
+ vocalUkrainian: '우크라이나어',
+ vocalUrdu: '우르두어',
+ vocalVietnamese: '베트남어',
+ vocalCantonese: '광둥어',
+ vocalChineseMandarin: '중국어(표준어)',
+
+ // CreatePanel - Style
+ stylePlaceholder: '예: 경쾌한 팝 록, 감성적인 발라드, 90년대 힙합',
+ genreMoodInstruments: '장르, 분위기, 악기, 느낌',
+ refreshGenres: '장르 제안 새로고침',
+ mainGenre: '주요 장르',
+ subGenre: '하위 장르',
+ nameSong: '곡 이름 짓기',
+
+ // CreatePanel - Parameters
+ bpm: 'BPM',
+ auto: '자동',
+ duration: '길이',
+ seconds: '초',
+ keyScale: '키와 스케일',
+ timeSignature: '박자',
+
+ // CreatePanel - Advanced
+ randomSeed: '랜덤 시드',
+ thinking: '생각',
+ audioFormat: '오디오 형식',
+ inferenceSteps: '추론 단계',
+ guidanceScale: '가이던스 스케일',
+ inferMethod: '추론 방법',
+ shift: '시프트',
+ timestepShiftForBase: '베이스 모델의 타임스텝 시프트 (turbo에서는 무효)',
+ expertControls: '전문가 제어',
+ lmParameters: 'LM 매개변수',
+ controlLyricGeneration: '가사 생성과 창의성 제어',
+ transform: '변환',
+ controlSourceAudio: '모델이 소스 오디오를 따르는 정도를 제어',
+ audioCodes: '오디오 코드',
+ optionalAudioCodes: '선택적 오디오 코드 페이로드',
+ taskType: '작업 유형',
+ textToMusic: '텍스트 → 음악',
+ audioCoverStrength: '오디오 커버 강도',
+ repaintingStart: '리페인팅 시작',
+ repaintingEnd: '리페인팅 종료',
+ instruction: '지시',
+ lmTemperature: 'LM 온도',
+ higherMoreRandom: '높을수록 랜덤 (0-2)',
+ lmCfgScale: 'LM CFG 스케일',
+ noCfgScale: '1.0 = CFG 없음 (1-3)',
+ topK: 'Top-K',
+ topP: 'Top-P',
+ lmNegativePrompt: 'LM 네거티브 프롬프트',
+ noUserInput: '사용자 입력 없음',
+ thingsToAvoid: '피해야 할 것들...',
+ useWhenCfgScaleGreater: 'LM CFG 스케일 > 1.0일 때 사용',
+ lmTopK: 'LM Top-K',
+ lmTopP: 'LM Top-P',
+
+ // Guidance section
+ guidance: '가이던스',
+ advancedCfgScheduling: '고급 CFG 스케줄링 제어.',
+ cfgIntervalStart: 'CFG 간격 시작',
+ cfgIntervalEnd: 'CFG 간격 종료',
+ customTimesteps: '사용자 정의 타임스텝',
+ timestepsPlaceholder: '예: 1,3,5,7',
+ scoreScale: '스코어 스케일',
+ lmBatchChunkSize: 'LM 배치 청크 크기',
+ trackName: '트랙 이름',
+ optionalTrackName: '선택적 트랙 이름',
+ completeTrackClasses: '완전한 트랙 클래스',
+ trackClassesPlaceholder: '클래스-a, 클래스-b',
+ useAdg: 'ADG 사용',
+ allowLmBatch: 'LM 배치 허용',
+ useCotMetas: 'CoT 메타 사용',
+ useCotCaption: 'CoT 캡션 사용',
+ useCotLanguage: 'CoT 언어 사용',
+ autogen: '자동 생성',
+ constrainedDecodingDebug: '제약 디코딩 디버그',
+ formatCaption: '캡션 포맷',
+ getScores: '점수 가져오기',
+ getLrcLyrics: 'LRC(가사) 가져오기',
+ batchSize: '배치 크기 (변형)',
+ variations: '변형',
+ bulkGenerate: '대량 생성',
+ job: '작업',
+ jobs: '작업',
+ queueMultipleJobs: '동일한 설정으로 여러 독립 생성 작업 대기열에 추가',
+ numberOfVariations: '생성할 곡 변형 수',
+ moreStepsBetterQuality: '단계가 많을수록 품질이 높고 느립니다 (turbo는 8 권장)',
+ howCloselyFollowPrompt: '프롬프트를 얼마나 엄격히 따를지',
+ seed: '시드',
+ randomSeedRecommended: '매 실행마다 무작위 (권장)',
+ fixedSeedReproducible: '재현 가능한 결과를 위한 고정 시드',
+ enterFixedSeed: '고정 시드 입력',
+ thinkingCot: '생각 (CoT)',
+ mp3Smaller: 'MP3 (작음)',
+ flacLossless: 'FLAC (무손실)',
+ odeDeterministic: 'ODE (결정론적)',
+ sdeStochastic: 'SDE (확률적)',
+ min: '분',
+
+ // CreatePanel - Drag & Drop
+ dropToUseAudio: '드롭하여 오디오 사용',
+ dropToUpload: '드롭하여 업로드',
+ usingAsReference: '참조로 사용',
+ usingAsCover: '커버로 사용',
+ uploadingAsReference: '참조로 업로드',
+ uploadingAsCover: '커버로 업로드',
+
+ // CreatePanel - Vocal Gender
+ vocalGender: '보컬 성별',
+ male: '남성',
+ female: '여성',
+
+ // CreatePanel - LM Backend & Model
+ lmBackendLabel: 'LM 백엔드',
+ lmBackendPt: 'PT (~1.6 GB VRAM)',
+ lmBackendVllm: 'VLLM (~9.2 GB VRAM)',
+ lmBackendHint: 'PT는 VRAM이 적고, VLLM은 고성능 GPU에서 더 빠름',
+ lmModelLabel: 'LM 모델',
+ lmModel06B: '0.6B (가장 가벼움, ~0.5 GB VRAM)',
+ lmModel17B: '1.7B (균형, ~1.5 GB VRAM)',
+ lmModel4B: '4B (최고 품질, ~4 GB VRAM)',
+ lmModelHint: '가사/스타일 향상에 사용되는 LLM을 제어. 없으면 자동 다운로드.',
+
+ // CreatePanel - Transcription
+ transcribing: '전사 중...',
+ transcribingWithWhisper: 'Whisper로 전사 중…',
+
+ // CreatePanel - Library Tabs
+ uploaded: '업로드됨',
+ createdTab: '생성됨',
+ useTrack: '사용',
+ noCreatedSongsYet: '생성된 곡이 아직 없습니다',
+ generateSongsToReuse: '곡을 생성하여 커버나 참조로 재사용',
+
+ // CreatePanel - Actions
+ generate: '생성',
+ generating: '생성 중...',
+ createButton: '만들기',
+ formatLyrics: '가사 포맷',
+ formatting: '포맷 중...',
+ clearAll: '모두 지우기',
+
+ // Simple Mode
+ describeYourSong: '곡 설명',
+ songDescriptionPlaceholder: '친구들과 여름 모험에 대한 밝은 팝송...',
+ quickSettings: '빠른 설정',
+ key: '키',
+ time: '박자',
+
+ // CreatePanel - Errors
+ loginToGenerate: '음악을 생성하려면 로그인하세요',
+ uploadFailed: '업로드 실패',
+ formatFailed: '포맷 실패',
+ formatFailedDetail: '포맷 실패. LLM이 초기화되었는지 확인하세요.',
+ formatFailedLlmUnavailable: '포맷 실패. LLM을 사용할 수 없을 수 있습니다.',
+ deleteSongConfirm: '「{title}」을(를) 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.',
+ profileUpdateFailed: '프로필 업데이트에 실패했습니다',
+ ffmpegLoadFailed: '비디오 인코더 로드에 실패했습니다. 새로고침 후 다시 시도하세요.',
+ videoRenderFailed: '비디오 렌더링에 실패했습니다. 다시 시도하세요.',
+
+ // SongList / Filters
+ searchYourSongs: '곡 검색...',
+ filters: '필터',
+ refineBy: '세분화',
+ liked: '좋아요',
+ public: '공개',
+ private: '비공개',
+ generatingStatus: '생성 중',
+ selectSongToView: '세부 정보를 볼 곡 선택',
+ noSongsMatchFilters: '필터와 일치하는 곡이 없습니다.',
+ clearFilters: '필터 지우기',
+
+ // RightSidebar - Song Details
+ songDetails: '곡 상세정보',
+ created: '생성일',
+ styleTags: '스타일 및 태그',
+ lyricsSection: '가사',
+ copyLyrics: '복사',
+
+ // Languages
+ japanese: '일본어',
+ spanish: '스페인어',
+ german: '독일어',
+ french: '프랑스어',
+ portuguese: '포르투갈어',
+ russian: '러시아어',
+ italian: '이탈리아어',
+ dutch: '네덜란드어',
+ polish: '폴란드어',
+ turkish: '터키어',
+ vietnamese: '베트남어',
+ czech: '체코어',
+ persian: '페르시아어',
+ arabic: '아랍어',
+ korean: '한국어',
+ thai: '태국어',
+ hindi: '힌디어',
+ indonesian: '인도네시아어',
+ ukrainian: '우크라이나어',
+ hungarian: '헝가리어',
+ swedish: '스웨덴어',
+ romanian: '루마니아어',
+ greek: '그리스어',
+
+ // Task Types
+ audio2audio: '오디오 → 오디오',
+ coverTask: '커버',
+ repaintTask: '리페인트',
+
+ // Search Page
+ searchSongsPlaceholder: '곡, 재생목록, 제작자 또는 스타일 검색',
+ songsMatching: '일치하는 곡',
+ featuredSongs: '추천 곡',
+ noSongsFound: '일치하는 곡을 찾을 수 없습니다',
+ creatorsMatching: '일치하는 제작자',
+ featuredCreators: '추천 제작자',
+ noCreatorsFound: '일치하는 제작자를 찾을 수 없습니다',
+ noCreatorsYet: '아직 제작자가 없습니다. 음악을 공유하는 첫 번째 사람이 되세요!',
+ playlistsMatching: '일치하는 재생목록',
+ featuredPlaylists: '추천 재생목록',
+ noPlaylistsFound: '일치하는 재생목록을 찾을 수 없습니다',
+ noPlaylistsYet: '공개 재생목록이 아직 없습니다. 만들고 즐겨찾기를 공유하세요!',
+ genres: '장르',
+ songs: '곡',
+
+ // Library View
+ yourLibrary: '내 라이브러리',
+ newPlaylist: '새 재생목록',
+ likedSongs: '좋아하는 곡',
+ playlists: '재생목록',
+ playlist: '재생목록',
+ byYou: '내가 만든',
+
+ // User Profile
+ back: '뒤로',
+ loadingProfile: '로딩 중...',
+ userNotFound: '사용자를 찾을 수 없습니다',
+ goBack: '뒤로 가기',
+ likes: '좋아요',
+ plays: '재생 수',
+ recent: '최신',
+ top: '인기',
+ noPublicSongsYet: '공개 곡이 아직 없습니다',
+ seeMore: '더 보기',
+ joined: '가입일',
+ supportingSince: '후원 시작일',
+ avatarImage: '아바타 이미지',
+ uploadAvatar: '아바타 업로드',
+ avatarFormats: 'JPG, PNG, WebP, GIF • 최대 5MB',
+ bannerImage: '배너 이미지',
+ clickToUploadBanner: '클릭하여 배너 업로드',
+ bannerFormats: '권장 크기: 1500x500px • JPG, PNG, WebP, GIF • 최대 5MB',
+ bio: '자기소개',
+ bioPlaceholder: '자신에 대해 소개하세요...',
+ uploadingAvatar: '아바타 업로드 중...',
+ uploadingBanner: '배너 업로드 중...',
+ saving: '저장 중...',
+ saveChanges: '변경 사항 저장',
+
+ // Playlist Modals
+ createPlaylist: '재생목록 만들기',
+ playlistName: '이름',
+ playlistNamePlaceholder: '내 멋진 재생목록',
+ playlistDescription: '설명',
+ descriptionPlaceholder: '코딩할 때 듣는 음악...',
+ addToPlaylist: '재생목록에 추가',
+ createNewPlaylist: '새 재생목록 만들기',
+ noExistingPlaylists: '재생목록이 아직 없습니다.',
+
+ // Edit Profile Modal (Settings)
+ usernameLabel: '사용자 이름',
+ usernamePlaceholder: '사용자 이름',
+ usernameMinLengthError: '사용자 이름은 최소 2자 이상이어야 합니다',
+ usernameTakenError: '이 사용자 이름은 이미 사용 중입니다',
+ usernameUpdateFailedError: '사용자 이름 업데이트에 실패했습니다',
+ usernameRequirements: '문자, 숫자, 밑줄, 하이픈만 허용됨',
+
+ // Song Details (RightSidebar)
+ more: '더보기',
+ copy: '복사',
+ copied: '복사됨!',
+ copyAllTags: '모든 태그 복사',
+
+ // Song Dropdown Menu
+ createVideo: '비디오 만들기',
+ editAudio: '오디오 편집',
+ extractStems: '스템 추출',
+ reusePrompt: '프롬프트 재사용',
+ deleteSong: '곡 삭제',
+ useAsReference: '참조로 사용',
+ coverSong: '커버 곡',
+ confirmDeleteTitle: '곡 삭제',
+ confirmDeleteManyTitle: '곡 삭제',
+ deleteSongsConfirm: '{count}곡을 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.',
+ songsDeletedSuccess: '곡이 삭제되었습니다',
+ songsDeletedPartial: '{succeeded}/{total}곡 삭제됨',
+ deleteUploadConfirm: '이 업로드를 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.',
+ cannotBeUndone: '이 작업은 되돌릴 수 없습니다.',
+
+ // Player
+ nowPlaying: '재생 중',
+ downloadAudio: '오디오 다운로드',
+ openInEditor: '편집기에서 열기',
+ anonymous: '익명 사용자',
+
+ // PlaylistDetail
+ loadingPlaylist: '재생목록 로딩 중...',
+ playlistNotFound: '재생목록을 찾을 수 없습니다',
+ deletePlaylistConfirm: '이 재생목록을 삭제하시겠습니까?',
+ dateAdded: '추가일',
+ justNow: '방금',
+ unknown: '알 수 없음',
+
+ // SongProfile
+ loadingSong: '곡 로딩 중...',
+ songNotFound: '곡을 찾을 수 없습니다',
+ similar: '유사',
+ by: '제작자',
+
+ // ShareModal
+ shareSong: '곡 공유',
+ shareOnX: 'X에서 공유',
+ shareOnFacebook: 'Facebook에서 공유',
+ shareOnWhatsApp: 'WhatsApp에서 공유',
+ shareOnTelegram: 'Telegram에서 공유',
+ shareOnReddit: 'Reddit에서 공유',
+ shareOnLinkedIn: 'LinkedIn에서 공유',
+ shareViaEmail: '이메일로 공유',
+ copyLink: '링크 복사',
+ emailSubject: '이 AI 곡을 들어보세요',
+ emailBody: '안녕하세요!\n\n제가 만든 이 AI 생성 곡을 들어보세요. 마음에 드실 거예요:\n\n"{title}" - {creator}\n{style}\n\n여기서 들으세요: {url}\n\nACE-Step UI로 제작 - 무료 오픈 소스 로컬 AI 음악 생성!',
+
+ // Reference Modal
+ referenceModalTitle: '참조 음악',
+ coverModalTitle: '커버 음악',
+ referenceModalDescription: '참조 트랙에서 영감을 받은 곡 만들기',
+ coverModalDescription: '기존 트랙을 새로운 버전으로 변환',
+ uploadAudio: '오디오 업로드',
+ uploadingAudio: '업로드 중...',
+ audioFormats: 'MP3, WAV, FLAC',
+ mine: '내 트랙',
+ loadingTracks: '로딩 중...',
+ noTracksYet: '트랙이 없습니다',
+ uploadAudioFilesAsReferences: '참조로 사용할 오디오 파일 업로드',
+
+ // Training Module
+ loraTraining: 'LoRA 훈련',
+ trainingDescription: '오디오 파일에서 데이터셋을 구축하고 커스텀 LoRA 어댑터를 훈련',
+ datasetBuilder: '데이터셋 빌더',
+ trainLora: 'LoRA 훈련',
+ quickStart: '빠른 시작',
+ chooseOneOption: '선택: 기존 데이터셋 로드 또는 새 디렉토리 스캔',
+ loadExistingDataset: '기존 데이터셋 로드',
+ loadDataset: '로드',
+ scanNewDirectory: '새 디렉토리 스캔',
+ scanDataset: '스캔',
+ datasetSettings: '데이터셋 설정',
+ datasetName: '데이터셋 이름',
+ customActivationTag: '커스텀 활성화 태그',
+ allInstrumental: '모두 인스트루멘탈',
+ tagPosition: '태그 위치',
+ tagPrepend: '앞에 추가 (태그, 캡션)',
+ tagAppend: '뒤에 추가 (캡션, 태그)',
+ tagReplace: '캡션 대체',
+ genreRatio: '장르 비율',
+ genreRatioHint: '0% = 모두 캡션, 100% = 모두 장르',
+ autoLabelWithAI: 'AI로 자동 라벨링',
+ autoLabelDescription: '오디오 파일의 메타데이터 생성: 캡션, BPM, 키, 박자',
+ skipMetas: 'BPM/키/박자 건너뛰기',
+ onlyUnlabeled: '라벨 없는 것만',
+ autoLabelAll: '모두 자동 라벨링',
+ filename: '파일명',
+ labeled: '라벨됨',
+ saveDataset: '데이터셋 저장',
+ preprocessToTensors: '텐서로 전처리',
+ preprocessDescription: '빠른 훈련을 위해 데이터셋을 사전 계산된 텐서로 변환 (모델 로드 필요)',
+ preprocess: '전처리',
+ preprocessedDataset: '전처리된 데이터셋',
+ loraSettings: 'LoRA 설정',
+ loraRank: 'LoRA 랭크',
+ loraAlpha: 'LoRA Alpha',
+ dropout: '드롭아웃',
+ trainingParameters: '훈련 파라미터',
+ learningRate: '학습률',
+ maxEpochs: '최대 에포크',
+ gradientAccumulation: '그래디언트 누적',
+ saveEvery: '저장 간격',
+ epochs: '에포크',
+ outputDirectory: '출력 디렉토리',
+ useFP8: 'FP8 양자화 사용',
+ fp8Description: 'VRAM 사용량 감소',
+ startTraining: '훈련 시작',
+ stopTraining: '훈련 중지',
+ trainingProgress: '훈련 진행',
+ trainingLog: '훈련 로그',
+
+ // Training Status Messages
+ scanning: '스캔 중...',
+ autoLabeling: '자동 라벨링 중...',
+ savingDataset: '저장 중...',
+ preprocessing: '전처리 중...',
+ loadingDataset: '로드 중...',
+ startingTraining: '시작 중...',
+ error: '오류',
+ datasetInfo: '데이터셋: {name}, 샘플: {samples}, 라벨됨: {labeled}',
+ trainingStep: '스텝 {step} - 손실: {loss}',
+ editSample: '샘플 편집',
+ caption: '캡션',
+ genre: '장르',
+ promptOverride: '프롬프트 재정의',
+ musicDescription: '음악 설명...',
+ overrideGlobalRatio: '이 샘플의 글로벌 비율 재정의',
+ editableUsedForTraining: '편집 가능, 훈련에 사용',
+ useGlobalRatio: '글로벌 비율 사용',
+ thisSample: '이 샘플',
+ }
+};
+
+export type TranslationKey = keyof typeof translations.en;