feat: add German and English UI language support

A single-language interface makes the app less usable for part of the audience
and encourages more hardcoded copy as new screens and states are added.
Introducing a shared i18n path with a persisted language preference gives the
UI one consistent way to present text and lowers the risk of partial or
inconsistent localization over time.

The surrounding copy cleanup belongs in the same change because it aligns
existing labels, messages, and settings text with that translation structure
instead of leaving mixed localization approaches in place.
This commit is contained in:
Andre
2026-05-16 11:44:06 +02:00
parent 682a8b77a8
commit 722bbc6f43
42 changed files with 859 additions and 320 deletions
+66 -49
View File
@@ -1,16 +1,19 @@
#!/bin/bash
# build-flatpak.sh — Kompletter Build-Ablauf für das Twitch4SteamDeck Flatpak.
# build-flatpak.sh — Complete build flow for the Twitch4SteamDeck Flatpak.
# Ausführen in WSL2 Ubuntu: bash flatpak/build-flatpak.sh
# Run in WSL2 Ubuntu: bash flatpak/build-flatpak.sh
set -e
# ─────────────────────────────────────────────────────────────────────────────
# Schritt 0: Projektdateien vom Windows-Dateisystem in WSL2 synchronisieren
# Step 0: sync project files from the Windows filesystem into WSL2
# ─────────────────────────────────────────────────────────────────────────────
WIN_PROJECT="/mnt/c/Projekte/twitch4steamdeck"
WSL_PROJECT="$HOME/twitch4steamdeck"
echo "=== Synchronisiere $WIN_PROJECT → $WSL_PROJECT ==="
echo "=== Syncing $WIN_PROJECT -> $WSL_PROJECT ==="
rsync -a --delete \
--exclude=node_modules/ \
--exclude=out/ \
@@ -18,29 +21,31 @@ rsync -a --delete \
--exclude=build-dir/ \
--exclude='*.flatpak' \
"$WIN_PROJECT/" "$WSL_PROJECT/"
echo " ✓ Sync abgeschlossen"
echo " ✓ Sync completed"
cd "$WSL_PROJECT"
echo "=== Arbeitsverzeichnis: $WSL_PROJECT ==="
echo "=== Working directory: $WSL_PROJECT ==="
# ─────────────────────────────────────────────────────────────────────────────
# WSL2-Dateisystem-Check: flatpak-builder kann nicht über /mnt/ (Windows 9P) bauen
# WSL2 filesystem check: flatpak-builder cannot build through /mnt/ (Windows 9P)
# ─────────────────────────────────────────────────────────────────────────────
if [[ "$WSL_PROJECT" == /mnt/* ]]; then
echo ""
echo "FEHLER: WSL_PROJECT zeigt auf das Windows-Dateisystem ($WSL_PROJECT)."
echo " flatpak-builder benötigt FUSE, das auf /mnt/ nicht funktioniert."
echo "ERROR: WSL_PROJECT points to the Windows filesystem ($WSL_PROJECT)."
echo " flatpak-builder requires FUSE, which does not work on /mnt/."
exit 1
fi
# ─────────────────────────────────────────────────────────────────────────────
# Schritt 1: Flatpak-Abhängigkeiten prüfen
# Step 1: verify Flatpak dependencies
# ─────────────────────────────────────────────────────────────────────────────
echo ""
echo "=== [1/6] Prüfe Flatpak-Voraussetzungen ==="
echo "=== [1/6] Checking Flatpak prerequisites ==="
for cmd in flatpak flatpak-builder node npm python3 rsvg-convert; do
if ! command -v "$cmd" &>/dev/null; then
echo "FEHLER: '$cmd' nicht gefunden."
echo "ERROR: '$cmd' not found."
case "$cmd" in
flatpak|flatpak-builder) echo " → sudo apt install flatpak flatpak-builder" ;;
node|npm) echo " → curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - && sudo apt install nodejs" ;;
@@ -52,6 +57,7 @@ done
# ─────────────────────────────────────────────────────────────────────────────
# Schritt 2: libplacebo-Tarball erzeugen (enthält glad2-Submodul, GitHub-Tarball reicht nicht)
# Step 2: create the libplacebo tarball (includes the glad2 submodule, GitHub tarball is not enough)
# ─────────────────────────────────────────────────────────────────────────────
LIBPLACEBO_VERSION="6.338.2"
LIBPLACEBO_TARBALL="flatpak/libplacebo-${LIBPLACEBO_VERSION}-full.tar.gz"
@@ -60,33 +66,34 @@ LIBPLACEBO_SHA="7f5da41b872302208f0e10c22d3e108ab9fdb1f253eb47c18651698c65d6b426
echo ""
echo "=== [2/7] libplacebo-Tarball ==="
if [ -f "$LIBPLACEBO_TARBALL" ] && echo "$LIBPLACEBO_SHA $LIBPLACEBO_TARBALL" | sha256sum -c --quiet 2>/dev/null; then
echo " ✓ libplacebo-${LIBPLACEBO_VERSION}-full.tar.gz bereits vorhanden und korrekt"
echo " ✓ libplacebo-${LIBPLACEBO_VERSION}-full.tar.gz already exists and is correct"
else
echo " → Klone libplacebo v${LIBPLACEBO_VERSION} mit Submodulen ..."
echo " → Cloning libplacebo v${LIBPLACEBO_VERSION} with submodules ..."
TMPDIR_LP=$(mktemp -d)
git clone --recurse-submodules --depth 1 --branch "v${LIBPLACEBO_VERSION}" \
https://github.com/haasn/libplacebo.git "$TMPDIR_LP/libplacebo"
echo " → Erstelle Tarball ..."
echo " → Creating tarball ..."
tar czf "$LIBPLACEBO_TARBALL" -C "$TMPDIR_LP" libplacebo/
rm -rf "$TMPDIR_LP"
ACTUAL_SHA=$(sha256sum "$LIBPLACEBO_TARBALL" | awk '{print $1}')
if [ "$ACTUAL_SHA" != "$LIBPLACEBO_SHA" ]; then
echo " WARNUNG: SHA256 weicht ab!"
echo " Erwartet: $LIBPLACEBO_SHA"
echo " Erhalten: $ACTUAL_SHA"
echo " → Manifest muss aktualisiert werden. Aktualisiere jetzt ..."
echo " WARNING: SHA256 differs!"
echo " Expected: $LIBPLACEBO_SHA"
echo " Received: $ACTUAL_SHA"
echo " → Manifest must be updated. Updating now ..."
sed -i "s|sha256: ${LIBPLACEBO_SHA}|sha256: ${ACTUAL_SHA}|" flatpak/tv.twitch4steamdeck.App.yml
echo " ✓ Manifest-SHA aktualisiert"
echo " ✓ Manifest SHA updated"
else
echo " ✓ SHA256 korrekt"
echo " ✓ SHA256 is correct"
fi
fi
# ─────────────────────────────────────────────────────────────────────────────
# Schritt 3: Flatpak-Runtimes prüfen / installieren
# Step 3: verify / install Flatpak runtimes
# ─────────────────────────────────────────────────────────────────────────────
echo ""
echo "=== [3/7] Prüfe Flatpak-Runtimes ==="
echo "=== [3/7] Checking Flatpak runtimes ==="
RUNTIMES=(
"org.freedesktop.Platform//24.08"
"org.freedesktop.Sdk//24.08"
@@ -95,74 +102,82 @@ RUNTIMES=(
for rt in "${RUNTIMES[@]}"; do
if ! flatpak info --user "$rt" &>/dev/null 2>&1 && \
! flatpak info --system "$rt" &>/dev/null 2>&1; then
echo "Installiere: $rt"
echo "Installing: $rt"
flatpak install --user --noninteractive flathub "$rt"
else
echo " ✓ $rt bereits vorhanden"
echo " ✓ $rt already installed"
fi
done
# ─────────────────────────────────────────────────────────────────────────────
# Schritt 3: .env prüfen
# Schritt 4: .env prüfen
# Step 4: verify .env
# ─────────────────────────────────────────────────────────────────────────────
echo ""
echo "=== [4/7] Prüfe .env (Twitch Client-ID) ==="
echo "=== [4/7] Checking .env (Twitch client ID) ==="
if [ ! -f .env ]; then
echo "FEHLER: .env nicht gefunden."
echo " → Kopiere .env.example nach .env und trage MAIN_VITE_TWITCH_CLIENT_ID ein."
echo "ERROR: .env not found."
echo " → Copy .env.example to .env and add MAIN_VITE_TWITCH_CLIENT_ID."
exit 1
fi
if ! grep -q "MAIN_VITE_TWITCH_CLIENT_ID=" .env; then
echo "FEHLER: MAIN_VITE_TWITCH_CLIENT_ID fehlt in .env"
echo "ERROR: MAIN_VITE_TWITCH_CLIENT_ID is missing in .env"
exit 1
fi
echo " ✓ .env gefunden"
echo " ✓ .env found"
# ─────────────────────────────────────────────────────────────────────────────
# Schritt 4: npm install (Linux) + better-sqlite3 rebuild + Build
# Schritt 5: npm install (Linux) + better-sqlite3 rebuild + Build
# Step 5: npm install (Linux) + better-sqlite3 rebuild + build
# ─────────────────────────────────────────────────────────────────────────────
echo ""
echo "=== [5/7] npm install (Linux-Binaries) + Rebuild native Modules ==="
echo "=== [5/7] npm install (Linux binaries) + rebuild native modules ==="
npm install
echo " → Rebuilde better-sqlite3 für Linux x64 ..."
echo " → Rebuilding better-sqlite3 for Linux x64 ..."
npx @electron/rebuild --module-dir node_modules/better-sqlite3
echo " → Build (electron-vite) ..."
echo " → Running build (electron-vite) ..."
npm run build
# Verifikation: better_sqlite3.node muss ELF/Linux sein
# Verification: better_sqlite3.node must be ELF/Linux
NATIVE_NODE="node_modules/better-sqlite3/build/Release/better_sqlite3.node"
if [ -f "$NATIVE_NODE" ]; then
FILE_OUT=$(file "$NATIVE_NODE")
echo " native module: $FILE_OUT"
echo " Native module: $FILE_OUT"
if echo "$FILE_OUT" | grep -q "ELF"; then
echo " ✓ Linux ELF — korrekt"
echo " ✓ Linux ELF - correct"
else
echo " WARNUNG: Datei ist kein Linux-ELF. Rebuild möglicherweise fehlgeschlagen."
echo " WARNING: File is not a Linux ELF. Rebuild may have failed."
fi
fi
# ─────────────────────────────────────────────────────────────────────────────
# Schritt 4b: Python-Deps für streamlink via flatpak-pip-generator
# Schritt 5b: Python-Deps für streamlink via flatpak-pip-generator
# Step 5b: generate Python dependencies for streamlink via flatpak-pip-generator
# Erzeugt flatpak/python3-streamlink.json mit allen pip-Deps + sha256-Hashes.
# Generates flatpak/python3-streamlink.json with all pip dependencies + sha256 hashes.
# Die Datei wird von tv.twitch4steamdeck.App.yml per !include eingebunden.
# The file is included by tv.twitch4steamdeck.App.yml via !include.
# ─────────────────────────────────────────────────────────────────────────────
echo ""
echo "=== [5b] Python-Deps für streamlink generieren ==="
echo "=== [5b] Generating Python dependencies for streamlink ==="
if ! python3 -c "import flatpak_pip_generator" &>/dev/null; then
echo " → Installiere flatpak-pip-generator ..."
echo " → Installing flatpak-pip-generator ..."
# Ubuntu 24.04: externally-managed-environment → --break-system-packages nötig
# Ubuntu 24.04: externally-managed-environment -> requires --break-system-packages
pip3 install --quiet --break-system-packages flatpak-pip-generator
fi
python3 -m flatpak_pip_generator \
streamlink==6.11.0 \
--output flatpak/python3-streamlink
echo " ✓ flatpak/python3-streamlink.json generiert ($(wc -l < flatpak/python3-streamlink.json) Zeilen)"
echo " ✓ Generated flatpak/python3-streamlink.json ($(wc -l < flatpak/python3-streamlink.json) lines)"
# ─────────────────────────────────────────────────────────────────────────────
# Schritt 5: Manifest-SHA256-Werte füllen (interaktiv)
# Schritt 6: Manifest-SHA256-Werte füllen (interaktiv)
# Step 6: fill manifest SHA256 values (interactive)
# ─────────────────────────────────────────────────────────────────────────────
echo ""
echo "=== [6/7] SHA256-Prüfsummen für Manifest-Sources ==="
echo "=== [6/7] SHA256 checksums for manifest sources ==="
echo ""
MPV_URL="https://github.com/mpv-player/mpv/archive/refs/tags/v0.41.0.tar.gz"
@@ -172,23 +187,25 @@ MANIFEST="flatpak/tv.twitch4steamdeck.App.yml"
MPV_ARCHIVE="/tmp/mpv-0.41.0.tar.gz"
SL_ARCHIVE="/tmp/streamlink-6.11.0.tar.gz"
echo "Lade mpv 0.41.0 ..."
echo "Downloading mpv 0.41.0 ..."
curl -L --progress-bar -o "$MPV_ARCHIVE" "$MPV_URL"
MPV_SHA=$(sha256sum "$MPV_ARCHIVE" | awk '{print $1}')
echo " mpv sha256: $MPV_SHA"
echo "Lade streamlink 6.11.0 ..."
echo "Downloading streamlink 6.11.0 ..."
curl -L --progress-bar -o "$SL_ARCHIVE" "$SL_URL"
SL_SHA=$(sha256sum "$SL_ARCHIVE" | awk '{print $1}')
echo " streamlink sha256: $SL_SHA"
# Platzhalter im Manifest ersetzen
# Replace placeholders in the manifest
sed -i "s/FILL_IN_sha256sum_of_mpv_0\.41\.0_tarball/$MPV_SHA/" "$MANIFEST"
sed -i "s/FILL_IN_sha256sum_of_streamlink_tarball/$SL_SHA/" "$MANIFEST"
echo " ✓ Manifest aktualisiert"
echo " ✓ Manifest updated"
# ─────────────────────────────────────────────────────────────────────────────
# Schritt 6: flatpak-builder — Build + lokale Installation
# Schritt 7: flatpak-builder — Build + lokale Installation
# Step 7: flatpak-builder - build + local install
# ─────────────────────────────────────────────────────────────────────────────
echo ""
echo "=== [7/7] flatpak-builder ==="
@@ -202,16 +219,16 @@ flatpak-builder \
echo ""
echo "======================================================"
echo " Build abgeschlossen!"
echo " Starten: flatpak run tv.twitch4steamdeck.App"
echo " Build completed!"
echo " Run: flatpak run tv.twitch4steamdeck.App"
echo ""
echo " Für Steam Deck (Bundle erstellen):"
echo " For Steam Deck (create bundle):"
echo " flatpak build-bundle ~/.local/share/flatpak/repo \\"
echo " twitch4steamdeck.flatpak tv.twitch4steamdeck.App"
echo " # Dann twitch4steamdeck.flatpak per USB/SSH auf Deck kopieren"
echo " # Dort: flatpak install --user twitch4steamdeck.flatpak"
echo " # Then copy twitch4steamdeck.flatpak to the Deck via USB/SSH"
echo " # There: flatpak install --user twitch4steamdeck.flatpak"
echo "======================================================"
echo "=== flatpak build-bundle ==="
flatpak build-bundle ~/.local/share/flatpak/repo twitch4steamdeck.flatpak tv.twitch4steamdeck.App
echo "=== Übertrage auf Steamdeck ==="
scp twitch4steamdeck.flatpak steamdeck:/home/deck/
echo "=== Copying bundle to Steam Deck ==="
scp twitch4steamdeck.flatpak steamdeck:/home/deck/
+1 -1
View File
@@ -1,6 +1,6 @@
[Desktop Entry]
Name=Twitch4SteamDeck
Comment=Werbefreier Twitch-Client für das Steam Deck
Comment=Twitch client for Steam Deck
Exec=twitch4steamdeck
Icon=tv.twitch4steamdeck.App
Type=Application
+31
View File
@@ -3,14 +3,19 @@ runtime: org.freedesktop.Platform
runtime-version: '24.08'
sdk: org.freedesktop.Sdk
# Stellt Chrome-Runtime-Bibliotheken (GTK, GLib, etc.) + zypak-wrapper bereit.
# Provides Chrome runtime libraries (GTK, GLib, etc.) + zypak-wrapper.
# Das Electron-Binary selbst kommt aus node_modules/electron/dist/electron (npm install in WSL2).
# The Electron binary itself comes from node_modules/electron/dist/electron (npm install in WSL2).
base: org.electronjs.Electron2.BaseApp
base-version: '24.08'
command: twitch4steamdeck
# ffmpeg-full: Stellt den vollen FFmpeg-Codec-Stack bereit (h264, h264_vaapi, etc.).
# ffmpeg-full: Provides the full FFmpeg codec stack (h264, h264_vaapi, etc.).
# Das freedesktop SDK 24.08 liefert nur ein reduziertes FFmpeg ohne patentbehaftete Codecs —
# The freedesktop SDK 24.08 only ships a reduced FFmpeg without patent-encumbered codecs.
# Electron/Chromium braucht h264 für hls.js (MediaSource Extensions).
# Electron/Chromium needs h264 for hls.js (MediaSource Extensions).
add-extensions:
org.freedesktop.Platform.ffmpeg-full:
directory: lib/ffmpeg
@@ -28,29 +33,42 @@ finish-args:
- --device=all # GPU + /dev/input/* (Gamepad API braucht Input-Devices)
- --talk-name=org.freedesktop.Notifications
# Electron userData liegt automatisch in ~/.var/app/tv.twitch4steamdeck.App/config/
# Electron userData is automatically stored in ~/.var/app/tv.twitch4steamdeck.App/config/
# Kein extra --filesystem nötig.
# No extra --filesystem permission is required.
# Build-Voraussetzung (WSL2, VOR flatpak-builder):
# Build prerequisite (WSL2, BEFORE flatpak-builder):
# cd /mnt/c/Projekte/twitch4steamdeck
# npm install # installiert Electron 33 für Linux + alle Deps
# npm install # installs Electron 33 for Linux + all dependencies
# npx @electron/rebuild # rebuildet better-sqlite3 für Linux x64
# npx @electron/rebuild # rebuilds better-sqlite3 for Linux x64
# npm run build # kompiliert TS → out/
# npm run build # compiles TS -> out/
# Das Projektverzeichnis (inkl. out/ und node_modules/) wird als type:dir Source
# The project directory (including out/ and node_modules/) is copied into the manifest build step
# in den Manifest-Build-Schritt kopiert.
# as a type:dir source.
modules:
# ─────────────────────────────────────────────────────────────────────────────
# 1) streamlink (Python) — liefert HLS-URLs aus Twitch-Streams
# 1) streamlink (Python) — provides HLS URLs from Twitch streams
# Wird von build-flatpak.sh via flatpak-pip-generator generiert:
# Generated by build-flatpak.sh via flatpak-pip-generator:
# python3 -m flatpak_pip_generator streamlink==6.11.0 \
# --output flatpak/python3-streamlink
# Das erzeugt flatpak/python3-streamlink.json mit allen Deps + sha256-Hashes.
# This generates flatpak/python3-streamlink.json with all dependencies + sha256 hashes.
# flatpak-builder lädt alle Sources offline herunter und installiert sie sauber.
# flatpak-builder downloads all sources offline and installs them cleanly.
# ─────────────────────────────────────────────────────────────────────────────
- !include python3-streamlink.json
# ─────────────────────────────────────────────────────────────────────────────
# 1b) Mountpoint fuer ffmpeg-full Extension (muss vor App-Modul existieren)
# 1b) Mountpoint for the ffmpeg-full extension (must exist before the app module)
# ─────────────────────────────────────────────────────────────────────────────
- name: ffmpeg-full-mountpoint
buildsystem: simple
@@ -59,28 +77,38 @@ modules:
# ─────────────────────────────────────────────────────────────────────────────
# 2) Haupt-App
# 2) Main app
# Voraussetzung: npm install + @electron/rebuild + npm run build wurden
# Prerequisite: npm install + @electron/rebuild + npm run build were run
# AUSSERHALB (in WSL2) ausgeführt. Dieses Modul kopiert nur die Artefakte.
# OUTSIDE the Flatpak build (in WSL2). This module only copies the artifacts.
# ─────────────────────────────────────────────────────────────────────────────
- name: twitch4steamdeck
buildsystem: simple
build-commands:
# App-Artefakte installieren
# Install app artifacts
- mkdir -p /app/lib/twitch4steamdeck
- cp -r out /app/lib/twitch4steamdeck/out
# node_modules wird für better-sqlite3 (native .node-Datei) zur Laufzeit benötigt.
# node_modules is needed at runtime for better-sqlite3 (native .node file).
# Nur die notwendigen Teile kopieren, um die Paketgröße zu begrenzen.
# Copy only the required parts to keep package size down.
- mkdir -p /app/lib/twitch4steamdeck/node_modules
- cp -r node_modules/better-sqlite3 /app/lib/twitch4steamdeck/node_modules/
- cp -r node_modules/bindings /app/lib/twitch4steamdeck/node_modules/
- cp -r node_modules/file-uri-to-path /app/lib/twitch4steamdeck/node_modules/
# Electron-Binary (Linux, via npm install in WSL2)
# Electron binary (Linux, via npm install in WSL2)
- cp -r node_modules/electron /app/lib/twitch4steamdeck/node_modules/
# package.json für node require-Resolution
# package.json for Node require resolution
- cp package.json /app/lib/twitch4steamdeck/
# Launcher-Skript
# Launcher script
- install -Dm755 flatpak/twitch4steamdeck.sh /app/bin/twitch4steamdeck
# Icon (512×512 PNG, aus SVG konvertiert oder direkt abgelegt)
# Icon (512x512 PNG, converted from SVG or provided directly)
- |
if [ -f resources/icons/icon.png ]; then
install -Dm644 resources/icons/icon.png \
@@ -92,9 +120,11 @@ modules:
/app/share/icons/hicolor/512x512/apps/tv.twitch4steamdeck.App.png
fi
# .desktop-Eintrag
# .desktop entry
- install -Dm644 flatpak/tv.twitch4steamdeck.App.desktop \
/app/share/applications/tv.twitch4steamdeck.App.desktop
# WSL/Windows-Checkouts können 0777 an viele Dateien vererben; OSTree lehnt das ab.
# WSL/Windows checkouts can inherit 0777 on many files; OSTree rejects that.
- find /app -type d -exec chmod 755 {} +
- find /app -type f -exec chmod 644 {} +
- find /app/bin -type f -exec chmod 755 {} +
@@ -113,5 +143,6 @@ modules:
fi
sources:
# Gesamtes Projektverzeichnis (inkl. aus/ + node_modules/ aus WSL2-Prebuild)
# Full project directory (including out/ + node_modules/ from the WSL2 prebuild)
- type: dir
path: ..
+3
View File
@@ -1,7 +1,10 @@
#!/bin/bash
# Launcher für Twitch4SteamDeck im Flatpak.
# Launcher for Twitch4SteamDeck inside Flatpak.
# zypak-wrapper ersetzt den Chrome-Sandbox-Helper (setuid) durch eine
# zypak-wrapper replaces the Chrome sandbox helper (setuid) with a
# Flatpak-kompatible Lösung — Pflicht für Electron in Flatpak-Sandboxes.
# Flatpak-compatible solution - required for Electron in Flatpak sandboxes.
exec zypak-wrapper \
/app/lib/twitch4steamdeck/node_modules/electron/dist/electron \
/app/lib/twitch4steamdeck/out/main/index.js \