Improved translations for English and Russian versions. (#760)

* First version of Russian translation

* Improvements

---------

Co-authored-by: Suoslex <mtsarev06@gmail.com>
This commit is contained in:
Mikhail Tsarev 2024-09-26 12:42:41 +08:00 committed by GitHub
parent 8cddbef701
commit 7bcfe30a8e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 251 additions and 120 deletions

View file

@ -147,6 +147,7 @@
"smartPlaylist": "smart $t(entity.playlist_one)", "smartPlaylist": "smart $t(entity.playlist_one)",
"track_one": "track", "track_one": "track",
"track_other": "tracks", "track_other": "tracks",
"song_many": "{{ count }} songs",
"trackWithCount_one": "{{count}} track", "trackWithCount_one": "{{count}} track",
"trackWithCount_other": "{{count}} tracks" "trackWithCount_other": "{{count}} tracks"
}, },
@ -315,6 +316,14 @@
"settings": "$t(common.setting_other)", "settings": "$t(common.setting_other)",
"version": "version {{version}}" "version": "version {{version}}"
}, },
"manageServers": {
"title": "manage servers",
"serverDetails": "server details",
"url": "URL",
"username": "username",
"editServerDetailsTooltip": "edit server details",
"removeServer": "remove server"
},
"contextMenu": { "contextMenu": {
"addFavorite": "$t(action.addToFavorites)", "addFavorite": "$t(action.addToFavorites)",
"addLast": "$t(player.addLast)", "addLast": "$t(player.addLast)",
@ -345,6 +354,7 @@
"dynamicIsImage": "enable background image", "dynamicIsImage": "enable background image",
"followCurrentLyric": "follow current lyric", "followCurrentLyric": "follow current lyric",
"lyricAlignment": "lyric alignment", "lyricAlignment": "lyric alignment",
"lyricOffset": "lyrics offset (ms)",
"lyricGap": "lyric gap", "lyricGap": "lyric gap",
"lyricSize": "lyric size", "lyricSize": "lyric size",
"opacity": "opacity", "opacity": "opacity",
@ -357,7 +367,8 @@
"lyrics": "lyrics", "lyrics": "lyrics",
"related": "related", "related": "related",
"upNext": "up next", "upNext": "up next",
"visualizer": "visualizer" "visualizer": "visualizer",
"noLyrics": "no lyrics found"
}, },
"genreList": { "genreList": {
"showAlbums": "show $t(entity.genre_one) $t(entity.album_other)", "showAlbums": "show $t(entity.genre_one) $t(entity.album_other)",
@ -449,7 +460,8 @@
"stop": "stop", "stop": "stop",
"toggleFullscreenPlayer": "toggle fullscreen player", "toggleFullscreenPlayer": "toggle fullscreen player",
"unfavorite": "unfavorite", "unfavorite": "unfavorite",
"pause": "pause" "pause": "pause",
"viewQueue": "view queue"
}, },
"setting": { "setting": {
"accentColor": "accent color", "accentColor": "accent color",
@ -706,6 +718,7 @@
"config": { "config": {
"general": { "general": {
"autoFitColumns": "auto fit columns", "autoFitColumns": "auto fit columns",
"followCurrentSong": "follow current song",
"displayType": "display type", "displayType": "display type",
"gap": "$t(common.gap)", "gap": "$t(common.gap)",
"itemGap": "item gap (px)", "itemGap": "item gap (px)",

View file

@ -7,8 +7,8 @@
"addToFavorites": "добавить в $t(entity.favorite_other)", "addToFavorites": "добавить в $t(entity.favorite_other)",
"addToPlaylist": "добавить в $t(entity.playlist_one)", "addToPlaylist": "добавить в $t(entity.playlist_one)",
"createPlaylist": "создать $t(entity.playlist_one)", "createPlaylist": "создать $t(entity.playlist_one)",
"removeFromPlaylist": "удалить из $t(entity.playlist_one)", "removeFromPlaylist": "удалить из $t(entity.playlist_few)",
"viewPlaylists": "просмотреть $t(entity.playlist_other)", "viewPlaylists": "показать $t(entity.playlist_other)",
"refresh": "$t(common.refresh)", "refresh": "$t(common.refresh)",
"deletePlaylist": "удалить $t(entity.playlist_one)", "deletePlaylist": "удалить $t(entity.playlist_one)",
"removeFromQueue": "удалить из очереди", "removeFromQueue": "удалить из очереди",
@ -16,7 +16,7 @@
"moveToBottom": "вниз", "moveToBottom": "вниз",
"setRating": "оценить", "setRating": "оценить",
"toggleSmartPlaylistEditor": "вкл./откл. редактор $t(entity.smartPlaylist)", "toggleSmartPlaylistEditor": "вкл./откл. редактор $t(entity.smartPlaylist)",
"removeFromFavorites": "удалить из $t(entity.favorite_other)", "removeFromFavorites": "удалить из $t(entity.favorite_few)",
"openIn": { "openIn": {
"lastfm": "открыть на Last.fm", "lastfm": "открыть на Last.fm",
"musicbrainz": "открыть на MusicBrainz" "musicbrainz": "открыть на MusicBrainz"
@ -38,15 +38,15 @@
"currentSong": "текущий $t(entity.track_one)", "currentSong": "текущий $t(entity.track_one)",
"collapse": "закрыть", "collapse": "закрыть",
"trackNumber": "трек", "trackNumber": "трек",
"descending": "убывание", "descending": "по убыванию",
"add": "добавить", "add": "добавить",
"gap": "промежуток", "gap": "промежуток",
"ascending": "возрастанию", "ascending": "по возрастанию",
"dismiss": "отклонить", "dismiss": "отклонить",
"year": "год", "year": "год",
"manage": "управлять", "manage": "управление",
"limit": "ограничение", "limit": "ограничение",
"minimize": "минимизировать", "minimize": "свернуть",
"modified": "изменено", "modified": "изменено",
"duration": "длительность", "duration": "длительность",
"name": "имя", "name": "имя",
@ -66,6 +66,8 @@
"cancel": "отменить", "cancel": "отменить",
"forceRestartRequired": "перезапустите приложение, чтобы применить изменения... закройте уведомление для перезапуска", "forceRestartRequired": "перезапустите приложение, чтобы применить изменения... закройте уведомление для перезапуска",
"setting": "настройка", "setting": "настройка",
"setting_one": "настройка",
"setting_other": "настройки",
"version": "версия", "version": "версия",
"title": "название", "title": "название",
"filter_one": "фильтр", "filter_one": "фильтр",
@ -78,11 +80,11 @@
"action_one": "действие", "action_one": "действие",
"action_few": "действия", "action_few": "действия",
"action_many": "действий", "action_many": "действий",
"playerMustBePaused": "воспроизведение должно быть остановлено", "playerMustBePaused": "необходимо остановить воспроизведение",
"confirm": "подтвердить", "confirm": "подтвердить",
"resetToDefault": "по умолчанию", "resetToDefault": "сбросить настройки",
"home": "главная страница", "home": "главная",
"comingSoon": "скоро будет…", "comingSoon": "скоро...",
"reset": "сбросить", "reset": "сбросить",
"channel_one": "канал", "channel_one": "канал",
"channel_few": "канала", "channel_few": "канала",
@ -92,14 +94,14 @@
"menu": "меню", "menu": "меню",
"restartRequired": "необходим перезапуск приложения", "restartRequired": "необходим перезапуск приложения",
"previousSong": "предыдущий $t(entity.track_one)", "previousSong": "предыдущий $t(entity.track_one)",
"noResultsFromQuery": ет результатов", "noResultsFromQuery": ичего не найдено",
"quit": "выйти", "quit": "выйти",
"expand": "расширить", "expand": "раскрыть",
"search": "поиск", "search": "поиск",
"saveAs": "сохранить как", "saveAs": "сохранить как",
"disc": "диск", "disc": "диск",
"yes": "да", "yes": "да",
"random": "случайный", "random": "случайно",
"size": "размер", "size": "размер",
"biography": "биография", "biography": "биография",
"note": "заметка", "note": "заметка",
@ -114,9 +116,11 @@
"entity": { "entity": {
"album_one": "альбом", "album_one": "альбом",
"album_few": "альбома", "album_few": "альбома",
"album_other": "альбомы",
"album_many": "альбомов", "album_many": "альбомов",
"genre_one": "жанр", "genre_one": "жанр",
"genre_few": "жанра", "genre_few": "жанра",
"genre_other": "жанры",
"genre_many": "жанров", "genre_many": "жанров",
"playlistWithCount_one": "{{count}} плейлист", "playlistWithCount_one": "{{count}} плейлист",
"playlistWithCount_few": "{{count}} плейлиста", "playlistWithCount_few": "{{count}} плейлиста",
@ -124,18 +128,26 @@
"playlist_one": "плейлист", "playlist_one": "плейлист",
"playlist_few": "плейлиста", "playlist_few": "плейлиста",
"playlist_many": "плейлистов", "playlist_many": "плейлистов",
"playlist_other": "плейлисты",
"play": "{{count}} прослушиваний",
"play_one": "{{count}} прослушивание",
"play_other": "{{count}} прослушиваний",
"artist_one": "автор", "artist_one": "автор",
"artist_few": "автора", "artist_few": "автора",
"artist_many": "авторов", "artist_other": "исполнители",
"artist_many": "исполнителей",
"folderWithCount_one": "{{count}} папка", "folderWithCount_one": "{{count}} папка",
"folderWithCount_few": "{{count}} папки", "folderWithCount_few": "{{count}} папки",
"folderWithCount_many": "{{count}} папок", "folderWithCount_many": "{{count}} папок",
"albumArtist_one": "автор альбома", "albumArtist_one": "исполнитель альбома",
"albumArtist_few": "автора альбома", "albumArtist_few": "исполнители альбома",
"albumArtist_many": "авторов альбома", "albumArtist_other": "исполнители альбомов",
"albumArtist_many": "исполнителей альбома",
"track_one": "трек", "track_one": "трек",
"track_few": "трека", "track_few": "трека",
"track_many": "треков", "track_many": "треков",
"track_other": "треки",
"song_many": "{{ count }} композиций",
"albumArtistCount_one": "{{count}} автор альбома", "albumArtistCount_one": "{{count}} автор альбома",
"albumArtistCount_few": "{{count}} автора альбома", "albumArtistCount_few": "{{count}} автора альбома",
"albumArtistCount_many": "{{count}} авторов альбома", "albumArtistCount_many": "{{count}} авторов альбома",
@ -145,24 +157,27 @@
"favorite_one": "любимый", "favorite_one": "любимый",
"favorite_few": "любимых", "favorite_few": "любимых",
"favorite_many": "любимые", "favorite_many": "любимые",
"favorite_other": "любимые",
"artistWithCount_one": "{{count}} автор", "artistWithCount_one": "{{count}} автор",
"artistWithCount_few": "{{count}} автора", "artistWithCount_few": "{{count}} автора",
"artistWithCount_many": "{{count}} авторов", "artistWithCount_many": "{{count}} авторов",
"folder_one": "папка", "folder_one": "папка",
"folder_few": "папки", "folder_few": "папки",
"folder_many": "папок", "folder_many": "папок",
"folder_other": "папки",
"smartPlaylist": "умный $t(entity.playlist_one)", "smartPlaylist": "умный $t(entity.playlist_one)",
"genreWithCount_one": "{{count}} жанр", "genreWithCount_one": "{{count}} жанр",
"genreWithCount_few": "{{count}} жанра", "genreWithCount_few": "{{count}} жанра",
"genreWithCount_many": "{{count}} жанров", "genreWithCount_many": "{{count}} жанров",
"trackWithCount_one": "{{count}} трек", "trackWithCount_one": "{{count}} трек",
"trackWithCount_few": "{{count}} трека", "trackWithCount_few": "{{count}} трека",
"trackWithCount_many": "{{count}} треков" "trackWithCount_many": "{{count}} треков",
"trackWithCount_other": "{{count}} треков"
}, },
"table": { "table": {
"config": { "config": {
"view": { "view": {
"card": "карта", "card": "карточки",
"table": "таблица", "table": "таблица",
"poster": "постер" "poster": "постер"
}, },
@ -171,8 +186,9 @@
"gap": "$t(common.gap)", "gap": "$t(common.gap)",
"tableColumns": "столбцы таблицы", "tableColumns": "столбцы таблицы",
"autoFitColumns": "автоматически расставить столбцы", "autoFitColumns": "автоматически расставить столбцы",
"followCurrentSong": "следовать за исполняемым треком",
"size": "$t(common.size)", "size": "$t(common.size)",
"itemSize": "рамер элементов (px)", "itemSize": "размер элементов (px)",
"itemGap": "отступ между элементами (px)" "itemGap": "отступ между элементами (px)"
}, },
"label": { "label": {
@ -185,7 +201,7 @@
"bpm": "$t(common.bpm)", "bpm": "$t(common.bpm)",
"lastPlayed": "последний", "lastPlayed": "последний",
"trackNumber": "номер трека", "trackNumber": "номер трека",
"rowIndex": "индекс ряда", "rowIndex": "номер строки",
"rating": "$t(common.rating)", "rating": "$t(common.rating)",
"artist": "$t(entity.artist_one)", "artist": "$t(entity.artist_one)",
"album": "$t(entity.album_one)", "album": "$t(entity.album_one)",
@ -234,25 +250,25 @@
} }
}, },
"error": { "error": {
"remotePortWarning": "перезапустить сервер для применения нового порта", "remotePortWarning": "необходимо перезапустить сервер для применения нового порта",
"systemFontError": "произошла ошибка при попытке получить системные шрифты", "systemFontError": "произошла ошибка при попытке получить системные шрифты",
"playbackError": "произошла ошибка при попытке проиграть медиа", "playbackError": "произошла ошибка при попытке проигрывания медиа",
"endpointNotImplementedError": "запрос {{endpoint}} не реализован для {{serverType}}", "endpointNotImplementedError": "запрос {{endpoint}} не реализован для {{serverType}}",
"remotePortError": "произошла ошибка при попытке установить порт удаленного сервера", "remotePortError": "произошла ошибка при попытке установить порт удаленного сервера",
"serverRequired": "необходим сервер", "serverRequired": "сервер не выбран",
"authenticationFailed": "авторизация завершилась с ошибкой", "authenticationFailed": "не удалось авторизироваться",
"apiRouteError": "невозможно выполнить запрос", "apiRouteError": "невозможно выполнить запрос",
"genericError": "произошла ошибка", "genericError": "произошла ошибка",
"credentialsRequired": "необходимы учётные данные", "credentialsRequired": "введите данные для входа",
"sessionExpiredError": "ваш сеанс истёк", "sessionExpiredError": "ваш сеанс истёк",
"remoteEnableError": "ошибка произошла при попытке $t(common.enable) удалённый сервер", "remoteEnableError": "произошла ошибка при попытке $t(common.enable) удалённый сервер",
"localFontAccessDenied": "не получилось получить доступ к шрифтам", "localFontAccessDenied": "не получилось получить доступ к шрифтам",
"serverNotSelectedError": "не выбран сервер", "serverNotSelectedError": "не выбран сервер",
"remoteDisableError": "ошибка произошла при попытке $t(common.disable) удалённый сервер", "remoteDisableError": "произошла ошибка при попытке $t(common.disable) удалённый сервер",
"mpvRequired": "необходим MPV", "mpvRequired": "необходим MPV",
"audioDeviceFetchError": "произошла ошибка с аудиоустройством", "audioDeviceFetchError": "произошла ошибка с аудиоустройством",
"invalidServer": "недействительный сервер", "invalidServer": "недействительный сервер",
"loginRateError": "слишком много попыток входа, пожалуйста, попробуйте ещё раз через несколько секунд", "loginRateError": "превышено максимальное количество попыток входа, пожалуйста, попробуйте ещё раз через несколько секунд",
"openError": "не удалось открыть файл", "openError": "не удалось открыть файл",
"badAlbum": "вы видите эту страницу из-за того, что эта песня не входит в альбом. скорее всего, вы видите эту ошибку, так как песня находится в корневой директории папки с музыкой. jellyfin группирует треки только по папкам.", "badAlbum": "вы видите эту страницу из-за того, что эта песня не входит в альбом. скорее всего, вы видите эту ошибку, так как песня находится в корневой директории папки с музыкой. jellyfin группирует треки только по папкам.",
"networkError": "возникла ошибка сети" "networkError": "возникла ошибка сети"
@ -265,48 +281,49 @@
"communityRating": "рейтинг сообщества", "communityRating": "рейтинг сообщества",
"favorited": "любимый", "favorited": "любимый",
"albumArtist": "$t(entity.albumArtist_one)", "albumArtist": "$t(entity.albumArtist_one)",
"isFavorited": "любимый", "isFavorited": "любимые",
"bpm": "уд./мин.", "bpm": "уд./мин.",
"disc": "диск", "disc": "диск",
"biography": "биография", "biography": "биография",
"artist": "$t(entity.artist_one)", "artist": "$t(entity.artist_one)",
"duration": "длительность", "duration": "длительность",
"fromYear": "из года", "fromYear": "год",
"criticRating": "рейтинг критиков", "criticRating": "рейтинг критиков",
"mostPlayed": "самое воспроизводимое", "mostPlayed": "слушают чаще всего",
"comment": "комментировать", "comment": "комментировать",
"playCount": "кол-во воспроизведений", "playCount": "количество воспроизведений",
"recentlyUpdated": "недавно обновлено", "recentlyUpdated": "обновленные недавно",
"channels": "$t(common.channel_other)", "channels": "$t(common.channel_other)",
"recentlyPlayed": "недавно проиграно", "recentlyPlayed": "проигрывались недавно",
"owner": "$t(common.owner)", "owner": "$t(common.owner)",
"title": "название", "title": "название",
"rating": "рейтинг", "rating": "рейтинг",
"search": "поиск", "search": "поиск",
"genre": "$t(entity.genre_one)", "genre": "$t(entity.genre_one)",
"recentlyAdded": "недавно добавлено", "recentlyAdded": "недавно добавленные",
"note": "заметка", "note": "заметка",
"name": "название", "name": "название",
"releaseDate": "дата выхода", "releaseDate": "дата выхода",
"albumCount": "кол-во $t(entity.album_other)", "albumCount": "количество $t(entity.album_many)",
"path": "путь", "path": "путь",
"isRecentlyPlayed": "недавно проигрывалась", "isRecentlyPlayed": "недавно проигрывался",
"releaseYear": "год выхода", "releaseYear": "год выхода",
"id": "№", "id": "№",
"songCount": "кол-во песен", "songCount": "количество песен",
"isPublic": "публичный", "isPublic": "публичный",
"random": "случайный", "random": "случайно",
"lastPlayed": "последний раз проигрывалась", "lastPlayed": "последний раз проигрывалась",
"toYear": "до года", "toYear": "до года",
"album": "$t(entity.album_one)", "album": "$t(entity.album_one)",
"trackNumber": "трек" "trackNumber": "трек"
}, },
"player": { "player": {
"repeat_all": "повтор всех", "repeat_all": "повторять все",
"stop": "остановить", "stop": "остановить",
"repeat": "повтор", "repeat": "повторять текущий",
"queue_remove": "удалить выбранное", "queue_remove": "удалить выбранное",
"playRandom": "случайные песни", "playRandom": "играть случайные песни",
"playSimilarSongs": "играть похожие песни",
"skip": "пропустить", "skip": "пропустить",
"previous": "предыдущий", "previous": "предыдущий",
"toggleFullscreenPlayer": "включить полноэкранный режим", "toggleFullscreenPlayer": "включить полноэкранный режим",
@ -316,10 +333,10 @@
"shuffle": "перемешать", "shuffle": "перемешать",
"playbackFetchNoResults": "песни не найдены", "playbackFetchNoResults": "песни не найдены",
"playbackFetchInProgress": "загрузка песен..", "playbackFetchInProgress": "загрузка песен..",
"addNext": "добавить следующий", "addNext": "воспроизвести следующим",
"playbackSpeed": "скорость воспроизведения", "playbackSpeed": "скорость воспроизведения",
"playbackFetchCancel": "это занимает некоторое время... закрыть уведомление для отмены", "playbackFetchCancel": "пожалуйста, подождите немного... закройте уведомление для отмены",
"play": "прослушать", "play": "играть",
"repeat_off": "повтор выключен", "repeat_off": "повтор выключен",
"pause": "пауза", "pause": "пауза",
"queue_clear": "очистить очередь", "queue_clear": "очистить очередь",
@ -328,13 +345,14 @@
"queue_moveToTop": "переместить выделенное вниз", "queue_moveToTop": "переместить выделенное вниз",
"queue_moveToBottom": "переместить выделенное вверх", "queue_moveToBottom": "переместить выделенное вверх",
"shuffle_off": "перемешивание выключено", "shuffle_off": "перемешивание выключено",
"addLast": "добавить последний", "addLast": "воспроизвести после всех",
"mute": "отключить звук", "mute": "отключить звук",
"skip_forward": "вперёд" "skip_forward": "вперёд",
"viewQueue": "показать очередь"
}, },
"page": { "page": {
"sidebar": { "sidebar": {
"nowPlaying": "Cейчас проигрывается", "nowPlaying": "сейчас играет",
"playlists": "$t(entity.playlist_other)", "playlists": "$t(entity.playlist_other)",
"search": "$t(common.search)", "search": "$t(common.search)",
"tracks": "$t(entity.track_other)", "tracks": "$t(entity.track_other)",
@ -354,30 +372,41 @@
"followCurrentLyric": "следовать за текущими словами песни", "followCurrentLyric": "следовать за текущими словами песни",
"opacity": "непрозрачность", "opacity": "непрозрачность",
"lyricSize": "размер слов", "lyricSize": "размер слов",
"showLyricProvider": "показать провайдера слов", "showLyricProvider": "показать источник слов",
"unsynchronized": "не синхронизировано", "unsynchronized": "не синхронизировано",
"lyricAlignment": "выравнивание слов песни", "lyricAlignment": "выравнивание слов песни",
"lyricOffset": "задержка слов (мсек)",
"useImageAspectRatio": "использовать соотношение сторон изображения", "useImageAspectRatio": "использовать соотношение сторон изображения",
"lyricGap": "пробел между словами", "lyricGap": "пробел между словами",
"dynamicIsImage": "включить фоновое изображение", "dynamicIsImage": "включить фоновое изображение",
"dynamicImageBlur": "сила размытия изображения" "dynamicImageBlur": "сила размытия изображения"
}, },
"upNext": "следующее", "upNext": "играет",
"lyrics": "слова песни", "lyrics": "слова",
"related": "схожие" "related": "похожие",
"visualizer": "визуализатор",
"noLyrics": "слова для песни не найдены"
}, },
"appMenu": { "appMenu": {
"selectServer": "выбрать сервер", "selectServer": "список серверов",
"version": "версия {{version}}", "version": "версия {{version}}",
"settings": "$t(common.setting_other)", "settings": "$t(common.setting_other)",
"manageServers": "настроить список серверов", "manageServers": "редактировать список серверов",
"expandSidebar": "развернуть", "expandSidebar": "развернуть боковую панель",
"collapseSidebar": "Скрыть боковую панель", "collapseSidebar": "Скрыть боковую панель",
"openBrowserDevtools": "открыть инструменты разработчика", "openBrowserDevtools": "открыть инструменты разработчика",
"quit": "$t(common.quit)", "quit": "$t(common.quit)",
"goBack": "назад", "goBack": "назад",
"goForward": "вперёд" "goForward": "вперёд"
}, },
"manageServers": {
"title": "сервера",
"serverDetails": "информация о сервере",
"url": "адрес",
"username": "пользователь",
"editServerDetailsTooltip": "изменить настройки сервера",
"removeServer": "удалить сервер"
},
"contextMenu": { "contextMenu": {
"addToPlaylist": "$t(action.addToPlaylist)", "addToPlaylist": "$t(action.addToPlaylist)",
"addToFavorites": "$t(action.addToFavorites)", "addToFavorites": "$t(action.addToFavorites)",
@ -390,6 +419,7 @@
"removeFromFavorites": "$t(action.removeFromFavorites)", "removeFromFavorites": "$t(action.removeFromFavorites)",
"addNext": "$t(player.addNext)", "addNext": "$t(player.addNext)",
"deselectAll": "$t(action.deselectAll)", "deselectAll": "$t(action.deselectAll)",
"download": "скачать",
"addLast": "$t(player.addLast)", "addLast": "$t(player.addLast)",
"addFavorite": "$t(action.addToFavorites)", "addFavorite": "$t(action.addToFavorites)",
"play": "$t(player.play)", "play": "$t(player.play)",
@ -399,11 +429,11 @@
"shareItem": "поделиться" "shareItem": "поделиться"
}, },
"home": { "home": {
"mostPlayed": "наибольшее кол-во воспроизведений", "mostPlayed": "слушают чаще всего",
"newlyAdded": "недавно добавленные релизы", "newlyAdded": "недавно добавленные релизы",
"title": "$t(common.home)", "title": "$t(common.home)",
"explore": "изучите вашу медиатеку", "explore": "откройте новое",
"recentlyPlayed": "недавно прослушано" "recentlyPlayed": "игралось недавно"
}, },
"albumDetail": { "albumDetail": {
"moreFromArtist": "больше от $t(entity.artist_one)", "moreFromArtist": "больше от $t(entity.artist_one)",
@ -420,8 +450,8 @@
}, },
"genreList": { "genreList": {
"title": "$t(entity.genre_other)", "title": "$t(entity.genre_other)",
"showAlbums": "показать $t(entity.genre_one) $t(entity.album_other)", "showAlbums": "показать $t(entity.genre_one) $t(entity.album_many)",
"showTracks": "показать $t(entity.genre_one) $t(entity.track_other)" "showTracks": "показать $t(entity.genre_one) $t(entity.track_many)"
}, },
"trackList": { "trackList": {
"title": "$t(entity.track_other)", "title": "$t(entity.track_other)",
@ -435,6 +465,9 @@
}, },
"title": "комманды" "title": "комманды"
}, },
"playlist": {
"reorder": "сортировка доступна только по ID"
},
"playlistList": { "playlistList": {
"title": "$t(entity.playlist_other)" "title": "$t(entity.playlist_other)"
}, },
@ -448,7 +481,7 @@
"viewAll": "посмотреть всё", "viewAll": "посмотреть всё",
"appearsOn": "появляется в", "appearsOn": "появляется в",
"viewDiscography": "посмотреть дискографию", "viewDiscography": "посмотреть дискографию",
"relatedArtists": "похож на $t(entity.artist_other)", "relatedArtists": "похож на $t(entity.artist_many)",
"viewAllTracks": "посмотреть все $t(entity.track_other)", "viewAllTracks": "посмотреть все $t(entity.track_other)",
"recentReleases": "недавние релизы", "recentReleases": "недавние релизы",
"about": "О {{artist}}", "about": "О {{artist}}",
@ -464,7 +497,7 @@
"deletePlaylist": { "deletePlaylist": {
"title": "удалить $t(entity.playlist_one)", "title": "удалить $t(entity.playlist_one)",
"success": "$t(entity.playlist_one) успешно удалён", "success": "$t(entity.playlist_one) успешно удалён",
"input_confirm": "напишите название $t(entity.playlist_one)а для подтверждения" "input_confirm": "напишите название $t(entity.playlist_few) для подтверждения"
}, },
"createPlaylist": { "createPlaylist": {
"input_description": "$t(common.description)", "input_description": "$t(common.description)",
@ -477,24 +510,24 @@
"addServer": { "addServer": {
"title": "добавить сервер", "title": "добавить сервер",
"input_username": "пользователь", "input_username": "пользователь",
"input_url": "url", "input_url": "адрес",
"input_password": "пароль", "input_password": "пароль",
"input_legacyAuthentication": "включить старую авторизацию", "input_legacyAuthentication": "включить старую авторизацию",
"input_name": "название сервера", "input_name": "название сервера",
"success": "сервер добавлен успешно", "success": "сервер успешно добавлен",
"input_savePassword": "сохранить пароль", "input_savePassword": "сохранить пароль",
"ignoreSsl": "игнорирование ssl ($t(common.restartRequired))", "ignoreSsl": "игнорировать ssl ($t(common.restartRequired))",
"ignoreCors": "игнорирование корсетов ($t(common.restartRequired))", "ignoreCors": "игнорировать CORS ($t(common.restartRequired))",
"error_savePassword": "произошла ошибка во время попытки сохранения пароля" "error_savePassword": "произошла ошибка при сохранении пароля"
}, },
"addToPlaylist": { "addToPlaylist": {
"success": "добавлено: $t(entity.trackWithCount, {\"count\": {{message}} }) в $t(entity.playlistWithCount, {\"count\": {{numOfPlaylists}} })", "success": "добавлено: $t(entity.trackWithCount, {\"count\": {{message}} }) в $t(entity.playlistWithCount, {\"count\": {{numOfPlaylists}} })",
"title": "добавить в $t(entity.playlist_one)", "title": "добавить в $t(entity.playlist_one)",
"input_skipDuplicates": "пропустить дубликаты", "input_skipDuplicates": "не добавлять дубликаты",
"input_playlists": "$t(entity.playlist_other)" "input_playlists": "$t(entity.playlist_other)"
}, },
"updateServer": { "updateServer": {
"title": "обновить сервер", "title": "обновление сервера",
"success": "сервер успешно обновлён" "success": "сервер успешно обновлён"
}, },
"queryEditor": { "queryEditor": {
@ -512,7 +545,7 @@
"shareItem": { "shareItem": {
"success": "ссылка скопирована в буфер обмена (нажмите здесь, чтобы открыть)", "success": "ссылка скопирована в буфер обмена (нажмите здесь, чтобы открыть)",
"expireInvalid": "время истечения срока действия должно быть в будущем", "expireInvalid": "время истечения срока действия должно быть в будущем",
"createFailed": "не удалось создать ссылку для общего доступа (общий доступ включён?)", "createFailed": "не удалось создать ссылку для общего доступа (проверьте, включен ли общий доступ?)",
"allowDownloading": "разрешить скачивание", "allowDownloading": "разрешить скачивание",
"setExpiration": "установить срок действия", "setExpiration": "установить срок действия",
"description": "описание" "description": "описание"
@ -521,16 +554,22 @@
"setting": { "setting": {
"accentColor": "цвет акцента", "accentColor": "цвет акцента",
"accentColor_description": "устанавливает цвет акцента для приложения", "accentColor_description": "устанавливает цвет акцента для приложения",
"albumBackground": "фоновое изображение альбомов",
"albumBackground_description": "добавляет фоновое изображение для страниц альбомов, содержащих обложку",
"albumBackgroundBlur": "размытие фонового изображения альбома",
"albumBackgroundBlur_description": "определяет степень размытия фонового изображения на странице альбомов",
"applicationHotkeys": "горячие клавиши приложения", "applicationHotkeys": "горячие клавиши приложения",
"crossfadeStyle_description": "выберите вид эффекта crossfade для аудиоплеера", "crossfadeStyle_description": "выберите вид эффекта crossfade для аудиоплеера",
"customCssEnable": "использовать кастомные css",
"customCssEnable_description": "разрешить использование кастомных css.",
"enableRemote_description": "включает сервер удалённого управления для управления воспроизведением с помощью других устройств", "enableRemote_description": "включает сервер удалённого управления для управления воспроизведением с помощью других устройств",
"fontType_optionSystem": "системный", "fontType_optionSystem": "системный",
"mpvExecutablePath_description": "укажите папку, в которой находится исполняющий файл аудиоплеера MPV. если оставить пустым, будет использоваться путь по умолчанию", "mpvExecutablePath_description": "укажите папку, в которой находится исполняющий файл аудиоплеера MPV. если оставить пустым, будет использоваться путь по умолчанию",
"crossfadeStyle": "Вид эффекта crossfade", "crossfadeStyle": "вид эффекта crossfade",
"fontType_optionBuiltIn": "встроенный", "fontType_optionBuiltIn": "встроенный",
"disableLibraryUpdateOnStartup": "Отключить проверку новых версий при запуске приложения", "disableLibraryUpdateOnStartup": "отключить проверку новых версий при запуске приложения",
"minimizeToTray_description": "Сворачивать приложение в панель уведомлений", "minimizeToTray_description": "сворачивать приложение в панель уведомлений",
"audioPlayer_description": "Укажите - какой аудиоплеер использовать для воспроизведения", "audioPlayer_description": "укажите, какой аудиоплеер использовать для воспроизведения",
"disableAutomaticUpdates": "отключить проверку обновлений", "disableAutomaticUpdates": "отключить проверку обновлений",
"exitToTray_description": "При закрытии приложения - оно останется в панели уведомлений", "exitToTray_description": "При закрытии приложения - оно останется в панели уведомлений",
"fontType_optionCustom": "пользовательский", "fontType_optionCustom": "пользовательский",
@ -544,7 +583,7 @@
"crossfadeDuration": "Длительность эффекта crossfade", "crossfadeDuration": "Длительность эффекта crossfade",
"audioPlayer": "Аудиоплеер", "audioPlayer": "Аудиоплеер",
"minimizeToTray": "сворачивать в панель уведомлений", "minimizeToTray": "сворачивать в панель уведомлений",
"font_description": "Выберите - какой шрифт использовать в приложении", "font_description": "Выберите, какой шрифт использовать в приложении",
"remoteUsername": "имя пользователя для доступа к серверу удалённого управления", "remoteUsername": "имя пользователя для доступа к серверу удалённого управления",
"buttonSize_description": "размер кнопок в панели управления воспроизведением", "buttonSize_description": "размер кнопок в панели управления воспроизведением",
"clearCache": "очистить кэш браузера", "clearCache": "очистить кэш браузера",
@ -554,11 +593,11 @@
"buttonSize": "размер кнопок панели управления воспроизведением", "buttonSize": "размер кнопок панели управления воспроизведением",
"hotkey_volumeDown": "уменьшить громкость", "hotkey_volumeDown": "уменьшить громкость",
"playButtonBehavior_optionAddLast": "$t(player.addLast)", "playButtonBehavior_optionAddLast": "$t(player.addLast)",
"theme_description": "устанавливает тему, которая будет использоваться приложением", "theme_description": "устанавливает тему, которая будет использоваться в приложении",
"passwordStore": "хранилище паролей/секретов", "passwordStore": "хранилище паролей/секретов",
"sidebarPlaylistList": "список плейлистов в боковой панели", "sidebarPlaylistList": "список плейлистов в боковой панели",
"windowBarStyle_description": "выберите стиль заголовка окна", "windowBarStyle_description": "выберите стиль заголовка окна",
"followLyric": "следовать тексту трека", "followLyric": "следовать за текстом трека",
"volumeWheelStep": "шаг регулировки громкости колёсиком мыши", "volumeWheelStep": "шаг регулировки громкости колёсиком мыши",
"windowBarStyle": "стиль заголовка окна", "windowBarStyle": "стиль заголовка окна",
"hotkey_zoomOut": "уменьшить масштаб", "hotkey_zoomOut": "уменьшить масштаб",
@ -567,7 +606,7 @@
"replayGainMode_optionAlbum": "$t(entity.album_one)", "replayGainMode_optionAlbum": "$t(entity.album_one)",
"replayGainMode_optionNone": "$t(common.none)", "replayGainMode_optionNone": "$t(common.none)",
"replayGainMode_optionTrack": "$t(entity.track_one)", "replayGainMode_optionTrack": "$t(entity.track_one)",
"clearQueryCache_description": "\"мягкая очистка\" feishin. при выполнении обновляются плейлисты, метаданные треков, но сохранённые тексты треков сбрасываются. настройки, учётные данные и кэшированные изображения сохраняются", "clearQueryCache_description": "так называемая \"мягкая очистка\" feishin: обновляются плейлисты, метаданные треков, но сохранённые тексты треков сбрасываются. настройки, учётные данные и кэшированные изображения сохраняются",
"hotkey_favoriteCurrentSong": "добавить $t(common.currentSong) в избранное", "hotkey_favoriteCurrentSong": "добавить $t(common.currentSong) в избранное",
"genreBehavior": "поведения страницы жанров", "genreBehavior": "поведения страницы жанров",
"globalMediaHotkeys": "глобальные мультимедийные горячие клавиши", "globalMediaHotkeys": "глобальные мультимедийные горячие клавиши",
@ -576,11 +615,11 @@
"hotkey_globalSearch": "глобальный поиск", "hotkey_globalSearch": "глобальный поиск",
"hotkey_playbackNext": "следующий трек", "hotkey_playbackNext": "следующий трек",
"hotkey_playbackPause": "пауза", "hotkey_playbackPause": "пауза",
"hotkey_playbackPlay": "прослушать", "hotkey_playbackPlay": "играть",
"hotkey_playbackPlayPause": "прослушать / пауза", "hotkey_playbackPlayPause": "играть / пауза",
"hotkey_playbackPrevious": "предыдущий трек", "hotkey_playbackPrevious": "предыдущий трек",
"hotkey_playbackStop": "остановить", "hotkey_playbackStop": "остановить",
"hotkey_rate0": "очистить оценку", "hotkey_rate0": "убрать оценку",
"hotkey_rate1": "оценить в 1 звезду", "hotkey_rate1": "оценить в 1 звезду",
"hotkey_rate2": "оценить в 2 звезды", "hotkey_rate2": "оценить в 2 звезды",
"hotkey_rate3": "оценить в 3 звезды", "hotkey_rate3": "оценить в 3 звезды",
@ -609,6 +648,8 @@
"playButtonBehavior_optionAddNext": "$t(player.addNext)", "playButtonBehavior_optionAddNext": "$t(player.addNext)",
"playButtonBehavior_optionPlay": "$t(player.play)", "playButtonBehavior_optionPlay": "$t(player.play)",
"playerAlbumArtResolution_description": "разрешение большой версии обложки альбома в проигрывателе. при большем разрешении она выглядит более четкой, но может замедлить загрузку. по умолчанию равно 0 - устанавливает разрешение автоматически", "playerAlbumArtResolution_description": "разрешение большой версии обложки альбома в проигрывателе. при большем разрешении она выглядит более четкой, но может замедлить загрузку. по умолчанию равно 0 - устанавливает разрешение автоматически",
"playerbarOpenDrawer": "полноэкранный переключатель по панели проигрывателя",
"playerbarOpenDrawer_description": "позволяет перейти в полноэкранный режим воспроизведения нажатием на панель проигрывателя",
"remotePort": "порт сервера удалённого управления", "remotePort": "порт сервера удалённого управления",
"remotePort_description": "устанавливает порт для сервера удалённого управления", "remotePort_description": "устанавливает порт для сервера удалённого управления",
"replayGainClipping": "{{ReplayGain}} клиппинг", "replayGainClipping": "{{ReplayGain}} клиппинг",
@ -622,11 +663,21 @@
"showSkipButtons": "показывать кнопки перемотки", "showSkipButtons": "показывать кнопки перемотки",
"showSkipButtons_description": "показывать или скрывать кнопки перемотки на панели управления воспроизведением", "showSkipButtons_description": "показывать или скрывать кнопки перемотки на панели управления воспроизведением",
"sidebarPlaylistList_description": "показать или скрыть список плейлистов на боковой панели", "sidebarPlaylistList_description": "показать или скрыть список плейлистов на боковой панели",
"sidePlayQueueStyle": "вид отображения боковой очереди",
"sidePlayQueueStyle_description": "определяет вид отображения боковой очереди",
"sidePlayQueueStyle_optionAttached": "закрепленная",
"sidePlayQueueStyle_optionDetached": "плавающая",
"skipDuration": "время перемотки", "skipDuration": "время перемотки",
"skipDuration_description": "задает время перемотки при использовании кнопок перемотки на панели проигрывателя", "skipDuration_description": "задает время перемотки при использовании кнопок перемотки на панели проигрывателя",
"useSystemTheme": "использовать тему системы", "useSystemTheme": "использовать тему системы",
"themeLight": "тема (светлая)", "themeLight": "тема (светлая)",
"themeLight_description": "устанавливает светлую тему приложения", "themeLight_description": "устанавливает светлую тему приложения",
"transcodeNote": "эффект применяется после 1 (для веб) - 2 (для mpv) песни",
"transcode": "включить транскодинг",
"transcode_description": "активирует транскодинг в другие форматы",
"transcodeBitrate": "битрейт транскодинга",
"transcodeBitrate_description": "выберите битрейт транскодинга. 0 - автоматическое определение сервером",
"transcodeFormat": "формат транкодинга",
"useSystemTheme_description": "использует тему, заданную в системе (светлую/тёмную)", "useSystemTheme_description": "использует тему, заданную в системе (светлую/тёмную)",
"zoom": "процент масштабирования", "zoom": "процент масштабирования",
"zoom_description": "устанавливает процент масштабирования приложения", "zoom_description": "устанавливает процент масштабирования приложения",
@ -634,6 +685,8 @@
"genreBehavior_description": "определяет, что отобразится при открытии на жанр — список треков или альбомов", "genreBehavior_description": "определяет, что отобразится при открытии на жанр — список треков или альбомов",
"globalMediaHotkeys_description": "включить или отключить использование системных мультимедийных горячих клавиш для управления воспроизведением", "globalMediaHotkeys_description": "включить или отключить использование системных мультимедийных горячих клавиш для управления воспроизведением",
"homeConfiguration_description": "позволяет настроить видимость и порядок элементов на домашней странице", "homeConfiguration_description": "позволяет настроить видимость и порядок элементов на домашней странице",
"homeFeature": "улучшенная карусель на главной",
"homeFeature_description": "определяет, показывать ли улучшенную карусель на главной странице",
"hotkey_toggleQueue": "показать/скрыть очередь воспроизведения", "hotkey_toggleQueue": "показать/скрыть очередь воспроизведения",
"imageAspectRatio": "использовать оригинальное соотношение сторон обложки", "imageAspectRatio": "использовать оригинальное соотношение сторон обложки",
"imageAspectRatio_description": "если эта опция включена, обложки будут отображаться в соответствии с их собственным соотношением сторон. для обложек не 1:1 оставшееся пространство будет пустым", "imageAspectRatio_description": "если эта опция включена, обложки будут отображаться в соответствии с их собственным соотношением сторон. для обложек не 1:1 оставшееся пространство будет пустым",
@ -658,8 +711,10 @@
"startMinimized": "запуск в свёрнутом режиме", "startMinimized": "запуск в свёрнутом режиме",
"themeDark_description": "устанавливает тёмную тему приложения", "themeDark_description": "устанавливает тёмную тему приложения",
"hotkey_volumeMute": "отключить звук", "hotkey_volumeMute": "отключить звук",
"clearCache_description": "\"жесткая очистка\" feishin. кроме очистки кэша feishin, также очищает кэш браузера (сохранённые картинки и другие ресурсы). учётные данные и настройки сохраняются", "clearCache_description": "\"жесткая очистка\" feishin: кроме очистки кэша feishin, также очищает кэш браузера (сохранённые картинки и другие ресурсы). учётные данные и настройки сохраняются",
"clearCacheSuccess": "кэш успешно удалён", "clearCacheSuccess": "кэш успешно удалён",
"contextMenu": "конфигурация контекстного меню (нажатие правой кнопкой мыши)",
"contextMenu_description": "позволяет скрыть элементы, отображаемые в меню, появляющемся при нажатии правой кнопки мыши на элемент. все, что не отмечено, будет скрыто",
"customFontPath": "путь к пользовательскому шрифту", "customFontPath": "путь к пользовательскому шрифту",
"customFontPath_description": "укажите путь к пользовательскому шрифту, который будет использоваться в приложении", "customFontPath_description": "укажите путь к пользовательскому шрифту, который будет использоваться в приложении",
"externalLinks_description": "включает отображение внешних ссылок (Last.fm, MusicBrainz) на страницах альбомов и артистов", "externalLinks_description": "включает отображение внешних ссылок (Last.fm, MusicBrainz) на страницах альбомов и артистов",
@ -681,6 +736,10 @@
"scrobble_description": "скробблинг треков на вашем медиасервере", "scrobble_description": "скробблинг треков на вашем медиасервере",
"startMinimized_description": "запуск приложения в области уведомлений", "startMinimized_description": "запуск приложения в области уведомлений",
"volumeWheelStep_description": "количество громкости, изменяемое при прокрутке колёсика мыши над ползунком громкости", "volumeWheelStep_description": "количество громкости, изменяемое при прокрутке колёсика мыши над ползунком громкости",
"volumeWidth": "ширина слайдера звука",
"volumeWidth_description": "ширина слайдера звука (в px)",
"webAudio": "использовать веб аудио",
"webAudio_description": "использование веб аудио. включение активирует продвинутые возможности (например, replaygain). отключите, если вам это не нужно",
"discordRichPresence": "состояние профиля {{discord}}", "discordRichPresence": "состояние профиля {{discord}}",
"discordApplicationId": "{{discord}} application id", "discordApplicationId": "{{discord}} application id",
"discordApplicationId_description": "application id приложения {{discord}} которое будет отображаться в статусе профиля (по умолчанию {{defaultId}})", "discordApplicationId_description": "application id приложения {{discord}} которое будет отображаться в статусе профиля (по умолчанию {{defaultId}})",
@ -688,9 +747,13 @@
"discordIdleStatus_description": "если включено, то обновляет статус, когда пользователь бездействует", "discordIdleStatus_description": "если включено, то обновляет статус, когда пользователь бездействует",
"discordUpdateInterval": "интервал обновления статуса профиля {{discord}}", "discordUpdateInterval": "интервал обновления статуса профиля {{discord}}",
"discordUpdateInterval_description": "время в секундах между каждым обновлением (минимум 15 секунд)", "discordUpdateInterval_description": "время в секундах между каждым обновлением (минимум 15 секунд)",
"doubleClickBehavior": "добавить в очередь все найденные треки при двойном клике",
"doubleClickBehavior_description": "есть включено: все найденные в поиске треки будут добавлены в очередь при двойном клике (иначе - только выбранный)",
"lyricOffset_description": "Смещение появления текста треков на указанное количество миллисекунд", "lyricOffset_description": "Смещение появления текста треков на указанное количество миллисекунд",
"skipPlaylistPage": "пропустить страницу плейлиста", "skipPlaylistPage": "пропускать страницу плейлиста",
"applicationHotkeys_description": "настройка горячих клавиш приложения. включите чекбокс, чтобы сделать горячую клавишу глобальной (только для ПК)", "applicationHotkeys_description": "настройка горячих клавиш приложения. поставьте галочку, чтобы сделать горячую клавишу глобальной (только для ПК)",
"artistConfiguration": "конфигурация страницы альбомов исполнителей",
"artistConfiguration_description": "позволяет настроить видимость и порядок элементов на странице альбомов исполнителей",
"fontType_description": "встроенный позволяет выбрать один из шрифтов, предоставляемых Feishin. системный позволяет выбрать любой шрифт, предоставляемый вашей операционной системой. пользовательский позволяет выбрать свой собственный шрифт", "fontType_description": "встроенный позволяет выбрать один из шрифтов, предоставляемых Feishin. системный позволяет выбрать любой шрифт, предоставляемый вашей операционной системой. пользовательский позволяет выбрать свой собственный шрифт",
"discordRichPresence_description": "включить статус воспроизведения в статус профиля в {{discord}}. Ключи изображений: {{icon}}, {{playing}} и {{paused}} ", "discordRichPresence_description": "включить статус воспроизведения в статус профиля в {{discord}}. Ключи изображений: {{icon}}, {{playing}} и {{paused}} ",
"lyricOffset": "синхронизация текста треков (мс)" "lyricOffset": "синхронизация текста треков (мс)"

View file

@ -207,7 +207,11 @@ export const FeatureCarousel = ({ data }: FeatureCarouselProps) => {
</Badge> </Badge>
))} ))}
<Badge size="lg">{currentItem?.releaseYear}</Badge> <Badge size="lg">{currentItem?.releaseYear}</Badge>
<Badge size="lg">{currentItem?.songCount} tracks</Badge> <Badge size="lg">
{t('entity.trackWithCount', {
count: currentItem?.songCount || 0,
})}
</Badge>
</Group> </Group>
<Group position="apart"> <Group position="apart">
<Button <Button

View file

@ -6,6 +6,7 @@ import { useSettingsStoreActions, useSettingsStore } from '/@/renderer/store/set
import { TableColumn, TableType } from '/@/renderer/types'; import { TableColumn, TableType } from '/@/renderer/types';
import { Option } from '/@/renderer/components/option'; import { Option } from '/@/renderer/components/option';
import i18n from '/@/i18n/i18n'; import i18n from '/@/i18n/i18n';
import { useTranslation } from 'react-i18next';
export const SONG_TABLE_COLUMNS = [ export const SONG_TABLE_COLUMNS = [
{ {
@ -285,6 +286,7 @@ interface TableConfigDropdownProps {
} }
export const TableConfigDropdown = ({ type }: TableConfigDropdownProps) => { export const TableConfigDropdown = ({ type }: TableConfigDropdownProps) => {
const { t } = useTranslation();
const { setSettings } = useSettingsStoreActions(); const { setSettings } = useSettingsStoreActions();
const tableConfig = useSettingsStore((state) => state.tables); const tableConfig = useSettingsStore((state) => state.tables);
@ -374,7 +376,9 @@ export const TableConfigDropdown = ({ type }: TableConfigDropdownProps) => {
return ( return (
<> <>
<Option> <Option>
<Option.Label>Auto-fit Columns</Option.Label> <Option.Label>
{t('table.config.general.autoFitColumns', { postProcess: 'sentenceCase' })}
</Option.Label>
<Option.Control> <Option.Control>
<Switch <Switch
defaultChecked={tableConfig[type]?.autoFit} defaultChecked={tableConfig[type]?.autoFit}
@ -384,7 +388,11 @@ export const TableConfigDropdown = ({ type }: TableConfigDropdownProps) => {
</Option> </Option>
{type !== 'albumDetail' && ( {type !== 'albumDetail' && (
<Option> <Option>
<Option.Label>Follow current song</Option.Label> <Option.Label>
{t('table.config.general.followCurrentSong', {
postProcess: 'sentenceCase',
})}
</Option.Label>
<Option.Control> <Option.Control>
<Switch <Switch
defaultChecked={tableConfig[type]?.followCurrentSong} defaultChecked={tableConfig[type]?.followCurrentSong}

View file

@ -37,7 +37,7 @@ const ActionRequiredRoute = () => {
const handleManageServersModal = () => { const handleManageServersModal = () => {
openModal({ openModal({
children: <ServerList />, children: <ServerList />,
title: 'Manage Servers', title: t('page.appMenu.manageServers', { postProcess: 'sentenceCase' }),
}); });
}; };

View file

@ -79,7 +79,9 @@ export const AlbumDetailHeader = forwardRef(
}, },
{ {
id: 'songCount', id: 'songCount',
value: `${detailQuery?.data?.songCount} songs`, value: t('entity.song_many', {
count: detailQuery?.data?.songCount as number,
}),
}, },
{ {
id: 'duration', id: 'duration',

View file

@ -511,7 +511,7 @@ export const AlbumListHeaderFilters = ({
}, },
}} }}
tooltip={{ tooltip={{
label: t('common.filter', { count: 2, postProcess: 'sentenceCase' }), label: t('common.filters', { count: 2, postProcess: 'sentenceCase' }),
}} }}
variant="subtle" variant="subtle"
onClick={handleOpenFiltersModal} onClick={handleOpenFiltersModal}
@ -589,7 +589,9 @@ export const AlbumListHeaderFilters = ({
</Button> </Button>
</DropdownMenu.Target> </DropdownMenu.Target>
<DropdownMenu.Dropdown> <DropdownMenu.Dropdown>
<DropdownMenu.Label>Display type</DropdownMenu.Label> <DropdownMenu.Label>
{t('table.config.general.displayType', { postProcess: 'sentenceCase' })}
</DropdownMenu.Label>
<DropdownMenu.Item <DropdownMenu.Item
$isActive={display === ListDisplayType.CARD} $isActive={display === ListDisplayType.CARD}
value={ListDisplayType.CARD} value={ListDisplayType.CARD}

View file

@ -446,7 +446,9 @@ export const AlbumArtistListHeaderFilters = ({
icon={<RiRefreshLine />} icon={<RiRefreshLine />}
onClick={handleRefresh} onClick={handleRefresh}
> >
Refresh {t('common.refresh', {
postProcess: 'titleCase',
})}
</DropdownMenu.Item> </DropdownMenu.Item>
</DropdownMenu.Dropdown> </DropdownMenu.Dropdown>
</DropdownMenu> </DropdownMenu>
@ -466,7 +468,9 @@ export const AlbumArtistListHeaderFilters = ({
</Button> </Button>
</DropdownMenu.Target> </DropdownMenu.Target>
<DropdownMenu.Dropdown> <DropdownMenu.Dropdown>
<DropdownMenu.Label>Display type</DropdownMenu.Label> <DropdownMenu.Label>
{t('table.config.general.displayType', { postProcess: 'sentenceCase' })}
</DropdownMenu.Label>
<DropdownMenu.Item <DropdownMenu.Item
$isActive={display === ListDisplayType.CARD} $isActive={display === ListDisplayType.CARD}
value={ListDisplayType.CARD} value={ListDisplayType.CARD}

View file

@ -876,7 +876,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
}, },
], ],
id: 'setRating', id: 'setRating',
label: 'Set rating', label: t('action.setRating', { postProcess: 'sentenceCase' }),
leftIcon: <RiStarFill size="1.1rem" />, leftIcon: <RiStarFill size="1.1rem" />,
onClick: () => {}, onClick: () => {},
rightIcon: <RiArrowRightSFill size="1.2rem" />, rightIcon: <RiArrowRightSFill size="1.2rem" />,

View file

@ -386,7 +386,7 @@ export const GenreListHeaderFilters = ({
</DropdownMenu.Target> </DropdownMenu.Target>
<DropdownMenu.Dropdown> <DropdownMenu.Dropdown>
<DropdownMenu.Label> <DropdownMenu.Label>
{t('table.config.general.displayType', { postProcess: 'titleCase' })} {t('table.config.general.displayType', { postProcess: 'sentenceCase' })}
</DropdownMenu.Label> </DropdownMenu.Label>
<DropdownMenu.Item <DropdownMenu.Item
$isActive={display === ListDisplayType.CARD} $isActive={display === ListDisplayType.CARD}
@ -423,7 +423,11 @@ export const GenreListHeaderFilters = ({
</DropdownMenu.Item> </DropdownMenu.Item>
{isGrid && ( {isGrid && (
<> <>
<DropdownMenu.Label>Item gap</DropdownMenu.Label> <DropdownMenu.Label>
{t('table.config.general.itemGap', {
postProcess: 'sentenceCase',
})}
</DropdownMenu.Label>
<DropdownMenu.Item closeMenuOnClick={false}> <DropdownMenu.Item closeMenuOnClick={false}>
<Slider <Slider
defaultValue={grid?.itemGap || 0} defaultValue={grid?.itemGap || 0}

View file

@ -2,6 +2,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
import { Center, Group } from '@mantine/core'; import { Center, Group } from '@mantine/core';
import { AnimatePresence, motion } from 'framer-motion'; import { AnimatePresence, motion } from 'framer-motion';
import { ErrorBoundary } from 'react-error-boundary'; import { ErrorBoundary } from 'react-error-boundary';
import { useTranslation } from 'react-i18next';
import { RiInformationFill } from 'react-icons/ri'; import { RiInformationFill } from 'react-icons/ri';
import styled from 'styled-components'; import styled from 'styled-components';
import { useSongLyricsByRemoteId, useSongLyricsBySong } from './queries/lyric-query'; import { useSongLyricsByRemoteId, useSongLyricsBySong } from './queries/lyric-query';
@ -86,6 +87,7 @@ const ScrollContainer = styled(motion.div)`
export const Lyrics = () => { export const Lyrics = () => {
const currentSong = useCurrentSong(); const currentSong = useCurrentSong();
const lyricsSettings = useLyricsSettings(); const lyricsSettings = useLyricsSettings();
const { t } = useTranslation();
const [index, setIndex] = useState(0); const [index, setIndex] = useState(0);
const [translatedLyrics, setTranslatedLyrics] = useState<string | null>(null); const [translatedLyrics, setTranslatedLyrics] = useState<string | null>(null);
const [showTranslation, setShowTranslation] = useState(false); const [showTranslation, setShowTranslation] = useState(false);
@ -217,7 +219,9 @@ export const Lyrics = () => {
order={3} order={3}
weight={700} weight={700}
> >
No lyrics found {t('page.fullscreenPlayer.noLyrics', {
postProcess: 'sentenceCase',
})}
</TextTitle> </TextTitle>
</Group> </Group>
</Center> </Center>

View file

@ -98,7 +98,7 @@ export const FullScreenPlayerQueue = () => {
items.push({ items.push({
active: activeTab === 'visualizer', active: activeTab === 'visualizer',
icon: <RiFileTextLine size="1.5rem" />, icon: <RiFileTextLine size="1.5rem" />,
label: t('page.fullscreenPlayer.visualizer'), label: t('page.fullscreenPlayer.visualizer', { postProcess: 'titleCase' }),
onClick: () => setStore({ activeTab: 'visualizer' }), onClick: () => setStore({ activeTab: 'visualizer' }),
}); });
} }

View file

@ -382,7 +382,11 @@ const Controls = () => {
</Option.Control> </Option.Control>
</Option> </Option>
<Option> <Option>
<Option.Label>Lyrics offset (ms)</Option.Label> <Option.Label>
{t('page.fullscreenPlayer.config.lyricOffset', {
postProcess: 'sentenceCase',
})}
</Option.Label>
<Option.Control> <Option.Control>
<NumberInput <NumberInput
defaultValue={lyricConfig.delayMs} defaultValue={lyricConfig.delayMs}

View file

@ -293,7 +293,10 @@ export const RightControls = () => {
{!isMinWidth ? ( {!isMinWidth ? (
<PlayerButton <PlayerButton
icon={<HiOutlineQueueList size="1.1rem" />} icon={<HiOutlineQueueList size="1.1rem" />}
tooltip={{ label: 'View queue', openDelay: 500 }} tooltip={{
label: t('player.viewQueue', { postProcess: 'titleCase' }),
openDelay: 500,
}}
variant="secondary" variant="secondary"
onClick={handleToggleQueue} onClick={handleToggleQueue}
/> />

View file

@ -596,7 +596,9 @@ export const PlaylistDetailSongListHeaderFilters = ({
</Button> </Button>
</DropdownMenu.Target> </DropdownMenu.Target>
<DropdownMenu.Dropdown> <DropdownMenu.Dropdown>
<DropdownMenu.Label>Display type</DropdownMenu.Label> <DropdownMenu.Label>
{t('table.config.general.displayType', { postProcess: 'sentenceCase' })}
</DropdownMenu.Label>
<DropdownMenu.Item <DropdownMenu.Item
$isActive={page.display === ListDisplayType.TABLE} $isActive={page.display === ListDisplayType.TABLE}
value={ListDisplayType.TABLE} value={ListDisplayType.TABLE}

View file

@ -400,7 +400,7 @@ export const PlaylistListHeaderFilters = ({
</DropdownMenu.Target> </DropdownMenu.Target>
<DropdownMenu.Dropdown> <DropdownMenu.Dropdown>
<DropdownMenu.Label> <DropdownMenu.Label>
{t('table.config.general.displayType', { postProcess: 'titleCase' })} {t('table.config.general.displayType', { postProcess: 'sentenceCase' })}
</DropdownMenu.Label> </DropdownMenu.Label>
<DropdownMenu.Item <DropdownMenu.Item
$isActive={display === ListDisplayType.CARD} $isActive={display === ListDisplayType.CARD}

View file

@ -467,11 +467,11 @@ export const PlaylistQueryBuilder = forwardRef(
<Select <Select
data={[ data={[
{ {
label: t('common.ascending', { postProcess: 'titleCase' }), label: t('common.ascending', { postProcess: 'sentenceCase' }),
value: 'asc', value: 'asc',
}, },
{ {
label: t('common.descending', { postProcess: 'titleCase' }), label: t('common.descending', { postProcess: 'sentenceCase' }),
value: 'desc', value: 'desc',
}, },
]} ]}

View file

@ -3,6 +3,7 @@ import { Stack, Group, Divider } from '@mantine/core';
import { Button, Text, TimeoutButton } from '/@/renderer/components'; import { Button, Text, TimeoutButton } from '/@/renderer/components';
import { useDisclosure } from '@mantine/hooks'; import { useDisclosure } from '@mantine/hooks';
import isElectron from 'is-electron'; import isElectron from 'is-electron';
import { useTranslation } from 'react-i18next';
import { RiDeleteBin2Line, RiEdit2Fill } from 'react-icons/ri'; import { RiDeleteBin2Line, RiEdit2Fill } from 'react-icons/ri';
import { EditServerForm } from '/@/renderer/features/servers/components/edit-server-form'; import { EditServerForm } from '/@/renderer/features/servers/components/edit-server-form';
import { ServerSection } from '/@/renderer/features/servers/components/server-section'; import { ServerSection } from '/@/renderer/features/servers/components/server-section';
@ -16,6 +17,7 @@ interface ServerListItemProps {
} }
export const ServerListItem = ({ server }: ServerListItemProps) => { export const ServerListItem = ({ server }: ServerListItemProps) => {
const { t } = useTranslation();
const [edit, editHandlers] = useDisclosure(false); const [edit, editHandlers] = useDisclosure(false);
const [savedPassword, setSavedPassword] = useState(''); const [savedPassword, setSavedPassword] = useState('');
const { deleteServer } = useAuthStoreActions(); const { deleteServer } = useAuthStoreActions();
@ -54,7 +56,11 @@ export const ServerListItem = ({ server }: ServerListItemProps) => {
<ServerSection <ServerSection
title={ title={
<Group position="apart"> <Group position="apart">
<Text>Server details</Text> <Text>
{t('page.manageServers.serverDetails', {
postProcess: 'sentenceCase',
})}
</Text>
</Group> </Group>
} }
> >
@ -68,8 +74,16 @@ export const ServerListItem = ({ server }: ServerListItemProps) => {
<Stack> <Stack>
<Group noWrap> <Group noWrap>
<Stack> <Stack>
<Text>URL</Text> <Text>
<Text>Username</Text> {t('page.manageServers.url', {
postProcess: 'sentenceCase',
})}
</Text>
<Text>
{t('page.manageServers.username', {
postProcess: 'sentenceCase',
})}
</Text>
</Stack> </Stack>
<Stack> <Stack>
<Text>{server.url}</Text> <Text>{server.url}</Text>
@ -79,11 +93,15 @@ export const ServerListItem = ({ server }: ServerListItemProps) => {
<Group grow> <Group grow>
<Button <Button
leftIcon={<RiEdit2Fill />} leftIcon={<RiEdit2Fill />}
tooltip={{ label: 'Edit server details' }} tooltip={{
label: t('page.manageServers.editServerDetailsTooltip', {
postProcess: 'sentenceCase',
}),
}}
variant="subtle" variant="subtle"
onClick={() => handleEdit()} onClick={() => handleEdit()}
> >
Edit {t('common.edit')}
</Button> </Button>
</Group> </Group>
</Stack> </Stack>
@ -95,7 +113,7 @@ export const ServerListItem = ({ server }: ServerListItemProps) => {
timeoutProps={{ callback: handleDeleteServer, duration: 1000 }} timeoutProps={{ callback: handleDeleteServer, duration: 1000 }}
variant="subtle" variant="subtle"
> >
Remove server {t('page.manageServers.removeServer', { postProcess: 'sentenceCase' })}
</TimeoutButton> </TimeoutButton>
</Stack> </Stack>
); );

View file

@ -16,8 +16,8 @@ export const OrderToggleButton = ({ sortOrder, onToggle, buttonProps }: OrderTog
<Tooltip <Tooltip
label={ label={
sortOrder === SortOrder.ASC sortOrder === SortOrder.ASC
? t('common.ascending', { postProcess: 'titleCase' }) ? t('common.ascending', { postProcess: 'sentenceCase' })
: t('common.descending', { postProcess: 'titleCase' }) : t('common.descending', { postProcess: 'sentenceCase' })
} }
> >
<Button <Button

View file

@ -609,7 +609,7 @@ export const SongListHeaderFilters = ({
icon={<RiRefreshLine />} icon={<RiRefreshLine />}
onClick={handleRefresh} onClick={handleRefresh}
> >
Refresh {t('common.refresh', { postProcess: 'titleCase' })}
</DropdownMenu.Item> </DropdownMenu.Item>
</DropdownMenu.Dropdown> </DropdownMenu.Dropdown>
</DropdownMenu> </DropdownMenu>

View file

@ -76,7 +76,7 @@ export const AppMenu = () => {
const handleManageServersModal = () => { const handleManageServersModal = () => {
openModal({ openModal({
children: <ServerList />, children: <ServerList />,
title: 'Manage Servers', title: t('page.manageServers.title', { postProcess: 'titleCase' }),
}); });
}; };