From 5749214a621a75b30d14aff18d6d65cbd965c7d1 Mon Sep 17 00:00:00 2001 From: xRangerDE Date: Sat, 14 Feb 2026 05:36:59 +0100 Subject: [PATCH] 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. --- typescript-version/package-lock.json | 4 +- typescript-version/package.json | 2 +- typescript-version/src/index.html | 4 +- typescript-version/src/main.ts | 4 +- typescript-version/src/renderer-locale-de.ts | 125 +++++++++ typescript-version/src/renderer-locale-en.ts | 125 +++++++++ typescript-version/src/renderer-texts.ts | 268 ++----------------- typescript-version/src/renderer.ts | 4 +- 8 files changed, 275 insertions(+), 261 deletions(-) create mode 100644 typescript-version/src/renderer-locale-de.ts create mode 100644 typescript-version/src/renderer-locale-en.ts diff --git a/typescript-version/package-lock.json b/typescript-version/package-lock.json index 1cfcdce..c3f5fed 100644 --- a/typescript-version/package-lock.json +++ b/typescript-version/package-lock.json @@ -1,12 +1,12 @@ { "name": "twitch-vod-manager", - "version": "3.8.6", + "version": "3.8.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "twitch-vod-manager", - "version": "3.8.6", + "version": "3.8.7", "license": "MIT", "dependencies": { "axios": "^1.6.0", diff --git a/typescript-version/package.json b/typescript-version/package.json index 2684ed8..7338c52 100644 --- a/typescript-version/package.json +++ b/typescript-version/package.json @@ -1,6 +1,6 @@ { "name": "twitch-vod-manager", - "version": "3.8.6", + "version": "3.8.7", "description": "Twitch VOD Manager - Download Twitch VODs easily", "main": "dist/main.js", "author": "xRangerDE", diff --git a/typescript-version/src/index.html b/typescript-version/src/index.html index 4b081ef..cc05c28 100644 --- a/typescript-version/src/index.html +++ b/typescript-version/src/index.html @@ -343,7 +343,7 @@

Updates

-

Version: v3.8.6

+

Version: v3.8.7

@@ -354,7 +354,7 @@
Nicht verbunden - v3.8.6 + v3.8.7 diff --git a/typescript-version/src/main.ts b/typescript-version/src/main.ts index 5dc601d..fef9d8f 100644 --- a/typescript-version/src/main.ts +++ b/typescript-version/src/main.ts @@ -8,7 +8,7 @@ import { autoUpdater } from 'electron-updater'; // ========================================== // CONFIG & CONSTANTS // ========================================== -const APP_VERSION = '3.8.6'; +const APP_VERSION = '3.8.7'; const UPDATE_CHECK_URL = 'http://24-music.de/version.json'; // Paths @@ -118,7 +118,7 @@ const defaultConfig: Config = { theme: 'twitch', download_mode: 'full', part_minutes: 120, - language: 'de' + language: 'en' }; function loadConfig(): Config { diff --git a/typescript-version/src/renderer-locale-de.ts b/typescript-version/src/renderer-locale-de.ts new file mode 100644 index 0000000..16162b3 --- /dev/null +++ b/typescript-version/src/renderer-locale-de.ts @@ -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; diff --git a/typescript-version/src/renderer-locale-en.ts b/typescript-version/src/renderer-locale-en.ts new file mode 100644 index 0000000..9ca9d67 --- /dev/null +++ b/typescript-version/src/renderer-locale-en.ts @@ -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; diff --git a/typescript-version/src/renderer-texts.ts b/typescript-version/src/renderer-texts.ts index abf472d..fb90723 100644 --- a/typescript-version/src/renderer-texts.ts +++ b/typescript-version/src/renderer-texts.ts @@ -1,261 +1,26 @@ type LanguageCode = 'de' | 'en'; const UI_TEXTS = { - 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: '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' - } - } + de: UI_TEXT_DE, + en: UI_TEXT_EN } as const; -let currentLanguage: LanguageCode = 'de'; +let currentLanguage: LanguageCode = 'en'; 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 { const node = document.getElementById(id); if (node) node.textContent = value; @@ -309,7 +74,6 @@ function applyLanguageToStaticUI(): void { setText('partMinutesLabel', UI_TEXT.static.partMinutesLabel); setText('updateTitle', UI_TEXT.static.updateTitle); setText('checkUpdateBtn', UI_TEXT.static.checkUpdates); - setPlaceholder('newStreamer', UI_TEXT.static.streamerPlaceholder); const status = document.getElementById('statusText')?.textContent?.trim() || ''; diff --git a/typescript-version/src/renderer.ts b/typescript-version/src/renderer.ts index e210fdb..ea4c477 100644 --- a/typescript-version/src/renderer.ts +++ b/typescript-version/src/renderer.ts @@ -1,6 +1,6 @@ async function init(): Promise { config = await window.api.getConfig(); - const language = setLanguage((config.language as string) || 'de'); + const language = setLanguage((config.language as string) || 'en'); config.language = language; const initialQueue = await window.api.getQueue(); queue = Array.isArray(initialQueue) ? initialQueue : []; @@ -14,7 +14,7 @@ async function init(): Promise { byId('clientSecret').value = config.client_secret ?? ''; byId('downloadPath').value = config.download_path ?? ''; byId('themeSelect').value = config.theme ?? 'twitch'; - byId('languageSelect').value = config.language ?? 'de'; + byId('languageSelect').value = config.language ?? 'en'; byId('downloadMode').value = config.download_mode ?? 'full'; byId('partMinutes').value = String(config.part_minutes ?? 120);