Fall back to English instead of showing raw keys

Every namespace the fork added -- main_tabs, feed, cards, watch, browse,
search, player, and now account -- exists only in en.json, because the thirteen
translated language files predate them. get_text() consults the embedded
fallback dict and then gives up and returns the key, so a non-English UI read
"main_tabs.watch" on its own tabs. This round made that worse by adding more
English-only keys.

The fallback dict now carries those namespaces verbatim from en.json. It does
not translate anything -- a German UI shows English for these strings -- but
nothing shows a dotted key, and keys added later degrade the same way instead
of breaking. Translations that do exist still win: buttons.download is still
"Herunterladen" in German.

Verified across all fourteen language files: no key in the fork's namespaces
resolves to itself in any of them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-09 01:22:08 +02:00
parent 9c4749e49b
commit aff1b03b16
2 changed files with 140 additions and 3 deletions
+7
View File
@@ -88,6 +88,13 @@ records.
### Fixed ### Fixed
- **A non-English interface no longer shows raw keys.** Every string SageTube
added — the tab names, the feed, cards, watch, browse, search, player and
account text — exists only in `en.json`, because the thirteen translated files
predate the fork. `get_text` returned the key itself, so the tabs literally
read `main_tabs.watch`. Those namespaces are now in the embedded English
fallback, so a missing translation reads as English rather than as a dotted
key. Translating the language files remains a separate job.
- The error log filled with hundreds of `after creating texture: OpenGL error - The error log filled with hundreds of `after creating texture: OpenGL error
INVALID_ENUM` lines per session. They come from the GL driver, playback INVALID_ENUM` lines per session. They come from the GL driver, playback
continues regardless, and they buried the errors that do matter, so they are continues regardless, and they buried the errors that do matter, so they are
+133 -3
View File
@@ -78,9 +78,139 @@ class LocalizationManager:
"check_app_updates": "Check for SageTube updates on startup", "check_app_updates": "Check for SageTube updates on startup",
"check_beta_updates": "Receive Beta Updates" "check_beta_updates": "Receive Beta Updates"
}, },
# Only the keys added by SageTube live here; the rest of update_dialog # --- SageTube's own strings -------------------------------------
# is in every language file already. Without this a non-English UI # These namespaces exist only in en.json: the fork added them and the
# would show the raw key for the buttons below. # thirteen translated files predate them. get_text() falls back to this
# dict before giving up and returning the key itself, so without these
# a non-English UI literally reads "main_tabs.watch" on its tabs.
# Keep in step with en.json when adding keys; translating the language
# files is the separate, larger job.
"main_tabs": {
"watch": "Watch",
"search": "Search",
"feed": "Feed",
"browse": "Browse",
"downloads": "Downloads"
},
"search": {
"placeholder": "Search YouTube...",
"button": "Search",
"searching": "Searching...",
"results_count": "{count} results",
"failed": "Search failed: {error}",
"button_tooltip": "Search YouTube"
},
"browse": {
"placeholder": "Paste a channel or playlist URL...",
"open": "Open",
"subscribe": "Subscribe",
"unsubscribe": "Unsubscribe",
"play_all": "Play all",
"download_playlist": "Download",
"tab_videos": "Videos",
"tab_shorts": "Shorts",
"tab_live": "Live",
"loading": "Loading...",
"entry_count": "{count} videos",
"failed": "Failed to load: {error}",
"hint": "Open a channel (youtube.com/@name) or playlist URL, or navigate here from Search.",
"open_tooltip": "Open this channel or playlist",
"subscribe_tooltip": "Follow this channel so its uploads appear in your Feed",
"unsubscribe_tooltip": "Stop following this channel",
"play_all_tooltip": "Queue everything loaded here",
"download_playlist_tooltip": "Open this playlist in Downloads",
"queued_loaded": "Queued {count} loaded videos — press Load more first to queue the rest"
},
"feed": {
"mode_local": "Local subscriptions",
"mode_account": "YouTube account (cookies)",
"refresh": "Refresh",
"subscriptions": "Subscriptions",
"no_subscriptions": "No subscriptions yet - subscribe from a channel page in Browse",
"refreshing": "Refreshing... {done}/{total}",
"refreshed": "{count} videos in feed",
"channel_failed": "A channel failed to refresh: {error}",
"fetching_account": "Fetching your subscription feed...",
"account_failed": "Account feed failed (are cookies valid?): {error}",
"subscribed": "Subscribed to {title}",
"unsubscribed": "Unsubscribed from {title}",
"open_channel": "Open channel",
"refresh_tooltip": "Fetch the latest uploads from every subscribed channel",
"mode_tooltip": "Where the feed comes from: your local subscriptions, or your signed-in YouTube account",
"refreshed_with_failures": "{count} videos — {failed} channel(s) could not be reached",
"account_needs_refresh": "Press Refresh to load your account feed",
"empty_no_subscriptions": "No subscriptions yet.\n\nFind channels in Search or Browse, then use Subscribe to follow them — their new uploads will appear here.",
"empty_not_refreshed": "Nothing here yet.\n\nPress Refresh to fetch the latest uploads from your subscriptions.",
"sign_in": "Sign in with cookies…",
"sign_in_tooltip": "Use your YouTube account via browser cookies, which enables the account feed",
"account_requires_cookies": "Requires signing in with cookies"
},
"cards": {
"play": "▶ Play",
"queue": "+ Queue",
"download": "",
"load_more": "Load more",
"empty": "Nothing here yet",
"play_tooltip": "Play this video now",
"queue_tooltip": "Add to the play queue",
"download_tooltip": "Open in Downloads with this video ready to analyse",
"load_more_tooltip": "Load the next page of results"
},
"watch": {
"clear_queue": "Clear queue"
},
"player": {
"quality_auto": "Auto",
"subtitles": "CC",
"unavailable": "Video player unavailable",
"now_playing": "Now Playing",
"queue": "Queue",
"play": "Play",
"pause": "Pause",
"stream_stalled": "Stream failed to start after several attempts - YouTube may be throttling. Try again or pick a lower quality.",
"play_pause": "Play / pause (Space)",
"fullscreen": "Fullscreen (F)",
"seek_tooltip": "Seek through the video",
"quality_tooltip": "Maximum playback resolution",
"speed_tooltip": "Playback speed",
"volume_tooltip": "Volume",
"subtitles_tooltip": "Toggle subtitles (C)",
"previous": "Previous in queue (P)",
"next": "Next in queue (N)",
"buffering": "Buffering…",
"act_play_pause": "Play / pause",
"act_seek_back_5": "Back 5 seconds",
"act_seek_fwd_5": "Forward 5 seconds",
"act_seek_back_10": "Back 10 seconds",
"act_seek_fwd_10": "Forward 10 seconds",
"act_seek_back_1": "Back 1 second",
"act_seek_fwd_1": "Forward 1 second",
"act_frame_back": "Previous frame",
"act_frame_fwd": "Next frame",
"act_vol_up": "Volume up",
"act_vol_down": "Volume down",
"act_mute": "Mute",
"act_unmute": "Unmute",
"act_speed_up": "Speed up",
"act_speed_down": "Slow down",
"act_speed_reset": "Normal speed",
"act_subtitles": "Subtitles on / off",
"act_fullscreen": "Fullscreen",
"act_leave_fullscreen": "Leave fullscreen",
"act_next": "Next in queue",
"act_previous": "Previous",
"act_start": "Back to start",
"act_end": "Jump to end",
"act_copy_url": "Copy video link",
"act_open_browser": "Open in browser"
},
"account": {
"signed_out": "Not signed in",
"signed_out_tooltip": "SageTube is not using a YouTube account. Sign in with browser cookies to use your subscription feed and reach age-restricted or members-only videos.",
"signed_in": "Account: {source}",
"signed_in_tooltip": "Using cookies from {source}. Click to change or clear them.",
"source_file": "cookie file"
},
"update_dialog": { "update_dialog": {
"skip_version": "Skip This Version", "skip_version": "Skip This Version",
"skip_version_tooltip": "Never offer {version} again. Later versions will still be shown.", "skip_version_tooltip": "Never offer {version} again. Later versions will still be shown.",