Set English as default locale for first install (v3.8.7)
Make English the initial language for fresh installations while keeping live DE/EN switching, and split locale dictionaries into dedicated per-language files for cleaner long-term translation maintenance.
This commit is contained in:
parent
7fb7e4b03b
commit
5749214a62
4
typescript-version/package-lock.json
generated
4
typescript-version/package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "twitch-vod-manager",
|
"name": "twitch-vod-manager",
|
||||||
"version": "3.8.6",
|
"version": "3.8.7",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "twitch-vod-manager",
|
"name": "twitch-vod-manager",
|
||||||
"version": "3.8.6",
|
"version": "3.8.7",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.6.0",
|
"axios": "^1.6.0",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "twitch-vod-manager",
|
"name": "twitch-vod-manager",
|
||||||
"version": "3.8.6",
|
"version": "3.8.7",
|
||||||
"description": "Twitch VOD Manager - Download Twitch VODs easily",
|
"description": "Twitch VOD Manager - Download Twitch VODs easily",
|
||||||
"main": "dist/main.js",
|
"main": "dist/main.js",
|
||||||
"author": "xRangerDE",
|
"author": "xRangerDE",
|
||||||
|
|||||||
@ -343,7 +343,7 @@
|
|||||||
|
|
||||||
<div class="settings-card">
|
<div class="settings-card">
|
||||||
<h3 id="updateTitle">Updates</h3>
|
<h3 id="updateTitle">Updates</h3>
|
||||||
<p id="versionInfo" style="margin-bottom: 10px; color: var(--text-secondary);">Version: v3.8.6</p>
|
<p id="versionInfo" style="margin-bottom: 10px; color: var(--text-secondary);">Version: v3.8.7</p>
|
||||||
<button class="btn-secondary" id="checkUpdateBtn" onclick="checkUpdate()">Nach Updates suchen</button>
|
<button class="btn-secondary" id="checkUpdateBtn" onclick="checkUpdate()">Nach Updates suchen</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -354,7 +354,7 @@
|
|||||||
<div class="status-dot" id="statusDot"></div>
|
<div class="status-dot" id="statusDot"></div>
|
||||||
<span id="statusText">Nicht verbunden</span>
|
<span id="statusText">Nicht verbunden</span>
|
||||||
</div>
|
</div>
|
||||||
<span id="versionText">v3.8.6</span>
|
<span id="versionText">v3.8.7</span>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import { autoUpdater } from 'electron-updater';
|
|||||||
// ==========================================
|
// ==========================================
|
||||||
// CONFIG & CONSTANTS
|
// CONFIG & CONSTANTS
|
||||||
// ==========================================
|
// ==========================================
|
||||||
const APP_VERSION = '3.8.6';
|
const APP_VERSION = '3.8.7';
|
||||||
const UPDATE_CHECK_URL = 'http://24-music.de/version.json';
|
const UPDATE_CHECK_URL = 'http://24-music.de/version.json';
|
||||||
|
|
||||||
// Paths
|
// Paths
|
||||||
@ -118,7 +118,7 @@ const defaultConfig: Config = {
|
|||||||
theme: 'twitch',
|
theme: 'twitch',
|
||||||
download_mode: 'full',
|
download_mode: 'full',
|
||||||
part_minutes: 120,
|
part_minutes: 120,
|
||||||
language: 'de'
|
language: 'en'
|
||||||
};
|
};
|
||||||
|
|
||||||
function loadConfig(): Config {
|
function loadConfig(): Config {
|
||||||
|
|||||||
125
typescript-version/src/renderer-locale-de.ts
Normal file
125
typescript-version/src/renderer-locale-de.ts
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
const UI_TEXT_DE = {
|
||||||
|
appName: 'Twitch VOD Manager',
|
||||||
|
static: {
|
||||||
|
navVods: 'Twitch VODs',
|
||||||
|
navClips: 'Twitch Clips',
|
||||||
|
navCutter: 'Video schneiden',
|
||||||
|
navMerge: 'Videos zusammenfugen',
|
||||||
|
navSettings: 'Einstellungen',
|
||||||
|
queueTitle: 'Warteschlange',
|
||||||
|
clearQueue: 'Leeren',
|
||||||
|
refresh: 'Aktualisieren',
|
||||||
|
streamerPlaceholder: 'Streamer hinzufugen...',
|
||||||
|
clipsHeading: 'Twitch Clip-Download',
|
||||||
|
clipsInfoTitle: 'Info',
|
||||||
|
clipsInfoText: 'Unterstutzte Formate:\n- https://clips.twitch.tv/ClipName\n- https://www.twitch.tv/streamer/clip/ClipName\n\nClips werden im Download-Ordner unter "Clips/StreamerName/" gespeichert.',
|
||||||
|
cutterSelectTitle: 'Video auswahlen',
|
||||||
|
cutterBrowse: 'Durchsuchen',
|
||||||
|
mergeTitle: 'Videos zusammenfugen',
|
||||||
|
mergeDesc: 'Wahle mehrere Videos aus, um sie zu einem Video zusammenzufugen. Die Reihenfolge kann geandert werden.',
|
||||||
|
mergeAdd: '+ Videos hinzufugen',
|
||||||
|
designTitle: 'Design',
|
||||||
|
themeLabel: 'Theme',
|
||||||
|
languageLabel: 'Sprache',
|
||||||
|
languageDe: 'DE - Deutsch',
|
||||||
|
languageEn: 'EN - Englisch',
|
||||||
|
apiTitle: 'Twitch API',
|
||||||
|
clientIdLabel: 'Client ID',
|
||||||
|
clientSecretLabel: 'Client Secret',
|
||||||
|
saveSettings: 'Speichern & Verbinden',
|
||||||
|
downloadSettingsTitle: 'Download-Einstellungen',
|
||||||
|
storageLabel: 'Speicherort',
|
||||||
|
openFolder: 'Offnen',
|
||||||
|
modeLabel: 'Download-Modus',
|
||||||
|
modeFull: 'Ganzes VOD',
|
||||||
|
modeParts: 'In Teile splitten',
|
||||||
|
partMinutesLabel: 'Teil-Lange (Minuten)',
|
||||||
|
updateTitle: 'Updates',
|
||||||
|
checkUpdates: 'Nach Updates suchen',
|
||||||
|
notConnected: 'Nicht verbunden'
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
noLogin: 'Ohne Login (Public Modus)',
|
||||||
|
connecting: 'Verbinde...',
|
||||||
|
connected: 'Verbunden',
|
||||||
|
connectFailedPublic: 'Verbindung fehlgeschlagen - Public Modus aktiv'
|
||||||
|
},
|
||||||
|
tabs: {
|
||||||
|
vods: 'VODs',
|
||||||
|
clips: 'Clips',
|
||||||
|
cutter: 'Video schneiden',
|
||||||
|
merge: 'Videos zusammenfugen',
|
||||||
|
settings: 'Einstellungen'
|
||||||
|
},
|
||||||
|
queue: {
|
||||||
|
empty: 'Keine Downloads in der Warteschlange',
|
||||||
|
start: 'Start',
|
||||||
|
stop: 'Stoppen',
|
||||||
|
statusDone: 'Abgeschlossen',
|
||||||
|
statusFailed: 'Fehlgeschlagen',
|
||||||
|
statusRunning: 'Laeuft',
|
||||||
|
statusWaiting: 'Wartet',
|
||||||
|
progressError: 'Fehler',
|
||||||
|
progressReady: 'Bereit',
|
||||||
|
progressLoading: 'Lade...',
|
||||||
|
readyToDownload: 'Bereit zum Download',
|
||||||
|
started: 'Download gestartet',
|
||||||
|
done: 'Fertig',
|
||||||
|
failed: 'Download fehlgeschlagen',
|
||||||
|
speed: 'Geschwindigkeit',
|
||||||
|
eta: 'Restzeit',
|
||||||
|
part: 'Teil',
|
||||||
|
emptyAlert: 'Die Warteschlange ist leer. Fuge zuerst ein VOD oder einen Clip hinzu.'
|
||||||
|
},
|
||||||
|
vods: {
|
||||||
|
noneTitle: 'Keine VODs',
|
||||||
|
noneText: 'Wahle einen Streamer aus der Liste.',
|
||||||
|
loading: 'Lade VODs...',
|
||||||
|
notFound: 'Streamer nicht gefunden',
|
||||||
|
noResultsTitle: 'Keine VODs gefunden',
|
||||||
|
noResultsText: 'Dieser Streamer hat keine VODs.',
|
||||||
|
untitled: 'Unbenanntes VOD',
|
||||||
|
views: 'Aufrufe',
|
||||||
|
addQueue: '+ Warteschlange'
|
||||||
|
},
|
||||||
|
clips: {
|
||||||
|
dialogTitle: 'Clip zuschneiden',
|
||||||
|
invalidDuration: 'Ungultig!',
|
||||||
|
endBeforeStart: 'Endzeit muss grosser als Startzeit sein!',
|
||||||
|
outOfRange: 'Zeit ausserhalb des VOD-Bereichs!',
|
||||||
|
enterUrl: 'Bitte URL eingeben',
|
||||||
|
loadingButton: 'Lade...',
|
||||||
|
loadingStatus: 'Download laeuft...',
|
||||||
|
downloadButton: 'Clip herunterladen',
|
||||||
|
success: 'Download erfolgreich!',
|
||||||
|
errorPrefix: 'Fehler: ',
|
||||||
|
unknownError: 'Unbekannter Fehler',
|
||||||
|
formatSimple: '(Standard)',
|
||||||
|
formatTimestamp: '(mit Zeitstempel)'
|
||||||
|
},
|
||||||
|
cutter: {
|
||||||
|
videoInfoFailed: 'Konnte Video-Informationen nicht lesen. FFprobe installiert?',
|
||||||
|
previewLoading: 'Lade Vorschau...',
|
||||||
|
previewUnavailable: 'Vorschau nicht verfugbar',
|
||||||
|
cutting: 'Schneidet...',
|
||||||
|
cut: 'Schneiden',
|
||||||
|
cutSuccess: 'Video erfolgreich geschnitten!',
|
||||||
|
cutFailed: 'Fehler beim Schneiden des Videos.'
|
||||||
|
},
|
||||||
|
merge: {
|
||||||
|
empty: 'Keine Videos ausgewahlt',
|
||||||
|
merging: 'Zusammenfugen...',
|
||||||
|
merge: 'Zusammenfugen',
|
||||||
|
success: 'Videos erfolgreich zusammengefugt!',
|
||||||
|
failed: 'Fehler beim Zusammenfugen der Videos.'
|
||||||
|
},
|
||||||
|
updates: {
|
||||||
|
latest: 'Du hast die neueste Version!',
|
||||||
|
downloading: 'Wird heruntergeladen...',
|
||||||
|
available: 'verfugbar!',
|
||||||
|
downloadNow: 'Jetzt herunterladen',
|
||||||
|
downloadLabel: 'Download',
|
||||||
|
ready: 'bereit zur Installation!',
|
||||||
|
installNow: 'Jetzt installieren'
|
||||||
|
}
|
||||||
|
} as const;
|
||||||
125
typescript-version/src/renderer-locale-en.ts
Normal file
125
typescript-version/src/renderer-locale-en.ts
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
const UI_TEXT_EN = {
|
||||||
|
appName: 'Twitch VOD Manager',
|
||||||
|
static: {
|
||||||
|
navVods: 'Twitch VODs',
|
||||||
|
navClips: 'Twitch Clips',
|
||||||
|
navCutter: 'Video Cutter',
|
||||||
|
navMerge: 'Merge Videos',
|
||||||
|
navSettings: 'Settings',
|
||||||
|
queueTitle: 'Queue',
|
||||||
|
clearQueue: 'Clear',
|
||||||
|
refresh: 'Refresh',
|
||||||
|
streamerPlaceholder: 'Add streamer...',
|
||||||
|
clipsHeading: 'Twitch Clip Download',
|
||||||
|
clipsInfoTitle: 'Info',
|
||||||
|
clipsInfoText: 'Supported formats:\n- https://clips.twitch.tv/ClipName\n- https://www.twitch.tv/streamer/clip/ClipName\n\nClips are saved in your download folder under "Clips/StreamerName/".',
|
||||||
|
cutterSelectTitle: 'Select video',
|
||||||
|
cutterBrowse: 'Browse',
|
||||||
|
mergeTitle: 'Merge videos',
|
||||||
|
mergeDesc: 'Select multiple videos to merge into one file. You can change the order before merging.',
|
||||||
|
mergeAdd: '+ Add videos',
|
||||||
|
designTitle: 'Design',
|
||||||
|
themeLabel: 'Theme',
|
||||||
|
languageLabel: 'Language',
|
||||||
|
languageDe: 'DE - German',
|
||||||
|
languageEn: 'EN - English',
|
||||||
|
apiTitle: 'Twitch API',
|
||||||
|
clientIdLabel: 'Client ID',
|
||||||
|
clientSecretLabel: 'Client Secret',
|
||||||
|
saveSettings: 'Save & Connect',
|
||||||
|
downloadSettingsTitle: 'Download Settings',
|
||||||
|
storageLabel: 'Storage Path',
|
||||||
|
openFolder: 'Open',
|
||||||
|
modeLabel: 'Download Mode',
|
||||||
|
modeFull: 'Full VOD',
|
||||||
|
modeParts: 'Split into parts',
|
||||||
|
partMinutesLabel: 'Part Length (Minutes)',
|
||||||
|
updateTitle: 'Updates',
|
||||||
|
checkUpdates: 'Check for updates',
|
||||||
|
notConnected: 'Not connected'
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
noLogin: 'No login (public mode)',
|
||||||
|
connecting: 'Connecting...',
|
||||||
|
connected: 'Connected',
|
||||||
|
connectFailedPublic: 'Connection failed - public mode active'
|
||||||
|
},
|
||||||
|
tabs: {
|
||||||
|
vods: 'VODs',
|
||||||
|
clips: 'Clips',
|
||||||
|
cutter: 'Video Cutter',
|
||||||
|
merge: 'Merge Videos',
|
||||||
|
settings: 'Settings'
|
||||||
|
},
|
||||||
|
queue: {
|
||||||
|
empty: 'No downloads in queue',
|
||||||
|
start: 'Start',
|
||||||
|
stop: 'Stop',
|
||||||
|
statusDone: 'Completed',
|
||||||
|
statusFailed: 'Failed',
|
||||||
|
statusRunning: 'Running',
|
||||||
|
statusWaiting: 'Waiting',
|
||||||
|
progressError: 'Error',
|
||||||
|
progressReady: 'Ready',
|
||||||
|
progressLoading: 'Loading...',
|
||||||
|
readyToDownload: 'Ready to download',
|
||||||
|
started: 'Download started',
|
||||||
|
done: 'Done',
|
||||||
|
failed: 'Download failed',
|
||||||
|
speed: 'Speed',
|
||||||
|
eta: 'ETA',
|
||||||
|
part: 'Part',
|
||||||
|
emptyAlert: 'Queue is empty. Add a VOD or clip first.'
|
||||||
|
},
|
||||||
|
vods: {
|
||||||
|
noneTitle: 'No VODs',
|
||||||
|
noneText: 'Select a streamer from the list.',
|
||||||
|
loading: 'Loading VODs...',
|
||||||
|
notFound: 'Streamer not found',
|
||||||
|
noResultsTitle: 'No VODs found',
|
||||||
|
noResultsText: 'This streamer has no VODs.',
|
||||||
|
untitled: 'Untitled VOD',
|
||||||
|
views: 'views',
|
||||||
|
addQueue: '+ Queue'
|
||||||
|
},
|
||||||
|
clips: {
|
||||||
|
dialogTitle: 'Trim clip',
|
||||||
|
invalidDuration: 'Invalid!',
|
||||||
|
endBeforeStart: 'End time must be greater than start time!',
|
||||||
|
outOfRange: 'Time is outside VOD range!',
|
||||||
|
enterUrl: 'Please enter a URL',
|
||||||
|
loadingButton: 'Loading...',
|
||||||
|
loadingStatus: 'Downloading...',
|
||||||
|
downloadButton: 'Download clip',
|
||||||
|
success: 'Download successful!',
|
||||||
|
errorPrefix: 'Error: ',
|
||||||
|
unknownError: 'Unknown error',
|
||||||
|
formatSimple: '(default)',
|
||||||
|
formatTimestamp: '(with timestamp)'
|
||||||
|
},
|
||||||
|
cutter: {
|
||||||
|
videoInfoFailed: 'Could not read video info. Is FFprobe installed?',
|
||||||
|
previewLoading: 'Loading preview...',
|
||||||
|
previewUnavailable: 'Preview unavailable',
|
||||||
|
cutting: 'Cutting...',
|
||||||
|
cut: 'Cut',
|
||||||
|
cutSuccess: 'Video cut successfully!',
|
||||||
|
cutFailed: 'Failed to cut video.'
|
||||||
|
},
|
||||||
|
merge: {
|
||||||
|
empty: 'No videos selected',
|
||||||
|
merging: 'Merging...',
|
||||||
|
merge: 'Merge',
|
||||||
|
success: 'Videos merged successfully!',
|
||||||
|
failed: 'Failed to merge videos.'
|
||||||
|
},
|
||||||
|
updates: {
|
||||||
|
latest: 'You are on the latest version!',
|
||||||
|
downloading: 'Downloading...',
|
||||||
|
available: 'available!',
|
||||||
|
downloadNow: 'Download now',
|
||||||
|
downloadLabel: 'Download',
|
||||||
|
ready: 'ready to install!',
|
||||||
|
installNow: 'Install now'
|
||||||
|
}
|
||||||
|
} as const;
|
||||||
@ -1,261 +1,26 @@
|
|||||||
type LanguageCode = 'de' | 'en';
|
type LanguageCode = 'de' | 'en';
|
||||||
|
|
||||||
const UI_TEXTS = {
|
const UI_TEXTS = {
|
||||||
de: {
|
de: UI_TEXT_DE,
|
||||||
appName: 'Twitch VOD Manager',
|
en: UI_TEXT_EN
|
||||||
static: {
|
|
||||||
navVods: 'Twitch VODs',
|
|
||||||
navClips: 'Twitch Clips',
|
|
||||||
navCutter: 'Video schneiden',
|
|
||||||
navMerge: 'Videos zusammenfugen',
|
|
||||||
navSettings: 'Einstellungen',
|
|
||||||
queueTitle: 'Warteschlange',
|
|
||||||
clearQueue: 'Leeren',
|
|
||||||
refresh: 'Aktualisieren',
|
|
||||||
streamerPlaceholder: 'Streamer hinzufugen...',
|
|
||||||
clipsHeading: 'Twitch Clip-Download',
|
|
||||||
clipsInfoTitle: 'Info',
|
|
||||||
clipsInfoText: 'Unterstutzte Formate:\n- https://clips.twitch.tv/ClipName\n- https://www.twitch.tv/streamer/clip/ClipName\n\nClips werden im Download-Ordner unter "Clips/StreamerName/" gespeichert.',
|
|
||||||
cutterSelectTitle: 'Video auswahlen',
|
|
||||||
cutterBrowse: 'Durchsuchen',
|
|
||||||
mergeTitle: 'Videos zusammenfugen',
|
|
||||||
mergeDesc: 'Wahle mehrere Videos aus, um sie zu einem Video zusammenzufugen. Die Reihenfolge kann geandert werden.',
|
|
||||||
mergeAdd: '+ Videos hinzufugen',
|
|
||||||
designTitle: 'Design',
|
|
||||||
themeLabel: 'Theme',
|
|
||||||
languageLabel: 'Sprache',
|
|
||||||
languageDe: 'Deutsch',
|
|
||||||
languageEn: 'Englisch',
|
|
||||||
apiTitle: 'Twitch API',
|
|
||||||
clientIdLabel: 'Client ID',
|
|
||||||
clientSecretLabel: 'Client Secret',
|
|
||||||
saveSettings: 'Speichern & Verbinden',
|
|
||||||
downloadSettingsTitle: 'Download-Einstellungen',
|
|
||||||
storageLabel: 'Speicherort',
|
|
||||||
openFolder: 'Offnen',
|
|
||||||
modeLabel: 'Download-Modus',
|
|
||||||
modeFull: 'Ganzes VOD',
|
|
||||||
modeParts: 'In Teile splitten',
|
|
||||||
partMinutesLabel: 'Teil-Lange (Minuten)',
|
|
||||||
updateTitle: 'Updates',
|
|
||||||
checkUpdates: 'Nach Updates suchen',
|
|
||||||
notConnected: 'Nicht verbunden'
|
|
||||||
},
|
|
||||||
status: {
|
|
||||||
noLogin: 'Ohne Login (Public Modus)',
|
|
||||||
connecting: 'Verbinde...',
|
|
||||||
connected: 'Verbunden',
|
|
||||||
connectFailedPublic: 'Verbindung fehlgeschlagen - Public Modus aktiv'
|
|
||||||
},
|
|
||||||
tabs: {
|
|
||||||
vods: 'VODs',
|
|
||||||
clips: 'Clips',
|
|
||||||
cutter: 'Video schneiden',
|
|
||||||
merge: 'Videos zusammenfugen',
|
|
||||||
settings: 'Einstellungen'
|
|
||||||
},
|
|
||||||
queue: {
|
|
||||||
empty: 'Keine Downloads in der Warteschlange',
|
|
||||||
start: 'Start',
|
|
||||||
stop: 'Stoppen',
|
|
||||||
statusDone: 'Abgeschlossen',
|
|
||||||
statusFailed: 'Fehlgeschlagen',
|
|
||||||
statusRunning: 'Laeuft',
|
|
||||||
statusWaiting: 'Wartet',
|
|
||||||
progressError: 'Fehler',
|
|
||||||
progressReady: 'Bereit',
|
|
||||||
progressLoading: 'Lade...',
|
|
||||||
readyToDownload: 'Bereit zum Download',
|
|
||||||
started: 'Download gestartet',
|
|
||||||
done: 'Fertig',
|
|
||||||
failed: 'Download fehlgeschlagen',
|
|
||||||
speed: 'Geschwindigkeit',
|
|
||||||
eta: 'Restzeit',
|
|
||||||
part: 'Teil',
|
|
||||||
emptyAlert: 'Die Warteschlange ist leer. Fuge zuerst ein VOD oder einen Clip hinzu.'
|
|
||||||
},
|
|
||||||
vods: {
|
|
||||||
noneTitle: 'Keine VODs',
|
|
||||||
noneText: 'Wahle einen Streamer aus der Liste.',
|
|
||||||
loading: 'Lade VODs...',
|
|
||||||
notFound: 'Streamer nicht gefunden',
|
|
||||||
noResultsTitle: 'Keine VODs gefunden',
|
|
||||||
noResultsText: 'Dieser Streamer hat keine VODs.',
|
|
||||||
untitled: 'Unbenanntes VOD',
|
|
||||||
views: 'Aufrufe',
|
|
||||||
addQueue: '+ Warteschlange'
|
|
||||||
},
|
|
||||||
clips: {
|
|
||||||
dialogTitle: 'Clip zuschneiden',
|
|
||||||
invalidDuration: 'Ungultig!',
|
|
||||||
endBeforeStart: 'Endzeit muss grosser als Startzeit sein!',
|
|
||||||
outOfRange: 'Zeit ausserhalb des VOD-Bereichs!',
|
|
||||||
enterUrl: 'Bitte URL eingeben',
|
|
||||||
loadingButton: 'Lade...',
|
|
||||||
loadingStatus: 'Download laeuft...',
|
|
||||||
downloadButton: 'Clip herunterladen',
|
|
||||||
success: 'Download erfolgreich!',
|
|
||||||
errorPrefix: 'Fehler: ',
|
|
||||||
unknownError: 'Unbekannter Fehler',
|
|
||||||
formatSimple: '(Standard)',
|
|
||||||
formatTimestamp: '(mit Zeitstempel)'
|
|
||||||
},
|
|
||||||
cutter: {
|
|
||||||
videoInfoFailed: 'Konnte Video-Informationen nicht lesen. FFprobe installiert?',
|
|
||||||
previewLoading: 'Lade Vorschau...',
|
|
||||||
previewUnavailable: 'Vorschau nicht verfugbar',
|
|
||||||
cutting: 'Schneidet...',
|
|
||||||
cut: 'Schneiden',
|
|
||||||
cutSuccess: 'Video erfolgreich geschnitten!',
|
|
||||||
cutFailed: 'Fehler beim Schneiden des Videos.'
|
|
||||||
},
|
|
||||||
merge: {
|
|
||||||
empty: 'Keine Videos ausgewahlt',
|
|
||||||
merging: 'Zusammenfugen...',
|
|
||||||
merge: 'Zusammenfugen',
|
|
||||||
success: 'Videos erfolgreich zusammengefugt!',
|
|
||||||
failed: 'Fehler beim Zusammenfugen der Videos.'
|
|
||||||
},
|
|
||||||
updates: {
|
|
||||||
latest: 'Du hast die neueste Version!',
|
|
||||||
downloading: 'Wird heruntergeladen...',
|
|
||||||
available: 'verfugbar!',
|
|
||||||
downloadNow: 'Jetzt herunterladen',
|
|
||||||
downloadLabel: 'Download',
|
|
||||||
ready: 'bereit zur Installation!',
|
|
||||||
installNow: 'Jetzt installieren'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
en: {
|
|
||||||
appName: 'Twitch VOD Manager',
|
|
||||||
static: {
|
|
||||||
navVods: 'Twitch VODs',
|
|
||||||
navClips: 'Twitch Clips',
|
|
||||||
navCutter: 'Video Cutter',
|
|
||||||
navMerge: 'Merge Videos',
|
|
||||||
navSettings: 'Settings',
|
|
||||||
queueTitle: 'Queue',
|
|
||||||
clearQueue: 'Clear',
|
|
||||||
refresh: 'Refresh',
|
|
||||||
streamerPlaceholder: 'Add streamer...',
|
|
||||||
clipsHeading: 'Twitch Clip Download',
|
|
||||||
clipsInfoTitle: 'Info',
|
|
||||||
clipsInfoText: 'Supported formats:\n- https://clips.twitch.tv/ClipName\n- https://www.twitch.tv/streamer/clip/ClipName\n\nClips are saved in your download folder under "Clips/StreamerName/".',
|
|
||||||
cutterSelectTitle: 'Select video',
|
|
||||||
cutterBrowse: 'Browse',
|
|
||||||
mergeTitle: 'Merge videos',
|
|
||||||
mergeDesc: 'Select multiple videos to merge into one file. You can change the order before merging.',
|
|
||||||
mergeAdd: '+ Add videos',
|
|
||||||
designTitle: 'Design',
|
|
||||||
themeLabel: 'Theme',
|
|
||||||
languageLabel: 'Language',
|
|
||||||
languageDe: 'German',
|
|
||||||
languageEn: 'English',
|
|
||||||
apiTitle: 'Twitch API',
|
|
||||||
clientIdLabel: 'Client ID',
|
|
||||||
clientSecretLabel: 'Client Secret',
|
|
||||||
saveSettings: 'Save & Connect',
|
|
||||||
downloadSettingsTitle: 'Download Settings',
|
|
||||||
storageLabel: 'Storage Path',
|
|
||||||
openFolder: 'Open',
|
|
||||||
modeLabel: 'Download Mode',
|
|
||||||
modeFull: 'Full VOD',
|
|
||||||
modeParts: 'Split into parts',
|
|
||||||
partMinutesLabel: 'Part Length (Minutes)',
|
|
||||||
updateTitle: 'Updates',
|
|
||||||
checkUpdates: 'Check for updates',
|
|
||||||
notConnected: 'Not connected'
|
|
||||||
},
|
|
||||||
status: {
|
|
||||||
noLogin: 'No login (public mode)',
|
|
||||||
connecting: 'Connecting...',
|
|
||||||
connected: 'Connected',
|
|
||||||
connectFailedPublic: 'Connection failed - public mode active'
|
|
||||||
},
|
|
||||||
tabs: {
|
|
||||||
vods: 'VODs',
|
|
||||||
clips: 'Clips',
|
|
||||||
cutter: 'Video Cutter',
|
|
||||||
merge: 'Merge Videos',
|
|
||||||
settings: 'Settings'
|
|
||||||
},
|
|
||||||
queue: {
|
|
||||||
empty: 'No downloads in queue',
|
|
||||||
start: 'Start',
|
|
||||||
stop: 'Stop',
|
|
||||||
statusDone: 'Completed',
|
|
||||||
statusFailed: 'Failed',
|
|
||||||
statusRunning: 'Running',
|
|
||||||
statusWaiting: 'Waiting',
|
|
||||||
progressError: 'Error',
|
|
||||||
progressReady: 'Ready',
|
|
||||||
progressLoading: 'Loading...',
|
|
||||||
readyToDownload: 'Ready to download',
|
|
||||||
started: 'Download started',
|
|
||||||
done: 'Done',
|
|
||||||
failed: 'Download failed',
|
|
||||||
speed: 'Speed',
|
|
||||||
eta: 'ETA',
|
|
||||||
part: 'Part',
|
|
||||||
emptyAlert: 'Queue is empty. Add a VOD or clip first.'
|
|
||||||
},
|
|
||||||
vods: {
|
|
||||||
noneTitle: 'No VODs',
|
|
||||||
noneText: 'Select a streamer from the list.',
|
|
||||||
loading: 'Loading VODs...',
|
|
||||||
notFound: 'Streamer not found',
|
|
||||||
noResultsTitle: 'No VODs found',
|
|
||||||
noResultsText: 'This streamer has no VODs.',
|
|
||||||
untitled: 'Untitled VOD',
|
|
||||||
views: 'views',
|
|
||||||
addQueue: '+ Queue'
|
|
||||||
},
|
|
||||||
clips: {
|
|
||||||
dialogTitle: 'Trim clip',
|
|
||||||
invalidDuration: 'Invalid!',
|
|
||||||
endBeforeStart: 'End time must be greater than start time!',
|
|
||||||
outOfRange: 'Time is outside VOD range!',
|
|
||||||
enterUrl: 'Please enter a URL',
|
|
||||||
loadingButton: 'Loading...',
|
|
||||||
loadingStatus: 'Downloading...',
|
|
||||||
downloadButton: 'Download clip',
|
|
||||||
success: 'Download successful!',
|
|
||||||
errorPrefix: 'Error: ',
|
|
||||||
unknownError: 'Unknown error',
|
|
||||||
formatSimple: '(default)',
|
|
||||||
formatTimestamp: '(with timestamp)'
|
|
||||||
},
|
|
||||||
cutter: {
|
|
||||||
videoInfoFailed: 'Could not read video info. Is FFprobe installed?',
|
|
||||||
previewLoading: 'Loading preview...',
|
|
||||||
previewUnavailable: 'Preview unavailable',
|
|
||||||
cutting: 'Cutting...',
|
|
||||||
cut: 'Cut',
|
|
||||||
cutSuccess: 'Video cut successfully!',
|
|
||||||
cutFailed: 'Failed to cut video.'
|
|
||||||
},
|
|
||||||
merge: {
|
|
||||||
empty: 'No videos selected',
|
|
||||||
merging: 'Merging...',
|
|
||||||
merge: 'Merge',
|
|
||||||
success: 'Videos merged successfully!',
|
|
||||||
failed: 'Failed to merge videos.'
|
|
||||||
},
|
|
||||||
updates: {
|
|
||||||
latest: 'You are on the latest version!',
|
|
||||||
downloading: 'Downloading...',
|
|
||||||
available: 'available!',
|
|
||||||
downloadNow: 'Download now',
|
|
||||||
downloadLabel: 'Download',
|
|
||||||
ready: 'ready to install!',
|
|
||||||
installNow: 'Install now'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
let currentLanguage: LanguageCode = 'de';
|
let currentLanguage: LanguageCode = 'en';
|
||||||
let UI_TEXT: (typeof UI_TEXTS)[LanguageCode] = UI_TEXTS[currentLanguage];
|
let UI_TEXT: (typeof UI_TEXTS)[LanguageCode] = UI_TEXTS[currentLanguage];
|
||||||
|
|
||||||
|
function getIntlLocale(): string {
|
||||||
|
return currentLanguage === 'en' ? 'en-US' : 'de-DE';
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatUiDate(input: string | Date): string {
|
||||||
|
const date = input instanceof Date ? input : new Date(input);
|
||||||
|
return date.toLocaleDateString(getIntlLocale());
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatUiNumber(value: number): string {
|
||||||
|
return value.toLocaleString(getIntlLocale());
|
||||||
|
}
|
||||||
|
|
||||||
function setText(id: string, value: string): void {
|
function setText(id: string, value: string): void {
|
||||||
const node = document.getElementById(id);
|
const node = document.getElementById(id);
|
||||||
if (node) node.textContent = value;
|
if (node) node.textContent = value;
|
||||||
@ -309,7 +74,6 @@ function applyLanguageToStaticUI(): void {
|
|||||||
setText('partMinutesLabel', UI_TEXT.static.partMinutesLabel);
|
setText('partMinutesLabel', UI_TEXT.static.partMinutesLabel);
|
||||||
setText('updateTitle', UI_TEXT.static.updateTitle);
|
setText('updateTitle', UI_TEXT.static.updateTitle);
|
||||||
setText('checkUpdateBtn', UI_TEXT.static.checkUpdates);
|
setText('checkUpdateBtn', UI_TEXT.static.checkUpdates);
|
||||||
|
|
||||||
setPlaceholder('newStreamer', UI_TEXT.static.streamerPlaceholder);
|
setPlaceholder('newStreamer', UI_TEXT.static.streamerPlaceholder);
|
||||||
|
|
||||||
const status = document.getElementById('statusText')?.textContent?.trim() || '';
|
const status = document.getElementById('statusText')?.textContent?.trim() || '';
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
async function init(): Promise<void> {
|
async function init(): Promise<void> {
|
||||||
config = await window.api.getConfig();
|
config = await window.api.getConfig();
|
||||||
const language = setLanguage((config.language as string) || 'de');
|
const language = setLanguage((config.language as string) || 'en');
|
||||||
config.language = language;
|
config.language = language;
|
||||||
const initialQueue = await window.api.getQueue();
|
const initialQueue = await window.api.getQueue();
|
||||||
queue = Array.isArray(initialQueue) ? initialQueue : [];
|
queue = Array.isArray(initialQueue) ? initialQueue : [];
|
||||||
@ -14,7 +14,7 @@ async function init(): Promise<void> {
|
|||||||
byId<HTMLInputElement>('clientSecret').value = config.client_secret ?? '';
|
byId<HTMLInputElement>('clientSecret').value = config.client_secret ?? '';
|
||||||
byId<HTMLInputElement>('downloadPath').value = config.download_path ?? '';
|
byId<HTMLInputElement>('downloadPath').value = config.download_path ?? '';
|
||||||
byId<HTMLSelectElement>('themeSelect').value = config.theme ?? 'twitch';
|
byId<HTMLSelectElement>('themeSelect').value = config.theme ?? 'twitch';
|
||||||
byId<HTMLSelectElement>('languageSelect').value = config.language ?? 'de';
|
byId<HTMLSelectElement>('languageSelect').value = config.language ?? 'en';
|
||||||
byId<HTMLSelectElement>('downloadMode').value = config.download_mode ?? 'full';
|
byId<HTMLSelectElement>('downloadMode').value = config.download_mode ?? 'full';
|
||||||
byId<HTMLInputElement>('partMinutes').value = String(config.part_minutes ?? 120);
|
byId<HTMLInputElement>('partMinutes').value = String(config.part_minutes ?? 120);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user