Three Phase-6 wins.
1. Cutter & Merge tab labels were the same i18n gap as the trim-VOD
dialog before 4.5.20: Dauer / Aufloesung / FPS / Auswahl / Start: /
Ende: / Schneiden / Zusammenfuegen were hardcoded German in
index.html. Each got an id + setText wiring + DE/EN locale strings
(cutter.infoDuration / .infoResolution / .infoFps / .infoSelection
/ .startLabel / .endLabel; cutter.cut + merge.merge already existed
for dynamic state, now also used as initial text on btnCut /
btnMerge).
2. Per-item retry button on failed queue entries. The existing
"retry failed" queue-action retried ALL failed items at once;
when only one specific item should be retried (e.g. transient
network blip on one URL), the user had to remove every other
failed item first. New ipcMain.handle("retry-queue-item", id)
resets that single item to status: pending and triggers
processQueue if idle. A small ↻ icon now sits next to the
remove (x) button on items in the error state.
3. Status bar queue summary. The footer previously showed only the
connection status + version. With longer queues the user had to
scroll the queue panel to see how many downloads were active
versus pending. New span between the status indicator and the
version reads "{downloading} dl, {pending} queued" (locale-aware,
hidden when queue is empty). Updated on onQueueUpdated and
onDownloadProgress so it stays live.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
288 lines
12 KiB
TypeScript
288 lines
12 KiB
TypeScript
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',
|
|
retryFailed: 'Retry',
|
|
retryFailedHint: 'Retry failed downloads only',
|
|
healthUnknown: 'System: Unknown',
|
|
healthGood: 'System: Stable',
|
|
healthWarn: 'System: Warning',
|
|
healthBad: 'System: Problem',
|
|
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',
|
|
themeLight: 'Light',
|
|
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)',
|
|
parallelDownloadsLabel: 'Parallel Downloads',
|
|
parallelDownloads1: '1 (Default)',
|
|
parallelDownloads2: '2 (Parallel)',
|
|
performanceModeLabel: 'Performance Profile',
|
|
performanceModeStability: 'Max Stability',
|
|
performanceModeBalanced: 'Balanced',
|
|
performanceModeSpeed: 'Max Speed',
|
|
smartSchedulerLabel: 'Enable smart queue scheduler',
|
|
smartSchedulerHint: 'Prefers shorter VODs and older queue entries first so the queue throughput stays steady. Disable to drain in strict insertion order.',
|
|
streamerInvalid: 'Invalid Twitch username (4-25 chars, letters/digits/underscore).',
|
|
apiHelpIntro: 'You need a Client ID and Client Secret from Twitch.',
|
|
apiHelpLinkText: 'dev.twitch.tv/console/apps',
|
|
openDebugLogFile: 'Open log file',
|
|
duplicatePreventionLabel: 'Prevent duplicate queue entries',
|
|
persistQueueLabel: 'Keep queue between app restarts',
|
|
metadataCacheMinutesLabel: 'Metadata Cache (Minutes)',
|
|
filenameTemplatesTitle: 'Filename Templates',
|
|
vodTemplateLabel: 'VOD Template',
|
|
partsTemplateLabel: 'VOD Part Template',
|
|
defaultClipTemplateLabel: 'Clip Template',
|
|
filenameTemplateHint: 'Placeholders: {title} {id} {channel} {date} {part} {part_padded} {trim_start} {trim_end} {trim_length} {date_custom="yyyy-MM-dd"}',
|
|
vodTemplatePlaceholder: '{title}.mp4',
|
|
partsTemplatePlaceholder: '{date}_Part{part_padded}.mp4',
|
|
defaultClipTemplatePlaceholder: '{date}_{part}.mp4',
|
|
templateLintOk: 'Template check: OK',
|
|
templateLintWarn: 'Unknown placeholder(s)',
|
|
templateGuideButton: 'Template Guide',
|
|
templateGuideTitle: 'Filename Template Guide',
|
|
templateGuideIntro: 'Use placeholders for filenames and test your pattern with a live preview.',
|
|
templateGuideTemplateLabel: 'Template',
|
|
templateGuideOutputLabel: 'Live preview',
|
|
templateGuideVarsTitle: 'Available placeholders',
|
|
templateGuideVarCol: 'Placeholder',
|
|
templateGuideDescCol: 'Description',
|
|
templateGuideExampleCol: 'Example',
|
|
templateGuideUseVod: 'Use VOD template',
|
|
templateGuideUseParts: 'Use part template',
|
|
templateGuideUseClip: 'Use clip template',
|
|
templateGuideClose: 'Close',
|
|
templateGuideContextVod: 'Context: Sample full VOD download',
|
|
templateGuideContextParts: 'Context: Sample split VOD part',
|
|
templateGuideContextClip: 'Context: Sample clip trim',
|
|
templateGuideContextClipLive: 'Context: Current clip dialog selection',
|
|
runtimeMetricsTitle: 'Runtime Metrics',
|
|
runtimeMetricsRefresh: 'Refresh',
|
|
runtimeMetricsExport: 'Export JSON',
|
|
runtimeMetricsAutoRefresh: 'Auto refresh',
|
|
runtimeMetricsLoading: 'Loading metrics...',
|
|
runtimeMetricsError: 'Could not load runtime metrics.',
|
|
runtimeMetricsExportDone: 'Runtime metrics exported successfully.',
|
|
runtimeMetricsExportCancelled: 'Runtime metrics export cancelled.',
|
|
runtimeMetricsExportFailed: 'Runtime metrics export failed.',
|
|
runtimeMetricQueue: 'Queue',
|
|
runtimeMetricMode: 'Mode',
|
|
runtimeMetricRetries: 'Retries',
|
|
runtimeMetricIntegrity: 'Integrity failures',
|
|
runtimeMetricCache: 'Cache',
|
|
runtimeMetricBandwidth: 'Bandwidth',
|
|
runtimeMetricDownloads: 'Downloads',
|
|
runtimeMetricActive: 'Active item',
|
|
runtimeMetricLastError: 'Last error class',
|
|
runtimeMetricUpdated: 'Updated',
|
|
updateTitle: 'Updates',
|
|
checkUpdates: 'Check for updates',
|
|
preflightTitle: 'System Check',
|
|
preflightRun: 'Run check',
|
|
preflightFix: 'Auto-fix tools',
|
|
preflightEmpty: 'No checks run yet.',
|
|
preflightChecking: 'Checking...',
|
|
preflightFixing: 'Fixing...',
|
|
preflightReady: 'Everything is ready.',
|
|
preflightInternet: 'Internet',
|
|
preflightStreamlink: 'Streamlink',
|
|
preflightFfmpeg: 'FFmpeg',
|
|
preflightFfprobe: 'FFprobe',
|
|
preflightPath: 'Download path',
|
|
debugLogTitle: 'Live Debug Log',
|
|
refreshLog: 'Refresh',
|
|
autoRefresh: 'Auto refresh',
|
|
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: 'Pause',
|
|
resume: 'Resume',
|
|
statusDone: 'Completed',
|
|
statusFailed: 'Failed',
|
|
statusRunning: 'Running',
|
|
statusPaused: 'Paused',
|
|
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.',
|
|
duplicateSkipped: 'This item is already active in the queue.',
|
|
openFile: 'Open file',
|
|
showInFolder: 'Show in folder',
|
|
openFileFailed: 'Could not open the file (it may have been moved or deleted).',
|
|
outputFilesLabel: '{count} output files',
|
|
retryItem: 'Retry this item',
|
|
statusBarSummary: '{downloading} dl, {pending} queued'
|
|
},
|
|
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',
|
|
trimButton: 'Trim VOD',
|
|
filterPlaceholder: 'Filter by title... (Ctrl+F)',
|
|
filterClearTitle: 'Clear filter (Esc)',
|
|
filterNoMatchTitle: 'No matches',
|
|
filterNoMatchText: 'No VODs match the current filter.',
|
|
filterMatchCount: '{shown} of {total} VODs',
|
|
sortLabel: 'Sort:',
|
|
sortDateDesc: 'Newest first',
|
|
sortDateAsc: 'Oldest first',
|
|
sortViewsDesc: 'Most viewed',
|
|
sortDurationDesc: 'Longest first',
|
|
sortDurationAsc: 'Shortest first',
|
|
bulkSelectedCount: '{count} selected',
|
|
bulkAddToQueue: '+ Queue',
|
|
bulkAdding: 'Adding...',
|
|
bulkClear: 'Clear',
|
|
bulkAddedToQueue: 'Added {count} VODs to the queue.',
|
|
bulkAddSkipped: 'No VODs were added (already in queue or invalid).'
|
|
},
|
|
clips: {
|
|
dialogTitle: 'Trim VOD',
|
|
dialogStart: 'Start:',
|
|
dialogStartTime: 'Start time (HH:MM:SS):',
|
|
dialogEnd: 'End:',
|
|
dialogEndTime: 'End time (HH:MM:SS):',
|
|
dialogDuration: 'Duration: ',
|
|
dialogPartLabel: 'Start part number (optional, for continuation):',
|
|
dialogPartHint: 'Leave empty = part 1',
|
|
dialogFormatLabel: 'Filename format:',
|
|
dialogConfirm: 'Add to queue',
|
|
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)',
|
|
formatParts: '(parts naming)',
|
|
formatTemplate: '(custom template)',
|
|
templateEmpty: 'Template cannot be empty in custom template mode.',
|
|
templatePlaceholder: '{date}_{part}.mp4',
|
|
templateHelp: 'Placeholders: {title} {id} {channel} {date} {part} {part_padded} {trim_start} {trim_end} {trim_length} {date_custom="yyyy-MM-dd"}'
|
|
},
|
|
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.',
|
|
infoDuration: 'Duration',
|
|
infoResolution: 'Resolution',
|
|
infoFps: 'FPS',
|
|
infoSelection: 'Selection',
|
|
startLabel: 'Start:',
|
|
endLabel: 'End:'
|
|
},
|
|
merge: {
|
|
empty: 'No videos selected',
|
|
merging: 'Merging...',
|
|
merge: 'Merge',
|
|
success: 'Videos merged successfully!',
|
|
failed: 'Failed to merge videos.'
|
|
},
|
|
mergeGroup: {
|
|
btn: 'Merge & Split',
|
|
phaseDownloading: 'Downloading VOD',
|
|
phaseMerging: 'Merging...',
|
|
phaseSplitting: 'Splitting Part',
|
|
phaseCleanup: 'Cleaning up...',
|
|
needMinTwo: 'Select at least 2 VODs',
|
|
titleTwo: 'Merge: {title1} + {title2}',
|
|
titleMany: 'Merge: {title1} + {count} more',
|
|
metaLabel: '{count} VODs',
|
|
},
|
|
updates: {
|
|
bannerDefault: 'New version available!',
|
|
latest: 'You are on the latest version!',
|
|
checking: 'Checking for updates...',
|
|
checkInProgress: 'Update check is already running.',
|
|
readyToInstall: 'Update is ready to install.',
|
|
checkFailed: 'Update check failed.',
|
|
downloading: 'Downloading...',
|
|
downloadInProgress: 'Update download is already running.',
|
|
downloadFailed: 'Update download failed.',
|
|
available: 'available!',
|
|
downloadNow: 'Download now',
|
|
downloadLabel: 'Download',
|
|
ready: 'ready to install!',
|
|
installNow: 'Install now & restart',
|
|
modalAvailableTitle: 'Update available',
|
|
modalAvailableMessage: 'Version {version} is available. Download it now?',
|
|
modalReadyTitle: 'Update ready',
|
|
modalReadyMessage: 'Version {version} has been downloaded. Install and restart now?',
|
|
modalDismiss: 'No',
|
|
modalDownloadConfirm: 'Yes, download',
|
|
modalInstallConfirm: 'Yes, install',
|
|
modalSkipVersion: 'Skip this version',
|
|
changelogLabel: 'Changelog',
|
|
showChangelog: 'Show changelog',
|
|
hideChangelog: 'Hide changelog',
|
|
noChangelog: 'No changelog available.',
|
|
releasedLabel: 'Release'
|
|
}
|
|
} as const;
|