Split locales into dedicated files and default to English (v3.8.8)

Move DE/EN translation content into separate renderer locale files, keep instant language switching, add locale-aware date/number formatting helpers, and set English as the default language for fresh installs.
This commit is contained in:
xRangerDE 2026-02-14 05:43:21 +01:00
parent 5749214a62
commit 2579198e8b
9 changed files with 22 additions and 11 deletions

View File

@ -1,12 +1,12 @@
{ {
"name": "twitch-vod-manager", "name": "twitch-vod-manager",
"version": "3.8.7", "version": "3.8.8",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "twitch-vod-manager", "name": "twitch-vod-manager",
"version": "3.8.7", "version": "3.8.8",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"axios": "^1.6.0", "axios": "^1.6.0",

View File

@ -1,6 +1,6 @@
{ {
"name": "twitch-vod-manager", "name": "twitch-vod-manager",
"version": "3.8.7", "version": "3.8.8",
"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",

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="de"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
@ -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.7</p> <p id="versionInfo" style="margin-bottom: 10px; color: var(--text-secondary);">Version: v3.8.8</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,11 +354,13 @@
<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.7</span> <span id="versionText">v3.8.8</span>
</div> </div>
</main> </main>
</div> </div>
<script src="../dist/renderer-locale-de.js"></script>
<script src="../dist/renderer-locale-en.js"></script>
<script src="../dist/renderer-texts.js"></script> <script src="../dist/renderer-texts.js"></script>
<script src="../dist/renderer-shared.js"></script> <script src="../dist/renderer-shared.js"></script>
<script src="../dist/renderer-settings.js"></script> <script src="../dist/renderer-settings.js"></script>

View File

@ -8,7 +8,7 @@ import { autoUpdater } from 'electron-updater';
// ========================================== // ==========================================
// CONFIG & CONSTANTS // CONFIG & CONSTANTS
// ========================================== // ==========================================
const APP_VERSION = '3.8.7'; const APP_VERSION = '3.8.8';
const UPDATE_CHECK_URL = 'http://24-music.de/version.json'; const UPDATE_CHECK_URL = 'http://24-music.de/version.json';
// Paths // Paths

View File

@ -114,6 +114,7 @@ const UI_TEXT_DE = {
failed: 'Fehler beim Zusammenfugen der Videos.' failed: 'Fehler beim Zusammenfugen der Videos.'
}, },
updates: { updates: {
bannerDefault: 'Neue Version verfugbar!',
latest: 'Du hast die neueste Version!', latest: 'Du hast die neueste Version!',
downloading: 'Wird heruntergeladen...', downloading: 'Wird heruntergeladen...',
available: 'verfugbar!', available: 'verfugbar!',

View File

@ -114,6 +114,7 @@ const UI_TEXT_EN = {
failed: 'Failed to merge videos.' failed: 'Failed to merge videos.'
}, },
updates: { updates: {
bannerDefault: 'New version available!',
latest: 'You are on the latest version!', latest: 'You are on the latest version!',
downloading: 'Downloading...', downloading: 'Downloading...',
available: 'available!', available: 'available!',

View File

@ -30,8 +30,13 @@ function changeLanguage(lang: string): void {
renderQueue(); renderQueue();
renderStreamers(); renderStreamers();
if (!currentStreamer) {
byId('pageTitle').textContent = UI_TEXT.tabs.vods; const activeTabId = document.querySelector('.tab-content.active')?.id || 'vodsTab';
const activeTab = activeTabId.replace('Tab', '');
if (activeTab === 'vods' && currentStreamer) {
byId('pageTitle').textContent = currentStreamer;
} else {
byId('pageTitle').textContent = (UI_TEXT.tabs as Record<string, string>)[activeTab] || UI_TEXT.appName;
} }
} }

View File

@ -84,7 +84,7 @@ function renderVODs(vods: VOD[] | null | undefined, streamer: string): void {
grid.innerHTML = vods.map((vod: VOD) => { grid.innerHTML = vods.map((vod: VOD) => {
const thumb = vod.thumbnail_url.replace('%{width}', '320').replace('%{height}', '180'); const thumb = vod.thumbnail_url.replace('%{width}', '320').replace('%{height}', '180');
const date = new Date(vod.created_at).toLocaleDateString('de-DE'); const date = formatUiDate(vod.created_at);
const escapedTitle = vod.title.replace(/'/g, "\\'").replace(/\"/g, '&quot;'); const escapedTitle = vod.title.replace(/'/g, "\\'").replace(/\"/g, '&quot;');
const safeDisplayTitle = escapeHtml(vod.title || UI_TEXT.vods.untitled); const safeDisplayTitle = escapeHtml(vod.title || UI_TEXT.vods.untitled);
@ -96,7 +96,7 @@ function renderVODs(vods: VOD[] | null | undefined, streamer: string): void {
<div class="vod-meta"> <div class="vod-meta">
<span>${date}</span> <span>${date}</span>
<span>${vod.duration}</span> <span>${vod.duration}</span>
<span>${vod.view_count.toLocaleString()} ${UI_TEXT.vods.views}</span> <span>${formatUiNumber(vod.view_count)} ${UI_TEXT.vods.views}</span>
</div> </div>
</div> </div>
<div class="vod-actions"> <div class="vod-actions">

View File

@ -74,6 +74,8 @@ 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);
setText('updateText', UI_TEXT.updates.bannerDefault);
setText('updateButton', UI_TEXT.updates.downloadNow);
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() || '';