quintodrome/resources/i18n/ru.json

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

718 lines
38 KiB
JSON
Raw Normal View History

2020-10-23 05:54:25 -08:00
{
"languageName": "Русский",
"resources": {
"song": {
"name": "Трек |||| Треки |||| Треков",
"fields": {
"albumArtist": "Исполнитель альбома",
"duration": "Длительность",
"trackNumber": "#",
"playCount": "Прослушивания",
"title": "Название трека",
"artist": "Артист",
"album": "Альбом",
"path": "Путь",
"genre": "Жанр",
"compilation": "Сборник",
"year": "Год",
"size": "Размер",
"updatedAt": "Обновлено",
"bitRate": "Битрейт",
"discSubtitle": "Название диска",
"starred": "Избранное",
"comment": "Комментарий",
"rating": "Рейтинг",
"quality": "Качество",
"bpm": "BPM",
"playDate": "Последнее воспроизведение",
"channels": "Каналы",
"createdAt": "Дата добавления",
"grouping": "Группирование",
"mood": "Настроение",
"participants": "Дополнительные участники",
"tags": "Дополнительные теги",
"mappedTags": "Сопоставленные теги",
"rawTags": "Исходные теги",
"bitDepth": "Битовая глубина (Bit)",
"sampleRate": "Частота дискретизации (Hz)",
"albumGain": "Усиление альбома",
"trackGain": "Усиление трека",
"missing": "Поле отсутствует",
"libraryName": "Библиотека",
"composer": "Композитор",
"disc": "Диск %{discNumber}"
},
"actions": {
"addToQueue": "В очередь",
"playNow": "Играть",
"addToPlaylist": "Добавить в плейлист",
"shuffleAll": "Перемешать",
"download": "Скачать",
"playNext": "Следующий",
"info": "Информация",
"showInPlaylist": "Показать в плейлисте",
"instantMix": "Быстрый микс"
}
2020-10-23 05:54:25 -08:00
},
"album": {
"name": "Альбом |||| Альбомы |||| Альбомов",
"fields": {
"albumArtist": "Исполнитель альбома",
"artist": "Артист",
"duration": "Длительность",
"songCount": "Трек |||| Треки |||| Треков",
"playCount": "Прослушивания",
"name": "Название альбома",
"genre": "Жанр",
"compilation": "Сборник",
"year": "Год",
"updatedAt": "Обновлено",
"comment": "Комментарий",
"rating": "Рейтинг",
"createdAt": "Дата добавления",
"size": "Размер",
"originalDate": "Оригинал",
"releaseDate": "Релиз",
"releases": "Релиз |||| Релиза |||| Релизов",
"released": "Релиз",
"recordLabel": "Лейбл",
"catalogNum": "Номер каталога",
"releaseType": "Тип",
"grouping": "Группирование",
"media": "Медиа",
"mood": "Настроение",
"date": "Дата записи",
"missing": "Поле отсутствует",
"libraryName": "Библиотека"
},
"actions": {
"playAll": "Играть",
"playNext": "Следующий",
"addToQueue": "В очередь",
"shuffle": "Перемешать",
"addToPlaylist": "Добавить в плейлист",
"download": "Скачать",
"info": "Информация",
"share": "Поделиться"
},
"lists": {
"all": "Все",
"random": "Случайные",
"recentlyAdded": "Новые",
"recentlyPlayed": "Проигранные",
"mostPlayed": "Популярные",
"starred": "Избранное",
"topRated": "Лучшие"
}
2020-10-23 05:54:25 -08:00
},
"artist": {
"name": "Артист |||| Артисты |||| Артистов",
"fields": {
"name": "Название исполнителя",
"albumCount": "Количество альбомов",
"songCount": "Количество треков",
"playCount": "Прослушивания",
"rating": "Рейтинг",
"genre": "Жанр",
"size": "Размер",
"role": "Роль",
"missing": "Поле отсутствует"
},
"roles": {
"albumartist": "Исполнитель альбома |||| Исполнители альбома |||| Исполнителей альбома",
"artist": "Артист |||| Артисты |||| Артистов",
"composer": "Композитор |||| Композиторы |||| Композиторов",
"conductor": "Дирижёр |||| Дирижёры |||| Дирижёров",
"lyricist": "Автор текста |||| Авторы текста |||| Авторов текста",
"arranger": "Аранжировщик |||| Аранжировщики |||| Аранжировщиков",
"producer": "Продюсер |||| Продюсеры |||| Продюсеров",
"director": "Режиссёр |||| Режиссёры |||| Режиссёров",
"engineer": "Инженер |||| Инженеры |||| Инженеров",
"mixer": "Звукоинженер |||| Звукоинженеры |||| Звукоинженеров",
"remixer": "Ремиксер |||| Ремиксеры |||| Ремиксеров",
"djmixer": "DJ-миксер |||| DJ-миксеры |||| DJ-миксеров",
"performer": "Исполнитель |||| Исполнители |||| Исполнителей",
"maincredit": "Исполнитель альбома или артист |||| Исполнители альбома или артисты |||| Исполнителей альбома или артистов"
},
"actions": {
"shuffle": "Перемешать",
"radio": "Радио",
"topSongs": "Топовые треки"
}
2020-10-23 05:54:25 -08:00
},
"user": {
"name": "Пользователь |||| Пользователи |||| Пользователей",
"fields": {
"userName": "Имя пользователя",
"isAdmin": "Администратор",
"lastLoginAt": "Последний вход",
"updatedAt": "Обновлено",
"name": "Имя",
"password": "Пароль",
"createdAt": "Аккаунт создан",
"changePassword": "Сменить пароль?",
"currentPassword": "Текущий пароль",
"newPassword": "Новый пароль",
"token": "Токен",
"lastAccessAt": "Последний доступ",
"libraries": "Библиотеки"
},
"helperTexts": {
"name": "Изменение вступит в силу после следующего входа в систему",
"libraries": "Выберите конкретные библиотеки для этого пользователя или оставьте поле пустым, чтобы использовать библиотеки по умолчанию"
},
"notifications": {
"created": "Пользователь создан",
"updated": "Пользователь обновлен",
"deleted": "Пользователь удален"
},
"message": {
"listenBrainzToken": "Введите свой токен пользователя ListenBrainz.",
"clickHereForToken": "Нажмите здесь, чтобы получить токен",
"selectAllLibraries": "Выбрать все библиотеки",
"adminAutoLibraries": "Пользователи-администраторы автоматически получают доступ ко всем библиотекам"
},
"validation": {
"librariesRequired": "Для пользователей, не являющихся администраторами, должна быть выбрана хотя бы одна библиотека"
}
2020-10-23 05:54:25 -08:00
},
"player": {
"name": "Плеер |||| Плееры |||| Плееров",
"fields": {
"name": "Название",
"transcodingId": "Транскодирование",
"maxBitRate": "Макс. битрейт",
"client": "Клиент",
"userName": "Пользователь",
"lastSeen": "Был на сайте",
"reportRealPath": "Показать реальный путь",
"scrobbleEnabled": "Отправлять скробблы во внешние службы"
}
2020-10-23 05:54:25 -08:00
},
"transcoding": {
"name": "Транскодирование |||| Транскодирование |||| Транскодирований",
"fields": {
"name": "Название",
"targetFormat": "Целевой формат",
"defaultBitRate": "Битрейт по умолчанию",
"command": "Команда"
}
},
"playlist": {
"name": "Плейлист |||| Плейлисты |||| Плейлистов",
"fields": {
"name": "Название",
"duration": "Длительность",
"ownerName": "Владелец",
"public": "Публичный",
"updatedAt": "Обновлено",
"createdAt": "Создан",
"songCount": "Трек |||| Трека |||| Треков",
"comment": "Комментарий",
"sync": "Автоимпорт",
"path": "Импортировать из"
},
"actions": {
"selectPlaylist": "Выберите плейлист:",
"addNewPlaylist": "Создать \"%{name}\"",
"export": "Экспорт",
"makePublic": "Опубликовать",
"makePrivate": "Сделать личным",
"saveQueue": "Сохранить очередь в плейлист",
"searchOrCreate": "Поиск плейлистов или введите текст для создания новых...",
"pressEnterToCreate": "Нажмите Enter, чтобы создать новый плейлист",
feat: add artist image uploads and image-folder artwork source (#5198) * feat: add shared ImageUploadService for entity image management * feat: add UploadedImage field and methods to Artist model * feat: add uploaded_image column to artist table * feat: add ArtistImageFolder config option * refactor: wire ImageUploadService and delegate playlist file ops to it Wire ImageUploadService into the DI container and refactor the playlist service to delegate image file operations (SetImage/RemoveImage) to the shared ImageUploadService, removing duplicated file I/O logic. A local ImageUploadService interface is defined in core/playlists to avoid an import cycle between core and core/playlists. * feat: artist artwork reader checks uploaded image first * feat: add image-folder priority source for artist artwork * feat: cache key invalidation for image-folder and uploaded images * refactor: extract shared image upload HTTP helpers * feat: add artist image upload/delete API endpoints * refactor: playlist handlers use shared image upload helpers * feat: add shared ImageUploadOverlay component * feat: add i18n keys for artist image upload * feat: add image upload overlay to artist detail pages * refactor: playlist details uses shared ImageUploadOverlay component * fix: add gosec nolint directive for ParseMultipartForm * refactor: deduplicate image upload code and optimize dir scanning - Remove dead ImageFilename methods from Artist and Playlist models (production code uses core.imageFilename exclusively) - Extract shared uploadedImagePath helper in model/image.go - Extract findImageInArtistFolder to deduplicate dir-scanning logic between fromArtistImageFolder and getArtistImageFolderModTime - Fix fileInputRef in useCallback dependency array * fix: include artist UpdatedAt in artwork cache key Without this, uploading or deleting an artist image would not invalidate the cached artwork because the cache key was only based on album folder timestamps, not the artist's own UpdatedAt field. * feat: add Portuguese translations for artist image upload * refactor: use shared i18n keys for cover art upload messages Move cover art upload/remove translations from per-entity sections (artist, playlist) to a shared top-level "message" section, avoiding duplication across entity types and translation files. * refactor: move cover art i18n keys to shared message section for all languages * refactor: simplify image upload code and eliminate redundancies Extracted duplicate image loading/lightbox state logic from DesktopArtistDetails and MobileArtistDetails into a shared useArtistImageState hook. Moved entity type constants to the consts package and replaced raw string literals throughout model, core, and nativeapi packages. Exported model.UploadedImagePath and reused it in core/image_upload.go to consolidate path construction. Cached the ArtistImageFolder lookup result in artistReader to eliminate a redundant os.ReadDir call on every artwork request. Signed-off-by: Deluan <deluan@navidrome.org> * style: fix prettier formatting in ImageUploadOverlay * fix: address code review feedback on image upload error handling - RemoveImage now returns errors instead of swallowing them - Artist handlers distinguish not-found from other DB errors - Defer multipart temp file cleanup after parsing * fix: enforce hard request size limit with MaxBytesReader for image uploads Signed-off-by: Deluan <deluan@navidrome.org> --------- Signed-off-by: Deluan <deluan@navidrome.org>
2026-03-15 18:19:55 -08:00
"removeFromSelection": "Удалить из списка выделенных"
},
"message": {
"duplicate_song": "Повторяющиеся треки",
"song_exist": "Некоторые треки уже есть в плейлисте. Вы хотите добавить их или пропустить?",
"noPlaylistsFound": "Плейлисты не найдены",
feat: add artist image uploads and image-folder artwork source (#5198) * feat: add shared ImageUploadService for entity image management * feat: add UploadedImage field and methods to Artist model * feat: add uploaded_image column to artist table * feat: add ArtistImageFolder config option * refactor: wire ImageUploadService and delegate playlist file ops to it Wire ImageUploadService into the DI container and refactor the playlist service to delegate image file operations (SetImage/RemoveImage) to the shared ImageUploadService, removing duplicated file I/O logic. A local ImageUploadService interface is defined in core/playlists to avoid an import cycle between core and core/playlists. * feat: artist artwork reader checks uploaded image first * feat: add image-folder priority source for artist artwork * feat: cache key invalidation for image-folder and uploaded images * refactor: extract shared image upload HTTP helpers * feat: add artist image upload/delete API endpoints * refactor: playlist handlers use shared image upload helpers * feat: add shared ImageUploadOverlay component * feat: add i18n keys for artist image upload * feat: add image upload overlay to artist detail pages * refactor: playlist details uses shared ImageUploadOverlay component * fix: add gosec nolint directive for ParseMultipartForm * refactor: deduplicate image upload code and optimize dir scanning - Remove dead ImageFilename methods from Artist and Playlist models (production code uses core.imageFilename exclusively) - Extract shared uploadedImagePath helper in model/image.go - Extract findImageInArtistFolder to deduplicate dir-scanning logic between fromArtistImageFolder and getArtistImageFolderModTime - Fix fileInputRef in useCallback dependency array * fix: include artist UpdatedAt in artwork cache key Without this, uploading or deleting an artist image would not invalidate the cached artwork because the cache key was only based on album folder timestamps, not the artist's own UpdatedAt field. * feat: add Portuguese translations for artist image upload * refactor: use shared i18n keys for cover art upload messages Move cover art upload/remove translations from per-entity sections (artist, playlist) to a shared top-level "message" section, avoiding duplication across entity types and translation files. * refactor: move cover art i18n keys to shared message section for all languages * refactor: simplify image upload code and eliminate redundancies Extracted duplicate image loading/lightbox state logic from DesktopArtistDetails and MobileArtistDetails into a shared useArtistImageState hook. Moved entity type constants to the consts package and replaced raw string literals throughout model, core, and nativeapi packages. Exported model.UploadedImagePath and reused it in core/image_upload.go to consolidate path construction. Cached the ArtistImageFolder lookup result in artistReader to eliminate a redundant os.ReadDir call on every artwork request. Signed-off-by: Deluan <deluan@navidrome.org> * style: fix prettier formatting in ImageUploadOverlay * fix: address code review feedback on image upload error handling - RemoveImage now returns errors instead of swallowing them - Artist handlers distinguish not-found from other DB errors - Defer multipart temp file cleanup after parsing * fix: enforce hard request size limit with MaxBytesReader for image uploads Signed-off-by: Deluan <deluan@navidrome.org> --------- Signed-off-by: Deluan <deluan@navidrome.org>
2026-03-15 18:19:55 -08:00
"noPlaylists": "Нет доступных плейлистов"
}
},
"radio": {
"name": "Радио |||| Радио |||| Радио",
"fields": {
"name": "Название",
"streamUrl": "Ссылка на поток",
"homePageUrl": "Домашняя страница",
"updatedAt": "Обновлено",
"createdAt": "Создано"
},
"actions": {
"playNow": "Играть сейчас"
}
},
"share": {
"name": "Общий доступ |||| Общий доступ |||| Общий доступ",
"fields": {
"username": "Поделился",
"url": "Ссылка",
"description": "Описание",
"contents": "Содержание",
"expiresAt": "Ссылка истекает",
"lastVisitedAt": "Последнее посещение",
"visitCount": "Количество посещений",
"format": "Формат",
"maxBitRate": "Макс. битрейт",
"updatedAt": "Обновлено",
"createdAt": "Создано",
"downloadable": "Разрешить загрузку?"
}
},
"missing": {
"name": "Отсутствующий файл |||| Отсутствующие файлы |||| Отсутствующих файлов",
"fields": {
"path": "Путь",
"size": "Размер",
"updatedAt": "Исчез",
"libraryName": "Библиотека"
},
"actions": {
"remove": "Удалить",
"remove_all": "Убрать все"
},
"notifications": {
"removed": "Отсутствующие файлы удалены"
},
"empty": "Нет отсутствующих файлов"
},
"library": {
"name": "Библиотека |||| Библиотеки |||| Библиотек",
"fields": {
"name": "Название",
"path": "Путь",
"remotePath": "Удаленный путь",
"lastScanAt": "Последнее сканирование",
"songCount": "Треки",
"albumCount": "Альбомы",
"artistCount": "Артисты",
"totalSongs": "Треки",
"totalAlbums": "Альбомы",
"totalArtists": "Артисты",
"totalFolders": "Папки",
"totalFiles": "Файлы",
"totalMissingFiles": "Отсутствующие файлы",
"totalSize": "Общий размер",
"totalDuration": "Длительность",
"defaultNewUsers": "По умолчанию для новых пользователей",
"createdAt": "Создано",
"updatedAt": "Обновлено"
},
"sections": {
"basic": "Основная информация",
"statistics": "Статистика"
},
"actions": {
"scan": "Сканировать библиотеку",
"manageUsers": "Управление доступом пользователей",
"viewDetails": "Просмотреть подробности",
"quickScan": "Быстрое сканирование",
"fullScan": "Полное сканирование"
},
"notifications": {
"created": "Библиотека успешно создана",
"updated": "Библиотека успешно обновлена",
"deleted": "Библиотека успешно удалена",
"scanStarted": "Сканирование библиотеки начато",
"scanCompleted": "Сканирование библиотеки закончено",
"quickScanStarted": "Быстрое сканирование началось",
"fullScanStarted": "Началось полное сканирование",
"scanError": "Ошибка при запуске сканирования. Проверьте логи"
},
"validation": {
"nameRequired": "Название библиотеки обязательно",
"pathRequired": "Путь к библиотеке обязателен",
"pathNotDirectory": "Путь к библиотеке должен быть директорией",
"pathNotFound": "Путь к библиотеке не найден",
"pathNotAccessible": "Путь к библиотеке недоступен",
"pathInvalid": "Неверный путь к библиотеке"
},
"messages": {
"deleteConfirm": "Вы уверены, что хотите удалить эту библиотеку? Это приведет к удалению всех связанных с ней данных и доступа пользователей.",
"scanInProgress": "Сканирование продолжается...",
"noLibrariesAssigned": "Нет библиотек, назначенных этому пользователю"
}
},
"plugin": {
"name": "Плагин |||| Плагины |||| Плагинов",
"fields": {
"id": "ID",
"name": "Название",
"description": "Описание",
"version": "Версия",
"author": "Автор",
"website": "Веб-сайт",
"permissions": "Разрешения",
"enabled": "Включено",
"status": "Статус",
"path": "Путь",
"lastError": "Ошибка",
"hasError": "Ошибка",
"updatedAt": "Обновлено",
"createdAt": "Дата установки",
"configKey": "Ключ",
"configValue": "Значение",
"allUsers": "Разрешить всем пользователям",
"selectedUsers": "Выбранные пользователи",
"allLibraries": "Разрешить доступ ко всем библиотекам",
"selectedLibraries": "Выбранные библиотеки",
"allowWriteAccess": "Разрешить запись"
},
"sections": {
"status": "Статус",
"info": "Информация о плагине",
"configuration": "Конфигурация",
"manifest": "Манифест",
"usersPermission": "Права доступа пользователей",
"libraryPermission": "Права доступа к библиотекам"
},
"status": {
"enabled": "Включено",
"disabled": "Отключено"
},
"actions": {
"enable": "Включить",
"disable": "Отключить",
"disabledDueToError": "Исправьте ошибку перед включением",
"disabledUsersRequired": "Выберите пользователей перед включением",
"disabledLibrariesRequired": "Выберите библиотеки перед включением",
"addConfig": "Добавить конфигурацию",
"rescan": "Повторное сканирование"
},
"notifications": {
"enabled": "Плагин включен",
"disabled": "Плагин отключен",
"updated": "Плагин обновлен",
"error": "Ошибка обновления плагина"
},
"validation": {
"invalidJson": "Конфигурация должна быть в формате JSON, допустимом для всех пользователей"
},
"messages": {
"configHelp": "Настройте плагин, используя пары ключ-значение. Оставьте поле пустым, если плагин не требует настройки.",
"clickPermissions": "Нажмите на разрешение для получения подробной информации",
"noConfig": "Конфигурация не задана",
"allUsersHelp": "При включении плагин получит доступ ко всем пользователям, включая тех, кто будет создан в будущем.",
"noUsers": "Не выбрано ни одного пользователя",
"permissionReason": "Причина",
"usersRequired": "Этому плагину требуется доступ к пользовательской информации. Выберите, к каким пользователям плагин может получить доступ, или включите \"Разрешить всем пользователям\".",
"allLibrariesHelp": "После включения плагин будет иметь доступ ко всем библиотекам, включая те, которые будут созданы в будущем.",
"noLibraries": "Библиотеки не выбраны",
"librariesRequired": "Этому плагину требуется доступ к библиотечной информации. Выберите, к каким библиотекам плагин может получить доступ, или включите \"Разрешить все библиотеки\".",
"requiredHosts": "Необходимые хосты",
"configValidationError": "Проверка конфигурации завершилась неудачей:",
"schemaRenderError": "Не удалось отобразить форму конфигурации. Возможно, схема плагина недействительна.",
"allowWriteAccessHelp": "Разрешить плагину изменять файлы в вашей библиотеке"
},
"placeholders": {
"configKey": "ключ",
"configValue": "значение"
}
}
},
"ra": {
"auth": {
"welcome1": "Спасибо за установку Navidrome!",
"welcome2": "Для начала создайте аккаунт администратора",
"confirmPassword": "Подтвердите пароль",
"buttonCreateAdmin": "Создать аккаунт администратора",
"auth_check_error": "Пожалуйста, авторизуйтесь для продолжения работы",
"user_menu": "Профиль",
"username": "Имя пользователя",
"password": "Пароль",
"sign_in": "Войти",
"sign_in_error": "Ошибка аутентификации, попробуйте снова",
"logout": "Выйти",
"insightsCollectionNote": "Navidrome анонимно собирает данные об использовании, \nчтобы сделать проект лучше. \nУзнать больше и отключить сбор данных можно [здесь]"
},
"validation": {
"invalidChars": "Пожалуйста, используйте только буквы и цифры",
"passwordDoesNotMatch": "Пароли не совпадают",
"required": "Обязательно для заполнения",
"minLength": "Минимальное количество символов: %{min}",
"maxLength": "Максимальное количество символов: %{max}",
"minValue": "Минимальное значение: %{min}",
"maxValue": "Максимальное значение: %{max}",
"number": "Должно быть числом",
"email": "Некорректный Email",
"oneOf": "Должно быть одним из: %{options}",
"regex": "Должно соответствовать формату: %{pattern}",
"unique": "Должно быть уникальным",
"url": "Должен быть действительный URL"
},
"action": {
"add_filter": "Фильтр",
"add": "Добавить",
"back": "Назад",
"bulk_actions": "1 выбран |||| %{smart_count} выбраны |||| %{smart_count} выбрано",
"cancel": "Отмена",
"clear_input_value": "Очистить",
"clone": "Дублировать",
"confirm": "Подтвердить",
"create": "Создать",
"delete": "Удалить",
"edit": "Редактировать",
"export": "Экспорт",
"list": "Список",
"refresh": "Обновить",
"remove_filter": "Убрать этот фильтр",
"remove": "Удалить",
"save": "Сохранить",
"search": "Поиск",
"show": "Просмотр",
"sort": "Сортировать",
"undo": "Отменить",
"expand": "Развернуть",
"close": "Закрыть",
"open_menu": "Открыть меню",
"close_menu": "Закрыть меню",
"unselect": "Снять выделение",
"skip": "Пропустить",
"bulk_actions_mobile": "1 |||| %{smart_count} |||| %{smart_count}",
"share": "Поделиться",
"download": "Скачать"
},
"boolean": {
"true": "Да",
"false": "Нет"
2021-09-05 06:56:54 -08:00
},
"page": {
"create": "Создать %{name}",
"dashboard": "Главная",
"edit": "%{name} #%{id}",
"error": "Что-то пошло не так",
"list": "%{name}",
"loading": "Загрузка...",
"not_found": "Не найдено",
"show": "%{name} #%{id}",
"empty": "Нет %{name}.",
"invite": "Хотите создать?"
},
"input": {
"file": {
"upload_several": "Перетащите файлы для загрузки или щёлкните для выбора.",
"upload_single": "Перетащите файл для загрузки или щёлкните для выбора."
},
"image": {
"upload_several": "Перетащите изображения для загрузки или щёлкните для выбора.",
"upload_single": "Перетащите изображение для загрузки или щёлкните для выбора."
},
"references": {
"all_missing": "Связанных данных не найдено.",
"many_missing": "Некоторые из связанных данных недоступны",
"single_missing": "Связанный объект недоступен"
},
"password": {
"toggle_visible": "Скрыть пароль",
"toggle_hidden": "Показать пароль"
}
},
"message": {
"about": "О программе",
"are_you_sure": "Вы уверены?",
"bulk_delete_content": "Вы уверены, что хотите удалить %{name}? |||| Удалить %{smart_count} объекта? |||| Удалить %{smart_count} объектов?",
"bulk_delete_title": "Удалить %{name} |||| Удалить %{smart_count} объекта |||| Удалить %{smart_count} объектов",
"delete_content": "Вы уверены, что хотите удалить этот объект?",
"delete_title": "Удалить %{name} #%{id}",
"details": "Подробности",
"error": "При выполнении запроса возникла ошибка",
"invalid_form": "Форма заполнена неверно, проверьте ошибки",
"loading": "Загрузка, пожалуйста, подождите...",
"no": "Нет",
"not_found": "Страница не найдена. Возможно, вы ввели неправильный URL.",
"yes": "Да",
"unsaved_changes": "Есть несохраненные изменения. Продолжить без сохранения?"
},
"navigation": {
"no_results": "Результатов не найдено",
"no_more_results": "Страница %{page} выходит за пределы, попробуйте предыдущую",
"page_out_of_boundaries": "Страница %{page} выходит за пределы",
"page_out_from_end": "Невозможно переместиться дальше последней страницы",
"page_out_from_begin": "Номер страницы не может быть меньше 1",
"page_range_info": "%{offsetBegin}-%{offsetEnd} из %{total}",
"page_rows_per_page": "Строк на странице:",
"next": "Вперед",
"prev": "Назад",
"skip_nav": "Перейти к основному контенту"
},
"notification": {
"updated": "Элемент обновлен |||| %{smart_count} элемента обновлены |||| %{smart_count} элементов обновлено",
"created": "Элемент создан",
"deleted": "Элемент удален |||| %{smart_count} элемента удалены |||| %{smart_count} элементов удалено",
"bad_item": "Некорректный элемент",
"item_doesnt_exist": "Элемент не существует",
"http_error": "Ошибка сервера",
"data_provider_error": "Ошибка поставщика данных, проверьте консоль",
"i18n_error": "Не удалось загрузить перевод",
"canceled": "Операция отменена",
"logged_out": "Сессия завершена, пожалуйста, войдите снова",
"new_version": "Доступна новая версия! Пожалуйста, обновите страницу."
},
"toggleFieldsMenu": {
"columnsToDisplay": "Отображение столбцов",
"layout": "Макет",
"grid": "Сетка",
"table": "Таблица"
}
},
"message": {
"note": "ПРИМЕЧАНИЕ",
"transcodingDisabled": "Изменение настроек транскодирования через веб-интерфейс отключено по соображениям безопасности. Если вы хотите изменить или добавить опции транскодирования, перезапустите сервер с опцией конфигурации %{config}.",
"transcodingEnabled": "Navidrome работает с настройками %{config}, позволяющими запускать команды транскодирования через веб-интерфейс. В целях безопасности мы рекомендуем отключить эту возможность.",
"songsAddedToPlaylist": "Добавлен 1 трек |||| Добавлены %{smart_count} трека |||| Добавлено %{smart_count} треков",
"noPlaylistsAvailable": "Недоступно",
"delete_user_title": "Удалить пользователя '%{name}'",
"delete_user_content": "Вы уверены, что хотите удалить пользователя и все его данные (включая плейлисты и настройки)?",
"notifications_blocked": "Вы заблокировали уведомления для этой страницы в настройках вашего браузера",
"notifications_not_available": "Ваш браузер не поддерживает всплывающие уведомления",
"lastfmLinkSuccess": "Соединение с Last.fm установлено, скробблинг включен",
"lastfmLinkFailure": "Не удалось подключиться к Last.fm",
"lastfmUnlinkSuccess": "Соединение с Last.fm разорвано, скробблинг отключен",
"lastfmUnlinkFailure": "Не удалось разорвать соединение с Last.fm",
"openIn": {
"lastfm": "Показать на Last.fm",
"musicbrainz": "Показать на MusicBrainz"
},
"lastfmLink": "Подробнее...",
"listenBrainzLinkSuccess": "ListenBrainz скробблинг успешно подключен для пользователя: %{user}",
"listenBrainzLinkFailure": "Не удалось подключить ListenBrainz:",
"listenBrainzUnlinkSuccess": "ListenBrainz скробблинг отключен",
"listenBrainzUnlinkFailure": "Не удалось отключить ListenBrainz",
"downloadOriginalFormat": "Скачать в оригинальном формате",
"shareOriginalFormat": "Поделиться в оригинальном формате",
"shareDialogTitle": "Поделиться %{resource} '%{name}'",
"shareBatchDialogTitle": "Поделиться 1 %{resource} |||| Поделиться %{smart_count} %{resource} |||| Поделиться %{smart_count} %{resource}",
"shareSuccess": "URL скопирован в буфер обмена: %{url}",
"shareFailure": "Ошибка копирования URL %{url} в буфер обмена",
"downloadDialogTitle": "Скачать %{resource} '%{name}' (%{size})",
"shareCopyToClipboard": "Копировать в буфер обмена: Ctrl+C, Enter",
"remove_missing_title": "Удалить отсутствующие файлы?",
"remove_missing_content": "Вы уверены, что хотите удалить выбранные отсутствующие файлы из базы данных? Это навсегда удалит все ссылки на них, включая данные о прослушиваниях и рейтингах.",
"remove_all_missing_title": "Удалить все отсутствующие файлы",
"remove_all_missing_content": "Вы уверены, что хотите удалить все отсутствующие файлы из базы данных? Это навсегда удалит все упоминания о них, включая количество прослушиваний и рейтинг.",
"noSimilarSongsFound": "Похожих треков не найдено",
"noTopSongsFound": "Лучших треков не найдено",
"startingInstantMix": "Загрузка быстрого микса..."
},
"menu": {
"library": "Библиотека",
"settings": "Настройки",
"version": "Версия",
"theme": "Тема",
"personal": {
"name": "Личное",
"options": {
"theme": "Тема",
"language": "Язык",
"defaultView": "Вид по умолчанию",
"desktop_notifications": "Уведомления на рабочем столе",
"lastfmScrobbling": "Скробблинг Last.fm",
"listenBrainzScrobbling": "Скробблинг ListenBrainz",
"replaygain": "Режим ReplayGain",
"preAmp": "Предусилитель ReplayGain (дБ)",
"gain": {
"none": "Отключено",
"album": "Использовать усиление альбома",
"track": "Использовать усиление трека"
},
"lastfmNotConfigured": "API-ключ Last.fm не настроен"
}
},
"albumList": "Альбомы",
"about": "О программе",
"playlists": "Плейлисты",
"sharedPlaylists": "Общие плейлисты",
"librarySelector": {
"allLibraries": "Все библиотеки (%{count})",
"multipleLibraries": "%{selected} из %{total} библиотек |||| %{selected} из %{total} библиотек |||| %{selected} из %{total} библиотек",
"selectLibraries": "Выбор библиотек",
"none": "Отсутствует"
}
},
"player": {
"playListsText": "Очередь воспроизведения",
"openText": "Открыть",
"closeText": "Закрыть",
"notContentText": "Нет музыки",
"clickToPlayText": "Играть",
"clickToPauseText": "Пауза",
"nextTrackText": "Следующий трек",
"previousTrackText": "Предыдущий трек",
"reloadText": "Перезагрузить",
"volumeText": "Громкость",
"toggleLyricText": "Посмотреть текст",
"toggleMiniModeText": "Свернуть",
"destroyText": "Выключить",
"downloadText": "Скачать",
"removeAudioListsText": "Очистить очередь",
"clickToDeleteText": "Нажмите для удаления %{name}",
"emptyLyricText": "Текст песни отсутствует",
"playModeText": {
"order": "По порядку",
"orderLoop": "Повторять",
"singleLoop": "Повторять один трек",
"shufflePlay": "Перемешать"
}
},
"about": {
"links": {
"homepage": "Сайт проекта",
"source": "Исходный код",
"featureRequests": "Предложения",
"lastInsightsCollection": "Последний сбор данных",
"insights": {
"disabled": "Выключено",
"waiting": "Ожидание"
}
},
"tabs": {
"about": "О программе",
"config": "Конфигурация"
},
"config": {
"configName": "Параметр",
"environmentVariable": "Переменная окружения",
"currentValue": "Текущее значение",
"configurationFile": "Файл конфигурации",
"exportToml": "Экспорт в TOML",
"exportSuccess": "Конфигурация скопирована в буфер обмена в формате TOML",
"exportFailed": "Не удалось скопировать конфигурацию",
"devFlagsHeader": "Флаги разработки (могут быть изменены/удалены)",
"devFlagsComment": "Это экспериментальные настройки, которые могут быть удалены в будущих версиях.",
"downloadToml": "Скачать TOML"
}
},
"activity": {
"title": "Активность",
"totalScanned": "Всего просканировано папок",
"quickScan": "Быстрое сканирование",
"fullScan": "Полное сканирование",
"serverUptime": "Время работы сервера",
"serverDown": "Офлайн",
"scanType": "Тип",
"status": "Статус",
"elapsedTime": "Прошедшее время",
"selectiveScan": "Избирательное"
},
"help": {
"title": "Горячие клавиши Navidrome",
"hotkeys": {
"show_help": "Показать справку",
"toggle_menu": "Показать/скрыть боковое меню",
"toggle_play": "Играть/Пауза",
"prev_song": "Предыдущий трек",
"next_song": "Следующий трек",
"vol_up": "Увеличить громкость",
"vol_down": "Уменьшить громкость",
"toggle_love": "Добавить/удалить из избранного",
"current_song": "Перейти к текущему треку"
2020-10-23 05:54:25 -08:00
}
},
"nowPlaying": {
"title": "Сейчас играет",
"empty": "Ничего не играет",
"minutesAgo": "%{smart_count} минуту назад |||| %{smart_count} минуты назад |||| %{smart_count} минут назад"
}
feat: add artist image uploads and image-folder artwork source (#5198) * feat: add shared ImageUploadService for entity image management * feat: add UploadedImage field and methods to Artist model * feat: add uploaded_image column to artist table * feat: add ArtistImageFolder config option * refactor: wire ImageUploadService and delegate playlist file ops to it Wire ImageUploadService into the DI container and refactor the playlist service to delegate image file operations (SetImage/RemoveImage) to the shared ImageUploadService, removing duplicated file I/O logic. A local ImageUploadService interface is defined in core/playlists to avoid an import cycle between core and core/playlists. * feat: artist artwork reader checks uploaded image first * feat: add image-folder priority source for artist artwork * feat: cache key invalidation for image-folder and uploaded images * refactor: extract shared image upload HTTP helpers * feat: add artist image upload/delete API endpoints * refactor: playlist handlers use shared image upload helpers * feat: add shared ImageUploadOverlay component * feat: add i18n keys for artist image upload * feat: add image upload overlay to artist detail pages * refactor: playlist details uses shared ImageUploadOverlay component * fix: add gosec nolint directive for ParseMultipartForm * refactor: deduplicate image upload code and optimize dir scanning - Remove dead ImageFilename methods from Artist and Playlist models (production code uses core.imageFilename exclusively) - Extract shared uploadedImagePath helper in model/image.go - Extract findImageInArtistFolder to deduplicate dir-scanning logic between fromArtistImageFolder and getArtistImageFolderModTime - Fix fileInputRef in useCallback dependency array * fix: include artist UpdatedAt in artwork cache key Without this, uploading or deleting an artist image would not invalidate the cached artwork because the cache key was only based on album folder timestamps, not the artist's own UpdatedAt field. * feat: add Portuguese translations for artist image upload * refactor: use shared i18n keys for cover art upload messages Move cover art upload/remove translations from per-entity sections (artist, playlist) to a shared top-level "message" section, avoiding duplication across entity types and translation files. * refactor: move cover art i18n keys to shared message section for all languages * refactor: simplify image upload code and eliminate redundancies Extracted duplicate image loading/lightbox state logic from DesktopArtistDetails and MobileArtistDetails into a shared useArtistImageState hook. Moved entity type constants to the consts package and replaced raw string literals throughout model, core, and nativeapi packages. Exported model.UploadedImagePath and reused it in core/image_upload.go to consolidate path construction. Cached the ArtistImageFolder lookup result in artistReader to eliminate a redundant os.ReadDir call on every artwork request. Signed-off-by: Deluan <deluan@navidrome.org> * style: fix prettier formatting in ImageUploadOverlay * fix: address code review feedback on image upload error handling - RemoveImage now returns errors instead of swallowing them - Artist handlers distinguish not-found from other DB errors - Defer multipart temp file cleanup after parsing * fix: enforce hard request size limit with MaxBytesReader for image uploads Signed-off-by: Deluan <deluan@navidrome.org> --------- Signed-off-by: Deluan <deluan@navidrome.org>
2026-03-15 18:19:55 -08:00
}