Owner answers to the E11 S5 raises (2026-09-13): 1 → A, 2 → "Feed" in every language, 3 → translate the
proxy label and fix every config key missing in BOTH languages ("maintenance", "tmdb" — old bugs).
Focus across a view change (1-A). Opening a Plex title from Home's rail, a channel from the Channels
table or a title from a Plex grid switches the page or the sub-view, which unmounts the list; Back used
to hand focus to <body>, so the next `j` started over at the top. The YouTube player (an overlay)
already restored onto the card.
- `lib/listNav`: `navPosition()` (list's place in reading order, the page's list count, item index)
and `restoreNavPosition()`: focuses the item once the page has as many lists on screen as when it was
left, polls on a timer (a hidden tab runs no animation frames), gives up after 2 s or at once when
something already holds focus, focuses without scrolling (the scroll restore owns the position).
- `lib/history`: `rememberNavPosition()` stamps `sfNav` onto the entry being left and returns the state
without it (a new entry must not inherit it); one popstate listener restores and spends the stamp,
so a later landing on the same entry (an overlay closing over it) cannot pull focus to an old item.
- Called before every view push: `setPage`, `openChannel`, `enterYtSearch`, `useHistorySubview.open`,
the Channels tab push. `navPosition.wiring.contract.test` fails on any `history.pushState(` without
it (the overlay stack's own push is the one exemption).
"Feed" (2). The module is "Feed" in both languages: every "hírfolyam" in the Hungarian UI (≈45 strings,
suffixed: Feedből, Feeded, Feedben…) and the prose "feed" in English that means the module ("your
Feed", "Hide from Feed"); "RSS feed" keeps its meaning. The welcome email says it too.
Backend ids without a name (3). The Configuration page showed `maintenance`, `tmdb`,
`maintenance_revalidate_batch`, `download_upload_max_bytes`, `audit_retention_days`, `plex_overlay_map`,
`tmdb_api_key` and `tmdb_language` as raw identifiers — the lookup falls back to the id, and the i18n
parity test stayed green because both languages missed the same keys. Added labels + hints (EN/HU),
the two groups (and their tab order), the missing `scheduler.jobDesc.demo_reset`, removed the stale
`plex_sync_interval_min` field, and "YouTube API kimenő proxy". `i18n/backendIds.contract.test` reads
`sysconfig.SPECS`, `scheduler.JOB_INTERVALS` and the audit/quota action enums from the backend sources
and fails on an id without its name in either language, or a name left for an id the backend dropped.
159 lines
8.1 KiB
JSON
159 lines
8.1 KiB
JSON
{
|
||
"actionsLabel": "Catalog actions",
|
||
"syncSubscriptions": "Read subscriptions from YouTube",
|
||
"syncSubscriptionsHint": "Re-import your subscription list from YouTube — adds channels you've newly followed and drops ones you've unfollowed. The videos themselves keep syncing automatically in the background; this does not re-fetch them.",
|
||
"backfillEverything": "Backfill everything",
|
||
"backfillEverythingHint": "Request full back-catalog backfill for every channel you're subscribed to. Older videos and search become complete as the shared daily quota allows — this can take a while.",
|
||
"tabs": {
|
||
"subscribed": "Subscriptions",
|
||
"discovery": "Discover from playlists",
|
||
"hidden": "Hidden",
|
||
"blocked": "Blocked"
|
||
},
|
||
"layoutLabel": "Layout",
|
||
"layout": {
|
||
"table": "Table",
|
||
"cards": "Cards"
|
||
},
|
||
"sort": {
|
||
"label": "Sort",
|
||
"default": "Default order",
|
||
"asc": "Ascending",
|
||
"desc": "Descending"
|
||
},
|
||
"cardsPerPage": "Cards per page",
|
||
"discovery": {
|
||
"intro": "Channels that appear in your playlists but that you don't subscribe to. Subscribe to follow them — their new uploads will start showing in your Feed (subscribing costs a little YouTube quota; existing videos aren't re-fetched).",
|
||
"loading": "Finding channels…",
|
||
"empty": "No new channels — every channel in your playlists is one you already follow.",
|
||
"subscribe": "Subscribe",
|
||
"subscribeHint": "Subscribe to this channel on YouTube (changes your real account; uses a little API quota). Its videos arrive on the next background sync.",
|
||
"needWriteHint": "Enable playlist editing in Settings to subscribe on YouTube.",
|
||
"subscribedTitle": "Subscribed on YouTube",
|
||
"subscribedBody": "You're now following {{name}} — its new uploads will start arriving in your Feed.",
|
||
"subscribeFailed": "Subscribe failed",
|
||
"confirmSubscribe": "Subscribe to \"{{name}}\" on YouTube? This changes your real YouTube account and spends a little API quota.",
|
||
"cols": {
|
||
"totalVideos": "Videos",
|
||
"inPlaylists": "In playlists",
|
||
"inPlaylistsHint": "{{videos}} video(s) from this channel across {{playlists}} of your playlist(s)."
|
||
}
|
||
},
|
||
"filters": {
|
||
"syncLabel": "Sync status",
|
||
"all": "All",
|
||
"needsFull": "Needs full history",
|
||
"fullySynced": "Fully synced"
|
||
},
|
||
"tags": {
|
||
"label": "Tags",
|
||
"add": "Tag",
|
||
"yourTagsHint": "Your personal labels. Attach them to channels below, then filter the Feed by tag from the sidebar. (Separate from the automatic language/topic tags.)",
|
||
"noneYet": "No tags yet — create one below.",
|
||
"create": "Create tag",
|
||
"createPlaceholder": "New tag…",
|
||
"createFailed": "Could not create the tag.",
|
||
"updateFailed": "Could not update the tag.",
|
||
"noTag": "No tag",
|
||
"moreCount_one": "{{count}} more tag",
|
||
"moreCount_other": "{{count}} more tags",
|
||
"suggestedHint": "Suggested from your tagging pattern ({{pct}}% match) — click to add",
|
||
"acceptSuggestion": "Add suggested tag {{name}}",
|
||
"dismissSuggestion": "Dismiss suggestion",
|
||
"suggestionsHint": "Tags suggested for your untagged channels, learned from how you've tagged similar ones. Click a ghost chip to add it, or × to dismiss.",
|
||
"suggestionsCount_one": "{{count}} suggestion",
|
||
"suggestionsCount_other": "{{count}} suggestions",
|
||
"acceptAllHigh_one": "Accept {{count}} confident",
|
||
"acceptAllHigh_other": "Accept {{count}} confident",
|
||
"acceptAllTitle": "Accept suggested tags",
|
||
"acceptAllConfirm_one": "Add the {{count}} high-confidence suggested tag to its channel?",
|
||
"acceptAllConfirm_other": "Add the {{count}} high-confidence suggested tags to their channels?",
|
||
"acceptAllConfirmCta": "Accept all"
|
||
},
|
||
"loading": "Loading channels…",
|
||
"empty": "No channels.",
|
||
"pager": {
|
||
"prev": "Previous",
|
||
"next": "Next",
|
||
"page": "Page {{page}} of {{total}}"
|
||
},
|
||
"cols": {
|
||
"priority": "Prio",
|
||
"channel": "Channel",
|
||
"about": "About",
|
||
"stored": "Stored",
|
||
"subs": "Subscribers",
|
||
"lastUpload": "Last upload",
|
||
"length": "Length",
|
||
"tags": "Tags",
|
||
"actions": "Actions"
|
||
},
|
||
"stats": {
|
||
"label": "Stats",
|
||
"channels": "Channels",
|
||
"channelsHint": "Channels you're subscribed to.",
|
||
"recentSynced": "Recent synced",
|
||
"recentSyncedHint": "Channels whose recent uploads are in the local DB and show in your Feed.",
|
||
"fullHistory": "Full history",
|
||
"fullHistoryHint": "Channels whose entire back-catalog is fetched, out of the ones you've requested full history for.",
|
||
"left": "left",
|
||
"leftHint": "Rough estimate to finish full-history backfill of {{count}} pending channel(s), based on the shared daily quota.",
|
||
"myVideos": "My videos",
|
||
"myVideosHint": "Total videos available across your channels.",
|
||
"quotaLeft": "Quota left",
|
||
"quotaLeftHint": "Shared YouTube API budget left today (resets midnight US Pacific)."
|
||
},
|
||
"row": {
|
||
"openOnYouTube": "Open on YouTube",
|
||
"editTags": "Edit tags",
|
||
"filterFeedByTag": "Filter the Feed by “{{name}}”",
|
||
"priorityHint": "Your ranking for this channel. Sort the Feed by “Channel priority” to bring higher-priority channels to the top.",
|
||
"raisePriority": "Raise priority",
|
||
"lowerPriority": "Lower priority",
|
||
"editPriority": "Click to type a priority (negatives allowed)",
|
||
"fullHint": "Full history fetched.",
|
||
"fullySynced": "fully synced",
|
||
"fullySyncedHint": "Recent uploads and the full back-catalog are both in.",
|
||
"backfillThis": "Backfill this channel",
|
||
"backfillThisHint": "Fetch this channel's full back-catalog (older videos + complete search). Click again to cancel the request.",
|
||
"resetBackfill": "Reset & re-fetch this channel",
|
||
"resetHint": "Admin: re-fetch this channel from scratch (recent + full back-catalog), regardless of its current sync state.",
|
||
"queuedRequestedHint": "Full history requested — this channel's whole back-catalog will backfill as the shared quota allows. Click to cancel your request.",
|
||
"queuedByOtherHint": "Another subscriber already requested this channel's full history, so its whole back-catalog is on its way to everyone — nothing to do here.",
|
||
"hiddenHint": "Hidden — this channel's videos are kept out of your Feed. Click to show them again.",
|
||
"hideHint": "Hide this channel's videos from your Feed. It stays subscribed; this doesn't unsubscribe on YouTube.",
|
||
"unhide": "Unhide",
|
||
"hideFromFeed": "Hide from Feed",
|
||
"unsubscribeHint": "Unsubscribe from this channel on YouTube (changes your real account). Read-only mode hides this — use Hide instead.",
|
||
"unsubscribeOnYoutube": "Unsubscribe on YouTube",
|
||
"thisChannel": "This channel"
|
||
},
|
||
"notify": {
|
||
"synced": "Synced {{count}} subscriptions",
|
||
"syncFailed": "Subscription sync failed",
|
||
"unsubscribed": "Unsubscribed from {{name}} on YouTube",
|
||
"unsubscribeFailed": "Unsubscribe failed",
|
||
"fullHistoryRequested": "Full history requested for {{count}} channels",
|
||
"fullHistoryFailed": "Couldn't request full history",
|
||
"needYouTube": "Connect your YouTube account to do this.",
|
||
"connect": "Connect",
|
||
"filteredByTag": "Feed filtered by tag: {{name}}",
|
||
"resetDone": "{{name}} reset — re-fetching now",
|
||
"resetFailed": "Couldn't reset this channel"
|
||
},
|
||
"confirmUnsubscribe": "Unsubscribe from \"{{name}}\" on YouTube? This changes your real YouTube account. To just remove it from your Feed, hide it instead.",
|
||
"confirmReset": "Re-fetch \"{{name}}\" from scratch? This re-runs its backfill (recent + full history) and spends some API quota.",
|
||
"searchPlaceholder": "Search channels…",
|
||
"blocked": {
|
||
"title": "Blocked channels",
|
||
"hint": "Their videos are hidden from your Feed, Library, and live search.",
|
||
"empty": "No blocked channels. Block one from its channel page to hide all its videos without unsubscribing."
|
||
},
|
||
"hidden": {
|
||
"title": "Hidden channels",
|
||
"hint": "Their videos are kept out of your personal Feed, but still appear in the shared Library.",
|
||
"empty": "No hidden channels. Hide a subscription (the eye icon on its row) to keep its uploads out of your personal Feed without unsubscribing.",
|
||
"unhide": "Unhide"
|
||
}
|
||
}
|