Add updated i18n config and en locale

This commit is contained in:
jeffvli 2023-10-26 03:58:32 -07:00
parent 7a580c2c65
commit 68df672953
6 changed files with 728 additions and 176 deletions

38
package-lock.json generated
View File

@ -42,7 +42,7 @@
"framer-motion": "^10.13.0",
"fuse.js": "^6.6.2",
"history": "^5.3.0",
"i18next": "^21.6.16",
"i18next": "^21.10.0",
"idb-keyval": "^6.2.1",
"immer": "^9.0.21",
"is-electron": "^2.2.2",
@ -57,7 +57,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-error-boundary": "^3.1.4",
"react-i18next": "^11.16.7",
"react-i18next": "^11.18.6",
"react-icons": "^4.10.1",
"react-player": "^2.11.0",
"react-router": "^6.16.0",
@ -125,7 +125,7 @@
"file-loader": "^6.2.0",
"html-webpack-plugin": "^5.5.0",
"husky": "^7.0.4",
"i18next-parser": "^6.3.0",
"i18next-parser": "^6.6.0",
"identity-obj-proxy": "^3.0.0",
"jest": "^27.5.1",
"lint-staged": "^12.3.7",
@ -11871,7 +11871,8 @@
"node_modules/html-escaper": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg=="
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
"dev": true
},
"node_modules/html-minifier-terser": {
"version": "6.1.0",
@ -12129,9 +12130,9 @@
}
},
"node_modules/i18next": {
"version": "21.6.16",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-21.6.16.tgz",
"integrity": "sha512-xJlzrVxG9CyAGsbMP1aKuiNr1Ed2m36KiTB7hjGMG2Zo4idfw3p9THUEu+GjBwIgEZ7F11ZbCzJcfv4uyfKNuw==",
"version": "21.10.0",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-21.10.0.tgz",
"integrity": "sha512-YeuIBmFsGjUfO3qBmMOc0rQaun4mIpGKET5WDwvu8lU7gvwpcariZLNtL0Fzj+zazcHUrlXHiptcFhBMFaxzfg==",
"funding": [
{
"type": "individual",
@ -16968,12 +16969,11 @@
"integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA=="
},
"node_modules/react-i18next": {
"version": "11.16.7",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.16.7.tgz",
"integrity": "sha512-7yotILJLnKfvUfrl/nt9eK9vFpVFjZPLWAwBzWL6XppSZZEvlmlKk0GBGDCAPfLfs8oND7WAbry8wGzdoiW5Nw==",
"version": "11.18.6",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.18.6.tgz",
"integrity": "sha512-yHb2F9BiT0lqoQDt8loZ5gWP331GwctHz9tYQ8A2EIEUu+CcEdjBLQWli1USG3RdWQt3W+jqQLg/d4rrQR96LA==",
"dependencies": {
"@babel/runtime": "^7.14.5",
"html-escaper": "^2.0.2",
"html-parse-stringify": "^3.0.1"
},
"peerDependencies": {
@ -30233,7 +30233,8 @@
"html-escaper": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg=="
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
"dev": true
},
"html-minifier-terser": {
"version": "6.1.0",
@ -30419,9 +30420,9 @@
"dev": true
},
"i18next": {
"version": "21.6.16",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-21.6.16.tgz",
"integrity": "sha512-xJlzrVxG9CyAGsbMP1aKuiNr1Ed2m36KiTB7hjGMG2Zo4idfw3p9THUEu+GjBwIgEZ7F11ZbCzJcfv4uyfKNuw==",
"version": "21.10.0",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-21.10.0.tgz",
"integrity": "sha512-YeuIBmFsGjUfO3qBmMOc0rQaun4mIpGKET5WDwvu8lU7gvwpcariZLNtL0Fzj+zazcHUrlXHiptcFhBMFaxzfg==",
"requires": {
"@babel/runtime": "^7.17.2"
}
@ -33952,12 +33953,11 @@
"integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA=="
},
"react-i18next": {
"version": "11.16.7",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.16.7.tgz",
"integrity": "sha512-7yotILJLnKfvUfrl/nt9eK9vFpVFjZPLWAwBzWL6XppSZZEvlmlKk0GBGDCAPfLfs8oND7WAbry8wGzdoiW5Nw==",
"version": "11.18.6",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.18.6.tgz",
"integrity": "sha512-yHb2F9BiT0lqoQDt8loZ5gWP331GwctHz9tYQ8A2EIEUu+CcEdjBLQWli1USG3RdWQt3W+jqQLg/d4rrQR96LA==",
"requires": {
"@babel/runtime": "^7.14.5",
"html-escaper": "^2.0.2",
"html-parse-stringify": "^3.0.1"
}
},

View File

@ -26,7 +26,7 @@
"start:web": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack serve --config ./.erb/configs/webpack.config.renderer.web.ts",
"test": "jest",
"prepare": "husky install",
"i18next": "i18next -c src/renderer/i18n/i18next-parser.config.js",
"i18next": "i18next -c src/i18n/i18next-parser.config.js",
"prod:buildserver": "pwsh -c \"./scripts/server-build.ps1\"",
"prod:publishserver": "pwsh -c \"./scripts/server-publish.ps1\""
},
@ -219,7 +219,7 @@
"file-loader": "^6.2.0",
"html-webpack-plugin": "^5.5.0",
"husky": "^7.0.4",
"i18next-parser": "^6.3.0",
"i18next-parser": "^6.6.0",
"identity-obj-proxy": "^3.0.0",
"jest": "^27.5.1",
"lint-staged": "^12.3.7",
@ -288,7 +288,7 @@
"framer-motion": "^10.13.0",
"fuse.js": "^6.6.2",
"history": "^5.3.0",
"i18next": "^21.6.16",
"i18next": "^21.10.0",
"idb-keyval": "^6.2.1",
"immer": "^9.0.21",
"is-electron": "^2.2.2",
@ -303,7 +303,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-error-boundary": "^3.1.4",
"react-i18next": "^11.16.7",
"react-i18next": "^11.18.6",
"react-icons": "^4.10.1",
"react-player": "^2.11.0",
"react-router": "^6.16.0",

View File

@ -1,32 +0,0 @@
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
const en = require('./locales/en.json');
const resources = {
en: { translation: en },
};
export const Languages = [
{
label: 'English',
value: 'en',
},
];
i18n
.use(initReactI18next) // passes i18n down to react-i18next
.init({
fallbackLng: 'en',
// language to use, more information here: https://www.i18next.com/overview/configuration-options#languages-namespaces-resources
// you can use the i18n.changeLanguage function to change the language manually: https://www.i18next.com/overview/api#changelanguage
// if you're using a language detector, do not define the lng option
interpolation: {
escapeValue: false, // react already safes from xss
},
lng: 'en',
resources,
});
export default i18n;

73
src/i18n/i18n.ts Normal file
View File

@ -0,0 +1,73 @@
import { PostProcessorModule } from 'i18next';
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
const en = require('./locales/en.json');
const resources = {
en: { translation: en },
};
export const Languages = [
{
label: 'English',
value: 'en',
},
];
const lowerCasePostProcessor: PostProcessorModule = {
type: 'postProcessor',
name: 'lowerCase',
process: (value: string) => {
return value.toLocaleLowerCase();
},
};
const upperCasePostProcessor: PostProcessorModule = {
type: 'postProcessor',
name: 'upperCase',
process: (value: string) => {
return value.toLocaleUpperCase();
},
};
const titleCasePostProcessor: PostProcessorModule = {
type: 'postProcessor',
name: 'titleCase',
process: (value: string) => {
return value.replace(/\w\S*/g, (txt) => {
return txt.charAt(0).toUpperCase() + txt.slice(1).toLowerCase();
});
},
};
const sentenceCasePostProcessor: PostProcessorModule = {
type: 'postProcessor',
name: 'sentenceCase',
process: (value: string) => {
const sentences = value.split('. ');
return sentences
.map((sentence) => {
return sentence.charAt(0).toUpperCase() + sentence.slice(1).toLocaleLowerCase();
})
.join('. ');
},
};
i18n.use(lowerCasePostProcessor)
.use(upperCasePostProcessor)
.use(titleCasePostProcessor)
.use(sentenceCasePostProcessor)
.use(initReactI18next) // passes i18n down to react-i18next
.init({
fallbackLng: 'en',
// language to use, more information here: https://www.i18next.com/overview/configuration-options#languages-namespaces-resources
// you can use the i18n.changeLanguage function to change the language manually: https://www.i18next.com/overview/api#changelanguage
// if you're using a language detector, do not define the lng option
interpolation: {
escapeValue: false, // react already safes from xss
},
lng: 'en',
resources,
});
export default i18n;

View File

@ -1,117 +1,44 @@
// i18next-parser.config.js
// Reference: https://github.com/i18next/i18next-parser#options
module.exports = {
contextSeparator: '_',
// Key separator used in your translation keys
createOldCatalogs: true,
// Exit with an exit code of 1 when translations are updated (for CI purpose)
customValueTemplate: null,
// Save the \_old files
defaultNamespace: 'translation',
// Default namespace used in your i18next config
defaultValue: '',
// Exit with an exit code of 1 on warnings
failOnUpdate: false,
// Display info about the parsing including some stats
failOnWarnings: false,
// The locale to compare with default values to determine whether a default value has been changed.
// If this is set and a default value differs from a translation in the specified locale, all entries
// for that key across locales are reset to the default value, and existing translations are moved to
// the `_old` file.
i18nextOptions: null,
// Default value to give to empty keys
// You may also specify a function accepting the locale, namespace, and key as arguments
indentation: 2,
// Plural separator used in your translation keys
// If you want to use plain english keys, separators such as `_` might conflict. You might want to set `pluralSeparator` to a different string that does not occur in your keys.
input: [
'../components/**/*.{js,jsx,ts,tsx}',
'../features/**/*.{js,jsx,ts,tsx}',
'../layouts/**/*.{js,jsx,ts,tsx}',
'!../../src/node_modules/**',
'!../../src/**/*.prod.js',
],
// Indentation of the catalog files
keepRemoved: false,
// Keep keys from the catalog that are no longer in code
keySeparator: '.',
// Key separator used in your translation keys
// If you want to use plain english keys, separators such as `.` and `:` will conflict. You might want to set `keySeparator: false` and `namespaceSeparator: false`. That way, `t('Status: Loading...')` will not think that there are a namespace and three separator dots for instance.
// see below for more details
lexers: {
default: ['JavascriptLexer'],
handlebars: ['HandlebarsLexer'],
hbs: ['HandlebarsLexer'],
htm: ['HTMLLexer'],
html: ['HTMLLexer'],
js: ['JavascriptLexer'],
jsx: ['JsxLexer'],
mjs: ['JavascriptLexer'],
// if you're writing jsx inside .js files, change this to JsxLexer
ts: ['JavascriptLexer'],
tsx: ['JsxLexer'],
},
lineEnding: 'auto',
// Control the line ending. See options at https://github.com/ryanve/eol
locales: ['en'],
// An array of the locales in your applications
namespaceSeparator: false,
// Namespace separator used in your translation keys
// If you want to use plain english keys, separators such as `.` and `:` will conflict. You might want to set `keySeparator: false` and `namespaceSeparator: false`. That way, `t('Status: Loading...')` will not think that there are a namespace and three separator dots for instance.
output: 'src/renderer/i18n/locales/$LOCALE.json',
// Supports $LOCALE and $NAMESPACE injection
// Supports JSON (.json) and YAML (.yml) file formats
// Where to write the locale files relative to process.cwd()
pluralSeparator: '_',
// If you wish to customize the value output the value as an object, you can set your own format.
// ${defaultValue} is the default value you set in your translation function.
// Any other custom property will be automatically extracted.
//
// Example:
// {
// message: "${defaultValue}",
// description: "${maxLength}", //
// }
resetDefaultValueLocale: 'en',
// Whether or not to sort the catalog. Can also be a [compareFunction](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#parameters)
skipDefaultValues: false,
// An array of globs that describe where to look for source files
// relative to the location of the configuration file
sort: true,
// Whether to ignore default values
// You may also specify a function accepting the locale and namespace as arguments
useKeysAsDefaultValue: true,
// Whether to use the keys as the default value; ex. "Hello": "Hello", "World": "World"
// This option takes precedence over the `defaultValue` and `skipDefaultValues` options
// You may also specify a function accepting the locale and namespace as arguments
verbose: false,
// If you wish to customize options in internally used i18next instance, you can define an object with any
// configuration property supported by i18next (https://www.i18next.com/overview/configuration-options).
// { compatibilityJSON: 'v3' } can be used to generate v3 compatible plurals.
contextSeparator: '_',
createOldCatalogs: true,
customValueTemplate: null,
defaultNamespace: 'translation',
defaultValue: '',
failOnUpdate: false,
failOnWarnings: false,
i18nextOptions: null,
indentation: 4,
input: [
'../renderer/components/**/*.{js,jsx,ts,tsx}',
'../renderer/features/**/*.{js,jsx,ts,tsx}',
'../renderer/layouts/**/*.{js,jsx,ts,tsx}',
'!../src/node_modules/**',
'!../src/**/*.prod.js',
],
keepRemoved: false,
keySeparator: '.',
lexers: {
default: ['JavascriptLexer'],
handlebars: ['HandlebarsLexer'],
hbs: ['HandlebarsLexer'],
htm: ['HTMLLexer'],
html: ['HTMLLexer'],
js: ['JavascriptLexer'],
jsx: ['JsxLexer'],
mjs: ['JavascriptLexer'],
ts: ['JavascriptLexer'],
tsx: ['JsxLexer'],
},
lineEnding: 'auto',
locales: ['en'],
namespaceSeparator: false,
output: 'src/renderer/i18n/locales/$LOCALE.json',
pluralSeparator: '_',
resetDefaultValueLocale: 'en',
skipDefaultValues: false,
sort: true,
useKeysAsDefaultValue: true,
verbose: false,
};

View File

@ -1,9 +1,593 @@
{
"player": {
"next": "player.next",
"play": "player.play",
"prev": "player.prev",
"seekBack": "player.seekBack",
"seekForward": "player.seekForward"
}
"action": {
"addToFavorites": "add to $t(entity.favorite_other)",
"addToPlaylist": "add to $t(entity.playlist_one)",
"createPlaylist": "create $t(entity.playlist_one)",
"deletePlaylist": "delete $t(entity.playlist_one)",
"deselectAll": "deselect all",
"editPlaylist": "edit $t(entity.playlist_one)",
"moveToBottom": "move to bottom",
"moveToTop": "move to top",
"refresh": "$t(glossary.refresh)",
"removeFromFavorites": "remove from $t(entity.favorite_other)",
"removeFromPlaylist": "remove from $t(entity.playlist_one)",
"removeFromQueue": "remove from queue",
"setRating": "set rating",
"toggleSmartPlaylistEditor": "toggle $t(entity.smartPlaylist) editor",
"viewPlaylists": "view $t(entity.playlist_other)"
},
"common": {
"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",
"cancel": "cancel",
"confirm": "confirm",
"create": "create",
"delete": "delete",
"disable": "disable",
"dismiss": "dismiss",
"edit": "edit",
"enable": "enable",
"no": "no",
"none": "none",
"ok": "ok",
"playerMustBePaused": "player must be paused",
"quit": "quit",
"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",
"search": "search",
"noResultsFromQuery": "the query returned no results"
},
"entity": {
"album_one": "album",
"album_other": "albums",
"albumArtist_one": "album artist",
"albumArtist_other": "album artists",
"albumArtistCount_one": "{{count}} album artist",
"albumArtistCount_other": "{{count}} album artists",
"albumWithCount_one": "{{count}} album",
"albumWithCount_other": "{{count}} albums",
"artist_one": "artist",
"artist_other": "artists",
"artistWithCount_one": "{{count}} artist",
"artistWithCount_other": "{{count}} artists",
"favorite_one": "favorite",
"favorite_other": "favorites",
"folder_one": "folder",
"folder_other": "folders",
"folderWithCount_one": "{{count}} folder",
"folderWithCount_other": "{{count}} folders",
"genre_one": "genre",
"genre_other": "genres",
"genreWithCount_one": "{{count}} genre",
"genreWithCount_other": "{{count}} genres",
"playlist_one": "playlist",
"playlist_other": "playlists",
"playlistWithCount_one": "{{count}} playlist",
"playlistWithCount_other": "{{count}} playlists",
"setting_one": "setting",
"setting_other": "settings",
"smartPlaylist": "smart $t(entity.playlist_one)",
"track_one": "track",
"track_other": "tracks",
"trackWithCount_one": "{{count}} track",
"trackWithCount_other": "{{count}} tracks"
},
"error": {
"playbackError": "an error occurred when trying to play the media",
"genericError": "an error occurred",
"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",
"localFontAccessDenied": "access denied to local fonts",
"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",
"remotePortError": "an error occurred when trying to set the remote server port",
"remotePortWarning": "restart the server to apply the new port",
"systemFontError": "an error occurred when trying to get system fonts",
"invalidServer": "invalid server",
"authenticationFailed": "authentication failed",
"sessionExpiredError": "your session has expired",
"loginRateError": "too many login attempts, please try again in a few seconds",
"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": {
"isRated": "is rated",
"isFavorited": "is favorited",
"isCompilation": "is compilation",
"isRecentlyPlayed": "is recently played",
"fromYear": "from year",
"toYear": "to year",
"albumArtist": "$t(entity.albumArtist_one)",
"artist": "$t(entity.artist_one)",
"biography": "biography",
"bitrate": "bitrate",
"bpm": "bpm",
"communityRating": "community rating",
"criticRating": "critic rating",
"dateAdded": "date added",
"disc": "disc",
"duration": "duration",
"favorited": "favorited",
"lastPlayed": "last played",
"mostPlayed": "most played",
"name": "name",
"note": "note",
"path": "path",
"playCount": "play count",
"random": "random",
"rating": "rating",
"recentlyAdded": "recently added",
"recentlyPlayed": "recently played",
"releaseDate": "release date",
"releaseYear": "release year",
"search": "search",
"songCount": "song count",
"title": "title",
"trackNumber": "track"
},
"glossary": {
"sortOrder": "order",
"limit": "limit",
"reset": "reset",
"clear": "clear",
"action": "action",
"expand": "expand",
"collapse": "collapse",
"action_other": "actions",
"ascending": "ascending",
"biography": "biography",
"bitrate": "bitrate",
"bpm": "bpm",
"channel": "channel",
"channel_other": "channels",
"configure": "configure",
"descending": "descending",
"disc": "disc",
"duration": "duration",
"favorite": "favorite",
"filter_one": "filter",
"filter_other": "filters",
"description": "description",
"gap": "gap",
"home": "home",
"menu": "menu",
"name": "name",
"note": "note",
"owner": "owner",
"path": "path",
"random": "random",
"rating": "rating",
"refresh": "refresh",
"search": "search",
"setting": "setting",
"setting_other": "settings",
"size": "size",
"title": "title",
"trackNumber": "track",
"version": "version",
"year": "year"
},
"page": {
"albumDetail": {
"moreFromArtist": "more from this $t(entity.genre_one)",
"moreFromGeneric": "more from {{item}}"
},
"setting": {
"generalTab": "general",
"playbackTab": "playback",
"hotkeysTab": "hotkeys",
"windowTab": "window"
},
"albumArtistList": {
"title": "$t(entity.albumArtist_other)"
},
"albumList": {
"title": "$t(entity.album_other)"
},
"appMenu": {
"collapseSidebar": "collapse sidebar",
"expandSidebar": "expand sidebar",
"goBack": "go back",
"goForward": "go forward",
"manageServers": "manage servers",
"openBrowserDevtools": "open browser devtools",
"quit": "$t(common.quit)",
"selectServer": "select server",
"settings": "$t(glossary.setting_other)",
"version": "version {{version}}"
},
"contextMenu": {
"addFavorite": "$t(action.addToFavorites)",
"addLast": "$t(player.addLast)",
"addNext": "$t(player.addNext)",
"addToFavorites": "$t(action.addToFavorites)",
"addToPlaylist": "$t(action.addToPlaylist)",
"createPlaylist": "$t(action.createPlaylist)",
"deletePlaylist": "$t(action.deletePlaylist)",
"deselectAll": "$t(action.deselectAll)",
"moveToBottom": "$t(action.moveToBottom)",
"moveToTop": "$t(action.moveToTop)",
"numberSelected": "{{count}} selected",
"play": "$t(player.play)",
"removeFromFavorites": "$t(action.removeFromFavorites)",
"removeFromPlaylist": "$t(action.removeFromPlaylist)",
"removeFromQueue": "$t(action.removeFromQueue)",
"setRating": "$t(action.setRating)"
},
"genreList": {
"title": "$t(entity.genre_other)"
},
"home": {
"explore": "explore from your library",
"mostPlayed": "most played",
"newlyAdded": "newly added releases",
"recentlyPlayed": "recently played",
"title": "$t(glossary.home)"
},
"playlistList": {
"title": "$t(entity.playlist_other)"
},
"sidebar": {
"albums": "$t(entity.album_other)",
"artists": "$t(entity.artist_other)",
"albumArtists": "$t(entity.albumArtist_other)",
"folders": "$t(entity.folder_other)",
"genres": "$t(entity.genre_other)",
"home": "$t(glossary.home)",
"nowPlaying": "now playing",
"playlists": "$t(entity.playlist_other)",
"search": "$t(glossary.search)",
"settings": "$t(entity.setting_other)",
"tracks": "$t(entity.track_other)"
},
"trackList": {
"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": {
"favorite": "favorite",
"unfavorite": "unfavorite",
"addLast": "add last",
"addNext": "add next",
"mute": "mute",
"muted": "muted",
"next": "next",
"play": "play",
"previous": "previous",
"queue_clear": "clear queue",
"queue_moveToBottom": "move selected to top",
"queue_moveToTop": "move selected to bottom",
"queue_remove": "remove selected",
"repeat": "repeat",
"repeat_all": "repeat all",
"repeat_off": "repeat disabled",
"repeat_one": "repeat one",
"skip": "skip",
"skip_back": "skip backwards",
"skip_forward": "skip forwards",
"shuffle": "shuffle",
"playRandom": "play random",
"shuffle_off": "shuffle disabled",
"stop": "stop",
"toggleFullscreenPlayer": "toggle fullscreen player",
"playbackSpeed": "playback speed",
"playbackFetchNoResults": "no songs found",
"playbackFetchInProgress": "loading songs...",
"playbackFetchCancel": "this is taking a while... close the notification to cancel"
},
"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_description": "sets the accent color for the application",
"applicationHotkeys": "application hotkeys",
"applicationHotkeys_description": "configure application hotkeys. toggle the checkbox to set as a global hotkey (desktop only)",
"audioDevice": "audio device",
"audioDevice_description": "select the audio device to use for playback (web player only)",
"audioExclusiveMode": "audio exclusive mode",
"audioExclusiveMode_description": "enable exclusive output mode. In this mode, the system is usually locked out, and only mpv will be able to output audio",
"audioPlayer": "audio player",
"audioPlayer_description": "select the audio player to use for playback",
"crossfadeDuration": "crossfade duration",
"crossfadeDuration_description": "sets the duration of the crossfade effect",
"crossfadeStyle": "crossfade style",
"crossfadeStyle_description": "select the crossfade style to use for the audio player",
"customFontPath": "custom font path",
"customFontPath_description": "sets the path to the custom font to use for the application",
"enableRemote": "enable remote control server",
"enableRemote_description": "enables the remote control server to allow other devices to control the application",
"floatingQueueArea": "show floating queue hover area",
"floatingQueueArea_description": "display a hover icon on the right side of the screen to view the play queue",
"followLyric": "follow current lyric",
"followLyric_description": "scroll the lyric to the current playing position",
"font": "font",
"font_description": "sets the font to use for the application",
"fontType": "font type",
"fontType_description": "built-in font selects one of the fonts provided by Feishin. system font allows you to select any font provided by your operating system. custom allows you to provide your own font",
"fontType_optionBuiltIn": "built-in font",
"fontType_optionCustom": "custom font",
"fontType_optionSystem": "system font",
"gaplessAudio": "gapless audio",
"gaplessAudio_description": "sets the gapless audio setting for mpv",
"gaplessAudio_optionWeak": "weak (recommended)",
"globalMediaHotkeys": "global media hotkeys",
"globalMediaHotkeys_description": "enable or disable the usage of your system media hotkeys to control playback",
"hotkey_browserBack": "browser back",
"hotkey_browserForward": "browser forward",
"hotkey_globalSearch": "global search",
"hotkey_localSearch": "in-page search",
"hotkey_playbackNext": "next track",
"hotkey_playbackPause": "pause",
"hotkey_playbackPlay": "play",
"hotkey_playbackPlayPause": "play / pause",
"hotkey_playbackPrevious": "previous track",
"hotkey_playbackStop": "stop",
"hotkey_rate0": "rating clear",
"hotkey_rate1": "rating 1 star",
"hotkey_rate2": "rating 2 stars",
"hotkey_rate3": "rating 3 stars",
"hotkey_rate4": "rating 4 stars",
"hotkey_rate5": "rating 5 stars",
"hotkey_skipBackward": "skip backward",
"hotkey_skipForward": "skip forward",
"hotkey_toggleFullScreenPlayer": "toggle full screen player",
"hotkey_toggleQueue": "toggle queue",
"hotkey_toggleRepeat": "toggle repeat",
"hotkey_toggleShuffle": "toggle shuffle",
"hotkey_volumeDown": "volume down",
"hotkey_volumeMute": "volume mute",
"hotkey_volumeUp": "volume up",
"hotkey_zoomIn": "zoom in",
"hotkey_zoomOut": "zoom out",
"language": "language",
"language_description": "sets the language for the application",
"lyricFetch": "fetch lyrics from the internet",
"lyricFetch_description": "fetch lyrics from various internet sources",
"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",
"lyricOffset": "lyric offset (ms)",
"lyricOffset_description": "offset the lyric by the specified amount of milliseconds",
"minimumScrobblePercentage": "minimum scrobble duration (percentage)",
"minimumScrobblePercentage_description": "the minimum percentage of the song that must be played before it is scrobbled",
"minimumScrobbleSeconds": "minimum scrobble (seconds)",
"minimumScrobbleSeconds_description": "the minimum duration in seconds of the song that must be played before it is scrobbled",
"mpvExecutablePath": "mpv executable path",
"mpvExecutablePath_description": "sets the path to the mpv executable",
"mpvExecutablePath_help": "one per line",
"mpvExtraParameters": "mpv parameters",
"playbackStyle": "playback style",
"playbackStyle_description": "select the playback style to use for the audio player",
"playbackStyle_optionCrossFade": "crossfade",
"playbackStyle_optionNormal": "normal",
"playButtonBehavior": "play button behavior",
"playButtonBehavior_description": "sets the default behavior of the play button when adding songs to the queue",
"playButtonBehavior_optionAddLast": "$t(player.addLast)",
"playButtonBehavior_optionAddNext": "$t(player.addNext)",
"playButtonBehavior_optionPlay": "$t(player.play)",
"remotePassword": "remote control server password",
"remotePassword_description": "sets the password for the remote control server. These credentials are by default transferred insecurely, so you should use a unique password that you do not care about",
"remotePort": "remote control server port",
"remotePort_description": "sets the port for the remote control server",
"remoteUsername": "remote control server username",
"remoteUsername_description": "sets the username for the remote control server. if both username and password are empty, authentication will be disabled",
"replayGainClipping": "{{ReplayGain}} clipping",
"replayGainClipping_description": "Prevent clipping caused by {{ReplayGain}} by automatically lowering the gain",
"replayGainFallback": "{{ReplayGain}} fallback",
"replayGainFallback_description": "gain in db to apply if the file has no {{ReplayGain}} tags",
"replayGainMode": "{{ReplayGain}} mode",
"replayGainMode_description": "adjust volume gain according to {{ReplayGain}} values stored in the file metadata",
"replayGainMode_optionAlbum": "$t(entity.album_one)",
"replayGainMode_optionNone": "$t(common.none)",
"replayGainMode_optionTrack": "$t(entity.track_one)",
"replayGainPreamp": "{{ReplayGain}} preamp (dB)",
"replayGainPreamp_description": "adjust the preamp gain applied to the {{ReplayGain}} values",
"sampleRate": "sample rate",
"sampleRate_description": "select the output sample rate to be used if the sample frequency selected is different from that of the current media",
"savePlayQueue": "save play queue",
"savePlayQueue_description": "save the play queue when the application is closed and restore it when the application is opened",
"scrobble": "scrobble",
"scrobble_description": "scrobble plays to your media server",
"showSkipButton": "show skip buttons",
"showSkipButton_description": "show or hide the skip buttons on the player bar",
"showSkipButtons": "show skip buttons",
"showSkipButtons_description": "show or hide the skip buttons on the player bar",
"sidebarCollapsedNavigation": "sidebar (collapsed) navigation",
"sidebarCollapsedNavigation_description": "show or hide the navigation in the collapsed sidebar",
"sidebarConfiguration": "sidebar configuration",
"sidebarConfiguration_description": "select the items and order in which they appear in the sidebar",
"sidebarPlaylistList": "sidebar playlist list",
"sidebarPlaylistList_description": "show or hide the playlist list in the sidebar",
"sidePlayQueueStyle": "side play queue style",
"sidePlayQueueStyle_description": "sets the style of the side play queue",
"sidePlayQueueStyle_optionAttached": "attached",
"sidePlayQueueStyle_optionDetached": "detached",
"skipDuration": "skip duration",
"skipDuration_description": "sets the duration to skip when using the skip buttons on the player bar",
"skipPlaylistPage": "skip playlist page",
"skipPlaylistPage_description": "when navigating to a playlist, go to the playlist song list page instead of the default page",
"theme": "theme",
"theme_description": "sets the theme to use for the application",
"themeDark": "theme (dark)",
"themeDark_description": "sets the dark theme to use for the application",
"themeLight": "theme (light)",
"themeLight_description": "sets the light theme to use for the application",
"useSystemTheme": "use system theme",
"useSystemTheme_description": "follow the system-defined light or dark preference",
"volumeWheelStep": "volume wheel step",
"volumeWheelStep_description": "the amount of volume to change when scrolling the mouse wheel on the volume slider",
"zoom": "zoom percentage",
"zoom_description": "sets the zoom percentage for the application",
"zoomPercentage": "zoom percentage",
"zoomPercentage_description": "sets the zoom percentage for the application"
},
"table": {
"column": {
"album": "album",
"albumArtist": "album artist",
"albumCount": "$t(entity.album_other)",
"artist": "$t(entity.artist_one)",
"biography": "biography",
"bitrate": "bitrate",
"bpm": "bpm",
"channels": "channels",
"comment": "comment",
"dateAdded": "date added",
"discNumber": "disc",
"favorite": "favorite",
"genre": "$t(entity.genre_one)",
"lastPlayed": "last played",
"path": "path",
"playCount": "plays",
"rating": "rating",
"releaseDate": "release date",
"releaseYear": "year",
"songCount": "$t(entity.track_other)",
"title": "title",
"trackNumber": "track"
},
"config": {
"general": {
"autoFitColumns": "auto fit columns",
"displayType": "display type",
"gap": "$t(glossary.gap)",
"size": "$t(glossary.size)",
"tableColumns": "table columns"
},
"label": {
"actions": "$t(glossary.action_other)",
"album": "$t(entity.album_one)",
"albumArtist": "$t(entity.albumArtist_one)",
"artist": "$t(entity.artist_one)",
"biography": "$t(glossary.biography)",
"bitrate": "$t(glossary.bitrate)",
"bpm": "$t(glossary.bpm)",
"channels": "$t(glossary.channel_other)",
"dateAdded": "date added",
"discNumber": "disc number",
"duration": "$t(glossary.duration)",
"favorite": "$t(glossary.favorite)",
"genre": "$t(entity.genre_one)",
"lastPlayed": "last played",
"note": "$t(glossary.note)",
"owner": "$t(glossary.owner)",
"path": "$t(glossary.path)",
"playCount": "play count",
"rating": "$t(glossary.rating)",
"releaseDate": "release date",
"rowIndex": "row index",
"size": "$t(glossary.size)",
"title": "$t(glossary.title)",
"titleCombined": "$t(glossary.title) (combined)",
"trackNumber": "track number",
"year": "$t(glossary.year)"
},
"view": {
"card": "card",
"poster": "poster",
"table": "table"
}
}
}
}