Files
Psychotoxical-psysonic/src/locales/ru/settings.ts
T
Psychotoxical f9df918c72 feat(themes): community Theme Store + semantic-token refactor (#1009)
* feat(themes): add semantic tokens for the theme-store contract (B0 P1)

Additive: define --highlight, --accent-2, --bg-deep, --bg-elevated and
--text-on-accent on the :root base as --ctp-* mappings. They resolve
per-theme automatically and nothing consumes them yet (zero behaviour
change) — groundwork for replacing direct --ctp-* use in components.

* refactor(themes): components consume semantic tokens, not --ctp-* (B0 P2)

Replace every direct --ctp-* reference in component/layout/track CSS and
TSX inline styles with the readable semantic token (--bg-app, --accent,
--highlight, --text-on-accent, …). --ctp-* now survives only as the
Catppuccin palette layer the base maps from, and as the deliberate
categorical rainbow in Composers/Genres/artistsHelpers (left untouched).

This is the readable contract surface for the community theme store.
Divergences (theme set a semantic var != its --ctp- source) are
corrections — the element now uses the theme's real semantic colour.

* feat(themes): add player-bar title/artist color tokens

New optional --player-title / --player-artist, defaulting to --text-primary / --text-secondary so nothing changes unless a theme overrides them. Lets a theme give the now-playing readout its own colour as a plain token.

* refactor(themes): token-only theme library (flatten, whitelist, one file per theme)

Turn every built-in theme into a single self-contained [data-theme] var block of semantic whitelist tokens (plus the internal --ctp-* palette layer):

- Flatten all themes: drop structural override rules, @keyframes, and global-token overrides (radius / shadow-elevation / transition / spacing / font / focus-ring). Signature player-bar readout colours are preserved via the new --player-title / --player-artist tokens.

- Normalize the var blocks to the semantic whitelist: drop the alternate token vocabulary (nav-active / scrollbar / bg-input / success / border-default / ...); rename --success -> --positive and --border-default -> --border where no whitelist equivalent was set. Migrate the few components that read those tokens to the whitelist equivalents.

- Split multi-theme files so each theme ships as its own file, making the built-in set 1:1 with the per-theme store packaging.

Kept as-is (built-in, not flattened): the two colour-blind-safe accessibility themes, plus the two curated core skins.

* chore(themes): remove seven themes retired after the token refactor

These themes leaned on heavy structural overrides and were dropped rather than flattened. Full removal each: the CSS file(s), the index.css import, the Theme type union, and the ThemePicker entry.

* feat(themes): granular tokens — track lists

Wire track rows to per-region tokens: row hover (--row-hover), the now-playing
row + indicator (--row-playing-bg / --row-playing-text), track title/artist/
number/duration text, column-header text, row dividers, and the resize-handle
active colour. Covers the desktop tracklist, the shared song-row (Tracks hub /
search), and the mobile tracklist. Drop a baked border fallback. Visual no-op.

* feat(themes): granular tokens — cards

Wire album and artist cards to per-region tokens (--card-hover-border,
--card-title, --card-subtitle, --card-placeholder-bg). Visual no-op.

* fix(themes): drop undefined/baked colour aliases

Replace the undefined --bg-surface (resolved to nothing — broken placeholder
backgrounds and filter input) with --card-placeholder-bg / --input-bg, and the
baked-hex aliases --color-error / --color-warning with --danger / --warning so
themes can actually recolour them.

* feat(themes): Spectrum demo theme + trim unused cascade tokens

Add a loud built-in demo theme that gives each region its own hue (sidebar
green, player pink, lists cyan, cards gold, menus red, controls blue) so the
per-region granularity is obvious when you switch to it. Drop two unused
cascade tokens (--sidebar-text-active, --row-active-bg) and the unused
on-media block (those media surfaces stay static by design).

* style(themes): make Spectrum demo brutally loud

Full-saturation neon per region (toxic green sidebar, magenta player, cyan
lists, acid-yellow cards, blood-red menus, electric-blue controls, purple
scrollbar) so the per-region separation is unmistakable. The earlier soft
tints were too subtle to read.

* feat(themes): name the granular demo theme Braindead

* feat(themes): granular per-region tokens — cascade layer + sidebar

Add an optional per-region token layer (semantic-cascade.css) so a theme can
recolour individual regions — sidebar hover, player controls, list rows,
menus, inputs, on-media surfaces — independently of the global tokens. Every
token defaults to its base token (or a media-safe literal), so this is a
visual no-op until a theme overrides one; it only adds control points.

Wire the sidebar region as the first consumer and drop the baked grey
fallbacks (--bg-tertiary, etc.) that no theme could reach.

* feat(themes): granular tokens — controls, menus, scrollbar

Wire inputs, buttons, sliders, the custom-select, context menus, submenus and
modals to per-region tokens, and tokenise the scrollbar. Complete B0 by
dropping the last direct --ctp-* references in the input/button/progress/
scrollbar utility CSS.

Fix three undefined-token bugs that fell back to nothing (so no theme could
reach them): --surface-2 (context-menu hover had no highlight), --bg-surface
(submenu create-input had no background), and the baked grey fallbacks in the
custom-select. Every other new token defaults to today's value — a visual
no-op that only adds override points.

* feat(themes): granular tokens — player bar

Wire the desktop player bar's transport controls, time toggle, and overflow
menu to per-region tokens (--player-control, --player-time-toggle-*, etc.).
Fix the undefined --surface-hover/--surface-active grey fallbacks on the time
toggle. Visual no-op; defaults match today's values.

* chore(themes): remove empty theme stub files

Six theme CSS files were reduced to comment-only stubs by the flatten
sweep but their files and @import lines remained. Five are empty
structural companions of now-flattened themes (morpheus, p-dvd,
aero-glass, luna-teal) and two are orphans of cut themes
(order-of-the-phoenix, pandora). Removed the files and their imports.

* feat(themes): runtime injection foundation for the theme store

Plumbing for installed community themes ahead of the in-app store UI,
nothing user-visible yet:

- installedThemesStore: persisted (localStorage) record of installed
  community themes incl. their CSS text, so an active community theme is
  available synchronously at startup (no flash, fully offline).
- themeInjection: reconcile <head> <style data-installed-theme> elements
  with the store; lightweight defense-in-depth sanitize on top of CI.
- themeRegistry: jsDelivr registry client with a 12h localStorage cache
  and stale-on-error fallback.
- App: inject installed themes before applying data-theme, in both webviews.
- themeStore: widen the Theme type to accept dynamic installed ids.

* feat(themes): dedicated Themes settings tab

Move theme selection and the day/night scheduler out of Appearance into
a new dedicated Themes tab — the future home of the community Theme Store.
Appearance keeps grid columns, visual options, UI scale, font and seekbar.

- ThemesTab: theme picker + scheduler (relocated verbatim).
- AppearanceTab: drop the two relocated sections + now-unused imports.
- Register the tab in settingsTabs (Tab union, resolveTab, search index)
  and Settings (tab bar, render, label map).
- i18n: settings.tabThemes in all 9 locales.

* feat(themes): community Theme Store browse + install

Add the Theme Store section to the Themes tab:

- Fetch the jsDelivr registry (12h cache, stale-on-error fallback).
- Search by name/author/description + filter by light/dark + refresh.
- Per-row CDN thumbnail, name, author, description and actions:
  Install / Apply / Update / Uninstall. Installing fetches the CSS,
  persists it (localStorage) and the runtime injection applies it;
  uninstalling the active theme falls back to the matching core.
- Rating slot left reserved (deferred).
- i18n: themeStore* keys in all 9 locales.

* feat(themes): slim bundle to fixed cores + flat Themes tab

Remove the 86 store palettes (incl. braindead) from the app bundle — the
CSS files, their index.css imports, the Theme union and the picker data —
leaving only the six fixed cores (Catppuccin Mocha/Latte, Kanagawa Wave,
Stark HUD, Vision Dark/Navy). Everything else installs from the store.

Themes tab is rebuilt flat (no collapsible accordions):
- "Your Themes": one card grid of the fixed cores + installed community
  themes; click to apply, uninstall on community ones (active theme falls
  back to the matching core). Catppuccin prefix on Mocha/Latte; a CVD-safe
  pill on the colour-blind-safe Vision themes.
- Scheduler day/night options include installed themes.
- Theme Store: alphabetical order, thumbnail lightbox, and a submit hint
  above the search linking to the themes repository.
- Nav order: Servers, Library, Audio, Themes, Appearance, Lyrics, …
- ThemePicker accordion removed; fixed-theme data moved to fixedThemes.ts.
- i18n for all new strings across 9 locales.

* feat(themes): reset removed-from-bundle themes to a bundled fallback

After slimming the bundle to the six fixed core themes, a profile upgraded
from an older build may have an active or scheduler theme that is now
store-only and not installed — it has no [data-theme] block and would render
as unstyled :root. Reset any theme/themeDay/themeNight that is neither bundled
nor installed to a bundled fallback: Mocha for the main + night slots, Latte
for the day slot. Runs synchronously in runPreReactBootstrap, rewriting the
persisted selection in localStorage before React mounts (no flash; Zustand
rehydrates after first paint). No auto-install and no network — the fallback
is always a bundled theme, so it works offline.

* feat(themes): floating back-to-top button on the Themes tab

The Themes tab can get long (theme grid + scheduler + full store list), so
add a floating back-to-top affordance that appears once the page is scrolled
and smooth-scrolls to the top. It is portalled into the route host and
positioned absolute against it — the main scroll viewport sets contain: paint,
which would otherwise make position: fixed resolve against the scrolling box
and drift with the content. Reusable component (scroll viewport id + threshold
props); i18n common.backToTop added in all nine locales.

* feat(themes): accessibility + state polish for the Theme Store

- Reuse the shared CoverLightbox for the thumbnail preview instead of a
  second inline dialog — gains a visible close button and a focus-managed,
  portalled dialog, and drops duplicated markup.
- Theme cards expose aria-pressed so assistive tech announces the selected
  theme, not just the visual check.
- Transient store messages get live-region roles (loading/empty/install
  failure = status, fetch error = alert).
- Thumbnails degrade gracefully when offline/missing (hide the broken-image
  glyph; the thumbnail button no longer stretches with the row, so its
  background can't show as letterbox bars).

* feat(themes): larger store-row thumbnails (120x75 -> 200x125)

The list previews were too small to make a theme out; bump the display size
(same 1.6 aspect). Thumbnails are now served at 720x450, so the larger
display stays crisp.

* fix(themes): bust thumbnail cache on registry change

jsDelivr serves theme thumbnails with a 7-day max-age, so when a thumbnail
is updated the webview keeps showing its cached old image (the path is
unchanged). Append the registry's generatedAt as a cache-busting query to
the thumbnail URLs (list + lightbox); it changes on every themes push, so a
registry refresh makes the webview re-fetch and reflect the current CDN
image instead of a stale one.

* docs(themes): changelog + credits for the Theme Store

Add the 1.48.0 "Themes — community Theme Store" changelog entry (PR #1009)
and the matching line in the Psychotoxical credits.

* fix(themes): address PR review (uninstall hygiene, validation, polish)

Uninstall/scheduler & validation:
- uninstallTheme() repairs every selection slot (active + day + night), not
  just the manual one, and is shared by both uninstall buttons (dedup).
- Validate theme CSS at install time and skip persisting CSS that won't inject
  (no more "installed/active but renders nothing" with no feedback).
- Harden the runtime validator: exactly one rule, scoped exactly to the
  theme's [data-theme='<id>'] selector (no unscoped/foreign selectors), no
  at-rules, url() only data:, no expression()/javascript:, size-capped.

Tokens & polish:
- Fix three dangling undefined tokens (--surface-2 x2, --bg-surface).
- Finish the warning/success token sweep (--warning / --positive, themeable).
- Apply the active theme synchronously before React mounts (no first-frame
  flash) and inject installed themes up front.
- One-time, dismissible notice when the slim-bundle migration reset a theme.
- Update badge uses semver, not string inequality.
- Offline/stale indicator in the store; cross-window theme sync; drop the now
  dead REMOVED_THEME_REMAP and Card.mode field.

Tests: themeInjection (validator + sync), themeRegistry (cache/force/stale/
malformed), uninstallTheme (slot repair), migration notice. i18n in all nine
locales. Full suite green (1755 tests).

* test(bootstrap): cover startup theme apply + cross-window sync

The review fixes added applyThemeAtStartup / installCrossWindowThemeSync to
bootstrap.ts (a hot-path file) without tests, dropping its coverage to 68.3%
and failing the frontend hot-path coverage gate (>=70%). Add unit tests for
both (and the no-op / malformed-storage paths); bootstrap.ts is back to ~98%.
2026-06-07 02:47:33 +02:00

684 lines
60 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
export const settings = {
title: 'Настройки',
language: 'Язык',
languageEn: 'English',
languageDe: 'Deutsch',
languageEs: 'Español',
languageFr: 'Français',
languageNl: 'Nederlands',
languageNb: 'Norsk',
languageRu: 'Русский',
languageZh: '中文',
languageRo: 'Română',
font: 'Шрифт',
fontHintOpenDyslexic: 'Подходит для дислексии · без поддержки китайского',
theme: 'Тема',
appearance: 'Оформление',
servers: 'Серверы',
serverName: 'Название',
serverUrl: 'Адрес',
serverUrlPlaceholder: '192.168.1.100:4533 или https://music.example.com',
serverAlternateUrl: 'Второй адрес (необязательно)',
serverAlternateUrlPlaceholderPublic: 'https://music.example.com',
serverAlternateUrlPlaceholderLocal: '192.168.1.100:4533',
serverAlternateUrlHintAddPublic: 'Добавьте публичный адрес, чтобы подключаться вне домашней сети.',
serverAlternateUrlHintAddLocal: 'Добавьте локальный адрес для более быстрой связи дома.',
serverBothLanError: 'Оба адреса локальные — оставьте один или добавьте публичный.',
dualAddressVerifying: 'Проверяем, что оба адреса указывают на один и тот же сервер…',
dualAddressMismatch: 'Адреса ведут к разным серверам. Проверьте написание и попробуйте снова.',
dualAddressInsufficient: 'Не удалось убедиться, что это один сервер. Удалите один адрес, чтобы продолжить.',
dualAddressUnreachable: 'Не удалось достучаться до {{host}}. Проверьте адрес и сеть, затем попробуйте снова.',
urlRemigrationTitle: 'Переместить данные библиотеки?',
urlRemigrationMessage: 'Смена адреса перенесёт все данные библиотеки, анализа и кэша обложек с {{oldKey}} на {{newKey}}. Это нельзя отменить.',
urlRemigrationConfirm: 'Переместить данные',
urlRemigrationProgress: 'Перемещаем данные библиотеки…',
urlRemigrationFailureInspect: 'Не удалось проверить, что нужно перенести. Попробуйте снова или откройте журнал отладки.',
urlRemigrationFailureRun: 'Не удалось перенести данные библиотеки. Сохранённые данные не изменены — попробуйте снова.',
urlRemigrationFailureCoverRename: 'Данные библиотеки перенесены, но файлы обложек не удалось переименовать. Обложки восстановятся при следующем обращении.',
shareUsesLocalUrl: 'Использовать локальный адрес в ссылках общего доступа',
shareUsesLocalUrlDesc: 'Применяется к приглашениям Orbit и ссылкам на библиотеку. По умолчанию — публичный адрес.',
serverUsername: 'Логин',
serverPassword: 'Пароль',
addServer: 'Добавить сервер',
addServerTitle: 'Новый сервер',
editServer: 'Изменить',
editServerTitle: 'Изменить сервер',
useServer: 'Выбрать',
deleteServer: 'Удалить',
noServers: 'Нет сохранённых серверов.',
serverActive: 'Активен',
confirmDeleteServer: 'Удалить сервер «{{name}}»?',
serverConnecting: 'Подключение…',
serverConnected: 'Подключено!',
serverFailed: 'Ошибка подключения.',
testBtn: 'Проверить',
testingBtn: 'Проверка…',
serverCompatible: 'Разработано для Navidrome. Другие Subsonic-совместимые серверы (Gonic, Airsonic, …) могут работать с ограничениями, так как Psysonic использует много специфичных для Navidrome API-эндпоинтов.',
userMgmtTitle: 'Управление пользователями',
userMgmtDesc: 'Управляйте пользователями этого сервера. Требуются права администратора.',
userMgmtNoAdmin: 'Для управления пользователями на этом сервере нужны права администратора.',
userMgmtLoadError: 'Не удалось загрузить пользователей.',
userMgmtLoadFriendly: 'Сервер не ответил — обычно разовая ошибка.',
userMgmtRetry: 'Повторить',
userMgmtEmpty: 'Пользователи не найдены.',
userMgmtYouBadge: 'Вы',
userMgmtAdminBadge: 'Админ',
userMgmtAddUser: 'Добавить пользователя',
userMgmtAddUserTitle: 'Новый пользователь',
userMgmtEditUserTitle: 'Изменить пользователя',
userMgmtUsername: 'Имя пользователя',
userMgmtName: 'Отображаемое имя',
userMgmtEmail: 'E-mail',
userMgmtPassword: 'Пароль',
userMgmtPasswordEditHint: 'Введите новый пароль, чтобы изменить его.',
userMgmtRoleAdmin: 'Админ',
userMgmtLibraries: 'Библиотеки',
userMgmtLibrariesAdminHint: 'Администраторы автоматически имеют доступ ко всем библиотекам.',
userMgmtLibrariesEmpty: 'На этом сервере нет доступных библиотек.',
userMgmtLibrariesValidation: 'Выберите хотя бы одну библиотеку.',
userMgmtLibrariesUpdateError: 'Пользователь сохранён, но не удалось назначить библиотеки',
userMgmtNoLibraries: 'Библиотеки не назначены',
userMgmtNeverSeen: 'Никогда',
userMgmtSave: 'Сохранить',
userMgmtCancel: 'Отмена',
userMgmtDelete: 'Удалить',
userMgmtEdit: 'Изменить',
userMgmtConfirmDelete: 'Удалить пользователя «{{username}}»? Действие нельзя отменить.',
userMgmtCreateError: 'Не удалось создать пользователя.',
userMgmtUpdateError: 'Не удалось обновить пользователя.',
userMgmtDeleteError: 'Не удалось удалить пользователя.',
userMgmtCreated: 'Пользователь создан.',
userMgmtUpdated: 'Пользователь обновлён.',
userMgmtDeleted: 'Пользователь удалён.',
userMgmtValidationMissing: 'Требуются имя пользователя, отображаемое имя и пароль.',
userMgmtValidationMissingIdentity: 'Укажите имя пользователя и отображаемое имя.',
userMgmtMagicStringGenerate: 'Сгенерировать magic string',
userMgmtSaveAndMagicString: 'Сохранить и получить magic string',
userMgmtMagicStringPasswordNavHint:
'Navidrome сохранит этот пароль для пользователя. Если он не совпадает с текущим, на сервере будет установлен новый пароль входа.',
userMgmtMagicStringPlaintextWarning:
'Передавайте magic string осторожно: в ней пароль в открытом виде (кодирование — не шифрование). У кого есть полная строка, тот может войти под этим пользователем.',
userMgmtMagicStringCopied: 'Magic string скопирован в буфер обмена.',
userMgmtMagicStringCopyFailed: 'Не удалось скопировать в буфер обмена.',
userMgmtMagicStringLoginFailed: 'Пароль не подошёл — не удалось проверить учётные данные.',
userMgmtMagicStringModalTitle: 'Сгенерировать magic string',
userMgmtMagicStringModalDesc: 'Введите пароль Subsonic для «{{username}}» — он попадёт в копируемую magic string.',
userMgmtMagicStringModalConfirm: 'Скопировать строку',
audiomuseTitle: 'AudioMuse-AI (Navidrome)',
audiomuseDesc:
'Включите, если на этом сервере настроен <pluginLink>плагин AudioMuse-AI для Navidrome</pluginLink>. Появится Instant Mix для треков, а на странице исполнителя похожие будут браться с сервера вместо Last.fm.',
audiomuseIssueHint:
'Недавно не удалось собрать Instant Mix — проверьте плагин Navidrome и API AudioMuse. Похожие исполнители подтянутся с Last.fm, если сервер ничего не вернёт.',
connected: 'Подключено',
failed: 'Ошибка',
eqTitle: 'Эквалайзер',
eqEnabled: 'Включить эквалайзер',
eqPreset: 'Пресет',
eqPresetCustom: 'Свой',
eqPresetBuiltin: 'Встроенные',
eqPresetCustomGroup: 'Мои пресеты',
eqSavePreset: 'Сохранить как пресет',
eqPresetName: 'Название пресета…',
eqDeletePreset: 'Удалить пресет',
eqResetBands: 'Сбросить полосы',
eqPreGain: 'Предусиление',
eqResetPreGain: 'Сбросить предусиление',
eqAutoEqTitle: 'AutoEQ — поиск профиля наушников',
eqAutoEqPlaceholder: 'Модель наушников или IEM…',
eqAutoEqSearching: 'Поиск…',
eqAutoEqNoResults: 'Ничего не найдено',
eqAutoEqError: 'Ошибка поиска',
eqAutoEqRateLimit: 'Лимит GitHub — попробуйте через минуту',
eqAutoEqFetchError: 'Не удалось загрузить профиль EQ',
lfmTitle: 'Last.fm',
lfmConnect: 'Подключить Last.fm',
lfmConnecting: 'Ожидание авторизации…',
lfmConfirm: 'Я разрешил доступ',
lfmConnected: 'Аккаунт',
lfmDisconnect: 'Отключить',
lfmConnectDesc:
'Привяжите Last.fm для скробблинга и статуса «Сейчас слушаю» прямо из Psysonic — настраивать Navidrome не нужно.',
lfmOpenBrowser: 'Откроется браузер. Разрешите доступ на Last.fm, затем нажмите кнопку ниже.',
lfmScrobbles: 'Скробблов: {{n}}',
lfmMemberSince: 'С {{year}} года',
scrobbleEnabled: 'Скробблинг включён',
scrobbleDesc: 'Отправлять прослушивания на Last.fm после 50% трека',
behavior: 'Поведение',
cacheTitle: 'Макс. размер кэша',
cacheDesc:
'Кэш обложек и фото исполнителей в хранилище приложения (IndexedDB). При нехватке места старые записи удаляются автоматически.',
cacheUsedImages: 'Изображения:',
cacheUsedOffline: 'Офлайн-треки:',
cacheUsedHot: 'На диске:',
hotCacheTrackCount: 'Треков в кэше:',
cacheMaxLabel: 'Лимит',
imageCacheScopeLabel: 'Область',
imageCacheSubTitle: 'Превью в приложении',
coverDiskCacheSubTitle: 'Обложки на диске',
coverCacheStrategyTitle: 'Кэш обложек',
coverCacheStrategyDesc: 'Для каждого сервера можно выбрать стратегию: Ленивый — загружать обложки по мере необходимости; Агрессивный — то же самое плюс дополнительный фоновый прогрев.',
coverCacheStrategyLabel: 'Стратегия',
coverCacheStrategyServerLabel: 'Сервер',
coverCacheStrategyProgressLabel: 'Кэш',
coverCacheStrategyActionsLabel: 'Действия',
coverCacheStrategyLazy: 'Ленивый',
coverCacheStrategyLazyDesc: 'Загружает обложки только когда они нужны.',
coverCacheStrategyAggressive: 'Агрессивный',
coverCacheStrategyAggressiveDesc: 'Как ленивый, но с дополнительным фоновым прогревом.',
coverCacheStrategyDiskUsage: 'На диске: {{size}}',
coverCacheStrategyProgressValue: '{{percent}}% ({{done}}/{{total}}) · {{size}}',
coverCacheStrategyClearAction: 'Очистить кэш обложек',
coverCacheStrategyClearTitle: 'Очистить кэш обложек?',
coverCacheStrategyClearDesc: 'Удалить все кэшированные обложки для {{server}}. При необходимости скачаются снова.',
coverCacheStrategyClearConfirm: 'Очистить',
coverCacheStrategyClearCancel: 'Отмена',
coverCacheStrategyClearSuccess: 'Кэш обложек для этого сервера очищен.',
coverCacheStrategyClearError: 'Не удалось очистить кэш обложек.',
coverCacheStrategyServerRemoved: 'удалённый сервер',
cacheClearBtn: 'Очистить кэш',
cacheClearWarning: 'Очистит кэш обложек и фото исполнителей в хранилище приложения. При необходимости скачаются снова.',
cacheClearConfirm: 'Очистить кэш изображений',
cacheClearCancel: 'Отмена',
waveformCacheCleared: 'Кэш waveform очищен ({{count}} строк).',
waveformCacheClearFailed: 'Не удалось очистить кэш waveform.',
storageTabTitle: 'Офлайн и кэш',
mediaDirTitle: 'Папка медиа',
mediaDirDesc: 'Корневая папка локального воспроизведения: офлайн-библиотека — library/, буфер очереди — cache/.',
mediaDirDefault: 'По умолчанию (данные приложения)',
mediaDirChange: 'Сменить папку',
mediaDirClear: 'Сбросить по умолчанию',
mediaDirHint: 'Новые загрузки пойдут в выбранную папку. Старые файлы останутся на прежних путях, пока вы их не удалите.',
offlineStorageTitle: 'Офлайн-хранилище',
offlineDirTitle: 'Офлайн-библиотека (в приложении)',
offlineDirDesc: 'Папка для треков, сохранённых для офлайн-прослушивания.',
offlineDirDefault: 'По умолчанию (данные приложения)',
offlineDirChange: 'Сменить папку',
offlineDirClear: 'Сбросить по умолчанию',
offlineDirHint: 'Новые загрузки пойдут в выбранную папку. Старые останутся на прежнем месте.',
hotCacheTitle: 'Горячий кэш воспроизведения',
hotCacheDisclaimer: 'Заранее подгружает следующие треки из очереди и сохраняет предыдущие. При включении использует место на диске и сеть.',
hotCacheDirDefault: 'По умолчанию (данные приложения)',
hotCacheDirChange: 'Сменить папку',
hotCacheDirClear: 'Сбросить по умолчанию',
hotCacheDirHint: 'При смене папки сбрасывается список в приложении; уже скачанные файлы остаются на старом пути, пока вы их не удалите.',
hotCacheEnabled: 'Включить горячий кэш воспроизведения',
hotCacheMaxMb: 'Максимальный размер кэша',
hotCacheDebounce: 'Задержка после изменения очереди',
hotCacheDebounceImmediate: 'Сразу',
hotCacheDebounceSeconds: '{{n}} с',
hotCacheClearBtn: 'Очистить горячий кэш',
audioOutputDevice: 'Устройство вывода звука',
audioOutputDeviceDesc: 'Выберите аудиоустройство для воспроизведения. Изменения применяются немедленно и перезапускают текущий трек.',
audioOutputDeviceDefault: 'Системное по умолчанию',
audioOutputDeviceRefresh: 'Обновить список устройств',
audioOutputDeviceOsDefaultNow: 'текущий системный вывод',
audioOutputDeviceListError: 'Не удалось загрузить список аудиоустройств.',
audioOutputDeviceNotInCurrentList: 'нет в текущем списке',
audioOutputDeviceMacNotice: 'В macOS воспроизведение в настоящее время всегда следует за системным устройством вывода по техническим причинам. Измените цель через Системные настройки → Звук или значок динамика в строке меню. Причина: CoreAudio запрашивает разрешение на использование микрофона при открытии не-стандартного потока — мы избегаем этого, всегда используя системный вывод по умолчанию.',
hiResTitle: 'Нативное воспроизведение Hi-Res',
hiResEnabled: 'Включить нативное Hi-Res воспроизведение',
hiResDesc: "По умолчанию вывод ограничен до 44,1 кГц для максимальной стабильности. Включайте только если оборудование и сеть надёжно поддерживают высокие частоты (88,2 кГц+).",
showArtistImages: 'Фото исполнителей',
showArtistImagesDesc:
'Показывать обложки в разделе «Исполнители». По умолчанию выключено — меньше нагрузки на диск и сеть.',
showOrbitTrigger: 'Показывать «Orbit» в шапке',
showOrbitTriggerDesc: 'Кнопка в шапке для запуска или присоединения к совместной сессии. Скрой, если не используешь Orbit — здесь же можно включить обратно.',
showTrayIcon: 'Иконка в трее',
showTrayIconDesc: 'Показывать Psysonic в области уведомлений / строке меню.',
minimizeToTray: 'Сворачивать в трей',
minimizeToTrayDesc: 'При закрытии окна не выходить из приложения, а оставаться в трее.',
clockFormat: 'Формат времени',
clockFormatDesc: 'Формат времени для ETA очереди и предпросмотра таймера сна.',
clockFormatAuto: 'Авто (системный)',
clockFormatTwentyFour: '24-часовой',
clockFormatTwelve: '12-часовой (AM/PM)',
preloadMiniPlayer: 'Предзагрузка мини-плеера',
preloadMiniPlayerDesc: 'Создаёт окно мини-плеера в фоне при запуске приложения, чтобы при первом открытии содержимое отображалось мгновенно. Использует немного больше памяти.',
useCustomTitlebar: 'Своя строка заголовка',
useCustomTitlebarDesc:
'Заменить системную строку заголовка встроенной, в стиле темы приложения. Отключите, чтобы использовать родную строку GNOME/GTK и т.д.',
linuxWebkitSmoothScroll: 'Плавное колесо (Linux)',
linuxWebkitSmoothScrollDesc: 'Вкл — инерция. Выкл — по шагам, как в GTK.',
linuxWebkitInputForceRepaint: 'Перерисовывать поля ввода при фокусе (Linux)',
linuxWebkitInputForceRepaintDesc: 'Обход проблемы WebKitGTK 2.50.x, когда текстовые поля зависают при клике. Иконки поиска кратко мигают при фокусе.',
linuxWaylandTextRender: 'Рендеринг текста Wayland (Linux)',
linuxWaylandTextRenderDesc:
'Сглаживание в интерфейсе меняется сразу. Политику ускорения WebKit (чёткий / GPU) сохраняем и применяем при следующем запуске — переключение на лету на части сборок зависает в WebKitGTK.',
linuxWaylandTextRenderBalanced: 'Сбалансированный',
linuxWaylandTextRenderSharp: 'Чёткий (меньше GPU)',
linuxWaylandTextRenderGpu: 'С приоритетом GPU',
linuxWaylandTextRenderMinimal: 'Минимальный (сглаживание по умолчанию)',
discordRichPresence: 'Статус в Discord',
discordRichPresenceDesc:
'Показывать текущий трек в профиле и статусе Discord. Нужен запущенный клиент Discord.',
discordCoverSource: 'Источник обложки',
discordCoverSourceDesc: 'Откуда загружать обложку альбома для профиля Discord.',
discordCoverNone: 'Нет (только иконка приложения)',
discordCoverServer: 'Сервер (через информацию об альбоме)',
discordCoverApple: 'Apple Music',
discordOptions: 'Расширенные параметры Discord',
discordTemplates: 'Пользовательские шаблоны текста',
discordTemplatesDesc: 'Настройте, какая информация отображается в профиле Discord. Переменные: {title}, {artist}, {album}',
discordTemplateDetails: 'Основная строка (details)',
discordTemplateState: 'Вторичная строка (state)',
discordTemplateLargeText: 'Подсказка альбома (largeText)',
discordTemplateName: 'Строка в списке пользователей (name)',
nowPlayingEnabled: 'Показывать в «Сейчас играет»',
nowPlayingEnabledDesc:
'Отправлять на сервер, что вы сейчас слушаете. Отключите, чтобы не делиться этим.',
enableBandsintown: 'Даты туров Bandsintown',
enableBandsintownDesc: 'Показывает предстоящие концерты текущего исполнителя на вкладке «Инфо». Данные берутся из публичного API Bandsintown.',
lyricsServerFirst: 'Предпочитать тексты с сервера',
lyricsServerFirstDesc: 'Проверять тексты песен, предоставленные сервером (встроенные теги, sidecar-файлы) перед запросом LRCLIB. Отключите, чтобы сначала использовать LRCLIB.',
enableNeteaselyrics: 'Тексты из Netease Cloud Music',
enableNeteaselyricsDesc: 'Использовать Netease Cloud Music как последний источник текстов, когда остальные способы не находят ничего. Лучшее покрытие для азиатской и международной музыки.',
lyricsSourcesTitle: 'Источники текстов',
lyricsSourcesDesc: 'Выберите источники для поиска текстов и их порядок. Перетаскивайте для сортировки. Отключённые источники пропускаются.',
lyricsSourceServer: 'Сервер',
lyricsSourceLrclib: 'LRCLIB',
lyricsSourceNetease: 'Netease Cloud Music',
lyricsYouLyPlus: 'YouLyPlus (Караоке)',
lyricsYouLyPlusDesc: 'Синхронизация слово-в-слово из общественного бэкенда (Apple Music, Spotify, Musixmatch, QQ). Пробуется первым; включённые источники ниже служат запасным вариантом.',
lyricsSourcesFallbackHint: 'Используются как запасной вариант, когда YouLyPlus ничего не находит. Перетащите для изменения порядка.',
lyricsSourcesPrimaryHint: 'Пробуются по порядку. Перетащите для изменения порядка. Всё выключено = текст отключён.',
lyricsStaticOnly: 'Показывать текст статично',
lyricsStaticOnlyDesc: 'Синхронизированный текст отображается без авто-прокрутки и подсветки слов.',
downloadsTitle: 'Экспорт ZIP и архивов',
downloadsFolderDesc: 'Куда сохранять альбомы в ZIP архиве на диск.',
downloadsDefault: 'Папка «Загрузки» по умолчанию',
pickFolder: 'Выбрать',
pickFolderTitle: 'Папка для загрузок',
clearFolder: 'Сбросить папку',
logout: 'Выйти',
aboutTitle: 'О Psysonic',
aboutDesc:
'Современный десктопный плеер, созданный для Navidrome. Использует API Subsonic плюс специфичные для Navidrome расширения. На Tauri v2 и нативном аудиодвижке на Rust — лёгкий и быстрый: волновая шкала, синхронные тексты, Last.fm, 10-полосный EQ, кроссфейд, воспроизведение без пауз, Replay Gain, жанры и много тем оформления.',
aboutLicense: 'Лицензия',
aboutLicenseText: 'GNU GPL v3 — свободное использование и изменение на тех же условиях.',
aboutRepo: 'Исходный код на GitHub',
aboutVersion: 'Версия',
aboutBuiltWith: 'Tauri · React · TypeScript · Rust/rodio',
aboutReleaseNotesLabel: 'Примечания к выпуску',
aboutReleaseNotesLink: 'Открыть «Что нового» этой версии',
aboutContributorsLabel: 'Участники',
showChangelogOnUpdate: 'Показывать «Что нового» после обновления',
showChangelogOnUpdateDesc: 'После обновления над «Сейчас играет» появится ненавязчивый баннер журнала изменений. Клик открывает заметки о выпуске, X скрывает.',
libraryGridMaxColumnsTitle: 'Сетки карточек в библиотеке',
libraryGridMaxColumnsPerfHint: 'Больше колонок — больше плиток в ряд и больше работы по вёрстке и отрисовке; на очень больших библиотеках или слабом железе это заметнее.',
libraryGridMaxColumnsRangeLabel: 'Максимум колонок ({{min}}{{max}})',
libraryGridMaxColumnsDesc: 'Действует для альбомов, исполнителей, плейлистов, радио, офлайн-библиотеки и других экранов с карточками. Меньше колонок — крупнее плитки и обычно меньше нагрузка на CPU.',
libraryIndexTitle: 'Локальный индекс библиотеки (preview)',
libraryIndexDesc: 'Локальная копия каталога каждого сервера для быстрого поиска и офлайн-доступа. Первичная индексация для всех серверов; офлайн-серверы синхронизируются позже автоматически.',
libraryIndexDeltaHint: 'Фоновая дельта-синхронизация проверяет привязанные серверы каждые 30 с и запускается по расписанию — обычно раз в 5–45 минут в зависимости от размера библиотеки и нагрузки.',
libraryIndexEnable: 'Включить локальный индекс',
libraryIndexEnableAllDesc: 'Индексировать и синхронизировать все настроенные серверы в фоне.',
libraryIndexNoServer: 'Сначала добавьте сервер.',
libraryIndexServerListTitle: 'Индексируемые серверы',
libraryIndexAllExcluded: 'Все серверы исключены из синхронизации.',
libraryIndexServerOffline: 'Сервер офлайн — синхронизация отложена',
libraryIndexServerDeferred: 'Отложено',
libraryIndexServerSyncing: 'Синхронизация…',
libraryIndexFullResync: 'Полная пересинхронизация',
libraryIndexDeltaSync: 'Быстрая дельта',
libraryIndexExcludeServer: 'Исключить из синхронизации',
libraryIndexExcludingServer: 'Отключается…',
libraryIndexExcludedTitle: 'Исключены из синхронизации',
libraryIndexIncludeServer: 'Включить снова',
libraryIndexIncludingServer: 'Подключается…',
libraryIndexStatus: 'Статус',
libraryIndexStatusIdle: 'Ожидание',
libraryIndexStatusProbing: 'Проверка сервера…',
libraryIndexStatusInitial: 'Первичная синхронизация…',
libraryIndexStatusReady: 'Готово ({{count}} треков)',
libraryIndexStatusError: 'Ошибка — см. логи',
libraryIndexProgressIngest: 'Проиндексировано {{count}} треков…',
libraryIndexProgressVerify: 'Проверено {{checked}} (удалено {{deleted}})',
libraryIndexSyncNow: 'Синхронизировать',
libraryIndexVerify: 'Проверить целостность',
libraryIndexCancel: 'Отмена',
libraryIndexAutoReconcile: 'Авто-сверка при падении счётчика',
libraryIndexAutoReconcileDesc: 'Автоматически искать удалённые треки, когда на сервере их меньше ожидаемого.',
libraryIndexSyncError: 'Ошибка синхронизации: {{error}}',
libraryIndexBindError: 'Не удалось включить индекс: {{error}}',
analyticsStrategyTitle: 'Стратегии анализа',
analyticsStrategyDesc:
'Для каждого сервера можно выбрать стратегию: Ленивый — анализ по мере прослушивания; Агрессивный — фоновый анализ всей библиотеки.',
analyticsStrategyLabel: 'Стратегия',
analyticsStrategyLazy: 'Ленивая',
analyticsStrategyLazyDesc:
'Анализирует только треки, которые вы слушаете или которые уже попали в кэш.',
analyticsStrategyAdvanced: 'Агрессивный',
analyticsStrategyAdvancedDesc:
'Запускает фоновый анализ всей библиотеки и скачивает треки для анализа.',
analyticsStrategyPriorityTitle: 'Приоритет анализа (всегда)',
analyticsStrategyPriorityHigh: '1 — Сейчас играет: скачивание и анализ в первую очередь (байты воспроизведения, loudness backfill или HTTP при необходимости).',
analyticsStrategyPriorityMiddle: '2 — Следующие: ~5 треков в очереди и соседи hot cache — анализ из уже скачанных байтов, HTTP backfill только при промахе.',
analyticsStrategyPriorityLow: '3 — Библиотечный batch (только Агрессивный): автоматическая фоновая очередь в хвосте; пополняется по watermark (~3× потоков), не дожидаясь полного опустошения.',
analyticsStrategyServerLabel: 'Сервер',
analyticsStrategyProgressLabel: 'Прогресс анализа:',
analyticsStrategyProgressValue: '{{percent}}% ({{done}}/{{total}})',
analyticsStrategyActionsLabel: 'Действия',
analyticsStrategyParallelismLabel: 'Параллельные потоки',
analyticsStrategyParallelismValue: '{{n}} потоков',
analyticsStrategyParallelismDesc: 'Сколько треков одновременно скачивать и анализировать (HTTP + CPU). Больше значение — быстрее догоняет библиотеку, но выше нагрузка на сеть и CPU.',
analyticsStrategyAdvancedWarning:
'Агрессивный режим скачивает всю библиотеку для анализа и создаёт заметную нагрузку на сеть и процессор. Рекомендуется в локальной сети или для не очень больших библиотек.',
analyticsStrategyServerRemoved: 'Удалённый сервер',
analyticsStrategyClearAction: 'Очистить анализ',
analyticsStrategyClearTitle: 'Очистить анализ?',
analyticsStrategyClearDesc: 'Очистка анализа для {{server}} удалит кэш волн и loudness. При повторном добавлении сервера индексация может занять много времени.',
analyticsStrategyClearCancel: 'Отмена',
analyticsStrategyClearConfirm: 'Очистить анализ',
analyticsStrategyClearSuccess: 'Анализ удалён для удалённого сервера.',
analyticsStrategyClearError: 'Не удалось очистить анализ для удалённого сервера.',
analyticsStrategyProgressEmptyAfterFailed: '100% (0/0, треки помечены как проблемные)',
analyticsFailedTracksOpenTitle: 'Проблемных треков: {{count}}',
analyticsFailedTracksTitle: 'Проблемные треки анализа — {{server}}',
analyticsFailedTracksDesc: 'Эти треки многократно падали на decode/enrichment и исключены из фонового автоанализа.',
analyticsFailedTracksLoading: 'Загрузка списка проблемных треков…',
analyticsFailedTracksEmpty: 'Для этого сервера проблемных треков нет.',
analyticsFailedTracksClose: 'Закрыть',
analyticsFailedTracksExport: 'Экспорт списка',
analyticsFailedTracksExportSuccess: 'Список проблемных треков экспортирован ({{count}}).',
analyticsFailedTracksExportError: 'Не удалось экспортировать список проблемных треков.',
analyticsFailedTracksRescan: 'Рескан проблемных треков',
analyticsFailedTracksRescanSuccess: 'Рескан запланирован для {{count}} проблемных треков.',
analyticsFailedTracksRescanError: 'Не удалось запустить рескан проблемных треков.',
analyticsFailedTracksLoadError: 'Не удалось загрузить список проблемных треков.',
randomMixTitle: 'Чёрный список случайного микса',
luckyMixMenuTitle: 'Показывать «Мне повезёт» в меню',
luckyMixMenuDesc:
'Включает «Мне повезёт» в «Собрать микс», а при раздельной навигации — отдельным пунктом меню. Видно только при включённом AudioMuse на активном сервере.',
randomMixBlacklistTitle: 'Свои слова-фильтры',
randomMixBlacklistDesc:
'Треки скрываются, если слово встречается в жанре, названии, альбоме или исполнителе (когда включён фильтр выше).',
randomMixBlacklistPlaceholder: 'Добавить слово…',
randomMixBlacklistAdd: 'Добавить',
randomMixBlacklistEmpty: 'Пока пусто.',
randomMixHardcodedTitle: 'Встроенные слова (при включённом фильтре)',
tabAudio: 'Звук',
tabStorage: 'Офлайн и кэш',
tabAppearance: 'Внешний вид',
tabThemes: 'Темы',
themesYourThemesTitle: 'Ваши темы',
themesCvdTooltip: 'Безопасно при дальтонизме — дейтеранопия, протанопия, тританопия',
themeStoreTitle: 'Магазин тем',
themeStoreSubmitText: 'Создали свою тему? Поделитесь с сообществом — подробности в репозитории тем.',
themeStoreSubmitLink: 'Открыть репозиторий тем',
themeStoreSearchPlaceholder: 'Поиск тем…',
themeStoreFilterMode: 'Фильтр по режиму',
themeStoreModeAll: 'Все',
themeStoreModeDark: 'Тёмные',
themeStoreModeLight: 'Светлые',
themeStoreRefresh: 'Обновить',
themeStoreLoading: 'Загрузка тем…',
themeStoreError: 'Не удалось загрузить магазин тем. Проверьте подключение.',
themeStoreRetry: 'Повторить',
themeStoreEmpty: 'Нет тем, соответствующих фильтрам.',
themeStoreActive: 'Активна',
themeStoreEnlarge: 'Увеличить превью',
themeStoreByAuthor: 'от {{author}}',
themeMigrationNoticeTitle: 'Тема перенесена в магазин',
themeMigrationNoticeBody: '{{themes}} больше не входит в приложение. Вы можете переустановить её из магазина тем (Настройки → Темы) или выбрать другую тему.',
themeMigrationNoticeOpen: 'Открыть магазин тем',
themeStoreOffline: 'Показан последний кэшированный каталог — похоже, вы офлайн.',
themeStoreInstall: 'Установить',
themeStoreInstalling: 'Установка…',
themeStoreApply: 'Применить',
themeStoreUpdate: 'Обновить',
themeStoreUpdating: 'Обновление…',
themeStoreUninstall: 'Удалить',
themeStoreInstallFailed: 'Ошибка установки',
tabLibrary: 'Библиотека',
tabServers: 'Серверы',
tabLyrics: 'Тексты песен',
tabPersonalisation: 'Персонализация',
tabIntegrations: 'Интеграции',
inputKeybindingsTitle: 'Горячие клавиши',
aboutContributorsCount_one: '{{count}} вклад',
aboutContributorsCount_few: '{{count}} вклада',
aboutContributorsCount_many: '{{count}} вкладов',
aboutContributorsCount_other: '{{count}} вклада',
searchPlaceholder: 'Поиск в настройках…',
searchNoResults: 'Ничего не найдено по вашему запросу.',
aboutMaintainersLabel: 'Сопровождающие',
integrationsPrivacyTitle: 'Уведомление о конфиденциальности',
integrationsPrivacyBody: 'Все интеграции на этой вкладке включаются <strong>по желанию</strong> и при активации отправляют данные во внешние сервисы или на ваш сервер Navidrome. Last.fm получает вашу историю прослушивания, Discord показывает текущую композицию в вашем профиле, Bandsintown опрашивается по артисту для получения дат гастролей, а «Сейчас играет» делится текущей композицией с другими пользователями вашего сервера Navidrome. Если вы не хотите ничего из этого, просто оставьте соответствующий раздел отключённым.',
homeCustomizerTitle: 'Для вас',
queueModeTitle: 'Режим отображения очереди',
queueModeQueueSub: 'Показывает только предстоящие треки. Текущий трек остаётся в заголовке и исчезает из списка после воспроизведения.',
queueModePlaylistSub: 'Сохраняет всю очередь в списке, текущий трек выделен вверху; воспроизведённые треки остаются.',
queueModeTimelineSub: 'Центрировать текущий трек: история воспроизведения сверху, предстоящие треки (в порядке перемешивания) снизу.',
queueToolbarTitle: 'Панель инструментов очереди',
queueToolbarReset: 'Сбросить',
queueToolbarSeparator: 'Разделитель',
sidebarTitle: 'Боковая панель',
sidebarReset: 'Сбросить порядок',
artistLayoutTitle: 'Разделы страницы исполнителя',
artistLayoutDesc: 'Перетаскивайте, чтобы изменить порядок, переключайте, чтобы скрыть отдельные разделы страницы исполнителя. Разделы без данных пропускаются автоматически.',
artistLayoutReset: 'Сбросить',
artistLayoutBio: 'Биография исполнителя',
artistLayoutTopTracks: 'Топ-треки',
artistLayoutSimilar: 'Похожие исполнители',
artistLayoutAlbums: 'Альбомы',
artistLayoutFeatured: 'Также участвует в',
playlistLayoutTitle: 'Макет страницы плейлиста',
playlistLayoutDesc: 'Показать или скрыть отдельные элементы на странице плейлиста.',
playlistLayoutReset: 'Сбросить',
playerBarTitle: 'Панель плеера',
playerBarReset: 'Сбросить',
playerBarStarRating: 'Оценка звёздами',
playerBarFavorite: 'Избранное (сердечко)',
playerBarLastfmLove: 'Last.fm love',
playerBarPlaybackRate: 'Скорость',
playerBarEqualizer: 'Эквалайзер',
playerBarMiniPlayer: 'Мини-плеер',
playbackRateTitle: 'Скорость воспроизведения',
playbackRateEnabled: 'Включить изменение скорости',
playbackRateEnabledDesc: 'Глобальная скорость для всех треков. Не применяется к радио и превью.',
playbackRateStrategy: 'Стратегия',
playbackRateStrategySpeed: 'Скорость',
playbackRateStrategyVarispeed: 'С тоном',
playbackRateStrategyPreserve: 'Сдвиг тона',
playbackRateSpeed: 'Скорость',
playbackRatePitch: 'Тон',
playbackRateDerivedPitch: 'Сдвиг тона от скорости: {{value}}',
playbackRateAutoPitch: 'Тон корректируется автоматически.',
playbackRateHint: '«Скорость» сохраняет высоту тона при изменении темпа. «С тоном» меняет тон вместе со скоростью. «Сдвиг тона» — ручное смещение. Выше нагрузка на процессор, чем у режима «С тоном». Не для радио, превью и Orbit.',
playbackRateNeutral: 'При 1.0× и нулевом сдвиге тона воспроизведение обычное.',
playbackRateOrbitPaused: 'Во время сессии Orbit не применяется — воспроизведение остаётся 1.0× для синхронизации.',
playbackRateOrbitPausedShort: 'Orbit: 1.0× для синхронизации.',
advancedMode: 'Дополнительно',
advancedModeTooltip: 'Показывать расширенные параметры во всех вкладках настроек. Вклады сообщества, которые не обязательно соответствуют дизайн-философии мейнтейнеров Psysonic.',
advancedBadge: 'Дополнительно',
sidebarDrag: 'Перетащите для порядка',
sidebarFixed: 'Всегда показывать',
nowPlayingTopTitle: '«Сейчас играет» вверху',
nowPlayingTopDesc: 'Закрепить пункт «Сейчас играет» вверху боковой панели вместо нижней части.',
randomNavSplitTitle: 'Разделить навигацию микса',
randomNavSplitDesc:
'Показывать «Случайный микс», «Случайные альбомы» и «Мне повезёт» как отдельные пункты боковой панели вместо хаба «Собрать микс».',
tabInput: 'Ввод',
tabUsers: 'Пользователи',
tabSystem: 'Система',
loggingTitle: 'Логирование',
loggingModeDesc: 'Управляет подробностью логов backend в терминале.',
loggingModeOff: 'Выключено',
loggingModeNormal: 'Обычное',
loggingModeDebug: 'Дебаг',
loggingExport: 'Экспорт логов',
loggingExportSuccess: 'Логи экспортированы ({{count}} строк).',
loggingExportError: 'Не удалось экспортировать логи.',
ratingsSectionTitle: 'Рейтинги',
ratingsSkipStarTitle: 'Скипнуть для 1 звезды',
ratingsSkipStarDesc:
'При N скипов подряд ставить 1★ треку. Только для не оцененных ранее.',
ratingsSkipStarThresholdLabel: 'Скипов',
ratingsMixFilterTitle: 'Фильтрация по рейтингу',
ratingsMixFilterDesc:
'Фильтровать с низким рейтингом в «{{mix}}» и «{{albums}}». Повторный клик по выбранной звезде отключает порог.',
ratingsMixMinSong: 'Песни',
ratingsMixMinAlbum: 'Альбомы',
ratingsMixMinArtist: 'Исполнители',
ratingsMixMinThresholdAria: 'Минимум звёзд: {{label}}',
backupTitle: 'Резервная копия',
backupExport: 'Экспорт настроек',
backupExportDesc:
'Сохраняет настройки, серверы, Last.fm, тему, EQ и горячие клавиши в файл .psybkp. Пароли в открытом виде — храните файл в безопасности.',
backupImport: 'Импорт настроек',
backupImportDesc: 'Восстановить из .psybkp. Приложение перезапустится.',
backupImportConfirm: 'Текущие настройки будут заменены. Продолжить?',
backupImportAny: 'Импорт резервной копии',
backupImportAnyConfirm:
'Импортировать выбранный файл резервной копии и применить его содержимое (настройки, базы библиотеки или полный архив). Продолжить?',
backupSuccess: 'Копия сохранена',
backupImportSuccess: 'Настройки восстановлены — перезапуск…',
backupImportError: 'Файл повреждён или не подходит.',
backupModeFull: 'Полный',
backupModeLibrary: 'Базы библиотеки',
backupModeConfig: 'Настройки',
backupFullDesc: 'Архивирует настройки и базы библиотеки в один файл резервной копии.',
backupFullExport: 'Экспорт полного архива',
backupFullImport: 'Импорт полного архива',
backupFullImportConfirm:
'Настройки будут перезаписаны, текущие базы библиотеки будут заменены и сохранены в .bak. Продолжить?',
backupFullExportSuccess: 'Полный архив экспортирован.',
backupFullImportSuccess: 'Полный архив импортирован — перезапуск…',
backupFullImportError: 'Не удалось импортировать полный архив.',
backupLibraryExport: 'Экспорт баз',
backupLibraryExportDesc: 'Создаёт сжатый архив с чистыми SQLite-снимками баз библиотеки.',
backupLibraryImport: 'Импорт баз',
backupLibraryImportDesc:
'Восстанавливает базы библиотеки из архива. Текущие базы перед заменой переносятся в .bak.',
backupLibraryImportConfirm:
'Текущие базы библиотеки будут заменены и сохранены в .bak. Продолжить?',
backupLibraryExportSuccess: 'Копия баз экспортирована.',
backupLibraryImportSuccess: 'Копия баз импортирована.',
backupLibraryImportError: 'Не удалось импортировать копию баз.',
backupOverlayExportTitle: 'Создаём резервную копию…',
backupOverlayImportTitle: 'Восстанавливаем резервную копию…',
backupOverlayHint: 'Окно можно не закрывать, идёт обработка файлов. Ввод временно заблокирован.',
shortcutsReset: 'Сбросить',
shortcutListening: 'Нажмите клавишу…',
shortcutUnbound: '—',
globalShortcutsTitle: 'Глобальные сочетания',
globalShortcutsNote:
'Работают, когда окно не в фокусе. Нужен модификатор: Ctrl, Alt или Super.',
shortcutClear: 'Сбросить',
shortcutPlayPause: 'Пауза / воспроизведение',
shortcutNext: 'Следующий трек',
shortcutPrev: 'Предыдущий трек',
shortcutVolumeUp: 'Громче',
shortcutVolumeDown: 'Тише',
shortcutSeekForward: 'Вперёд на 10 с',
shortcutSeekBackward: 'Назад на 10 с',
shortcutToggleQueue: 'Показать / скрыть очередь',
shortcutOpenFolderBrowser: 'Открыть {{folderBrowser}}',
shortcutFullscreenPlayer: 'Полноэкранный плеер',
shortcutNativeFullscreen: 'Системный полный экран',
shortcutOpenMiniPlayer: 'Открыть мини-плеер',
shortcutStartSearch: 'Начать поиск',
shortcutStartAdvancedSearch: 'Начать расширенный поиск',
shortcutToggleSidebar: 'Переключить боковую панель',
shortcutMuteSound: 'Без звука',
shortcutToggleEqualizer: 'Открыть / переключить эквалайзер',
shortcutToggleRepeat: 'Переключить повтор',
shortcutOpenNowPlaying: 'Открыть «Сейчас играет»',
shortcutShowLyrics: 'Показать текст песни',
shortcutFavoriteCurrentTrack: 'Добавить текущий трек в избранное',
shortcutOpenHelp: 'Справка',
playbackTitle: 'Воспроизведение',
replayGain: 'Replay Gain',
replayGainDesc: 'Выравнивание громкости по метаданным ReplayGain',
replayGainMode: 'Режим',
replayGainAuto: 'Авто',
replayGainAutoDesc: 'Использует громкость альбома, когда соседние треки в очереди из того же альбома, иначе громкость трека.',
replayGainTrack: 'По треку',
replayGainAlbum: 'По альбому',
replayGainPreGain: 'Предусиление (файлы с тегами)',
replayGainPreGainDesc: 'Общая прибавка, добавляемая к каждому расчёту ReplayGain. Удобно, если библиотека в целом кажется тихой.',
replayGainFallback: 'Резерв (без тегов / радио)',
replayGainFallbackDesc: 'Применяется к трекам (и радиопотокам) без тегов ReplayGain, чтобы непомеченный контент не звучал громче остального.',
normalization: 'Нормализация',
normalizationDesc: 'Выровнять воспринимаемую громкость между треками, альбомами и радио.',
normalizationOff: 'Выкл.',
normalizationReplayGain: 'ReplayGain',
normalizationLufs: 'LUFS',
loudnessTargetLufs: 'Целевой LUFS',
loudnessTargetLufsDesc: 'Опорная громкость, к которой подгоняются все треки. Меньше число = громче на выходе. Стриминг-сервисы обычно держат около -14 LUFS.',
loudnessPreAnalysisAttenuation: 'Ослабление до измерения',
loudnessPreAnalysisAttenuationDesc:
'Насколько приглушить звук, пока для трека нет сохранённого измерения громкости. При стриме дальше идут лишь грубые оценки, не полный LUFS. 0 dB — без дополнительного приглушения; ниже — тише. Справа показывается фактическая поправка для текущей цели.',
loudnessPreAnalysisAttenuationRef: 'Фактически {{eff}} dB при цели {{tgt}} LUFS.',
loudnessPreAnalysisAttenuationReset: 'По умолчанию',
loudnessFirstPlayNote:
'При первом прослушивании нового трека громкость может ненадолго колебаться, пока идёт измерение. Со второго раза применяется уже сохранённое значение и всё стабильно. Следующие треки в очереди обычно анализируются во время предыдущей композиции, поэтому на практике это случается редко.',
crossfade: 'Кроссфейд',
crossfadeDesc: 'Плавный переход между треками',
crossfadeSecs: '{{n}} с',
notWithGapless: 'Недоступно при включённом режиме без пауз',
notWithCrossfade: 'Недоступно при включённом кроссфейде',
gapless: 'Без пауз между треками',
gaplessDesc: 'Заранее подгружать следующий трек, чтобы не было тишины',
preservePlayNextOrder: 'Сохранять порядок «Играть следующим»',
preservePlayNextOrderDesc: 'Новые элементы «Играть следующим» становятся в конец очереди, а не лезут вперёд.',
trackPreviewsTitle: 'Превью треков',
trackPreviewsToggle: 'Включить превью треков',
trackPreviewsDesc: 'Показывать встроенные кнопки воспроизведения и превью в списках треков для быстрого прослушивания фрагмента.',
trackPreviewStart: 'Начальная позиция',
trackPreviewStartDesc: 'С какого момента трека начинается превью (% от длительности).',
trackPreviewDuration: 'Длительность',
trackPreviewDurationDesc: 'Сколько играет каждое превью до автоматической остановки.',
trackPreviewDurationSecs: '{{n}} с',
trackPreviewLocationsTitle: 'Где показывать превью',
trackPreviewLocationsDesc: 'Выберите, в каких списках показывать кнопки превью.',
trackPreviewLocation_suggestions: 'В предложениях плейлиста',
trackPreviewLocation_albums: 'В списках треков альбома',
trackPreviewLocation_playlists: 'В плейлистах',
trackPreviewLocation_favorites: 'В избранном',
trackPreviewLocation_artist: 'В топ-треках исполнителя',
trackPreviewLocation_randomMix: 'В Random Mix',
nextTrackBufferingTitle: 'Буферизация',
infiniteQueue: 'Бесконечная очередь',
infiniteQueueDesc: 'Подмешивать случайные треки, когда очередь закончится',
experimental: 'Экспериментально',
sidebarLyricsStyle: 'Стиль прокрутки текста',
sidebarLyricsStyleClassic: 'Классический',
sidebarLyricsStyleClassicDesc: 'Активная строка центрируется.',
sidebarLyricsStyleApple: 'Apple Music-like',
sidebarLyricsStyleAppleDesc: 'Активная строка фиксируется сверху с плавной анимацией.',
seekbarStyle: 'Стиль прогресс-бара',
seekbarStyleDesc: 'Выбор внешнего вида полосы воспроизведения',
seekbarTruewave: 'Реальная форма волны',
seekbarPseudowave: 'Псевдо форма волны',
seekbarLinedot: 'Линия и точка',
seekbarBar: 'Полоса',
seekbarThick: 'Толстая полоса',
seekbarSegmented: 'Сегменты',
seekbarNeon: 'Неон',
seekbarPulsewave: 'Пульс-волна',
seekbarParticletrail: 'Частицы',
seekbarLiquidfill: 'Жидкость',
seekbarRetrotape: 'Ретро-лента',
themeSchedulerTitle: 'Расписание тем',
themeSchedulerEnable: 'Включить расписание тем',
themeSchedulerEnableSub: 'Автоматически переключается между двумя темами в зависимости от времени суток',
themeSchedulerDayTheme: 'Дневная тема',
themeSchedulerDayStart: 'День начинается в',
themeSchedulerNightTheme: 'Ночная тема',
themeSchedulerNightStart: 'Ночь начинается в',
themeSchedulerActiveHint: 'Расписание тем активно - темы переключаются автоматически.',
visualOptionsTitle: 'Визуальные Настройки',
coverArtBackground: 'Фон Обложки',
coverArtBackgroundSub: 'Показывать размытую обложку как фон в заголовках альбомов и плейлистов',
playlistCoverPhoto: 'Обложка Плейлиста',
playlistCoverPhotoSub: 'Показывать сетку обложек в детальном виде плейлиста',
showBitrate: 'Показывать Битрейт',
showBitrateSub: 'Отображать битрейт аудио в списках треков',
floatingPlayerBar: 'Плавающая панель плеера',
floatingPlayerBarSub: 'Держать панель плеера плавающей над содержимым',
uiScaleTitle: 'Масштаб интерфейса',
uiScaleLabel: 'Масштаб',
confirmDeleteServerLibrary: 'Также удалить локальный индекс библиотеки этого сервера? Нажмите «Отмена», чтобы сохранить кэш-копию для офлайн-использования.',
};