diff --git a/typescript-version/package-lock.json b/typescript-version/package-lock.json
index 0165aa0..3c2921d 100644
--- a/typescript-version/package-lock.json
+++ b/typescript-version/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "twitch-vod-manager",
- "version": "4.0.2",
+ "version": "4.0.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "twitch-vod-manager",
- "version": "4.0.2",
+ "version": "4.0.3",
"license": "MIT",
"dependencies": {
"axios": "^1.6.0",
diff --git a/typescript-version/package.json b/typescript-version/package.json
index 2b0b7b9..d144708 100644
--- a/typescript-version/package.json
+++ b/typescript-version/package.json
@@ -1,6 +1,6 @@
{
"name": "twitch-vod-manager",
- "version": "4.0.2",
+ "version": "4.0.3",
"description": "Twitch VOD Manager - Download Twitch VODs easily",
"main": "dist/main.js",
"author": "xRangerDE",
diff --git a/typescript-version/scripts/smoke-test-full.js b/typescript-version/scripts/smoke-test-full.js
index fd3898f..6da9f35 100644
--- a/typescript-version/scripts/smoke-test-full.js
+++ b/typescript-version/scripts/smoke-test-full.js
@@ -201,7 +201,9 @@ async function run() {
const deState = {
nav: (document.getElementById('navSettingsText')?.textContent || '').trim(),
retry: (document.getElementById('btnRetryFailed')?.textContent || '').trim(),
- deFlag: (document.getElementById('languageDeText')?.textContent || '').trim()
+ deText: (document.getElementById('languageDeText')?.textContent || '').trim(),
+ deIcon: !!document.querySelector('#langOptionDe .flag-icon.flag-de'),
+ deActive: !!document.getElementById('langOptionDe')?.classList.contains('active')
};
lang.value = 'en';
@@ -210,14 +212,18 @@ async function run() {
const enState = {
nav: (document.getElementById('navSettingsText')?.textContent || '').trim(),
retry: (document.getElementById('btnRetryFailed')?.textContent || '').trim(),
- enFlag: (document.getElementById('languageEnText')?.textContent || '').trim()
+ enText: (document.getElementById('languageEnText')?.textContent || '').trim(),
+ enIcon: !!document.querySelector('#langOptionEn .flag-icon.flag-en'),
+ enActive: !!document.getElementById('langOptionEn')?.classList.contains('active')
};
checks.language = { deState, enState };
assert(deState.nav.includes('Einstellungen'), 'German language switch failed');
assert(enState.nav.includes('Settings'), 'English language switch failed');
- assert(deState.deFlag.includes('π©πͺ'), 'German flag missing');
- assert(enState.enFlag.includes('πΊπΈ'), 'English flag missing');
+ assert(deState.deIcon, 'German flag icon missing');
+ assert(enState.enIcon, 'English flag icon missing');
+ assert(deState.deActive, 'German language button did not activate');
+ assert(enState.enActive, 'English language button did not activate');
await window.api.saveConfig({ client_id: '', client_secret: '', download_path: tmpDir });
window.showTab('vods');
diff --git a/typescript-version/src/index.html b/typescript-version/src/index.html
index 3a2d144..2293545 100644
--- a/typescript-version/src/index.html
+++ b/typescript-version/src/index.html
@@ -300,9 +300,19 @@
@@ -345,7 +355,7 @@
Updates
-
Version: v4.0.2
+
Version: v4.0.3
@@ -377,7 +387,7 @@
Nicht verbunden
- v4.0.2
+ v4.0.3
diff --git a/typescript-version/src/main.ts b/typescript-version/src/main.ts
index 1c5bef1..ac4fcd2 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 = '4.0.2';
+const APP_VERSION = '4.0.3';
const UPDATE_CHECK_URL = 'http://24-music.de/version.json';
// Paths
diff --git a/typescript-version/src/renderer-locale-de.ts b/typescript-version/src/renderer-locale-de.ts
index 5bbe3d3..43f0fb4 100644
--- a/typescript-version/src/renderer-locale-de.ts
+++ b/typescript-version/src/renderer-locale-de.ts
@@ -27,8 +27,8 @@ const UI_TEXT_DE = {
designTitle: 'Design',
themeLabel: 'Theme',
languageLabel: 'Sprache',
- languageDe: 'π©πͺ Deutsch',
- languageEn: 'πΊπΈ Englisch',
+ languageDe: 'Deutsch',
+ languageEn: 'Englisch',
apiTitle: 'Twitch API',
clientIdLabel: 'Client ID',
clientSecretLabel: 'Client Secret',
diff --git a/typescript-version/src/renderer-locale-en.ts b/typescript-version/src/renderer-locale-en.ts
index bd40d7a..7b41738 100644
--- a/typescript-version/src/renderer-locale-en.ts
+++ b/typescript-version/src/renderer-locale-en.ts
@@ -27,8 +27,8 @@ const UI_TEXT_EN = {
designTitle: 'Design',
themeLabel: 'Theme',
languageLabel: 'Language',
- languageDe: 'π©πͺ German',
- languageEn: 'πΊπΈ English',
+ languageDe: 'German',
+ languageEn: 'English',
apiTitle: 'Twitch API',
clientIdLabel: 'Client ID',
clientSecretLabel: 'Client Secret',
diff --git a/typescript-version/src/renderer-settings.ts b/typescript-version/src/renderer-settings.ts
index cb559ae..90d5c6a 100644
--- a/typescript-version/src/renderer-settings.ts
+++ b/typescript-version/src/renderer-settings.ts
@@ -22,6 +22,7 @@ function updateStatus(text: string, connected: boolean): void {
function changeLanguage(lang: string): void {
const normalized = setLanguage(lang);
byId('languageSelect').value = normalized;
+ updateLanguagePicker(normalized);
config.language = normalized;
void window.api.saveConfig({ language: normalized });
@@ -40,6 +41,21 @@ function changeLanguage(lang: string): void {
}
}
+function updateLanguagePicker(lang: string): void {
+ const de = byId('langOptionDe');
+ const en = byId('langOptionEn');
+
+ const isDe = lang === 'de';
+ de.classList.toggle('active', isDe);
+ en.classList.toggle('active', !isDe);
+ de.setAttribute('aria-pressed', String(isDe));
+ en.setAttribute('aria-pressed', String(!isDe));
+}
+
+function selectLanguageOption(lang: string): void {
+ changeLanguage(lang);
+}
+
function renderPreflightResult(result: PreflightResult): void {
const entries = [
[UI_TEXT.static.preflightInternet, result.checks.internet],
diff --git a/typescript-version/src/renderer.ts b/typescript-version/src/renderer.ts
index f44af9e..ced3056 100644
--- a/typescript-version/src/renderer.ts
+++ b/typescript-version/src/renderer.ts
@@ -15,6 +15,7 @@ async function init(): Promise {
byId('downloadPath').value = config.download_path ?? '';
byId('themeSelect').value = config.theme ?? 'twitch';
byId('languageSelect').value = config.language ?? 'en';
+ updateLanguagePicker(config.language ?? 'en');
byId('downloadMode').value = config.download_mode ?? 'full';
byId('partMinutes').value = String(config.part_minutes ?? 120);
diff --git a/typescript-version/src/styles.css b/typescript-version/src/styles.css
index e4c4aa3..373eeba 100644
--- a/typescript-version/src/styles.css
+++ b/typescript-version/src/styles.css
@@ -606,6 +606,62 @@ body {
border-color: var(--accent);
}
+.language-picker {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 8px;
+}
+
+.lang-option {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ border: 1px solid rgba(255,255,255,0.14);
+ border-radius: 6px;
+ background: var(--bg-main);
+ color: var(--text);
+ padding: 9px 10px;
+ cursor: pointer;
+ font-size: 13px;
+}
+
+.lang-option:hover {
+ border-color: rgba(255,255,255,0.26);
+}
+
+.lang-option.active {
+ border-color: var(--accent);
+ box-shadow: 0 0 0 1px rgba(145, 70, 255, 0.2);
+}
+
+.flag-icon {
+ width: 16px;
+ height: 12px;
+ border-radius: 2px;
+ border: 1px solid rgba(0,0,0,0.35);
+ flex-shrink: 0;
+ position: relative;
+ overflow: hidden;
+}
+
+.flag-de {
+ background: linear-gradient(to bottom, #111 0 33.33%, #dd0000 33.33% 66.66%, #ffce00 66.66% 100%);
+}
+
+.flag-en {
+ background: repeating-linear-gradient(to bottom, #b22234 0 7.7%, #ffffff 7.7% 15.4%);
+}
+
+.flag-en::before {
+ content: '';
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 45%;
+ height: 56%;
+ background: #3c3b6e;
+}
+
.form-row {
display: flex;
gap: 10px;