Add missing translations

This commit is contained in:
jeffvli
2023-10-28 03:56:48 -07:00
parent 15eb4a70aa
commit fbc23d545c
14 changed files with 268 additions and 198 deletions
+168 -160
View File
@@ -2,10 +2,12 @@
"action": { "action": {
"addToFavorites": "add to $t(entity.favorite_other)", "addToFavorites": "add to $t(entity.favorite_other)",
"addToPlaylist": "add to $t(entity.playlist_one)", "addToPlaylist": "add to $t(entity.playlist_one)",
"clearQueue": "clear queue",
"createPlaylist": "create $t(entity.playlist_one)", "createPlaylist": "create $t(entity.playlist_one)",
"deletePlaylist": "delete $t(entity.playlist_one)", "deletePlaylist": "delete $t(entity.playlist_one)",
"deselectAll": "deselect all", "deselectAll": "deselect all",
"editPlaylist": "edit $t(entity.playlist_one)", "editPlaylist": "edit $t(entity.playlist_one)",
"goToPage": "go to page",
"moveToBottom": "move to bottom", "moveToBottom": "move to bottom",
"moveToTop": "move to top", "moveToTop": "move to top",
"refresh": "$t(glossary.refresh)", "refresh": "$t(glossary.refresh)",
@@ -17,43 +19,46 @@
"viewPlaylists": "view $t(entity.playlist_other)" "viewPlaylists": "view $t(entity.playlist_other)"
}, },
"common": { "common": {
"currentSong": "current $t(entity.track_one)",
"previousSong": "previous $t(entity.track_one)",
"backward": "backward",
"forward": "forward",
"modified": "modified",
"minimize": "minimize",
"increase": "increase",
"decrease": "decrease",
"maximize": "maximize",
"areYouSure": "are you sure?",
"resetToDefault": "reset to default",
"manage": "manage",
"add": "add", "add": "add",
"areYouSure": "are you sure?",
"backward": "backward",
"cancel": "cancel", "cancel": "cancel",
"center": "center",
"comingSoon": "coming soon...",
"confirm": "confirm", "confirm": "confirm",
"create": "create", "create": "create",
"currentSong": "current $t(entity.track_one)",
"decrease": "decrease",
"delete": "delete", "delete": "delete",
"disable": "disable", "disable": "disable",
"dismiss": "dismiss", "dismiss": "dismiss",
"edit": "edit", "edit": "edit",
"enable": "enable", "enable": "enable",
"filters": "filters",
"forceRestartRequired": "restart to apply changes... close the notification to restart",
"forward": "forward",
"increase": "increase",
"left": "left",
"manage": "manage",
"maximize": "maximize",
"minimize": "minimize",
"modified": "modified",
"no": "no", "no": "no",
"none": "none", "none": "none",
"noResultsFromQuery": "the query returned no results",
"ok": "ok", "ok": "ok",
"playerMustBePaused": "player must be paused", "playerMustBePaused": "player must be paused",
"previousSong": "previous $t(entity.track_one)",
"quit": "quit", "quit": "quit",
"resetToDefault": "reset to default",
"restartRequired": "restart required", "restartRequired": "restart required",
"forceRestartRequired": "restart to apply changes... close the notification to restart",
"save": "save",
"saveAs": "save as",
"saveAndReplace": "save and replace",
"yes": "yes",
"left": "left",
"center": "center",
"right": "right", "right": "right",
"save": "save",
"saveAndReplace": "save and replace",
"saveAs": "save as",
"search": "search", "search": "search",
"noResultsFromQuery": "the query returned no results" "unknown": "unknown",
"yes": "yes"
}, },
"entity": { "entity": {
"album_one": "album", "album_one": "album",
@@ -82,8 +87,6 @@
"playlist_other": "playlists", "playlist_other": "playlists",
"playlistWithCount_one": "{{count}} playlist", "playlistWithCount_one": "{{count}} playlist",
"playlistWithCount_other": "{{count}} playlists", "playlistWithCount_other": "{{count}} playlists",
"setting_one": "setting",
"setting_other": "settings",
"smartPlaylist": "smart $t(entity.playlist_one)", "smartPlaylist": "smart $t(entity.playlist_one)",
"track_one": "track", "track_one": "track",
"track_other": "tracks", "track_other": "tracks",
@@ -91,79 +94,27 @@
"trackWithCount_other": "{{count}} tracks" "trackWithCount_other": "{{count}} tracks"
}, },
"error": { "error": {
"playbackError": "an error occurred when trying to play the media",
"genericError": "an error occurred",
"apiRouteError": "unable to route request", "apiRouteError": "unable to route request",
"serverNotSelectedError": "no server selected",
"endpointNotImplementedError": "endpoint {{endpoint} is not implemented for {{serverType}}",
"audioDeviceFetchError": "an error occurred when trying to get audio devices", "audioDeviceFetchError": "an error occurred when trying to get audio devices",
"authenticationFailed": "authentication failed",
"credentialsRequired": "credentials required",
"endpointNotImplementedError": "endpoint {{endpoint} is not implemented for {{serverType}}",
"genericError": "an error occurred",
"invalidServer": "invalid server",
"localFontAccessDenied": "access denied to local fonts", "localFontAccessDenied": "access denied to local fonts",
"loginRateError": "too many login attempts, please try again in a few seconds",
"mpvRequired": "MPV required",
"playbackError": "an error occurred when trying to play the media",
"remoteDisableError": "an error occurred when trying to $t(common.disable) the remote server", "remoteDisableError": "an error occurred when trying to $t(common.disable) the remote server",
"remoteEnableError": "an error occurred when trying to $t(common.enable) the remote server", "remoteEnableError": "an error occurred when trying to $t(common.enable) the remote server",
"remotePortError": "an error occurred when trying to set the remote server port", "remotePortError": "an error occurred when trying to set the remote server port",
"remotePortWarning": "restart the server to apply the new port", "remotePortWarning": "restart the server to apply the new port",
"systemFontError": "an error occurred when trying to get system fonts", "serverNotSelectedError": "no server selected",
"invalidServer": "invalid server", "serverRequired": "server required",
"authenticationFailed": "authentication failed",
"sessionExpiredError": "your session has expired", "sessionExpiredError": "your session has expired",
"loginRateError": "too many login attempts, please try again in a few seconds", "systemFontError": "an error occurred when trying to get system fonts"
"mpvRequired": "MPV required",
"credentialsRequired": "credentials required",
"serverRequired": "server required"
},
"form": {
"addServer": {
"title": "add server",
"input_name": "server name",
"input_url": "url",
"input_username": "username",
"input_password": "password",
"input_savePassword": "save password",
"input_legacyAuthentication": "enable legacy authentication",
"ignoreCors": "ignore cors ($t(common.restartRequired))",
"ignoreSsl": "ignore ssl ($t(common.restartRequired))",
"success": "server added successfully",
"error_savePassword": "an error occurred when trying to save the password"
},
"createPlaylist": {
"title": "create $t(entity.playlist_one)",
"input_name": "$t(glossary.name)",
"input_description": "$t(glossary.description)",
"input_public": "public",
"input_owner": "$t(glossary.owner)",
"success": "$t(entity.playlist_one) created successfully"
},
"editPlaylist": {
"title": "edit $t(entity.playlist_one)"
},
"deletePlaylist": {
"title": "delete $t(entity.playlist_one)",
"input_confirm": "type the name of the $t(entity.playlist_one) to confirm",
"success": "$t(entity.playlist_one) deleted successfully"
},
"addToPlaylist": {
"title": "add to $t(entity.playlist_one)",
"input_playlists": "$t(entity.playlist_other)",
"input_skipDuplicates": "skip duplicates",
"success": "added {{message}} $t(entity.song_other) to {{numOfPlaylists}} $t(entity.playlist_other)"
},
"updateServer": {
"title": "update server",
"success": "server updated successfully"
},
"lyricSearch": {
"title": "lyric search",
"input_name": "$t(glossary.name)",
"input_artist": "$t(entity.artist_one)"
}
}, },
"filter": { "filter": {
"isRated": "is rated",
"isFavorited": "is favorited",
"isCompilation": "is compilation",
"isRecentlyPlayed": "is recently played",
"fromYear": "from year",
"toYear": "to year",
"albumArtist": "$t(entity.albumArtist_one)", "albumArtist": "$t(entity.albumArtist_one)",
"artist": "$t(entity.artist_one)", "artist": "$t(entity.artist_one)",
"biography": "biography", "biography": "biography",
@@ -175,6 +126,11 @@
"disc": "disc", "disc": "disc",
"duration": "duration", "duration": "duration",
"favorited": "favorited", "favorited": "favorited",
"fromYear": "from year",
"isCompilation": "is compilation",
"isFavorited": "is favorited",
"isRated": "is rated",
"isRecentlyPlayed": "is recently played",
"lastPlayed": "last played", "lastPlayed": "last played",
"mostPlayed": "most played", "mostPlayed": "most played",
"name": "name", "name": "name",
@@ -190,16 +146,61 @@
"search": "search", "search": "search",
"songCount": "song count", "songCount": "song count",
"title": "title", "title": "title",
"toYear": "to year",
"trackNumber": "track" "trackNumber": "track"
}, },
"form": {
"addServer": {
"error_savePassword": "an error occurred when trying to save the password",
"ignoreCors": "ignore cors ($t(common.restartRequired))",
"ignoreSsl": "ignore ssl ($t(common.restartRequired))",
"input_legacyAuthentication": "enable legacy authentication",
"input_name": "server name",
"input_password": "password",
"input_savePassword": "save password",
"input_url": "url",
"input_username": "username",
"success": "server added successfully",
"title": "add server"
},
"addToPlaylist": {
"input_playlists": "$t(entity.playlist_other)",
"input_skipDuplicates": "skip duplicates",
"success": "added {{message}} $t(entity.song_other) to {{numOfPlaylists}} $t(entity.playlist_other)",
"title": "add to $t(entity.playlist_one)"
},
"createPlaylist": {
"input_description": "$t(glossary.description)",
"input_name": "$t(glossary.name)",
"input_owner": "$t(glossary.owner)",
"input_public": "public",
"success": "$t(entity.playlist_one) created successfully",
"title": "create $t(entity.playlist_one)"
},
"deletePlaylist": {
"input_confirm": "type the name of the $t(entity.playlist_one) to confirm",
"success": "$t(entity.playlist_one) deleted successfully",
"title": "delete $t(entity.playlist_one)"
},
"editPlaylist": {
"title": "edit $t(entity.playlist_one)"
},
"lyricSearch": {
"input_artist": "$t(entity.artist_one)",
"input_name": "$t(glossary.name)",
"title": "lyric search"
},
"queryEditor": {
"input_optionMatchAll": "match all",
"input_optionMatchAny": "match any"
},
"updateServer": {
"success": "server updated successfully",
"title": "update server"
}
},
"glossary": { "glossary": {
"sortOrder": "order",
"limit": "limit",
"reset": "reset",
"clear": "clear",
"action": "action", "action": "action",
"expand": "expand",
"collapse": "collapse",
"action_other": "actions", "action_other": "actions",
"ascending": "ascending", "ascending": "ascending",
"biography": "biography", "biography": "biography",
@@ -207,16 +208,20 @@
"bpm": "bpm", "bpm": "bpm",
"channel": "channel", "channel": "channel",
"channel_other": "channels", "channel_other": "channels",
"clear": "clear",
"collapse": "collapse",
"configure": "configure", "configure": "configure",
"descending": "descending", "descending": "descending",
"description": "description",
"disc": "disc", "disc": "disc",
"duration": "duration", "duration": "duration",
"expand": "expand",
"favorite": "favorite", "favorite": "favorite",
"filter_one": "filter", "filter_one": "filter",
"filter_other": "filters", "filter_other": "filters",
"description": "description",
"gap": "gap", "gap": "gap",
"home": "home", "home": "home",
"limit": "limit",
"menu": "menu", "menu": "menu",
"name": "name", "name": "name",
"note": "note", "note": "note",
@@ -225,29 +230,25 @@
"random": "random", "random": "random",
"rating": "rating", "rating": "rating",
"refresh": "refresh", "refresh": "refresh",
"reset": "reset",
"search": "search", "search": "search",
"setting": "setting", "setting": "setting",
"setting_other": "settings", "setting_other": "settings",
"size": "size", "size": "size",
"sortOrder": "order",
"title": "title", "title": "title",
"trackNumber": "track", "trackNumber": "track",
"version": "version", "version": "version",
"year": "year" "year": "year"
}, },
"page": { "page": {
"albumArtistList": {
"title": "$t(entity.albumArtist_other)"
},
"albumDetail": { "albumDetail": {
"moreFromArtist": "more from this $t(entity.genre_one)", "moreFromArtist": "more from this $t(entity.genre_one)",
"moreFromGeneric": "more from {{item}}" "moreFromGeneric": "more from {{item}}"
}, },
"setting": {
"generalTab": "general",
"playbackTab": "playback",
"hotkeysTab": "hotkeys",
"windowTab": "window"
},
"albumArtistList": {
"title": "$t(entity.albumArtist_other)"
},
"albumList": { "albumList": {
"title": "$t(entity.album_other)" "title": "$t(entity.album_other)"
}, },
@@ -281,9 +282,35 @@
"removeFromQueue": "$t(action.removeFromQueue)", "removeFromQueue": "$t(action.removeFromQueue)",
"setRating": "$t(action.setRating)" "setRating": "$t(action.setRating)"
}, },
"fullscreenPlayer": {
"config": {
"dynamicBackground": "dynamic background",
"followCurrentLyric": "follow current lyric",
"lyricAlignment": "lyric alignment",
"lyricGap": "lyric gap",
"lyricSize": "lyric size",
"opacity": "opacity",
"showLyricMatch": "show lyric match",
"showLyricProvider": "show lyric provider",
"synchronized": "synchronized",
"unsynchronized": "unsynchronized",
"useImageAspectRatio": "use image aspect ratio"
},
"lyrics": "lyrics",
"related": "related",
"upNext": "up next"
},
"genreList": { "genreList": {
"title": "$t(entity.genre_other)" "title": "$t(entity.genre_other)"
}, },
"globalSearch": {
"commands": {
"goToPage": "go to page",
"searchFor": "search for {{query}}",
"serverCommands": "server commands"
},
"title": "commands"
},
"home": { "home": {
"explore": "explore from your library", "explore": "explore from your library",
"mostPlayed": "most played", "mostPlayed": "most played",
@@ -294,10 +321,16 @@
"playlistList": { "playlistList": {
"title": "$t(entity.playlist_other)" "title": "$t(entity.playlist_other)"
}, },
"setting": {
"generalTab": "general",
"hotkeysTab": "hotkeys",
"playbackTab": "playback",
"windowTab": "window"
},
"sidebar": { "sidebar": {
"albumArtists": "$t(entity.albumArtist_other)",
"albums": "$t(entity.album_other)", "albums": "$t(entity.album_other)",
"artists": "$t(entity.artist_other)", "artists": "$t(entity.artist_other)",
"albumArtists": "$t(entity.albumArtist_other)",
"folders": "$t(entity.folder_other)", "folders": "$t(entity.folder_other)",
"genres": "$t(entity.genre_other)", "genres": "$t(entity.genre_other)",
"home": "$t(glossary.home)", "home": "$t(glossary.home)",
@@ -309,40 +342,21 @@
}, },
"trackList": { "trackList": {
"title": "$t(entity.track_other)" "title": "$t(entity.track_other)"
},
"globalSearch": {
"title": "commands",
"commands": {
"searchFor": "search for {{query}}",
"goToPage": "go to page",
"serverCommands": "server commands"
}
},
"fullscreenPlayer": {
"config": {
"dynamicBackground": "dynamic background",
"useImageAspectRatio": "use image aspect ratio",
"opacity": "opacity",
"followCurrentLyric": "follow current lyric",
"showLyricProvider": "show lyric provider",
"showLyricMatch": "show lyric match",
"lyricSize": "lyric size",
"synchronized": "synchronized",
"unsynchronized": "unsynchronized",
"lyricGap": "lyric gap",
"lyricAlignment": "lyric alignment"
}
} }
}, },
"player": { "player": {
"favorite": "favorite",
"unfavorite": "unfavorite",
"addLast": "add last", "addLast": "add last",
"addNext": "add next", "addNext": "add next",
"favorite": "favorite",
"mute": "mute", "mute": "mute",
"muted": "muted", "muted": "muted",
"next": "next", "next": "next",
"play": "play", "play": "play",
"playbackFetchCancel": "this is taking a while... close the notification to cancel",
"playbackFetchInProgress": "loading songs...",
"playbackFetchNoResults": "no songs found",
"playbackSpeed": "playback speed",
"playRandom": "play random",
"previous": "previous", "previous": "previous",
"queue_clear": "clear queue", "queue_clear": "clear queue",
"queue_moveToBottom": "move selected to top", "queue_moveToBottom": "move selected to top",
@@ -352,36 +366,16 @@
"repeat_all": "repeat all", "repeat_all": "repeat all",
"repeat_off": "repeat disabled", "repeat_off": "repeat disabled",
"repeat_one": "repeat one", "repeat_one": "repeat one",
"shuffle": "shuffle",
"shuffle_off": "shuffle disabled",
"skip": "skip", "skip": "skip",
"skip_back": "skip backwards", "skip_back": "skip backwards",
"skip_forward": "skip forwards", "skip_forward": "skip forwards",
"shuffle": "shuffle",
"playRandom": "play random",
"shuffle_off": "shuffle disabled",
"stop": "stop", "stop": "stop",
"toggleFullscreenPlayer": "toggle fullscreen player", "toggleFullscreenPlayer": "toggle fullscreen player",
"playbackSpeed": "playback speed", "unfavorite": "unfavorite"
"playbackFetchNoResults": "no songs found",
"playbackFetchInProgress": "loading songs...",
"playbackFetchCancel": "this is taking a while... close the notification to cancel"
}, },
"setting": { "setting": {
"exitToTray": "exit to tray",
"exitToTray_description": "exit the application to the system tray",
"minimizeToTray": "minimize to tray",
"minimizeToTray_description": "minimize the application to the system tray",
"windowBarStyle": "window bar style",
"windowBarStyle_description": "select the style of the window bar",
"disableAutomaticUpdates": "disable automatic updates",
"disableLibraryUpdateOnStartup": "disable checking for new versions on startup",
"discordRichPresence": "{{discord}} rich presence",
"discordRichPresence_description": "enable playback status in {{discord}} rich presence. Image keys are: {{icon}}, {{playing}}, and {{paused}} ",
"discordApplicationId": "{{discord}} application id",
"discordApplicationId_description": "the application id for {{discord}} rich presence (defaults to {{defaultId}}",
"discordUpdateInterval": "{{discord}} rich presence update interval",
"discordUpdateInterval_description": "the time in seconds between each update (minimum 15 seconds)",
"discordIdleStatus": "show rich presence idle status",
"discordIdleStatus_description": "when enabled, update status while player is idle",
"accentColor": "accent color", "accentColor": "accent color",
"accentColor_description": "sets the accent color for the application", "accentColor_description": "sets the accent color for the application",
"applicationHotkeys": "application hotkeys", "applicationHotkeys": "application hotkeys",
@@ -398,8 +392,20 @@
"crossfadeStyle_description": "select the crossfade style to use for the audio player", "crossfadeStyle_description": "select the crossfade style to use for the audio player",
"customFontPath": "custom font path", "customFontPath": "custom font path",
"customFontPath_description": "sets the path to the custom font to use for the application", "customFontPath_description": "sets the path to the custom font to use for the application",
"disableAutomaticUpdates": "disable automatic updates",
"disableLibraryUpdateOnStartup": "disable checking for new versions on startup",
"discordApplicationId": "{{discord}} application id",
"discordApplicationId_description": "the application id for {{discord}} rich presence (defaults to {{defaultId}}",
"discordIdleStatus": "show rich presence idle status",
"discordIdleStatus_description": "when enabled, update status while player is idle",
"discordRichPresence": "{{discord}} rich presence",
"discordRichPresence_description": "enable playback status in {{discord}} rich presence. Image keys are: {{icon}}, {{playing}}, and {{paused}} ",
"discordUpdateInterval": "{{discord}} rich presence update interval",
"discordUpdateInterval_description": "the time in seconds between each update (minimum 15 seconds)",
"enableRemote": "enable remote control server", "enableRemote": "enable remote control server",
"enableRemote_description": "enables the remote control server to allow other devices to control the application", "enableRemote_description": "enables the remote control server to allow other devices to control the application",
"exitToTray": "exit to tray",
"exitToTray_description": "exit the application to the system tray",
"floatingQueueArea": "show floating queue hover area", "floatingQueueArea": "show floating queue hover area",
"floatingQueueArea_description": "display a hover icon on the right side of the screen to view the play queue", "floatingQueueArea_description": "display a hover icon on the right side of the screen to view the play queue",
"followLyric": "follow current lyric", "followLyric": "follow current lyric",
@@ -416,14 +422,10 @@
"gaplessAudio_optionWeak": "weak (recommended)", "gaplessAudio_optionWeak": "weak (recommended)",
"globalMediaHotkeys": "global media hotkeys", "globalMediaHotkeys": "global media hotkeys",
"globalMediaHotkeys_description": "enable or disable the usage of your system media hotkeys to control playback", "globalMediaHotkeys_description": "enable or disable the usage of your system media hotkeys to control playback",
"hotkey_favoriteCurrentSong": "favorite $t(common.currentSong)",
"hotkey_unfavoriteCurrentSong": "unfavorite $t(common.currentSong)",
"hotkey_toggleCurrentSongFavorite": "toggle $t(common.currentSong) favorite",
"hotkey_favoritePreviousSong": "favorite $t(common.previousSong)",
"hotkey_unfavoritePreviousSong": "unfavorite $t(common.previousSong)",
"hotkey_togglePreviousSongFavorite": "toggle $t(common.previousSong) favorite",
"hotkey_browserBack": "browser back", "hotkey_browserBack": "browser back",
"hotkey_browserForward": "browser forward", "hotkey_browserForward": "browser forward",
"hotkey_favoriteCurrentSong": "favorite $t(common.currentSong)",
"hotkey_favoritePreviousSong": "favorite $t(common.previousSong)",
"hotkey_globalSearch": "global search", "hotkey_globalSearch": "global search",
"hotkey_localSearch": "in-page search", "hotkey_localSearch": "in-page search",
"hotkey_playbackNext": "next track", "hotkey_playbackNext": "next track",
@@ -440,23 +442,29 @@
"hotkey_rate5": "rating 5 stars", "hotkey_rate5": "rating 5 stars",
"hotkey_skipBackward": "skip backward", "hotkey_skipBackward": "skip backward",
"hotkey_skipForward": "skip forward", "hotkey_skipForward": "skip forward",
"hotkey_toggleCurrentSongFavorite": "toggle $t(common.currentSong) favorite",
"hotkey_toggleFullScreenPlayer": "toggle full screen player", "hotkey_toggleFullScreenPlayer": "toggle full screen player",
"hotkey_togglePreviousSongFavorite": "toggle $t(common.previousSong) favorite",
"hotkey_toggleQueue": "toggle queue", "hotkey_toggleQueue": "toggle queue",
"hotkey_toggleRepeat": "toggle repeat", "hotkey_toggleRepeat": "toggle repeat",
"hotkey_toggleShuffle": "toggle shuffle", "hotkey_toggleShuffle": "toggle shuffle",
"hotkey_unfavoriteCurrentSong": "unfavorite $t(common.currentSong)",
"hotkey_unfavoritePreviousSong": "unfavorite $t(common.previousSong)",
"hotkey_volumeDown": "volume down", "hotkey_volumeDown": "volume down",
"hotkey_volumeMute": "volume mute", "hotkey_volumeMute": "volume mute",
"hotkey_volumeUp": "volume up", "hotkey_volumeUp": "volume up",
"hotkey_zoomIn": "zoom in", "hotkey_zoomIn": "zoom in",
"hotkey_zoomOut": "zoom out", "hotkey_zoomOut": "zoom out",
"language": "language", "language": "language",
"language_description": "sets the language for the application", "language_description": "sets the language for the application ($t(common.restartRequired))",
"lyricFetch": "fetch lyrics from the internet", "lyricFetch": "fetch lyrics from the internet",
"lyricFetch_description": "fetch lyrics from various internet sources", "lyricFetch_description": "fetch lyrics from various internet sources",
"lyricFetchProvider": "providers to fetch lyrics from", "lyricFetchProvider": "providers to fetch lyrics from",
"lyricFetchProvider_description": "select the providers to fetch lyrics from. the order of the providers is the order in which they will be queried", "lyricFetchProvider_description": "select the providers to fetch lyrics from. the order of the providers is the order in which they will be queried",
"lyricOffset": "lyric offset (ms)", "lyricOffset": "lyric offset (ms)",
"lyricOffset_description": "offset the lyric by the specified amount of milliseconds", "lyricOffset_description": "offset the lyric by the specified amount of milliseconds",
"minimizeToTray": "minimize to tray",
"minimizeToTray_description": "minimize the application to the system tray",
"minimumScrobblePercentage": "minimum scrobble duration (percentage)", "minimumScrobblePercentage": "minimum scrobble duration (percentage)",
"minimumScrobblePercentage_description": "the minimum percentage of the song that must be played before it is scrobbled", "minimumScrobblePercentage_description": "the minimum percentage of the song that must be played before it is scrobbled",
"minimumScrobbleSeconds": "minimum scrobble (seconds)", "minimumScrobbleSeconds": "minimum scrobble (seconds)",
@@ -525,10 +533,10 @@
"useSystemTheme_description": "follow the system-defined light or dark preference", "useSystemTheme_description": "follow the system-defined light or dark preference",
"volumeWheelStep": "volume wheel step", "volumeWheelStep": "volume wheel step",
"volumeWheelStep_description": "the amount of volume to change when scrolling the mouse wheel on the volume slider", "volumeWheelStep_description": "the amount of volume to change when scrolling the mouse wheel on the volume slider",
"windowBarStyle": "window bar style",
"windowBarStyle_description": "select the style of the window bar",
"zoom": "zoom percentage", "zoom": "zoom percentage",
"zoom_description": "sets the zoom percentage for the application", "zoom_description": "sets the zoom percentage for the application"
"zoomPercentage": "zoom percentage",
"zoomPercentage_description": "sets the zoom percentage for the application"
}, },
"table": { "table": {
"column": { "column": {
@@ -6,14 +6,21 @@ import { Button } from '/@/renderer/components/button';
import { DropdownMenu } from '/@/renderer/components/dropdown-menu'; import { DropdownMenu } from '/@/renderer/components/dropdown-menu';
import { QueryBuilderOption } from '/@/renderer/components/query-builder/query-builder-option'; import { QueryBuilderOption } from '/@/renderer/components/query-builder/query-builder-option';
import { QueryBuilderGroup, QueryBuilderRule } from '/@/renderer/types'; import { QueryBuilderGroup, QueryBuilderRule } from '/@/renderer/types';
import i18n from '/@/i18n/i18n';
const FILTER_GROUP_OPTIONS_DATA = [ const FILTER_GROUP_OPTIONS_DATA = [
{ {
label: 'Match all', label: i18n.t('form.queryEditor.input', {
context: 'optionMatchAll',
postProcess: 'sentenceCase',
}),
value: 'all', value: 'all',
}, },
{ {
label: 'Match any', label: i18n.t('form.queryEditor.input', {
context: 'optionMatchAny',
postProcess: 'sentenceCase',
}),
value: 'any', value: 'any',
}, },
]; ];
@@ -1,8 +1,9 @@
import { MutableRefObject } from 'react';
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact'; import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
import { Group } from '@mantine/core'; import { Group } from '@mantine/core';
import { useForm } from '@mantine/form'; import { useForm } from '@mantine/form';
import { useDisclosure } from '@mantine/hooks'; import { useDisclosure } from '@mantine/hooks';
import { MutableRefObject } from 'react'; import { useTranslation } from 'react-i18next';
import { RiHashtag } from 'react-icons/ri'; import { RiHashtag } from 'react-icons/ri';
import { Button } from '/@/renderer/components/button'; import { Button } from '/@/renderer/components/button';
import { MotionFlex } from '../motion'; import { MotionFlex } from '../motion';
@@ -29,6 +30,7 @@ export const TablePagination = ({
setPagination, setPagination,
setIdPagination, setIdPagination,
}: TablePaginationProps) => { }: TablePaginationProps) => {
const { t } = useTranslation();
const [isGoToPageOpen, handlers] = useDisclosure(false); const [isGoToPageOpen, handlers] = useDisclosure(false);
const containerQuery = useContainerQuery(); const containerQuery = useContainerQuery();
@@ -115,7 +117,9 @@ export const TablePagination = ({
radius="sm" radius="sm"
size="sm" size="sm"
sx={{ height: '26px', padding: '0', width: '26px' }} sx={{ height: '26px', padding: '0', width: '26px' }}
tooltip={{ label: 'Go to page' }} tooltip={{
label: t('action.goToPage', { postProcess: 'sentenceCase' }),
}}
variant="default" variant="default"
onClick={() => handlers.toggle()} onClick={() => handlers.toggle()}
> >
@@ -53,7 +53,7 @@ export const JellyfinAlbumFilters = ({
const toggleFilters = [ const toggleFilters = [
{ {
label: 'Is favorited', label: t('filter.isFavorited', { postProcess: 'sentenceCase' }),
onChange: (e: ChangeEvent<HTMLInputElement>) => { onChange: (e: ChangeEvent<HTMLInputElement>) => {
const updatedFilters = setFilter({ const updatedFilters = setFilter({
customFilters, customFilters,
@@ -1,9 +1,10 @@
import { ChangeEvent, MouseEvent, MutableRefObject, useCallback } from 'react';
import { IDatasource } from '@ag-grid-community/core'; import { IDatasource } from '@ag-grid-community/core';
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact'; import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
import { Divider, Flex, Group, Stack } from '@mantine/core'; import { Divider, Flex, Group, Stack } from '@mantine/core';
import { useQueryClient } from '@tanstack/react-query'; import { useQueryClient } from '@tanstack/react-query';
import debounce from 'lodash/debounce'; import debounce from 'lodash/debounce';
import { ChangeEvent, MouseEvent, MutableRefObject, useCallback } from 'react'; import { useTranslation } from 'react-i18next';
import { RiFolder2Line, RiMoreFill, RiRefreshLine, RiSettings3Fill } from 'react-icons/ri'; import { RiFolder2Line, RiMoreFill, RiRefreshLine, RiSettings3Fill } from 'react-icons/ri';
import { useListContext } from '../../../context/list-context'; import { useListContext } from '../../../context/list-context';
import { api } from '/@/renderer/api'; import { api } from '/@/renderer/api';
@@ -62,6 +63,7 @@ export const AlbumArtistListHeaderFilters = ({
gridRef, gridRef,
tableRef, tableRef,
}: AlbumArtistListHeaderFiltersProps) => { }: AlbumArtistListHeaderFiltersProps) => {
const { t } = useTranslation();
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const server = useCurrentServer(); const server = useCurrentServer();
const { pageKey } = useListContext(); const { pageKey } = useListContext();
@@ -77,7 +79,7 @@ export const AlbumArtistListHeaderFilters = ({
(server?.type && (server?.type &&
FILTERS[server.type as keyof typeof FILTERS].find((f) => f.value === filter.sortBy) FILTERS[server.type as keyof typeof FILTERS].find((f) => f.value === filter.sortBy)
?.name) || ?.name) ||
'Unknown'; t('common.unknown', { postProcess: 'titleCase' });
const handleItemSize = (e: number) => { const handleItemSize = (e: number) => {
if (display === ListDisplayType.TABLE || display === ListDisplayType.TABLE_PAGINATED) { if (display === ListDisplayType.TABLE || display === ListDisplayType.TABLE_PAGINATED) {
@@ -359,7 +361,7 @@ export const AlbumArtistListHeaderFilters = ({
<Button <Button
compact compact
size="md" size="md"
tooltip={{ label: 'Refresh' }} tooltip={{ label: t('common.refresh', { postProcess: 'titleCase' }) }}
variant="subtle" variant="subtle"
onClick={handleRefresh} onClick={handleRefresh}
> >
@@ -407,21 +409,27 @@ export const AlbumArtistListHeaderFilters = ({
value={ListDisplayType.CARD} value={ListDisplayType.CARD}
onClick={handleSetViewType} onClick={handleSetViewType}
> >
Card {t('table.config.view.card', {
postProcess: 'sentenceCase',
})}
</DropdownMenu.Item> </DropdownMenu.Item>
<DropdownMenu.Item <DropdownMenu.Item
$isActive={display === ListDisplayType.POSTER} $isActive={display === ListDisplayType.POSTER}
value={ListDisplayType.POSTER} value={ListDisplayType.POSTER}
onClick={handleSetViewType} onClick={handleSetViewType}
> >
Poster {t('table.config.view.poster', {
postProcess: 'sentenceCase',
})}
</DropdownMenu.Item> </DropdownMenu.Item>
<DropdownMenu.Item <DropdownMenu.Item
$isActive={display === ListDisplayType.TABLE} $isActive={display === ListDisplayType.TABLE}
value={ListDisplayType.TABLE} value={ListDisplayType.TABLE}
onClick={handleSetViewType} onClick={handleSetViewType}
> >
Table {t('table.config.view.table', {
postProcess: 'sentenceCase',
})}
</DropdownMenu.Item> </DropdownMenu.Item>
{/* <DropdownMenu.Item {/* <DropdownMenu.Item
$isActive={display === ListDisplayType.TABLE_PAGINATED} $isActive={display === ListDisplayType.TABLE_PAGINATED}
@@ -465,7 +473,11 @@ export const AlbumArtistListHeaderFilters = ({
)} )}
{!isGrid && ( {!isGrid && (
<> <>
<DropdownMenu.Label>Table Columns</DropdownMenu.Label> <DropdownMenu.Label>
{t('table.config.general.tableColumns', {
postProcess: 'sentenceCase',
})}
</DropdownMenu.Label>
<DropdownMenu.Item <DropdownMenu.Item
closeMenuOnClick={false} closeMenuOnClick={false}
component="div" component="div"
@@ -482,7 +494,11 @@ export const AlbumArtistListHeaderFilters = ({
onChange={handleTableColumns} onChange={handleTableColumns}
/> />
<Group position="apart"> <Group position="apart">
<Text>Auto Fit Columns</Text> <Text>
{t('table.config.general.autoFitColumns', {
postProcess: 'sentenceCase',
})}
</Text>
<Switch <Switch
defaultChecked={table.autoFit} defaultChecked={table.autoFit}
onChange={handleAutoFitColumns} onChange={handleAutoFitColumns}
@@ -3,6 +3,7 @@ import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/li
import { Group } from '@mantine/core'; import { Group } from '@mantine/core';
import { Button, Popover } from '/@/renderer/components'; import { Button, Popover } from '/@/renderer/components';
import isElectron from 'is-electron'; import isElectron from 'is-electron';
import { useTranslation } from 'react-i18next';
import { import {
RiArrowDownLine, RiArrowDownLine,
RiArrowUpLine, RiArrowUpLine,
@@ -27,6 +28,7 @@ interface PlayQueueListOptionsProps {
} }
export const PlayQueueListControls = ({ type, tableRef }: PlayQueueListOptionsProps) => { export const PlayQueueListControls = ({ type, tableRef }: PlayQueueListOptionsProps) => {
const { t } = useTranslation();
const { clearQueue, moveToBottomOfQueue, moveToTopOfQueue, shuffleQueue, removeFromQueue } = const { clearQueue, moveToBottomOfQueue, moveToTopOfQueue, shuffleQueue, removeFromQueue } =
useQueueControls(); useQueueControls();
@@ -115,7 +117,7 @@ export const PlayQueueListControls = ({ type, tableRef }: PlayQueueListOptionsPr
<Button <Button
compact compact
size="md" size="md"
tooltip={{ label: 'Shuffle queue' }} tooltip={{ label: t('player.shuffle', { postProcess: 'sentenceCase' }) }}
variant="default" variant="default"
onClick={handleShuffleQueue} onClick={handleShuffleQueue}
> >
@@ -124,7 +126,7 @@ export const PlayQueueListControls = ({ type, tableRef }: PlayQueueListOptionsPr
<Button <Button
compact compact
size="md" size="md"
tooltip={{ label: 'Move selected to bottom' }} tooltip={{ label: t('action.moveToBottom', { postProcess: 'sentenceCase' }) }}
variant="default" variant="default"
onClick={handleMoveToBottom} onClick={handleMoveToBottom}
> >
@@ -133,7 +135,7 @@ export const PlayQueueListControls = ({ type, tableRef }: PlayQueueListOptionsPr
<Button <Button
compact compact
size="md" size="md"
tooltip={{ label: 'Move selected to top' }} tooltip={{ label: t('action.moveToTop', { postProcess: 'sentenceCase' }) }}
variant="default" variant="default"
onClick={handleMoveToTop} onClick={handleMoveToTop}
> >
@@ -142,7 +144,9 @@ export const PlayQueueListControls = ({ type, tableRef }: PlayQueueListOptionsPr
<Button <Button
compact compact
size="md" size="md"
tooltip={{ label: 'Remove selected' }} tooltip={{
label: t('action.removeFromQueue', { postProcess: 'sentenceCase' }),
}}
variant="default" variant="default"
onClick={handleRemoveSelected} onClick={handleRemoveSelected}
> >
@@ -151,7 +155,7 @@ export const PlayQueueListControls = ({ type, tableRef }: PlayQueueListOptionsPr
<Button <Button
compact compact
size="md" size="md"
tooltip={{ label: 'Clear queue' }} tooltip={{ label: t('action.clearQueue', { postProcess: 'sentenceCase' }) }}
variant="default" variant="default"
onClick={handleClearQueue} onClick={handleClearQueue}
> >
@@ -167,7 +171,9 @@ export const PlayQueueListControls = ({ type, tableRef }: PlayQueueListOptionsPr
<Button <Button
compact compact
size="md" size="md"
tooltip={{ label: 'Configure' }} tooltip={{
label: t('glossary.configure', { postProcess: 'sentenceCase' }),
}}
variant="subtle" variant="subtle"
> >
<RiListSettingsLine size="1.1rem" /> <RiListSettingsLine size="1.1rem" />
@@ -1,5 +1,6 @@
import { Group, Center } from '@mantine/core'; import { Group, Center } from '@mantine/core';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { useTranslation } from 'react-i18next';
import { HiOutlineQueueList } from 'react-icons/hi2'; import { HiOutlineQueueList } from 'react-icons/hi2';
import { RiFileMusicLine, RiFileTextLine, RiInformationFill } from 'react-icons/ri'; import { RiFileMusicLine, RiFileTextLine, RiInformationFill } from 'react-icons/ri';
import styled from 'styled-components'; import styled from 'styled-components';
@@ -50,11 +51,12 @@ const GridContainer = styled.div<TransparendGridContainerProps>`
grid-template-rows: auto minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr);
grid-template-columns: 1fr; grid-template-columns: 1fr;
padding: 1rem; padding: 1rem;
background: rgb(var(--main-bg-transparent), ${({ opacity }) => opacity}%); background: rgb(var(--main-bg-transparent) ${({ opacity }) => opacity}%);
border-radius: 5px; border-radius: 5px;
`; `;
export const FullScreenPlayerQueue = () => { export const FullScreenPlayerQueue = () => {
const { t } = useTranslation();
const { activeTab, opacity } = useFullScreenPlayerStore(); const { activeTab, opacity } = useFullScreenPlayerStore();
const { setStore } = useFullScreenPlayerStoreActions(); const { setStore } = useFullScreenPlayerStoreActions();
@@ -62,19 +64,19 @@ export const FullScreenPlayerQueue = () => {
{ {
active: activeTab === 'queue', active: activeTab === 'queue',
icon: <RiFileMusicLine size="1.5rem" />, icon: <RiFileMusicLine size="1.5rem" />,
label: 'Up Next', label: t('page.fullScreenPlayer.upNext'),
onClick: () => setStore({ activeTab: 'queue' }), onClick: () => setStore({ activeTab: 'queue' }),
}, },
{ {
active: activeTab === 'related', active: activeTab === 'related',
icon: <HiOutlineQueueList size="1.5rem" />, icon: <HiOutlineQueueList size="1.5rem" />,
label: 'Related', label: t('page.fullScreenPlayer.related'),
onClick: () => setStore({ activeTab: 'related' }), onClick: () => setStore({ activeTab: 'related' }),
}, },
{ {
active: activeTab === 'lyrics', active: activeTab === 'lyrics',
icon: <RiFileTextLine size="1.5rem" />, icon: <RiFileTextLine size="1.5rem" />,
label: 'Lyrics', label: t('page.fullScreenPlayer.lyrics'),
onClick: () => setStore({ activeTab: 'lyrics' }), onClick: () => setStore({ activeTab: 'lyrics' }),
}, },
]; ];
@@ -125,7 +127,7 @@ export const FullScreenPlayerQueue = () => {
order={3} order={3}
weight={700} weight={700}
> >
COMING SOON {t('common.comingSoon', { postProcess: 'upperCase' })}
</TextTitle> </TextTitle>
</Group> </Group>
</Center> </Center>
@@ -271,9 +271,14 @@ export const ApplicationSettings = () => {
}} }}
/> />
), ),
description: 'Sets the application zoom factor in percent', description: t('setting.zoom', {
context: 'description',
postProcess: 'sentenceCase',
}),
isHidden: !isElectron(), isHidden: !isElectron(),
title: 'Zoom factor', title: t('setting.zoom', {
postProcess: 'sentenceCase',
}),
}, },
]; ];
@@ -136,7 +136,7 @@ export const SidebarSettings = () => {
variant="filled" variant="filled"
onClick={handleSave} onClick={handleSave}
> >
Save sidebar configuration {t('common.save', { postProcess: 'titleCase' })}
</Button> </Button>
} }
description={t('setting.sidebarCollapsedNavigation', { description={t('setting.sidebarCollapsedNavigation', {
@@ -282,7 +282,7 @@ export const MpvSettings = () => {
note: t('common.restartRequired', { postProcess: 'sentenceCase' }), note: t('common.restartRequired', { postProcess: 'sentenceCase' }),
title: t('setting.replayGainMode', { title: t('setting.replayGainMode', {
ReplayGain: 'ReplayGain', ReplayGain: 'ReplayGain',
postProcess: 'lowerCase', postProcess: 'sentenceCase',
}), }),
}, },
{ {
@@ -300,7 +300,7 @@ export const MpvSettings = () => {
}), }),
title: t('setting.replayGainPreamp', { title: t('setting.replayGainPreamp', {
ReplayGain: 'ReplayGain', ReplayGain: 'ReplayGain',
postProcess: 'lowerCase', postProcess: 'sentenceCase',
}), }),
}, },
{ {
@@ -318,7 +318,7 @@ export const MpvSettings = () => {
}), }),
title: t('setting.replayGainClipping', { title: t('setting.replayGainClipping', {
ReplayGain: 'ReplayGain', ReplayGain: 'ReplayGain',
postProcess: 'lowerCase', postProcess: 'sentenceCase',
}), }),
}, },
{ {
@@ -335,7 +335,7 @@ export const MpvSettings = () => {
}), }),
title: t('setting.replayGainFallback', { title: t('setting.replayGainFallback', {
ReplayGain: 'ReplayGain', ReplayGain: 'ReplayGain',
postProcess: 'lowerCase', postProcess: 'sentenceCase',
}), }),
}, },
]; ];
@@ -38,7 +38,7 @@ export const DiscordSettings = () => {
isHidden: !isElectron(), isHidden: !isElectron(),
title: t('setting.discordRichPresence', { title: t('setting.discordRichPresence', {
discord: 'Discord', discord: 'Discord',
postProcess: 'lowerCase', postProcess: 'sentenceCase',
}), }),
}, },
{ {
@@ -64,7 +64,7 @@ export const DiscordSettings = () => {
isHidden: !isElectron(), isHidden: !isElectron(),
title: t('setting.discordApplicationId', { title: t('setting.discordApplicationId', {
discord: 'Discord', discord: 'Discord',
postProcess: 'lowerCase', postProcess: 'sentenceCase',
}), }),
}, },
{ {
@@ -93,7 +93,7 @@ export const DiscordSettings = () => {
isHidden: !isElectron(), isHidden: !isElectron(),
title: t('setting.discordUpdateInterval', { title: t('setting.discordUpdateInterval', {
discord: 'Discord', discord: 'Discord',
postProcess: 'lowerCase', postProcess: 'sentenceCase',
}), }),
}, },
{ {
@@ -1,5 +1,6 @@
import { Group } from '@mantine/core';
import { forwardRef, ReactNode, Ref, useState } from 'react'; import { forwardRef, ReactNode, Ref, useState } from 'react';
import { Group } from '@mantine/core';
import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import styles from './library-header.module.scss'; import styles from './library-header.module.scss';
import { LibraryItem } from '/@/renderer/api/types'; import { LibraryItem } from '/@/renderer/api/types';
@@ -20,12 +21,30 @@ export const LibraryHeader = forwardRef(
{ imageUrl, imagePlaceholderUrl, background, title, item, children }: LibraryHeaderProps, { imageUrl, imagePlaceholderUrl, background, title, item, children }: LibraryHeaderProps,
ref: Ref<HTMLDivElement>, ref: Ref<HTMLDivElement>,
) => { ) => {
const { t } = useTranslation();
const [isImageError, setIsImageError] = useState<boolean | null>(false); const [isImageError, setIsImageError] = useState<boolean | null>(false);
const onImageError = () => { const onImageError = () => {
setIsImageError(true); setIsImageError(true);
}; };
const itemTypeString = () => {
switch (item.type) {
case LibraryItem.ALBUM:
return t('entity.album', { count: 1 });
case LibraryItem.ARTIST:
return t('entity.artist', { count: 1 });
case LibraryItem.ALBUM_ARTIST:
return t('entity.albumArtist', { count: 1 });
case LibraryItem.PLAYLIST:
return t('entity.playlist', { count: 1 });
case LibraryItem.SONG:
return t('entity.track', { count: 1 });
default:
return t('common.unknown');
}
};
return ( return (
<div <div
ref={ref} ref={ref}
@@ -59,7 +78,7 @@ export const LibraryHeader = forwardRef(
tt="uppercase" tt="uppercase"
weight={600} weight={600}
> >
{item.type} {itemTypeString()}
</Text> </Text>
</Group> </Group>
<h1 className={styles.title}>{title}</h1> <h1 className={styles.title}>{title}</h1>
@@ -1,4 +1,5 @@
import { Grid, Group } from '@mantine/core'; import { Grid, Group } from '@mantine/core';
import { useTranslation } from 'react-i18next';
import { RiSearchLine, RiMenuFill, RiArrowLeftSLine, RiArrowRightSLine } from 'react-icons/ri'; import { RiSearchLine, RiMenuFill, RiArrowLeftSLine, RiArrowRightSLine } from 'react-icons/ri';
import { useNavigate } from 'react-router'; import { useNavigate } from 'react-router';
import styled from 'styled-components'; import styled from 'styled-components';
@@ -19,6 +20,7 @@ const ActionsContainer = styled.div`
`; `;
export const ActionBar = () => { export const ActionBar = () => {
const { t } = useTranslation();
const cq = useContainerQuery({ md: 300 }); const cq = useContainerQuery({ md: 300 });
const navigate = useNavigate(); const navigate = useNavigate();
const { open } = useCommandPalette(); const { open } = useCommandPalette();
@@ -36,6 +38,7 @@ export const ActionBar = () => {
<TextInput <TextInput
readOnly readOnly
icon={<RiSearchLine />} icon={<RiSearchLine />}
placeholder={t('common.search', { postProcess: 'titleCase' })}
size="md" size="md"
onClick={open} onClick={open}
onKeyDown={(e) => { onKeyDown={(e) => {
@@ -423,7 +423,7 @@ export const SongListHeaderFilters = ({ gridRef, tableRef }: SongListHeaderFilte
fill: isFilterApplied ? 'var(--primary-color) !important' : undefined, fill: isFilterApplied ? 'var(--primary-color) !important' : undefined,
}, },
}} }}
tooltip={{ label: 'Filters' }} tooltip={{ label: t('common.filters', { postProcess: 'titleCase' }) }}
variant="subtle" variant="subtle"
onClick={handleOpenFiltersModal} onClick={handleOpenFiltersModal}
> >
@@ -433,7 +433,7 @@ export const SongListHeaderFilters = ({ gridRef, tableRef }: SongListHeaderFilte
<Button <Button
compact compact
size="md" size="md"
tooltip={{ label: 'Refresh' }} tooltip={{ label: t('glossary.refresh', { postProcess: 'titleCase' }) }}
variant="subtle" variant="subtle"
onClick={handleRefresh} onClick={handleRefresh}
> >